Make FreezableAtomicReference atomic when unfrozen for the new MM.
This commit is contained in:
committed by
Space
parent
518e8691b7
commit
28b6427d3e
@@ -596,17 +596,10 @@ func testShared() throws {
|
|||||||
try assertFalse(ValuesKt.isFrozen(obj: obj), "isFrozen(\(obj))")
|
try assertFalse(ValuesKt.isFrozen(obj: obj), "isFrozen(\(obj))")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ValuesKt.isExperimentalMM {
|
try assertFrozen(NSObject())
|
||||||
try assertNotFrozen(NSObject())
|
try assertFrozen(TestSharedIImpl())
|
||||||
try assertNotFrozen(TestSharedIImpl())
|
try assertFrozen(ValuesKt.kotlinLambda(block: { return $0 }) as AnyObject)
|
||||||
try assertNotFrozen(ValuesKt.kotlinLambda(block: { return $0 }) as AnyObject)
|
try assertNotFrozen(FinalClassExtOpen())
|
||||||
try assertNotFrozen(FinalClassExtOpen())
|
|
||||||
} else {
|
|
||||||
try assertFrozen(NSObject())
|
|
||||||
try assertFrozen(TestSharedIImpl())
|
|
||||||
try assertFrozen(ValuesKt.kotlinLambda(block: { return $0 }) as AnyObject)
|
|
||||||
try assertNotFrozen(FinalClassExtOpen())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class PureSwiftClass {
|
class PureSwiftClass {
|
||||||
|
|||||||
@@ -59,36 +59,27 @@ data class Data(var int: Int)
|
|||||||
assertFailsWith<InvalidMutabilityException> { a8[1] = 2.0 }
|
assertFailsWith<InvalidMutabilityException> { a8[1] = 2.0 }
|
||||||
|
|
||||||
// Ensure that String and integral boxes are frozen by default, by passing local to the worker.
|
// Ensure that String and integral boxes are frozen by default, by passing local to the worker.
|
||||||
val hasToBeFrozen = Platform.memoryModel == MemoryModel.STRICT
|
|
||||||
val worker = Worker.start()
|
val worker = Worker.start()
|
||||||
var data: Any = "Hello" + " " + "world"
|
var data: Any = "Hello" + " " + "world"
|
||||||
if (hasToBeFrozen) {
|
assertTrue(data.isFrozen)
|
||||||
assertTrue(data.isFrozen)
|
|
||||||
}
|
|
||||||
worker.execute(TransferMode.SAFE, { data } ) {
|
worker.execute(TransferMode.SAFE, { data } ) {
|
||||||
input -> println("Worker 1: $input")
|
input -> println("Worker 1: $input")
|
||||||
}.result
|
}.result
|
||||||
|
|
||||||
data = 42
|
data = 42
|
||||||
if (hasToBeFrozen) {
|
assertTrue(data.isFrozen)
|
||||||
assertTrue(data.isFrozen)
|
|
||||||
}
|
|
||||||
worker.execute(TransferMode.SAFE, { data } ) {
|
worker.execute(TransferMode.SAFE, { data } ) {
|
||||||
input -> println("Worker2: $input")
|
input -> println("Worker2: $input")
|
||||||
}.result
|
}.result
|
||||||
|
|
||||||
data = 239.0
|
data = 239.0
|
||||||
if (hasToBeFrozen) {
|
assertTrue(data.isFrozen)
|
||||||
assertTrue(data.isFrozen)
|
|
||||||
}
|
|
||||||
worker.execute(TransferMode.SAFE, { data } ) {
|
worker.execute(TransferMode.SAFE, { data } ) {
|
||||||
input -> println("Worker3: $input")
|
input -> println("Worker3: $input")
|
||||||
}.result
|
}.result
|
||||||
|
|
||||||
data = 'a'
|
data = 'a'
|
||||||
if (hasToBeFrozen) {
|
assertTrue(data.isFrozen)
|
||||||
assertTrue(data.isFrozen)
|
|
||||||
}
|
|
||||||
worker.execute(TransferMode.SAFE, { data } ) {
|
worker.execute(TransferMode.SAFE, { data } ) {
|
||||||
input -> println("Worker4: $input")
|
input -> println("Worker4: $input")
|
||||||
}.result
|
}.result
|
||||||
|
|||||||
@@ -182,7 +182,9 @@ void Kotlin_AtomicReference_checkIfFrozen(KRef value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(Kotlin_AtomicReference_compareAndSwap, KRef thiz, KRef expectedValue, KRef newValue) {
|
OBJ_GETTER(Kotlin_AtomicReference_compareAndSwap, KRef thiz, KRef expectedValue, KRef newValue) {
|
||||||
Kotlin_AtomicReference_checkIfFrozen(newValue);
|
if (isPermanentOrFrozen(thiz)) {
|
||||||
|
Kotlin_AtomicReference_checkIfFrozen(newValue);
|
||||||
|
}
|
||||||
// See Kotlin_AtomicReference_get() for explanations, why locking is needed.
|
// See Kotlin_AtomicReference_get() for explanations, why locking is needed.
|
||||||
AtomicReferenceLayout* ref = asAtomicReference(thiz);
|
AtomicReferenceLayout* ref = asAtomicReference(thiz);
|
||||||
RETURN_RESULT_OF(SwapHeapRefLocked, &ref->value_, expectedValue, newValue,
|
RETURN_RESULT_OF(SwapHeapRefLocked, &ref->value_, expectedValue, newValue,
|
||||||
@@ -190,7 +192,9 @@ OBJ_GETTER(Kotlin_AtomicReference_compareAndSwap, KRef thiz, KRef expectedValue,
|
|||||||
}
|
}
|
||||||
|
|
||||||
KBoolean Kotlin_AtomicReference_compareAndSet(KRef thiz, KRef expectedValue, KRef newValue) {
|
KBoolean Kotlin_AtomicReference_compareAndSet(KRef thiz, KRef expectedValue, KRef newValue) {
|
||||||
Kotlin_AtomicReference_checkIfFrozen(newValue);
|
if (isPermanentOrFrozen(thiz)) {
|
||||||
|
Kotlin_AtomicReference_checkIfFrozen(newValue);
|
||||||
|
}
|
||||||
// See Kotlin_AtomicReference_get() for explanations, why locking is needed.
|
// See Kotlin_AtomicReference_get() for explanations, why locking is needed.
|
||||||
AtomicReferenceLayout* ref = asAtomicReference(thiz);
|
AtomicReferenceLayout* ref = asAtomicReference(thiz);
|
||||||
ObjHolder holder;
|
ObjHolder holder;
|
||||||
@@ -200,7 +204,9 @@ KBoolean Kotlin_AtomicReference_compareAndSet(KRef thiz, KRef expectedValue, KRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_AtomicReference_set(KRef thiz, KRef newValue) {
|
void Kotlin_AtomicReference_set(KRef thiz, KRef newValue) {
|
||||||
Kotlin_AtomicReference_checkIfFrozen(newValue);
|
if (isPermanentOrFrozen(thiz)) {
|
||||||
|
Kotlin_AtomicReference_checkIfFrozen(newValue);
|
||||||
|
}
|
||||||
AtomicReferenceLayout* ref = asAtomicReference(thiz);
|
AtomicReferenceLayout* ref = asAtomicReference(thiz);
|
||||||
SetHeapRefLocked(&ref->value_, newValue, &ref->lock_, &ref->cookie_);
|
SetHeapRefLocked(&ref->value_, newValue, &ref->lock_, &ref->cookie_);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ public class FreezableAtomicReference<T>(private var value_: T) {
|
|||||||
public var value: T
|
public var value: T
|
||||||
get() = @Suppress("UNCHECKED_CAST")(getImpl() as T)
|
get() = @Suppress("UNCHECKED_CAST")(getImpl() as T)
|
||||||
set(new) {
|
set(new) {
|
||||||
if (this.isFrozen)
|
if (this.isShareable())
|
||||||
setImpl(new)
|
setImpl(new)
|
||||||
else
|
else
|
||||||
value_ = new
|
value_ = new
|
||||||
@@ -342,7 +342,9 @@ public class FreezableAtomicReference<T>(private var value_: T) {
|
|||||||
* @return the old value
|
* @return the old value
|
||||||
*/
|
*/
|
||||||
public fun compareAndSwap(expected: T, new: T): T {
|
public fun compareAndSwap(expected: T, new: T): T {
|
||||||
return if (this.isFrozen) @Suppress("UNCHECKED_CAST")(compareAndSwapImpl(expected, new) as T) else {
|
return if (this.isShareable()) {
|
||||||
|
@Suppress("UNCHECKED_CAST")(compareAndSwapImpl(expected, new) as T)
|
||||||
|
} else {
|
||||||
val old = value_
|
val old = value_
|
||||||
if (old === expected) value_ = new
|
if (old === expected) value_ = new
|
||||||
old
|
old
|
||||||
@@ -358,7 +360,8 @@ public class FreezableAtomicReference<T>(private var value_: T) {
|
|||||||
* @return true if successful
|
* @return true if successful
|
||||||
*/
|
*/
|
||||||
public fun compareAndSet(expected: T, new: T): Boolean {
|
public fun compareAndSet(expected: T, new: T): Boolean {
|
||||||
if (this.isFrozen) return compareAndSetImpl(expected, new)
|
if (this.isShareable())
|
||||||
|
return compareAndSetImpl(expected, new)
|
||||||
val old = value_
|
val old = value_
|
||||||
if (old === expected) {
|
if (old === expected) {
|
||||||
value_ = new
|
value_ = new
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ import kotlin.native.identityHashCode
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlinx.cinterop.*
|
import kotlinx.cinterop.*
|
||||||
|
|
||||||
|
@GCUnsafeCall("Kotlin_Any_isShareable")
|
||||||
|
external internal fun Any?.isShareable(): Boolean
|
||||||
|
|
||||||
// Implementation details.
|
// Implementation details.
|
||||||
|
|
||||||
@GCUnsafeCall("Kotlin_Worker_stateOfFuture")
|
@GCUnsafeCall("Kotlin_Worker_stateOfFuture")
|
||||||
|
|||||||
@@ -125,8 +125,5 @@ private class CleanerImpl(
|
|||||||
private val cleanPtr: NativePtr,
|
private val cleanPtr: NativePtr,
|
||||||
): Cleaner {}
|
): Cleaner {}
|
||||||
|
|
||||||
@GCUnsafeCall("Kotlin_Any_isShareable")
|
|
||||||
external private fun Any?.isShareable(): Boolean
|
|
||||||
|
|
||||||
@GCUnsafeCall("CreateStablePointer")
|
@GCUnsafeCall("CreateStablePointer")
|
||||||
external private fun createStablePointer(obj: Any): NativePtr
|
external private fun createStablePointer(obj: Any): NativePtr
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ void ObjHeader::destroyMetaObject(ObjHeader* object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool isPermanentOrFrozen(const ObjHeader* obj) {
|
ALWAYS_INLINE bool isPermanentOrFrozen(const ObjHeader* obj) {
|
||||||
return mm::IsFrozen(obj);
|
// TODO: Freeze TF_IMMUTABLE objects upon creation.
|
||||||
|
return mm::IsFrozen(obj) || ((obj->type_info()->flags_ & TF_IMMUTABLE) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool isShareable(const ObjHeader* obj) {
|
ALWAYS_INLINE bool isShareable(const ObjHeader* obj) {
|
||||||
|
|||||||
Reference in New Issue
Block a user