diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index a6459c81aba..225df0cf39b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -405,6 +405,8 @@ public class ClosureCodegen extends MemberCodegen { iv.invokespecial(superClassAsmType.getInternalName(), "", "()V", false); } + generateAdditionalCodeInConstructor(iv); + iv.visitInsn(RETURN); FunctionCodegen.endVisit(iv, "constructor", element); @@ -412,6 +414,10 @@ public class ClosureCodegen extends MemberCodegen { return constructor; } + protected void generateAdditionalCodeInConstructor(@NotNull InstructionAdapter iv) { + + } + @NotNull public static List calculateConstructorParameters( @NotNull KotlinTypeMapper typeMapper, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index b0dc548883d..b6a49104ddd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter class CoroutineCodegen( @@ -73,9 +74,7 @@ class CoroutineCodegen( 1, codegen.v) with(codegen.v) { - load(0, AsmTypes.OBJECT_TYPE) - iconst(0) - putfield(v.thisName, COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor) + setLabelValue(LABEL_VALUE_BEFORE_FIRST_SUSPENSION) load(0, AsmTypes.OBJECT_TYPE) areturn(AsmTypes.OBJECT_TYPE) } @@ -123,7 +122,6 @@ class CoroutineCodegen( }) } - private fun createSynthesizedImplementationByName( name: String, interfaceSupertype: KotlinType, @@ -164,8 +162,23 @@ class CoroutineCodegen( }) } + private fun InstructionAdapter.setLabelValue(value: Int) { + load(0, AsmTypes.OBJECT_TYPE) + iconst(value) + putfield(v.thisName, COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor) + } + + override fun generateAdditionalCodeInConstructor(iv: InstructionAdapter) { + super.generateAdditionalCodeInConstructor(iv) + // Change label value to illegal to make sure continuation will not be used until `invoke(Controler)` + // where correct value will be set up + iv.setLabelValue(LABEL_VALUE_BEFORE_INVOKE) + } companion object { + private const val LABEL_VALUE_BEFORE_INVOKE = -2 + private const val LABEL_VALUE_BEFORE_FIRST_SUSPENSION = 0 + @JvmStatic fun create( expressionCodegen: ExpressionCodegen, originalCoroutineLambdaDescriptor: FunctionDescriptor, diff --git a/compiler/testData/codegen/box/coroutines/illegalState.kt b/compiler/testData/codegen/box/coroutines/illegalState.kt new file mode 100644 index 00000000000..dcbf302fc88 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/illegalState.kt @@ -0,0 +1,42 @@ +// WITH_RUNTIME +class Controller { + suspend fun suspendHere(x: Continuation) { + x.resume(Unit) + } +} + +fun builder1(coroutine c: Controller.() -> Continuation) { + (c as Continuation).resume(Unit) +} + +fun builder2(coroutine c: Controller.() -> Continuation) { + val continuation = c(Controller()) + val declaredField = continuation!!.javaClass.getDeclaredField("label") + declaredField.setAccessible(true) + declaredField.set(continuation, -3) + continuation.resume(Unit) +} + +fun box(): String { + + try { + builder1 { + suspendHere() + } + return "fail 1" + } catch (e: java.lang.IllegalStateException) { + if (e.message != "call to 'resume' before 'invoke' with coroutine") return "fail 2: ${e.message!!}" + } + + try { + builder2 { + suspendHere() + } + return "fail 3" + } catch (e: java.lang.IllegalStateException) { + if (e.message != "call to 'resume' before 'invoke' with coroutine") return "fail 4: ${e.message!!}" + return "OK" + } + + return "fail" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 4e91e4fc678..33c632d7240 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4123,6 +4123,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("illegalState.kt") + public void testIllegalState() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/illegalState.kt"); + doTest(fileName); + } + @TestMetadata("innerSuspensionCalls.kt") public void testInnerSuspensionCalls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/innerSuspensionCalls.kt");