Skip to content

Commit 1fc01e7

Browse files
authored
Replace hand-rolled ArrayQueue with ArrayDeque in standard library in … (#3438)
* Reduce hand-rolled ArrayQueue with ArrayDeque in standard library in order to (potentially) reduce dex size
1 parent 4e97c83 commit 1fc01e7

File tree

5 files changed

+32
-86
lines changed

5 files changed

+32
-86
lines changed

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

+16-17
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ internal abstract class EventLoop : CoroutineDispatcher() {
3636
* Queue used by [Dispatchers.Unconfined] tasks.
3737
* These tasks are thread-local for performance and take precedence over the rest of the queue.
3838
*/
39-
private var unconfinedQueue: ArrayQueue<DispatchedTask<*>>? = null
39+
private var unconfinedQueue: ArrayDeque<DispatchedTask<*>>? = null
4040

4141
/**
4242
* Processes next event in this event loop.
@@ -49,7 +49,7 @@ internal abstract class EventLoop : CoroutineDispatcher() {
4949
* **NOTE**: Must be invoked only from the event loop's thread
5050
* (no check for performance reasons, may be added in the future).
5151
*/
52-
public open fun processNextEvent(): Long {
52+
open fun processNextEvent(): Long {
5353
if (!processUnconfinedEvent()) return Long.MAX_VALUE
5454
return 0
5555
}
@@ -59,10 +59,10 @@ internal abstract class EventLoop : CoroutineDispatcher() {
5959
protected open val nextTime: Long
6060
get() {
6161
val queue = unconfinedQueue ?: return Long.MAX_VALUE
62-
return if (queue.isEmpty) Long.MAX_VALUE else 0L
62+
return if (queue.isEmpty()) Long.MAX_VALUE else 0L
6363
}
6464

65-
public fun processUnconfinedEvent(): Boolean {
65+
fun processUnconfinedEvent(): Boolean {
6666
val queue = unconfinedQueue ?: return false
6767
val task = queue.removeFirstOrNull() ?: return false
6868
task.run()
@@ -74,27 +74,27 @@ internal abstract class EventLoop : CoroutineDispatcher() {
7474
* By default, event loop implementation is thread-local and should not processed in the context
7575
* (current thread's event loop should be processed instead).
7676
*/
77-
public open fun shouldBeProcessedFromContext(): Boolean = false
77+
open fun shouldBeProcessedFromContext(): Boolean = false
7878

7979
/**
8080
* Dispatches task whose dispatcher returned `false` from [CoroutineDispatcher.isDispatchNeeded]
8181
* into the current event loop.
8282
*/
83-
public fun dispatchUnconfined(task: DispatchedTask<*>) {
83+
fun dispatchUnconfined(task: DispatchedTask<*>) {
8484
val queue = unconfinedQueue ?:
85-
ArrayQueue<DispatchedTask<*>>().also { unconfinedQueue = it }
85+
ArrayDeque<DispatchedTask<*>>().also { unconfinedQueue = it }
8686
queue.addLast(task)
8787
}
8888

89-
public val isActive: Boolean
89+
val isActive: Boolean
9090
get() = useCount > 0
9191

92-
public val isUnconfinedLoopActive: Boolean
92+
val isUnconfinedLoopActive: Boolean
9393
get() = useCount >= delta(unconfined = true)
9494

9595
// May only be used from the event loop's thread
96-
public val isUnconfinedQueueEmpty: Boolean
97-
get() = unconfinedQueue?.isEmpty ?: true
96+
val isUnconfinedQueueEmpty: Boolean
97+
get() = unconfinedQueue?.isEmpty() ?: true
9898

9999
private fun delta(unconfined: Boolean) =
100100
if (unconfined) (1L shl 32) else 1L
@@ -200,7 +200,7 @@ internal abstract class EventLoopImplBase: EventLoopImplPlatform(), Delay {
200200
}
201201
}
202202

203-
protected override val nextTime: Long
203+
override val nextTime: Long
204204
get() {
205205
if (super.nextTime == 0L) return 0L
206206
val queue = _queue.value
@@ -227,7 +227,7 @@ internal abstract class EventLoopImplBase: EventLoopImplPlatform(), Delay {
227227
rescheduleAllDelayed()
228228
}
229229

230-
public override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
230+
override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
231231
val timeNanos = delayToNanos(timeMillis)
232232
if (timeNanos < MAX_DELAY_NS) {
233233
val now = nanoTime()
@@ -283,7 +283,7 @@ internal abstract class EventLoopImplBase: EventLoopImplPlatform(), Delay {
283283
return nextTime
284284
}
285285

286-
public final override fun dispatch(context: CoroutineContext, block: Runnable) = enqueue(block)
286+
final override fun dispatch(context: CoroutineContext, block: Runnable) = enqueue(block)
287287

288288
open fun enqueue(task: Runnable) {
289289
if (enqueueImpl(task)) {
@@ -362,7 +362,7 @@ internal abstract class EventLoopImplBase: EventLoopImplPlatform(), Delay {
362362

363363
}
364364

365-
public fun schedule(now: Long, delayedTask: DelayedTask) {
365+
fun schedule(now: Long, delayedTask: DelayedTask) {
366366
when (scheduleImpl(now, delayedTask)) {
367367
SCHEDULE_OK -> if (shouldUnpark(delayedTask)) unpark()
368368
SCHEDULE_COMPLETED -> reschedule(now, delayedTask)
@@ -481,7 +481,6 @@ internal abstract class EventLoopImplBase: EventLoopImplPlatform(), Delay {
481481
final override fun dispose() {
482482
val heap = _heap
483483
if (heap === DISPOSED_TASK) return // already disposed
484-
@Suppress("UNCHECKED_CAST")
485484
(heap as? DelayedTaskQueue)?.remove(this) // remove if it is in heap (first)
486485
_heap = DISPOSED_TASK // never add again to any heap
487486
}
@@ -530,7 +529,7 @@ internal expect fun createEventLoop(): EventLoop
530529
internal expect fun nanoTime(): Long
531530

532531
internal expect object DefaultExecutor {
533-
public fun enqueue(task: Runnable)
532+
fun enqueue(task: Runnable)
534533
}
535534

536535
/**

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

-52
This file was deleted.

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ private class WindowMessageQueue(private val window: Window) : MessageQueue() {
131131
*
132132
* Yet there could be a long tail of "slow" reschedules, but it should be amortized by the queue size.
133133
*/
134-
internal abstract class MessageQueue : ArrayQueue<Runnable>() {
134+
internal abstract class MessageQueue : MutableList<Runnable> by ArrayDeque() {
135135
val yieldEvery = 16 // yield to JS macrotask event loop after this many processed messages
136136
private var scheduled = false
137137

@@ -140,7 +140,7 @@ internal abstract class MessageQueue : ArrayQueue<Runnable>() {
140140
abstract fun reschedule()
141141

142142
fun enqueue(element: Runnable) {
143-
addLast(element)
143+
add(element)
144144
if (!scheduled) {
145145
scheduled = true
146146
schedule()
@@ -155,7 +155,7 @@ internal abstract class MessageQueue : ArrayQueue<Runnable>() {
155155
element.run()
156156
}
157157
} finally {
158-
if (isEmpty) {
158+
if (isEmpty()) {
159159
scheduled = false
160160
} else {
161161
reschedule()

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
package kotlinx.coroutines
66

7-
import kotlinx.coroutines.internal.*
87
import org.w3c.dom.Window
98

109
/**
@@ -35,8 +34,8 @@ private fun Window.asWindowAnimationQueue(): WindowAnimationQueue =
3534
private class WindowAnimationQueue(private val window: Window) {
3635
private val dispatcher = window.asCoroutineDispatcher()
3736
private var scheduled = false
38-
private var current = ArrayQueue<CancellableContinuation<Double>>()
39-
private var next = ArrayQueue<CancellableContinuation<Double>>()
37+
private var current = ArrayDeque<CancellableContinuation<Double>>()
38+
private var next = ArrayDeque<CancellableContinuation<Double>>()
4039
private var timestamp = 0.0
4140

4241
fun enqueue(cont: CancellableContinuation<Double>) {

kotlinx-coroutines-core/js/test/MessageQueueTest.kt

+11-11
Original file line numberDiff line numberDiff line change
@@ -36,41 +36,41 @@ class MessageQueueTest {
3636

3737
@Test
3838
fun testBasic() {
39-
assertTrue(queue.isEmpty)
39+
assertTrue(queue.isEmpty())
4040
queue.enqueue(Box(1))
41-
assertFalse(queue.isEmpty)
41+
assertFalse(queue.isEmpty())
4242
assertTrue(scheduled)
4343
queue.enqueue(Box(2))
44-
assertFalse(queue.isEmpty)
44+
assertFalse(queue.isEmpty())
4545
scheduled = false
4646
queue.process()
4747
assertEquals(listOf(1, 2), processed)
4848
assertFalse(scheduled)
49-
assertTrue(queue.isEmpty)
49+
assertTrue(queue.isEmpty())
5050
}
5151

5252
@Test fun testRescheduleFromProcess() {
53-
assertTrue(queue.isEmpty)
53+
assertTrue(queue.isEmpty())
5454
queue.enqueue(ReBox(1))
55-
assertFalse(queue.isEmpty)
55+
assertFalse(queue.isEmpty())
5656
assertTrue(scheduled)
5757
queue.enqueue(ReBox(2))
58-
assertFalse(queue.isEmpty)
58+
assertFalse(queue.isEmpty())
5959
scheduled = false
6060
queue.process()
6161
assertEquals(listOf(1, 2, 11, 12), processed)
6262
assertFalse(scheduled)
63-
assertTrue(queue.isEmpty)
63+
assertTrue(queue.isEmpty())
6464
}
6565

6666
@Test
6767
fun testResizeAndWrap() {
6868
repeat(10) { phase ->
6969
val n = 10 * (phase + 1)
70-
assertTrue(queue.isEmpty)
70+
assertTrue(queue.isEmpty())
7171
repeat(n) {
7272
queue.enqueue(Box(it))
73-
assertFalse(queue.isEmpty)
73+
assertFalse(queue.isEmpty())
7474
assertTrue(scheduled)
7575
}
7676
var countYields = 0
@@ -84,4 +84,4 @@ class MessageQueueTest {
8484
processed.clear()
8585
}
8686
}
87-
}
87+
}

0 commit comments

Comments
 (0)