| // DISABLE_NATIVE: gcType=NOOP |
| // FREE_COMPILER_ARGS: -opt-in=kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi,kotlin.native.runtime.NativeRuntimeApi,kotlin.native.internal.InternalForKotlinNative |
| |
| import kotlin.concurrent.AtomicInt |
| import kotlin.native.concurrent.* |
| import kotlin.native.identityHashCode |
| import kotlin.native.internal.NativePtr |
| import kotlin.native.internal.isPermanent |
| import kotlin.native.internal.ref.* |
| import kotlin.native.runtime.GC |
| import kotlin.native.NoInline |
| import kotlin.test.* |
| |
| typealias Id = Int |
| typealias Ref = Pair<Id, ExternalRCRef> |
| |
| @NoInline |
| fun createLocal() : Ref { |
| val obj = Any() |
| return obj.identityHashCode() to createRetainedExternalRCRef(obj) |
| } |
| |
| @NoInline |
| fun createLocalUnretained() : Ref { |
| val obj = Any() |
| return obj.identityHashCode() to createUnretainedExternalRCRef(obj) |
| } |
| |
| val globalObj = Any() |
| |
| fun createGlobal() : Ref { |
| return globalObj.identityHashCode() to createRetainedExternalRCRef(globalObj) |
| } |
| |
| fun createGlobalUnretained() : Ref { |
| return globalObj.identityHashCode() to createUnretainedExternalRCRef(globalObj) |
| } |
| |
| object Singleton { |
| val x = Any() |
| } |
| |
| fun createSingleton() : Ref { |
| assertFalse(Singleton.isPermanent()) |
| return Singleton.identityHashCode() to createRetainedExternalRCRef(Singleton) |
| } |
| |
| fun createSingletonUnretained() : Ref { |
| assertFalse(Singleton.isPermanent()) |
| return Singleton.identityHashCode() to createUnretainedExternalRCRef(Singleton) |
| } |
| |
| object Permanent |
| |
| fun createPermanent() : Ref { |
| assertTrue(Permanent.isPermanent()) |
| return Permanent.identityHashCode() to createRetainedExternalRCRef(Permanent) |
| } |
| |
| fun createPermanentUnretained() : Ref { |
| assertTrue(Permanent.isPermanent()) |
| return Permanent.identityHashCode() to createUnretainedExternalRCRef(Permanent) |
| } |
| |
| fun createNull(): Ref { |
| return null.identityHashCode() to createRetainedExternalRCRef(null) |
| } |
| |
| fun createNullUnretained(): Ref { |
| return null.identityHashCode() to createUnretainedExternalRCRef(null) |
| } |
| |
| @Test fun nullExternalRCRef() { |
| assertTrue(createRetainedExternalRCRef(null) == NativePtr.NULL) |
| assertTrue(createUnretainedExternalRCRef(null) == NativePtr.NULL) |
| assertNull(dereferenceExternalRCRef(NativePtr.NULL)) |
| } |
| |
| inline fun createAndDisposeTest(create: () -> Ref) { |
| val ref = create() |
| GC.collect() |
| assertEquals(ref.first, dereferenceExternalRCRef(ref.second).identityHashCode()) |
| retainExternalRCRef(ref.second) |
| releaseExternalRCRef(ref.second) |
| releaseExternalRCRef(ref.second) |
| disposeExternalRCRef(ref.second) |
| } |
| |
| @Test fun createAndDisposeLocal() { |
| createAndDisposeTest(::createLocal) |
| } |
| |
| @Test fun createAndDisposeGlobal() { |
| createAndDisposeTest(::createGlobal) |
| } |
| |
| @Test fun createAndDisposeSingleton() { |
| createAndDisposeTest(::createSingleton) |
| } |
| |
| @Test fun createAndDisposePermanent() { |
| createAndDisposeTest(::createPermanent) |
| } |
| |
| @Test fun createAndDisposeNull() { |
| createAndDisposeTest(::createNull) |
| } |
| |
| inline fun weakTestSuccess(create: () -> Ref) { |
| val ref = create() |
| GC.collect() |
| assertNull(dereferenceExternalRCRefOrNull(ref.second)) |
| disposeExternalRCRef(ref.second) |
| } |
| |
| inline fun weakTestFailure(create: () -> Ref) { |
| val ref = create() |
| GC.collect() |
| assertEquals(ref.first, dereferenceExternalRCRefOrNull(ref.second).identityHashCode()) |
| assertEquals(ref.first, dereferenceExternalRCRef(ref.second).identityHashCode()) |
| disposeExternalRCRef(ref.second) |
| } |
| |
| @Test fun weakLocal() { |
| weakTestSuccess(::createLocalUnretained) |
| } |
| |
| @Test fun weakGlobal() { |
| weakTestFailure(::createGlobalUnretained) |
| } |
| |
| @Test fun weakSingleton() { |
| weakTestFailure(::createSingletonUnretained) |
| } |
| |
| @Test fun weakPermanent() { |
| weakTestFailure(::createPermanentUnretained) |
| } |
| |
| @Test fun weakNull() { |
| weakTestSuccess(::createNullUnretained) |
| } |
| |
| inline fun weakResurrectTest(create: () -> Ref, doRetainRelease: Boolean) { |
| val ref = create() |
| val state = AtomicInt(0) |
| withWorker { |
| releaseExternalRCRef(ref.second) |
| val future = execute(TransferMode.SAFE, { Triple(ref, state, doRetainRelease) }) { (ref, state, doRetainRelease) -> |
| state.value = 1 |
| while (state.value == 1) { |
| val result = dereferenceExternalRCRefOrNull(ref.second) |
| if (result != null) { |
| if (doRetainRelease) retainExternalRCRef(ref.second) |
| assertEquals(ref.first, result.identityHashCode()) |
| assertEquals(ref.first, dereferenceExternalRCRef(ref.second).identityHashCode()) |
| if (doRetainRelease) releaseExternalRCRef(ref.second) |
| } |
| } |
| Unit |
| } |
| while (state.value == 0) {} |
| repeat(10) { |
| GC.collect() |
| } |
| state.value = 2 |
| future.result |
| } |
| disposeExternalRCRef(ref.second) |
| } |
| |
| @Test fun weakResurrectLocal() { |
| weakResurrectTest(::createLocal, false) |
| } |
| |
| @Test fun weakResurrectGlobal() { |
| weakResurrectTest(::createGlobal, false) |
| } |
| |
| @Test fun weakResurrectSingleton() { |
| weakResurrectTest(::createSingleton, false) |
| } |
| |
| @Test fun weakResurrectPermanent() { |
| weakResurrectTest(::createPermanent, false) |
| } |
| |
| @Test fun weakResurrectNull() { |
| weakResurrectTest(::createNull, false) |
| } |
| |
| @Test fun weakResurrectLocalWithRetainRelease() { |
| weakResurrectTest(::createLocal, true) |
| } |
| |
| @Test fun weakResurrectGlobalWithRetainRelease() { |
| weakResurrectTest(::createGlobal, true) |
| } |
| |
| @Test fun weakResurrectSingletonWithRetainRelease() { |
| weakResurrectTest(::createSingleton, true) |
| } |
| |
| @Test fun weakResurrectPermanentWithRetainRelease() { |
| weakResurrectTest(::createPermanent, true) |
| } |
| |
| @Test fun weakResurrectNullWithRetainRelease() { |
| weakResurrectTest(::createNull, true) |
| } |