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 // 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) { current = matchRange(current) {
aload(slot) aload(slot)
index = iconst() index = iconst()
new(PROPERTY_REFERENCE_CLASSES) new(PROPERTY_REFERENCE_CLASSES)
dup() dup()
// Either getOrCreateKotlinPackage(class, module) or getOrCreateKotlinClass(class)
ldc() // java class ldc() // java class
optional { either(
ldc() // module name {
} optional { ldc() } // module name, if package
invokestatic("kotlin/jvm/internal/Reflection") invokestatic("kotlin/jvm/internal/Reflection") // getOrCreateKotlinPackage or getOrCreateKotlinClass
ldc() // name ldc() // name
ldc() // signature ldc() // signature
invokespecial("<init>", "(Lkotlin/reflect/KDeclarationContainer;Ljava/lang/String;Ljava/lang/String;)V") invokespecial("<init>", "(Lkotlin/reflect/KDeclarationContainer;Ljava/lang/String;Ljava/lang/String;)V")
invokestatic("kotlin/jvm/internal/Reflection") }, {
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() aastore()
} ?: break } ?: break
@@ -239,10 +246,15 @@ private class InstructionMatcher(var current: AbstractInsnNode?) {
} }
inline fun optional(block: () -> Unit) { inline fun optional(block: () -> Unit) {
either(block) {}
}
inline fun either(first: () -> Unit, second: () -> Unit) {
val start = current val start = current
block() first()
if (current == null) { if (current == null) {
current = start 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;"))`. // Example: `C::property` -> `Reflection.property1(PropertyReference1Impl(C::class, "property", "getProperty()LType;"))`.
private fun createReflectedKProperty(expression: IrCallableReference<*>): IrExpression { private fun createReflectedKProperty(expression: IrCallableReference<*>): IrExpression {
assert(expression.dispatchReceiver == null && expression.extensionReceiver == null) { 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()}" "cannot create a reflected KProperty if the reference has a bound receiver: ${expression.render()}"
} }
val referenceKind = propertyReferenceKindFor(expression) val referenceKind = propertyReferenceKindFor(expression)
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run { return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run {
irCall(referenceKind.wrapper).apply { irCall(referenceKind.wrapper).apply {
val constructor = referenceKind.implSymbol.constructors.single { it.owner.valueParameters.size == 3 } val container = expression.propertyContainer
putValueArgument(0, irCall(constructor).apply { val name = irString(expression.referencedName.asString())
putValueArgument(0, calculateOwner(expression.propertyContainer, this@PropertyReferenceLowering.context)) val signature = computeSignatureString(expression)
putValueArgument(1, irString(expression.referencedName.asString())) val impl = when {
putValueArgument(2, computeSignatureString(expression)) 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)
} }
} }
} }