diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt index 9b321ad6cda..87190097b0b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt @@ -10,14 +10,11 @@ import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType -import org.jetbrains.kotlin.codegen.ExpressionCodegen -import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.inline.addFakeContinuationMarker import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper -import org.jetbrains.kotlin.codegen.topLevelClassAsmType -import org.jetbrains.kotlin.codegen.topLevelClassInternalName import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.coroutines.isSuspendLambda import org.jetbrains.kotlin.descriptors.* @@ -46,6 +43,7 @@ import org.jetbrains.kotlin.types.TypeConstructorSubstitution import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -395,18 +393,39 @@ fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn( typeMapper.mapAsmMethod(functionDescriptor).descriptor, null, null ) - node.visitVarInsn(Opcodes.ALOAD, 0) - node.visitVarInsn(Opcodes.ALOAD, 1) + with(InstructionAdapter(node)) { + load(0, AsmTypes.OBJECT_TYPE) // block + load(1, AsmTypes.OBJECT_TYPE) // continuation + + // block.invoke(continuation) + invokeinterface( + typeMapper.mapType(functionDescriptor.valueParameters[0]).internalName, + OperatorNameConventions.INVOKE.identifier, + "(${AsmTypes.OBJECT_TYPE})${AsmTypes.OBJECT_TYPE}" + ) + + if (languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)) { + val elseLabel = Label() + // if (result === COROUTINE_SUSPENDED) { + dup() + loadCoroutineSuspendedMarker(languageVersionSettings) + ifacmpne(elseLabel) + // DebugProbesKt.probeCoroutineSuspended(continuation) + load(1, AsmTypes.OBJECT_TYPE) // continuation + checkcast(languageVersionSettings.continuationAsmType()) + invokestatic( + languageVersionSettings.coroutinesJvmInternalPackageFqName().child(Name.identifier("DebugProbesKt")).topLevelClassAsmType().internalName, + "probeCoroutineSuspended", + "(${languageVersionSettings.continuationAsmType()})V", + false + ) + // } + mark(elseLabel) + } + } - node.visitMethodInsn( - Opcodes.INVOKEINTERFACE, - typeMapper.mapType(functionDescriptor.valueParameters[0]).internalName, - OperatorNameConventions.INVOKE.identifier, - "(${AsmTypes.OBJECT_TYPE})${AsmTypes.OBJECT_TYPE}", - true - ) node.visitInsn(Opcodes.ARETURN) - node.visitMaxs(2, 2) + node.visitMaxs(3, 2) return node } diff --git a/compiler/testData/codegen/bytecodeText/coroutines/debug/probeCoroutineSuspended.kt b/compiler/testData/codegen/bytecodeText/coroutines/debug/probeCoroutineSuspended.kt new file mode 100644 index 00000000000..dc10fc7c511 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/coroutines/debug/probeCoroutineSuspended.kt @@ -0,0 +1,17 @@ +// LANGUAGE_VERSION: 1.3 +// WITH_RUNTIME +// TREAT_AS_ONE_FILE + +import kotlin.coroutines.intrinsics.* +import kotlin.coroutines.* + +suspend fun suspended() = suspendCoroutineUninterceptedOrReturn { cont -> + cont.resume(0) + COROUTINE_SUSPENDED +} + +suspend fun simpleReturn() = suspendCoroutineUninterceptedOrReturn { cont -> + cont.resume(0) +} + +// 2 INVOKESTATIC kotlin/coroutines/jvm/internal/DebugProbesKt.probeCoroutineSuspended \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index cfdf81c4ad3..ffb50fb7280 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1102,6 +1102,24 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/coroutines/varValueConflictsWithTable_1_2.kt"); } + @TestMetadata("compiler/testData/codegen/bytecodeText/coroutines/debug") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Debug extends AbstractBytecodeTextTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInDebug() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/coroutines/debug"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("probeCoroutineSuspended.kt") + public void testProbeCoroutineSuspended() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/debug/probeCoroutineSuspended.kt"); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeText/coroutines/destructuringInLambda") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)