From 1ed7e33f4204923a0811cef499ba52b1748718d2 Mon Sep 17 00:00:00 2001 From: Mads Ager Date: Fri, 3 Jan 2020 11:28:43 +0100 Subject: [PATCH] JVM_IR: Fix default argument bit mask for methods made static. When called by reflection the bit mask will be generated discounting dispatch/extension receivers. Make sure that the interpretation of the bit mask is consistent for direct and reflective calls. In addition, this also fixes the modifiers on java 8 parameter metadata for the dispatch and extension receivers for these inline class methods. --- .../kotlin/backend/common/ir/IrUtils.kt | 4 +-- .../lower/DefaultArgumentStubGenerator.kt | 15 ++++++++-- .../backend/jvm/codegen/FunctionCodegen.kt | 3 +- .../MemoizedInlineClassReplacements.kt | 8 +++-- .../ir/declarations/IrDeclarationOrigin.kt | 3 +- .../inlineClassMethodParameterModifiers.kt | 29 +++++++++++++++++++ .../inlineClassMethodParameterNames.kt | 28 ++++++++++++++++++ .../inlineClassFunctionsAndConstructors.kt | 6 ++-- .../codegen/BlackBoxCodegenTestGenerated.java | 10 +++++++ .../LightAnalysisModeTestGenerated.java | 10 +++++++ .../ir/FirBlackBoxCodegenTestGenerated.java | 10 +++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 10 +++++++ 12 files changed, 126 insertions(+), 10 deletions(-) create mode 100644 compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt create mode 100644 compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index b307fe1711d..388f960cff4 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -582,13 +582,13 @@ fun createStaticFunctionWithReceivers( name = Name.identifier("this"), index = offset++, type = dispatchReceiverType!!, - origin = IrDeclarationOrigin.MOVED_RECEIVER_PARAMETER + origin = IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER ) val extensionReceiver = oldFunction.extensionReceiverParameter?.copyTo( this, name = Name.identifier("receiver"), index = offset++, - origin = IrDeclarationOrigin.MOVED_RECEIVER_PARAMETER + origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER ) valueParameters.addAll(listOfNotNull(dispatchReceiver, extensionReceiver) + oldFunction.valueParameters.map { it.copyTo(this, index = it.index + offset) } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt index e1f143c3216..99455fea670 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt @@ -85,11 +85,15 @@ open class DefaultArgumentStubGenerator( newIrFunction.valueParameters[it.index] } + var sourceParameterIndex = -1 for (valueParameter in irFunction.valueParameters) { + if (!valueParameter.isMovedReceiver()) { + ++sourceParameterIndex + } val parameter = newIrFunction.valueParameters[valueParameter.index] val remapped = if (valueParameter.defaultValue != null) { val mask = irGet(newIrFunction.valueParameters[irFunction.valueParameters.size + valueParameter.index / 32]) - val bit = irInt(1 shl (valueParameter.index % 32)) + val bit = irInt(1 shl (sourceParameterIndex % 32)) val defaultFlag = irCallOp(this@DefaultArgumentStubGenerator.context.ir.symbols.intAnd, context.irBuiltIns.intType, mask, bit) val expressionBody = valueParameter.defaultValue!! @@ -289,14 +293,18 @@ open class DefaultParameterInjector( "argument count mismatch: expected $realArgumentsNumber arguments + ${maskValues.size} masks + optional handler/marker, " + "got ${stubFunction.valueParameters.size} total in ${stubFunction.render()}" } + var sourceParameterIndex = -1 return stubFunction.symbol to stubFunction.valueParameters.mapIndexed { i, parameter -> + if (!parameter.isMovedReceiver()) { + ++sourceParameterIndex + } when { i >= realArgumentsNumber + maskValues.size -> IrConstImpl.constNull(startOffset, endOffset, parameter.type) i >= realArgumentsNumber -> IrConstImpl.int(startOffset, endOffset, parameter.type, maskValues[i - realArgumentsNumber]) else -> { val valueArgument = expression.getValueArgument(i) if (valueArgument == null) { - maskValues[i / 32] = maskValues[i / 32] or (1 shl (i % 32)) + maskValues[i / 32] = maskValues[i / 32] or (1 shl (sourceParameterIndex % 32)) } valueArgument ?: nullConst(startOffset, endOffset, parameter)?.let { IrCompositeImpl( @@ -440,3 +448,6 @@ private fun IrFunction.generateDefaultsFunctionImpl( annotations.mapTo(newFunction.annotations) { it.deepCopyWithSymbols() } return newFunction } + +private fun IrValueParameter.isMovedReceiver() = + origin == IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER || 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 85691ba9130..2a0d63d3bb0 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 @@ -307,7 +307,8 @@ private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, jv 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) - irParameter.origin == IrDeclarationOrigin.MOVED_RECEIVER_PARAMETER -> Opcodes.ACC_SYNTHETIC + irParameter.origin == IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER -> Opcodes.ACC_MANDATED + irParameter.origin == IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER -> Opcodes.ACC_SYNTHETIC irParameter.origin == BOUND_VALUE_PARAMETER -> Opcodes.ACC_SYNTHETIC irParameter.origin == BOUND_RECEIVER_PARAMETER -> Opcodes.ACC_SYNTHETIC irParameter.origin.isSynthetic -> Opcodes.ACC_SYNTHETIC 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 5ccf2ce0bb3..49b45cfc132 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 @@ -182,8 +182,12 @@ class MemoizedInlineClassReplacements { function.extensionReceiverParameter -> Name.identifier("\$receiver") else -> parameter.name } - - val newParameter = parameter.copyTo(this, index = index, name = name, defaultValue = null) + val parameterOrigin = when (parameter) { + function.dispatchReceiverParameter -> IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER + function.extensionReceiverParameter -> IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER + else -> parameter.origin + } + val newParameter = parameter.copyTo(this, index = index, name = name, defaultValue = null, origin = parameterOrigin) valueParameters.add(newParameter) // See comment next to a similar line above. newParameter.defaultValue = parameter.defaultValue?.patchDeclarationParents(this) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index 8988283a583..9859317a137 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -32,7 +32,8 @@ interface IrDeclarationOrigin { object MASK_FOR_DEFAULT_FUNCTION : IrDeclarationOriginImpl("MASK_FOR_DEFAULT_FUNCTION", isSynthetic = true) object DEFAULT_CONSTRUCTOR_MARKER : IrDeclarationOriginImpl("DEFAULT_CONSTRUCTOR_MARKER", isSynthetic = true) object METHOD_HANDLER_IN_DEFAULT_FUNCTION : IrDeclarationOriginImpl("METHOD_HANDLER_IN_DEFAULT_FUNCTION", isSynthetic = true) - object MOVED_RECEIVER_PARAMETER : IrDeclarationOriginImpl("MOVED_RECEIVER_PARAMETER") + object MOVED_DISPATCH_RECEIVER : IrDeclarationOriginImpl("MOVED_DISPATCH_RECEIVER") + object MOVED_EXTENSION_RECEIVER : IrDeclarationOriginImpl("MOVED_EXTENSION_RECEIVER") object FILE_CLASS : IrDeclarationOriginImpl("FILE_CLASS") object GENERATED_DATA_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_DATA_CLASS_MEMBER") diff --git a/compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt b/compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt new file mode 100644 index 00000000000..19f6b3c66f7 --- /dev/null +++ b/compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt @@ -0,0 +1,29 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// SKIP_JDK6 +// TARGET_BACKEND: JVM +// WITH_RUNTIME +// FULL_JDK +// KOTLIN_CONFIGURATION_FLAGS: +JVM.PARAMETERS_METADATA + +// FILE: A.kt + +inline class A(val i: Int) { + fun f() = i +} + +fun A.extension() = this.i + +fun box(): String { + val method = Class.forName("A").declaredMethods.single { it.name == "f-impl" } + val parameters = method.getParameters() + if (!parameters[0].isSynthetic()) return "wrong modifier on receiver parameter: ${parameters[0].modifiers}" + + val extensionMethod = Class.forName("AKt").declaredMethods.single { it.name.contains("extension") } + val extensionMethodParameters = extensionMethod.getParameters() + if (extensionMethodParameters[0].isSynthetic()) + return "wrong modifier (synthetic) on extension receiver parameter: ${extensionMethodParameters[0].modifiers}" + if (!extensionMethodParameters[0].isImplicit()) + return "wrong modifier (not implicit) on extension receiver parameter: ${extensionMethodParameters[0].modifiers}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt b/compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt new file mode 100644 index 00000000000..d98a66dd97e --- /dev/null +++ b/compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt @@ -0,0 +1,28 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// IGNORE_BACKEND: JVM_IR +// SKIP_JDK6 +// TARGET_BACKEND: JVM +// WITH_RUNTIME +// FULL_JDK +// KOTLIN_CONFIGURATION_FLAGS: +JVM.PARAMETERS_METADATA + +// FILE: A.kt + +inline class A(val i: Int) { + fun f() = i +} + +fun A.extension() = this.i + +fun box(): String { + val method = Class.forName("A").declaredMethods.single { it.name == "f-impl" } + val parameters = method.getParameters() + if (parameters[0].name != "arg0") return "wrong name on receiver parameter: ${parameters[0].name}" + + val extensionMethod = Class.forName("AKt").declaredMethods.single { it.name.contains("extension") } + val extensionMethodParameters = extensionMethod.getParameters() + if (extensionMethodParameters[0].name != "\$this\$extension") + return "wrong name on extension receiver parameter: ${extensionMethodParameters[0].name}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt b/compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt index feb19876dde..841abbf58bc 100644 --- a/compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt +++ b/compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.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 @@ -23,17 +23,19 @@ class D(e: S, f: S = S("f")) { fun S.extension(h: S = S("h")): S = this + h fun box(): String { + assertEquals(S("ab"), C().member(S("a"))) assertEquals(S("ab"), C::member.callBy(C::member.parameters.filter { it.name != "b" }.associate { it to (if (it.name == "a") S("a") else C()) })) + assertEquals(S("cd"), topLevel(S("c"))) assertEquals(S("cd"), ::topLevel.callBy(::topLevel.parameters.filter { it.name != "d" }.associate { it to S("c") })) // assertEquals(S("ef"), ::D.callBy(::D.parameters.filter { it.name != "f" }.associate { it to S("e") }).result) + assertEquals(S("gh"), S("g").extension()) assertEquals(S("gh"), S::extension.callBy(S::extension.parameters.filter { it.name != "h" }.associate { it to S("g") })) - val boundMember = C()::member assertEquals(S("ab"), boundMember.callBy(boundMember.parameters.associate { it to S(it.name!!) })) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 055ce43c896..7a3026aaa17 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -18571,6 +18571,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/parametersMetadata/function.kt"); } + @TestMetadata("inlineClassMethodParameterModifiers.kt") + public void testInlineClassMethodParameterModifiers() throws Exception { + runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt"); + } + + @TestMetadata("inlineClassMethodParameterNames.kt") + public void testInlineClassMethodParameterNames() throws Exception { + runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt"); + } + @TestMetadata("innerClass.kt") public void testInnerClass() throws Exception { runTest("compiler/testData/codegen/box/parametersMetadata/innerClass.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index c42c2ea64f1..1b6f8edb22e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -18571,6 +18571,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/parametersMetadata/function.kt"); } + @TestMetadata("inlineClassMethodParameterModifiers.kt") + public void testInlineClassMethodParameterModifiers() throws Exception { + runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt"); + } + + @TestMetadata("inlineClassMethodParameterNames.kt") + public void testInlineClassMethodParameterNames() throws Exception { + runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt"); + } + @TestMetadata("innerClass.kt") public void testInnerClass() throws Exception { runTest("compiler/testData/codegen/box/parametersMetadata/innerClass.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index d17ff45e633..e850f558e79 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -17055,6 +17055,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/parametersMetadata/function.kt"); } + @TestMetadata("inlineClassMethodParameterModifiers.kt") + public void testInlineClassMethodParameterModifiers() throws Exception { + runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt"); + } + + @TestMetadata("inlineClassMethodParameterNames.kt") + public void testInlineClassMethodParameterNames() throws Exception { + runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt"); + } + @TestMetadata("innerClass.kt") public void testInnerClass() throws Exception { runTest("compiler/testData/codegen/box/parametersMetadata/innerClass.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 892ce812f9c..c847d58b116 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -17055,6 +17055,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/parametersMetadata/function.kt"); } + @TestMetadata("inlineClassMethodParameterModifiers.kt") + public void testInlineClassMethodParameterModifiers() throws Exception { + runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt"); + } + + @TestMetadata("inlineClassMethodParameterNames.kt") + public void testInlineClassMethodParameterNames() throws Exception { + runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt"); + } + @TestMetadata("innerClass.kt") public void testInnerClass() throws Exception { runTest("compiler/testData/codegen/box/parametersMetadata/innerClass.kt");