Kotlin suspend lambda 会编译成什么样的代码?

对于这样的 suspend lambda :

val block = suspend (p1 : P1, ..., pn : Pn) -> R = {
    ...
    suspendFun(...)
    ...
    resultR
}

其编译期生成的代码类似这样(这里只考虑 lambda 块里只调用了一次 suspend 方法的情况;如果调用了 n 次 suspend 方法,switch 块会被 n - 1 层 label 标签块嵌套包围):

public class SuspendLambdaBlock<P1, ..., Pn, R> extends kotlin.coroutines.jvm.internal.SuspendLambda
        implements FunctionN<P1, ..., Pn, Continuation<? super R>, Object> {
    // 状态机状态标记
    int label;

    // 用于保存局部临时变量
    Object L$0;
    ...
    Object L$x;

    public SuspendLambdaBlock(@Nullable Continuation<Object> completion) {
        super(N, completion);
    }

    @Nullable
    @Override
    protected Object invokeSuspend(@NotNull Object lastResult) {
        Object state = IntrinsicsKt.getCOROUTINE_SUSPENDED();
        Object newResult;
        switch (label) {
            case 0:
                ... // 执行 suspendFun() 方法之前的代码
                label = 1; // 设置下一次恢复执行的状态
                newResult = suspendFun(..., this);
                if (newResult == state /*COROUTINE_SUSPENDED*/) {
                    return state; // suspendFun() 返回 COROUTINE_SUSPENDED,说明需要挂起 SuspendLambdaBlock 的执行
                }
                break; // suspendFun() 立即返回结果值,说明不需要挂起 SuspendLambdaBlock 的执行,break 后继续执行 suspendFun() 方法之后的代码,返回最终结果。
            case 1:
                ... // 恢复保存的临时变量 L$0, ..., L$x
                newResult = lastResult
                break;
            default:
                throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
        }

        ... // 执行 suspendFun() 方法之后的代码
        Object finalResult = ... // 计算最终结果值
        return finalResult;
    }

    @NotNull
    @Override
    public final SuspendLambdaBlock<P1, ..., Pn, R> create(
            @Nullable Object p1, ..., @Nullable Object pn, @NotNull Continuation completion) {
        Intrinsics.checkNotNullParameter(completion, "completion");
        return SuspendLambdaBlock(completion);
    }

    @Override
    public final Object invoke(P1 p1, ..., Pn pn, Continuation<? super R> continuation) {
        return create(p1, ..., pn, continuation).invokeSuspend(Unit.INSTANCE);
    }
}

FunctionN<P1, ..., Pn, R> block = new SuspendLambdaBlock(null);

例如以下代码:

suspend fun suspendFun(): R = {
    ...
}

val test : suspend CoroutineScope.() -> R = {
    suspendFun()
}
注:
suspend CoroutineScope.() -> R
与
suspend (CoroutineScope) -> R
是同一类型

编译期间生成的代码类似这样:

fun <R> suspendFun(completion: Continuation<R>): Any? {
    ...
}

class SuspendLambdaBlock<R>(completion: Continuation<*>?) :
        SuspendLambda(2, completion),
        Function2<CoroutineScope, Continuation<in R>, Any?> {
    var label = 0

    override fun invokeSuspend(result: Result<Any?>): Any? {
        val state = COROUTINE_SUSPENDED
        val newResult: Any?
        when (label) {
            0 -> {
                result.getOrThrow()
                label = 1
                newResult = suspendFun(this)
                if (newResult === state) {
                    return state
                }
            }
            1 -> {
                newResult = result.getOrThrow()
            }
            else -> throw IllegalStateException("call to 'resume' before 'invoke' with coroutine")
        }

        return newResult
    }

    override fun create(value: Any?, completion: Continuation<R>): SuspendLambdaBlock<R> {
        return SuspendLambdaBlockKt(completion)
    }

    override operator fun invoke(coroutineScope: CoroutineScope, continuation: Continuation<in R>): Any? {
        return create(coroutineScope, continuation).invokeSuspend(Result.success(Unit))
    }
}

Function2<CoroutineScope, Continuation<in R> test = SuspendLambdaBlock<R>(null);

SuspendLambdaBlock 第一次创建时,completion 为 null,此 SuspendLambdaBlock 代表一个 Function,可执行 invoke(…, continuation : Continuation) 方法,
此方法会将 continuation 传入并 create 一个新的 SuspendLambdaBlock 实例,此 SuspendLambdaBlock 代表一个 ContinuationImpl,
然后执行 invokeSuspend() 状态机代码。

// Suspension lambdas inherit from this class
internal abstract class SuspendLambda(
    public override val arity: Int,
    completion: Continuation<Any?>?
) : ContinuationImpl(completion), FunctionBase<Any?>, SuspendFunction {
    constructor(arity: Int) : this(arity, null)

    public override fun toString(): String =
        if (completion == null)
            Reflection.renderLambdaToString(this) // this is lambda
        else
            super.toString() // this is continuation
}

SuspendLambda 的 toString() 方法的注释:当 completion 为空时,它代表一个 lambda;当 completion 不为空时,它代表一个 continuation。

比如 IntrinsicsJvm.kt 的 (suspend R.() -> T).startCoroutineUninterceptedOrReturn 方法:

public actual inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedOrReturn(
    receiver: R,
    completion: Continuation<T>
): Any? = (this as Function2<R, Continuation<T>, Any?>).invoke(receiver, completion)

this (类型为 suspend R.() -> T) 代表一个 Function2<R, Continuation<T>, Any?>,可以执行 invoke(r : R, continuation : Continuation<T>) 方法。
invoke() 方法创建一个新的 SuspendLambda(=suspend R.() -> T) 实例(它代表一个 ContinuationImpl),然后执行它的 invokeSuspend() 方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值