Refine dispatching convention

Dispatching happens only via `suspendWithCurrentContinuation` calls
instead of each `resume` call

 #KT-15657 Fixed
This commit is contained in:
Denis Zharkov
2017-01-11 20:22:26 +03:00
parent 0240ab0738
commit d487c1ef0f
6 changed files with 81 additions and 29 deletions
@@ -19,41 +19,25 @@ package kotlin.jvm.internal
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.SUSPENDED_MARKER
private const val INTERCEPT_BIT_SET = 1 shl 31
private const val INTERCEPT_BIT_CLEAR = INTERCEPT_BIT_SET.inv()
abstract class CoroutineImpl : RestrictedCoroutineImpl, DispatchedContinuation<Any?> {
private val _dispatcher: ContinuationDispatcher?
override val dispatcher: ContinuationDispatcher?
get() = _dispatcher
private var facade_: Continuation<Any?>? = null
val facade: Continuation<Any?> get() {
if (facade_ == null) {
facade_ = wrapContinuationIfNeeded(this, dispatcher)
}
return facade_!!
}
// this constructor is used to create a continuation instance for coroutine
constructor(arity: Int, completion: Continuation<Any?>?) : super(arity, completion) {
_dispatcher = (completion as? DispatchedContinuation<*>)?.dispatcher
}
override fun resume(value: Any?) {
if (_dispatcher != null) {
if (label and INTERCEPT_BIT_SET == 0) {
label = label or INTERCEPT_BIT_SET
if (_dispatcher.dispatchResume(value, this)) return
}
label = label and INTERCEPT_BIT_CLEAR
}
super.resume(value)
}
override fun resumeWithException(exception: Throwable) {
if (_dispatcher != null) {
if (label and INTERCEPT_BIT_SET == 0) {
label = label or INTERCEPT_BIT_SET
if (_dispatcher.dispatchResumeWithException(exception, this)) return
}
label = label and INTERCEPT_BIT_CLEAR
}
super.resumeWithException(exception)
}
}
abstract class RestrictedCoroutineImpl : Lambda, Continuation<Any?> {
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:kotlin.jvm.JvmName("CoroutineIntrinsics")
package kotlin.jvm.internal
import kotlin.coroutines.Continuation
import kotlin.coroutines.ContinuationDispatcher
fun <T> normalizeContinuation(c: Continuation<T>): Continuation<T> {
if (c is CoroutineImpl) {
return c.facade
}
return c
}
internal fun <T> wrapContinuationIfNeeded(c: Continuation<T>, dispatcher: ContinuationDispatcher?): Continuation<T> {
if (dispatcher == null) return c
return DispatchedContinuationImpl(c, dispatcher)
}
private class DispatchedContinuationImpl<in T>(
private val c: Continuation<T>,
private val dispatcher: ContinuationDispatcher
) : Continuation<T> {
override fun resume(value: T) {
if (!dispatcher.dispatchResume(value, c)) {
c.resume(value)
}
}
override fun resumeWithException(exception: Throwable) {
if (!dispatcher.dispatchResumeWithException(exception, c)) {
c.resumeWithException(exception)
}
}
}