JVM_IR: default-initialize variables visible in the LVT
See KT-36812. Aside from the problem stated there, D8 will throw out the entire LVT if it sees a variable that has not been written to (and will generate incorrect SSA if the slot is reused with a different type). Note: this only fixes a FIR test because it's missing an `else -> throw` branch, and default initialization satisfies the verifier and masks the incorrect control flow.
This commit is contained in:
+13
-13
@@ -322,18 +322,14 @@ class ExpressionCodegen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val IrVariable.isVisibleInLVT: Boolean
|
||||||
|
get() = origin != IrDeclarationOrigin.IR_TEMPORARY_VARIABLE &&
|
||||||
|
origin != IrDeclarationOrigin.FOR_LOOP_ITERATOR
|
||||||
|
|
||||||
private fun writeLocalVariablesInTable(info: BlockInfo, endLabel: Label) {
|
private fun writeLocalVariablesInTable(info: BlockInfo, endLabel: Label) {
|
||||||
info.variables.forEach {
|
info.variables.forEach {
|
||||||
when (it.declaration.origin) {
|
if (it.declaration.isVisibleInLVT) {
|
||||||
IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
|
mv.visitLocalVariable(it.declaration.name.asString(), it.type.descriptor, null, it.startLabel, endLabel, it.index)
|
||||||
IrDeclarationOrigin.FOR_LOOP_ITERATOR -> {
|
|
||||||
// Ignore implicitly created variables
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
mv.visitLocalVariable(
|
|
||||||
it.declaration.name.asString(), it.type.descriptor, null, it.startLabel, endLabel, it.index
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,9 +481,13 @@ class ExpressionCodegen(
|
|||||||
|
|
||||||
declaration.markLineNumber(startOffset = true)
|
declaration.markLineNumber(startOffset = true)
|
||||||
|
|
||||||
declaration.initializer?.let {
|
val initializer = declaration.initializer
|
||||||
it.accept(this, data).coerce(varType, declaration.type).materialize()
|
if (initializer != null) {
|
||||||
it.markLineNumber(startOffset = true)
|
initializer.accept(this, data).coerce(varType, declaration.type).materialize()
|
||||||
|
initializer.markLineNumber(startOffset = true)
|
||||||
|
mv.store(index, varType)
|
||||||
|
} else if (declaration.isVisibleInLVT) {
|
||||||
|
pushDefaultValueOnStack(varType, mv)
|
||||||
mv.store(index, varType)
|
mv.store(index, varType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
sealed class A {
|
sealed class A {
|
||||||
object B : A()
|
object B : A()
|
||||||
|
|
||||||
|
|||||||
-3
@@ -1,6 +1,3 @@
|
|||||||
// This test checks, that different variables occupy the same slot
|
|
||||||
// In JVM_IR, however, loop variable's lifetime goes beyond the loop itself, thus the test has no sense in JVM_IR
|
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|
||||||
import helpers.*
|
import helpers.*
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// TODO KT-36648 Captured variables not optimized in JVM_IR
|
// TODO KT-36648 Captured variables not optimized in JVM_IR
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
fun test(): java.lang.Integer {
|
fun test(): java.lang.Integer {
|
||||||
val c: java.lang.Integer
|
val c: java.lang.Integer
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
@@ -22,4 +20,4 @@ fun doIt(block: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0 ISTORE 0
|
// 0 ISTORE 0
|
||||||
// 1 LOCALVARIABLE c Lkotlin/jvm/internal/Ref\$CharRef; L1 L3 0
|
// 1 LOCALVARIABLE c Lkotlin/jvm/internal/Ref\$CharRef;
|
||||||
+2
-4
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
@@ -22,8 +20,8 @@ fun doIt(block: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0 ISTORE 0
|
// 0 ISTORE 0
|
||||||
// 1 LOCALVARIABLE c Lkotlin/jvm/internal/Ref\$CharRef; L1 L3 0
|
// 1 LOCALVARIABLE c Lkotlin/jvm/internal/Ref\$CharRef;
|
||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 0 ISTORE 0
|
// 0 ISTORE 0
|
||||||
// 1 LOCALVARIABLE c Lkotlin/jvm/internal/Ref\$CharRef; L1 L4 0
|
// 1 LOCALVARIABLE c Lkotlin/jvm/internal/Ref\$CharRef;
|
||||||
+1
-4
@@ -1,6 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
fun test(): Char {
|
fun test(): Char {
|
||||||
@@ -14,4 +11,4 @@ fun test(): Char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3 ISTORE 0
|
// 3 ISTORE 0
|
||||||
// 1 LOCALVARIABLE c C L1 L7 0
|
// 1 LOCALVARIABLE c C
|
||||||
|
|||||||
+1
-4
@@ -1,6 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
fun test(): Char {
|
fun test(): Char {
|
||||||
@@ -14,4 +11,4 @@ fun test(): Char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3 ISTORE 0
|
// 3 ISTORE 0
|
||||||
// 1 LOCALVARIABLE c C L1 L7 0
|
// 1 LOCALVARIABLE c C
|
||||||
|
|||||||
-3
@@ -1,6 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
fun test(): Char {
|
fun test(): Char {
|
||||||
|
|||||||
Vendored
-3
@@ -1,6 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
fun test(): Char {
|
fun test(): Char {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// TODO KT-36648 Captured variables not optimized in JVM_IR
|
// TODO KT-36648 Captured variables not optimized in JVM_IR
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
fun test(): UInt {
|
fun test(): UInt {
|
||||||
val c: UInt
|
val c: UInt
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// TODO KT-36648 Captured variables not optimized in JVM_IR
|
// TODO KT-36648 Captured variables not optimized in JVM_IR
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
fun test(): UInt {
|
fun test(): UInt {
|
||||||
var c: UInt
|
var c: UInt
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// TODO KT-36648 Captured variables not optimized in JVM_IR
|
// TODO KT-36648 Captured variables not optimized in JVM_IR
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
fun test(): Char {
|
fun test(): Char {
|
||||||
lateinit var c: Any
|
lateinit var c: Any
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
// IGNORE_BACKEND: JVM_IR
|
||||||
// TODO KT-36648 Captured variables not optimized in JVM_IR
|
// TODO KT-36648 Captured variables not optimized in JVM_IR
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
fun test(): Char {
|
fun test(): Char {
|
||||||
val c: Char
|
val c: Char
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
fun test(): Char {
|
fun test(): Char {
|
||||||
val c: Char
|
val c: Char
|
||||||
val l = Any()
|
val l = Any()
|
||||||
|
|||||||
-3
@@ -1,6 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
fun test(): Char {
|
fun test(): Char {
|
||||||
var c: Char
|
var c: Char
|
||||||
val l = Any()
|
val l = Any()
|
||||||
|
|||||||
+1
-4
@@ -1,6 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
fun test(i: Int): Char {
|
fun test(i: Int): Char {
|
||||||
val c: Char
|
val c: Char
|
||||||
when (i) {
|
when (i) {
|
||||||
@@ -20,4 +17,4 @@ fun test(i: Int): Char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 12 ISTORE 1
|
// 12 ISTORE 1
|
||||||
// 1 LOCALVARIABLE c C L1 L16 1
|
// 1 LOCALVARIABLE c C
|
||||||
|
|||||||
+1
-4
@@ -1,6 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TODO KT-36812 Generate proper lifetime intervals for local variables in JVM_IR
|
|
||||||
|
|
||||||
fun test(i: Int): Char {
|
fun test(i: Int): Char {
|
||||||
var c: Char
|
var c: Char
|
||||||
when (i) {
|
when (i) {
|
||||||
@@ -20,4 +17,4 @@ fun test(i: Int): Char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 12 ISTORE 1
|
// 12 ISTORE 1
|
||||||
// 1 LOCALVARIABLE c C L1 L16 1
|
// 1 LOCALVARIABLE c C
|
||||||
|
|||||||
Reference in New Issue
Block a user