From 7b4e0b2f5d335c0e9a57d3659989695ad9e0c77e Mon Sep 17 00:00:00 2001 From: Mads Ager Date: Wed, 4 Nov 2020 15:59:26 +0100 Subject: [PATCH] [JVM_IR] Deal with lowering ordering issues for JvmStatic function references. Do not destructively update the @JvmStatic function, instead create a copy on first access, and replace the original with the copy in the jvm static lowering. This ensures that the original function is seen in other lowerings independently of file lowering order. --- .../ir/FirBlackBoxCodegenTestGenerated.java | 5 ++ .../kotlin/backend/jvm/JvmBackendContext.kt | 2 + .../jvm/lower/JvmStaticAnnotationLowering.kt | 66 +++++++++++++------ .../box/jvmStatic/functionReference.kt | 13 ++++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 ++ .../LightAnalysisModeTestGenerated.java | 5 ++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 ++ 7 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 compiler/testData/codegen/box/jvmStatic/functionReference.kt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index b7a9c69695a..e060073994a 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -17779,6 +17779,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt"); } + @TestMetadata("functionReference.kt") + public void testFunctionReference() throws Exception { + runTest("compiler/testData/codegen/box/jvmStatic/functionReference.kt"); + } + @TestMetadata("importStaticMemberFromObject.kt") public void testImportStaticMemberFromObject() throws Exception { runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt"); diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index 5fc528ef78e..75fd6b0263c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -129,6 +129,8 @@ class JvmBackendContext( val suspendFunctionOriginalToView = mutableMapOf() val fakeContinuation: IrExpression = createFakeContinuation(this) + val jvmStaticObjectFunctionToStaticFunctionMap = mutableMapOf() + val staticDefaultStubs = mutableMapOf() val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt index a1c0d7be115..81cf15b7cd3 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt @@ -17,8 +17,8 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.ir.copyCorrespondingPropertyFrom import org.jetbrains.kotlin.backend.jvm.ir.isInCurrentModule import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference -import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.builders.declarations.addFunction import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.irCall @@ -127,36 +127,62 @@ private class CompanionObjectJvmStaticLowering(val context: JvmBackendContext) : } } -private class SingletonObjectJvmStaticLowering( - val context: JvmBackendContext -) : ClassLoweringPass { +private class SingletonObjectJvmStaticLowering(val context: JvmBackendContext) : ClassLoweringPass { override fun lower(irClass: IrClass) { if (!irClass.isObject || irClass.isCompanion) return - irClass.declarations.filter(::isJvmStaticFunction).forEach { - val jvmStaticFunction = it as IrSimpleFunction + val jvmStaticFunctionsToReplace = irClass.declarations.filter { // dispatch receiver parameter is already null for synthetic property annotation methods - jvmStaticFunction.dispatchReceiverParameter?.let { oldDispatchReceiverParameter -> - jvmStaticFunction.dispatchReceiverParameter = null - jvmStaticFunction.body = jvmStaticFunction.body?.replaceThisByStaticReference( - context.cachedDeclarations, - irClass, - oldDispatchReceiverParameter - ) - } + isJvmStaticFunction(it) && it is IrSimpleFunction && it.dispatchReceiverParameter != null + } + jvmStaticFunctionsToReplace.forEach { function -> + val replacement = createReplacement(context, function as IrSimpleFunction) + // Set dispatch receiver parameter for body move operation. + replacement.dispatchReceiverParameter = function.dispatchReceiverParameter + replacement.body = function.moveBodyTo(replacement)?.replaceThisByStaticReference( + context.cachedDeclarations, + irClass, + function.dispatchReceiverParameter!! + ) + // Clear dispatch receiver parameter again after body move operation. + replacement.dispatchReceiverParameter = null + irClass.declarations.remove(function) + irClass.declarations.add(replacement) } } - } +private fun createReplacement( + context: JvmBackendContext, + jvmStaticFunction: IrSimpleFunction +): IrSimpleFunction = + context.jvmStaticObjectFunctionToStaticFunctionMap.getOrPut(jvmStaticFunction) { + val irClass = jvmStaticFunction.parentAsClass + val newFunction = context.irFactory.buildFun { + updateFrom(jvmStaticFunction) + name = jvmStaticFunction.name + returnType = jvmStaticFunction.returnType + }.apply { + parent = irClass + copyTypeParametersFrom(jvmStaticFunction) + copyAnnotationsFrom(jvmStaticFunction) + extensionReceiverParameter = jvmStaticFunction.extensionReceiverParameter?.copyTo(this) + valueParameters = jvmStaticFunction.valueParameters.map { it.copyTo(this) } + copyAttributes(jvmStaticFunction) + copyCorrespondingPropertyFrom(jvmStaticFunction) + metadata = jvmStaticFunction.metadata + } + context.jvmStaticObjectFunctionToStaticFunctionMap[jvmStaticFunction] = newFunction + newFunction + } + + private fun IrFunction.isJvmStaticInSingleton(): Boolean { val parentClass = parent as? IrClass ?: return false return isJvmStaticFunction(this) && parentClass.isObject && !parentClass.isCompanion } -private class MakeCallsStatic( - val context: JvmBackendContext -) : IrElementTransformerVoid() { +private class MakeCallsStatic(val context: JvmBackendContext) : IrElementTransformerVoid() { override fun visitCall(expression: IrCall): IrExpression { if (expression.symbol.owner.isJvmStaticInSingleton() && expression.dispatchReceiver != null) { // Imported functions do not have their receiver parameter nulled by SingletonObjectJvmStaticLowering, @@ -165,7 +191,9 @@ private class MakeCallsStatic( val callee = expression.symbol.owner val newCallee = if (!callee.isInCurrentModule()) { callee.copyRemovingDispatchReceiver() // TODO: cache these - } else callee + } else { + createReplacement(context, callee) + } return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).irBlock(expression) { // OldReceiver has to be evaluated for its side effects. diff --git a/compiler/testData/codegen/box/jvmStatic/functionReference.kt b/compiler/testData/codegen/box/jvmStatic/functionReference.kt new file mode 100644 index 00000000000..93f187f3904 --- /dev/null +++ b/compiler/testData/codegen/box/jvmStatic/functionReference.kt @@ -0,0 +1,13 @@ +// TARGET_BACKEND: JVM + +// WITH_RUNTIME +// FILE: u1.kt + +object O { + @JvmStatic + fun foo() = "OK" +} + +// FILE: u2.kt + +fun box() = (O::foo)() diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index aeb7c5cf9b2..bfb847b9f6e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -19179,6 +19179,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt"); } + @TestMetadata("functionReference.kt") + public void testFunctionReference() throws Exception { + runTest("compiler/testData/codegen/box/jvmStatic/functionReference.kt"); + } + @TestMetadata("importStaticMemberFromObject.kt") public void testImportStaticMemberFromObject() throws Exception { runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 06ce5e9fda9..96d8a6ee25b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -19179,6 +19179,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt"); } + @TestMetadata("functionReference.kt") + public void testFunctionReference() throws Exception { + runTest("compiler/testData/codegen/box/jvmStatic/functionReference.kt"); + } + @TestMetadata("importStaticMemberFromObject.kt") public void testImportStaticMemberFromObject() throws Exception { runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 3afc9182e33..bcf94dd10fe 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -17779,6 +17779,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt"); } + @TestMetadata("functionReference.kt") + public void testFunctionReference() throws Exception { + runTest("compiler/testData/codegen/box/jvmStatic/functionReference.kt"); + } + @TestMetadata("importStaticMemberFromObject.kt") public void testImportStaticMemberFromObject() throws Exception { runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt");