KT-14581 Make FixStackAnalyzer tolerant to uninitialized values

This commit is contained in:
Dmitry Petrov
2016-11-10 18:09:32 +03:00
parent 71ef8c4f89
commit b429f7bc86
9 changed files with 104 additions and 3 deletions
@@ -31,9 +31,15 @@ import java.util.List;
import static org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue.*;
public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implements Opcodes {
private final boolean tolerantToUninitializedValues;
public OptimizationBasicInterpreter(boolean tolerantToUninitializedValues) {
super(ASM5);
this.tolerantToUninitializedValues = tolerantToUninitializedValues;
}
public OptimizationBasicInterpreter() {
super(ASM5);
this(false);
}
@Override
@@ -355,7 +361,11 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
) {
if (v.equals(w)) return v;
if (v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE) {
if (tolerantToUninitializedValues) {
if (v == StrictBasicValue.UNINITIALIZED_VALUE) return w;
if (w == StrictBasicValue.UNINITIALIZED_VALUE) return v;
}
else if (v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE) {
return StrictBasicValue.UNINITIALIZED_VALUE;
}
@@ -33,7 +33,7 @@ internal class FixStackAnalyzer(
owner: String,
methodNode: MethodNode,
val context: FixStackContext
) : MethodAnalyzer<BasicValue>(owner, methodNode, OptimizationBasicInterpreter()) {
) : MethodAnalyzer<BasicValue>(owner, methodNode, OptimizationBasicInterpreter(/* tolerantToUninitializedValues = */true)) {
val savedStacks = hashMapOf<AbstractInsnNode, List<BasicValue>>()
var maxExtraStackSize = 0; private set
@@ -44,6 +44,10 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
}
private fun allocateNewHandle(numRestoreStackMarkers: Int, saveStackMarker: AbstractInsnNode, savedStackValues: List<BasicValue>): SavedStackDescriptor {
if (savedStackValues.any { it.type == null }) {
throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}")
}
val firstUnusedLocalVarIndex = getFirstUnusedLocalVariableIndex()
val savedStackDescriptor = SavedStackDescriptor(savedStackValues, firstUnusedLocalVarIndex)
updateMaxLocals(savedStackDescriptor.firstUnusedLocalVarIndex)
@@ -0,0 +1,10 @@
fun box(): String {
val ok: String? = "OK"
var res = ""
do {
res += ok ?: break
} while (false)
return res
}
@@ -0,0 +1,6 @@
fun box(): String {
var i = 0
do continue while (i++ < 3)
return "OK"
}
@@ -0,0 +1,11 @@
fun foo(x: String): String {
var y: String
do {
y = x
} while (y != x.bar(x))
return y
}
inline fun String.bar(other: String) = this
fun box(): String = foo("OK")
@@ -4156,12 +4156,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("breakInDoWhile.kt")
public void testBreakInDoWhile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInDoWhile.kt");
doTest(fileName);
}
@TestMetadata("breakInExpr.kt")
public void testBreakInExpr() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInExpr.kt");
doTest(fileName);
}
@TestMetadata("continueInDoWhile.kt")
public void testContinueInDoWhile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInDoWhile.kt");
doTest(fileName);
}
@TestMetadata("continueInExpr.kt")
public void testContinueInExpr() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInExpr.kt");
@@ -4180,6 +4192,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("kt14581.kt")
public void testKt14581() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt14581.kt");
doTest(fileName);
}
@TestMetadata("kt9022And.kt")
public void testKt9022And() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");
@@ -4156,12 +4156,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("breakInDoWhile.kt")
public void testBreakInDoWhile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInDoWhile.kt");
doTest(fileName);
}
@TestMetadata("breakInExpr.kt")
public void testBreakInExpr() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInExpr.kt");
doTest(fileName);
}
@TestMetadata("continueInDoWhile.kt")
public void testContinueInDoWhile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInDoWhile.kt");
doTest(fileName);
}
@TestMetadata("continueInExpr.kt")
public void testContinueInExpr() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInExpr.kt");
@@ -4180,6 +4192,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("kt14581.kt")
public void testKt14581() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt14581.kt");
doTest(fileName);
}
@TestMetadata("kt9022And.kt")
public void testKt9022And() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");
@@ -5140,12 +5140,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
}
}
@TestMetadata("breakInDoWhile.kt")
public void testBreakInDoWhile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInDoWhile.kt");
doTest(fileName);
}
@TestMetadata("breakInExpr.kt")
public void testBreakInExpr() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInExpr.kt");
doTest(fileName);
}
@TestMetadata("continueInDoWhile.kt")
public void testContinueInDoWhile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInDoWhile.kt");
doTest(fileName);
}
@TestMetadata("continueInExpr.kt")
public void testContinueInExpr() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInExpr.kt");
@@ -5164,6 +5176,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("kt14581.kt")
public void testKt14581() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt14581.kt");
doTest(fileName);
}
@TestMetadata("kt9022And.kt")
public void testKt9022And() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");
@@ -7088,6 +7106,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("kt13557.kt")
public void testKt13557() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/kt13557.kt");
doTest(fileName);
}
@TestMetadata("localVal.kt")
public void testLocalVal() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/localVal.kt");