JVM IR: support optimized callable reference superclasses

See KT-27362.

 #KT-37334 Fixed
This commit is contained in:
Alexander Udalov
2020-03-31 22:04:18 +02:00
parent bb1a12e28e
commit 774fc32f3e
7 changed files with 200 additions and 100 deletions
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
import org.jetbrains.kotlin.codegen.coroutines.isSuspendLambdaOrLocalFunction
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.isReleaseCoroutines
@@ -29,15 +28,12 @@ import org.jetbrains.kotlin.types.KotlinType
class JvmRuntimeTypes(
module: ModuleDescriptor,
private val languageVersionSettings: LanguageVersionSettings,
forceNoOptimizedCallableReferences: Boolean
private val generateOptimizedCallableReferenceSuperClasses: Boolean
) {
private val kotlinJvmInternalPackage = MutablePackageFragmentDescriptor(module, FqName("kotlin.jvm.internal"))
private val kotlinCoroutinesJvmInternalPackage =
MutablePackageFragmentDescriptor(module, languageVersionSettings.coroutinesJvmInternalPackageFqName())
val generateOptimizedCallableReferenceSuperClasses =
languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4 && !forceNoOptimizedCallableReferences
private fun internal(className: String, packageFragment: PackageFragmentDescriptor = kotlinJvmInternalPackage): Lazy<ClassDescriptor> =
lazy { createClass(packageFragment, className) }
@@ -16,11 +16,9 @@ import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper;
import org.jetbrains.kotlin.codegen.inline.NameGenerator;
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages;
import org.jetbrains.kotlin.codegen.inline.SourceMapper;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
import org.jetbrains.kotlin.config.ApiVersion;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotatedImpl;
@@ -644,7 +642,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
if (!state.getClassBuilderMode().generateBodies) return;
boolean generateClassIntCtorCall = state.getJvmRuntimeTypes().getGenerateOptimizedCallableReferenceSuperClasses();
boolean generateClassIntCtorCall = state.getGenerateOptimizedCallableReferenceSuperClasses();
InstructionAdapter iv = createOrGetClInitCodegen().v;
iv.iconst(delegatedProperties.size());
@@ -216,11 +216,14 @@ class GenerationState private constructor(
!configuration.getBoolean(JVMConfigurationKeys.NO_EXCEPTION_ON_EXPLICIT_EQUALS_FOR_BOXED_NULL)
IntrinsicMethods(target, canReplaceStdlibRuntimeApiBehavior, shouldUseConsistentEquals)
}
val generateOptimizedCallableReferenceSuperClasses =
languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4 &&
!configuration.getBoolean(JVMConfigurationKeys.NO_OPTIMIZED_CALLABLE_REFERENCES)
val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this)
val globalInlineContext: GlobalInlineContext = GlobalInlineContext(diagnostics)
val mappingsClassesForWhenByEnum: MappingsClassesForWhenByEnum = MappingsClassesForWhenByEnum(this)
val jvmRuntimeTypes: JvmRuntimeTypes = JvmRuntimeTypes(
module, configuration.languageVersionSettings, configuration.getBoolean(JVMConfigurationKeys.NO_OPTIMIZED_CALLABLE_REFERENCES)
module, configuration.languageVersionSettings, generateOptimizedCallableReferenceSuperClasses
)
val factory: ClassFileFactory
private var duplicateSignatureFactory: BuilderFactoryForDuplicateSignatureDiagnostics? = null
@@ -50,6 +50,8 @@ class JvmSymbols(
private val irBuiltIns = context.irBuiltIns
private val generateOptimizedCallableReferenceSuperClasses = context.state.generateOptimizedCallableReferenceSuperClasses
private val nullPointerExceptionClass: IrClassSymbol =
createClass(FqName("java.lang.NullPointerException")) { klass ->
klass.addConstructor().apply {
@@ -307,6 +309,26 @@ class JvmSymbols(
val functionReferenceGetName: IrSimpleFunctionSymbol = functionReference.functionByName("getName")
val functionReferenceGetOwner: IrSimpleFunctionSymbol = functionReference.functionByName("getOwner")
val functionReferenceImpl: IrClassSymbol =
createClass(FqName("kotlin.jvm.internal.FunctionReferenceImpl"), classModality = Modality.OPEN) { klass ->
klass.superTypes = listOf(functionReference.defaultType)
if (generateOptimizedCallableReferenceSuperClasses) {
for (hasBoundReceiver in listOf(false, true)) {
klass.addConstructor().apply {
addValueParameter("arity", irBuiltIns.intType)
if (hasBoundReceiver) {
addValueParameter("receiver", irBuiltIns.anyNType)
}
addValueParameter("owner", javaLangClass.starProjectedType)
addValueParameter("name", irBuiltIns.stringType)
addValueParameter("signature", irBuiltIns.stringType)
addValueParameter("flags", irBuiltIns.intType)
}
}
}
}
fun getFunction(parameterCount: Int): IrClassSymbol =
symbolTable.referenceClass(builtIns.getFunction(parameterCount))
@@ -379,6 +401,21 @@ class JvmSymbols(
addValueParameter("name", irBuiltIns.stringType)
addValueParameter("string", irBuiltIns.stringType)
}
if (generateOptimizedCallableReferenceSuperClasses) {
for (hasBoundReceiver in listOf(false, true)) {
klass.addConstructor().apply {
if (hasBoundReceiver) {
addValueParameter("receiver", irBuiltIns.anyNType)
}
addValueParameter("owner", javaLangClass.starProjectedType)
addValueParameter("name", irBuiltIns.stringType)
addValueParameter("signature", irBuiltIns.stringType)
addValueParameter("flags", irBuiltIns.intType)
}
}
}
klass.superTypes += getPropertyReferenceClass(mutable, parameterCount, false).defaultType
} else {
klass.addConstructor()
@@ -11,14 +11,10 @@ import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.ir.isSuspend
import org.jetbrains.kotlin.backend.common.ir.moveBodyTo
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.irArray
import org.jetbrains.kotlin.backend.jvm.ir.isLambda
import org.jetbrains.kotlin.backend.jvm.ir.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -123,8 +119,14 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
context.ir.symbols.getJvmFunctionClass(argumentTypes.size)
private val superMethod =
functionSuperClass.functions.single { it.owner.modality == Modality.ABSTRACT }
private val useOptimizedSuperClass =
context.state.generateOptimizedCallableReferenceSuperClasses
private val superType =
samSuperType ?: (if (isLambda) context.ir.symbols.lambdaClass else context.ir.symbols.functionReference).defaultType
samSuperType ?: when {
isLambda -> context.ir.symbols.lambdaClass
useOptimizedSuperClass -> context.ir.symbols.functionReferenceImpl
else -> context.ir.symbols.functionReference
}.defaultType
private val functionReferenceClass = buildClass {
setSourceRange(irFunctionReference)
@@ -167,10 +169,16 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
} else null
)
if (!isLambda && samSuperType == null) {
createGetSignatureMethod(this@run.irSymbols.functionReferenceGetSignature.owner)
createGetNameMethod(this@run.irSymbols.functionReferenceGetName.owner)
createGetOwnerMethod(this@run.irSymbols.functionReferenceGetOwner.owner)
if (!isLambda && samSuperType == null && !useOptimizedSuperClass) {
createLegacyMethodOverride(irSymbols.functionReferenceGetSignature.owner) {
generateSignature()
}
createLegacyMethodOverride(irSymbols.functionReferenceGetName.owner) {
irString(callee.originalName.asString())
}
createLegacyMethodOverride(irSymbols.functionReferenceGetOwner.owner) {
calculateOwner(callee.parent, backendContext)
}
}
+functionReferenceClass
@@ -199,25 +207,43 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
// Super constructor:
// - For SAM references, the super class is Any
// - For function references with bound receivers, accepts arity and receiver
// - For lambdas and function references without bound receivers, accepts arity
// - For lambdas, accepts arity
// - For optimized function references (1.4+), accepts:
// arity, [receiver], owner, name, signature, flags
// - For unoptimized function references, accepts:
// arity, [receiver]
val constructor = if (samSuperType != null) {
context.irBuiltIns.anyClass.owner.constructors.single()
} else {
val expectedArity =
if (isLambda) 1
else 1 + (if (boundReceiver != null) 1 else 0) + (if (useOptimizedSuperClass) 4 else 0)
superType.getClass()!!.constructors.single {
it.valueParameters.size == if (boundReceiver != null) 2 else 1
it.valueParameters.size == expectedArity
}
}
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
+irDelegatingConstructorCall(constructor).apply {
if (samSuperType == null) {
putValueArgument(0, irInt(argumentTypes.size + if (irFunctionReference.isSuspend) 1 else 0))
if (boundReceiver != null)
putValueArgument(1, irGet(valueParameters.first()))
body = context.createJvmIrBuilder(symbol).run {
irBlockBody(startOffset, endOffset) {
+irDelegatingConstructorCall(constructor).apply {
if (samSuperType == null) {
var index = 0
putValueArgument(index++, irInt(argumentTypes.size + if (irFunctionReference.isSuspend) 1 else 0))
if (boundReceiver != null) {
putValueArgument(index++, irGet(valueParameters.first()))
}
if (!isLambda && useOptimizedSuperClass) {
val owner = calculateOwnerKClass(callee.parent, backendContext)
putValueArgument(index++, kClassToJavaClass(owner, backendContext))
putValueArgument(index++, irString(callee.originalName.asString()))
putValueArgument(index++, generateSignature())
// TODO: use correct parents for adapted function references
putValueArgument(index, irInt(if (callee.parent.let { it is IrClass && it.isFileClass }) 1 else 0))
}
}
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, context.irBuiltIns.unitType)
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, context.irBuiltIns.unitType)
}
}
@@ -320,37 +346,28 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
private val IrFunction.originalName: Name
get() = (metadata as? MetadataSource.Function)?.descriptor?.name ?: name
private fun createGetSignatureMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply {
body = context.createJvmIrBuilder(symbol, startOffset, endOffset).run {
irExprBody(irCall(backendContext.ir.symbols.signatureStringIntrinsic).apply {
putValueArgument(
0,
//don't pass receivers otherwise LocalDeclarationLowering will create additional captured parameters
IrFunctionReferenceImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
irFunctionReference.type,
irFunctionReference.symbol,
0,
irFunctionReference.reflectionTarget,
null
)
private fun JvmIrBuilder.generateSignature(): IrExpression =
irCall(backendContext.ir.symbols.signatureStringIntrinsic).apply {
putValueArgument(
0,
//don't pass receivers otherwise LocalDeclarationLowering will create additional captured parameters
IrFunctionReferenceImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunctionReference.type, irFunctionReference.symbol, 0,
irFunctionReference.reflectionTarget, null
)
})
)
}
}
private fun createGetNameMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply {
body = context.createIrBuilder(symbol, startOffset, endOffset).run {
irExprBody(irString(callee.originalName.asString()))
private fun createLegacyMethodOverride(
superFunction: IrSimpleFunction,
generator: JvmIrBuilder.() -> IrExpression
): IrSimpleFunction =
buildOverride(superFunction).apply {
body = context.createJvmIrBuilder(symbol, startOffset, endOffset).run {
irExprBody(generator())
}
}
}
private fun createGetOwnerMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply {
body = context.createIrBuilder(symbol, startOffset, endOffset).run {
irExprBody(calculateOwner(callee.parent, this@FunctionReferenceLowering.context))
}
}
}
companion object {
@@ -359,7 +376,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
startOffset, endOffset, context.irBuiltIns.kClassClass.starProjectedType, context.irBuiltIns.kClassClass, classType
)
private fun IrBuilderWithScope.kClassToJavaClass(kClassReference: IrExpression, context: JvmBackendContext) =
internal fun IrBuilderWithScope.kClassToJavaClass(kClassReference: IrExpression, context: JvmBackendContext) =
irGet(context.ir.symbols.javaLangClass.starProjectedType, null, context.ir.symbols.kClassJava.owner.getter!!.symbol).apply {
extensionReceiver = kClassReference
}
@@ -368,15 +385,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
kClassToJavaClass(kClassReference(classType), context)
internal fun IrBuilderWithScope.calculateOwner(irContainer: IrDeclarationParent, context: JvmBackendContext): IrExpression {
val classType =
if (irContainer is IrClass) irContainer.defaultType
else {
// For built-in members (i.e. top level `toString`) we generate reference to an internal class for an owner.
// This allows kotlin-reflect to understand that this is a built-in intrinsic which has no real declaration,
// and construct a special KCallable object.
context.ir.symbols.intrinsicsKotlinClass.defaultType
}
val kClass = kClassReference(classType)
val kClass = calculateOwnerKClass(irContainer, context)
if ((irContainer as? IrClass)?.isFileClass != true && irContainer !is IrPackageFragment)
return kClass
@@ -389,5 +398,16 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
putValueArgument(1, irString(context.state.moduleName))
}
}
internal fun IrBuilderWithScope.calculateOwnerKClass(irContainer: IrDeclarationParent, context: JvmBackendContext): IrExpression =
kClassReference(
if (irContainer is IrClass) irContainer.defaultType
else {
// For built-in members (i.e. top level `toString`) we generate reference to an internal class for an owner.
// This allows kotlin-reflect to understand that this is a built-in intrinsic which has no real declaration,
// and construct a special KCallable object.
context.ir.symbols.intrinsicsKotlinClass.defaultType
}
)
}
}
@@ -14,20 +14,22 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.JvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.irArrayOf
import org.jetbrains.kotlin.backend.jvm.lower.FunctionReferenceLowering.Companion.calculateOwner
import org.jetbrains.kotlin.backend.jvm.lower.FunctionReferenceLowering.Companion.calculateOwnerKClass
import org.jetbrains.kotlin.backend.jvm.lower.FunctionReferenceLowering.Companion.kClassToJavaClass
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addField
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.builders.declarations.buildField
import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.createType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
@@ -84,6 +86,9 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
private val kPropertiesFieldType =
context.ir.symbols.array.createType(false, listOf(makeTypeProjection(kPropertyStarType, Variance.OUT_VARIANCE)))
private val useOptimizedSuperClass =
context.state.generateOptimizedCallableReferenceSuperClasses
private val IrMemberAccessExpression.propertyContainer: IrDeclarationParent
get() {
var current: IrDeclaration = getter?.owner ?: field?.owner ?: error("Property without getter or field: ${dump()}")
@@ -93,9 +98,10 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
}
private fun IrBuilderWithScope.buildReflectedContainerReference(expression: IrMemberAccessExpression): IrExpression =
with(FunctionReferenceLowering) {
calculateOwner(expression.propertyContainer, this@PropertyReferenceLowering.context)
}
calculateOwner(expression.propertyContainer, this@PropertyReferenceLowering.context)
private fun JvmIrBuilder.buildReflectedContainerReferenceKClass(expression: IrMemberAccessExpression): IrExpression =
calculateOwnerKClass(expression.propertyContainer, backendContext)
private fun IrBuilderWithScope.computeSignatureString(expression: IrCallableReference): IrExpression {
return expression.getter?.let { getter ->
@@ -149,7 +155,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
private class PropertyReferenceKind(
val interfaceSymbol: IrClassSymbol,
val reflectedSymbol: IrClassSymbol,
val implSymbol: IrClassSymbol,
val wrapper: IrFunction
)
@@ -222,7 +228,8 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
val referenceKind = propertyReferenceKindFor(expression)
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run {
irCall(referenceKind.wrapper).apply {
putValueArgument(0, irCall(referenceKind.reflectedSymbol.constructors.single()).apply {
val constructor = referenceKind.implSymbol.constructors.single { it.owner.valueParameters.size == 3 }
putValueArgument(0, irCall(constructor).apply {
putValueArgument(0, buildReflectedContainerReference(expression))
putValueArgument(1, irString(expression.symbol.descriptor.name.asString()))
putValueArgument(2, computeSignatureString(expression))
@@ -234,11 +241,8 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
// Create an instance of KProperty that overrides the get() and set() methods to directly call getX() and setX() on the object.
// This is (relatively) fast, but space-inefficient. Also, the instances can store bound receivers in their fields. Example:
//
// class C$property$0 : PropertyReference0 {
// constructor(boundReceiver: C) : super(boundReceiver)
// override val name = "property"
// override fun getOwner() = C::class
// override fun getSignature() = "getProperty()LType;"
// class C$property$0 : PropertyReference0Impl {
// constructor(boundReceiver: C) : super(boundReceiver, C::class.java, "property", "getProperty()LType;", 0)
// override fun get(): T = receiver.property
// override fun set(value: T) { receiver.property = value }
// }
@@ -261,7 +265,8 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
}
private fun createKPropertySubclass(expression: IrCallableReference): IrClass {
val superClass = propertyReferenceKindFor(expression).interfaceSymbol.owner
val kind = propertyReferenceKindFor(expression)
val superClass = if (useOptimizedSuperClass) kind.implSymbol.owner else kind.interfaceSymbol.owner
val referenceClass = buildClass {
setSourceRange(expression)
name = SpecialNames.NO_NAME_PROVIDED
@@ -269,27 +274,23 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
visibility = Visibilities.LOCAL
}.apply {
parent = irClass
superTypes += IrSimpleTypeImpl(superClass.symbol, false, listOf(), listOf())
superTypes = listOf(superClass.defaultType)
createImplicitParameterDeclarationWithWrappedDescriptor()
}.copyAttributes(expression)
// See propertyReferenceKindFor -- only one of them could ever be present.
val numOfSuperArgs = if (expression.dispatchReceiver != null || expression.extensionReceiver != null) 1 else 0
val superConstructor = superClass.constructors.single { it.valueParameters.size == numOfSuperArgs }
val backingFieldFromSuper = superClass.properties.single { it.name.asString() == "receiver" }.backingField!!
val getName = superClass.functions.single { it.name.asString() == "getName" }
val getOwner = superClass.functions.single { it.name.asString() == "getOwner" }
val getSignature = superClass.functions.single { it.name.asString() == "getSignature" }
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" }
addConstructor(expression, referenceClass, superClass)
referenceClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns, isPrimary = true)
referenceClass.addOverride(getName) { irString(expression.symbol.descriptor.name.asString()) }
referenceClass.addOverride(getOwner) { buildReflectedContainerReference(expression) }
referenceClass.addOverride(getSignature) { computeSignatureString(expression) }
if (!useOptimizedSuperClass) {
val getName = superClass.functions.single { it.name.asString() == "getName" }
val getOwner = superClass.functions.single { it.name.asString() == "getOwner" }
val getSignature = superClass.functions.single { it.name.asString() == "getSignature" }
referenceClass.addOverride(getName) { irString(expression.symbol.descriptor.name.asString()) }
referenceClass.addOverride(getOwner) { buildReflectedContainerReference(expression) }
referenceClass.addOverride(getSignature) { computeSignatureString(expression) }
}
val receiverField = referenceClass.addField {
val backingFieldFromSuper = superClass.properties.single { it.name.asString() == "receiver" }.backingField!!
name = backingFieldFromSuper.name
isFakeOverride = true
origin = IrDeclarationOrigin.FAKE_OVERRIDE
@@ -299,6 +300,10 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
visibility = backingFieldFromSuper.visibility
}
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" }
val field = expression.field?.owner
if (field == null) {
fun IrBuilderWithScope.setCallArguments(call: IrCall, arguments: List<IrValueParameter>) {
@@ -356,6 +361,45 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
}
return referenceClass
}
private fun addConstructor(expression: IrCallableReference, referenceClass: IrClass, superClass: IrClass) {
// See propertyReferenceKindFor -- only one of them could ever be present.
val hasBoundReceiver = expression.dispatchReceiver != null || expression.extensionReceiver != null
val numOfSuperArgs =
(if (hasBoundReceiver) 1 else 0) + (if (useOptimizedSuperClass) 4 else 0)
val superConstructor = superClass.constructors.single { it.valueParameters.size == numOfSuperArgs }
if (!useOptimizedSuperClass) {
referenceClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns, isPrimary = true)
return
}
referenceClass.addConstructor {
origin = JvmLoweredDeclarationOrigin.GENERATED_MEMBER_IN_CALLABLE_REFERENCE
isPrimary = true
}.apply {
if (hasBoundReceiver) {
addValueParameter("receiver", context.irBuiltIns.anyNType)
}
body = context.createJvmIrBuilder(symbol).run {
irBlockBody(startOffset, endOffset) {
+irDelegatingConstructorCall(superConstructor).apply {
var index = 0
if (hasBoundReceiver) {
putValueArgument(index++, irGet(valueParameters.first()))
}
val callee = expression.symbol.owner as IrDeclaration
val owner = buildReflectedContainerReferenceKClass(expression)
putValueArgument(index++, kClassToJavaClass(owner, backendContext))
putValueArgument(index++, irString(expression.symbol.descriptor.name.asString()))
putValueArgument(index++, computeSignatureString(expression))
putValueArgument(index, irInt(if (callee.parent.let { it is IrClass && it.isFileClass }) 1 else 0))
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, referenceClass.symbol, context.irBuiltIns.unitType)
}
}
}
}
})
// Put the new field at the beginning so that static delegated properties with initializers work correctly.
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
class A {
@@ -9,6 +7,8 @@ class A {
}
val topLevelProperty: Int = 0
fun A.extensionFunction() {}
val A.extensionProperty: String get() = ""
fun check(reference: Any, expected: String, message: String) {
val actual = reference.javaClass.declaredMethods.map { it.name }.sorted().toString()
@@ -21,9 +21,11 @@ fun box(): String {
check(A::memberFunction, "[invoke, invoke]", "unbound function reference")
check(A()::memberFunction, "[invoke, invoke]", "bound function reference")
check(::topLevelProperty, "[get]", "unbound property reference 0")
check(A::memberProperty, "[get]", "unbound property reference 1")
check(A()::memberProperty, "[get]", "bound property reference 1")
check(::topLevelProperty, "[get]", "unbound top-level property reference 0")
check(A::memberProperty, "[get]", "unbound member property reference 1")
check(A()::memberProperty, "[get]", "bound member property reference 1")
check(A::extensionProperty, "[get]", "unbound extension property reference 1")
check(A()::extensionProperty, "[get]", "bound extension property reference 1")
return "OK"
}