Setup label value in constructor to be invalid until 'invoke(Controller)' call
This commit is contained in:
@@ -405,6 +405,8 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
|||||||
iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false);
|
iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateAdditionalCodeInConstructor(iv);
|
||||||
|
|
||||||
iv.visitInsn(RETURN);
|
iv.visitInsn(RETURN);
|
||||||
|
|
||||||
FunctionCodegen.endVisit(iv, "constructor", element);
|
FunctionCodegen.endVisit(iv, "constructor", element);
|
||||||
@@ -412,6 +414,10 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
|||||||
return constructor;
|
return constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void generateAdditionalCodeInConstructor(@NotNull InstructionAdapter iv) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static List<FieldInfo> calculateConstructorParameters(
|
public static List<FieldInfo> calculateConstructorParameters(
|
||||||
@NotNull KotlinTypeMapper typeMapper,
|
@NotNull KotlinTypeMapper typeMapper,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
|||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
|
|
||||||
class CoroutineCodegen(
|
class CoroutineCodegen(
|
||||||
@@ -73,9 +74,7 @@ class CoroutineCodegen(
|
|||||||
1, codegen.v)
|
1, codegen.v)
|
||||||
|
|
||||||
with(codegen.v) {
|
with(codegen.v) {
|
||||||
load(0, AsmTypes.OBJECT_TYPE)
|
setLabelValue(LABEL_VALUE_BEFORE_FIRST_SUSPENSION)
|
||||||
iconst(0)
|
|
||||||
putfield(v.thisName, COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor)
|
|
||||||
load(0, AsmTypes.OBJECT_TYPE)
|
load(0, AsmTypes.OBJECT_TYPE)
|
||||||
areturn(AsmTypes.OBJECT_TYPE)
|
areturn(AsmTypes.OBJECT_TYPE)
|
||||||
}
|
}
|
||||||
@@ -123,7 +122,6 @@ class CoroutineCodegen(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun createSynthesizedImplementationByName(
|
private fun createSynthesizedImplementationByName(
|
||||||
name: String,
|
name: String,
|
||||||
interfaceSupertype: KotlinType,
|
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 {
|
companion object {
|
||||||
|
private const val LABEL_VALUE_BEFORE_INVOKE = -2
|
||||||
|
private const val LABEL_VALUE_BEFORE_FIRST_SUSPENSION = 0
|
||||||
|
|
||||||
@JvmStatic fun create(
|
@JvmStatic fun create(
|
||||||
expressionCodegen: ExpressionCodegen,
|
expressionCodegen: ExpressionCodegen,
|
||||||
originalCoroutineLambdaDescriptor: FunctionDescriptor,
|
originalCoroutineLambdaDescriptor: FunctionDescriptor,
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Controller {
|
||||||
|
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||||
|
x.resume(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder1(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||||
|
(c as Continuation<Unit>).resume(Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder2(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||||
|
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"
|
||||||
|
}
|
||||||
@@ -4123,6 +4123,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("innerSuspensionCalls.kt")
|
||||||
public void testInnerSuspensionCalls() throws Exception {
|
public void testInnerSuspensionCalls() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/innerSuspensionCalls.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/innerSuspensionCalls.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user