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 }