Safely unfold callable reference instruction in interpreter

There was an assumption that if receiver exists then parameter will
also exist. This is not true for references marked with `JvmStatic`.
Later in `JvmStaticInObjectLowering` dispatch receiver may be dropped.
This commit is contained in:
Ivan Kylchik
2022-08-18 14:24:11 +03:00
committed by Space
parent 8e17c39cc9
commit 4e740e91f2
6 changed files with 68 additions and 24 deletions
@@ -16889,6 +16889,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/evaluate/plus.kt");
}
@Test
@TestMetadata("referenceNameFromStaticInDifferentModule.kt")
public void testReferenceNameFromStaticInDifferentModule() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/referenceNameFromStaticInDifferentModule.kt");
}
@Test
@TestMetadata("rem.kt")
public void testRem() throws Exception {
@@ -416,28 +416,21 @@ private fun unfoldComposite(element: IrComposite, callStack: CallStack) {
}
}
private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) {
val function = reference.symbol.owner
private fun unfoldCallableReference(reference: IrCallableReference<*>, callStack: CallStack) {
callStack.pushSimpleInstruction(reference)
reference.getArgumentsWithIr().forEach { (parameter, arg) ->
callStack.pushSimpleInstruction(parameter)
callStack.pushCompoundInstruction(arg)
}
}
reference.dispatchReceiver?.let { callStack.pushSimpleInstruction(function.dispatchReceiverParameter!!) }
reference.extensionReceiver?.let { callStack.pushSimpleInstruction(function.extensionReceiverParameter!!) }
reference.extensionReceiver?.let { callStack.pushCompoundInstruction(it) }
reference.dispatchReceiver?.let { callStack.pushCompoundInstruction(it) }
private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) {
unfoldCallableReference(reference, callStack)
}
private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) {
callStack.pushSimpleInstruction(propertyReference)
val getter = propertyReference.getter?.owner
if (getter != null) {
propertyReference.dispatchReceiver?.let { callStack.pushSimpleInstruction(getter.dispatchReceiverParameter!!) }
propertyReference.extensionReceiver?.let { callStack.pushSimpleInstruction(getter.extensionReceiverParameter!!) }
propertyReference.extensionReceiver?.let { callStack.pushCompoundInstruction(it) }
propertyReference.dispatchReceiver?.let { callStack.pushCompoundInstruction(it) }
}
if (propertyReference.field != null) return callStack.pushSimpleInstruction(propertyReference)
unfoldCallableReference(propertyReference, callStack)
}
private fun unfoldClassReference(classReference: IrClassReference, callStack: CallStack) {
@@ -566,8 +566,8 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
private fun interpretFunctionReference(reference: IrFunctionReference) {
val irFunction = reference.symbol.owner
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.popState() }
val extensionReceiver = reference.extensionReceiver?.let { callStack.popState() }
val dispatchReceiver = irFunction.getDispatchReceiver()?.let { reference.dispatchReceiver?.let { callStack.popState() } }
val extensionReceiver = irFunction.getExtensionReceiver()?.let { reference.extensionReceiver?.let { callStack.popState() } }
val function = KFunctionState(
reference,
@@ -581,7 +581,11 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
private fun interpretPropertyReference(propertyReference: IrPropertyReference) {
// it is impossible to get KProperty2 through ::, so only one receiver can be not null (or both null)
val receiver = (propertyReference.dispatchReceiver ?: propertyReference.extensionReceiver)?.let { callStack.popState() }
val getter = propertyReference.getter?.owner
val dispatchReceiver = getter?.getDispatchReceiver()?.let { propertyReference.dispatchReceiver?.let { callStack.popState() } }
val extensionReceiver = getter?.getExtensionReceiver()?.let { propertyReference.extensionReceiver?.let { callStack.popState() } }
val receiver = dispatchReceiver ?: extensionReceiver
val propertyState = KPropertyState(propertyReference, receiver)
fun List<IrTypeParameter>.addToFields() {
@@ -108,12 +108,12 @@ fun IrMemberAccessExpression<*>.getArgumentsWithIr(): List<Pair<IrValueParameter
else -> error(this)
}
dispatchReceiver?.let {
res += (irFunction.dispatchReceiverParameter!! to it)
dispatchReceiver?.let { arg ->
irFunction.dispatchReceiverParameter?.let { parameter -> res += (parameter to arg) }
}
extensionReceiver?.let {
res += (irFunction.extensionReceiverParameter!! to it)
extensionReceiver?.let { arg ->
irFunction.extensionReceiverParameter?.let { parameter -> res += (parameter to arg) }
}
irFunction.valueParameters.forEachIndexed { index, it ->
@@ -0,0 +1,35 @@
// TARGET_BACKEND: JVM_IR
// WITH_STDLIB
// MODULE: lib
// FILE: lib.kt
object A {
@JvmStatic
val somePropertyFromObject: Int = 0
@JvmStatic
fun someFunctionFromObject(str: String): String = str
}
class B {
companion object {
@JvmStatic
val somePropertyFromCompanionObject: Int = 0
@JvmStatic
fun someFunctionFromCompanionObject(str: String): String = str
}
}
// MODULE: main(lib)
// FILE: main.kt
fun box(): String {
// `name` call must be optimized with `ConstEvaluationLowering`
if (A::somePropertyFromObject.name != "somePropertyFromObject") return "Fail 1"
if (A::someFunctionFromObject.name != "someFunctionFromObject") return "Fail 2"
if (B.Companion::somePropertyFromCompanionObject.name != "somePropertyFromCompanionObject") return "Fail 3"
if (B.Companion::someFunctionFromCompanionObject.name != "someFunctionFromCompanionObject") return "Fail 4"
return "OK"
}
@@ -16889,6 +16889,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/evaluate/plus.kt");
}
@Test
@TestMetadata("referenceNameFromStaticInDifferentModule.kt")
public void testReferenceNameFromStaticInDifferentModule() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/referenceNameFromStaticInDifferentModule.kt");
}
@Test
@TestMetadata("rem.kt")
public void testRem() throws Exception {