From 9c51392affc7ed33b5df5b0746a64551928e0da9 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Thu, 4 May 2017 11:01:00 +0200 Subject: [PATCH] Convert LambdaInfo.java to Kotlin --- .../kotlin/codegen/inline/InlineCodegen.java | 3 +- .../kotlin/codegen/inline/LambdaInfo.kt | 271 +++++++----------- .../kotlin/codegen/inline/Parameters.kt | 2 +- 3 files changed, 107 insertions(+), 169 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index ada65496c16..e2401dac24c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -575,7 +575,8 @@ public class InlineCodegen extends CallGenerator { Type asmType = state.getTypeMapper().mapClass(lambdaInfo.getClassDescriptor()); PropertyReferenceInfo info = lambdaInfo.getPropertyReferenceInfo(); strategy = new PropertyReferenceCodegen.PropertyReferenceGenerationStrategy( - true, info.getGetFunction(), info.getTarget(), asmType, receiverType, lambdaInfo.expression, state, true); + true, info.getGetFunction(), info.getTarget(), asmType, receiverType, + lambdaInfo.getFunctionWithBodyOrCallableReference(), state, true); } else { strategy = new FunctionReferenceGenerationStrategy( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt index 241fdc58dc7..3cb8c16d755 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt @@ -14,191 +14,128 @@ * limitations under the License. */ -package org.jetbrains.kotlin.codegen.inline; +package org.jetbrains.kotlin.codegen.inline -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.codegen.AsmUtil; -import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen; -import org.jetbrains.kotlin.codegen.StackValue; -import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; -import org.jetbrains.kotlin.codegen.binding.CodegenBinding; -import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor; -import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; -import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.psi.KtCallableReferenceExpression; -import org.jetbrains.kotlin.psi.KtExpression; -import org.jetbrains.kotlin.psi.KtLambdaExpression; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.jvm.AsmTypes; -import org.jetbrains.org.objectweb.asm.Type; -import org.jetbrains.org.objectweb.asm.commons.Method; -import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode; +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen +import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.codegen.binding.CalculatedClosure +import org.jetbrains.kotlin.codegen.binding.CodegenBinding +import org.jetbrains.kotlin.codegen.binding.CodegenBinding.* +import org.jetbrains.kotlin.codegen.binding.MutableClosure +import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.psi.KtCallableReferenceExpression +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtLambdaExpression +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert +import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode +import java.util.* -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; +class LambdaInfo( + expression: KtExpression, + private val typeMapper: KotlinTypeMapper, + @JvmField val isCrossInline: Boolean, + val isBoundCallableReference: Boolean +) : LabelOwner { + val functionWithBodyOrCallableReference: KtExpression = (expression as? KtLambdaExpression)?.functionLiteral ?: expression -import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*; + val labels: Set + private lateinit var closure: CalculatedClosure + val functionDescriptor: FunctionDescriptor + val classDescriptor: ClassDescriptor + val lambdaClassType: Type -public class LambdaInfo implements LabelOwner { - public final KtExpression expression; - private final KotlinTypeMapper typeMapper; - public final Set labels; - private final CalculatedClosure closure; - public final boolean isCrossInline; - private final FunctionDescriptor functionDescriptor; - private final ClassDescriptor classDescriptor; - private final Type closureClassType; + var node: SMAPAndMethodNode? = null + val propertyReferenceInfo: PropertyReferenceInfo? - private SMAPAndMethodNode node; - private List capturedVars; - private final boolean isBoundCallableReference; - private final PropertyReferenceInfo propertyReferenceInfo; - - public LambdaInfo(@NotNull KtExpression expression, @NotNull KotlinTypeMapper typeMapper, boolean isCrossInline, boolean isBoundCallableReference) { - this.isCrossInline = isCrossInline; - this.expression = expression instanceof KtLambdaExpression ? - ((KtLambdaExpression) expression).getFunctionLiteral() : expression; - - this.typeMapper = typeMapper; - this.isBoundCallableReference = isBoundCallableReference; - BindingContext bindingContext = typeMapper.getBindingContext(); - FunctionDescriptor function = bindingContext.get(BindingContext.FUNCTION, this.expression); - if (function == null && expression instanceof KtCallableReferenceExpression) { - VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, this.expression); - assert variableDescriptor instanceof VariableDescriptorWithAccessors : - "Reference expression not resolved to variable descriptor with accessors: " + expression.getText(); - classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor); - closureClassType = typeMapper.mapClass(classDescriptor); - SimpleFunctionDescriptor getFunction = PropertyReferenceCodegen.findGetFunction(variableDescriptor); - functionDescriptor = PropertyReferenceCodegen.createFakeOpenDescriptor(getFunction, classDescriptor); - ResolvedCall resolvedCall = CallUtilKt.getResolvedCallWithAssert(((KtCallableReferenceExpression) expression).getCallableReference(), bindingContext); - propertyReferenceInfo = new PropertyReferenceInfo( - (VariableDescriptor) resolvedCall.getResultingDescriptor(), getFunction - ); + init { + val bindingContext = typeMapper.bindingContext + val function = bindingContext.get(BindingContext.FUNCTION, this.functionWithBodyOrCallableReference) + if (function == null && expression is KtCallableReferenceExpression) { + val variableDescriptor = bindingContext.get(BindingContext.VARIABLE, this.functionWithBodyOrCallableReference) + assert(variableDescriptor is VariableDescriptorWithAccessors) { "Reference expression not resolved to variable descriptor with accessors: " + expression.getText() } + classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor!!) + lambdaClassType = typeMapper.mapClass(classDescriptor) + val getFunction = PropertyReferenceCodegen.findGetFunction(variableDescriptor) + functionDescriptor = PropertyReferenceCodegen.createFakeOpenDescriptor(getFunction, classDescriptor) + val resolvedCall = expression.callableReference.getResolvedCallWithAssert(bindingContext) + propertyReferenceInfo = PropertyReferenceInfo( + resolvedCall.resultingDescriptor as VariableDescriptor, getFunction + ) } else { - propertyReferenceInfo = null; - functionDescriptor = function; - assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText(); - classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor); - closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor); + propertyReferenceInfo = null + assert(function != null) { "Function is not resolved to descriptor: " + expression.text } + functionDescriptor = function!! + classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor) + lambdaClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor) } - - closure = bindingContext.get(CLOSURE, classDescriptor); - assert closure != null : "Closure for lambda should be not null " + expression.getText(); - - labels = InlineCodegen.getDeclarationLabels(expression, functionDescriptor); - } - - @NotNull - public SMAPAndMethodNode getNode() { - return node; - } - - public void setNode(@NotNull SMAPAndMethodNode node) { - this.node = node; - } - - @NotNull - public FunctionDescriptor getFunctionDescriptor() { - return functionDescriptor; - } - - @NotNull - public KtExpression getFunctionWithBodyOrCallableReference() { - return expression; - } - - @NotNull - public ClassDescriptor getClassDescriptor() { - return classDescriptor; - } - - @NotNull - public Type getLambdaClassType() { - return closureClassType; - } - - @NotNull - public List getCapturedVars() { - //lazy initialization cause it would be calculated after object creation - if (capturedVars == null) { - capturedVars = new ArrayList<>(); - - if (closure.getCaptureThis() != null) { - Type type = typeMapper.mapType(closure.getCaptureThis()); - EnclosedValueDescriptor descriptor = - new EnclosedValueDescriptor( - AsmUtil.CAPTURED_THIS_FIELD, - /* descriptor = */ null, - StackValue.field(type, closureClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0), - type - ); - capturedVars.add(getCapturedParamInfo(descriptor)); - } - - if (closure.getCaptureReceiverType() != null) { - Type type = typeMapper.mapType(closure.getCaptureReceiverType()); - EnclosedValueDescriptor descriptor = - new EnclosedValueDescriptor( - AsmUtil.CAPTURED_RECEIVER_FIELD, - /* descriptor = */ null, - StackValue.field(type, closureClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false, StackValue.LOCAL_0), - type - ); - capturedVars.add(getCapturedParamInfo(descriptor)); - } - - for (EnclosedValueDescriptor descriptor : closure.getCaptureVariables().values()) { - capturedVars.add(getCapturedParamInfo(descriptor)); - } - } - return capturedVars; - } - - @NotNull - private CapturedParamDesc getCapturedParamInfo(@NotNull EnclosedValueDescriptor descriptor) { - return new CapturedParamDesc(closureClassType, descriptor.getFieldName(), descriptor.getType()); - } - - @NotNull - public List getInvokeParamsWithoutCaptured() { - return Arrays.asList(typeMapper.mapAsmMethod(functionDescriptor).getArgumentTypes()); - } - - @NotNull - public Parameters addAllParameters(@NotNull FieldRemapper remapper) { - Method asmMethod = typeMapper.mapAsmMethod(getFunctionDescriptor()); - ParametersBuilder builder = ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, asmMethod.getDescriptor(), this); - - for (CapturedParamDesc info : getCapturedVars()) { - CapturedParamInfo field = remapper.findField(new FieldInsnNode(0, info.getContainingLambdaName(), info.getFieldName(), "")); - assert field != null : "Captured field not found: " + info.getContainingLambdaName() + "." + info.getFieldName(); - builder.addCapturedParam(field, info.getFieldName()); + bindingContext.get(CLOSURE, classDescriptor).let { + assert(it != null) { "Closure for lambda should be not null " + expression.text } + closure = it!! } - return builder.buildParameters(); + labels = InlineCodegen.getDeclarationLabels(expression, functionDescriptor) } - @Override - public boolean isMyLabel(@NotNull String name) { - return labels.contains(name); + val capturedVars: List by lazy { + arrayListOf().apply { + if (closure.captureThis != null) { + val type = typeMapper.mapType(closure.captureThis!!) + val descriptor = EnclosedValueDescriptor( + AsmUtil.CAPTURED_THIS_FIELD, null, + StackValue.field(type, lambdaClassType, AsmUtil.CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0), + type + ) + add(getCapturedParamInfo(descriptor)) + } + + if (closure.captureReceiverType != null) { + val type = typeMapper.mapType(closure.captureReceiverType!!) + val descriptor = EnclosedValueDescriptor( + AsmUtil.CAPTURED_RECEIVER_FIELD, null, + StackValue.field(type, lambdaClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false, StackValue.LOCAL_0), + type + ) + add(getCapturedParamInfo(descriptor)) + } + + closure.captureVariables.values.forEach { + descriptor -> add(getCapturedParamInfo(descriptor)) + } + } } - public boolean isBoundCallableReference() { - return isBoundCallableReference; + private fun getCapturedParamInfo(descriptor: EnclosedValueDescriptor): CapturedParamDesc { + return CapturedParamDesc(lambdaClassType, descriptor.fieldName, descriptor.type) } - public boolean isPropertyReference() { - return propertyReferenceInfo != null; + val invokeParamsWithoutCaptured: List + get() = Arrays.asList(*typeMapper.mapAsmMethod(functionDescriptor).argumentTypes) + + fun addAllParameters(remapper: FieldRemapper): Parameters { + val asmMethod = typeMapper.mapAsmMethod(functionDescriptor) + val builder = ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, asmMethod.descriptor, this) + + for (info in capturedVars) { + val field = remapper.findField(FieldInsnNode(0, info.containingLambdaName, info.fieldName, "")) ?: error("Captured field not found: " + info.containingLambdaName + "." + info.fieldName) + builder.addCapturedParam(field, info.fieldName) + } + + return builder.buildParameters() } - public PropertyReferenceInfo getPropertyReferenceInfo() { - return propertyReferenceInfo; + override fun isMyLabel(name: String): Boolean { + return labels.contains(name) } + + val isPropertyReference: Boolean + get() = propertyReferenceInfo != null } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/Parameters.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/Parameters.kt index 2e411b19b89..f7280f588f1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/Parameters.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/Parameters.kt @@ -19,7 +19,7 @@ package org.jetbrains.kotlin.codegen.inline import org.jetbrains.org.objectweb.asm.Type import java.util.* -internal class Parameters(val parameters: List) : Iterable { +class Parameters(val parameters: List) : Iterable { private val actualDeclShifts: Array private val paramToDeclByteCodeIndex: HashMap = hashMapOf()