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    import org.jetbrains.org.objectweb.asm.tree.MethodNode;
036    
037    import java.util.ArrayList;
038    import java.util.Arrays;
039    import java.util.List;
040    
041    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
042    
043    public class LambdaInfo implements CapturedParamOwner, LabelOwner {
044    
045        public final JetFunctionLiteralExpression expression;
046    
047        private final JetTypeMapper typeMapper;
048    
049        @Nullable
050        public final String labelName;
051    
052        private final CalculatedClosure closure;
053    
054        private MethodNode node;
055    
056        private List<CapturedParamDesc> capturedVars;
057    
058        private final FunctionDescriptor functionDescriptor;
059    
060        private final ClassDescriptor classDescriptor;
061    
062        private final Type closureClassType;
063    
064        LambdaInfo(@NotNull JetFunctionLiteralExpression expression, @NotNull JetTypeMapper typeMapper, @Nullable String labelName) {
065            this.expression = expression;
066            this.typeMapper = typeMapper;
067            this.labelName = labelName;
068            BindingContext bindingContext = typeMapper.getBindingContext();
069            functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression.getFunctionLiteral());
070            assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
071    
072            classDescriptor = anonymousClassForFunction(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        public MethodNode getNode() {
080            return node;
081        }
082    
083        public void setNode(MethodNode node) {
084            this.node = node;
085        }
086    
087        public FunctionDescriptor getFunctionDescriptor() {
088            return functionDescriptor;
089        }
090    
091        public JetFunctionLiteral getFunctionLiteral() {
092            return expression.getFunctionLiteral();
093        }
094    
095        public ClassDescriptor getClassDescriptor() {
096            return classDescriptor;
097        }
098    
099        public Type getLambdaClassType() {
100            return closureClassType;
101        }
102    
103        public List<CapturedParamDesc> getCapturedVars() {
104            //lazy initialization cause it would be calculated after object creation
105            if (capturedVars == null) {
106                capturedVars = new ArrayList<CapturedParamDesc>();
107    
108                if (closure.getCaptureThis() != null) {
109                    Type type = typeMapper.mapType(closure.getCaptureThis());
110                    EnclosedValueDescriptor descriptor =
111                            new EnclosedValueDescriptor(AsmUtil.CAPTURED_THIS_FIELD,
112                                                        null,
113                                                        StackValue.field(type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false,
114                                                                         StackValue.LOCAL_0),
115                                                        type);
116                    capturedVars.add(getCapturedParamInfo(descriptor));
117                }
118    
119                if (closure.getCaptureReceiverType() != null) {
120                    Type type = typeMapper.mapType(closure.getCaptureReceiverType());
121                    EnclosedValueDescriptor descriptor =
122                            new EnclosedValueDescriptor(
123                                    AsmUtil.CAPTURED_RECEIVER_FIELD,
124                                    null,
125                                    StackValue.field(type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false,
126                                                     StackValue.LOCAL_0),
127                                    type);
128                    capturedVars.add(getCapturedParamInfo(descriptor));
129                }
130    
131                for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) {
132                    capturedVars.add(getCapturedParamInfo(descriptor));
133                }
134            }
135            return capturedVars;
136        }
137    
138        @NotNull
139        private CapturedParamDesc getCapturedParamInfo(@NotNull EnclosedValueDescriptor descriptor) {
140            return CapturedParamDesc.createDesc(this, descriptor.getFieldName(), descriptor.getType());
141        }
142    
143        @NotNull
144        public List<Type> getInvokeParamsWithoutCaptured() {
145            Type[] types = typeMapper.mapSignature(functionDescriptor).getAsmMethod().getArgumentTypes();
146            return Arrays.asList(types);
147        }
148    
149        @NotNull
150        public Parameters addAllParameters(FieldRemapper remapper) {
151            ParametersBuilder builder = ParametersBuilder.newBuilder();
152            //add skipped this cause inlined lambda doesn't have it
153            builder.addThis(AsmTypes.OBJECT_TYPE, true).setLambda(this);
154    
155            List<ValueParameterDescriptor> valueParameters = getFunctionDescriptor().getValueParameters();
156            for (ValueParameterDescriptor parameter : valueParameters) {
157                Type type = typeMapper.mapType(parameter.getType());
158                builder.addNextParameter(type, false, null);
159            }
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 name.equals(labelName);
177        }
178    
179    }