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:
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.codegen.inline
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor
|
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -101,14 +100,6 @@ abstract class DefaultLambda(
|
|||||||
final override lateinit var invokeMethod: Method
|
final override lateinit var invokeMethod: Method
|
||||||
private set
|
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>
|
final override lateinit var capturedVars: List<CapturedParamDesc>
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -123,10 +114,10 @@ abstract class DefaultLambda(
|
|||||||
val isPropertyReference = superName in PROPERTY_REFERENCE_SUPER_CLASSES
|
val isPropertyReference = superName in PROPERTY_REFERENCE_SUPER_CLASSES
|
||||||
val isFunctionReference = superName == FUNCTION_REFERENCE.internalName || superName == FUNCTION_REFERENCE_IMPL.internalName
|
val isFunctionReference = superName == FUNCTION_REFERENCE.internalName || superName == FUNCTION_REFERENCE_IMPL.internalName
|
||||||
|
|
||||||
val descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
|
val constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
|
||||||
val constructor = getMethodNode(classBytes, "<init>", descriptor, lambdaClassType)?.node
|
val constructor = getMethodNode(classBytes, "<init>", constructorDescriptor, lambdaClassType)?.node
|
||||||
assert(constructor != null || capturedArgs.isEmpty()) {
|
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 =
|
capturedVars =
|
||||||
if (isFunctionReference || isPropertyReference)
|
if (isFunctionReference || isPropertyReference)
|
||||||
@@ -140,11 +131,12 @@ abstract class DefaultLambda(
|
|||||||
}?.toList() ?: emptyList()
|
}?.toList() ?: emptyList()
|
||||||
isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty()
|
isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty()
|
||||||
|
|
||||||
invokeMethodDescriptor = findInvokeMethodDescriptor(isPropertyReference)
|
val invokeName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString()
|
||||||
val methodName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString()
|
val invokeDescriptor = mapAsmDescriptor(sourceCompiler, isPropertyReference)
|
||||||
val signature = mapAsmSignature(sourceCompiler, invokeMethodDescriptor)
|
// TODO: `signatureAmbiguity = true` ignores the argument types from `invokeDescriptor` and only looks at the count.
|
||||||
node = getMethodNode(classBytes, methodName, signature.descriptor, lambdaClassType, signatureAmbiguity = true)
|
// This effectively masks incorrect results from `mapAsmDescriptor`, which hopefully won't manifest in another way.
|
||||||
?: error("Can't find method '$signature' in '${lambdaClassType.internalName}'")
|
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)
|
invokeMethod = Method(node.node.name, node.node.desc)
|
||||||
if (needReification) {
|
if (needReification) {
|
||||||
//nested classes could also require reification
|
//nested classes could also require reification
|
||||||
@@ -152,10 +144,7 @@ abstract class DefaultLambda(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun mapAsmSignature(sourceCompiler: SourceCompilerForInline, descriptor: FunctionDescriptor): Method
|
protected abstract fun mapAsmDescriptor(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): String
|
||||||
|
|
||||||
// TODO: get rid of this; descriptors should *only* be used by PsiDefaultLambda
|
|
||||||
protected abstract fun findInvokeMethodDescriptor(isPropertyReference: Boolean): FunctionDescriptor
|
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
val PROPERTY_REFERENCE_SUPER_CLASSES =
|
val PROPERTY_REFERENCE_SUPER_CLASSES =
|
||||||
|
|||||||
@@ -343,14 +343,22 @@ class PsiDefaultLambda(
|
|||||||
offset: Int,
|
offset: Int,
|
||||||
needReification: Boolean
|
needReification: Boolean
|
||||||
) : DefaultLambda(capturedArgs, parameterDescriptor.isCrossinline, offset, needReification) {
|
) : DefaultLambda(capturedArgs, parameterDescriptor.isCrossinline, offset, needReification) {
|
||||||
override fun mapAsmSignature(sourceCompiler: SourceCompilerForInline, descriptor: FunctionDescriptor): Method =
|
private lateinit var invokeMethodDescriptor: FunctionDescriptor
|
||||||
sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(descriptor).asmMethod
|
|
||||||
|
|
||||||
override fun findInvokeMethodDescriptor(isPropertyReference: Boolean): FunctionDescriptor =
|
override val invokeMethodParameters: List<KotlinType?>
|
||||||
parameterDescriptor.type.memberScope
|
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)
|
.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND)
|
||||||
.single().let {
|
.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
|
if (isPropertyReference) it.original else it
|
||||||
}
|
}
|
||||||
|
return sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-10
@@ -14,17 +14,16 @@ import org.jetbrains.kotlin.codegen.ValueKind
|
|||||||
import org.jetbrains.kotlin.codegen.inline.*
|
import org.jetbrains.kotlin.codegen.inline.*
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.descriptors.*
|
import org.jetbrains.kotlin.ir.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
@@ -234,18 +233,33 @@ class IrExpressionLambdaImpl(
|
|||||||
class IrDefaultLambda(
|
class IrDefaultLambda(
|
||||||
override val lambdaClassType: Type,
|
override val lambdaClassType: Type,
|
||||||
capturedArgs: Array<Type>,
|
capturedArgs: Array<Type>,
|
||||||
irValueParameter: IrValueParameter,
|
private val irValueParameter: IrValueParameter,
|
||||||
offset: Int,
|
offset: Int,
|
||||||
needReification: Boolean
|
needReification: Boolean
|
||||||
) : DefaultLambda(capturedArgs, irValueParameter.isCrossinline, offset, needReification) {
|
) : DefaultLambda(capturedArgs, irValueParameter.isCrossinline, offset, needReification) {
|
||||||
// TODO: this always produces an erased signature, but it should be non-erased if this isn't a property reference
|
private lateinit var typeArguments: List<IrType>
|
||||||
private val invoke = irValueParameter.type.classOrNull!!.owner.functions.single { it.name == OperatorNameConventions.INVOKE }
|
|
||||||
|
|
||||||
override fun mapAsmSignature(sourceCompiler: SourceCompilerForInline, descriptor: FunctionDescriptor): Method =
|
override val invokeMethodParameters: List<KotlinType>
|
||||||
(sourceCompiler as IrSourceCompilerForInline).codegen.context.methodSignatureMapper.mapSignatureSkipGeneric(invoke).asmMethod
|
get() = typeArguments.dropLast(1).map { it.toIrBasedKotlinType() }
|
||||||
|
|
||||||
override fun findInvokeMethodDescriptor(isPropertyReference: Boolean): FunctionDescriptor =
|
override val invokeMethodReturnType: KotlinType
|
||||||
invoke.toIrBasedDescriptor()
|
get() = typeArguments.last().toIrBasedKotlinType()
|
||||||
|
|
||||||
|
override fun mapAsmDescriptor(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): String {
|
||||||
|
val context = (sourceCompiler as IrSourceCompilerForInline).codegen.context
|
||||||
|
typeArguments = (irValueParameter.type as IrSimpleType).arguments.let {
|
||||||
|
// 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) {
|
||||||
|
List(it.size) { context.irBuiltIns.anyNType }
|
||||||
|
} else {
|
||||||
|
it.map { argument -> (argument as IrTypeProjection).type }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: while technically only the number of arguments here matters right now (see DefaultLambdaInfo.generateLambdaBody),
|
||||||
|
// it would be better to map to a non-erased signature if not a property reference.
|
||||||
|
return Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, *Array(typeArguments.size - 1) { AsmTypes.OBJECT_TYPE })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrExpression.isInlineIrExpression() =
|
fun IrExpression.isInlineIrExpression() =
|
||||||
|
|||||||
Reference in New Issue
Block a user