JVM_IR: support generation of bound reflected property references
Not currently used though, since only references for delegated properties' accessors are reflected, and those are unbound.
This commit is contained in:
+3
-6
@@ -120,11 +120,6 @@ private class AssertionLowering(private val context: JvmBackendContext) :
|
||||
get() = name.asString() == "assert" && getPackageFragment()?.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.getJavaClass(backendContext: JvmBackendContext, irClass: IrClass) =
|
||||
with(FunctionReferenceLowering) {
|
||||
javaClassReference(irClass.defaultType, backendContext)
|
||||
}
|
||||
|
||||
fun IrClass.buildAssertionsDisabledField(backendContext: JvmBackendContext, topLevelClass: IrClass) =
|
||||
factory.buildField {
|
||||
name = Name.identifier(ASSERTIONS_DISABLED_FIELD_NAME)
|
||||
@@ -138,7 +133,9 @@ fun IrClass.buildAssertionsDisabledField(backendContext: JvmBackendContext, topL
|
||||
field.initializer = backendContext.createJvmIrBuilder(this.symbol).run {
|
||||
at(field)
|
||||
irExprBody(irNot(irCall(irSymbols.desiredAssertionStatus).apply {
|
||||
dispatchReceiver = getJavaClass(backendContext, topLevelClass)
|
||||
dispatchReceiver = with(FunctionReferenceLowering) {
|
||||
javaClassReference(topLevelClass.defaultType)
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
||||
IrSyntheticBodyKind.ENUM_VALUEOF ->
|
||||
irCall(backendContext.ir.symbols.enumValueOfFunction).apply {
|
||||
putValueArgument(0, with(FunctionReferenceLowering) {
|
||||
javaClassReference(irClass.defaultType, backendContext)
|
||||
javaClassReference(irClass.defaultType)
|
||||
})
|
||||
putValueArgument(1, irGet(declaration.valueParameters[0]))
|
||||
}
|
||||
|
||||
+14
-14
@@ -519,7 +519,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
irString(callee.originalName.asString())
|
||||
}
|
||||
createLegacyMethodOverride(irSymbols.functionReferenceGetOwner.owner) {
|
||||
calculateOwner(callee.parent, backendContext)
|
||||
calculateOwner(callee.parent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,8 +632,8 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
}
|
||||
if (!isLambda && useOptimizedSuperClass) {
|
||||
val callableReferenceTarget = adaptedReferenceOriginalTarget ?: callee
|
||||
val owner = calculateOwnerKClass(callableReferenceTarget.parent, backendContext)
|
||||
call.putValueArgument(index++, kClassToJavaClass(owner, backendContext))
|
||||
val owner = calculateOwnerKClass(callableReferenceTarget.parent)
|
||||
call.putValueArgument(index++, kClassToJavaClass(owner))
|
||||
call.putValueArgument(index++, irString(callableReferenceTarget.originalName.asString()))
|
||||
call.putValueArgument(index++, generateSignature(callableReferenceTarget.symbol))
|
||||
call.putValueArgument(index, irInt(getFunctionReferenceFlags(callableReferenceTarget)))
|
||||
@@ -808,31 +808,31 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
startOffset, endOffset, context.irBuiltIns.kClassClass.starProjectedType, context.irBuiltIns.kClassClass, classType
|
||||
)
|
||||
|
||||
internal fun IrBuilderWithScope.kClassToJavaClass(kClassReference: IrExpression, context: JvmBackendContext) =
|
||||
irGet(context.ir.symbols.javaLangClass.starProjectedType, null, context.ir.symbols.kClassJava.owner.getter!!.symbol).apply {
|
||||
internal fun JvmIrBuilder.kClassToJavaClass(kClassReference: IrExpression) =
|
||||
irGet(irSymbols.javaLangClass.starProjectedType, null, irSymbols.kClassJava.owner.getter!!.symbol).apply {
|
||||
extensionReceiver = kClassReference
|
||||
}
|
||||
|
||||
internal fun IrBuilderWithScope.javaClassReference(classType: IrType, context: JvmBackendContext) =
|
||||
kClassToJavaClass(kClassReference(classType), context)
|
||||
internal fun JvmIrBuilder.javaClassReference(classType: IrType) =
|
||||
kClassToJavaClass(kClassReference(classType))
|
||||
|
||||
internal fun IrBuilderWithScope.calculateOwner(irContainer: IrDeclarationParent, context: JvmBackendContext): IrExpression {
|
||||
val kClass = calculateOwnerKClass(irContainer, context)
|
||||
internal fun JvmIrBuilder.calculateOwner(irContainer: IrDeclarationParent): IrExpression {
|
||||
val kClass = calculateOwnerKClass(irContainer)
|
||||
|
||||
if ((irContainer as? IrClass)?.isFileClass != true && irContainer !is IrPackageFragment)
|
||||
return kClass
|
||||
|
||||
return irCall(context.ir.symbols.getOrCreateKotlinPackage).apply {
|
||||
putValueArgument(0, kClassToJavaClass(kClass, context))
|
||||
return irCall(irSymbols.getOrCreateKotlinPackage).apply {
|
||||
putValueArgument(0, kClassToJavaClass(kClass))
|
||||
// Note that this name is not used in reflection. There should be the name of the referenced declaration's
|
||||
// module instead, but there's no nice API to obtain that name here yet
|
||||
// TODO: write the referenced declaration's module name and use it in reflection
|
||||
putValueArgument(1, irString(context.state.moduleName))
|
||||
putValueArgument(1, irString(backendContext.state.moduleName))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun IrBuilderWithScope.calculateOwnerKClass(irContainer: IrDeclarationParent, context: JvmBackendContext): IrExpression =
|
||||
kClassReference(getOwnerKClassType(irContainer, context))
|
||||
internal fun JvmIrBuilder.calculateOwnerKClass(irContainer: IrDeclarationParent): IrExpression =
|
||||
kClassReference(getOwnerKClassType(irContainer, backendContext))
|
||||
|
||||
internal fun getOwnerKClassType(irContainer: IrDeclarationParent, context: JvmBackendContext): IrType =
|
||||
if (irContainer is IrClass) irContainer.defaultType
|
||||
|
||||
+38
-47
@@ -15,10 +15,7 @@ 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.codegen.parentClassId
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.hasChild
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.irArrayOf
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.needsAccessor
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||
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
|
||||
@@ -129,7 +126,7 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
|
||||
return irCall(signatureStringIntrinsic).apply { putValueArgument(0, reference) }
|
||||
}
|
||||
|
||||
private fun IrClass.addOverride(method: IrSimpleFunction, buildBody: IrBuilderWithScope.(List<IrValueParameter>) -> IrExpression) =
|
||||
private fun IrClass.addOverride(method: IrSimpleFunction, buildBody: JvmIrBuilder.(List<IrValueParameter>) -> IrExpression) =
|
||||
addFunction {
|
||||
setSourceRange(this@addOverride)
|
||||
name = method.name
|
||||
@@ -141,7 +138,7 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
|
||||
overriddenSymbols += method.symbol
|
||||
dispatchReceiverParameter = thisReceiver!!.copyTo(this)
|
||||
valueParameters = method.valueParameters.map { it.copyTo(this) }
|
||||
body = context.createIrBuilder(symbol, startOffset, endOffset).run {
|
||||
body = context.createJvmIrBuilder(symbol, startOffset, endOffset).run {
|
||||
irExprBody(buildBody(listOf(dispatchReceiverParameter!!) + valueParameters))
|
||||
}
|
||||
}
|
||||
@@ -316,38 +313,43 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
|
||||
}
|
||||
|
||||
// Create an instance of KProperty that uses Java reflection to locate the getter and the setter. This kind of reference
|
||||
// does not support local variables or bound receivers (e.g. `Class()::field`) and is slower, but takes up less space.
|
||||
// does not support local variables and is slower, but takes up less space in the output binary.
|
||||
// Example: `C::property` -> `Reflection.property1(PropertyReference1Impl(C::class, "property", "getProperty()LType;"))`.
|
||||
private fun createReflectedKProperty(expression: IrCallableReference<*>): IrExpression {
|
||||
assert(expression.dispatchReceiver == null && expression.extensionReceiver == null) {
|
||||
// TODO: technically can with `generateOptimizedCallableReferenceSuperClasses` - use the 5-argument constructor
|
||||
"cannot create a reflected KProperty if the reference has a bound receiver: ${expression.render()}"
|
||||
val boundReceiver = expression.getBoundReceiver()
|
||||
if (boundReceiver != null && !useOptimizedSuperClass) {
|
||||
// Pre-1.4 reflected property reference constructors do not allow bound receivers.
|
||||
return createSpecializedKProperty(expression)
|
||||
}
|
||||
val referenceKind = propertyReferenceKindFor(expression)
|
||||
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run {
|
||||
irCall(referenceKind.wrapper).apply {
|
||||
val container = expression.propertyContainer
|
||||
val name = irString(expression.referencedName.asString())
|
||||
val signature = computeSignatureString(expression)
|
||||
val impl = when {
|
||||
this@PropertyReferenceLowering.context.state.generateOptimizedCallableReferenceSuperClasses ->
|
||||
irCall(referenceKind.implSymbol.constructors.single { it.owner.valueParameters.size == 4 }).apply {
|
||||
val kClass = calculateOwnerKClass(container, this@PropertyReferenceLowering.context)
|
||||
val isPackage = (container is IrClass && container.isFileClass) || container is IrPackageFragment
|
||||
putValueArgument(0, kClassToJavaClass(kClass, this@PropertyReferenceLowering.context))
|
||||
putValueArgument(1, name)
|
||||
putValueArgument(2, signature)
|
||||
putValueArgument(3, irInt(if (isPackage) 1 else 0))
|
||||
}
|
||||
else ->
|
||||
irCall(referenceKind.implSymbol.constructors.single { it.owner.valueParameters.size == 3 }).apply {
|
||||
putValueArgument(0, calculateOwner(container, this@PropertyReferenceLowering.context))
|
||||
putValueArgument(1, name)
|
||||
putValueArgument(2, signature)
|
||||
}
|
||||
}
|
||||
putValueArgument(0, impl)
|
||||
return context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run {
|
||||
val arity = when {
|
||||
boundReceiver != null -> 5 // (receiver, jClass, name, desc, flags)
|
||||
useOptimizedSuperClass -> 4 // (jClass, name, desc, flags)
|
||||
else -> 3 // (kClass, name, desc)
|
||||
}
|
||||
val instance = irCall(referenceKind.implSymbol.constructors.single { it.owner.valueParameters.size == arity }).apply {
|
||||
fillReflectedPropertyArguments(this, expression, boundReceiver)
|
||||
}
|
||||
irCall(referenceKind.wrapper).apply { putValueArgument(0, instance) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun JvmIrBuilder.fillReflectedPropertyArguments(
|
||||
call: IrFunctionAccessExpression,
|
||||
expression: IrCallableReference<*>,
|
||||
receiver: IrExpression?,
|
||||
) {
|
||||
val container = expression.propertyContainer
|
||||
val containerClass = if (useOptimizedSuperClass) kClassToJavaClass(calculateOwnerKClass(container)) else calculateOwner(container)
|
||||
var index = 0
|
||||
receiver?.let { call.putValueArgument(index++, it) }
|
||||
call.putValueArgument(index++, containerClass)
|
||||
call.putValueArgument(index++, irString(expression.referencedName.asString()))
|
||||
call.putValueArgument(index++, computeSignatureString(expression))
|
||||
if (useOptimizedSuperClass) {
|
||||
val isPackage = (container is IrClass && container.isFileClass) || container is IrPackageFragment
|
||||
call.putValueArgument(index, irInt(if (isPackage) 1 else 0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +397,7 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
|
||||
val getOwner = superClass.functions.single { it.name.asString() == "getOwner" }
|
||||
val getSignature = superClass.functions.single { it.name.asString() == "getSignature" }
|
||||
referenceClass.addOverride(getName) { irString(expression.referencedName.asString()) }
|
||||
referenceClass.addOverride(getOwner) { calculateOwner(expression.propertyContainer, this@PropertyReferenceLowering.context) }
|
||||
referenceClass.addOverride(getOwner) { calculateOwner(expression.propertyContainer) }
|
||||
referenceClass.addOverride(getSignature) { computeSignatureString(expression) }
|
||||
}
|
||||
|
||||
@@ -475,22 +477,11 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
|
||||
origin = JvmLoweredDeclarationOrigin.GENERATED_MEMBER_IN_CALLABLE_REFERENCE
|
||||
isPrimary = true
|
||||
}.apply {
|
||||
if (hasBoundReceiver) {
|
||||
addValueParameter("receiver", context.irBuiltIns.anyNType)
|
||||
}
|
||||
val receiverParameter = if (hasBoundReceiver) addValueParameter("receiver", context.irBuiltIns.anyNType) else null
|
||||
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 = calculateOwnerKClass(expression.propertyContainer, backendContext)
|
||||
putValueArgument(index++, kClassToJavaClass(owner, backendContext))
|
||||
putValueArgument(index++, irString(expression.referencedName.asString()))
|
||||
putValueArgument(index++, computeSignatureString(expression))
|
||||
putValueArgument(index, irInt(FunctionReferenceLowering.getCallableReferenceTopLevelFlag(callee)))
|
||||
fillReflectedPropertyArguments(this, expression, receiverParameter?.let(::irGet))
|
||||
}
|
||||
+IrInstanceInitializerCallImpl(startOffset, endOffset, referenceClass.symbol, context.irBuiltIns.unitType)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user