diff --git a/kotlin-native/runtime/src/main/cpp/Atomic.cpp b/kotlin-native/runtime/src/main/cpp/Atomic.cpp deleted file mode 100644 index b02ffbbbfd7..00000000000 --- a/kotlin-native/runtime/src/main/cpp/Atomic.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2010-2018 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. - */ - -#include "Atomic.h" -#include "Common.h" -#include "Exceptions.h" -#include "Memory.h" -#include "Types.h" - -namespace { - -struct AtomicReferenceLayout { - ObjHeader header; - KRef value_; - KInt lock_; - KInt cookie_; -}; - -inline AtomicReferenceLayout* asAtomicReference(KRef thiz) { - return reinterpret_cast(thiz); -} - -} // namespace - -extern "C" { - - - -void Kotlin_AtomicReference_checkIfFrozen(KRef value) { - if (!kotlin::compiler::freezingEnabled()) { - return; - } - if (value != nullptr && !isPermanentOrFrozen(value)) { - ThrowInvalidMutabilityException(value); - } -} - -OBJ_GETTER(Kotlin_AtomicReference_compareAndSwap, KRef thiz, KRef expectedValue, KRef newValue) { - if (isPermanentOrFrozen(thiz)) { - Kotlin_AtomicReference_checkIfFrozen(newValue); - } - // See Kotlin_AtomicReference_get() for explanations, why locking is needed. - AtomicReferenceLayout* ref = asAtomicReference(thiz); - RETURN_RESULT_OF(SwapHeapRefLocked, &ref->value_, expectedValue, newValue, - &ref->lock_, &ref->cookie_); -} - -KBoolean Kotlin_AtomicReference_compareAndSet(KRef thiz, KRef expectedValue, KRef newValue) { - if (isPermanentOrFrozen(thiz)) { - Kotlin_AtomicReference_checkIfFrozen(newValue); - } - // See Kotlin_AtomicReference_get() for explanations, why locking is needed. - AtomicReferenceLayout* ref = asAtomicReference(thiz); - ObjHolder holder; - auto old = SwapHeapRefLocked(&ref->value_, expectedValue, newValue, - &ref->lock_, &ref->cookie_, holder.slot()); - return old == expectedValue; -} - -void Kotlin_AtomicReference_set(KRef thiz, KRef newValue) { - if (isPermanentOrFrozen(thiz)) { - Kotlin_AtomicReference_checkIfFrozen(newValue); - } - AtomicReferenceLayout* ref = asAtomicReference(thiz); - SetHeapRefLocked(&ref->value_, newValue, &ref->lock_, &ref->cookie_); -} - -OBJ_GETTER(Kotlin_AtomicReference_get, KRef thiz) { - // Here we must take a lock to prevent race when value, while taken here, is CASed and immediately - // destroyed by an another thread. AtomicReference no longer holds such an object, so if we got - // rescheduled unluckily, between the moment value is read from the field and RC is incremented, - // object may go away. - AtomicReferenceLayout* ref = asAtomicReference(thiz); - RETURN_RESULT_OF(ReadHeapRefLocked, &ref->value_, &ref->lock_, &ref->cookie_); -} - -} // extern "C" diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/Lazy.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/Lazy.kt index 9de68adc48c..220e5d1e447 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/Lazy.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/Lazy.kt @@ -19,11 +19,7 @@ import kotlin.native.isExperimentalMM * the returned instance as it may cause accidental deadlock. Also this behavior can be changed in the future. */ @OptIn(kotlin.ExperimentalStdlibApi::class, FreezingIsDeprecated::class) -public actual fun lazy(initializer: () -> T): Lazy = - if (isExperimentalMM()) - SynchronizedLazyImpl(initializer) - else - FreezeAwareLazyImpl(initializer) +public actual fun lazy(initializer: () -> T): Lazy = SynchronizedLazyImpl(initializer) /** @@ -39,8 +35,8 @@ public actual fun lazy(initializer: () -> T): Lazy = @OptIn(kotlin.ExperimentalStdlibApi::class, FreezingIsDeprecated::class) public actual fun lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy = when (mode) { - LazyThreadSafetyMode.SYNCHRONIZED -> if (isExperimentalMM()) SynchronizedLazyImpl(initializer) else throw UnsupportedOperationException() - LazyThreadSafetyMode.PUBLICATION -> if (isExperimentalMM()) SafePublicationLazyImpl(initializer) else FreezeAwareLazyImpl(initializer) + LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer) + LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer) LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer) } diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/concurrent/Atomics.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/concurrent/Atomics.kt index a7a330c5ce7..360e204785b 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/concurrent/Atomics.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/concurrent/Atomics.kt @@ -15,13 +15,7 @@ import kotlin.native.concurrent.* /** * An [Int] value that is always updated atomically. * For additional details about atomicity guarantees for reads and writes see [kotlin.concurrent.Volatile]. - * - * Legacy MM: Atomic values and freezing: this type is unique with regard to freezing. - * Namely, it provides mutating operations, while can participate in frozen subgraphs. - * So shared frozen objects can have mutable fields of [AtomicInt] type. */ -@Frozen -@OptIn(FreezingIsDeprecated::class, ExperimentalStdlibApi::class) @SinceKotlin("1.9") public class AtomicInt(@Volatile public var value: Int) { /** @@ -103,12 +97,7 @@ public class AtomicInt(@Volatile public var value: Int) { * A [Long] value that is always updated atomically. * For additional details about atomicity guarantees for reads and writes see [kotlin.concurrent.Volatile]. * - * Legacy MM: Atomic values and freezing: this type is unique with regard to freezing. - * Namely, it provides mutating operations, while can participate in frozen subgraphs. - * So shared frozen objects can have mutable fields of [AtomicLong] type. */ -@Frozen -@OptIn(FreezingIsDeprecated::class, ExperimentalStdlibApi::class) @SinceKotlin("1.9") public class AtomicLong(@Volatile public var value: Long) { /** @@ -194,64 +183,15 @@ public class AtomicLong(@Volatile public var value: Long) { /** * An object reference that is always updated atomically. - * - * Legacy MM: An atomic reference to a frozen Kotlin object. Can be used in concurrent scenarious - * but frequently shall be of nullable type and be zeroed out once no longer needed. - * Otherwise memory leak could happen. To detect such leaks [kotlin.native.internal.GC.detectCycles] - * in debug mode could be helpful. */ -@FrozenLegacyMM -@LeakDetectorCandidate -@NoReorderFields @OptIn(FreezingIsDeprecated::class) @SinceKotlin("1.9") -public class AtomicReference { - private var value_: T - - // A spinlock to fix potential ARC race. - private var lock: Int = 0 - - // Optimization for speeding up access. - private var cookie: Int = 0 - - /** - * Creates a new atomic reference pointing to the [given value][value]. - * - * @throws InvalidMutabilityException with legacy MM if reference is not frozen. - */ - constructor(value: T) { - if (this.isFrozen) { - checkIfFrozen(value) - } - value_ = value - } - - /** - * The current value. - * Gets the current value or sets to the given [new value][newValue]. - * - * Legacy MM: if the [new value][newValue] value is not null, it must be frozen or permanent object. - * - * @throws InvalidMutabilityException with legacy MM if the value is not frozen or a permanent object - */ - public var value: T - get() = @Suppress("UNCHECKED_CAST")(getImpl() as T) - set(newValue) = setImpl(newValue) +public class AtomicReference(public @Volatile var value: T) { /** * Atomically sets the value to the given [new value][newValue] and returns the old value. */ - public fun getAndSet(newValue: T): T { - while (true) { - val old = value - if (old === newValue) { - return old - } - if (compareAndSet(old, newValue)) { - return old - } - } - } + public fun getAndSet(newValue: T): T = this::value.getAndSetField(newValue) /** * Atomically sets the value to the given [new value][newValue] if the current value equals the [expected value][expected], @@ -261,8 +201,7 @@ public class AtomicReference { * * Comparison of values is done by reference. */ - @GCUnsafeCall("Kotlin_AtomicReference_compareAndSet") - external public fun compareAndSet(expected: T, newValue: T): Boolean + public fun compareAndSet(expected: T, newValue: T): Boolean = this::value.compareAndSetField(expected, newValue) /** * Atomically sets the value to the given [new value][newValue] if the current value equals the [expected value][expected] @@ -271,26 +210,14 @@ public class AtomicReference { * Provides sequential consistent ordering guarantees and cannot fail spuriously. * * Comparison of values is done by reference. - * - * Legacy MM: if the [new value][newValue] value is not null, it must be frozen or permanent object. - * - * @throws InvalidMutabilityException with legacy MM if the value is not frozen or a permanent object */ - @GCUnsafeCall("Kotlin_AtomicReference_compareAndSwap") - external public fun compareAndExchange(expected: T, newValue: T): T + public fun compareAndExchange(expected: T, newValue: T): T = this::value.compareAndExchangeField(expected, newValue) /** * Returns the string representation of the current [value]. */ public override fun toString(): String = "${debugString(this)} -> ${debugString(value)}" - - // Implementation details. - @GCUnsafeCall("Kotlin_AtomicReference_set") - private external fun setImpl(newValue: Any?): Unit - - @GCUnsafeCall("Kotlin_AtomicReference_get") - private external fun getImpl(): Any? } /** @@ -299,13 +226,7 @@ public class AtomicReference { * * [kotlinx.cinterop.NativePtr] is a value type, hence it is stored in [AtomicNativePtr] without boxing * and [compareAndSet], [compareAndExchange] operations perform comparison by value. - * - * Legacy MM: Atomic values and freezing: this type is unique with regard to freezing. - * Namely, it provides mutating operations, while can participate in frozen subgraphs. - * So shared frozen objects can have mutable fields of [AtomicNativePtr] type. */ -@Frozen -@OptIn(FreezingIsDeprecated::class, ExperimentalStdlibApi::class) @SinceKotlin("1.9") @ExperimentalForeignApi public class AtomicNativePtr(@Volatile public var value: NativePtr) { @@ -376,7 +297,6 @@ private fun debugString(value: Any?): String { * * Returns true if the actual field value matched [expectedValue] * - * Legacy MM: if [this] is a reference for a non-value represented field, [IllegalArgumentException] would be thrown. */ @PublishedApi @TypedIntrinsic(IntrinsicType.COMPARE_AND_SET_FIELD) @@ -398,7 +318,6 @@ internal external fun KMutableProperty0.compareAndSetField(expectedValue: * * Returns the field value before operation. * - * Legacy MM: if [this] is a reference for a non-value represented field, [IllegalArgumentException] would be thrown. */ @PublishedApi @TypedIntrinsic(IntrinsicType.COMPARE_AND_EXCHANGE_FIELD) @@ -414,8 +333,6 @@ internal external fun KMutableProperty0.compareAndExchangeField(expectedV * would be thrown. * * If property referenced by [this] has nontrivial setter it will not be called. - * - * Legacy MM: if [this] is a reference for a non-value represented field, [IllegalArgumentException] would be thrown. */ @PublishedApi @TypedIntrinsic(IntrinsicType.GET_AND_SET_FIELD) @@ -432,8 +349,6 @@ internal external fun KMutableProperty0.getAndSetField(newValue: T): T * would be thrown. * * If property referenced by [this] has nontrivial setter it will not be called. - * - * Legacy MM: if [this] is a reference for a non-value represented field, [IllegalArgumentException] would be thrown. */ @PublishedApi @TypedIntrinsic(IntrinsicType.GET_AND_ADD_FIELD) @@ -449,8 +364,6 @@ internal external fun KMutableProperty0.getAndAddField(delta: Short): Sho * would be thrown. * * If property referenced by [this] has nontrivial setter it will not be called. - * - * Legacy MM: if [this] is a reference for a non-value represented field, [IllegalArgumentException] would be thrown. */ @PublishedApi @TypedIntrinsic(IntrinsicType.GET_AND_ADD_FIELD) @@ -466,8 +379,6 @@ internal external fun KMutableProperty0.getAndAddField(newValue: Int): Int * would be thrown. * * If property referenced by [this] has nontrivial setter it will not be called. - * - * Legacy MM: if [this] is a reference for a non-value represented field, [IllegalArgumentException] would be thrown. */ @PublishedApi @TypedIntrinsic(IntrinsicType.GET_AND_ADD_FIELD) @@ -483,8 +394,6 @@ internal external fun KMutableProperty0.getAndAddField(newValue: Long): Lo * would be thrown. * * If property referenced by [this] has nontrivial setter it will not be called. - * - * Legacy MM: if [this] is a reference for a non-value represented field, [IllegalArgumentException] would be thrown. */ @PublishedApi @TypedIntrinsic(IntrinsicType.GET_AND_ADD_FIELD) diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/coroutines/SafeContinuationNative.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/coroutines/SafeContinuationNative.kt index 9edf1fa8309..cb68a6f0ed4 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/coroutines/SafeContinuationNative.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/coroutines/SafeContinuationNative.kt @@ -6,7 +6,7 @@ package kotlin.coroutines import kotlin.* -import kotlin.native.concurrent.* +import kotlin.concurrent.* import kotlin.coroutines.intrinsics.CoroutineSingletons.* import kotlin.coroutines.intrinsics.* import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED @@ -25,8 +25,7 @@ internal actual constructor( public actual override val context: CoroutineContext get() = delegate.context - @Suppress("DEPRECATION") - private var resultRef = FreezableAtomicReference(initialResult) + private var resultRef = AtomicReference(initialResult) public actual override fun resumeWith(result: Result) { while (true) { diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/Runtime.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/Runtime.kt index c13db6e2328..2c07f59a7a6 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/Runtime.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/Runtime.kt @@ -61,7 +61,7 @@ public typealias ReportUnhandledExceptionHook = Function1 @OptIn(FreezingIsDeprecated::class) public fun setUnhandledExceptionHook(hook: ReportUnhandledExceptionHook?): ReportUnhandledExceptionHook? { try { - return UnhandledExceptionHookHolder.hook.swap(hook) + return UnhandledExceptionHookHolder.hook.getAndSet(hook) } catch (e: InvalidMutabilityException) { throw InvalidMutabilityException("Unhandled exception hook must be frozen") } @@ -72,7 +72,7 @@ public fun setUnhandledExceptionHook(hook: ReportUnhandledExceptionHook?): Repor @OptIn(FreezingIsDeprecated::class, ExperimentalNativeApi::class) public fun setUnhandledExceptionHook(hook: ReportUnhandledExceptionHook): ReportUnhandledExceptionHook? { try { - return UnhandledExceptionHookHolder.hook.swap(hook) + return UnhandledExceptionHookHolder.hook.getAndSet(hook) } catch (e: InvalidMutabilityException) { throw InvalidMutabilityException("Unhandled exception hook must be frozen") } diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/concurrent/Atomics.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/concurrent/Atomics.kt index 79c6dcc9b56..9a33c6e880d 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/concurrent/Atomics.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/concurrent/Atomics.kt @@ -15,13 +15,7 @@ import kotlin.concurrent.* /** * An [Int] value that is always updated atomically. * For additional details about atomicity guarantees for reads and writes see [kotlin.concurrent.Volatile]. - * - * Legacy MM: Atomic values and freezing: this type is unique with regard to freezing. - * Namely, it provides mutating operations, while can participate in frozen subgraphs. - * So shared frozen objects can have mutable fields of [AtomicInt] type. */ -@Frozen -@OptIn(FreezingIsDeprecated::class, ExperimentalStdlibApi::class) @Deprecated("Use kotlin.concurrent.AtomicInt instead.", ReplaceWith("kotlin.concurrent.AtomicInt")) @DeprecatedSinceKotlin(warningSince = "1.9") public class AtomicInt(public @Volatile var value: Int) { @@ -101,13 +95,7 @@ public class AtomicInt(public @Volatile var value: Int) { /** * A [Long] value that is always updated atomically. * For additional details about atomicity guarantees for reads and writes see [kotlin.concurrent.Volatile]. - * - * Legacy MM: Atomic values and freezing: this type is unique with regard to freezing. - * Namely, it provides mutating operations, while can participate in frozen subgraphs. - * So shared frozen objects can have mutable fields of [AtomicLong] type. */ -@Frozen -@OptIn(FreezingIsDeprecated::class, ExperimentalStdlibApi::class) @Deprecated("Use kotlin.concurrent.AtomicLong instead.", ReplaceWith("kotlin.concurrent.AtomicLong")) @DeprecatedSinceKotlin(warningSince = "1.9") public class AtomicLong(public @Volatile var value: Long = 0L) { @@ -192,65 +180,14 @@ public class AtomicLong(public @Volatile var value: Long = 0L) { /** * An object reference that is always updated atomically. - * - * Legacy MM: An atomic reference to a frozen Kotlin object. Can be used in concurrent scenarious - * but frequently shall be of nullable type and be zeroed out once no longer needed. - * Otherwise memory leak could happen. To detect such leaks [kotlin.native.runtime.GC.detectCycles] - * in debug mode could be helpful. */ -@FrozenLegacyMM -@LeakDetectorCandidate -@NoReorderFields -@OptIn(FreezingIsDeprecated::class) @Deprecated("Use kotlin.concurrent.AtomicReference instead.", ReplaceWith("kotlin.concurrent.AtomicReference")) @DeprecatedSinceKotlin(warningSince = "1.9") -public class AtomicReference { - private var value_: T - - // A spinlock to fix potential ARC race. - private var lock: Int = 0 - - // Optimization for speeding up access. - private var cookie: Int = 0 - - /** - * Creates a new atomic reference pointing to the [given value][value]. - * - * @throws InvalidMutabilityException with legacy MM if reference is not frozen. - */ - constructor(value: T) { - if (this.isFrozen) { - checkIfFrozen(value) - } - value_ = value - } - - /** - * The current value. - * Gets the current value or sets to the given [new value][newValue]. - * - * Legacy MM: if the [new value][newValue] value is not null, it must be frozen or permanent object. - * - * @throws InvalidMutabilityException with legacy MM if the value is not frozen or a permanent object - */ - public var value: T - get() = @Suppress("UNCHECKED_CAST")(getImpl() as T) - set(newValue) = setImpl(newValue) - +public class AtomicReference(public @Volatile var value: T) { /** * Atomically sets the value to the given [new value][newValue] and returns the old value. */ - public fun getAndSet(newValue: T): T { - while (true) { - val old = value - if (old === newValue) { - return old - } - if (compareAndSet(old, newValue)) { - return old - } - } - } + public fun getAndSet(newValue: T): T = this::value.getAndSetField(newValue) /** * Atomically sets the value to the given [new value][newValue] if the current value equals the [expected value][expected], @@ -260,8 +197,7 @@ public class AtomicReference { * * Comparison of values is done by reference. */ - @GCUnsafeCall("Kotlin_AtomicReference_compareAndSet") - external public fun compareAndSet(expected: T, newValue: T): Boolean + public fun compareAndSet(expected: T, newValue: T): Boolean = this::value.compareAndSetField(expected, newValue) /** * Atomically sets the value to the given [new value][newValue] if the current value equals the [expected value][expected] @@ -270,26 +206,14 @@ public class AtomicReference { * Provides sequential consistent ordering guarantees and cannot fail spuriously. * * Comparison of values is done by reference. - * - * Legacy MM: if the [new value][newValue] value is not null, it must be frozen or permanent object. - * - * @throws InvalidMutabilityException with legacy MM if the value is not frozen or a permanent object */ - @GCUnsafeCall("Kotlin_AtomicReference_compareAndSwap") - external public fun compareAndSwap(expected: T, newValue: T): T + public fun compareAndSwap(expected: T, newValue: T): T = this::value.compareAndExchangeField(expected, newValue) /** * Returns the string representation of this object. */ public override fun toString(): String = "${debugString(this)} -> ${debugString(value)}" - - // Implementation details. - @GCUnsafeCall("Kotlin_AtomicReference_set") - private external fun setImpl(newValue: Any?): Unit - - @GCUnsafeCall("Kotlin_AtomicReference_get") - private external fun getImpl(): Any? } /** @@ -298,13 +222,7 @@ public class AtomicReference { * * [kotlinx.cinterop.NativePtr] is a value type, hence it is stored in [AtomicNativePtr] without boxing * and [compareAndSet], [compareAndSwap] operations perform comparison by value. - * - * Legacy MM: Atomic values and freezing: this type is unique with regard to freezing. - * Namely, it provides mutating operations, while can participate in frozen subgraphs. - * So shared frozen objects can have mutable fields of [AtomicNativePtr] type. */ -@Frozen -@OptIn(FreezingIsDeprecated::class, ExperimentalStdlibApi::class) @Deprecated("Use kotlin.concurrent.AtomicNativePtr instead.", ReplaceWith("kotlin.concurrent.AtomicNativePtr")) @DeprecatedSinceKotlin(warningSince = "1.9") public class AtomicNativePtr(public @Volatile var value: NativePtr) { @@ -360,62 +278,23 @@ private fun debugString(value: Any?): String { } /** - * Note: this class is useful only with legacy memory manager. Please use [AtomicReference] instead. - * - * An atomic reference to a Kotlin object. Can be used in concurrent scenarious, but must be frozen first, - * otherwise behaves as regular box for the value. If frozen, shall be zeroed out once no longer needed. - * Otherwise memory leak could happen. To detect such leaks [kotlin.native.runtime.GC.detectCycles] - * in debug mode could be helpful. + * This class was useful only with legacy memory manager. Please use [AtomicReference] instead. */ -@NoReorderFields -@LeakDetectorCandidate -@ExportTypeInfo("theFreezableAtomicReferenceTypeInfo") @FreezingIsDeprecated @Deprecated("Use kotlin.concurrent.AtomicReference instead.", ReplaceWith("kotlin.concurrent.AtomicReference")) @DeprecatedSinceKotlin(warningSince = "1.9") -public class FreezableAtomicReference(private var value_: T) { - // A spinlock to fix potential ARC race. - private var lock: Int = 0 - - // Optimization for speeding up access. - private var cookie: Int = 0 - - /** - * The referenced value. - * Gets the value or sets to the given [new value][newValue]. If the [new value][newValue] is not null, - * and `this` is frozen - it must be frozen or permanent object. - * - * @throws InvalidMutabilityException if the value is not frozen or a permanent object - */ - public var value: T - get() = @Suppress("UNCHECKED_CAST")(getImpl() as T) - set(newValue) { - if (this.isShareable()) - setImpl(newValue) - else - value_ = newValue - } +public class FreezableAtomicReference(public @Volatile var value: T) { /** * Atomically sets the value to the given [new value][newValue] if the current value equals the [expected value][expected] * and returns the old value in any case. * - * Legacy MM: If the [new value][newValue] value is not null and object is frozen, it must be frozen or permanent object. * * @param expected the expected value * @param newValue the new value - * @throws InvalidMutabilityException with legacy MM if the value is not frozen or a permanent object * @return the old value */ - public fun compareAndSwap(expected: T, newValue: T): T { - return if (this.isShareable()) { - @Suppress("UNCHECKED_CAST")(compareAndSwapImpl(expected, newValue) as T) - } else { - val old = value_ - if (old === expected) value_ = newValue - old - } - } + public fun compareAndSwap(expected: T, newValue: T): T = this::value.compareAndExchangeField(expected, newValue) /** * Atomically sets the value to the given [new value][newValue] if the current value equals the [expected value][expected] @@ -427,17 +306,7 @@ public class FreezableAtomicReference(private var value_: T) { * @param newValue the new value * @return true if successful */ - public fun compareAndSet(expected: T, newValue: T): Boolean { - if (this.isShareable()) - return compareAndSetImpl(expected, newValue) - val old = value_ - if (old === expected) { - value_ = newValue - return true - } else { - return false - } - } + public fun compareAndSet(expected: T, newValue: T): Boolean = this::value.compareAndSetField(expected, newValue) /** * Returns the string representation of this object. @@ -447,29 +316,4 @@ public class FreezableAtomicReference(private var value_: T) { public override fun toString(): String = "${debugString(this)} -> ${debugString(value)}" - // TODO: Consider making this public. - internal fun swap(newValue: T): T { - while (true) { - val old = value - if (old === newValue) { - return old - } - if (compareAndSet(old, newValue)) { - return old - } - } - } - - // Implementation details. - @GCUnsafeCall("Kotlin_AtomicReference_set") - private external fun setImpl(newValue: Any?): Unit - - @GCUnsafeCall("Kotlin_AtomicReference_get") - private external fun getImpl(): Any? - - @GCUnsafeCall("Kotlin_AtomicReference_compareAndSwap") - private external fun compareAndSwapImpl(expected: Any?, newValue: Any?): Any? - - @GCUnsafeCall("Kotlin_AtomicReference_compareAndSet") - private external fun compareAndSetImpl(expected: Any?, newValue: Any?): Boolean } diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/concurrent/Lazy.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/concurrent/Lazy.kt index b67fd698191..74ea26cc9fd 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/concurrent/Lazy.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/concurrent/Lazy.kt @@ -12,68 +12,6 @@ import kotlin.native.internal.Frozen import kotlin.concurrent.AtomicReference import kotlinx.cinterop.ExperimentalForeignApi -@FreezingIsDeprecated - -internal class FreezeAwareLazyImpl(initializer: () -> T) : Lazy { - private val value_ = FreezableAtomicReference(UNINITIALIZED) - // This cannot be made atomic because of the legacy MM. See https://github.com/JetBrains/kotlin-native/pull/3944 - // So it must be protected by the lock below. - private var initializer_: (() -> T)? = initializer - private val lock_ = Lock() - - private fun getOrInit(doFreeze: Boolean): T { - var result = value_.value - if (result !== UNINITIALIZED) { - if (result === INITIALIZING) { - value_.value = UNINITIALIZED - throw IllegalStateException("Recursive lazy computation") - } - @Suppress("UNCHECKED_CAST") - return result as T - } - // Set value_ to INITIALIZING. - value_.value = INITIALIZING - try { - result = initializer_!!() - if (doFreeze) result.freeze() - } catch (throwable: Throwable) { - value_.value = UNINITIALIZED - throw throwable - } - if (!doFreeze) { - if (this.isFrozen) { - value_.value = UNINITIALIZED - throw InvalidMutabilityException("Frozen during lazy computation") - } - // Clear initializer. - initializer_ = null - } - // Set value_ to actual one. - value_.value = result - return result - } - - override val value: T - get() { - return if (isShareable()) { - // TODO: This is probably a big performance problem for lazy with the new MM. Address it. - locked(lock_) { - getOrInit(isFrozen) - } - } else { - getOrInit(false) - } - } - - /** - * This operation on shared objects may return value which is no longer reflect the current state of lazy. - */ - override fun isInitialized(): Boolean = (value_.value !== UNINITIALIZED) && (value_.value !== INITIALIZING) - - override fun toString(): String = if (isInitialized()) - value.toString() else "Lazy value not initialized yet" -} - @OptIn(FreezingIsDeprecated::class) internal object UNINITIALIZED { // So that single-threaded configs can use those as well. @@ -137,8 +75,8 @@ public fun atomicLazy(initializer: () -> T): Lazy = AtomicLazyImpl(initia @Suppress("UNCHECKED_CAST") @OptIn(FreezingIsDeprecated::class) internal class SynchronizedLazyImpl(initializer: () -> T) : Lazy { - private var initializer = FreezableAtomicReference<(() -> T)?>(initializer) - private var valueRef = FreezableAtomicReference(UNINITIALIZED) + private var initializer = AtomicReference<(() -> T)?>(initializer) + private var valueRef = AtomicReference(UNINITIALIZED) private val lock = Lock() override val value: T @@ -151,14 +89,7 @@ internal class SynchronizedLazyImpl(initializer: () -> T) : Lazy { return locked(lock) { val _v2 = valueRef.value if (_v2 === UNINITIALIZED) { - val wasFrozen = this.isFrozen val typedValue = initializer.value!!() - if (this.isFrozen) { - if (!wasFrozen) { - throw InvalidMutabilityException("Frozen during lazy computation") - } - typedValue.freeze() - } valueRef.value = typedValue initializer.value = null typedValue @@ -175,10 +106,9 @@ internal class SynchronizedLazyImpl(initializer: () -> T) : Lazy { @Suppress("UNCHECKED_CAST") -@OptIn(FreezingIsDeprecated::class) internal class SafePublicationLazyImpl(initializer: () -> T) : Lazy { - private var initializer = FreezableAtomicReference<(() -> T)?>(initializer) - private var valueRef = FreezableAtomicReference(UNINITIALIZED) + private var initializer = AtomicReference<(() -> T)?>(initializer) + private var valueRef = AtomicReference(UNINITIALIZED) override val value: T get() { @@ -190,14 +120,7 @@ internal class SafePublicationLazyImpl(initializer: () -> T) : Lazy { val initializerValue = initializer.value // if we see null in initializer here, it means that the value is already set by another thread if (initializerValue != null) { - val wasFrozen = this.isFrozen val newValue = initializerValue() - if (this.isFrozen) { - if (!wasFrozen) { - throw InvalidMutabilityException("Frozen during lazy computation") - } - newValue.freeze() - } if (valueRef.compareAndSet(UNINITIALIZED, newValue)) { initializer.value = null return newValue diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt index d884cfe50d4..80aa192fe11 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt @@ -10,9 +10,8 @@ package kotlin.native.internal import kotlin.experimental.ExperimentalNativeApi import kotlin.internal.getProgressionLastElement import kotlin.reflect.KClass -import kotlin.native.concurrent.freeze +import kotlin.concurrent.AtomicReference import kotlinx.cinterop.* -import kotlin.native.concurrent.FreezableAtomicReference @ExportForCppRuntime @PublishedApi @@ -158,12 +157,7 @@ internal fun ReportUnhandledException(throwable: Throwable) { // to throw an exception during it's initialization before this hook would've been initialized. @OptIn(FreezingIsDeprecated::class, ExperimentalNativeApi::class) internal object UnhandledExceptionHookHolder { - internal val hook: FreezableAtomicReference = - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - FreezableAtomicReference(null) - } else { - FreezableAtomicReference(null).freeze() - } + internal val hook: AtomicReference = AtomicReference(null) } // TODO: Can be removed only when native-mt coroutines stop using it.