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