[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.
This commit is contained in:
Mads Ager
2020-11-04 15:59:26 +01:00
committed by Alexander Udalov
parent 3d2f5f4bc1
commit 7b4e0b2f5d
7 changed files with 82 additions and 19 deletions
@@ -17779,6 +17779,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt"); 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") @TestMetadata("importStaticMemberFromObject.kt")
public void testImportStaticMemberFromObject() throws Exception { public void testImportStaticMemberFromObject() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt"); runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt");
@@ -129,6 +129,8 @@ class JvmBackendContext(
val suspendFunctionOriginalToView = mutableMapOf<IrFunction, IrFunction>() val suspendFunctionOriginalToView = mutableMapOf<IrFunction, IrFunction>()
val fakeContinuation: IrExpression = createFakeContinuation(this) val fakeContinuation: IrExpression = createFakeContinuation(this)
val jvmStaticObjectFunctionToStaticFunctionMap = mutableMapOf<IrSimpleFunction, IrSimpleFunction>()
val staticDefaultStubs = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>() val staticDefaultStubs = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>()
val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory) val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory)
@@ -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.copyCorrespondingPropertyFrom
import org.jetbrains.kotlin.backend.jvm.ir.isInCurrentModule import org.jetbrains.kotlin.backend.jvm.ir.isInCurrentModule
import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference 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.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.builders.declarations.addFunction import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irCall
@@ -127,36 +127,62 @@ private class CompanionObjectJvmStaticLowering(val context: JvmBackendContext) :
} }
} }
private class SingletonObjectJvmStaticLowering( private class SingletonObjectJvmStaticLowering(val context: JvmBackendContext) : ClassLoweringPass {
val context: JvmBackendContext
) : ClassLoweringPass {
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
if (!irClass.isObject || irClass.isCompanion) return if (!irClass.isObject || irClass.isCompanion) return
irClass.declarations.filter(::isJvmStaticFunction).forEach { val jvmStaticFunctionsToReplace = irClass.declarations.filter {
val jvmStaticFunction = it as IrSimpleFunction
// dispatch receiver parameter is already null for synthetic property annotation methods // dispatch receiver parameter is already null for synthetic property annotation methods
jvmStaticFunction.dispatchReceiverParameter?.let { oldDispatchReceiverParameter -> isJvmStaticFunction(it) && it is IrSimpleFunction && it.dispatchReceiverParameter != null
jvmStaticFunction.dispatchReceiverParameter = null }
jvmStaticFunction.body = jvmStaticFunction.body?.replaceThisByStaticReference( jvmStaticFunctionsToReplace.forEach { function ->
context.cachedDeclarations, val replacement = createReplacement(context, function as IrSimpleFunction)
irClass, // Set dispatch receiver parameter for body move operation.
oldDispatchReceiverParameter 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 { private fun IrFunction.isJvmStaticInSingleton(): Boolean {
val parentClass = parent as? IrClass ?: return false val parentClass = parent as? IrClass ?: return false
return isJvmStaticFunction(this) && parentClass.isObject && !parentClass.isCompanion return isJvmStaticFunction(this) && parentClass.isObject && !parentClass.isCompanion
} }
private class MakeCallsStatic( private class MakeCallsStatic(val context: JvmBackendContext) : IrElementTransformerVoid() {
val context: JvmBackendContext
) : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
if (expression.symbol.owner.isJvmStaticInSingleton() && expression.dispatchReceiver != null) { if (expression.symbol.owner.isJvmStaticInSingleton() && expression.dispatchReceiver != null) {
// Imported functions do not have their receiver parameter nulled by SingletonObjectJvmStaticLowering, // Imported functions do not have their receiver parameter nulled by SingletonObjectJvmStaticLowering,
@@ -165,7 +191,9 @@ private class MakeCallsStatic(
val callee = expression.symbol.owner val callee = expression.symbol.owner
val newCallee = if (!callee.isInCurrentModule()) { val newCallee = if (!callee.isInCurrentModule()) {
callee.copyRemovingDispatchReceiver() // TODO: cache these callee.copyRemovingDispatchReceiver() // TODO: cache these
} else callee } else {
createReplacement(context, callee)
}
return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).irBlock(expression) { return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).irBlock(expression) {
// OldReceiver has to be evaluated for its side effects. // OldReceiver has to be evaluated for its side effects.
@@ -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)()
@@ -19179,6 +19179,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt"); 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") @TestMetadata("importStaticMemberFromObject.kt")
public void testImportStaticMemberFromObject() throws Exception { public void testImportStaticMemberFromObject() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt"); runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt");
@@ -19179,6 +19179,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt"); 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") @TestMetadata("importStaticMemberFromObject.kt")
public void testImportStaticMemberFromObject() throws Exception { public void testImportStaticMemberFromObject() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt"); runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt");
@@ -17779,6 +17779,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt"); 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") @TestMetadata("importStaticMemberFromObject.kt")
public void testImportStaticMemberFromObject() throws Exception { public void testImportStaticMemberFromObject() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt"); runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt");