From bd6d96114be05032eb894088cfeec061a5e27f67 Mon Sep 17 00:00:00 2001 From: pyos Date: Mon, 21 Jun 2021 12:54:28 +0200 Subject: [PATCH] JVM_IR: generate shorter bytecode for reflected property references --- .../jvm/codegen/DelegatedPropertyOptimizer.kt | 34 +++++++++++++------ .../jvm/lower/PropertyReferenceLowering.kt | 28 +++++++++++---- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/DelegatedPropertyOptimizer.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/DelegatedPropertyOptimizer.kt index a5dae3aafc7..9cbbbf4ffe3 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/DelegatedPropertyOptimizer.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/DelegatedPropertyOptimizer.kt @@ -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("", "(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("", "(Lkotlin/reflect/KDeclarationContainer;Ljava/lang/String;Ljava/lang/String;)V") + }, { + ldc() // name + ldc() // signature + iconst() // flags + invokespecial("", "(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() } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt index 49d748df814..816a05b477c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt @@ -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) } } }