Skip to content

Commit 54b2ecd

Browse files
committed
Merge branch 'develop' into stacktrace-recovery
# Conflicts: # common/kotlinx-coroutines-core-common/src/JobSupport.kt # core/kotlinx-coroutines-core/test/exceptions/SuppressionTests.kt
2 parents 515ccb1 + 3c4168b commit 54b2ecd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+379
-102
lines changed

binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,6 @@ public final class kotlinx/coroutines/channels/ClosedSendChannelException : java
630630
}
631631

632632
public final class kotlinx/coroutines/channels/ConflatedBroadcastChannel : kotlinx/coroutines/channels/BroadcastChannel {
633-
public static final field Companion Lkotlinx/coroutines/channels/ConflatedBroadcastChannel$Companion;
634633
public fun <init> ()V
635634
public fun <init> (Ljava/lang/Object;)V
636635
public fun cancel (Ljava/lang/Throwable;)Z

build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,11 @@ configure(subprojects.findAll { !unpublished.contains(it.name) }) {
193193
tasks.withType(org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile).all {
194194
kotlinOptions.freeCompilerArgs += ["-Xuse-experimental=kotlin.Experimental",
195195
"-Xuse-experimental=kotlin.experimental.ExperimentalTypeInference",
196+
"-Xuse-experimental=kotlin.ExperimentalMultiplatform",
196197
"-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi",
197198
"-Xuse-experimental=kotlinx.coroutines.ObsoleteCoroutinesApi",
198-
"-Xuse-experimental=kotlinx.coroutines.InternalCoroutinesApi"]
199-
199+
"-Xuse-experimental=kotlinx.coroutines.InternalCoroutinesApi",
200+
"-progressive"]
200201
}
201202
}
202203

common/kotlinx-coroutines-core-common/src/AbstractContinuation.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ internal abstract class AbstractContinuation<in T>(
277277
internal interface NotCompleted
278278

279279
private class Active : NotCompleted
280+
@SharedImmutable
280281
private val ACTIVE: Active = Active()
281282

282283
internal abstract class CancelHandler : CancelHandlerBase(), NotCompleted

common/kotlinx-coroutines-core-common/src/Builders.common.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ private class DispatchedCoroutine<in T>(
228228
fun getResult(): Any? {
229229
if (trySuspend()) return COROUTINE_SUSPENDED
230230
// otherwise, onCompletionInternal was already invoked & invoked tryResume, and the result is in the state
231-
val state = this.state
231+
val state = this.state.unboxState()
232232
if (state is CompletedExceptionally) throw state.cause
233233
@Suppress("UNCHECKED_CAST")
234234
return state as T

common/kotlinx-coroutines-core-common/src/CoroutineExceptionHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ internal fun handlerException(originalException: Throwable, thrownException: Thr
6565
*/
6666
@Suppress("FunctionName")
6767
public inline fun CoroutineExceptionHandler(crossinline handler: (CoroutineContext, Throwable) -> Unit): CoroutineExceptionHandler =
68-
object: AbstractCoroutineContextElement(CoroutineExceptionHandler), CoroutineExceptionHandler {
68+
object : AbstractCoroutineContextElement(CoroutineExceptionHandler), CoroutineExceptionHandler {
6969
override fun handleException(context: CoroutineContext, exception: Throwable) =
7070
handler.invoke(context, exception)
7171
}

common/kotlinx-coroutines-core-common/src/Dispatched.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import kotlin.coroutines.*
99
import kotlin.jvm.*
1010

1111
@Suppress("PrivatePropertyName")
12+
@SharedImmutable
1213
private val UNDEFINED = Symbol("UNDEFINED")
1314

1415
@NativeThreadLocal

common/kotlinx-coroutines-core-common/src/JobSupport.kt

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,10 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
154154
}
155155

156156
// ------------ state query ------------
157-
158157
/**
159158
* Returns current state of this job.
160-
* @suppress **This is unstable API and it is subject to change.**
159+
* If final state of the job is [Incomplete], then it is boxed into [IncompleteStateBox]
160+
* and should be [unboxed][unboxState] before returning to user code.
161161
*/
162162
internal val state: Any? get() {
163163
_state.loop { state -> // helper loop on state (complete in-progress atomic operations)
@@ -192,7 +192,12 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
192192
// Finalizes Finishing -> Completed (terminal state) transition.
193193
// ## IMPORTANT INVARIANT: Only one thread can be concurrently invoking this method.
194194
private fun tryFinalizeFinishingState(state: Finishing, proposedUpdate: Any?, mode: Int): Boolean {
195-
require(proposedUpdate !is Incomplete) // only incomplete -> completed transition is allowed
195+
/*
196+
* Note: proposed state can be Incompleted, e.g.
197+
* async {
198+
* smth.invokeOnCompletion {} // <- returns handle which implements Incomplete under the hood
199+
* }
200+
*/
196201
require(this.state === state) // consistency check -- it cannot change
197202
require(!state.isSealed) // consistency check -- cannot be sealed yet
198203
require(state.isCompleting) // consistency check -- must be marked as completing
@@ -220,7 +225,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
220225
handleJobException(finalException)
221226
}
222227
// Then CAS to completed state -> it must succeed
223-
require(_state.compareAndSet(state, finalState)) { "Unexpected state: ${_state.value}, expected: $state, update: $finalState" }
228+
require(_state.compareAndSet(state, finalState.boxIncomplete())) { "Unexpected state: ${_state.value}, expected: $state, update: $finalState" }
224229
// And process all post-completion actions
225230
completeStateFinalization(state, finalState, mode, suppressed)
226231
return true
@@ -255,7 +260,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
255260
private fun tryFinalizeSimpleState(state: Incomplete, update: Any?, mode: Int): Boolean {
256261
check(state is Empty || state is JobNode<*>) // only simple state without lists where children can concurrently add
257262
check(update !is CompletedExceptionally) // only for normal completion
258-
if (!_state.compareAndSet(state, update)) return false
263+
if (!_state.compareAndSet(state, update.boxIncomplete())) return false
259264
completeStateFinalization(state, update, mode, false)
260265
return true
261266
}
@@ -1067,7 +1072,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
10671072
val state = this.state
10681073
check(state !is Incomplete) { "This job has not completed yet" }
10691074
if (state is CompletedExceptionally) throw state.cause
1070-
return state
1075+
return state.unboxState()
10711076
}
10721077

10731078
/**
@@ -1082,7 +1087,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
10821087
if (state is CompletedExceptionally) { // Slow path to recover stacktrace
10831088
recoverAndThrow(state.cause)
10841089
}
1085-
return state
1090+
return state.unboxState()
10861091

10871092
}
10881093
if (startInternal(state) >= 0) break // break unless needs to retry
@@ -1114,10 +1119,12 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
11141119
if (state !is Incomplete) {
11151120
// already complete -- select result
11161121
if (select.trySelect(null)) {
1117-
if (state is CompletedExceptionally)
1122+
if (state is CompletedExceptionally) {
11181123
select.resumeSelectCancellableWithException(state.cause)
1119-
else
1120-
block.startCoroutineUnintercepted(state as T, select.completion)
1124+
}
1125+
else {
1126+
block.startCoroutineUnintercepted(state.unboxState() as T, select.completion)
1127+
}
11211128
}
11221129
return
11231130
}
@@ -1139,10 +1146,17 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
11391146
if (state is CompletedExceptionally)
11401147
select.resumeSelectCancellableWithException(state.cause)
11411148
else
1142-
block.startCoroutineCancellable(state as T, select.completion)
1149+
block.startCoroutineCancellable(state.unboxState() as T, select.completion)
11431150
}
11441151
}
11451152

1153+
/*
1154+
* Class to represent object as the final state of the Job
1155+
*/
1156+
private class IncompleteStateBox(@JvmField val state: Incomplete)
1157+
private fun Any?.boxIncomplete(): Any? = if (this is Incomplete) IncompleteStateBox(this) else this
1158+
internal fun Any?.unboxState(): Any? = (this as? IncompleteStateBox)?.state ?: this
1159+
11461160
// --------------- helper classes & constants for job implementation
11471161

11481162
private const val COMPLETING_ALREADY_COMPLETING = 0
@@ -1154,9 +1168,11 @@ private const val RETRY = -1
11541168
private const val FALSE = 0
11551169
private const val TRUE = 1
11561170

1171+
@SharedImmutable
11571172
private val SEALED = Symbol("SEALED")
1158-
1173+
@SharedImmutable
11591174
private val EMPTY_NEW = Empty(false)
1175+
@SharedImmutable
11601176
private val EMPTY_ACTIVE = Empty(true)
11611177

11621178
private class Empty(override val isActive: Boolean) : Incomplete {
@@ -1241,7 +1257,7 @@ private class ResumeAwaitOnCompletion<T>(
12411257
} else {
12421258
// Resuming with value in a cancellable way (AwaitContinuation is configured for this mode).
12431259
@Suppress("UNCHECKED_CAST")
1244-
continuation.resume(state as T)
1260+
continuation.resume(state.unboxState() as T)
12451261
}
12461262
}
12471263
override fun toString() = "ResumeAwaitOnCompletion[$continuation]"

common/kotlinx-coroutines-core-common/src/SchedulerTask.common.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ internal expect abstract class SchedulerTask() : Runnable
88

99
internal expect interface SchedulerTaskContext
1010

11+
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
1112
internal expect val SchedulerTask.taskContext: SchedulerTaskContext
1213

14+
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
1315
internal expect inline fun SchedulerTaskContext.afterTask()

common/kotlinx-coroutines-core-common/src/Timeout.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import kotlin.jvm.*
2626
* @param timeMillis timeout time in milliseconds.
2727
*/
2828
public suspend fun <T> withTimeout(timeMillis: Long, block: suspend CoroutineScope.() -> T): T {
29-
if (timeMillis <= 0L) throw CancellationException("Timed out immediately")
29+
if (timeMillis <= 0L) throw TimeoutCancellationException("Timed out immediately")
3030
return suspendCoroutineUninterceptedOrReturn { uCont ->
3131
setupTimeout(TimeoutCoroutine(timeMillis, uCont), block)
3232
}

common/kotlinx-coroutines-core-common/src/channels/AbstractChannel.kt

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,32 +1003,43 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
10031003
)
10041004
}
10051005

1006-
/** @suppress **This is unstable API and it is subject to change.** */
1007-
@JvmField internal val OFFER_SUCCESS: Any = Symbol("OFFER_SUCCESS")
1006+
@JvmField
1007+
@SharedImmutable
1008+
internal val OFFER_SUCCESS: Any = Symbol("OFFER_SUCCESS")
10081009

1009-
/** @suppress **This is unstable API and it is subject to change.** */
1010-
@JvmField internal val OFFER_FAILED: Any = Symbol("OFFER_FAILED")
1010+
@JvmField
1011+
@SharedImmutable
1012+
internal val OFFER_FAILED: Any = Symbol("OFFER_FAILED")
10111013

1012-
/** @suppress **This is unstable API and it is subject to change.** */
1013-
@JvmField internal val POLL_FAILED: Any = Symbol("POLL_FAILED")
1014+
@JvmField
1015+
@SharedImmutable
1016+
internal val POLL_FAILED: Any = Symbol("POLL_FAILED")
10141017

1015-
/** @suppress **This is unstable API and it is subject to change.** */
1016-
@JvmField internal val ENQUEUE_FAILED: Any = Symbol("ENQUEUE_FAILED")
1018+
@JvmField
1019+
@SharedImmutable
1020+
internal val ENQUEUE_FAILED: Any = Symbol("ENQUEUE_FAILED")
10171021

1018-
/** @suppress **This is unstable API and it is subject to change.** */
1019-
@JvmField internal val SELECT_STARTED: Any = Symbol("SELECT_STARTED")
1022+
@JvmField
1023+
@SharedImmutable
1024+
internal val SELECT_STARTED: Any = Symbol("SELECT_STARTED")
10201025

1021-
/** @suppress **This is unstable API and it is subject to change.** */
1022-
@JvmField internal val NULL_VALUE: Any = Symbol("NULL_VALUE")
1026+
@JvmField
1027+
@SharedImmutable
1028+
internal val NULL_VALUE: Any = Symbol("NULL_VALUE")
10231029

1024-
/** @suppress **This is unstable API and it is subject to change.** */
1025-
@JvmField internal val CLOSE_RESUMED: Any = Symbol("CLOSE_RESUMED")
1030+
@JvmField
1031+
@SharedImmutable
1032+
internal val CLOSE_RESUMED: Any = Symbol("CLOSE_RESUMED")
10261033

1027-
/** @suppress **This is unstable API and it is subject to change.** */
1028-
@JvmField internal val SEND_RESUMED = Symbol("SEND_RESUMED")
1034+
@JvmField
1035+
@SharedImmutable
1036+
internal val SEND_RESUMED: Any = Symbol("SEND_RESUMED")
1037+
1038+
@JvmField
1039+
@SharedImmutable
1040+
internal val HANDLER_INVOKED: Any = Symbol("ON_CLOSE_HANDLER_INVOKED")
10291041

10301042
internal typealias Handler = (Throwable?) -> Unit
1031-
@JvmField internal val HANDLER_INVOKED = Any()
10321043

10331044
/**
10341045
* Represents sending waiter in the queue.

0 commit comments

Comments
 (0)