Minor. Simplify suspension point processing
Move type coercing logic from transformer to ExpressionCodegen. For suspension points it's always guaranteed that values returned from suspension points are always can be successfully casted to appropriate type, because they cannot return SUSPENDED marker (it gets processed via CoroutineTransformerMethodVisitor).
This commit is contained in:
@@ -2781,11 +2781,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
StackValue result = callable.invokeMethodWithArguments(resolvedCall, receiver, this);
|
||||
|
||||
if (CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, bindingContext)) {
|
||||
// Suspension points should behave like they leave actual values on stack, while real methods return VOID
|
||||
return new OperationStackValue(getSuspensionBoxedReturnTypeByResolvedCall(resolvedCall), ((OperationStackValue) result).getLambda());
|
||||
}
|
||||
|
||||
if (bindingContext.get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall()) != null) {
|
||||
// Suspend function's calls inside another suspend function should behave like they leave values of correct type,
|
||||
// while real methods return java/lang/Object.
|
||||
@@ -2907,11 +2902,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
if (isSuspensionPoint) {
|
||||
v.tconst(getSuspensionBoxedReturnTypeByResolvedCall(resolvedCall));
|
||||
v.invokestatic(
|
||||
CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER,
|
||||
CoroutineCodegenUtilKt.BEFORE_SUSPENSION_POINT_MARKER_NAME,
|
||||
"(Ljava/lang/Class;)V", false);
|
||||
"()V", false
|
||||
);
|
||||
}
|
||||
|
||||
callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this);
|
||||
@@ -2930,23 +2925,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Type getSuspensionBoxedReturnTypeByResolvedCall(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
assert resolvedCall.getResultingDescriptor() instanceof SimpleFunctionDescriptor
|
||||
: "Suspension point resolved call should be built on SimpleFunctionDescriptor";
|
||||
|
||||
FunctionDescriptor initialSignature =
|
||||
((SimpleFunctionDescriptor) resolvedCall.getResultingDescriptor())
|
||||
.getUserData(CoroutineCodegenUtilKt.INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION);
|
||||
|
||||
assert initialSignature != null : "Initial signature must be not null for suspension point";
|
||||
|
||||
KotlinType returnType = initialSignature.getReturnType();
|
||||
|
||||
assert returnType != null : "Return type of suspension point should not be null";
|
||||
return typeMapper.mapType(TypeUtils.makeNullable(returnType));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CallGenerator getOrCreateCallGenerator(
|
||||
@NotNull CallableDescriptor descriptor,
|
||||
|
||||
+7
-37
@@ -162,36 +162,12 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
|
||||
AFTER_SUSPENSION_POINT_MARKER_NAME -> {
|
||||
assert(beforeSuspensionPointMarkerStack.isNotEmpty()) { "Expected non-empty stack beforeSuspensionPointMarkerStack" }
|
||||
val beforeSuspensionPointMarker = beforeSuspensionPointMarkerStack.pop()
|
||||
assert(beforeSuspensionPointMarker.previous is LdcInsnNode) {
|
||||
"Instruction before BEFORE_SUSPENSION_POINT_MARKER_NAME should be LDC with expected return type, " +
|
||||
"but ${beforeSuspensionPointMarker.previous} was found"
|
||||
}
|
||||
|
||||
val fakeReturnValueInsns = mutableListOf<AbstractInsnNode>()
|
||||
|
||||
val suspensionPoint = SuspensionPoint(
|
||||
suspensionCallBegin = beforeSuspensionPointMarker,
|
||||
suspensionCallEnd = methodInsn,
|
||||
fakeReturnValueInsns = fakeReturnValueInsns,
|
||||
returnType = (beforeSuspensionPointMarker.previous as LdcInsnNode).cst as Type)
|
||||
suspensionPoints.add(suspensionPoint)
|
||||
|
||||
// Drop type info from marker
|
||||
methodNode.instructions.remove(beforeSuspensionPointMarker.previous)
|
||||
beforeSuspensionPointMarker.desc = "()V"
|
||||
|
||||
assert(suspensionPoint.returnType != Type.VOID_TYPE) { "Suspension point can't be VOID" }
|
||||
|
||||
// Checkcast only is needed to tell analyzer what type exactly should be returned from suspension point
|
||||
// This type is used when for restoring spilled variables into fields
|
||||
val checkCast = TypeInsnNode(Opcodes.CHECKCAST, suspensionPoint.returnType.internalName)
|
||||
methodNode.instructions.insertBefore(
|
||||
suspensionPoint.suspensionCallEnd, checkCast
|
||||
suspensionPoints.add(
|
||||
SuspensionPoint(
|
||||
suspensionCallBegin = beforeSuspensionPointMarkerStack.pop(),
|
||||
suspensionCallEnd = methodInsn
|
||||
)
|
||||
)
|
||||
|
||||
fakeReturnValueInsns.add(checkCast)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +200,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
for (suspension in suspensionPoints) {
|
||||
val suspensionCallBegin = suspension.suspensionCallBegin
|
||||
val suspensionCallEnd = suspension.suspensionCallEnd
|
||||
assert(frames[suspensionCallEnd.next.index()]?.stackSize == (if (suspension.returnType.sort == Type.VOID) 0 else 1)) {
|
||||
assert(frames[suspensionCallEnd.next.index()]?.stackSize == 1) {
|
||||
"Stack should be spilled before suspension call"
|
||||
}
|
||||
|
||||
@@ -338,9 +314,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
)
|
||||
)
|
||||
|
||||
// Drop default value that purpose was to simulate returned value by suspension method
|
||||
suspension.fakeReturnValueInsns.forEach { methodNode.instructions.remove(it) }
|
||||
|
||||
insert(suspension.tryCatchBlockEndLabelAfterSuspensionCall, withInstructionAdapter {
|
||||
dup()
|
||||
load(suspendMarkerVarIndex, AsmTypes.OBJECT_TYPE)
|
||||
@@ -371,7 +344,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
load(1, AsmTypes.OBJECT_TYPE)
|
||||
|
||||
visitLabel(continuationLabelAfterLoadedResult.label)
|
||||
StackValue.coerce(AsmTypes.OBJECT_TYPE, suspension.returnType, this)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -500,9 +472,7 @@ private class SuspensionPoint(
|
||||
// INVOKESTATIC beforeSuspensionMarker
|
||||
val suspensionCallBegin: AbstractInsnNode,
|
||||
// INVOKESTATIC afterSuspensionMarker
|
||||
val suspensionCallEnd: AbstractInsnNode,
|
||||
val fakeReturnValueInsns: List<AbstractInsnNode>,
|
||||
val returnType: Type
|
||||
val suspensionCallEnd: AbstractInsnNode
|
||||
) {
|
||||
lateinit var tryCatchBlocksContinuationLabel: LabelNode
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user