Document coroutines codegen: suspend markers
This commit is contained in:
committed by
Ilmir Usmanov
parent
1d7a661624
commit
f7cf5f435f
@@ -252,4 +252,26 @@ On a closing note, the state machine should be flat; in other words, there shoul
|
||||
Otherwise, inner state-machine states will rewrite `label`, breaking the whole suspend-resume machinery and leading to weird behavior,
|
||||
ranging from CCE to infinite loops. Similar buggy behavior happens when several suspending calls are in one state: when the first call
|
||||
suspends, and then the execution resumes, skipping all the remaining code in the state. Both these bugs were quite frequent in the early
|
||||
days of coroutines inlining.
|
||||
days of coroutines inlining.
|
||||
|
||||
#### JVM: Suspend Markers
|
||||
To distinguish suspending calls from ordinary ones, the codegen (more specifically, `ExpressionCodegen`) puts so-called suspend markers
|
||||
around the calls. We need to generate markers both before the call and after it since callee can be `suspendCoroutineUninterceptedOrReturn`
|
||||
intrinsic, and we consider its call as a suspension point, i.e., a place where a coroutine can suspend. Thus, a suspension point is either
|
||||
a non-inline suspend call or an inlined `suspendCoroutineUninterceptedOrReturn` call.
|
||||
|
||||
It is important to note that there is no point in putting the markers around inline function calls since the compiler inlines their bodies,
|
||||
and their suspend points will become inline-side's suspension points. Remember, a state-machines should be flat, without nested
|
||||
state-machines.
|
||||
|
||||
The markers are calls of `kotlin.jvm.internal.InlineMarker.mark` with an integer parameter. The values for before and after suspending call
|
||||
markers are `0` and `1` respectively. Inline suspending functions keep the markers in generated bytecode so, upon inlining suspending calls,
|
||||
which they surround become suspension points. Well, at least in one copy of the inline function, to be technically correct. Because the
|
||||
compiler generates two copies of it: one with a state-machine, so one can call it via reflection; and the other one without, so the inliner
|
||||
can inline it without inlining the state-machine into another. Since there are libraries with inline suspend functions, the values passed
|
||||
to `kotlin.jvm.internal.InlineMarker.mark`'s call cannot be changed.
|
||||
|
||||
The codegen generates the markers by calling `addSuspendMarker`. After generating `MethodNode` of the function, it passes the node to
|
||||
`CoroutineTransformerMethodVisitor`. `CoroutineTransformerMethodVisitor` collects the suspension
|
||||
points by checking these markers, and then it generates the state-machine.
|
||||
FIXME: I should rename `CoroutineTransformerMethodVisitor` to `StateMachineBuilder` already.
|
||||
Reference in New Issue
Block a user