Skip to content

Commit

Permalink
Formalize the internal IDEA dependencies for binary compatibility (#3746
Browse files Browse the repository at this point in the history
)

Using the list in the issue KTIJ-24102.
  • Loading branch information
dkhalanskyjb committed Jun 28, 2023
1 parent c485118 commit 5664713
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 62 deletions.
78 changes: 75 additions & 3 deletions kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public final class kotlinx/coroutines/CancellableContinuation$DefaultImpls {
public static synthetic fun tryResume$default (Lkotlinx/coroutines/CancellableContinuation;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;
}

public class kotlinx/coroutines/CancellableContinuationImpl : kotlin/coroutines/jvm/internal/CoroutineStackFrame, kotlinx/coroutines/CancellableContinuation, kotlinx/coroutines/Waiter {
public class kotlinx/coroutines/CancellableContinuationImpl : kotlinx/coroutines/DispatchedTask, kotlin/coroutines/jvm/internal/CoroutineStackFrame, kotlinx/coroutines/CancellableContinuation, kotlinx/coroutines/Waiter {
public fun <init> (Lkotlin/coroutines/Continuation;I)V
public final fun callCancelHandler (Lkotlinx/coroutines/CancelHandler;Ljava/lang/Throwable;)V
public final fun callOnCancellation (Lkotlin/jvm/functions/Function1;Ljava/lang/Throwable;)V
Expand Down Expand Up @@ -84,6 +84,13 @@ public final class kotlinx/coroutines/CancellableContinuationKt {
public static final fun suspendCancellableCoroutine (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class kotlinx/coroutines/ChildContinuation {
public final field child Lkotlinx/coroutines/CancellableContinuationImpl;
public fun <init> (Lkotlinx/coroutines/CancellableContinuationImpl;)V
public synthetic fun invoke (Ljava/lang/Object;)Ljava/lang/Object;
public fun invoke (Ljava/lang/Throwable;)V
}

public abstract interface class kotlinx/coroutines/ChildHandle : kotlinx/coroutines/DisposableHandle {
public abstract fun childCancelled (Ljava/lang/Throwable;)Z
public abstract fun getParent ()Lkotlinx/coroutines/Job;
Expand Down Expand Up @@ -200,6 +207,25 @@ public final class kotlinx/coroutines/CoroutineExceptionHandlerKt {
public static final fun handleCoroutineException (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Throwable;)V
}

public final class kotlinx/coroutines/CoroutineId : kotlin/coroutines/AbstractCoroutineContextElement, kotlinx/coroutines/ThreadContextElement {
public static final field Key Lkotlinx/coroutines/CoroutineId$Key;
public fun <init> (J)V
public final fun component1 ()J
public final fun copy (J)Lkotlinx/coroutines/CoroutineId;
public static synthetic fun copy$default (Lkotlinx/coroutines/CoroutineId;JILjava/lang/Object;)Lkotlinx/coroutines/CoroutineId;
public fun equals (Ljava/lang/Object;)Z
public final fun getId ()J
public fun hashCode ()I
public synthetic fun restoreThreadContext (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Object;)V
public fun restoreThreadContext (Lkotlin/coroutines/CoroutineContext;Ljava/lang/String;)V
public fun toString ()Ljava/lang/String;
public synthetic fun updateThreadContext (Lkotlin/coroutines/CoroutineContext;)Ljava/lang/Object;
public fun updateThreadContext (Lkotlin/coroutines/CoroutineContext;)Ljava/lang/String;
}

public final class kotlinx/coroutines/CoroutineId$Key : kotlin/coroutines/CoroutineContext$Key {
}

public final class kotlinx/coroutines/CoroutineName : kotlin/coroutines/AbstractCoroutineContextElement {
public static final field Key Lkotlinx/coroutines/CoroutineName$Key;
public fun <init> (Ljava/lang/String;)V
Expand Down Expand Up @@ -288,6 +314,15 @@ public final class kotlinx/coroutines/DelayKt {
public abstract interface annotation class kotlinx/coroutines/DelicateCoroutinesApi : java/lang/annotation/Annotation {
}

public final class kotlinx/coroutines/DispatchedCoroutine {
public static final fun get_decision$FU ()Ljava/util/concurrent/atomic/AtomicIntegerFieldUpdater;
}

public abstract class kotlinx/coroutines/DispatchedTask : kotlinx/coroutines/scheduling/Task {
public field resumeMode I
public final fun run ()V
}

public final class kotlinx/coroutines/DispatchedTaskKt {
public static final field MODE_CANCELLABLE I
}
Expand Down Expand Up @@ -877,9 +912,7 @@ public final class kotlinx/coroutines/channels/TickerMode : java/lang/Enum {
}

public final class kotlinx/coroutines/debug/internal/DebugCoroutineInfo {
public fun <init> (Lkotlinx/coroutines/debug/internal/DebugCoroutineInfoImpl;Lkotlin/coroutines/CoroutineContext;)V
public final fun getContext ()Lkotlin/coroutines/CoroutineContext;
public final fun getCreationStackBottom ()Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;
public final fun getCreationStackTrace ()Ljava/util/List;
public final fun getLastObservedFrame ()Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;
public final fun getLastObservedThread ()Ljava/lang/Thread;
Expand All @@ -888,6 +921,35 @@ public final class kotlinx/coroutines/debug/internal/DebugCoroutineInfo {
public final fun lastObservedStackTrace ()Ljava/util/List;
}

public final class kotlinx/coroutines/debug/internal/DebugCoroutineInfoImpl {
public field _lastObservedFrame Ljava/lang/ref/WeakReference;
public field _state Ljava/lang/String;
public field lastObservedThread Ljava/lang/Thread;
public final field sequenceNumber J
public final fun getContext ()Lkotlin/coroutines/CoroutineContext;
public final fun getCreationStackTrace ()Ljava/util/List;
public fun toString ()Ljava/lang/String;
}

public final class kotlinx/coroutines/debug/internal/DebugProbesImpl {
public static final field INSTANCE Lkotlinx/coroutines/debug/internal/DebugProbesImpl;
public final fun dumpCoroutinesInfo ()Ljava/util/List;
public final fun dumpCoroutinesInfoAsJsonAndReferences ()[Ljava/lang/Object;
public final fun dumpDebuggerInfo ()Ljava/util/List;
public final fun enhanceStackTraceWithThreadDump (Lkotlinx/coroutines/debug/internal/DebugCoroutineInfo;Ljava/util/List;)Ljava/util/List;
public final fun enhanceStackTraceWithThreadDumpAsJson (Lkotlinx/coroutines/debug/internal/DebugCoroutineInfo;)Ljava/lang/String;
public final fun isInstalled ()Z
}

public final class kotlinx/coroutines/debug/internal/DebugProbesImpl$CoroutineOwner : kotlin/coroutines/Continuation, kotlin/coroutines/jvm/internal/CoroutineStackFrame {
public final field info Lkotlinx/coroutines/debug/internal/DebugCoroutineInfoImpl;
public fun getCallerFrame ()Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;
public fun getContext ()Lkotlin/coroutines/CoroutineContext;
public fun getStackTraceElement ()Ljava/lang/StackTraceElement;
public fun resumeWith (Ljava/lang/Object;)V
public fun toString ()Ljava/lang/String;
}

public final class kotlinx/coroutines/debug/internal/DebuggerInfo : java/io/Serializable {
public fun <init> (Lkotlinx/coroutines/debug/internal/DebugCoroutineInfoImpl;Lkotlin/coroutines/CoroutineContext;)V
public final fun getCoroutineId ()Ljava/lang/Long;
Expand All @@ -900,6 +962,12 @@ public final class kotlinx/coroutines/debug/internal/DebuggerInfo : java/io/Seri
public final fun getState ()Ljava/lang/String;
}

public final class kotlinx/coroutines/debug/internal/StackTraceFrame : kotlin/coroutines/jvm/internal/CoroutineStackFrame {
public final field stackTraceElement Ljava/lang/StackTraceElement;
public fun getCallerFrame ()Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;
public fun getStackTraceElement ()Ljava/lang/StackTraceElement;
}

public abstract class kotlinx/coroutines/flow/AbstractFlow : kotlinx/coroutines/flow/CancellableFlow, kotlinx/coroutines/flow/Flow {
public fun <init> ()V
public final fun collect (Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Expand Down Expand Up @@ -1210,6 +1278,10 @@ public class kotlinx/coroutines/scheduling/ExperimentalCoroutineDispatcher : kot
public fun toString ()Ljava/lang/String;
}

public abstract class kotlinx/coroutines/scheduling/Task : java/lang/Runnable {
public field submissionTime J
}

public final class kotlinx/coroutines/selects/OnTimeoutKt {
public static final fun onTimeout (Lkotlinx/coroutines/selects/SelectBuilder;JLkotlin/jvm/functions/Function1;)V
public static final fun onTimeout-8Mi8wO0 (Lkotlinx/coroutines/selects/SelectBuilder;JLkotlin/jvm/functions/Function1;)V
Expand Down
9 changes: 6 additions & 3 deletions kotlinx-coroutines-core/common/src/Builders.common.kt
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,16 @@ private const val SUSPENDED = 1
private const val RESUMED = 2

// Used by withContext when context dispatcher changes
internal class DispatchedCoroutine<in T>(
@PublishedApi
internal class DispatchedCoroutine<in T> internal constructor(
context: CoroutineContext,
uCont: Continuation<T>
) : ScopeCoroutine<T>(context, uCont) {
// this is copy-and-paste of a decision state machine inside AbstractionContinuation
// todo: we may some-how abstract it via inline class
private val _decision = atomic(UNDECIDED)
// Used by the IDEA debugger via reflection and must be kept binary-compatible, see KTIJ-24102
@JvmField
public val _decision = atomic(UNDECIDED)

private fun trySuspend(): Boolean {
_decision.loop { decision ->
Expand Down Expand Up @@ -258,7 +261,7 @@ internal class DispatchedCoroutine<in T>(
uCont.intercepted().resumeCancellableWith(recoverResult(state, uCont))
}

fun getResult(): Any? {
internal fun getResult(): Any? {
if (trySuspend()) return COROUTINE_SUSPENDED
// otherwise, onCompletionInternal was already invoked & invoked tryResume, and the result is in the state
val state = this.state.unboxState()
Expand Down
3 changes: 3 additions & 0 deletions kotlinx-coroutines-core/common/src/JobSupport.kt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
*/

// Note: use shared objects while we have no listeners
// Used by the IDEA debugger via reflection and must be kept binary-compatible, see KTIJ-24102
private val _state = atomic<Any?>(if (active) EMPTY_ACTIVE else EMPTY_NEW)

private val _parentHandle = atomic<ChildHandle?>(null)
Expand Down Expand Up @@ -1440,7 +1441,9 @@ internal class ChildHandleNode(
}

// Same as ChildHandleNode, but for cancellable continuation
@PublishedApi
internal class ChildContinuation(
// Used by the IDEA debugger via reflection and must be kept binary-compatible, see KTIJ-24102
@JvmField val child: CancellableContinuationImpl<*>
) : JobCancellingNode() {
override fun invoke(cause: Throwable?) {
Expand Down
2 changes: 1 addition & 1 deletion kotlinx-coroutines-core/common/src/SchedulerTask.common.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

package kotlinx.coroutines

internal expect abstract class SchedulerTask() : Runnable
internal expect abstract class SchedulerTask internal constructor() : Runnable

internal expect interface SchedulerTaskContext

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ private val UNDEFINED = Symbol("UNDEFINED")
@JvmField
internal val REUSABLE_CLAIMED = Symbol("REUSABLE_CLAIMED")

@PublishedApi
internal class DispatchedContinuation<in T>(
@JvmField val dispatcher: CoroutineDispatcher,
@JvmField internal val dispatcher: CoroutineDispatcher,
// Used by the IDEA debugger via reflection and must be kept binary-compatible, see KTIJ-24102
@JvmField val continuation: Continuation<T>
) : DispatchedTask<T>(MODE_UNINITIALIZED), CoroutineStackFrame, Continuation<T> by continuation {
@JvmField
Expand Down Expand Up @@ -58,7 +60,7 @@ internal class DispatchedContinuation<in T>(
private val reusableCancellableContinuation: CancellableContinuationImpl<*>?
get() = _reusableCancellableContinuation.value as? CancellableContinuationImpl<*>

fun isReusable(): Boolean {
internal fun isReusable(): Boolean {
/*
Invariant: caller.resumeMode.isReusableMode
* Reusability control:
Expand All @@ -72,13 +74,13 @@ internal class DispatchedContinuation<in T>(
* Awaits until previous call to `suspendCancellableCoroutineReusable` will
* stop mutating cached instance
*/
fun awaitReusability() {
internal fun awaitReusability() {
_reusableCancellableContinuation.loop {
if (it !== REUSABLE_CLAIMED) return
}
}

fun release() {
internal fun release() {
/*
* Called from `releaseInterceptedContinuation`, can be concurrent with
* the code in `getResult` right after `trySuspend` returned `true`, so we have
Expand All @@ -93,7 +95,7 @@ internal class DispatchedContinuation<in T>(
* so all cancellations will be postponed.
*/
@Suppress("UNCHECKED_CAST")
fun claimReusableCancellableContinuation(): CancellableContinuationImpl<T>? {
internal fun claimReusableCancellableContinuation(): CancellableContinuationImpl<T>? {
/*
* Transitions:
* 1) `null` -> claimed, caller will instantiate CC instance
Expand Down Expand Up @@ -142,7 +144,7 @@ internal class DispatchedContinuation<in T>(
*
* See [CancellableContinuationImpl.getResult].
*/
fun tryReleaseClaimedContinuation(continuation: CancellableContinuation<*>): Throwable? {
internal fun tryReleaseClaimedContinuation(continuation: CancellableContinuation<*>): Throwable? {
_reusableCancellableContinuation.loop { state ->
// not when(state) to avoid Intrinsics.equals call
when {
Expand All @@ -162,7 +164,7 @@ internal class DispatchedContinuation<in T>(
* Tries to postpone cancellation if reusable CC is currently in [REUSABLE_CLAIMED] state.
* Returns `true` if cancellation is (or previously was) postponed, `false` otherwise.
*/
fun postponeCancellation(cause: Throwable): Boolean {
internal fun postponeCancellation(cause: Throwable): Boolean {
_reusableCancellableContinuation.loop { state ->
when (state) {
REUSABLE_CLAIMED -> {
Expand Down Expand Up @@ -208,7 +210,7 @@ internal class DispatchedContinuation<in T>(
// We inline it to save an entry on the stack in cases where it shows (unconfined dispatcher)
// It is used only in Continuation<T>.resumeCancellableWith
@Suppress("NOTHING_TO_INLINE")
inline fun resumeCancellableWith(
internal inline fun resumeCancellableWith(
result: Result<T>,
noinline onCancellation: ((cause: Throwable) -> Unit)?
) {
Expand Down Expand Up @@ -237,7 +239,7 @@ internal class DispatchedContinuation<in T>(

// inline here is to save us an entry on the stack for the sake of better stacktraces
@Suppress("NOTHING_TO_INLINE")
inline fun resumeCancelled(state: Any?): Boolean {
internal inline fun resumeCancelled(state: Any?): Boolean {
val job = context[Job]
if (job != null && !job.isActive) {
val cause = job.getCancellationException()
Expand All @@ -249,7 +251,7 @@ internal class DispatchedContinuation<in T>(
}

@Suppress("NOTHING_TO_INLINE")
inline fun resumeUndispatchedWith(result: Result<T>) {
internal inline fun resumeUndispatchedWith(result: Result<T>) {
withContinuationContext(continuation, countOrElement) {
continuation.resumeWith(result)
}
Expand Down
8 changes: 5 additions & 3 deletions kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ internal const val MODE_UNINITIALIZED = -1
internal val Int.isCancellableMode get() = this == MODE_CANCELLABLE || this == MODE_CANCELLABLE_REUSABLE
internal val Int.isReusableMode get() = this == MODE_CANCELLABLE_REUSABLE

internal abstract class DispatchedTask<in T>(
@PublishedApi
internal abstract class DispatchedTask<in T> internal constructor(
// Used by the IDEA debugger via reflection and must be kept binary-compatible, see KTIJ-24102
@JvmField public var resumeMode: Int
) : SchedulerTask() {
internal abstract val delegate: Continuation<T>
Expand Down Expand Up @@ -78,7 +80,7 @@ internal abstract class DispatchedTask<in T>(
internal open fun getExceptionalResult(state: Any?): Throwable? =
(state as? CompletedExceptionally)?.cause

public final override fun run() {
final override fun run() {
assert { resumeMode != MODE_UNINITIALIZED } // should have been set before dispatching
val taskContext = this.taskContext
var fatalException: Throwable? = null
Expand Down Expand Up @@ -134,7 +136,7 @@ internal abstract class DispatchedTask<in T>(
* Fatal exception handling can be intercepted with [CoroutineExceptionHandler] element in the context of
* a failed coroutine, but such exceptions should be reported anyway.
*/
public fun handleFatalException(exception: Throwable?, finallyException: Throwable?) {
internal fun handleFatalException(exception: Throwable?, finallyException: Throwable?) {
if (exception === null && finallyException === null) return
if (exception !== null && finallyException !== null) {
exception.addSuppressedThrowable(finallyException)
Expand Down
3 changes: 3 additions & 0 deletions kotlinx-coroutines-core/jvm/src/CoroutineContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,12 @@ internal actual val CoroutineContext.coroutineName: String? get() {
private const val DEBUG_THREAD_NAME_SEPARATOR = " @"

@IgnoreJreRequirement // desugared hashcode implementation
@PublishedApi
internal data class CoroutineId(
// Used by the IDEA debugger via reflection and must be kept binary-compatible, see KTIJ-24102
val id: Long
) : ThreadContextElement<String>, AbstractCoroutineContextElement(CoroutineId) {
// Used by the IDEA debugger via reflection and must be kept binary-compatible, see KTIJ-24102
companion object Key : CoroutineContext.Key<CoroutineId>
override fun toString(): String = "CoroutineId($id)"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import kotlin.coroutines.jvm.internal.*
*/
@Suppress("unused")
@PublishedApi
internal class DebugCoroutineInfo(
internal class DebugCoroutineInfo internal constructor(
source: DebugCoroutineInfoImpl,
public val context: CoroutineContext // field is used as of 1.4-M3
) {
public val creationStackBottom: CoroutineStackFrame? = source.creationStackBottom // field is used as of 1.4-M3
internal val creationStackBottom: CoroutineStackFrame? = source.creationStackBottom // field is used as of 1.4-M3
public val sequenceNumber: Long = source.sequenceNumber // field is used as of 1.4-M3
public val creationStackTrace = source.creationStackTrace // getter is used as of 1.4-M3
public val state: String = source.state // getter is used as of 1.4-M3
Expand Down
Loading

0 comments on commit 5664713

Please sign in to comment.