JVM IR: improve generation of receiver for bound callable references

Trick codegen into generating getfield from the anonymous class instead
of its supertype (e.g. kotlin.jvm.internal.FunctionReference,
PropertyReference or AdaptedFunctionReference). This gets rid of
unnecessary accessors in some cases, and will help in the subsequent
commit that changes logic around access to fields from Java
superclasses.
This commit is contained in:
Alexander Udalov
2023-02-10 13:39:38 +01:00
parent 4ad594a3cd
commit 641d636c45
4 changed files with 20 additions and 8 deletions
@@ -570,8 +570,6 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
return fakeTypeParameters
}
private val receiverField = context.ir.symbols.functionReferenceReceiverField.owner
fun build(): IrExpression = context.createJvmIrBuilder(currentScope!!).run {
irBlock(irFunctionReference.startOffset, irFunctionReference.endOffset) {
val constructor = createConstructor()
@@ -826,7 +824,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
irImplicitCast(
irGetField(
irGet(dispatchReceiverParameter!!),
this@FunctionReferenceBuilder.receiverField
functionReferenceClass.getReceiverField(backendContext)
),
boundReceiver.second.type
)
@@ -1010,5 +1008,18 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
internal fun JvmIrBuilder.calculateOwnerKClass(irContainer: IrDeclarationParent): IrExpression =
kClassReference(irContainer.getCallableReferenceOwnerKClassType(backendContext))
// This method creates an IrField for the field `kotlin.jvm.internal.CallableReference.receiver`, as if this field was declared
// in the anonymous class for this callable reference. Technically it's incorrect because this field is not declared here. It would
// be more correct to create a fake override but that seems like more work for no clear benefit. Codegen will generate the correct
// field access anyway, even if the field is not present in this parent.
internal fun IrClass.getReceiverField(context: JvmBackendContext): IrField =
context.irFactory.buildField {
name = Name.identifier("receiver")
type = context.irBuiltIns.anyNType
visibility = DescriptorVisibilities.PROTECTED
}.apply {
parent = this@getReceiverField
}
}
}
@@ -413,7 +413,6 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
}
val boundReceiver = expression.getBoundReceiver()
val backingField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!!
val get = superClass.functions.find { it.name.asString() == "get" }
val set = superClass.functions.find { it.name.asString() == "set" }
val invoke = superClass.functions.find { it.name.asString() == "invoke" }
@@ -421,6 +420,8 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
val field = expression.field?.owner
if (field == null) {
fun IrBuilderWithScope.setCallArguments(call: IrCall, arguments: List<IrValueParameter>) {
val backingField =
with(FunctionReferenceLowering) { referenceClass.getReceiverField(this@PropertyReferenceLowering.context) }
val receiverFromField = boundReceiver?.let { irImplicitCast(irGetField(irGet(arguments[0]), backingField), it.type) }
if (expression.isJavaSyntheticPropertyReference) {
assert(call.typeArgumentsCount == 0) { "Unexpected type arguments: ${call.typeArgumentsCount}" }
@@ -458,8 +459,11 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
fun IrBuilderWithScope.fieldReceiver(arguments: List<IrValueParameter>) = when {
field.isStatic ->
null
expression.dispatchReceiver != null ->
expression.dispatchReceiver != null -> {
val backingField =
with(FunctionReferenceLowering) { referenceClass.getReceiverField(this@PropertyReferenceLowering.context) }
irImplicitCast(irGetField(irGet(arguments[0]), backingField), expression.receiverType)
}
else ->
irImplicitCast(irGet(arguments[1]), expression.receiverType)
}
@@ -371,7 +371,6 @@ class JvmSymbols(
generateCallableReferenceMethods(klass)
}
val functionReferenceReceiverField: IrFieldSymbol = functionReference.fieldByName("receiver")
val functionReferenceGetSignature: IrSimpleFunctionSymbol = functionReference.functionByName("getSignature")
val functionReferenceGetName: IrSimpleFunctionSymbol = functionReference.functionByName("getName")
val functionReferenceGetOwner: IrSimpleFunctionSymbol = functionReference.functionByName("getOwner")
@@ -4,7 +4,6 @@ synthetic final class A$testDefaultArguments$1 {
enclosing method A.testDefaultArguments()V
inner (anonymous) class A$testDefaultArguments$1
method <init>(p0: java.lang.Object): void
public synthetic final static method access$getReceiver$p(p0: A$testDefaultArguments$1): java.lang.Object
public synthetic bridge method invoke(): java.lang.Object
public final @org.jetbrains.annotations.NotNull method invoke(): java.lang.String
}
@@ -15,7 +14,6 @@ synthetic final class A$testDefaultArguments$2 {
enclosing method A.testDefaultArguments()V
inner (anonymous) class A$testDefaultArguments$2
method <init>(p0: java.lang.Object): void
public synthetic final static method access$getReceiver$p(p0: A$testDefaultArguments$2): java.lang.Object
public final @org.jetbrains.annotations.Nullable method invoke(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
public synthetic bridge method invoke(p0: java.lang.Object): java.lang.Object
}