diff --git a/js/js.libraries/src/core/coroutines.kt b/js/js.libraries/src/core/coroutines.kt index b9da7e94768..9f6699f91c6 100644 --- a/js/js.libraries/src/core/coroutines.kt +++ b/js/js.libraries/src/core/coroutines.kt @@ -29,7 +29,7 @@ public fun (suspend R.() -> T).createCoroutine( receiver: R, completion: Continuation, dispatcher: ContinuationDispatcher? = null -): Continuation = this.asDynamic().call(receiver, withDispatcher(completion, dispatcher)) +): Continuation = this.asDynamic().call(receiver, withDispatcher(completion, dispatcher)).facade /** * Starts coroutine with receiver type [R] and result type [T]. @@ -57,7 +57,7 @@ public fun (suspend R.() -> T).startCoroutine( public fun (suspend () -> T).createCoroutine( completion: Continuation, dispatcher: ContinuationDispatcher? = null -): Continuation = this.asDynamic()(withDispatcher(completion, dispatcher)) +): Continuation = this.asDynamic()(withDispatcher(completion, dispatcher)).facade /** * Starts coroutine without receiver and with result type [T]. @@ -75,13 +75,19 @@ public fun (suspend () -> T).startCoroutine( // ------- internal stuff ------- -private fun withDispatcher(completion: Continuation, dispatcher: ContinuationDispatcher?): Continuation { - val finalContinuationDispatcher = dispatcher ?: object : ContinuationDispatcher { - override fun dispatchResume(value: T, continuation: Continuation) = false +internal interface DispatchedContinuation { + val dispatcher: ContinuationDispatcher? +} - override fun dispatchResumeWithException(exception: Throwable, continuation: Continuation<*>) = false +private fun withDispatcher(completion: Continuation, dispatcher: ContinuationDispatcher?): Continuation { + return if (dispatcher == null) { + completion + } + else { + object : Continuation by completion, DispatchedContinuation { + override val dispatcher = dispatcher + } } - return object : Continuation by completion, ContinuationDispatcher by finalContinuationDispatcher {} } @JsName("CoroutineImpl") @@ -91,18 +97,19 @@ internal abstract class CoroutineImpl(private val resultContinuation: Continuati protected var result: Any? = null protected var exception: Throwable? = null protected var finallyPath: Array? = null - private val continuationDispatcher = resultContinuation as? ContinuationDispatcher + private val continuationDispatcher = (resultContinuation as? DispatchedContinuation)?.dispatcher + val facade: Continuation + + init { + facade = if (continuationDispatcher != null) { + ContinuationFacade(this, continuationDispatcher) + } + else { + this + } + } override fun resume(data: Any?) { - if (continuationDispatcher != null && (state and INTERCEPTING) == 0) { - state = state or INTERCEPTING - if (continuationDispatcher.dispatchResume(data, this)) { - state = state and INTERCEPTING.inv() - return - } - } - - state = state and INTERCEPTING.inv() this.result = data try { val result = doResume() @@ -116,14 +123,6 @@ internal abstract class CoroutineImpl(private val resultContinuation: Continuati } override fun resumeWithException(exception: Throwable) { - if (continuationDispatcher != null && (state and INTERCEPTING) == 0) { - state = state or INTERCEPTING - if (continuationDispatcher.dispatchResumeWithException(exception, this)) { - state = state and INTERCEPTING.inv() - return - } - } - state = exceptionState this.exception = exception try { @@ -140,4 +139,16 @@ internal abstract class CoroutineImpl(private val resultContinuation: Continuati protected abstract fun doResume(): Any? } -private const val INTERCEPTING = 1 shl 31 \ No newline at end of file +private class ContinuationFacade(val innerContinuation: Continuation, val dispatcher: ContinuationDispatcher) : Continuation { + override fun resume(value: Any?) { + if (!dispatcher.dispatchResume(value, innerContinuation)) { + innerContinuation.resume(value) + } + } + + override fun resumeWithException(exception: Throwable) { + if (!dispatcher.dispatchResumeWithException(exception, innerContinuation)) { + innerContinuation.resumeWithException(exception) + } + } +} \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt index d0333f0b8e0..b81adf0e7d8 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt @@ -21,10 +21,7 @@ import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind import com.google.dart.compiler.backend.js.ast.metadata.sideEffects import com.intellij.util.SmartList import org.jetbrains.kotlin.coroutines.isSuspendLambda -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable import org.jetbrains.kotlin.js.translate.context.TranslationContext @@ -156,7 +153,8 @@ class CallArgumentTranslator private constructor( val callableDescriptor = resolvedCall.resultingDescriptor if (callableDescriptor is FunctionDescriptor && callableDescriptor.isSuspend) { - result.add(TranslationUtils.translateContinuationArgument(context(), resolvedCall)) + val facadeName = context().getNameForDescriptor(TranslationUtils.getCoroutineProperty(context(), "facade")) + result.add(JsAstUtils.pureFqn(facadeName, TranslationUtils.translateContinuationArgument(context(), resolvedCall))) } removeLastUndefinedArguments(result)