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.org.objectweb.asm.Type;
022 import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
023 import org.jetbrains.org.objectweb.asm.tree.MethodNode;
024 import org.jetbrains.jet.codegen.AsmUtil;
025 import org.jetbrains.jet.codegen.binding.CalculatedClosure;
026 import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
027 import org.jetbrains.jet.codegen.state.JetTypeMapper;
028 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
029 import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
030 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
031 import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
032 import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
033 import org.jetbrains.jet.lang.resolve.BindingContext;
034 import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
035
036 import java.util.*;
037
038 import static org.jetbrains.jet.codegen.binding.CodegenBinding.CLOSURE;
039 import static org.jetbrains.jet.codegen.binding.CodegenBinding.anonymousClassForFunction;
040 import static org.jetbrains.jet.codegen.binding.CodegenBinding.asmTypeForAnonymousClass;
041
042 public class LambdaInfo implements CapturedParamOwner, LabelOwner {
043
044 public final JetFunctionLiteralExpression expression;
045
046 @NotNull
047 private final JetTypeMapper typeMapper;
048
049 @Nullable
050 public final String labelName;
051
052 public 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 EnclosedValueDescriptor descriptor = new EnclosedValueDescriptor(AsmUtil.CAPTURED_THIS_FIELD, null, null, typeMapper.mapType(closure.getCaptureThis()));
110 capturedVars.add(getCapturedParamInfo(descriptor));
111 }
112
113 if (closure.getCaptureReceiverType() != null) {
114 EnclosedValueDescriptor descriptor = new EnclosedValueDescriptor(AsmUtil.CAPTURED_RECEIVER_FIELD, null, null, typeMapper.mapType(closure.getCaptureReceiverType()));
115 capturedVars.add(getCapturedParamInfo(descriptor));
116 }
117
118 for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) {
119 capturedVars.add(getCapturedParamInfo(descriptor));
120 }
121 }
122 return capturedVars;
123 }
124
125 @NotNull
126 private CapturedParamDesc getCapturedParamInfo(@NotNull EnclosedValueDescriptor descriptor) {
127 return CapturedParamDesc.createDesc(this, descriptor.getFieldName(), descriptor.getType());
128 }
129
130 @NotNull
131 public List<Type> getInvokeParamsWithoutCaptured() {
132 Type[] types = typeMapper.mapSignature(functionDescriptor).getAsmMethod().getArgumentTypes();
133 return Arrays.asList(types);
134 }
135
136 @NotNull
137 public Parameters addAllParameters(FieldRemapper remapper) {
138 ParametersBuilder builder = ParametersBuilder.newBuilder();
139 //add skipped this cause inlined lambda doesn't have it
140 builder.addThis(AsmTypeConstants.OBJECT_TYPE, true).setLambda(this);
141
142 List<ValueParameterDescriptor> valueParameters = getFunctionDescriptor().getValueParameters();
143 for (ValueParameterDescriptor parameter : valueParameters) {
144 Type type = typeMapper.mapType(parameter.getType());
145 builder.addNextParameter(type, false, null);
146 }
147
148 for (CapturedParamDesc info : getCapturedVars()) {
149 CapturedParamInfo field = remapper.findField(new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), ""));
150 builder.addCapturedParam(field, info.getFieldName());
151 }
152
153 return builder.buildParameters();
154 }
155
156 @Override
157 public Type getType() {
158 return closureClassType;
159 }
160
161 @Override
162 public boolean isMyLabel(@NotNull String name) {
163 return name.equals(labelName);
164 }
165
166 }