JVM: move descriptors from DefaultLambda to PsiDefaultLambda

Also, produce more correct results in IrDefaultLambda's
`invokeMethodParameters` and `invokeMethodReturnType`. This affects
whether the inliner inserts inline class boxings/unboxings around lambda
calls; while this doesn't matter now due to KT-46601, it would if the
naming was fixed.
This commit is contained in:
pyos
2021-05-11 14:12:00 +02:00
committed by max-kammerer
parent 7c168d663a
commit c32ccbb39a
3 changed files with 47 additions and 36 deletions
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -101,14 +100,6 @@ abstract class DefaultLambda(
final override lateinit var invokeMethod: Method
private set
private lateinit var invokeMethodDescriptor: FunctionDescriptor
override val invokeMethodParameters: List<KotlinType?>
get() = invokeMethodDescriptor.valueParameters.map { it.returnType }
override val invokeMethodReturnType: KotlinType?
get() = invokeMethodDescriptor.returnType
final override lateinit var capturedVars: List<CapturedParamDesc>
private set
@@ -123,10 +114,10 @@ abstract class DefaultLambda(
val isPropertyReference = superName in PROPERTY_REFERENCE_SUPER_CLASSES
val isFunctionReference = superName == FUNCTION_REFERENCE.internalName || superName == FUNCTION_REFERENCE_IMPL.internalName
val descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
val constructor = getMethodNode(classBytes, "<init>", descriptor, lambdaClassType)?.node
val constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
val constructor = getMethodNode(classBytes, "<init>", constructorDescriptor, lambdaClassType)?.node
assert(constructor != null || capturedArgs.isEmpty()) {
"Can't find non-default constructor <init>$descriptor for default lambda $lambdaClassType"
"Can't find non-default constructor <init>$constructorDescriptor for default lambda $lambdaClassType"
}
capturedVars =
if (isFunctionReference || isPropertyReference)
@@ -140,11 +131,12 @@ abstract class DefaultLambda(
}?.toList() ?: emptyList()
isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty()
invokeMethodDescriptor = findInvokeMethodDescriptor(isPropertyReference)
val methodName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString()
val signature = mapAsmSignature(sourceCompiler, invokeMethodDescriptor)
node = getMethodNode(classBytes, methodName, signature.descriptor, lambdaClassType, signatureAmbiguity = true)
?: error("Can't find method '$signature' in '${lambdaClassType.internalName}'")
val invokeName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString()
val invokeDescriptor = mapAsmDescriptor(sourceCompiler, isPropertyReference)
// TODO: `signatureAmbiguity = true` ignores the argument types from `invokeDescriptor` and only looks at the count.
// This effectively masks incorrect results from `mapAsmDescriptor`, which hopefully won't manifest in another way.
node = getMethodNode(classBytes, invokeName, invokeDescriptor, lambdaClassType, signatureAmbiguity = true)
?: error("Can't find method '$invokeName$invokeDescriptor' in '${lambdaClassType.internalName}'")
invokeMethod = Method(node.node.name, node.node.desc)
if (needReification) {
//nested classes could also require reification
@@ -152,10 +144,7 @@ abstract class DefaultLambda(
}
}
protected abstract fun mapAsmSignature(sourceCompiler: SourceCompilerForInline, descriptor: FunctionDescriptor): Method
// TODO: get rid of this; descriptors should *only* be used by PsiDefaultLambda
protected abstract fun findInvokeMethodDescriptor(isPropertyReference: Boolean): FunctionDescriptor
protected abstract fun mapAsmDescriptor(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): String
private companion object {
val PROPERTY_REFERENCE_SUPER_CLASSES =
@@ -343,14 +343,22 @@ class PsiDefaultLambda(
offset: Int,
needReification: Boolean
) : DefaultLambda(capturedArgs, parameterDescriptor.isCrossinline, offset, needReification) {
override fun mapAsmSignature(sourceCompiler: SourceCompilerForInline, descriptor: FunctionDescriptor): Method =
sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(descriptor).asmMethod
private lateinit var invokeMethodDescriptor: FunctionDescriptor
override fun findInvokeMethodDescriptor(isPropertyReference: Boolean): FunctionDescriptor =
parameterDescriptor.type.memberScope
override val invokeMethodParameters: List<KotlinType?>
get() = invokeMethodDescriptor.explicitParameters.map { it.returnType }
override val invokeMethodReturnType: KotlinType?
get() = invokeMethodDescriptor.returnType
override fun mapAsmDescriptor(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): String {
invokeMethodDescriptor = parameterDescriptor.type.memberScope
.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND)
.single().let {
// property reference generates erased 'get' method
// Property references only have an erased `get` method, while function references and lambdas
// have a non-erased `invoke` with an erased synthetic bridge, and we want to inline the former.
if (isPropertyReference) it.original else it
}
return sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
}
}