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