JS: improve how base class for coroutines is implemented: 1) use JVM-like style of passing dispatcher 2) instead of flag, use additional "facade" continuation when dealing with dispatchers
This commit is contained in:
@@ -29,7 +29,7 @@ public fun <R, T> (suspend R.() -> T).createCoroutine(
|
|||||||
receiver: R,
|
receiver: R,
|
||||||
completion: Continuation<T>,
|
completion: Continuation<T>,
|
||||||
dispatcher: ContinuationDispatcher? = null
|
dispatcher: ContinuationDispatcher? = null
|
||||||
): Continuation<Unit> = this.asDynamic().call(receiver, withDispatcher(completion, dispatcher))
|
): Continuation<Unit> = this.asDynamic().call(receiver, withDispatcher(completion, dispatcher)).facade
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts coroutine with receiver type [R] and result type [T].
|
* Starts coroutine with receiver type [R] and result type [T].
|
||||||
@@ -57,7 +57,7 @@ public fun <R, T> (suspend R.() -> T).startCoroutine(
|
|||||||
public fun <T> (suspend () -> T).createCoroutine(
|
public fun <T> (suspend () -> T).createCoroutine(
|
||||||
completion: Continuation<T>,
|
completion: Continuation<T>,
|
||||||
dispatcher: ContinuationDispatcher? = null
|
dispatcher: ContinuationDispatcher? = null
|
||||||
): Continuation<Unit> = this.asDynamic()(withDispatcher(completion, dispatcher))
|
): Continuation<Unit> = this.asDynamic()(withDispatcher(completion, dispatcher)).facade
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts coroutine without receiver and with result type [T].
|
* Starts coroutine without receiver and with result type [T].
|
||||||
@@ -75,13 +75,19 @@ public fun <T> (suspend () -> T).startCoroutine(
|
|||||||
|
|
||||||
// ------- internal stuff -------
|
// ------- internal stuff -------
|
||||||
|
|
||||||
private fun <T> withDispatcher(completion: Continuation<T>, dispatcher: ContinuationDispatcher?): Continuation<T> {
|
internal interface DispatchedContinuation {
|
||||||
val finalContinuationDispatcher = dispatcher ?: object : ContinuationDispatcher {
|
val dispatcher: ContinuationDispatcher?
|
||||||
override fun <T> dispatchResume(value: T, continuation: Continuation<T>) = false
|
}
|
||||||
|
|
||||||
override fun dispatchResumeWithException(exception: Throwable, continuation: Continuation<*>) = false
|
private fun <T> withDispatcher(completion: Continuation<T>, dispatcher: ContinuationDispatcher?): Continuation<T> {
|
||||||
|
return if (dispatcher == null) {
|
||||||
|
completion
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
object : Continuation<T> by completion, DispatchedContinuation {
|
||||||
|
override val dispatcher = dispatcher
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return object : Continuation<T> by completion, ContinuationDispatcher by finalContinuationDispatcher {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsName("CoroutineImpl")
|
@JsName("CoroutineImpl")
|
||||||
@@ -91,18 +97,19 @@ internal abstract class CoroutineImpl(private val resultContinuation: Continuati
|
|||||||
protected var result: Any? = null
|
protected var result: Any? = null
|
||||||
protected var exception: Throwable? = null
|
protected var exception: Throwable? = null
|
||||||
protected var finallyPath: Array<Int>? = null
|
protected var finallyPath: Array<Int>? = null
|
||||||
private val continuationDispatcher = resultContinuation as? ContinuationDispatcher
|
private val continuationDispatcher = (resultContinuation as? DispatchedContinuation)?.dispatcher
|
||||||
|
val facade: Continuation<Any?>
|
||||||
|
|
||||||
|
init {
|
||||||
|
facade = if (continuationDispatcher != null) {
|
||||||
|
ContinuationFacade(this, continuationDispatcher)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun resume(data: Any?) {
|
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
|
this.result = data
|
||||||
try {
|
try {
|
||||||
val result = doResume()
|
val result = doResume()
|
||||||
@@ -116,14 +123,6 @@ internal abstract class CoroutineImpl(private val resultContinuation: Continuati
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun resumeWithException(exception: Throwable) {
|
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
|
state = exceptionState
|
||||||
this.exception = exception
|
this.exception = exception
|
||||||
try {
|
try {
|
||||||
@@ -140,4 +139,16 @@ internal abstract class CoroutineImpl(private val resultContinuation: Continuati
|
|||||||
protected abstract fun doResume(): Any?
|
protected abstract fun doResume(): Any?
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val INTERCEPTING = 1 shl 31
|
private class ContinuationFacade(val innerContinuation: Continuation<Any?>, val dispatcher: ContinuationDispatcher) : Continuation<Any?> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-5
@@ -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.google.dart.compiler.backend.js.ast.metadata.sideEffects
|
||||||
import com.intellij.util.SmartList
|
import com.intellij.util.SmartList
|
||||||
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable
|
import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
@@ -156,7 +153,8 @@ class CallArgumentTranslator private constructor(
|
|||||||
|
|
||||||
val callableDescriptor = resolvedCall.resultingDescriptor
|
val callableDescriptor = resolvedCall.resultingDescriptor
|
||||||
if (callableDescriptor is FunctionDescriptor && callableDescriptor.isSuspend) {
|
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)
|
removeLastUndefinedArguments(result)
|
||||||
|
|||||||
Reference in New Issue
Block a user