From 337cbeded1842e796900eb68e4f240d38bddc25b Mon Sep 17 00:00:00 2001 From: pyos Date: Tue, 5 Oct 2021 10:41:09 +0200 Subject: [PATCH] JVM_IR: do not move receivers on functions with inline class parameters ^KT-48993 Fixed --- .../FirBlackBoxCodegenTestGenerated.java | 6 +++ .../jvm/MemoizedInlineClassReplacements.kt | 17 ++++----- .../backend/jvm/codegen/FunctionCodegen.kt | 38 +++++++------------ .../codegen/box/inlineClasses/kt48993.kt | 20 ++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++ .../IrBlackBoxCodegenTestGenerated.java | 6 +++ .../LightAnalysisModeTestGenerated.java | 5 +++ 7 files changed, 64 insertions(+), 34 deletions(-) create mode 100644 compiler/testData/codegen/box/inlineClasses/kt48993.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 4d81ef2eb16..1e02aa46e72 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -19488,6 +19488,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt"); } + @Test + @TestMetadata("kt48993.kt") + public void testKt48993() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt"); + } + @Test @TestMetadata("mangledDefaultParameterFunction.kt") public void testMangledDefaultParameterFunction() throws Exception { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt index 67263564ba2..33a81c4dbfc 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.copyTypeParameters import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter import org.jetbrains.kotlin.backend.jvm.codegen.classFileContainsMethod +import org.jetbrains.kotlin.backend.jvm.codegen.extensionReceiverName import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.codegen.parentClassId import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault @@ -81,10 +82,7 @@ class MemoizedInlineClassReplacements( // Otherwise, mangle functions with mangled parameters, ignoring constructors it is IrSimpleFunction && !it.isFromJava() && (it.hasMangledParameters || mangleReturnTypes && it.hasMangledReturnType) -> - if (it.dispatchReceiverParameter != null) - createMethodReplacement(it) - else - createStaticReplacement(it) + createMethodReplacement(it) else -> null @@ -182,9 +180,11 @@ class MemoizedInlineClassReplacements( private fun createMethodReplacement(function: IrFunction): IrSimpleFunction = buildReplacement(function, function.origin) { originalFunctionForMethodReplacement[this] = function - require(function.dispatchReceiverParameter != null && function is IrSimpleFunction) dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1) - extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(this, index = -1, name = Name.identifier("\$receiver")) + extensionReceiverParameter = function.extensionReceiverParameter?.copyTo( + // The function's name will be mangled, so preserve the old receiver name. + this, index = -1, name = Name.identifier(function.extensionReceiverName(context.state)) + ) valueParameters = function.valueParameters.mapIndexed { index, parameter -> parameter.copyTo(this, index = index, defaultValue = null).also { // Assuming that constructors and non-override functions are always replaced with the unboxed @@ -207,11 +207,8 @@ class MemoizedInlineClassReplacements( ) } function.extensionReceiverParameter?.let { - val baseName = - (function as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.name?.asStringStripSpecialMarkers() - ?: function.name newValueParameters += it.copyTo( - this, index = newValueParameters.size, name = Name.identifier("\$this\$$baseName"), + this, index = newValueParameters.size, name = Name.identifier(function.extensionReceiverName(context.state)), origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER ) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index fb75c60c834..b64fa244fd8 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -69,7 +69,7 @@ class FunctionCodegen(private val irFunction: IrFunction, private val classCodeg val methodVisitor: MethodVisitor = wrapWithMaxLocalCalc(methodNode) if (context.state.generateParametersMetadata && !isSynthetic) { - generateParameterNames(irFunction, methodVisitor, signature, context.state) + generateParameterNames(irFunction, methodVisitor, context.state) } if (irFunction.origin !in methodOriginsWithoutAnnotations) { @@ -329,23 +329,16 @@ private fun IrValueParameter.isSyntheticMarkerParameter(): Boolean = origin == IrDeclarationOrigin.DEFAULT_CONSTRUCTOR_MARKER || origin == JvmLoweredDeclarationOrigin.SYNTHETIC_MARKER_PARAMETER -private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, jvmSignature: JvmMethodSignature, state: GenerationState) { - val iterator = irFunction.valueParameters.iterator() - for (parameterSignature in jvmSignature.valueParameters) { - val irParameter = when (parameterSignature.kind) { - JvmMethodParameterKind.RECEIVER -> irFunction.extensionReceiverParameter!! - else -> iterator.next() - } - val name = when (parameterSignature.kind) { - JvmMethodParameterKind.RECEIVER -> getNameForReceiverParameter(irFunction, state) - else -> irParameter.name.asString() - } +private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, state: GenerationState) { + irFunction.extensionReceiverParameter?.let { + mv.visitParameter(irFunction.extensionReceiverName(state), Opcodes.ACC_MANDATED) + } + for (irParameter in irFunction.valueParameters) { // A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared // explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9). // A construct emitted by a Java compiler must be marked as mandated if it corresponds to a formal parameter // declared implicitly in source code (§8.8.1, §8.8.9, §8.9.3, §15.9.5.1). val access = when { - irParameter == irFunction.extensionReceiverParameter -> Opcodes.ACC_MANDATED irParameter.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> Opcodes.ACC_MANDATED // TODO mark these backend-common origins as synthetic? (note: ExpressionCodegen is still expected // to generate LVT entries for them) @@ -356,24 +349,21 @@ private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, jv irParameter.origin.isSynthetic -> Opcodes.ACC_SYNTHETIC else -> 0 } - mv.visitParameter(name, access) + mv.visitParameter(irParameter.name.asString(), access) } } -private fun getNameForReceiverParameter(irFunction: IrFunction, state: GenerationState): String { +internal fun IrFunction.extensionReceiverName(state: GenerationState): String { if (!state.languageVersionSettings.supportsFeature(LanguageFeature.NewCapturedReceiverFieldNamingConvention)) { return AsmUtil.RECEIVER_PARAMETER_NAME } - // Current codegen never touches CALL_LABEL_FOR_LAMBDA_ARGUMENT -// if (irFunction is IrSimpleFunction) { -// val labelName = bindingContext.get(CodegenBinding.CALL_LABEL_FOR_LAMBDA_ARGUMENT, irFunction.descriptor) -// if (labelName != null) { -// return getLabeledThisName(labelName, prefix, defaultName) -// } -// } - - val callableName = irFunction.safeAs()?.correspondingPropertySymbol?.owner?.name ?: irFunction.name + extensionReceiverParameter?.let { + if (it.name.asString().startsWith(AsmUtil.LABELED_THIS_PARAMETER)) { + return it.name.asString() + } + } + val callableName = (this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.name ?: name return if (callableName.isSpecial || !Name.isValidIdentifier(callableName.asString())) AsmUtil.RECEIVER_PARAMETER_NAME else diff --git a/compiler/testData/codegen/box/inlineClasses/kt48993.kt b/compiler/testData/codegen/box/inlineClasses/kt48993.kt new file mode 100644 index 00000000000..437ed048e09 --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/kt48993.kt @@ -0,0 +1,20 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME +// FILE: 1.kt +inline class C(val x: String) + +// FILE: 2.kt +@file:JvmMultifileClass +@file:JvmName("Multifile") + +private var result: String? = null + +var String.k: C + get() = C(this + result!!) + set(value) { result = value.x } + +// FILE: 3.kt +fun box(): String { + "".k = C("K") + return "O".k.x +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index fde8a814fb1..daaeb8c953f 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -19356,6 +19356,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt"); } + @Test + @TestMetadata("kt48993.kt") + public void testKt48993() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt"); + } + @Test @TestMetadata("mangledDefaultParameterFunction.kt") public void testMangledDefaultParameterFunction() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index ee7c7323085..cd4e106fdb8 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -19488,6 +19488,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt"); } + @Test + @TestMetadata("kt48993.kt") + public void testKt48993() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt"); + } + @Test @TestMetadata("mangledDefaultParameterFunction.kt") public void testMangledDefaultParameterFunction() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 92bccf4bbc5..7cd5958d8b9 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -16078,6 +16078,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt"); } + @TestMetadata("kt48993.kt") + public void testKt48993() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt"); + } + @TestMetadata("mangledDefaultParameterFunction.kt") public void testMangledDefaultParameterFunction() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");