KT-16713 Insufficient maximum stack size
1. Analyze method node with fake jumps for loops to make sure that all instructions reachable only through break/continue jumps are processed. 2. Fix stack for break/continue jumps. 3. Drop fake jumps for loops, analyze method node again. 4. Fix stack for try/catch and beforeInline.
This commit is contained in:
committed by
Mikhael Bogdanov
parent
80063b6f91
commit
11caa03427
+1
-8
@@ -58,16 +58,9 @@ internal class FixStackAnalyzer(
|
|||||||
for (marker in context.fakeAlwaysFalseIfeqMarkers) {
|
for (marker in context.fakeAlwaysFalseIfeqMarkers) {
|
||||||
val next = marker.next
|
val next = marker.next
|
||||||
if (next is JumpInsnNode) {
|
if (next is JumpInsnNode) {
|
||||||
val nop = InsnNode(Opcodes.NOP)
|
expectedStackNode[next.label] = marker
|
||||||
expectedStackNode[next.label] = nop
|
|
||||||
method.instructions.insert(next, nop)
|
|
||||||
method.instructions.remove(marker)
|
|
||||||
method.instructions.remove(next)
|
|
||||||
context.nodesToRemoveOnCleanup.add(nop)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.fakeAlwaysFalseIfeqMarkers.clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val analyzer = InternalAnalyzer(owner, method, context)
|
private val analyzer = InternalAnalyzer(owner, method, context)
|
||||||
|
|||||||
-2
@@ -39,8 +39,6 @@ internal class FixStackContext(val methodNode: MethodNode) {
|
|||||||
val openingInlineMethodMarker = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
|
val openingInlineMethodMarker = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
|
||||||
var consistentInlineMarkers: Boolean = true; private set
|
var consistentInlineMarkers: Boolean = true; private set
|
||||||
|
|
||||||
val nodesToRemoveOnCleanup = arrayListOf<AbstractInsnNode>()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode)
|
saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode)
|
||||||
isThereAnyTryCatch = saveStackMarkerForRestoreMarker.isNotEmpty()
|
isThereAnyTryCatch = saveStackMarkerForRestoreMarker.isNotEmpty()
|
||||||
|
|||||||
+37
-17
@@ -39,31 +39,51 @@ class FixStackMethodTransformer : MethodTransformer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (context.isAnalysisRequired()) {
|
if (context.isAnalysisRequired()) {
|
||||||
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
|
analyzeAndTransformBreakContinueGotos(context, internalClassName, methodNode)
|
||||||
analyzer.analyze()
|
removeAlwaysFalseIfeqMarkers(context, methodNode)
|
||||||
|
analyzeAndTransformSaveRestoreStack(context, internalClassName, methodNode)
|
||||||
methodNode.maxStack = methodNode.maxStack + analyzer.maxExtraStackSize
|
|
||||||
|
|
||||||
val actions = arrayListOf<() -> Unit>()
|
|
||||||
|
|
||||||
transformBreakContinueGotos(methodNode, context, actions, analyzer)
|
|
||||||
|
|
||||||
transformSaveRestoreStackMarkers(methodNode, context, actions, analyzer)
|
|
||||||
|
|
||||||
actions.forEach { it() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.fakeAlwaysTrueIfeqMarkers.forEach { marker ->
|
removeAlwaysTrueIfeqMarkers(context, methodNode)
|
||||||
replaceAlwaysTrueIfeqWithGoto(methodNode, marker)
|
removeAlwaysFalseIfeqMarkers(context, methodNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun analyzeAndTransformBreakContinueGotos(context: FixStackContext, internalClassName: String, methodNode: MethodNode) {
|
||||||
|
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
|
||||||
|
analyzer.analyze()
|
||||||
|
|
||||||
|
methodNode.maxStack = methodNode.maxStack + analyzer.maxExtraStackSize
|
||||||
|
|
||||||
|
val actions = arrayListOf<() -> Unit>()
|
||||||
|
|
||||||
|
transformBreakContinueGotos(methodNode, context, actions, analyzer)
|
||||||
|
|
||||||
|
actions.forEach { it() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun analyzeAndTransformSaveRestoreStack(context: FixStackContext, internalClassName: String, methodNode: MethodNode) {
|
||||||
|
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
|
||||||
|
analyzer.analyze()
|
||||||
|
|
||||||
|
val actions = arrayListOf<() -> Unit>()
|
||||||
|
|
||||||
|
transformSaveRestoreStackMarkers(methodNode, context, actions, analyzer)
|
||||||
|
|
||||||
|
actions.forEach { it() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeAlwaysFalseIfeqMarkers(context: FixStackContext, methodNode: MethodNode) {
|
||||||
context.fakeAlwaysFalseIfeqMarkers.forEach { marker ->
|
context.fakeAlwaysFalseIfeqMarkers.forEach { marker ->
|
||||||
removeAlwaysFalseIfeq(methodNode, marker)
|
removeAlwaysFalseIfeq(methodNode, marker)
|
||||||
}
|
}
|
||||||
|
context.fakeAlwaysFalseIfeqMarkers.clear()
|
||||||
|
}
|
||||||
|
|
||||||
context.nodesToRemoveOnCleanup.forEach {
|
private fun removeAlwaysTrueIfeqMarkers(context: FixStackContext, methodNode: MethodNode) {
|
||||||
methodNode.instructions.remove(it)
|
context.fakeAlwaysTrueIfeqMarkers.forEach { marker ->
|
||||||
|
replaceAlwaysTrueIfeqWithGoto(methodNode, marker)
|
||||||
}
|
}
|
||||||
|
context.fakeAlwaysTrueIfeqMarkers.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformBreakContinueGotos(
|
private fun transformBreakContinueGotos(
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
class MyQueue {
|
||||||
|
fun poll(): String? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
val delayedQueue = MyQueue()
|
||||||
|
|
||||||
|
fun next() {
|
||||||
|
while (true) {
|
||||||
|
delayedQueue.poll() ?: break
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
unblock(delayedQueue.poll() ?: break)
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
unblock(delayedQueue.poll() ?: break)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unblock(p: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
A().next()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
class MyQueue {
|
||||||
|
fun poll(): String? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
val delayedQueue = MyQueue()
|
||||||
|
|
||||||
|
var cond = true
|
||||||
|
|
||||||
|
fun next() {
|
||||||
|
while (cond) {
|
||||||
|
delayedQueue.poll() ?: break
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cond) {
|
||||||
|
unblock(delayedQueue.poll() ?: break)
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cond) {
|
||||||
|
unblock(delayedQueue.poll() ?: break)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unblock(p: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
A().next()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Vendored
+19
@@ -0,0 +1,19 @@
|
|||||||
|
@kotlin.Metadata
|
||||||
|
public final class A {
|
||||||
|
private final @org.jetbrains.annotations.NotNull field delayedQueue: MyQueue
|
||||||
|
public method <init>(): void
|
||||||
|
public final @org.jetbrains.annotations.NotNull method getDelayedQueue(): MyQueue
|
||||||
|
public final method next(): void
|
||||||
|
public final method unblock(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class Kt16713Kt {
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class MyQueue {
|
||||||
|
public method <init>(): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method poll(): java.lang.String
|
||||||
|
}
|
||||||
Vendored
+22
@@ -0,0 +1,22 @@
|
|||||||
|
@kotlin.Metadata
|
||||||
|
public final class A {
|
||||||
|
private field cond: boolean
|
||||||
|
private final @org.jetbrains.annotations.NotNull field delayedQueue: MyQueue
|
||||||
|
public method <init>(): void
|
||||||
|
public final method getCond(): boolean
|
||||||
|
public final @org.jetbrains.annotations.NotNull method getDelayedQueue(): MyQueue
|
||||||
|
public final method next(): void
|
||||||
|
public final method setCond(p0: boolean): void
|
||||||
|
public final method unblock(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class Kt16713_2Kt {
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class MyQueue {
|
||||||
|
public method <init>(): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method poll(): java.lang.String
|
||||||
|
}
|
||||||
+12
@@ -4456,6 +4456,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt16713.kt")
|
||||||
|
public void testKt16713() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt16713_2.kt")
|
||||||
|
public void testKt16713_2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713_2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt9022And.kt")
|
@TestMetadata("kt9022And.kt")
|
||||||
public void testKt9022And() throws Exception {
|
public void testKt9022And() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");
|
||||||
|
|||||||
@@ -4456,6 +4456,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt16713.kt")
|
||||||
|
public void testKt16713() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt16713_2.kt")
|
||||||
|
public void testKt16713_2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713_2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt9022And.kt")
|
@TestMetadata("kt9022And.kt")
|
||||||
public void testKt9022And() throws Exception {
|
public void testKt9022And() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");
|
||||||
|
|||||||
+12
@@ -5153,6 +5153,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt16713.kt")
|
||||||
|
public void testKt16713() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt16713_2.kt")
|
||||||
|
public void testKt16713_2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713_2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt9022And.kt")
|
@TestMetadata("kt9022And.kt")
|
||||||
public void testKt9022And() throws Exception {
|
public void testKt9022And() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user