From e7835fecfc93349e9bc7e79adcbb90b92597279b Mon Sep 17 00:00:00 2001 From: Mads Ager Date: Mon, 23 Dec 2019 08:53:14 +0100 Subject: [PATCH] JVM_IR: fix a couple of inline class reflection issues. 1. Postpone the computation of the signature for property reference getters for extension properties until codegen time. 2. Generate metadata for static replacement functions instead of the original functions. --- .../backend/jvm/intrinsics/SignatureString.kt | 13 +++----- .../jvm/lower/PropertyReferenceLowering.kt | 30 ++++++++++++++----- .../MemoizedInlineClassReplacements.kt | 6 +++- .../nonOverridingVarOfInlineClass.kt | 2 +- .../overridingFunOfInlineClass.kt | 2 +- .../overridingVarOfInlineClass.kt | 2 +- .../call/inlineClasses/properties.kt | 2 +- .../reflection/callBy/inlineClassMembers.kt | 2 +- 8 files changed, 37 insertions(+), 22 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/SignatureString.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/SignatureString.kt index 42c1f046e59..17362012239 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/SignatureString.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/SignatureString.kt @@ -8,9 +8,10 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.ir.util.collectRealOverrides import org.jetbrains.kotlin.resolve.jvm.AsmTypes /** @@ -20,15 +21,9 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes object SignatureString : IntrinsicMethod() { override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? { val function = (expression.getValueArgument(0) as IrFunctionReference).symbol.owner - - // TODO do not use descriptors - val declaration = codegen.context.referenceFunction( - DescriptorUtils.unwrapFakeOverride(function.descriptor).original - ).owner - - val method = codegen.context.methodSignatureMapper.mapAsmMethod(declaration) + val resolved = if (function is IrSimpleFunction) function.collectRealOverrides().first() else function + val method = codegen.context.methodSignatureMapper.mapAsmMethod(resolved) val descriptor = method.name + method.descriptor - return object : PromisedValue(codegen, AsmTypes.JAVA_STRING_TYPE, codegen.context.irBuiltIns.stringType) { override fun materialize() { codegen.mv.aconst(descriptor) 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 3f5ddff1367..5ad883758c2 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 @@ -19,10 +19,12 @@ import org.jetbrains.kotlin.backend.jvm.ir.irArrayOf 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.* 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.symbols.* import org.jetbrains.kotlin.ir.types.createType import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl @@ -64,14 +66,11 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class private val IrField.signature: String get() = "${JvmAbi.getterName(name.asString())}()${context.methodSignatureMapper.mapReturnType(this)}" - private val IrMemberAccessExpression.signature: String - get() = getter?.let { getter -> - localPropertyIndices[getter]?.let { "" } - } ?: getter?.owner?.signature ?: field!!.owner.signature - private val arrayItemGetter = context.ir.symbols.array.owner.functions.single { it.name.asString() == "get" } + private val signatureStringIntrinsic = context.ir.symbols.signatureStringIntrinsic + private val kPropertyStarType = IrSimpleTypeImpl( context.irBuiltIns.kPropertyClass, false, @@ -95,6 +94,23 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class calculateOwner(expression.propertyContainer, this@PropertyReferenceLowering.context) } + private fun IrBuilderWithScope.computeSignatureString(expression: IrCallableReference): IrExpression { + return expression.getter?.let { getter -> + localPropertyIndices[getter]?.let { irString("") } + ?: if (getter.owner.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) { + // Default property accessor. Compute the signature now, so that we will not get into trouble + // if the getter is transformed to a static method by inline classes lowering. + irString(getter.owner.signature) + } else { + // Delay the computation of the signature until after inline classes lowering to make sure + // we mangle the function names correctly for things like extension methods on inline classes. + irCall(signatureStringIntrinsic).apply { + putValueArgument(0, IrFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, expression.type, getter, 0, null)) + } + } + } ?: irString(expression.field!!.owner.signature) + } + private fun IrClass.addOverride(method: IrSimpleFunction, buildBody: IrBuilderWithScope.(List) -> IrExpression) = addFunction { setSourceRange(this@addOverride) @@ -204,7 +220,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class putValueArgument(0, irCall(referenceKind.reflectedSymbol.constructors.single()).apply { putValueArgument(0, buildReflectedContainerReference(expression)) putValueArgument(1, irString(expression.symbol.descriptor.name.asString())) - putValueArgument(2, irString(expression.signature)) + putValueArgument(2, computeSignatureString(expression)) }) } } @@ -266,7 +282,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class referenceClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns, isPrimary = true) referenceClass.addOverride(getName) { irString(expression.symbol.descriptor.name.asString()) } referenceClass.addOverride(getOwner) { buildReflectedContainerReference(expression) } - referenceClass.addOverride(getSignature) { irString(expression.signature) } + referenceClass.addOverride(getSignature) { computeSignatureString(expression) } val receiverField = referenceClass.addField { name = backingFieldFromSuper.name diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt index 221047a9193..c63ae8a9260 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.declarations.buildFunWithDescriptorForInlining import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionBase import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol @@ -169,8 +170,11 @@ class MemoizedInlineClassReplacements { private fun createStaticReplacement(function: IrFunction): IrReplacementFunction { val parameterMap = mutableMapOf() val replacement = buildReplacement(function) { - if (function !is IrSimpleFunction || function.overriddenSymbols.isEmpty()) + // Generate metadata for the replacement function instead of the original. + if (function is IrFunctionBase) { metadata = function.metadata + function.metadata = null + } for ((index, parameter) in function.explicitParameters.withIndex()) { val name = when (parameter) { diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt index 33327f540d3..318deb2cebb 100644 --- a/compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt @@ -1,5 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// IGNORE_BACKEND: JS_IR, JS, NATIVE // WITH_REFLECT import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt index 3df9e8da34d..6f6e84bf4f8 100644 --- a/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt @@ -1,5 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// IGNORE_BACKEND: JS_IR, JS, NATIVE // WITH_REFLECT import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt index 7f06afc6f08..6d98427740e 100644 --- a/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt @@ -1,5 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// IGNORE_BACKEND: JS_IR, JS, NATIVE // WITH_REFLECT import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt index 21461d764e0..6069be53e8c 100644 --- a/compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt @@ -1,5 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// IGNORE_BACKEND: JS_IR, JS, NATIVE // WITH_REFLECT import kotlin.reflect.KMutableProperty2 diff --git a/compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt b/compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt index 383f795b97b..c8f2486f241 100644 --- a/compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt +++ b/compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt @@ -1,5 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// IGNORE_BACKEND: JS_IR, JS, NATIVE // WITH_REFLECT import kotlin.test.assertEquals