001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.codegen.inline;
018    
019    import org.jetbrains.annotations.Nullable;
020    import org.jetbrains.asm4.Opcodes;
021    import org.jetbrains.asm4.Type;
022    import org.jetbrains.asm4.tree.AbstractInsnNode;
023    import org.jetbrains.asm4.tree.FieldInsnNode;
024    import org.jetbrains.asm4.tree.MethodNode;
025    
026    import java.util.Collection;
027    import java.util.List;
028    import java.util.Map;
029    
030    public class RegeneratedLambdaFieldRemapper extends LambdaFieldRemapper {
031    
032        private final String oldOwnerType;
033    
034        private final String newOwnerType;
035    
036        private final Parameters parameters;
037    
038        private final Map<String, LambdaInfo> recapturedLambdas;
039    
040        public RegeneratedLambdaFieldRemapper(
041                String oldOwnerType,
042                String newOwnerType,
043                Parameters parameters,
044                Map<String, LambdaInfo> recapturedLambdas
045        ) {
046            this.oldOwnerType = oldOwnerType;
047            this.newOwnerType = newOwnerType;
048            this.parameters = parameters;
049            this.recapturedLambdas = recapturedLambdas;
050        }
051    
052        @Override
053        public AbstractInsnNode doTransform(
054                MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField
055        ) {
056            boolean isRecaptured = isRecapturedLambdaType(fieldInsnNode.owner);
057    
058            if (!isRecaptured && capturedField.getLambda() != null) {
059                //strict inlining
060                return super.doTransform(node, fieldInsnNode, capturedField);
061            }
062    
063            AbstractInsnNode loadThis = getPreviousThis(fieldInsnNode);
064    
065            int opcode = Opcodes.GETSTATIC;
066    
067            String descriptor = Type.getObjectType(newOwnerType).getDescriptor();
068    
069            //HACK: it would be reverted again to ALOAD 0 later
070            FieldInsnNode thisStub = new FieldInsnNode(opcode, newOwnerType, "$$$this", descriptor);
071    
072            node.instructions.insertBefore(loadThis, thisStub);
073            node.instructions.remove(loadThis);
074    
075            fieldInsnNode.owner = newOwnerType;
076            fieldInsnNode.name = isRecaptured || capturedField.getRecapturedFrom() != null ? LambdaTransformer.getNewFieldName(capturedField.getFieldName()) : capturedField.getFieldName();
077    
078            return fieldInsnNode;
079        }
080    
081        @Override
082        public List<CapturedParamInfo> markRecaptured(List<CapturedParamInfo> originalCaptured, LambdaInfo lambda) {
083            List<CapturedParamInfo> captured = parameters.getCaptured();
084            for (CapturedParamInfo originalField : originalCaptured) {
085                for (CapturedParamInfo capturedParamInfo : captured) {
086                    if (capturedParamInfo.getRecapturedFrom() == lambda) {
087                        if (capturedParamInfo.getFieldName().equals(LambdaTransformer.getNewFieldName(originalField.getFieldName()))) {
088                            originalField.setRecapturedFrom(lambda);//just mark recaptured
089                        }
090                    }
091                }
092            }
093            return originalCaptured;
094        }
095    
096        @Override
097        public boolean canProcess(String owner, String currentLambdaType) {
098            return super.canProcess(owner, currentLambdaType) || isRecapturedLambdaType(owner);
099        }
100    
101        private boolean isRecapturedLambdaType(String owner) {
102            return recapturedLambdas.containsKey(owner);
103        }
104    
105        @Nullable
106        @Override
107        public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection<CapturedParamInfo> captured) {
108            if (isRecapturedLambdaType(fieldInsnNode.owner)) {
109                LambdaInfo info = recapturedLambdas.get(fieldInsnNode.owner);
110                return super.findField(fieldInsnNode, info.getCapturedVars());
111            }
112            else {
113                return super.findField(fieldInsnNode, captured);
114            }
115        }
116    }