blob: 392a279b9771db28bee152361f6d7d58118c8a05 [file]
// 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)
}