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