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