Generate LVT entry for continuation
#KT-25688: Fixed
This commit is contained in:
+29
-3
@@ -73,6 +73,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
// First instruction in the method node may change in case of named function
|
// First instruction in the method node may change in case of named function
|
||||||
val actualCoroutineStart = methodNode.instructions.first
|
val actualCoroutineStart = methodNode.instructions.first
|
||||||
|
|
||||||
|
var startLabelNode: LabelNode? = null
|
||||||
if (isForNamedFunction) {
|
if (isForNamedFunction) {
|
||||||
ReturnUnitMethodTransformer.transform(containingClassInternalName, methodNode)
|
ReturnUnitMethodTransformer.transform(containingClassInternalName, methodNode)
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
}
|
}
|
||||||
continuationIndex = methodNode.maxLocals++
|
continuationIndex = methodNode.maxLocals++
|
||||||
|
|
||||||
prepareMethodNodePreludeForNamedFunction(methodNode)
|
startLabelNode = prepareMethodNodePreludeForNamedFunction(methodNode)
|
||||||
} else {
|
} else {
|
||||||
ReturnUnitMethodTransformer.cleanUpReturnsUnitMarkers(methodNode, ReturnUnitMethodTransformer.findReturnsUnitMarks(methodNode))
|
ReturnUnitMethodTransformer.cleanUpReturnsUnitMarkers(methodNode, ReturnUnitMethodTransformer.findReturnsUnitMarks(methodNode))
|
||||||
}
|
}
|
||||||
@@ -113,9 +114,9 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
transformCallAndReturnContinuationLabel(it.index + 1, it.value, methodNode, suspendMarkerVarIndex)
|
transformCallAndReturnContinuationLabel(it.index + 1, it.value, methodNode, suspendMarkerVarIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val defaultLabel = LabelNode()
|
||||||
methodNode.instructions.apply {
|
methodNode.instructions.apply {
|
||||||
val startLabel = LabelNode()
|
val startLabel = LabelNode()
|
||||||
val defaultLabel = LabelNode()
|
|
||||||
val tableSwitchLabel = LabelNode()
|
val tableSwitchLabel = LabelNode()
|
||||||
|
|
||||||
// tableswitch(this.label)
|
// tableswitch(this.label)
|
||||||
@@ -152,6 +153,27 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
|
|
||||||
dropSuspensionMarkers(methodNode, suspensionPoints)
|
dropSuspensionMarkers(methodNode, suspensionPoints)
|
||||||
methodNode.removeEmptyCatchBlocks()
|
methodNode.removeEmptyCatchBlocks()
|
||||||
|
|
||||||
|
if (isForNamedFunction) {
|
||||||
|
addContinuationToLvt(
|
||||||
|
methodNode,
|
||||||
|
startLabelNode.sure { "start label has not been initialized during prelude generation" },
|
||||||
|
defaultLabel
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addContinuationToLvt(methodNode: MethodNode, startLabel: LabelNode, endLabel: LabelNode) {
|
||||||
|
methodNode.localVariables.add(
|
||||||
|
LocalVariableNode(
|
||||||
|
"\$continuation",
|
||||||
|
languageVersionSettings.continuationAsmType().descriptor,
|
||||||
|
null,
|
||||||
|
startLabel,
|
||||||
|
endLabel,
|
||||||
|
continuationIndex
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeFakeContinuationConstructorCall(methodNode: MethodNode) {
|
private fun removeFakeContinuationConstructorCall(methodNode: MethodNode) {
|
||||||
@@ -209,7 +231,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prepareMethodNodePreludeForNamedFunction(methodNode: MethodNode) {
|
private fun prepareMethodNodePreludeForNamedFunction(methodNode: MethodNode): LabelNode {
|
||||||
val objectTypeForState = Type.getObjectType(classBuilderForCoroutineState.thisName)
|
val objectTypeForState = Type.getObjectType(classBuilderForCoroutineState.thisName)
|
||||||
val continuationArgumentIndex = getLastParameterIndex(methodNode.desc, methodNode.access)
|
val continuationArgumentIndex = getLastParameterIndex(methodNode.desc, methodNode.access)
|
||||||
methodNode.instructions.asSequence().filterIsInstance<VarInsnNode>().forEach {
|
methodNode.instructions.asSequence().filterIsInstance<VarInsnNode>().forEach {
|
||||||
@@ -218,6 +240,8 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
it.`var` = continuationIndex
|
it.`var` = continuationIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val startLabel = LabelNode()
|
||||||
|
|
||||||
methodNode.instructions.insert(withInstructionAdapter {
|
methodNode.instructions.insert(withInstructionAdapter {
|
||||||
val createStateInstance = Label()
|
val createStateInstance = Label()
|
||||||
val afterCoroutineStateCreated = Label()
|
val afterCoroutineStateCreated = Label()
|
||||||
@@ -237,6 +261,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
// `doResume` just before calling the suspend function (see kotlin.coroutines.experimental.jvm.internal.CoroutineImplForNamedFunction).
|
// `doResume` just before calling the suspend function (see kotlin.coroutines.experimental.jvm.internal.CoroutineImplForNamedFunction).
|
||||||
// So, if it's set we're in continuation.
|
// So, if it's set we're in continuation.
|
||||||
|
|
||||||
|
visitLabel(startLabel.label)
|
||||||
visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex)
|
visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex)
|
||||||
instanceOf(objectTypeForState)
|
instanceOf(objectTypeForState)
|
||||||
ifeq(createStateInstance)
|
ifeq(createStateInstance)
|
||||||
@@ -288,6 +313,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
visitVarInsn(Opcodes.ASTORE, exceptionIndex)
|
visitVarInsn(Opcodes.ASTORE, exceptionIndex)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
return startLabel
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeUnreachableSuspensionPointsAndExitPoints(methodNode: MethodNode, suspensionPoints: MutableList<SuspensionPoint>) {
|
private fun removeUnreachableSuspensionPointsAndExitPoints(methodNode: MethodNode, suspensionPoints: MutableList<SuspensionPoint>) {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// LANGUAGE_VERSION: 1.3
|
||||||
|
|
||||||
|
suspend fun dummy() {}
|
||||||
|
|
||||||
|
suspend fun tailCall() {
|
||||||
|
dummy()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun stateMachine() {
|
||||||
|
dummy()
|
||||||
|
dummy()
|
||||||
|
}
|
||||||
|
|
||||||
|
// for tail-calls there is no need to add continuation to LVT
|
||||||
|
// 1 LOCALVARIABLE \$continuation Lkotlin/coroutines/Continuation; L.* 2
|
||||||
@@ -1114,6 +1114,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/coroutines/debug"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/coroutines/debug"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("continuationInLvt.kt")
|
||||||
|
public void testContinuationInLvt() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/coroutines/debug/continuationInLvt.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("probeCoroutineSuspended.kt")
|
@TestMetadata("probeCoroutineSuspended.kt")
|
||||||
public void testProbeCoroutineSuspended() throws Exception {
|
public void testProbeCoroutineSuspended() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeText/coroutines/debug/probeCoroutineSuspended.kt");
|
runTest("compiler/testData/codegen/bytecodeText/coroutines/debug/probeCoroutineSuspended.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user