Adapt FixStackAnalyzer to code generated by coroutine transformation

Without this change internal error happens while inlining coroutine code with try/catch inside
Also get rid of hack with SKIP_MANDATORY_TRANSFORMATIONS_ANNOTATION_DESC
See comment within MethodAnalyzer for clarification
This commit is contained in:
Denis Zharkov
2016-06-03 16:11:28 +03:00
parent 678e8c2baa
commit 0d01edb7f9
5 changed files with 41 additions and 9 deletions
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.optimization.MandatoryMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.SKIP_MANDATORY_TRANSFORMATIONS_ANNOTATION_DESC
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.common.insnListOf
@@ -70,8 +69,6 @@ class CoroutineTransformerMethodVisitor(
processUninitializedStores(methodNode)
methodNode.visibleAnnotations.add(AnnotationNode(SKIP_MANDATORY_TRANSFORMATIONS_ANNOTATION_DESC))
val suspensionPoints = collectSuspensionPoints(methodNode)
if (suspensionPoints.isEmpty()) return
@@ -20,16 +20,11 @@ import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransfor
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.org.objectweb.asm.tree.MethodNode
val SKIP_MANDATORY_TRANSFORMATIONS_ANNOTATION_DESC = "Lkotlin/SkipMandatoryTransformations;"
class MandatoryMethodTransformer : MethodTransformer() {
private val labelNormalization = LabelNormalizationMethodTransformer()
private val fixStack = FixStackMethodTransformer()
override fun transform(internalClassName: String, methodNode: MethodNode) {
// Mandatory transformations have already been applied
if (methodNode.visibleAnnotations?.removeAll { it.desc == SKIP_MANDATORY_TRANSFORMATIONS_ANNOTATION_DESC } == true) return
labelNormalization.transform(internalClassName, methodNode)
fixStack.transform(internalClassName, methodNode)
}
@@ -136,7 +136,12 @@ open class MethodAnalyzer<V : Value>(
private fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: Frame<V>, insn: Int) {
var jump = instructions.indexOf(insnNode.dflt)
processControlFlowEdge(current, insn, jump)
for (label in insnNode.labels) {
// In most cases order of visiting switch labels should not matter
// The only one is a tableswitch being added in the beginning of coroutine method, these switch' labels may lead
// in the middle of try/catch block, and FixStackAnalyzer is not ready for this (trying to restore stack before it was saved)
// So we just fix the order of labels being traversed: the first one should be one at the method beginning
// Using 'reversed' is because nodes are processed in LIFO order
for (label in insnNode.labels.reversed()) {
jump = instructions.indexOf(label)
processControlFlowEdge(current, insn, jump)
}
@@ -0,0 +1,29 @@
class Controller {
suspend fun suspendHere(v: String, x: Continuation<String>) {
x.resume(v)
}
}
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
c(Controller()).resume(Unit)
}
inline fun run(block: () -> Unit) {
block()
}
fun box(): String {
var result = ""
run {
builder {
try {
result += suspendHere("O")
} finally {
result += suspendHere("K")
}
}
}
return result
}
@@ -4200,6 +4200,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstruction.kt");
doTest(fileName);
}
@TestMetadata("tryFinallyInsideInlineLambda.kt")
public void testTryFinallyInsideInlineLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tryFinallyInsideInlineLambda.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/dataClasses")