001    /*
002     * Copyright 2010-2015 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.kotlin.codegen.inline;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.codegen.AsmUtil;
022    import org.jetbrains.kotlin.codegen.StackValue;
023    import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
024    import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
025    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
026    import org.jetbrains.kotlin.descriptors.ClassDescriptor;
027    import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
028    import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
029    import org.jetbrains.kotlin.psi.JetFunctionLiteral;
030    import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression;
031    import org.jetbrains.kotlin.resolve.BindingContext;
032    import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
033    import org.jetbrains.org.objectweb.asm.Type;
034    import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
035    
036    import java.util.ArrayList;
037    import java.util.Arrays;
038    import java.util.List;
039    
040    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
041    
042    public class LambdaInfo implements CapturedParamOwner, LabelOwner {
043    
044        public final JetFunctionLiteralExpression expression;
045    
046        private final JetTypeMapper typeMapper;
047    
048        @Nullable
049        public final String labelName;
050    
051        private final CalculatedClosure closure;
052    
053        private SMAPAndMethodNode node;
054    
055        private List<CapturedParamDesc> capturedVars;
056    
057        private final FunctionDescriptor functionDescriptor;
058    
059        private final ClassDescriptor classDescriptor;
060    
061        private final Type closureClassType;
062    
063        LambdaInfo(@NotNull JetFunctionLiteralExpression expression, @NotNull JetTypeMapper typeMapper, @Nullable String labelName) {
064            this.expression = expression;
065            this.typeMapper = typeMapper;
066            this.labelName = labelName;
067            BindingContext bindingContext = typeMapper.getBindingContext();
068            functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression.getFunctionLiteral());
069            assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
070    
071            classDescriptor = anonymousClassForFunction(bindingContext, functionDescriptor);
072            closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
073    
074            closure = bindingContext.get(CLOSURE, classDescriptor);
075            assert closure != null : "Closure for lambda should be not null " + expression.getText();
076        }
077    
078        public SMAPAndMethodNode getNode() {
079            return node;
080        }
081    
082        public void setNode(SMAPAndMethodNode node) {
083            this.node = node;
084        }
085    
086        public FunctionDescriptor getFunctionDescriptor() {
087            return functionDescriptor;
088        }
089    
090        public JetFunctionLiteral getFunctionLiteral() {
091            return expression.getFunctionLiteral();
092        }
093    
094        public ClassDescriptor getClassDescriptor() {
095            return classDescriptor;
096        }
097    
098        public Type getLambdaClassType() {
099            return closureClassType;
100        }
101    
102        public List<CapturedParamDesc> getCapturedVars() {
103            //lazy initialization cause it would be calculated after object creation
104            if (capturedVars == null) {
105                capturedVars = new ArrayList<CapturedParamDesc>();
106    
107                if (closure.getCaptureThis() != null) {
108                    Type type = typeMapper.mapType(closure.getCaptureThis());
109                    EnclosedValueDescriptor descriptor =
110                            new EnclosedValueDescriptor(AsmUtil.CAPTURED_THIS_FIELD,
111                                                        null,
112                                                        StackValue.field(type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false,
113                                                                         StackValue.LOCAL_0),
114                                                        type);
115                    capturedVars.add(getCapturedParamInfo(descriptor));
116                }
117    
118                if (closure.getCaptureReceiverType() != null) {
119                    Type type = typeMapper.mapType(closure.getCaptureReceiverType());
120                    EnclosedValueDescriptor descriptor =
121                            new EnclosedValueDescriptor(
122                                    AsmUtil.CAPTURED_RECEIVER_FIELD,
123                                    null,
124                                    StackValue.field(type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false,
125                                                     StackValue.LOCAL_0),
126                                    type);
127                    capturedVars.add(getCapturedParamInfo(descriptor));
128                }
129    
130                for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) {
131                    capturedVars.add(getCapturedParamInfo(descriptor));
132                }
133            }
134            return capturedVars;
135        }
136    
137        @NotNull
138        private CapturedParamDesc getCapturedParamInfo(@NotNull EnclosedValueDescriptor descriptor) {
139            return CapturedParamDesc.createDesc(this, descriptor.getFieldName(), descriptor.getType());
140        }
141    
142        @NotNull
143        public List<Type> getInvokeParamsWithoutCaptured() {
144            Type[] types = typeMapper.mapSignature(functionDescriptor).getAsmMethod().getArgumentTypes();
145            return Arrays.asList(types);
146        }
147    
148        @NotNull
149        public Parameters addAllParameters(FieldRemapper remapper) {
150            ParametersBuilder builder = ParametersBuilder.newBuilder();
151            //add skipped this cause inlined lambda doesn't have it
152            builder.addThis(AsmTypes.OBJECT_TYPE, true).setLambda(this);
153    
154            List<ValueParameterDescriptor> valueParameters = getFunctionDescriptor().getValueParameters();
155            for (ValueParameterDescriptor parameter : valueParameters) {
156                Type type = typeMapper.mapType(parameter.getType());
157                builder.addNextParameter(type, false, null);
158            }
159    
160            for (CapturedParamDesc info : getCapturedVars()) {
161                CapturedParamInfo field = remapper.findField(new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), ""));
162                builder.addCapturedParam(field, info.getFieldName());
163            }
164    
165            return builder.buildParameters();
166        }
167    
168        @Override
169        public Type getType() {
170            return closureClassType;
171        }
172    
173        @Override
174        public boolean isMyLabel(@NotNull String name) {
175            return name.equals(labelName);
176        }
177    
178    }