Kotlin coroutines are managed at the JVM level using the concept of “continuations.” Continuations are a programming technique that allows suspending the execution of a function at a certain point and resuming it later from where it left off. Coroutines build upon this concept to provide a high-level and efficient way to write asynchronous code.
Continuation
When a code with suspend is converted to bytecode, a parameter is added to the end of the function to convert it into handing over an object called Continuation.
When such a suspend function is called from the coroutine, the execution information at that time is cached by making it a Continuation
object, and when the execution is resumed (Resume), the execution is resumed based on the stored execution information.
Continuation is just a geneeric callback that any suspending function actually uses behind the scenes. You can’t see it, every time you call the suspend function, it’s actually called back.
Labels
It also performs labeling for recognized callback points. The Kotlin compiler checks and labels the suspension points, as they require suspension points when resuming.
sm
on the above code means state machine
, the state (the result of the operations done so far) when each function is called.
This state machine
is eventually Continuation, and Corutin operates internally as Continuation passes in a form with some information value. This style is called as continuation-passing style (CPS).
Each suspend function takes Continuation (sm in the code above) as the last parameter, so :
- if
requestToken(sm)
is completed,resume()
is called insm(continuation)
. - The
createPost(token, item, sm)
is called again, and even when it is completed, the form of callingresume()
tosm(continuation)
is repeated.
So what is resume()
for? In the code above, resume()
is what eventually calls itself. (postItem(…)
Inside the postItem(…) is being recalled.)
- For example, when the operation of suspend function
requestToken(sm)
is finished,postItem(…)
again throughresume()
is called, which increases the Label value by one so that another case is called. In this case, internally, it is as if the suspend function is called and then the next case, and then the next case.
Decompile the code
Let’s make the above code into Kotlin’s byte code, then decompose it into Java code.
It can be seen that functions that were suspend functions were changed to general functions and Continuation was included as the last parameter.
reference