JVM_IR: generate shorter bytecode for reflected property references

This commit is contained in:
pyos
2021-06-21 12:54:28 +02:00
committed by Dmitry Petrov
parent 7079ad49bc
commit bd6d96114b
2 changed files with 45 additions and 17 deletions
@@ -148,22 +148,29 @@ class DelegatedPropertyOptimizer {
//
// AASTORE
//
// With the caveat that we might create a class instead of a package as the `KDeclarationContainer`.
// With the caveat that we might create a class instead of a package as the `KDeclarationContainer`,
// and with optimized references the Java class is passed to the constructor without wrapping.
current = matchRange(current) {
aload(slot)
index = iconst()
new(PROPERTY_REFERENCE_CLASSES)
dup()
// Either getOrCreateKotlinPackage(class, module) or getOrCreateKotlinClass(class)
ldc() // java class
optional {
ldc() // module name
}
invokestatic("kotlin/jvm/internal/Reflection")
ldc() // name
ldc() // signature
invokespecial("<init>", "(Lkotlin/reflect/KDeclarationContainer;Ljava/lang/String;Ljava/lang/String;)V")
invokestatic("kotlin/jvm/internal/Reflection")
either(
{
optional { ldc() } // module name, if package
invokestatic("kotlin/jvm/internal/Reflection") // getOrCreateKotlinPackage or getOrCreateKotlinClass
ldc() // name
ldc() // signature
invokespecial("<init>", "(Lkotlin/reflect/KDeclarationContainer;Ljava/lang/String;Ljava/lang/String;)V")
}, {
ldc() // name
ldc() // signature
iconst() // flags
invokespecial("<init>", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V")
}
)
invokestatic("kotlin/jvm/internal/Reflection") // (property|mutableProperty)[012]
aastore()
} ?: break
@@ -239,10 +246,15 @@ private class InstructionMatcher(var current: AbstractInsnNode?) {
}
inline fun optional(block: () -> Unit) {
either(block) {}
}
inline fun either(first: () -> Unit, second: () -> Unit) {
val start = current
block()
first()
if (current == null) {
current = start
second()
}
}
@@ -279,17 +279,33 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
// 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 referenceKind = propertyReferenceKindFor(expression)
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run {
irCall(referenceKind.wrapper).apply {
val constructor = referenceKind.implSymbol.constructors.single { it.owner.valueParameters.size == 3 }
putValueArgument(0, irCall(constructor).apply {
putValueArgument(0, calculateOwner(expression.propertyContainer, this@PropertyReferenceLowering.context))
putValueArgument(1, irString(expression.referencedName.asString()))
putValueArgument(2, computeSignatureString(expression))
})
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)
}
}
}