001 /*
002 * Copyright 2010-2013 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.jet.codegen.inline;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.jet.codegen.AsmUtil;
022 import org.jetbrains.jet.codegen.StackValue;
023 import org.jetbrains.jet.codegen.binding.CalculatedClosure;
024 import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
025 import org.jetbrains.jet.codegen.state.JetTypeMapper;
026 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
027 import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
028 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
029 import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
030 import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
031 import org.jetbrains.jet.lang.resolve.BindingContext;
032 import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
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.jet.codegen.binding.CodegenBinding.*;
042
043 public class LambdaInfo implements CapturedParamOwner, LabelOwner {
044
045 public final JetFunctionLiteralExpression expression;
046
047 @NotNull
048 private final JetTypeMapper typeMapper;
049
050 @Nullable
051 public final String labelName;
052
053 private final CalculatedClosure closure;
054
055 private MethodNode 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 JetFunctionLiteralExpression expression, @NotNull JetTypeMapper typeMapper, @Nullable String labelName) {
066 this.expression = expression;
067 this.typeMapper = typeMapper;
068 this.labelName = labelName;
069 BindingContext bindingContext = typeMapper.getBindingContext();
070 functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression.getFunctionLiteral());
071 assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
072
073 classDescriptor = anonymousClassForFunction(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 public MethodNode getNode() {
081 return node;
082 }
083
084 public void setNode(MethodNode node) {
085 this.node = node;
086 }
087
088 public FunctionDescriptor getFunctionDescriptor() {
089 return functionDescriptor;
090 }
091
092 public JetFunctionLiteral getFunctionLiteral() {
093 return expression.getFunctionLiteral();
094 }
095
096 public ClassDescriptor getClassDescriptor() {
097 return classDescriptor;
098 }
099
100 public Type getLambdaClassType() {
101 return closureClassType;
102 }
103
104 public List<CapturedParamDesc> getCapturedVars() {
105 //lazy initialization cause it would be calculated after object creation
106 if (capturedVars == null) {
107 capturedVars = new ArrayList<CapturedParamDesc>();
108
109 if (closure.getCaptureThis() != null) {
110 Type type = typeMapper.mapType(closure.getCaptureThis());
111 EnclosedValueDescriptor descriptor =
112 new EnclosedValueDescriptor(AsmUtil.CAPTURED_THIS_FIELD,
113 null,
114 StackValue.field(type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false,
115 StackValue.LOCAL_0),
116 type);
117 capturedVars.add(getCapturedParamInfo(descriptor));
118 }
119
120 if (closure.getCaptureReceiverType() != null) {
121 Type type = typeMapper.mapType(closure.getCaptureReceiverType());
122 EnclosedValueDescriptor descriptor =
123 new EnclosedValueDescriptor(
124 AsmUtil.CAPTURED_RECEIVER_FIELD,
125 null,
126 StackValue.field(type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false,
127 StackValue.LOCAL_0),
128 type);
129 capturedVars.add(getCapturedParamInfo(descriptor));
130 }
131
132 for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) {
133 capturedVars.add(getCapturedParamInfo(descriptor));
134 }
135 }
136 return capturedVars;
137 }
138
139 @NotNull
140 private CapturedParamDesc getCapturedParamInfo(@NotNull EnclosedValueDescriptor descriptor) {
141 return CapturedParamDesc.createDesc(this, descriptor.getFieldName(), descriptor.getType());
142 }
143
144 @NotNull
145 public List<Type> getInvokeParamsWithoutCaptured() {
146 Type[] types = typeMapper.mapSignature(functionDescriptor).getAsmMethod().getArgumentTypes();
147 return Arrays.asList(types);
148 }
149
150 @NotNull
151 public Parameters addAllParameters(FieldRemapper remapper) {
152 ParametersBuilder builder = ParametersBuilder.newBuilder();
153 //add skipped this cause inlined lambda doesn't have it
154 builder.addThis(AsmTypeConstants.OBJECT_TYPE, true).setLambda(this);
155
156 List<ValueParameterDescriptor> valueParameters = getFunctionDescriptor().getValueParameters();
157 for (ValueParameterDescriptor parameter : valueParameters) {
158 Type type = typeMapper.mapType(parameter.getType());
159 builder.addNextParameter(type, false, null);
160 }
161
162 for (CapturedParamDesc info : getCapturedVars()) {
163 CapturedParamInfo field = remapper.findField(new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), ""));
164 builder.addCapturedParam(field, info.getFieldName());
165 }
166
167 return builder.buildParameters();
168 }
169
170 @Override
171 public Type getType() {
172 return closureClassType;
173 }
174
175 @Override
176 public boolean isMyLabel(@NotNull String name) {
177 return name.equals(labelName);
178 }
179
180 }