Kotlin coroutines are one of the key features in the language. I was curious how they implemented it. So I wrote this kotlin code snippet,
CoroutineScope(Dispatchers.IO).launch { someFun(6) // A suspend fun with single int argument.} // Which is converted into a synthetic method with an extra argument of continuation type added at the end.
And then compiled it to bytecode and then decompiled it to Java(in Android Studio). I got this,
BuildersKt.launch$default(CoroutineScopeKt.CoroutineScope((CoroutineContext)Dispatchers.getIO()), (CoroutineContext)null, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) { private CoroutineScope p$; Object L$0; int label; @Nullable public final Object invokeSuspend(@NotNull Object $result) { Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED(); CoroutineScope $this$launch; switch(this.label) { case 0: ResultKt.throwOnFailure($result); $this$launch = this.p$; MainActivity var10000 = MainActivity.this; this.L$0 = $this$launch; this.label = 1; if (var10000.someFun(6, this) == var3) { return var3; } break; case 1: $this$launch = (CoroutineScope)this.L$0; ResultKt.throwOnFailure($result); break; default: throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine"); } return Unit.INSTANCE; } @NotNull public final Continuation create(@Nullable Object value, @NotNull Continuation completion) { Intrinsics.checkNotNullParameter(completion, "completion"); Function2 var3 = new <anonymous constructor>(completion); var3.p$ = (CoroutineScope)value; return var3; } public final Object invoke(Object var1, Object var2) { return ((<undefinedtype>)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE); }}), 3, (Object)null);
Some part of this code I understood. But still some parts are not going into my head.
According to this answer, a suspend function is split into multiple continuations at each suspension point and then starts executing from the begining by calling invokeSuspend
continuosly. Each time when invokeSuspend
is called, it executes the corresponding switch case and then updates the lable
. So next time when invokeSuspend
is called, it runs the next case. When <it?> gets call to suspend the function, it stops calling invokeSuspend
and waits for resume call. Once it gets call to resume, again it continues normally. This is all what I know.
At the first line, Function2 constructor is accepting a null object for Continuation. But why Function2
class has a single argument constructor? I don't know the implementation of Function2. I searched for its source code, but didn't get it. If possible, I want a link to source code of kotlin.jvm.functions.Function2
.
At the end of case0:, what does if (var10000.someFun(6, this) == var3) return var3;
actually means.
Who is responsible for calling invokeSuspend after previous call to invokeSuspend is finished. And how it knows when the last case of invokeSuspend is executed?
What does 3, (Object)null
represent in the last argument for launch$default