Switch sourcesets of experimental and release coroutines

- Move experimental coroutines out of the main source root.
- Include experimental coroutines into the coroutines source set.
- Include release coroutines into the main source set.
This commit is contained in:
Ilya Gorbunov
2018-08-31 20:53:08 +03:00
parent 0fa2d29779
commit e22ca022d4
31 changed files with 25 additions and 30 deletions
@@ -0,0 +1,81 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package kotlin.coroutines.experimental
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
import kotlin.*
import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED
@PublishedApi
internal actual class SafeContinuation<in T>
internal actual constructor(
private val delegate: Continuation<T>,
initialResult: Any?
) : Continuation<T> {
@PublishedApi
internal actual constructor(delegate: Continuation<T>) : this(delegate, UNDECIDED)
public actual override val context: CoroutineContext
get() = delegate.context
@Volatile
private var result: Any? = initialResult
companion object {
private val UNDECIDED: Any? = Any()
private val RESUMED: Any? = Any()
@Suppress("UNCHECKED_CAST")
@JvmStatic
private val RESULT = AtomicReferenceFieldUpdater.newUpdater<SafeContinuation<*>, Any?>(
SafeContinuation::class.java, Any::class.java as Class<Any?>, "result"
)
}
private class Fail(val exception: Throwable)
actual override fun resume(value: T) {
while (true) { // lock-free loop
val result = this.result // atomic read
when {
result === UNDECIDED -> if (RESULT.compareAndSet(this, UNDECIDED, value)) return
result === COROUTINE_SUSPENDED -> if (RESULT.compareAndSet(this, COROUTINE_SUSPENDED, RESUMED)) {
delegate.resume(value)
return
}
else -> throw IllegalStateException("Already resumed")
}
}
}
actual override fun resumeWithException(exception: Throwable) {
while (true) { // lock-free loop
val result = this.result // atomic read
when {
result === UNDECIDED -> if (RESULT.compareAndSet(this, UNDECIDED, Fail(exception))) return
result === COROUTINE_SUSPENDED -> if (RESULT.compareAndSet(this, COROUTINE_SUSPENDED, RESUMED)) {
delegate.resumeWithException(exception)
return
}
else -> throw IllegalStateException("Already resumed")
}
}
}
@PublishedApi
internal actual fun getResult(): Any? {
var result = this.result // atomic read
if (result === UNDECIDED) {
if (RESULT.compareAndSet(this, UNDECIDED, COROUTINE_SUSPENDED)) return COROUTINE_SUSPENDED
result = this.result // reread volatile var
}
when {
result === RESUMED -> return COROUTINE_SUSPENDED // already called continuation, indicate COROUTINE_SUSPENDED upstream
result is Fail -> throw result.exception
else -> return result // either COROUTINE_SUSPENDED or data
}
}
}
@@ -0,0 +1,126 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:kotlin.jvm.JvmName("IntrinsicsKt")
@file:kotlin.jvm.JvmMultifileClass
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
package kotlin.coroutines.experimental.intrinsics
import kotlin.coroutines.experimental.*
/**
* Starts unintercepted coroutine without receiver and with result type [T] and executes it until its first suspension.
* Returns the result of the coroutine or throws its exception if it does not suspend or [COROUTINE_SUSPENDED] if it suspends.
* In the later case, the [completion] continuation is invoked when coroutine completes with result or exception.
* This function is designed to be used from inside of [suspendCoroutineOrReturn] to resume the execution of suspended
* coroutine using a reference to the suspending function.
*/
@SinceKotlin("1.1")
@Suppress("UNCHECKED_CAST")
@kotlin.internal.InlineOnly
public actual inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrReturn(
completion: Continuation<T>
): Any? = (this as Function1<Continuation<T>, Any?>).invoke(completion)
/**
* Starts unintercepted coroutine with receiver type [R] and result type [T] and executes it until its first suspension.
* Returns the result of the coroutine or throws its exception if it does not suspend or [COROUTINE_SUSPENDED] if it suspends.
* In the later case, the [completion] continuation is invoked when coroutine completes with result or exception.
* This function is designed to be used from inside of [suspendCoroutineOrReturn] to resume the execution of suspended
* coroutine using a reference to the suspending function.
*/
@SinceKotlin("1.1")
@Suppress("UNCHECKED_CAST")
@kotlin.internal.InlineOnly
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)
// JVM declarations
/**
* Creates a coroutine without receiver and with result type [T].
* This function creates a new, fresh instance of suspendable computation every time it is invoked.
*
* To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance.
* The [completion] continuation is invoked when coroutine completes with result or exception.
*
* This function is _unchecked_. Repeated invocation of any resume function on the resulting continuation corrupts the
* state machine of the coroutine and may result in arbitrary behaviour or exception.
*/
@SinceKotlin("1.1")
public actual fun <T> (suspend () -> T).createCoroutineUnchecked(
completion: Continuation<T>
): Continuation<Unit> =
if (this !is kotlin.coroutines.experimental.jvm.internal.CoroutineImpl)
buildContinuationByInvokeCall(completion) {
@Suppress("UNCHECKED_CAST")
(this as Function1<Continuation<T>, Any?>).invoke(completion)
}
else
(this.create(completion) as kotlin.coroutines.experimental.jvm.internal.CoroutineImpl).facade
/**
* Creates a coroutine with receiver type [R] and result type [T].
* This function creates a new, fresh instance of suspendable computation every time it is invoked.
*
* To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance.
* The [completion] continuation is invoked when coroutine completes with result or exception.
*
* This function is _unchecked_. Repeated invocation of any resume function on the resulting continuation corrupts the
* state machine of the coroutine and may result in arbitrary behaviour or exception.
*/
@SinceKotlin("1.1")
public actual fun <R, T> (suspend R.() -> T).createCoroutineUnchecked(
receiver: R,
completion: Continuation<T>
): Continuation<Unit> =
if (this !is kotlin.coroutines.experimental.jvm.internal.CoroutineImpl)
buildContinuationByInvokeCall(completion) {
@Suppress("UNCHECKED_CAST")
(this as Function2<R, Continuation<T>, Any?>).invoke(receiver, completion)
}
else
(this.create(receiver, completion) as kotlin.coroutines.experimental.jvm.internal.CoroutineImpl).facade
// INTERNAL DEFINITIONS
private inline fun <T> buildContinuationByInvokeCall(
completion: Continuation<T>,
crossinline block: () -> Any?
): Continuation<Unit> {
val continuation =
object : Continuation<Unit> {
override val context: CoroutineContext
get() = completion.context
override fun resume(value: Unit) {
processBareContinuationResume(completion, block)
}
override fun resumeWithException(exception: Throwable) {
completion.resumeWithException(exception)
}
}
return kotlin.coroutines.experimental.jvm.internal.interceptContinuationIfNeeded(completion.context, continuation)
}
/**
* This value is used as a return value of [suspendCoroutineOrReturn] `block` argument to state that
* the execution was suspended and will not return any result immediately.
*/
@SinceKotlin("1.1")
public actual val COROUTINE_SUSPENDED: Any get() = CoroutineSingletons.COROUTINE_SUSPENDED
// Using enum here ensures two important properties:
// 1. It makes SafeContinuation serializable with all kinds of serialization frameworks (since all of them natively support enums)
// 2. It improves debugging experience, since you clearly see toString() value of those objects and what package they come from
private enum class CoroutineSingletons {
COROUTINE_SUSPENDED
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package kotlin.coroutines.experimental.jvm.internal
import java.lang.IllegalStateException
import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.CoroutineContext
import kotlin.coroutines.experimental.processBareContinuationResume
import kotlin.jvm.internal.Lambda
/**
* @suppress
*/
abstract class CoroutineImpl(
arity: Int,
@JvmField
protected var completion: Continuation<Any?>?
) : Lambda<Any?>(arity), Continuation<Any?> {
// label == -1 when coroutine cannot be started (it is just a factory object) or has already finished execution
// label == 0 in initial part of the coroutine
@JvmField
protected var label: Int = if (completion != null) 0 else -1
private val _context: CoroutineContext? = completion?.context
override val context: CoroutineContext
get() = _context!!
private var _facade: Continuation<Any?>? = null
val facade: Continuation<Any?> get() {
if (_facade == null) _facade = interceptContinuationIfNeeded(_context!!, this)
return _facade!!
}
override fun resume(value: Any?) {
processBareContinuationResume(completion!!) {
doResume(value, null)
}
}
override fun resumeWithException(exception: Throwable) {
processBareContinuationResume(completion!!) {
doResume(null, exception)
}
}
protected abstract fun doResume(data: Any?, exception: Throwable?): Any?
open fun create(completion: Continuation<*>): Continuation<Unit> {
throw IllegalStateException("create(Continuation) has not been overridden")
}
open fun create(value: Any?, completion: Continuation<*>): Continuation<Unit> {
throw IllegalStateException("create(Any?;Continuation) has not been overridden")
}
}
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:JvmName("CoroutineIntrinsics")
package kotlin.coroutines.experimental.jvm.internal
import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.ContinuationInterceptor
import kotlin.coroutines.experimental.CoroutineContext
/**
* @suppress
*/
fun <T> normalizeContinuation(continuation: Continuation<T>): Continuation<T> =
(continuation as? CoroutineImpl)?.facade ?: continuation
internal fun <T> interceptContinuationIfNeeded(
context: CoroutineContext,
continuation: Continuation<T>
) = context[ContinuationInterceptor]?.interceptContinuation(continuation) ?: continuation
@@ -0,0 +1,144 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package kotlin.coroutines.experimental.migration
import kotlin.coroutines.experimental.Continuation as ExperimentalContinuation
import kotlin.coroutines.experimental.CoroutineContext as ExperimentalCoroutineContext
import kotlin.coroutines.experimental.AbstractCoroutineContextElement as ExperimentalAbstractCoroutineContextElement
import kotlin.coroutines.experimental.EmptyCoroutineContext as ExperimentalEmptyCoroutineContext
import kotlin.coroutines.experimental.ContinuationInterceptor as ExperimentalContinuationInterceptor
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
/**
* Converts [Continuation] to [ExperimentalContinuation].
*/
@SinceKotlin("1.3")
public fun <T> Continuation<T>.toExperimentalContinuation(): ExperimentalContinuation<T> =
(this as? ContinuationMigration<T>)?.continuation ?: ExperimentalContinuationMigration(this)
/**
* Converts [ExperimentalContinuation] to [Continuation].
*/
@SinceKotlin("1.3")
public fun <T> ExperimentalContinuation<T>.toContinuation(): Continuation<T> =
(this as? ExperimentalContinuationMigration<T>)?.continuation ?: ContinuationMigration(this)
/**
* Converts [CoroutineContext] to [ExperimentalCoroutineContext].
*/
@SinceKotlin("1.3")
public fun CoroutineContext.toExperimentalCoroutineContext(): ExperimentalCoroutineContext {
val interceptor = get(ContinuationInterceptor.Key)
val migration = get(ContextMigration.Key)
val remainder = minusKey(ContinuationInterceptor.Key).minusKey(ContextMigration.Key)
val original = migration?.context ?: ExperimentalEmptyCoroutineContext
val result = if (remainder === EmptyCoroutineContext) original else original + ExperimentalContextMigration(remainder)
return if (interceptor == null) result else result + interceptor.toExperimentalContinuationInterceptor()
}
/**
* Converts [ExperimentalCoroutineContext] to [CoroutineContext].
*/
@SinceKotlin("1.3")
public fun ExperimentalCoroutineContext.toCoroutineContext(): CoroutineContext {
val interceptor = get(ExperimentalContinuationInterceptor.Key)
val migration = get(ExperimentalContextMigration.Key)
val remainder = minusKey(ExperimentalContinuationInterceptor.Key).minusKey(ExperimentalContextMigration.Key)
val original = migration?.context ?: EmptyCoroutineContext
val result = if (remainder === ExperimentalEmptyCoroutineContext) original else original + ContextMigration(remainder)
return if (interceptor == null) result else result + interceptor.toContinuationInterceptor()
}
/**
* Converts [ContinuationInterceptor] to [ExperimentalContinuationInterceptor].
*/
@SinceKotlin("1.3")
public fun ContinuationInterceptor.toExperimentalContinuationInterceptor(): ExperimentalContinuationInterceptor =
(this as? ContinuationInterceptorMigration)?.interceptor ?: ExperimentalContinuationInterceptorMigration(this)
/**
* Converts [ExperimentalContinuationInterceptor] to [ContinuationInterceptor].
*/
@SinceKotlin("1.3")
public fun ExperimentalContinuationInterceptor.toContinuationInterceptor(): ContinuationInterceptor =
(this as? ExperimentalContinuationInterceptorMigration)?.interceptor ?: ContinuationInterceptorMigration(this)
// ------------------ converter classes ------------------
// Their name starts with "Experimental" if they implement the corresponding Experimental interfaces
private class ExperimentalContinuationMigration<T>(val continuation: Continuation<T>): ExperimentalContinuation<T> {
override val context = continuation.context.toExperimentalCoroutineContext()
override fun resume(value: T) = continuation.resume(value)
override fun resumeWithException(exception: Throwable) = continuation.resumeWithException(exception)
}
private class ContinuationMigration<T>(val continuation: ExperimentalContinuation<T>): Continuation<T> {
override val context: CoroutineContext = continuation.context.toCoroutineContext()
override fun resumeWith(result: SuccessOrFailure<T>) {
result
.onSuccess { continuation.resume(it) }
.onFailure { continuation.resumeWithException(it) }
}
}
private class ExperimentalContextMigration(val context: CoroutineContext): ExperimentalAbstractCoroutineContextElement(Key) {
companion object Key : ExperimentalCoroutineContext.Key<ExperimentalContextMigration>
}
private class ContextMigration(val context: ExperimentalCoroutineContext): AbstractCoroutineContextElement(Key) {
companion object Key : CoroutineContext.Key<ContextMigration>
}
private class ExperimentalContinuationInterceptorMigration(val interceptor: ContinuationInterceptor) : ExperimentalContinuationInterceptor {
override val key: ExperimentalCoroutineContext.Key<*>
get() = ExperimentalContinuationInterceptor.Key
override fun <T> interceptContinuation(continuation: ExperimentalContinuation<T>): ExperimentalContinuation<T> =
interceptor.interceptContinuation(continuation.toContinuation()).toExperimentalContinuation()
}
private class ContinuationInterceptorMigration(val interceptor: ExperimentalContinuationInterceptor) : ContinuationInterceptor {
override val key: CoroutineContext.Key<*>
get() = ContinuationInterceptor.Key
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
interceptor.interceptContinuation(continuation.toExperimentalContinuation()).toContinuation()
}
internal fun <R> ((Continuation<R>) -> Any?).toExperimentalSuspendFunction(): (ExperimentalContinuation<R>) -> Any? =
ExperimentalSuspendFunction0Migration(this)
internal fun <T1, R> ((T1, Continuation<R>) -> Any?).toExperimentalSuspendFunction(): (T1, ExperimentalContinuation<R>) -> Any? =
ExperimentalSuspendFunction1Migration(this)
internal fun <T1, T2, R> ((T1, T2, Continuation<R>) -> Any?).toExperimentalSuspendFunction(): (T1, T2, ExperimentalContinuation<R>) -> Any? =
ExperimentalSuspendFunction2Migration(this)
private class ExperimentalSuspendFunction0Migration<R>(
val function: (Continuation<R>) -> Any?
) : (ExperimentalContinuation<R>) -> Any? {
override fun invoke(continuation: ExperimentalContinuation<R>): Any? {
return function(continuation.toContinuation())
}
}
private class ExperimentalSuspendFunction1Migration<T1, R>(
val function: (T1, Continuation<R>) -> Any?
) : (T1, ExperimentalContinuation<R>) -> Any? {
override fun invoke(t1: T1, continuation: ExperimentalContinuation<R>): Any? {
return function(t1, continuation.toContinuation())
}
}
private class ExperimentalSuspendFunction2Migration<T1, T2, R>(
val function: (T1, T2, Continuation<R>) -> Any?
) : (T1, T2, ExperimentalContinuation<R>) -> Any? {
override fun invoke(t1: T1, t2: T2, continuation: ExperimentalContinuation<R>): Any? {
return function(t1, t2, continuation.toContinuation())
}
}