Skip to content

Commit 583d39d

Browse files
committed
Rewrite assertions so that they are checked only in debug mode
* Make sure assertions are absent on native and JS * Only print full toString for Job in debug mode
1 parent e174298 commit 583d39d

27 files changed

+135
-104
lines changed

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines
@@ -297,7 +297,7 @@ internal open class CancellableContinuationImpl<in T>(
297297
}
298298
is CompletedIdempotentResult -> {
299299
return if (state.idempotentResume === idempotent) {
300-
check(state.result === value) { "Non-idempotent resume" }
300+
assert { state.result === value } // "Non-idempotent resume"
301301
state.token
302302
} else {
303303
null
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/*
2-
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines
66

7+
internal expect val DEBUG: Boolean
78
internal expect val Any.hexAddress: String
89
internal expect val Any.classSimpleName: String
10+
internal expect fun assert(value: () -> Boolean)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ internal class DispatchedContinuation<in T>(
8787

8888
override fun takeState(): Any? {
8989
val state = _state
90-
check(state !== UNDEFINED) // fail-fast if repeatedly invoked
90+
assert { state !== UNDEFINED } // fail-fast if repeatedly invoked
9191
_state = UNDEFINED
9292
return state
9393
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines
@@ -104,7 +104,7 @@ internal abstract class EventLoop : CoroutineDispatcher() {
104104
fun decrementUseCount(unconfined: Boolean = false) {
105105
useCount -= delta(unconfined)
106106
if (useCount > 0) return
107-
check(useCount == 0L) { "Extra decrementUseCount" }
107+
assert { useCount == 0L } // "Extra decrementUseCount"
108108
if (shared) {
109109
// shut it down and remove from ThreadLocalEventLoop
110110
shutdown()

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

+12-15
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,9 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
136136
/**
137137
* Initializes parent job.
138138
* It shall be invoked at most once after construction after all other initialization.
139-
* @suppress **This is unstable API and it is subject to change.**
140139
*/
141140
internal fun initParentJobInternal(parent: Job?) {
142-
check(parentHandle == null)
141+
assert { parentHandle == null }
143142
if (parent == null) {
144143
parentHandle = NonDisposableHandle
145144
return
@@ -269,8 +268,8 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
269268

270269
// fast-path method to finalize normally completed coroutines without children
271270
private fun tryFinalizeSimpleState(state: Incomplete, update: Any?, mode: Int): Boolean {
272-
check(state is Empty || state is JobNode<*>) // only simple state without lists where children can concurrently add
273-
check(update !is CompletedExceptionally) // only for normal completion
271+
assert { state is Empty || state is JobNode<*> } // only simple state without lists where children can concurrently add
272+
assert { update !is CompletedExceptionally } // only for normal completion
274273
if (!_state.compareAndSet(state, update.boxIncomplete())) return false
275274
onCancelling(null) // simple state is not a failure
276275
onCompletionInternal(update)
@@ -397,16 +396,14 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
397396
*/
398397
internal open fun onStartInternal() {}
399398

400-
public final override fun getCancellationException(): CancellationException {
401-
val state = this.state
402-
return when (state) {
399+
public final override fun getCancellationException(): CancellationException =
400+
when (val state = this.state) {
403401
is Finishing -> state.rootCause?.toCancellationException("$classSimpleName is cancelling")
404402
?: error("Job is still new or active: $this")
405403
is Incomplete -> error("Job is still new or active: $this")
406404
is CompletedExceptionally -> state.cause.toCancellationException()
407405
else -> JobCancellationException("$classSimpleName has completed normally", null, this)
408406
}
409-
}
410407

411408
protected fun Throwable.toCancellationException(message: String? = null): CancellationException =
412409
this as? CancellationException ?:
@@ -747,8 +744,8 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
747744

748745
// try make new Cancelling state on the condition that we're still in the expected state
749746
private fun tryMakeCancelling(state: Incomplete, rootCause: Throwable): Boolean {
750-
check(state !is Finishing) // only for non-finishing states
751-
check(state.isActive) // only for active states
747+
assert { state !is Finishing } // only for non-finishing states
748+
assert { state.isActive } // only for active states
752749
// get state's list or else promote to list to correctly operate on child lists
753750
val list = getOrPromoteCancellingList(state) ?: return false
754751
// Create cancelling state (with rootCause!)
@@ -1037,8 +1034,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
10371034
// Seals current state and returns list of exceptions
10381035
// guarded by `synchronized(this)`
10391036
fun sealLocked(proposedException: Throwable?): List<Throwable> {
1040-
val eh = _exceptionsHolder // volatile read
1041-
val list = when(eh) {
1037+
val list = when(val eh = _exceptionsHolder) { // volatile read
10421038
null -> allocateList()
10431039
is Throwable -> allocateList().also { it.add(eh) }
10441040
is ArrayList<*> -> eh as ArrayList<Throwable>
@@ -1305,14 +1301,15 @@ internal class NodeList : LockFreeLinkedListHead(), Incomplete {
13051301
append("]")
13061302
}
13071303

1308-
override fun toString(): String = getString("Active")
1304+
override fun toString(): String =
1305+
if (DEBUG) getString("Active") else super.toString()
13091306
}
13101307

13111308
internal class InactiveNodeList(
13121309
override val list: NodeList
13131310
) : Incomplete {
13141311
override val isActive: Boolean get() = false
1315-
override fun toString(): String = list.getString("New")
1312+
override fun toString(): String = if (DEBUG) list.getString("New") else super.toString()
13161313
}
13171314

13181315
private class InvokeOnCompletion(
@@ -1337,7 +1334,7 @@ private class ResumeAwaitOnCompletion<T>(
13371334
) : JobNode<JobSupport>(job) {
13381335
override fun invoke(cause: Throwable?) {
13391336
val state = job.state
1340-
check(state !is Incomplete)
1337+
assert { state !is Incomplete }
13411338
if (state is CompletedExceptionally) {
13421339
// Resume with exception in atomic way to preserve exception
13431340
continuation.resumeWithExceptionMode(state.cause, MODE_ATOMIC_DEFAULT)

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines.channels
@@ -449,7 +449,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
449449
if (select.trySelect(idempotent)) SELECT_STARTED else null
450450

451451
override fun completeResumeSend(token: Any) {
452-
check(token === SELECT_STARTED)
452+
assert { token === SELECT_STARTED }
453453
block.startCoroutine(receiver = channel, completion = select.completion)
454454
}
455455

@@ -474,7 +474,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
474474
) : LockFreeLinkedListNode(), Send {
475475
override val pollResult: Any? get() = element
476476
override fun tryResumeSend(idempotent: Any?): Any? = SEND_RESUMED
477-
override fun completeResumeSend(token: Any) { check(token === SEND_RESUMED) }
477+
override fun completeResumeSend(token: Any) { assert { token === SEND_RESUMED } }
478478
override fun resumeSendClosed(closed: Closed<*>) {}
479479
}
480480
}
@@ -654,7 +654,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
654654
while (true) {
655655
val send = takeFirstSendOrPeekClosed() ?: error("Cannot happen")
656656
if (send is Closed<*>) {
657-
check(send === closed)
657+
assert { send === closed }
658658
return // cleaned
659659
}
660660
send.resumeSendClosed(closed)
@@ -1065,10 +1065,10 @@ internal class Closed<in E>(
10651065
override val offerResult get() = this
10661066
override val pollResult get() = this
10671067
override fun tryResumeSend(idempotent: Any?): Any? = CLOSE_RESUMED
1068-
override fun completeResumeSend(token: Any) { check(token === CLOSE_RESUMED) }
1068+
override fun completeResumeSend(token: Any) { assert { token === CLOSE_RESUMED } }
10691069
override fun tryResumeReceive(value: E, idempotent: Any?): Any? = CLOSE_RESUMED
1070-
override fun completeResumeReceive(token: Any) { check(token === CLOSE_RESUMED) }
1071-
override fun resumeSendClosed(closed: Closed<*>) = error("Should be never invoked")
1070+
override fun completeResumeReceive(token: Any) { assert { token === CLOSE_RESUMED } }
1071+
override fun resumeSendClosed(closed: Closed<*>) = assert { false } // "Should be never invoked"
10721072
override fun toString(): String = "Closed[$closeCause]"
10731073
}
10741074

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/*
2-
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines.channels
66

7+
import kotlinx.coroutines.*
78
import kotlinx.coroutines.internal.*
89
import kotlinx.coroutines.selects.*
910
import kotlin.jvm.*
@@ -94,7 +95,7 @@ internal open class ArrayChannel<E>(
9495
this.size = size // restore size
9596
receive = offerOp.result
9697
token = offerOp.resumeToken
97-
check(token != null)
98+
assert { token != null }
9899
return@withLock
99100
}
100101
failure === OFFER_FAILED -> break@loop // cannot offer -> Ok to queue to buffer
@@ -180,7 +181,7 @@ internal open class ArrayChannel<E>(
180181
failure == null -> { // polled successfully
181182
send = pollOp.result
182183
token = pollOp.resumeToken
183-
check(token != null)
184+
assert { token != null }
184185
replacement = send!!.pollResult
185186
break@loop
186187
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines.channels
@@ -142,7 +142,7 @@ public class ConflatedBroadcastChannel<E>() : BroadcastChannel<E> {
142142
private fun removeSubscriber(list: Array<Subscriber<E>>, subscriber: Subscriber<E>): Array<Subscriber<E>>? {
143143
val n = list.size
144144
val i = list.indexOf(subscriber)
145-
check(i >= 0)
145+
assert { i >= 0 }
146146
if (n == 1) return null
147147
val update = arrayOfNulls<Subscriber<E>>(n - 1)
148148
list.copyInto(

kotlinx-coroutines-core/common/src/flow/internal/ChannelFlow.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ public abstract class ChannelFlow<T>(
4242
capacity == Channel.CONFLATED -> Channel.CONFLATED
4343
else -> {
4444
// sanity checks
45-
check(this.capacity >= 0) { "Unexpected capacity ${this.capacity}" }
46-
check(capacity >= 0) { "Unexpected capacity $capacity" }
45+
assert { this.capacity >= 0 }
46+
assert { capacity >= 0 }
4747
// combine capacities clamping to UNLIMITED on overflow
4848
val sum = this.capacity + capacity
4949
if (sum >= 0) sum else Channel.UNLIMITED // unlimited on int overflow

kotlinx-coroutines-core/common/src/flow/operators/Merge.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ private class ChannelFlowMerge<T>(
167167
// Fast path in ChannelFlowOperator calls this function (channel was not created yet)
168168
override suspend fun flowCollect(collector: FlowCollector<T>) {
169169
// this function should not have been invoked when channel was explicitly requested
170-
check(capacity == OPTIONAL_CHANNEL)
170+
assert { capacity == OPTIONAL_CHANNEL }
171171
flowScope {
172172
mergeImpl(this, collector.asConcurrentFlowCollector())
173173
}

kotlinx-coroutines-core/common/src/internal/Atomic.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package kotlinx.coroutines.internal
66

77
import kotlinx.atomicfu.atomic
8+
import kotlinx.coroutines.*
89

910
/**
1011
* The most abstract operation that can be in process. Other threads observing an instance of this
@@ -40,7 +41,7 @@ public abstract class AtomicOp<in T> : OpDescriptor() {
4041
val isDecided: Boolean get() = _consensus.value !== NO_DECISION
4142

4243
fun tryDecide(decision: Any?): Boolean {
43-
check(decision !== NO_DECISION)
44+
assert { decision !== NO_DECISION }
4445
return _consensus.compareAndSet(NO_DECISION, decision)
4546
}
4647

kotlinx-coroutines-core/common/src/internal/SegmentQueue.kt

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
/*
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
15
package kotlinx.coroutines.internal
26

3-
import kotlinx.atomicfu.AtomicRef
4-
import kotlinx.atomicfu.atomic
5-
import kotlinx.atomicfu.loop
7+
import kotlinx.atomicfu.*
8+
import kotlinx.coroutines.*
69

710
/**
811
* Essentially, this segment queue is an infinite array of segments, which is represented as
@@ -133,7 +136,7 @@ internal abstract class Segment<S: Segment<S>>(val id: Long, prev: S?) {
133136
* logically removed (so [removed] returns `true`) at the point of invocation.
134137
*/
135138
fun remove() {
136-
check(removed) { " The segment should be logically removed at first "}
139+
assert { removed } // The segment should be logically removed at first
137140
// Read `next` and `prev` pointers.
138141
var next = this._next.value ?: return // tail cannot be removed
139142
var prev = prev.value ?: return // head cannot be removed

kotlinx-coroutines-core/common/src/selects/Select.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines.selects
@@ -234,7 +234,7 @@ internal class SelectBuilderImpl<in R>(
234234
override val completion: Continuation<R> get() = this
235235

236236
private inline fun doResume(value: () -> Any?, block: () -> Unit) {
237-
check(isSelected) { "Must be selected first" }
237+
assert { isSelected } // "Must be selected first"
238238
_result.loop { result ->
239239
when {
240240
result === UNDECIDED -> if (_result.compareAndSet(UNDECIDED, value())) return
@@ -343,7 +343,7 @@ internal class SelectBuilderImpl<in R>(
343343

344344
// it is just like start(), but support idempotent start
345345
override fun trySelect(idempotent: Any?): Boolean {
346-
check(idempotent !is OpDescriptor) { "cannot use OpDescriptor as idempotent marker"}
346+
assert { idempotent !is OpDescriptor } // "cannot use OpDescriptor as idempotent marker"
347347
while (true) { // lock-free loop on state
348348
val state = this.state
349349
when {

kotlinx-coroutines-core/common/src/sync/Mutex.kt

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines.sync
@@ -206,7 +206,7 @@ internal class MutexImpl(locked: Boolean) : Mutex, SelectClause2<Any?, Mutex> {
206206
is LockedQueue -> {
207207
val curOwner = state.owner
208208
check(curOwner !== owner) { "Already locked by $owner" }
209-
if (state.addLastIf(waiter, { _state.value === state })) {
209+
if (state.addLastIf(waiter) { _state.value === state }) {
210210
// added to waiter list!
211211
cont.removeOnCancellation(waiter)
212212
return@sc
@@ -226,8 +226,7 @@ internal class MutexImpl(locked: Boolean) : Mutex, SelectClause2<Any?, Mutex> {
226226
override fun <R> registerSelectClause2(select: SelectInstance<R>, owner: Any?, block: suspend (Mutex) -> R) {
227227
while (true) { // lock-free loop on state
228228
if (select.isSelected) return
229-
val state = _state.value
230-
when (state) {
229+
when (val state = _state.value) {
231230
is Empty -> {
232231
if (state.locked !== UNLOCKED) { // try upgrade to queue & retry
233232
_state.compareAndSet(state, LockedQueue(state.locked))
@@ -388,7 +387,7 @@ internal class MutexImpl(locked: Boolean) : Mutex, SelectClause2<Any?, Mutex> {
388387
) : LockWaiter(owner) {
389388
override fun tryResumeLockWaiter(): Any? = if (select.trySelect(null)) SELECT_SUCCESS else null
390389
override fun completeResumeLockWaiter(token: Any) {
391-
check(token === SELECT_SUCCESS)
390+
assert { token === SELECT_SUCCESS }
392391
block.startCoroutine(receiver = mutex, completion = select.completion)
393392
}
394393
override fun toString(): String = "LockSelect[$owner, $mutex, $select]"

kotlinx-coroutines-core/js/src/Debug.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
/*
2-
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines
66

77
private var counter = 0
88

9+
internal actual val DEBUG: Boolean = false
10+
911
internal actual val Any.hexAddress: String
1012
get() {
1113
var result = this.asDynamic().__debug_counter
@@ -18,3 +20,5 @@ internal actual val Any.hexAddress: String
1820
}
1921

2022
internal actual val Any.classSimpleName: String get() = this::class.simpleName ?: "Unknown"
23+
24+
internal actual inline fun assert(value: () -> Boolean) {}

kotlinx-coroutines-core/jvm/src/CoroutineContext.kt

-7
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,6 @@ import kotlinx.coroutines.scheduling.*
99
import java.util.concurrent.atomic.*
1010
import kotlin.coroutines.*
1111

12-
private val COROUTINE_ID = AtomicLong()
13-
14-
// for tests only
15-
internal fun resetCoroutineId() {
16-
COROUTINE_ID.set(0)
17-
}
18-
1912
internal const val COROUTINES_SCHEDULER_PROPERTY_NAME = "kotlinx.coroutines.scheduler"
2013

2114
internal val useCoroutinesScheduler = systemProp(COROUTINES_SCHEDULER_PROPERTY_NAME).let { value ->

0 commit comments

Comments
 (0)