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.PropertyReferenceCodegen;
022    import org.jetbrains.kotlin.codegen.StackValue;
023    import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
024    import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
025    import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
026    import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
027    import org.jetbrains.kotlin.descriptors.*;
028    import org.jetbrains.kotlin.psi.KtCallableReferenceExpression;
029    import org.jetbrains.kotlin.psi.KtExpression;
030    import org.jetbrains.kotlin.psi.KtLambdaExpression;
031    import org.jetbrains.kotlin.resolve.BindingContext;
032    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
033    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
034    import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
035    import org.jetbrains.org.objectweb.asm.Type;
036    import org.jetbrains.org.objectweb.asm.commons.Method;
037    import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
038    
039    import java.util.ArrayList;
040    import java.util.Arrays;
041    import java.util.List;
042    import java.util.Set;
043    
044    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
045    
046    public class LambdaInfo implements LabelOwner {
047        public final KtExpression expression;
048        private final KotlinTypeMapper typeMapper;
049        public final Set<String> labels;
050        private final CalculatedClosure closure;
051        public final boolean isCrossInline;
052        private final FunctionDescriptor functionDescriptor;
053        private final ClassDescriptor classDescriptor;
054        private final Type closureClassType;
055    
056        private SMAPAndMethodNode node;
057        private List<CapturedParamDesc> capturedVars;
058        private final boolean isBoundCallableReference;
059        private final PropertyReferenceInfo propertyReferenceInfo;
060    
061        public LambdaInfo(@NotNull KtExpression expression, @NotNull KotlinTypeMapper typeMapper, boolean isCrossInline, boolean isBoundCallableReference) {
062            this.isCrossInline = isCrossInline;
063            this.expression = expression instanceof KtLambdaExpression ?
064                              ((KtLambdaExpression) expression).getFunctionLiteral() : expression;
065    
066            this.typeMapper = typeMapper;
067            this.isBoundCallableReference = isBoundCallableReference;
068            BindingContext bindingContext = typeMapper.getBindingContext();
069            FunctionDescriptor function = bindingContext.get(BindingContext.FUNCTION, this.expression);
070            if (function == null && expression instanceof KtCallableReferenceExpression) {
071                VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, this.expression);
072                assert variableDescriptor instanceof VariableDescriptorWithAccessors :
073                        "Reference expression not resolved to variable descriptor with accessors: " + expression.getText();
074                classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
075                closureClassType = typeMapper.mapClass(classDescriptor);
076                SimpleFunctionDescriptor getFunction = PropertyReferenceCodegen.findGetFunction(variableDescriptor);
077                functionDescriptor = PropertyReferenceCodegen.createFakeOpenDescriptor(getFunction, classDescriptor);
078                ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(((KtCallableReferenceExpression) expression).getCallableReference(), bindingContext);
079                propertyReferenceInfo = new PropertyReferenceInfo(
080                        (VariableDescriptor) resolvedCall.getResultingDescriptor(), getFunction
081                );
082            }
083            else {
084                propertyReferenceInfo = null;
085                functionDescriptor = function;
086                assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
087                classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor);
088                closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
089            }
090    
091    
092            closure = bindingContext.get(CLOSURE, classDescriptor);
093            assert closure != null : "Closure for lambda should be not null " + expression.getText();
094    
095            labels = InlineCodegen.getDeclarationLabels(expression, functionDescriptor);
096        }
097    
098        @NotNull
099        public SMAPAndMethodNode getNode() {
100            return node;
101        }
102    
103        public void setNode(@NotNull SMAPAndMethodNode node) {
104            this.node = node;
105        }
106    
107        @NotNull
108        public FunctionDescriptor getFunctionDescriptor() {
109            return functionDescriptor;
110        }
111    
112        @NotNull
113        public KtExpression getFunctionWithBodyOrCallableReference() {
114            return expression;
115        }
116    
117        @NotNull
118        public ClassDescriptor getClassDescriptor() {
119            return classDescriptor;
120        }
121    
122        @NotNull
123        public Type getLambdaClassType() {
124            return closureClassType;
125        }
126    
127        @NotNull
128        public List<CapturedParamDesc> getCapturedVars() {
129            //lazy initialization cause it would be calculated after object creation
130            if (capturedVars == null) {
131                capturedVars = new ArrayList<CapturedParamDesc>();
132    
133                if (closure.getCaptureThis() != null) {
134                    Type type = typeMapper.mapType(closure.getCaptureThis());
135                    EnclosedValueDescriptor descriptor =
136                            new EnclosedValueDescriptor(
137                                    AsmUtil.CAPTURED_THIS_FIELD,
138                                    /* descriptor = */ null,
139                                    StackValue.field(type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0),
140                                    type
141                            );
142                    capturedVars.add(getCapturedParamInfo(descriptor));
143                }
144    
145                if (closure.getCaptureReceiverType() != null) {
146                    Type type = typeMapper.mapType(closure.getCaptureReceiverType());
147                    EnclosedValueDescriptor descriptor =
148                            new EnclosedValueDescriptor(
149                                    AsmUtil.CAPTURED_RECEIVER_FIELD,
150                                    /* descriptor = */ null,
151                                    StackValue.field(type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false, StackValue.LOCAL_0),
152                                    type
153                            );
154                    capturedVars.add(getCapturedParamInfo(descriptor));
155                }
156    
157                for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) {
158                    capturedVars.add(getCapturedParamInfo(descriptor));
159                }
160            }
161            return capturedVars;
162        }
163    
164        @NotNull
165        private CapturedParamDesc getCapturedParamInfo(@NotNull EnclosedValueDescriptor descriptor) {
166            return new CapturedParamDesc(closureClassType, descriptor.getFieldName(), descriptor.getType());
167        }
168    
169        @NotNull
170        public List<Type> getInvokeParamsWithoutCaptured() {
171            return Arrays.asList(typeMapper.mapAsmMethod(functionDescriptor).getArgumentTypes());
172        }
173    
174        @NotNull
175        public Parameters addAllParameters(@NotNull FieldRemapper remapper) {
176            Method asmMethod = typeMapper.mapAsmMethod(getFunctionDescriptor());
177            ParametersBuilder builder = ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, asmMethod.getDescriptor(), this);
178    
179            for (CapturedParamDesc info : getCapturedVars()) {
180                CapturedParamInfo field = remapper.findField(new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), ""));
181                assert field != null : "Captured field not found: " + info.getContainingLambdaName() + "." + info.getFieldName();
182                builder.addCapturedParam(field, info.getFieldName());
183            }
184    
185            return builder.buildParameters();
186        }
187    
188        @Override
189        public boolean isMyLabel(@NotNull String name) {
190            return labels.contains(name);
191        }
192    
193        public boolean isBoundCallableReference() {
194            return isBoundCallableReference;
195        }
196    
197        public boolean isPropertyReference() {
198            return propertyReferenceInfo != null;
199        }
200    
201        public PropertyReferenceInfo getPropertyReferenceInfo() {
202            return propertyReferenceInfo;
203        }
204    }