[JVM_IR] Fix offsets in constant propagation optimization.

Loads of temporary variables that contain constants are replaced
with a copy of the constant. This avoids locals loads and stores.
However, the copy of the constant needs to have the offset of
the load and not of the original constant.

Fixes KT-41963.
This commit is contained in:
Mads Ager
2020-09-21 13:50:32 +02:00
committed by Alexander Udalov
parent f273edeb8e
commit 78483930bc
10 changed files with 94 additions and 8 deletions
@@ -13,8 +13,10 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetField
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.ir.types.isPrimitiveType
import org.jetbrains.kotlin.ir.types.isStringClassType
@@ -41,9 +43,6 @@ fun IrField.constantValue(context: JvmBackendContext? = null): IrConst<*>? {
return if (implicitConst || correspondingPropertySymbol?.owner?.isConst == true) value else null
}
private fun <T> IrConst<T>.copyWithOffsets(startOffset: Int, endOffset: Int) =
IrConstImpl(startOffset, endOffset, type, kind, value)
class ConstLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid()
@@ -347,7 +347,7 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass
// initializer with the constant initializer.
val variable = expression.symbol.owner
return if (isImmutableTemporaryVariableWithConstantValue(variable))
((variable as IrVariable).initializer!! as IrConst<*>).copy()
((variable as IrVariable).initializer!! as IrConst<*>).copyWithOffsets(expression.startOffset, expression.endOffset)
else
expression
}
@@ -21,6 +21,7 @@ abstract class IrConst<T> : IrExpression(), IrExpressionWithCopy {
abstract val value: T
abstract override fun copy(): IrConst<T>
abstract fun copyWithOffsets(startOffset: Int, endOffset: Int): IrConst<T>
}
sealed class IrConstKind<T>(val asString: kotlin.String) {
@@ -34,6 +34,9 @@ class IrConstImpl<T>(
override fun copy(): IrConst<T> =
IrConstImpl(startOffset, endOffset, type, kind, value)
override fun copyWithOffsets(startOffset: Int, endOffset: Int) =
IrConstImpl(startOffset, endOffset, type, kind, value)
companion object {
fun string(startOffset: Int, endOffset: Int, type: IrType, value: String): IrConstImpl<String> =
IrConstImpl(startOffset, endOffset, type, IrConstKind.String, value)
+25
View File
@@ -0,0 +1,25 @@
// FILE: test.kt
fun box() {
when (1) {
2 ->
"2"
3 ->
"3"
else ->
"1"
}
}
// JVM_IR and JVM backends have different heuristics for when to use a switch.
// JVM_IR does not use a switch in this case and therefore steps to the evaluation
// of the condition for each of the cases.
// LINENUMBERS
// test.kt:4 box
// LINENUMBERS JVM_IR
// test.kt:5 box
// test.kt:7 box
// LINENUMBERS
// test.kt:10 box
// test.kt:12 box
@@ -433,6 +433,12 @@ public class IrSteppingTestGenerated extends AbstractIrSteppingTest {
runTest("compiler/testData/debug/stepping/whenComplicatedSubject.kt");
}
@Test
@TestMetadata("whenConstant.kt")
public void testWhenConstant() throws Exception {
runTest("compiler/testData/debug/stepping/whenConstant.kt");
}
@Test
@TestMetadata("whenIsChecks.kt")
public void testWhenIsChecks() throws Exception {
@@ -433,6 +433,12 @@ public class SteppingTestGenerated extends AbstractSteppingTest {
runTest("compiler/testData/debug/stepping/whenComplicatedSubject.kt");
}
@Test
@TestMetadata("whenConstant.kt")
public void testWhenConstant() throws Exception {
runTest("compiler/testData/debug/stepping/whenConstant.kt");
}
@Test
@TestMetadata("whenIsChecks.kt")
public void testWhenIsChecks() throws Exception {
@@ -0,0 +1,43 @@
LineBreakpoint created at stepOverWhenWithInline.kt:5
Run Java
Connected to the target VM
stepOverWhenWithInline.kt:5
stepOverWhenWithInline.kt:7
stepOverWhenWithInline.kt:8
stepOverWhenWithInline.kt:9
stepOverWhenWithInline.kt:7
stepOverWhenWithInline.kt:13
stepOverWhenWithInline.kt:14
stepOverWhenWithInline.kt:17
stepOverWhenWithInline.kt:18
stepOverWhenWithInline.kt:13
stepOverWhenWithInline.kt:25
stepOverWhenWithInline.kt:26
stepOverWhenWithInline.kt:27
stepOverWhenWithInline.kt:25
stepOverWhenWithInline.kt:32
stepOverWhenWithInline.kt:33
stepOverWhenWithInline.kt:34
stepOverWhenWithInline.kt:32
stepOverWhenWithInline.kt:38
stepOverWhenWithInline.kt:39
stepOverWhenWithInline.kt:42
stepOverWhenWithInline.kt:43
stepOverWhenWithInline.kt:38
stepOverWhenWithInline.kt:51
stepOverWhenWithInline.kt:52
stepOverWhenWithInline.kt:51
stepOverWhenWithInline.kt:57
stepOverWhenWithInline.kt:58
stepOverWhenWithInline.kt:57
stepOverWhenWithInline.kt:63
stepOverWhenWithInline.kt:64
stepOverWhenWithInline.kt:65
stepOverWhenWithInline.kt:63
stepOverWhenWithInline.kt:75
stepOverWhenWithInline.kt:76
stepOverWhenWithInline.kt:75
stepOverWhenWithInline.kt:80
Disconnected from the target VM
Process finished with exit code 0
@@ -86,4 +86,7 @@ inline fun foo(f: () -> Int): Int {
fun test(i: Int) = i
// STEP_OVER: 32
// STEP_OVER: 36
// JVM_IR and JVM backends have different heuristics for when to use a table switch.
// This results is minor differences in step over behavior.
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
LineBreakpoint created at stepOverWhenWithInline.kt:5
Run Java
Connected to the target VM
@@ -35,6 +34,7 @@ stepOverWhenWithInline.kt:63
stepOverWhenWithInline.kt:75
stepOverWhenWithInline.kt:76
stepOverWhenWithInline.kt:75
stepOverWhenWithInline.kt:80
Disconnected from the target VM
Process finished with exit code 0