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