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