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