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