Put default value (null or zero) to slot for uninitialized values
This way range of the variable is correct in LVT. #KT-24672 Fixed
This commit is contained in:
@@ -4039,6 +4039,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
else if (property.hasModifier(KtTokens.LATEINIT_KEYWORD)) {
|
||||
initializeLocalVariable(property, null);
|
||||
}
|
||||
else if (!property.isVar()) {
|
||||
initializeLocalVariableWithFakeDefaultValue(property);
|
||||
}
|
||||
|
||||
return StackValue.none();
|
||||
}
|
||||
@@ -4182,6 +4185,47 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
storeTo.storeSelector(resultType, resultKotlinType, v);
|
||||
}
|
||||
|
||||
// This is a workaround to avoid bugs with incorrect range of uninitialized variable:
|
||||
// 1) JDI error 305
|
||||
// 2) Expected R, got . in code with contracts
|
||||
// 3) D8 dropping the whole LVT
|
||||
private void initializeLocalVariableWithFakeDefaultValue(@NotNull KtProperty variableDeclaration) {
|
||||
LocalVariableDescriptor variableDescriptor = (LocalVariableDescriptor) getVariableDescriptorNotNull(variableDeclaration);
|
||||
|
||||
assert !variableDeclaration.isVar() && !variableDeclaration.hasDelegateExpressionOrInitializer() &&
|
||||
!variableDescriptor.isLateInit() : variableDeclaration.getText() + " in not variable declaration without initializer";
|
||||
|
||||
KotlinType kotlinType = variableDescriptor.getType();
|
||||
Type type = typeMapper.mapType(kotlinType);
|
||||
|
||||
if (type == Type.VOID_TYPE) return;
|
||||
|
||||
int index = lookupLocalIndex(variableDescriptor);
|
||||
assert index >= 0: variableDescriptor + " is not in frame map";
|
||||
|
||||
switch (type.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
case Type.CHAR:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
case Type.INT:
|
||||
v.iconst(0);
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
v.fconst(0.0f);
|
||||
break;
|
||||
case Type.LONG:
|
||||
v.lconst(0L);
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
v.dconst(0.0);
|
||||
break;
|
||||
default:
|
||||
v.aconst(null);
|
||||
}
|
||||
v.store(index, type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generateProvideDelegateCallForLocalVariable(
|
||||
@NotNull StackValue initializer,
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
fun test(): java.lang.Integer {
|
||||
val c: java.lang.Integer
|
||||
run {
|
||||
c = java.lang.Integer(1)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// 2 ASTORE 0
|
||||
// 1 LOCALVARIABLE c Ljava/lang/Integer; L1 L10 0
|
||||
@@ -0,0 +1,25 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@ExperimentalContracts
|
||||
fun test(): Char {
|
||||
val c: Char
|
||||
doIt {
|
||||
c = ' '
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
@ExperimentalContracts
|
||||
fun doIt(block: () -> Unit) {
|
||||
contract {
|
||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
block()
|
||||
}
|
||||
|
||||
// 2 FCONST 0
|
||||
// 1 LOCALVARIABLE c Lkotlin/jvm/internal/Ref$CharRef; L1 L10 0
|
||||
@@ -0,0 +1,16 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline fun <reified T> foo(default: T): T {
|
||||
val t: T
|
||||
run {
|
||||
t = default
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
fun test() {
|
||||
foo(0.0f)
|
||||
}
|
||||
|
||||
// 2 ASTORE 1
|
||||
// 1 LOCALVARIABLE t\$iv Ljava/lang/Object; L2 L11 1
|
||||
@@ -0,0 +1,16 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
import kotlin.random.Random
|
||||
|
||||
fun test(): Char {
|
||||
val c: Char
|
||||
if (Random.nextBoolean()) {
|
||||
c = '1'
|
||||
} else {
|
||||
c = '2'
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// 3 ISTORE 0
|
||||
// 1 LOCALVARIABLE c C L1 L7 0
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
import kotlin.random.Random
|
||||
|
||||
fun test(): Char {
|
||||
val c: Char
|
||||
if (Random.nextBoolean())
|
||||
c = '1'
|
||||
else
|
||||
c = '2'
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// 3 ISTORE 0
|
||||
// 1 LOCALVARIABLE c C L1 L5 0
|
||||
@@ -0,0 +1,12 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
fun test(): UInt {
|
||||
val c: UInt
|
||||
run {
|
||||
c = 1u
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// 2 ISTORE 0
|
||||
// 1 LOCALVARIABLE c I L1 L10 0
|
||||
@@ -0,0 +1,12 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
fun test(): Char {
|
||||
lateinit var c: Any
|
||||
run {
|
||||
c = ' '
|
||||
}
|
||||
return c as Char
|
||||
}
|
||||
|
||||
// 2 ASTORE 0
|
||||
// 1 LOCALVARIABLE c Ljava/lang/Object; L1 L11 0
|
||||
@@ -0,0 +1,14 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
fun test(): Char {
|
||||
val c: Char
|
||||
run {
|
||||
c = ' '
|
||||
println(c)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// The first on declaration, the other on initialization
|
||||
// 2 ISTORE 0
|
||||
// 1 LOCALVARIABLE c C L1 L13 0
|
||||
@@ -0,0 +1,23 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
fun test(): Char {
|
||||
val c: Char
|
||||
val l = Any()
|
||||
val l1 = Any()
|
||||
val l2 = Any()
|
||||
val l3 = Any()
|
||||
val l4 = Any()
|
||||
val l5 = Any()
|
||||
val l6 = Any()
|
||||
val l7 = Any()
|
||||
val l8 = Any()
|
||||
val l11 = Any()
|
||||
val l12 = Any()
|
||||
val l13 = Any()
|
||||
val l14 = Any()
|
||||
c = '1'
|
||||
return c
|
||||
}
|
||||
|
||||
// 2 ISTORE 0
|
||||
// 1 LOCALVARIABLE c C L1 L16 0
|
||||
@@ -0,0 +1,12 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
fun test(): Char {
|
||||
var c: Char
|
||||
run {
|
||||
c = ' '
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// 1 ASTORE 0
|
||||
// 1 LOCALVARIABLE c Lkotlin/jvm/internal/Ref\$CharRef; L1 L10 0
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
fun test(i: Int): Char {
|
||||
val c: Char
|
||||
when (i) {
|
||||
1 -> c = '1'
|
||||
2 -> c = '2'
|
||||
3 -> c = '3'
|
||||
4 -> c = '4'
|
||||
5 -> c = '5'
|
||||
6 -> c = '6'
|
||||
7 -> c = '7'
|
||||
8 -> c = '8'
|
||||
9 -> c = '9'
|
||||
0 -> c = '0'
|
||||
else -> c = ' '
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// 12 ISTORE 1
|
||||
// 1 LOCALVARIABLE c C L1 L16 1
|
||||
@@ -2585,6 +2585,74 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/localInitializationLVT")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class LocalInitializationLVT extends AbstractBytecodeTextTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInLocalInitializationLVT() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/localInitializationLVT"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("boxing.kt")
|
||||
public void testBoxing() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/boxing.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("contract.kt")
|
||||
public void testContract() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/contract.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("generics.kt")
|
||||
public void testGenerics() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/generics.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ifStatement.kt")
|
||||
public void testIfStatement() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/ifStatement.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ifStatementWithoutBlock.kt")
|
||||
public void testIfStatementWithoutBlock() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/ifStatementWithoutBlock.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClass.kt")
|
||||
public void testInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/inlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lateinit.kt")
|
||||
public void testLateinit() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/lateinit.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("run.kt")
|
||||
public void testRun() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/run.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("singleBlock.kt")
|
||||
public void testSingleBlock() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/singleBlock.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("var.kt")
|
||||
public void testVar() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/var.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenStatement.kt")
|
||||
public void testWhenStatement() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/whenStatement.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/multifileClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+68
@@ -2585,6 +2585,74 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/localInitializationLVT")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class LocalInitializationLVT extends AbstractIrBytecodeTextTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInLocalInitializationLVT() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/localInitializationLVT"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("boxing.kt")
|
||||
public void testBoxing() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/boxing.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("contract.kt")
|
||||
public void testContract() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/contract.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("generics.kt")
|
||||
public void testGenerics() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/generics.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ifStatement.kt")
|
||||
public void testIfStatement() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/ifStatement.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ifStatementWithoutBlock.kt")
|
||||
public void testIfStatementWithoutBlock() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/ifStatementWithoutBlock.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClass.kt")
|
||||
public void testInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/inlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lateinit.kt")
|
||||
public void testLateinit() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/lateinit.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("run.kt")
|
||||
public void testRun() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/run.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("singleBlock.kt")
|
||||
public void testSingleBlock() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/singleBlock.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("var.kt")
|
||||
public void testVar() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/var.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenStatement.kt")
|
||||
public void testWhenStatement() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/localInitializationLVT/whenStatement.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/multifileClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user