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:
+14
-3
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -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")
|
||||
|
||||
-2
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user