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.KotlinTypeMapper;
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.KtLambdaExpression;
029    import org.jetbrains.kotlin.resolve.BindingContext;
030    import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
031    import org.jetbrains.org.objectweb.asm.Type;
032    import org.jetbrains.org.objectweb.asm.commons.Method;
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 LabelOwner {
043        public final KtExpression expression;
044        private final KotlinTypeMapper typeMapper;
045        public final Set<String> labels;
046        private final CalculatedClosure closure;
047        public final boolean isCrossInline;
048        private final FunctionDescriptor functionDescriptor;
049        private final ClassDescriptor classDescriptor;
050        private final Type closureClassType;
051    
052        private SMAPAndMethodNode node;
053        private List<CapturedParamDesc> capturedVars;
054    
055        public LambdaInfo(@NotNull KtExpression expression, @NotNull KotlinTypeMapper typeMapper, boolean isCrossInline) {
056            this.isCrossInline = isCrossInline;
057            this.expression = expression instanceof KtLambdaExpression ?
058                              ((KtLambdaExpression) expression).getFunctionLiteral() : expression;
059    
060            this.typeMapper = typeMapper;
061            BindingContext bindingContext = typeMapper.getBindingContext();
062            functionDescriptor = bindingContext.get(BindingContext.FUNCTION, this.expression);
063            assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
064    
065            classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor);
066            closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
067    
068            closure = bindingContext.get(CLOSURE, classDescriptor);
069            assert closure != null : "Closure for lambda should be not null " + expression.getText();
070    
071            labels = InlineCodegen.getDeclarationLabels(expression, functionDescriptor);
072        }
073    
074        @NotNull
075        public SMAPAndMethodNode getNode() {
076            return node;
077        }
078    
079        public void setNode(@NotNull SMAPAndMethodNode node) {
080            this.node = node;
081        }
082    
083        @NotNull
084        public FunctionDescriptor getFunctionDescriptor() {
085            return functionDescriptor;
086        }
087    
088        @NotNull
089        public KtExpression getFunctionWithBodyOrCallableReference() {
090            return expression;
091        }
092    
093        @NotNull
094        public ClassDescriptor getClassDescriptor() {
095            return classDescriptor;
096        }
097    
098        @NotNull
099        public Type getLambdaClassType() {
100            return closureClassType;
101        }
102    
103        @NotNull
104        public List<CapturedParamDesc> getCapturedVars() {
105            //lazy initialization cause it would be calculated after object creation
106            if (capturedVars == null) {
107                capturedVars = new ArrayList<CapturedParamDesc>();
108    
109                if (closure.getCaptureThis() != null) {
110                    Type type = typeMapper.mapType(closure.getCaptureThis());
111                    EnclosedValueDescriptor descriptor =
112                            new EnclosedValueDescriptor(
113                                    AsmUtil.CAPTURED_THIS_FIELD,
114                                    /* descriptor = */ null,
115                                    StackValue.field(type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0),
116                                    type
117                            );
118                    capturedVars.add(getCapturedParamInfo(descriptor));
119                }
120    
121                if (closure.getCaptureReceiverType() != null) {
122                    Type type = typeMapper.mapType(closure.getCaptureReceiverType());
123                    EnclosedValueDescriptor descriptor =
124                            new EnclosedValueDescriptor(
125                                    AsmUtil.CAPTURED_RECEIVER_FIELD,
126                                    /* descriptor = */ null,
127                                    StackValue.field(type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false, StackValue.LOCAL_0),
128                                    type
129                            );
130                    capturedVars.add(getCapturedParamInfo(descriptor));
131                }
132    
133                for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) {
134                    capturedVars.add(getCapturedParamInfo(descriptor));
135                }
136            }
137            return capturedVars;
138        }
139    
140        @NotNull
141        private CapturedParamDesc getCapturedParamInfo(@NotNull EnclosedValueDescriptor descriptor) {
142            return new CapturedParamDesc(closureClassType, descriptor.getFieldName(), descriptor.getType());
143        }
144    
145        @NotNull
146        public List<Type> getInvokeParamsWithoutCaptured() {
147            return Arrays.asList(typeMapper.mapAsmMethod(functionDescriptor).getArgumentTypes());
148        }
149    
150        @NotNull
151        public Parameters addAllParameters(@NotNull FieldRemapper remapper) {
152            Method asmMethod = typeMapper.mapAsmMethod(getFunctionDescriptor());
153            ParametersBuilder builder = ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, asmMethod.getDescriptor(), this);
154    
155            for (CapturedParamDesc info : getCapturedVars()) {
156                CapturedParamInfo field = remapper.findField(new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), ""));
157                assert field != null : "Captured field not found: " + info.getContainingLambdaName() + "." + info.getFieldName();
158                builder.addCapturedParam(field, info.getFieldName());
159            }
160    
161            return builder.buildParameters();
162        }
163    
164        @Override
165        public boolean isMyLabel(@NotNull String name) {
166            return labels.contains(name);
167        }
168    }