diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 12fc374701d..1b7c6917b6c 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -285,195 +285,6 @@ Task dynamicTest(String name, Closure configureClosure) { // source = "codegen/object/constructor.kt" //} -standaloneTest("runtime_basic_init") { - source = "runtime/basic/init.kt" - expectedExitStatus = 0 -} - -standaloneTest("cleaner_basic") { - enabled = !isNoopGC - source = "runtime/basic/cleaner_basic.kt" - flags = ['-tr', '-opt-in=kotlin.native.internal.InternalForKotlinNative'] -} - -standaloneTest("cleaner_workers") { - enabled = !isNoopGC - source = "runtime/basic/cleaner_workers.kt" - flags = ['-tr', '-opt-in=kotlin.native.internal.InternalForKotlinNative'] -} - -standaloneTest("cleaner_in_main_with_checker") { - enabled = !isNoopGC - source = "runtime/basic/cleaner_in_main_with_checker.kt" - useGoldenData = true -} - -standaloneTest("cleaner_in_main_without_checker") { - source = "runtime/basic/cleaner_in_main_without_checker.kt" - useGoldenData = true -} - -standaloneTest("cleaner_leak_without_checker") { - source = "runtime/basic/cleaner_leak_without_checker.kt" - useGoldenData = true -} - -standaloneTest("cleaner_leak_with_checker") { - enabled = !isNoopGC - source = "runtime/basic/cleaner_leak_with_checker.kt" - expectedExitStatusChecker = { it != 0 } - outputChecker = { s -> (s =~ /Cleaner (0x)?[0-9a-fA-F]+ was disposed during program exit/).find() } -} - -standaloneTest("cleaner_in_tls_main_without_checker") { - source = "runtime/basic/cleaner_in_tls_main_without_checker.kt" -} - -standaloneTest("cleaner_in_tls_main_with_checker") { - enabled = !isNoopGC - source = "runtime/basic/cleaner_in_tls_main_with_checker.kt" - expectedExitStatusChecker = { it != 0 } - outputChecker = { s -> (s =~ /Cleaner (0x)?[0-9a-fA-F]+ was disposed during program exit/).find() } -} - -standaloneTest("cleaner_in_tls_worker") { - enabled = !isNoopGC - source = "runtime/basic/cleaner_in_tls_worker.kt" - flags = ['-opt-in=kotlin.native.internal.InternalForKotlinNative'] -} - -standaloneTest('logging') { - outputChecker = { out -> - out.toLowerCase().contains("[logging]") && // loging reports configured log levels on info level - out.toLowerCase().contains("logging = debug") && - out.toLowerCase().contains("gc = info") && - out.toLowerCase().contains("mm = warning") && - out.toLowerCase().contains("tls = error") && - out.toLowerCase().contains("[gc]") // gc reports initialization on info level - } - source = "runtime/basic/logging.kt" - flags = ['-Xruntime-logs=gc=info,mm=warning,tls=error,logging=debug'] -} - -standaloneTest('logging_invalid') { - outputChecker = { it.isEmpty() } - source = "runtime/basic/logging.kt" - flags = ['-Xruntime-logs=invalid=unknown,logging=debug'] -} - -standaloneTest('logging_override') { - outputChecker = { it.isEmpty() } - source = "runtime/basic/logging.kt" - flags = ['-Xruntime-logs=logging=info,logging=debug,logging=none'] -} - -standaloneTest("worker_bound_reference0") { - source = "runtime/concurrent/worker_bound_reference0.kt" - flags = ['-tr'] - - if (isNoopGC) { - def exclude = [ - "*.testCollect", - "*.testCollectFrozen", - "*.testCollectInWorkerFrozen", - "*.collectCyclicGarbage", - "*.collectCyclicGarbageWithAtomicsFrozen", - "*.collectCrossThreadCyclicGarbageWithAtomicsFrozen" - ] - arguments += ["--ktest_filter=*-${exclude.join(":")}"] - } -} - -// This tests changes main thread worker queue state, so better be executed alone. -standaloneTest("worker5") { - useGoldenData = true - source = "runtime/workers/worker5.kt" -} - -tasks.register("worker10", KonanLocalTest) { - enabled = !isNoopGC - useGoldenData = true - source = "runtime/workers/worker10.kt" -} - -standaloneTest("worker_exceptions") { - flags = ["-tr"] - outputChecker = { - !it.contains("testExecuteAfterStartQuiet error") && it.contains("testExecuteStart error") && !it.contains("testExecuteStartQuiet error") - } - source = "runtime/workers/worker_exceptions.kt" -} - -standaloneTest("worker_exceptions_terminate") { - expectedExitStatusChecker = { it != 0 } - outputChecker = { - it.contains("some error") && !it.contains("Will not happen") - } - source = "runtime/workers/worker_exceptions_terminate.kt" -} - -standaloneTest("worker_exceptions_terminate_hook") { - outputChecker = { - it.contains("hook called") && !it.contains("some error") && it.contains("Will happen") - } - source = "runtime/workers/worker_exceptions_terminate_hook.kt" -} - -standaloneTest("worker_exceptions_terminate_current") { - expectedExitStatusChecker = { it != 0 } - outputChecker = { - it.contains("some error") && !it.contains("Will not happen") - } - source = "runtime/workers/worker_exceptions_terminate_current.kt" -} - -standaloneTest("worker_exceptions_terminate_hook_current") { - outputChecker = { - it.contains("hook called") && !it.contains("some error") && it.contains("Will happen") - } - source = "runtime/workers/worker_exceptions_terminate_hook_current.kt" -} - -standaloneTest("worker_threadlocal_no_leak") { - source = "runtime/workers/worker_threadlocal_no_leak.kt" -} - -standaloneTest("freeze_disabled") { - enabled = !isNoopGC - flags = ["-tr"] - source = "runtime/workers/freeze_disabled.kt" - testLogger = KonanTest.Logger.SILENT -} - -standaloneTest("lazy2") { - useGoldenData = true - source = "runtime/workers/lazy2.kt" -} - -standaloneTest("lazy3") { - enabled = !isNoopGC - source = "runtime/workers/lazy3.kt" -} - -tasks.register("mutableData1", KonanLocalTest) { - source = "runtime/workers/mutableData1.kt" -} - -tasks.register("enumIdentity", KonanLocalTest) { - useGoldenData = true - source = "runtime/workers/enum_identity.kt" -} - -standaloneTest("leakWorker") { - source = "runtime/workers/leak_worker.kt" - expectedExitStatusChecker = { it != 0 } - outputChecker = { s -> s.contains("Unfinished workers detected, 1 workers leaked!") } -} - -standaloneTest("leakMemoryWithWorkerTermination") { - source = "runtime/workers/leak_memory_with_worker_termination.kt" -} - standaloneTest("initializers_testInfrastructure") { source = "codegen/initializers/testInfrastructure.kt" flags = ["-tr"] @@ -571,128 +382,6 @@ standaloneTest("throw_from_except_constr") { source = "runtime/exceptions/throw_from_except_constr.kt" } -tasks.register("initializers6", KonanLocalTest) { - source = "runtime/basic/initializers6.kt" -} - -tasks.register("memory_var1", KonanLocalTest) { - source = "runtime/memory/var1.kt" -} - -tasks.register("memory_var2", KonanLocalTest) { - source = "runtime/memory/var2.kt" -} - -tasks.register("memory_var3", KonanLocalTest) { - source = "runtime/memory/var3.kt" -} - -tasks.register("memory_var4", KonanLocalTest) { - source = "runtime/memory/var4.kt" -} - -tasks.register("memory_throw_cleanup", KonanLocalTest) { - useGoldenData = true - source = "runtime/memory/throw_cleanup.kt" -} - -tasks.register("memory_escape0", KonanLocalTest) { - source = "runtime/memory/escape0.kt" -} - -tasks.register("memory_escape1", KonanLocalTest) { - useGoldenData = true - source = "runtime/memory/escape1.kt" -} - -tasks.register("memory_cycles0", KonanLocalTest) { - useGoldenData = true - source = "runtime/memory/cycles0.kt" -} - -tasks.register("memory_cycles1", KonanLocalTest) { - enabled = !isNoopGC - source = "runtime/memory/cycles1.kt" -} - -tasks.register("memory_basic0", KonanLocalTest) { - source = "runtime/memory/basic0.kt" -} - -tasks.register("memory_escape2", KonanLocalTest) { - useGoldenData = true - source = "runtime/memory/escape2.kt" -} - -tasks.register("memory_weak0", KonanLocalTest) { - enabled = !isNoopGC - useGoldenData = true - source = "runtime/memory/weak0.kt" -} - -tasks.register("memory_weak1", KonanLocalTest) { - useGoldenData = true - source = "runtime/memory/weak1.kt" -} - -standaloneTest("memory_only_gc") { - source = "runtime/memory/only_gc.kt" -} - -standaloneTest("leakMemory") { - source = "runtime/memory/leak_memory.kt" -} - -standaloneTest("leakMemoryWithTestRunner") { - source = "runtime/memory/leak_memory_test_runner.kt" - flags = ['-tr'] -} - -standaloneTest("gcStats") { - source = "runtime/memory/gcStats.kt" - flags = ['-tr', "-Xbinary=gcSchedulerType=disabled"] - enabled = !isNoopGC && !isAggressiveGC -} - -standaloneTest("stress_gc_allocations") { - // TODO: Support obtaining peak RSS on more platforms. - enabled = - (project.testTarget != "watchos_arm32") && - (project.testTarget != "watchos_arm64") && - (project.testTarget != "watchos_x86") && - (project.testTarget != "watchos_x64") && - (project.testTarget != "watchos_simulator_arm64") && - !isNoopGC && // Requires some GC. - !isAggressiveGC && // No need to check with aggressive GC at all - !runtimeAssertionsPanic // New allocator with assertions makes this test very slow. - source = "runtime/memory/stress_gc_allocations.kt" - flags = [ - '-opt-in=kotlin.native.internal.InternalForKotlinNative', // MemoryUsageInfo is internal - '-Xdisable-phases=EscapeAnalysis', // The test checks GC, we need to allocate everything on the heap. - ] -} - -standaloneTest("array_out_of_memory") { - // This test allocs a large array that may make Linux - // kill any process inlcuding Gradle with OOM-killer - enabled = project.target.family != Family.LINUX - source = "runtime/memory/array_out_of_memory.kt" - flags = ['-tr'] - switch(project.target.architecture) { - case Architecture.X64: - case Architecture.ARM64: - break; - case Architecture.X86: - case Architecture.ARM32: - case Architecture.MIPS32: - case Architecture.MIPSEL32: - case Architecture.WASM32: - expectedExitStatusChecker = { it != 0 } - outputChecker = { s -> s.contains("Out of memory trying to allocate") } - break; - } -} - tasks.register("vararg0", KonanLocalTest) { source = "lower/vararg.kt" } diff --git a/kotlin-native/backend.native/tests/runtime/basic/logging.kt b/kotlin-native/backend.native/tests/runtime/basic/logging.kt deleted file mode 100644 index 4b0c5c62cba..00000000000 --- a/kotlin-native/backend.native/tests/runtime/basic/logging.kt +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -fun main() {} diff --git a/kotlin-native/backend.native/tests/runtime/concurrent/worker_bound_reference0.kt b/kotlin-native/backend.native/tests/runtime/concurrent/worker_bound_reference0.kt deleted file mode 100644 index 12fb269feae..00000000000 --- a/kotlin-native/backend.native/tests/runtime/concurrent/worker_bound_reference0.kt +++ /dev/null @@ -1,847 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, FreezingIsDeprecated::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class) - -package runtime.concurrent.worker_bound_reference0 - -import kotlin.test.* - -import kotlin.concurrent.AtomicInt -import kotlin.concurrent.AtomicReference -import kotlin.native.concurrent.* -import kotlin.native.* -import kotlin.native.ref.WeakReference -import kotlin.native.runtime.GC -import kotlin.text.Regex - -class A(var a: Int) - -val global1: WorkerBoundReference = WorkerBoundReference(A(3)) - -@Test -fun testGlobal() { - assertEquals(3, global1.value.a) - assertEquals(3, global1.valueOrNull?.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, {}) { - global1 - } - - val value = future.result - assertEquals(3, value.value.a) - assertEquals(3, value.valueOrNull?.a) - worker.requestTermination().result -} - -val global2: WorkerBoundReference = WorkerBoundReference(A(3)) - -@Test -fun testGlobalAccessOnWorker() { - assertEquals(3, global2.value.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, {}) { - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - assertEquals(global2.value, global2.valueOrNull) - global2.value.a - } else { - val local = global2 - assertFailsWith { - local.value - } - assertEquals(null, local.valueOrNull) - null - } - } - - val value = future.result - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - assertEquals(3, value) - } else { - assertEquals(null, value) - } - worker.requestTermination().result -} - -val global3: WorkerBoundReference = WorkerBoundReference(A(3).freeze()) - -@Test -fun testGlobalAccessOnWorkerFrozenInitially() { - assertEquals(3, global3.value.a) - assertEquals(3, global3.valueOrNull?.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, {}) { - global3.value.a - } - - val value = future.result - assertEquals(3, value) - worker.requestTermination().result -} - -val global4: WorkerBoundReference = WorkerBoundReference(A(3)) - -@Test -fun testGlobalAccessOnWorkerFrozenBeforePassing() { - assertEquals(3, global4.value.a) - global4.value.freeze() - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, {}) { - global4.value.a - } - - val value = future.result - assertEquals(3, value) - worker.requestTermination().result -} - -val global5: WorkerBoundReference = WorkerBoundReference(A(3)) - -@Test -fun testGlobalAccessOnWorkerFrozenBeforeAccess() { - val semaphore: AtomicInt = AtomicInt(0) - - assertEquals(3, global5.value.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { semaphore }) { semaphore -> - semaphore.incrementAndGet() - while (semaphore.value < 2) { - } - - global5.value.a - } - - while (semaphore.value < 1) { - } - global5.value.freeze() - semaphore.incrementAndGet() - - val value = future.result - assertEquals(3, value) - worker.requestTermination().result -} - -val global6: WorkerBoundReference = WorkerBoundReference(A(3)) - -@Test -fun testGlobalModification() { - val semaphore: AtomicInt = AtomicInt(0) - - assertEquals(3, global6.value.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { semaphore }) { semaphore -> - semaphore.incrementAndGet() - while (semaphore.value < 2) { - } - global6 - } - - while (semaphore.value < 1) { - } - global6.value.a = 4 - semaphore.incrementAndGet() - - val value = future.result - assertEquals(4, value.value.a) - assertEquals(4, value.valueOrNull?.a) - worker.requestTermination().result -} - -val global7: WorkerBoundReference = WorkerBoundReference(A(3)) - -@Test -fun testGlobalGetWorker() { - val ownerId = Worker.current.id - assertEquals(ownerId, global7.worker.id) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { ownerId }) { ownerId -> - assertEquals(ownerId, global7.worker.id) - Unit - } - - future.result - worker.requestTermination().result -} - -@Test -fun testLocal() { - val local = WorkerBoundReference(A(3)) - assertEquals(3, local.value.a) - assertEquals(3, local.valueOrNull?.a) -} - -@Test -fun testLocalFrozen() { - val local = WorkerBoundReference(A(3)).freeze() - assertEquals(3, local.value.a) - assertEquals(3, local.valueOrNull?.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { local }) { local -> - local - } - - val value = future.result - assertEquals(3, value.value.a) - assertEquals(3, value.valueOrNull?.a) - worker.requestTermination().result -} - -@Test -fun testLocalAccessOnWorkerFrozen() { - val local = WorkerBoundReference(A(3)).freeze() - assertEquals(3, local.value.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { local }) { local -> - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - assertEquals(local.value, local.valueOrNull) - local.value.a - } else { - assertFailsWith { - local.value - } - assertEquals(null, local.valueOrNull) - null - } - } - - val value = future.result - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - assertEquals(3, value) - } else { - assertEquals(null, value) - } - worker.requestTermination().result -} - -@Test -fun testLocalAccessOnWorkerFrozenInitiallyFrozen() { - val local = WorkerBoundReference(A(3).freeze()).freeze() - assertEquals(3, local.value.a) - assertEquals(3, local.valueOrNull?.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { local }) { local -> - local.value.a - } - - val value = future.result - assertEquals(3, value) - worker.requestTermination().result -} - -@Test -fun testLocalAccessOnWorkerFrozenBeforePassingFrozen() { - val local = WorkerBoundReference(A(3)).freeze() - assertEquals(3, local.value.a) - local.value.freeze() - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { local }) { local -> - local.value.a - } - - val value = future.result - assertEquals(3, value) - worker.requestTermination().result -} - -@Test -fun testLocalAccessOnWorkerFrozenBeforeAccessFrozen() { - val semaphore: AtomicInt = AtomicInt(0) - - val local = WorkerBoundReference(A(3)).freeze() - assertEquals(3, local.value.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { Pair(local, semaphore) }) { (local, semaphore) -> - semaphore.incrementAndGet() - while (semaphore.value < 2) { - } - - local.value.a - } - - while (semaphore.value < 1) { - } - local.value.freeze() - semaphore.incrementAndGet() - - val value = future.result - assertEquals(3, value) - worker.requestTermination().result -} - -@Test -fun testLocalAccessOnMainThread() { - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, {}) { - WorkerBoundReference(A(3)) - } - - assertEquals(3, future.result.value.a) - - worker.requestTermination().result -} - -@Test -fun testLocalAccessOnMainThreadFrozen() { - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, {}) { - WorkerBoundReference(A(3)).freeze() - } - - val value = future.result - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - assertEquals(3, value.value.a) - assertEquals(value.value, value.valueOrNull) - } else { - assertFailsWith { - value.value - } - assertEquals(null, value.valueOrNull) - } - - worker.requestTermination().result -} - -@Test -fun testLocalModificationFrozen() { - val semaphore: AtomicInt = AtomicInt(0) - - val local = WorkerBoundReference(A(3)).freeze() - assertEquals(3, local.value.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { Pair(local, semaphore) }) { (local, semaphore) -> - semaphore.incrementAndGet() - while (semaphore.value < 2) { - } - local - } - - while (semaphore.value < 1) { - } - local.value.a = 4 - semaphore.incrementAndGet() - - val value = future.result - assertEquals(4, value.value.a) - assertEquals(4, value.valueOrNull?.a) - worker.requestTermination().result -} - -@Test -fun testLocalGetWorkerFrozen() { - val local = WorkerBoundReference(A(3)).freeze() - - val ownerId = Worker.current.id - assertEquals(ownerId, local.worker.id) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { Pair(local, ownerId) }) { (local, ownerId) -> - assertEquals(ownerId, local.worker.id) - Unit - } - - future.result - worker.requestTermination().result -} - -@Test -fun testLocalForeignGetWorker() { - val worker = Worker.start() - val ownerId = worker.id - val future = worker.execute(TransferMode.SAFE, { ownerId }) { ownerId -> - val local = WorkerBoundReference(A(3)) - assertEquals(ownerId, local.worker.id) - local - } - - val value = future.result - assertEquals(ownerId, value.worker.id) - - worker.requestTermination().result -} - -@Test -fun testLocalForeignGetWorkerFrozen() { - val worker = Worker.start() - val ownerId = worker.id - val future = worker.execute(TransferMode.SAFE, { ownerId }) { ownerId -> - val local = WorkerBoundReference(A(3)).freeze() - assertEquals(ownerId, local.worker.id) - local - } - - val value = future.result - assertEquals(ownerId, value.worker.id) - - worker.requestTermination().result -} - -class Wrapper(val ref: WorkerBoundReference) - -@Test -fun testLocalWithWrapperFrozen() { - val local = Wrapper(WorkerBoundReference(A(3))).freeze() - assertEquals(3, local.ref.value.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { local }) { local -> - local - } - - val value = future.result - assertEquals(3, value.ref.value.a) - worker.requestTermination().result -} - -@Test -fun testLocalAccessWithWrapperFrozen() { - val local = Wrapper(WorkerBoundReference(A(3))).freeze() - assertEquals(3, local.ref.value.a) - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, { local }) { local -> - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - assertEquals(local.ref.value, local.ref.valueOrNull) - local.ref.value.a - } else { - assertFailsWith { - local.ref.value - } - assertEquals(null, local.ref.valueOrNull) - null - } - } - - val value = future.result - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - assertEquals(3, value) - } else { - assertEquals(null, value) - } - worker.requestTermination().result -} - -fun getOwnerAndWeaks(initial: Int): Triple?>, WeakReference>, WeakReference> { - val ref = WorkerBoundReference(A(initial)) - val refOwner: AtomicReference?> = AtomicReference(ref) - val refWeak = WeakReference(ref) - val refValueWeak = WeakReference(ref.value) - - return Triple(refOwner, refWeak, refValueWeak) -} - -@Test -fun testCollect() { - val (refOwner, refWeak, refValueWeak) = getOwnerAndWeaks(3) - - refOwner.value = null - GC.collect() - - // Last reference to WorkerBoundReference is gone, so it and it's referent are destroyed. - assertNull(refWeak.value) - assertNull(refValueWeak.value) -} - -fun getOwnerAndWeaksFrozen(initial: Int): Triple?>, WeakReference>, WeakReference> { - val ref = WorkerBoundReference(A(initial)).freeze() - val refOwner: AtomicReference?> = AtomicReference(ref) - val refWeak = WeakReference(ref) - val refValueWeak = WeakReference(ref.value) - - return Triple(refOwner, refWeak, refValueWeak) -} - -@Test -fun testCollectFrozen() { - val (refOwner, refWeak, refValueWeak) = getOwnerAndWeaksFrozen(3) - - refOwner.value = null - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - // This runs the finalizer on the WorkerBoundReference, which schedules removing A from the root set - GC.collect() - // This actually frees A - GC.collect() - } else { - GC.collect() - } - - // Last reference to WorkerBoundReference is gone, so it and it's referent are destroyed. - assertNull(refWeak.value) - assertNull(refValueWeak.value) -} - -fun collectInWorkerFrozen(worker: Worker, semaphore: AtomicInt): Pair, Future> { - val (refOwner, _, refValueWeak) = getOwnerAndWeaksFrozen(3) - - val future = worker.execute(TransferMode.SAFE, { Pair(refOwner, semaphore) }) { (refOwner, semaphore) -> - semaphore.incrementAndGet() - while (semaphore.value < 2) { - } - - refOwner.value = null - GC.collect() - } - - while (semaphore.value < 1) { - } - // At this point worker is spinning on semaphore. refOwner still contains reference to - // WorkerBoundReference, so referent is kept alive. - GC.collect() - assertNotNull(refValueWeak.value) - - return Pair(refValueWeak, future) -} - -@Test -fun testCollectInWorkerFrozen() { - val semaphore: AtomicInt = AtomicInt(0) - - val worker = Worker.start() - - val (refValueWeak, future) = collectInWorkerFrozen(worker, semaphore) - semaphore.incrementAndGet() - future.result - - // At this point WorkerBoundReference no longer has a reference, so it's referent is destroyed. - GC.collect() - assertNull(refValueWeak.value) - - worker.requestTermination().result -} - -fun doNotCollectInWorkerFrozen(worker: Worker, semaphore: AtomicInt): Future> { - val ref = WorkerBoundReference(A(3)).freeze() - - return worker.execute(TransferMode.SAFE, { Pair(ref, semaphore) }) { (ref, semaphore) -> - semaphore.incrementAndGet() - while (semaphore.value < 2) { - } - - GC.collect() - ref - } -} - -@Test -fun testDoNotCollectInWorkerFrozen() { - val semaphore: AtomicInt = AtomicInt(0) - - val worker = Worker.start() - - val future = doNotCollectInWorkerFrozen(worker, semaphore) - while (semaphore.value < 1) { - } - GC.collect() - semaphore.incrementAndGet() - - val value = future.result - assertEquals(3, value.value.a) - worker.requestTermination().result -} - -class B1 { - lateinit var b2: WorkerBoundReference -} - -data class B2(val b1: WorkerBoundReference) - -fun createCyclicGarbage(): Triple?>, WeakReference, WeakReference> { - val ref1 = WorkerBoundReference(B1()) - val ref1Owner: AtomicReference?> = AtomicReference(ref1) - val ref1Weak = WeakReference(ref1.value) - - val ref2 = WorkerBoundReference(B2(ref1)) - val ref2Weak = WeakReference(ref2.value) - - ref1.value.b2 = ref2 - - return Triple(ref1Owner, ref1Weak, ref2Weak) -} - -@Test -fun collectCyclicGarbage() { - val (ref1Owner, ref1Weak, ref2Weak) = createCyclicGarbage() - - ref1Owner.value = null - GC.collect() - - assertNull(ref1Weak.value) - assertNull(ref2Weak.value) -} - -fun createCyclicGarbageFrozen(): Triple?>, WeakReference, WeakReference> { - val ref1 = WorkerBoundReference(B1()).freeze() - val ref1Owner: AtomicReference?> = AtomicReference(ref1) - val ref1Weak = WeakReference(ref1.value) - - val ref2 = WorkerBoundReference(B2(ref1)).freeze() - val ref2Weak = WeakReference(ref2.value) - - ref1.value.b2 = ref2 - - return Triple(ref1Owner, ref1Weak, ref2Weak) -} - -@Test -fun doesNotCollectCyclicGarbageFrozen() { - if (!Platform.isFreezingEnabled) return - val (ref1Owner, ref1Weak, ref2Weak) = createCyclicGarbageFrozen() - - ref1Owner.value = null - GC.collect() - - // If these asserts fail, that means WorkerBoundReference managed to clean up cyclic garbage all by itself. - assertNotNull(ref1Weak.value) - assertNotNull(ref2Weak.value) -} - -fun createCrossThreadCyclicGarbageFrozen( - worker: Worker -): Triple?>, WeakReference, WeakReference> { - val ref1 = WorkerBoundReference(B1()).freeze() - val ref1Owner: AtomicReference?> = AtomicReference(ref1) - val ref1Weak = WeakReference(ref1.value) - - val future = worker.execute(TransferMode.SAFE, { ref1 }) { ref1 -> - val ref2 = WorkerBoundReference(B2(ref1)).freeze() - Pair(ref2, WeakReference(ref2.value)) - } - val (ref2, ref2Weak) = future.result - - ref1.value.b2 = ref2 - - return Triple(ref1Owner, ref1Weak, ref2Weak) -} - -@Test -fun doesNotCollectCrossThreadCyclicGarbageFrozen() { - if (!Platform.isFreezingEnabled) return - val worker = Worker.start() - - val (ref1Owner, ref1Weak, ref2Weak) = createCrossThreadCyclicGarbageFrozen(worker) - - ref1Owner.value = null - GC.collect() - worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result - - // If these asserts fail, that means WorkerBoundReference managed to clean up cyclic garbage all by itself. - assertNotNull(ref1Weak.value) - assertNotNull(ref2Weak.value) - - worker.requestTermination().result -} - -class C1 { - lateinit var c2: AtomicReference?> - - fun dispose() { - c2.value = null - } -} - -data class C2(val c1: AtomicReference>) - -fun createCyclicGarbageWithAtomicsFrozen(): Triple?>, WeakReference, WeakReference> { - val ref1 = WorkerBoundReference(C1()).freeze() - val ref1Weak = WeakReference(ref1.value) - - val ref2 = WorkerBoundReference(C2(AtomicReference(ref1))).freeze() - val ref2Weak = WeakReference(ref2.value) - - ref1.value.c2 = AtomicReference(ref2) - - return Triple(AtomicReference(ref1), ref1Weak, ref2Weak) -} - -fun dispose(refOwner: AtomicReference?>) { - refOwner.value!!.value.dispose() - refOwner.value = null -} - -@Test -fun doesNotCollectCyclicGarbageWithAtomicsFrozen() { - if (!Platform.isFreezingEnabled) return - val (ref1Owner, ref1Weak, ref2Weak) = createCyclicGarbageWithAtomicsFrozen() - - ref1Owner.value = null - GC.collect() - - // If these asserts fail, that means AtomicReference managed to clean up cyclic garbage all by itself. - assertNotNull(ref1Weak.value) - assertNotNull(ref2Weak.value) -} - -@Test -fun collectCyclicGarbageWithAtomicsFrozen() { - val (ref1Owner, ref1Weak, ref2Weak) = createCyclicGarbageWithAtomicsFrozen() - - dispose(ref1Owner) - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - // Finalizes WorkerBoundReference and schedules C2 removal from the root set - GC.collect() - // Frees C2, finalizes WorkerBoundReference and schedules C1 removal from the root set - GC.collect() - // Frees C1 - GC.collect() - } else { - GC.collect() - } - - assertNull(ref1Weak.value) - assertNull(ref2Weak.value) -} - -fun createCrossThreadCyclicGarbageWithAtomicsFrozen( - worker: Worker -): Triple?>, WeakReference, WeakReference> { - val ref1 = WorkerBoundReference(C1()).freeze() - val ref1Weak = WeakReference(ref1.value) - - val future = worker.execute(TransferMode.SAFE, { ref1 }) { ref1 -> - val ref2 = WorkerBoundReference(C2(AtomicReference(ref1))).freeze() - Pair(ref2, WeakReference(ref2.value)) - } - val (ref2, ref2Weak) = future.result - - ref1.value.c2 = AtomicReference(ref2) - - return Triple(AtomicReference(ref1), ref1Weak, ref2Weak) -} - -@Test -fun doesNotCollectCrossThreadCyclicGarbageWithAtomicsFrozen() { - if (!Platform.isFreezingEnabled) return - val worker = Worker.start() - - val (ref1Owner, ref1Weak, ref2Weak) = createCrossThreadCyclicGarbageWithAtomicsFrozen(worker) - - ref1Owner.value = null - GC.collect() - worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result - - // If these asserts fail, that means AtomicReference managed to clean up cyclic garbage all by itself. - assertNotNull(ref1Weak.value) - assertNotNull(ref2Weak.value) - - worker.requestTermination().result -} - -@Test -fun collectCrossThreadCyclicGarbageWithAtomicsFrozen() { - val worker = Worker.start() - - val (ref1Owner, ref1Weak, ref2Weak) = createCrossThreadCyclicGarbageWithAtomicsFrozen(worker) - - dispose(ref1Owner) - // This marks C2 as gone on the main thread - GC.collect() - // This cleans up all the references from the worker thread and destroys C2, but C1 is still alive. - worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result - // And this finally destroys C1 - GC.collect() - - assertNull(ref1Weak.value) - assertNull(ref2Weak.value) - - worker.requestTermination().result -} - -@Test -fun concurrentAccessFrozen() { - val workerCount = 10 - val workerUnlocker = AtomicInt(0) - - val ref = WorkerBoundReference(A(3)).freeze() - assertEquals(3, ref.value.a) - - val workers = Array(workerCount) { - Worker.start() - } - val futures = Array(workers.size) { - workers[it].execute(TransferMode.SAFE, { Pair(ref, workerUnlocker) }) { (ref, workerUnlocker) -> - while (workerUnlocker.value < 1) { - } - - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - ref.value.a - } else { - assertFailsWith { - ref.value - } - null - } - } - } - workerUnlocker.incrementAndGet() - - for (future in futures) { - val value = future.result - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - assertEquals(3, value) - } else { - assertEquals(null, value) - } - } - - for (worker in workers) { - worker.requestTermination().result - } -} - -@Test -fun testExceptionMessageFrozen() { - // Only for legacy MM - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - return - } - - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, {}) { - WorkerBoundReference(A(3)).freeze() - } - val value = future.result - - val ownerName = worker.name - val messagePattern = Regex("illegal attempt to access non-shared runtime\\.concurrent\\.worker_bound_reference0\\.A@[a-f0-9]+ bound to `$ownerName` from `${Worker.current.name}`") - - val exception = assertFailsWith { - value.value - } - assertTrue(messagePattern matches exception.message!!) - - worker.requestTermination().result -} - -@Test -fun testDoubleFreeze() { - val ref = WorkerBoundReference(A(3)) - val wrapper = Wrapper(ref) - ref.freeze() - ref.freeze() - wrapper.freeze() -} - -@Test -fun testDoubleFreezeWithFreezeBlocker() { - if (!Platform.isFreezingEnabled) return - val ref = WorkerBoundReference(A(3)) - val wrapper = Wrapper(ref) - wrapper.ensureNeverFrozen() - assertFailsWith { - wrapper.freeze() - } - ref.freeze() -} diff --git a/kotlin-native/backend.native/tests/runtime/memory/basic0.kt b/kotlin-native/backend.native/tests/runtime/memory/basic0.kt deleted file mode 100644 index 3fce09e781d..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/basic0.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package runtime.memory.basic0 - -import kotlin.test.* - -class A { - var field: B? = null -} - -class B(var field: Int) - -@Test fun runTest() { - val a = A() - a.field = B(2) -} diff --git a/kotlin-native/backend.native/tests/runtime/memory/cycles0.out b/kotlin-native/backend.native/tests/runtime/memory/cycles0.out deleted file mode 100644 index d81cc0710eb..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/cycles0.out +++ /dev/null @@ -1 +0,0 @@ -42 diff --git a/kotlin-native/backend.native/tests/runtime/memory/cycles1.kt b/kotlin-native/backend.native/tests/runtime/memory/cycles1.kt deleted file mode 100644 index 1f43c3a8fdb..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/cycles1.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) - -package runtime.memory.cycles1 - -import kotlin.test.* -import kotlin.native.ref.* - -@OptIn(kotlin.native.runtime.NativeRuntimeApi::class) -@Test fun runTest() { - // TODO: make it work in relaxed model as well. - if (Platform.memoryModel == MemoryModel.RELAXED) return - val weakRefToTrashCycle = createLoop() - kotlin.native.runtime.GC.collect() - assertNull(weakRefToTrashCycle.get()) -} - -private fun createLoop(): WeakReference { - val loop = Array(1, { null }) - loop[0] = loop - - return WeakReference(loop) -} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/memory/escape1.kt b/kotlin-native/backend.native/tests/runtime/memory/escape1.kt deleted file mode 100644 index 07c516aa6a7..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/escape1.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package runtime.memory.escape1 - -import kotlin.test.* - -class B(val s: String) - -class A { - val b = B("zzz") -} - -fun foo(): B { - val a = A() - return a.b -} - -@Test fun runTest() { - println(foo().s) -} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/memory/escape1.out b/kotlin-native/backend.native/tests/runtime/memory/escape1.out deleted file mode 100644 index b1a17ba1369..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/escape1.out +++ /dev/null @@ -1 +0,0 @@ -zzz diff --git a/kotlin-native/backend.native/tests/runtime/memory/escape2.out b/kotlin-native/backend.native/tests/runtime/memory/escape2.out deleted file mode 100644 index b1a17ba1369..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/escape2.out +++ /dev/null @@ -1 +0,0 @@ -zzz diff --git a/kotlin-native/backend.native/tests/runtime/memory/only_gc.kt b/kotlin-native/backend.native/tests/runtime/memory/only_gc.kt deleted file mode 100644 index 97349d58cf3..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/only_gc.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ -@OptIn(kotlin.native.runtime.NativeRuntimeApi::class) -fun main(args: Array) { - kotlin.native.runtime.GC.collect() -} - diff --git a/kotlin-native/backend.native/tests/runtime/memory/throw_cleanup.kt b/kotlin-native/backend.native/tests/runtime/memory/throw_cleanup.kt deleted file mode 100644 index d96bb6ce00c..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/throw_cleanup.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package runtime.memory.throw_cleanup - -import kotlin.test.* - -@Test fun runTest() { - foo(false) - try { - foo(true) - } catch (e: Error) { - println("Ok") - } -} - -fun foo(b: Boolean): Any { - var result = Any() - if (b) { - throw Error() - } - return result -} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/memory/throw_cleanup.out b/kotlin-native/backend.native/tests/runtime/memory/throw_cleanup.out deleted file mode 100644 index 7326d960397..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/throw_cleanup.out +++ /dev/null @@ -1 +0,0 @@ -Ok diff --git a/kotlin-native/backend.native/tests/runtime/memory/weak0.out b/kotlin-native/backend.native/tests/runtime/memory/weak0.out deleted file mode 100644 index 39ec2141cb3..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/weak0.out +++ /dev/null @@ -1,3 +0,0 @@ -Data(s=Hello) -null -OK diff --git a/kotlin-native/backend.native/tests/runtime/memory/weak1.kt b/kotlin-native/backend.native/tests/runtime/memory/weak1.kt deleted file mode 100644 index 813b0e0c09e..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/weak1.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) - -package runtime.memory.weak1 - -import kotlin.test.* -import kotlin.native.ref.* - -class Node(var next: Node?) - -@Test fun runTest1() { - val node1 = Node(null) - val node2 = Node(node1) - node1.next = node2 - - kotlin.native.ref.WeakReference(node1) - println("OK") -} diff --git a/kotlin-native/backend.native/tests/runtime/memory/weak1.out b/kotlin-native/backend.native/tests/runtime/memory/weak1.out deleted file mode 100644 index d86bac9de59..00000000000 --- a/kotlin-native/backend.native/tests/runtime/memory/weak1.out +++ /dev/null @@ -1 +0,0 @@ -OK diff --git a/kotlin-native/backend.native/tests/runtime/workers/enum_identity.kt b/kotlin-native/backend.native/tests/runtime/workers/enum_identity.kt deleted file mode 100644 index 2bf9c2bddb8..00000000000 --- a/kotlin-native/backend.native/tests/runtime/workers/enum_identity.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -@file:OptIn(ObsoleteWorkersApi::class) -package runtime.workers.enum_identity - -import kotlin.test.* -import kotlin.native.concurrent.* - -enum class A { - A, B -} - -data class Foo(val kind: A) - -// Enums are shared between threads so identity should be kept. -@Test -fun runTest() { - val result = Worker.start().execute(TransferMode.SAFE, { Foo(A.B) }, { input -> - input.kind == A.B - }).result - println(result) -} diff --git a/kotlin-native/backend.native/tests/runtime/workers/enum_identity.out b/kotlin-native/backend.native/tests/runtime/workers/enum_identity.out deleted file mode 100644 index 27ba77ddaf6..00000000000 --- a/kotlin-native/backend.native/tests/runtime/workers/enum_identity.out +++ /dev/null @@ -1 +0,0 @@ -true diff --git a/kotlin-native/backend.native/tests/runtime/workers/freeze_disabled.kt b/kotlin-native/backend.native/tests/runtime/workers/freeze_disabled.kt deleted file mode 100644 index 35d6beceae4..00000000000 --- a/kotlin-native/backend.native/tests/runtime/workers/freeze_disabled.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ -@file:OptIn(FreezingIsDeprecated::class) - -package runtime.workers.freeze_disabled - -import kotlin.test.* -import kotlin.native.concurrent.* - -// this test is ran with disabled freezing, so no mutability checks are done - -class A(var x:Int) - -@Test -fun testClassNotFrozen(){ - val a = A(1) - a.freeze() - a.x = 2 - assertEquals(a.x, 2) -} - -@Test -fun testArrayNotFrozen(){ - val a = arrayOf(1, 2, 3, 4, 5) - a.freeze() - a[0] = 6 - assertEquals(a[0], 6) -} diff --git a/kotlin-native/backend.native/tests/runtime/workers/lazy2.kt b/kotlin-native/backend.native/tests/runtime/workers/lazy2.kt deleted file mode 100644 index 4cb2e70829a..00000000000 --- a/kotlin-native/backend.native/tests/runtime/workers/lazy2.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ -import kotlin.test.* - -object Foo { - val bar = Bar() -} - -class Bar { - val f by lazy { - foo() - } - - fun foo() = 123 -} - -fun printAll() { - println(Foo.bar.f) -} - -// This test is extracted from the real problem found in kotlinx.serialization, where zeroing out -// initializer field in frozen lazy object led to the crash, induced by breaking frozen objects' -// invariant (initializer end up in the same container as the lazy object itself, so it was destroyed -// earlier than it should when reference counter was decremented). -@OptIn(kotlin.native.runtime.NativeRuntimeApi::class) -fun main(args: Array) { - printAll() - kotlin.native.runtime.GC.collect() - println("OK") -} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/workers/lazy2.out b/kotlin-native/backend.native/tests/runtime/workers/lazy2.out deleted file mode 100644 index f49db2498c6..00000000000 --- a/kotlin-native/backend.native/tests/runtime/workers/lazy2.out +++ /dev/null @@ -1,2 +0,0 @@ -123 -OK diff --git a/kotlin-native/backend.native/tests/runtime/workers/lazy3.kt b/kotlin-native/backend.native/tests/runtime/workers/lazy3.kt deleted file mode 100644 index 8b33cf19daa..00000000000 --- a/kotlin-native/backend.native/tests/runtime/workers/lazy3.kt +++ /dev/null @@ -1,56 +0,0 @@ -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, FreezingIsDeprecated::class, kotlin.native.runtime.NativeRuntimeApi::class) - -import kotlin.native.concurrent.* -import kotlin.native.ref.* -import kotlin.test.* - -fun main() { - test1() - test2() -} - -fun test1() { - ensureGetsCollectedFrozenAndNotFrozen { LazyCapturesThis() } - ensureGetsCollectedFrozenAndNotFrozen { - val l = LazyCapturesThis() - l.bar - l - } - ensureGetsCollected { - val l = LazyCapturesThis().freeze() - l.bar - l - } -} - -class LazyCapturesThis { - fun foo() = 42 - val bar by lazy { foo() } -} - -fun test2() { - ensureGetsCollectedFrozenAndNotFrozen { Throwable() } - ensureGetsCollectedFrozenAndNotFrozen { - val throwable = Throwable() - throwable.getStackTrace() - throwable - } - ensureGetsCollected { - val throwable = Throwable().freeze() - throwable.getStackTrace() - throwable - } -} - -fun ensureGetsCollectedFrozenAndNotFrozen(create: () -> Any) { - ensureGetsCollected { create().freeze() } - ensureGetsCollected(create) -} - -fun ensureGetsCollected(create: () -> Any) { - val ref = makeWeakRef(create) - kotlin.native.runtime.GC.collect() - assertNull(ref.get()) -} - -fun makeWeakRef(create: () -> Any) = WeakReference(create()) \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/workers/mutableData1.kt b/kotlin-native/backend.native/tests/runtime/workers/mutableData1.kt deleted file mode 100644 index 9de286fb158..00000000000 --- a/kotlin-native/backend.native/tests/runtime/workers/mutableData1.kt +++ /dev/null @@ -1,48 +0,0 @@ -@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class) -package runtime.workers.mutableData1 - -import kotlin.native.concurrent.* -import kotlin.test.* - -// See https://youtrack.jetbrains.com/issue/KT-39145 -@Test -fun kt39145_1() = withWorker { - execute(TransferMode.SAFE, { "test" }) { - val data = MutableData(1_000) - val bytes = byteArrayOf(0, 10, 20, 30) - data.append(bytes, 0, 4) - assertEquals(4, data.size) - - assertContentsEquals(bytes, data) - }.result -} - -@Test -fun kt39145_2() = withWorker { - val externalData = MutableData(1_000) - execute(TransferMode.SAFE, { externalData }) { - val bytes = byteArrayOf(0, 10, 20, 30) - it.append(bytes, 0, 4) - assertEquals(4, it.size) - - assertContentsEquals(bytes, it) - }.result -} - -@Test -fun kt39145_3() { - val mainThreadData = MutableData(1_000) - val bytes = byteArrayOf(0, 10, 20, 30) - mainThreadData.append(bytes, 0, 4) - assertEquals(4, mainThreadData.size) - - assertContentsEquals(bytes, mainThreadData) -} - -private fun assertContentsEquals(expected: ByteArray, actual: MutableData) { - assertEquals(expected.size, actual.size) - - expected.forEachIndexed { index, byte -> - assertEquals(byte, actual.get(index)) - } -} diff --git a/kotlin-native/backend.native/tests/runtime/workers/worker5.out b/kotlin-native/backend.native/tests/runtime/workers/worker5.out deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions.kt b/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions.kt deleted file mode 100644 index d4d1458dcbe..00000000000 --- a/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions.kt +++ /dev/null @@ -1,40 +0,0 @@ -@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class) - -package runtime.workers.worker_exceptions - -import kotlin.test.* - -import kotlin.native.concurrent.* - -@Test -fun testExecuteAfterStartQuiet() { - val worker = Worker.start(errorReporting = false) - worker.executeAfter(0L, { - throw Error("testExecuteAfterStartQuiet error") - }.freeze()) - worker.requestTermination().result -} - -@Test -fun testExecuteStart() { - val worker = Worker.start() - val future = worker.execute(TransferMode.SAFE, {}) { - throw Error("testExecuteStart error") - } - assertFailsWith { - future.result - } - worker.requestTermination().result -} - -@Test -fun testExecuteStartQuiet() { - val worker = Worker.start(errorReporting = false) - val future = worker.execute(TransferMode.SAFE, {}) { - throw Error("testExecuteStartQuiet error") - } - assertFailsWith { - future.result - } - worker.requestTermination().result -} diff --git a/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate_hook.kt b/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate_hook.kt deleted file mode 100644 index 5ff0a1ecc16..00000000000 --- a/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate_hook.kt +++ /dev/null @@ -1,17 +0,0 @@ -@file:OptIn(FreezingIsDeprecated::class, kotlin.experimental.ExperimentalNativeApi::class, ObsoleteWorkersApi::class) - -import kotlin.native.concurrent.* - -fun main() { - setUnhandledExceptionHook({ _: Throwable -> - println("hook called") - }.freeze()) - - - val worker = Worker.start() - worker.executeAfter(0L, { - throw Error("some error") - }.freeze()) - worker.requestTermination().result - println("Will happen") -} diff --git a/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate_hook_current.kt b/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate_hook_current.kt deleted file mode 100644 index 4df744caa7c..00000000000 --- a/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate_hook_current.kt +++ /dev/null @@ -1,15 +0,0 @@ -@file:OptIn(FreezingIsDeprecated::class, kotlin.experimental.ExperimentalNativeApi::class, ObsoleteWorkersApi::class) - -import kotlin.native.concurrent.* - -fun main() { - setUnhandledExceptionHook({ _: Throwable -> - println("hook called") - }.freeze()) - - Worker.current.executeAfter(0L, { - throw Error("some error") - }.freeze()) - Worker.current.processQueue() - println("Will happen") -} diff --git a/kotlin-native/runtime/test/native/concurrent/FreezingTest.kt b/kotlin-native/runtime/test/native/concurrent/FreezingTest.kt new file mode 100644 index 00000000000..858a66df2b9 --- /dev/null +++ b/kotlin-native/runtime/test/native/concurrent/FreezingTest.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package test.native.concurrent + +import kotlin.native.concurrent.* +import kotlin.test.* + +private class A(var x: Int) + +@OptIn(FreezingIsDeprecated::class) +class FreezingTest { + @Test + fun freezeIsNoopForObjects() { + val a = A(1) + a.freeze() + a.x = 2 + assertEquals(2, a.x) + } + + @Test + fun freezeIsNoopForArrays() { + val a = arrayOf(1, 2, 3) + a.freeze() + a[0] = 4 + assertContentEquals(arrayOf(4, 2, 3), a) + } + + @Test + fun freezeIsNoopForPrimitiveArrays() { + val a = intArrayOf(1, 2, 3) + a.freeze() + a[0] = 4 + assertContentEquals(intArrayOf(4, 2, 3), a) + } +} \ No newline at end of file diff --git a/kotlin-native/runtime/test/native/concurrent/MutableDataTest.kt b/kotlin-native/runtime/test/native/concurrent/MutableDataTest.kt new file mode 100644 index 00000000000..a82fe1452ce --- /dev/null +++ b/kotlin-native/runtime/test/native/concurrent/MutableDataTest.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package test.native.concurrent + +import kotlin.native.concurrent.* +import kotlin.test.* + +@OptIn(FreezingIsDeprecated::class) +private fun assertContentsEquals(expected: ByteArray, actual: MutableData) { + assertEquals(expected.size, actual.size) + + expected.forEachIndexed { index, byte -> + assertEquals(byte, actual.get(index)) + } +} + +@OptIn(FreezingIsDeprecated::class) +class MutableDataTest { + // See https://youtrack.jetbrains.com/issue/KT-39145 + @Test + fun kt39145_1() = withWorker { + execute(TransferMode.SAFE, { "test" }) { + val data = MutableData(1_000) + val bytes = byteArrayOf(0, 10, 20, 30) + data.append(bytes, 0, 4) + assertEquals(4, data.size) + + assertContentsEquals(bytes, data) + }.result + } + + @Test + fun kt39145_2() = withWorker { + val externalData = MutableData(1_000) + execute(TransferMode.SAFE, { externalData }) { + val bytes = byteArrayOf(0, 10, 20, 30) + it.append(bytes, 0, 4) + assertEquals(4, it.size) + + assertContentsEquals(bytes, it) + }.result + } + + @Test + fun kt39145_3() { + val mainThreadData = MutableData(1_000) + val bytes = byteArrayOf(0, 10, 20, 30) + mainThreadData.append(bytes, 0, 4) + assertEquals(4, mainThreadData.size) + + assertContentsEquals(bytes, mainThreadData) + } +} \ No newline at end of file diff --git a/kotlin-native/runtime/test/native/concurrent/WorkerBoundReference.kt b/kotlin-native/runtime/test/native/concurrent/WorkerBoundReference.kt new file mode 100644 index 00000000000..29638255d31 --- /dev/null +++ b/kotlin-native/runtime/test/native/concurrent/WorkerBoundReference.kt @@ -0,0 +1,418 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +@file:OptIn(FreezingIsDeprecated::class) +package test.native.concurrent + +import kotlin.concurrent.AtomicInt +import kotlin.native.concurrent.* +import kotlin.native.concurrent.WorkerBoundReference +import kotlin.test.* + +private class C(var a: Int) +private class Wrapper(val ref: WorkerBoundReference) + +private val global1: WorkerBoundReference = WorkerBoundReference(C(3)) +private val global2: WorkerBoundReference = WorkerBoundReference(C(3)) +private val global3: WorkerBoundReference = WorkerBoundReference(C(3).freeze()) +private val global4: WorkerBoundReference = WorkerBoundReference(C(3)) +private val global5: WorkerBoundReference = WorkerBoundReference(C(3)) +private val global6: WorkerBoundReference = WorkerBoundReference(C(3)) +private val global7: WorkerBoundReference = WorkerBoundReference(C(3)) + +class WorkerBoundReference { + @Test + fun global() { + assertEquals(3, global1.value.a) + assertEquals(3, global1.valueOrNull?.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, {}) { + global1 + } + + val value = future.result + assertEquals(3, value.value.a) + assertEquals(3, value.valueOrNull?.a) + worker.requestTermination().result + } + + @Test + fun globalOnWorker() { + assertEquals(3, global2.value.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, {}) { + assertEquals(global2.value, global2.valueOrNull) + global2.value.a + } + + val value = future.result + assertEquals(3, value) + worker.requestTermination().result + } + + @Test + fun globalOnWorkerFrozenInitially() { + assertEquals(3, global3.value.a) + assertEquals(3, global3.valueOrNull?.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, {}) { + global3.value.a + } + + val value = future.result + assertEquals(3, value) + worker.requestTermination().result + } + + @Test + fun globalOnWorkerFrozenBeforePassing() { + assertEquals(3, global4.value.a) + global4.value.freeze() + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, {}) { + global4.value.a + } + + val value = future.result + assertEquals(3, value) + worker.requestTermination().result + } + + @Test + fun globalOnWorkerFrozenBeforeAccess() { + val semaphore = AtomicInt(0) + + assertEquals(3, global5.value.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { semaphore }) { semaphore -> + semaphore.incrementAndGet() + while (semaphore.value < 2) { + } + + global5.value.a + } + + while (semaphore.value < 1) { + } + global5.value.freeze() + semaphore.incrementAndGet() + + val value = future.result + assertEquals(3, value) + worker.requestTermination().result + } + + @Test + fun globalModification() { + val semaphore = AtomicInt(0) + + assertEquals(3, global6.value.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { semaphore }) { semaphore -> + semaphore.incrementAndGet() + while (semaphore.value < 2) { + } + global6 + } + + while (semaphore.value < 1) { + } + global6.value.a = 4 + semaphore.incrementAndGet() + + val value = future.result + assertEquals(4, value.value.a) + assertEquals(4, value.valueOrNull?.a) + worker.requestTermination().result + } + + @Test + fun globalGetWorker() { + val ownerId = Worker.current.id + assertEquals(ownerId, global7.worker.id) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { ownerId }) { ownerId -> + assertEquals(ownerId, global7.worker.id) + } + + future.result + worker.requestTermination().result + } + + @Test + fun local() { + val local = WorkerBoundReference(C(3)) + assertEquals(3, local.value.a) + assertEquals(3, local.valueOrNull?.a) + } + + @Test + fun localFrozen() { + val local = WorkerBoundReference(C(3)).freeze() + assertEquals(3, local.value.a) + assertEquals(3, local.valueOrNull?.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { local }) { local -> + local + } + + val value = future.result + assertEquals(3, value.value.a) + assertEquals(3, value.valueOrNull?.a) + worker.requestTermination().result + } + + @Test + fun localOnWorkerFrozen() { + val local = WorkerBoundReference(C(3)).freeze() + assertEquals(3, local.value.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { local }) { local -> + assertEquals(local.value, local.valueOrNull) + local.value.a + } + + val value = future.result + assertEquals(3, value) + worker.requestTermination().result + } + + @Test + fun localOnWorkerFrozenInitiallyFrozen() { + val local = WorkerBoundReference(C(3).freeze()).freeze() + assertEquals(3, local.value.a) + assertEquals(3, local.valueOrNull?.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { local }) { local -> + local.value.a + } + + val value = future.result + assertEquals(3, value) + worker.requestTermination().result + } + + @Test + fun localOnWorkerFrozenBeforePassingFrozen() { + val local = WorkerBoundReference(C(3)).freeze() + assertEquals(3, local.value.a) + local.value.freeze() + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { local }) { local -> + local.value.a + } + + val value = future.result + assertEquals(3, value) + worker.requestTermination().result + } + + @Test + fun localOnWorkerFrozenBeforeAccessFrozen() { + val semaphore = AtomicInt(0) + + val local = WorkerBoundReference(C(3)).freeze() + assertEquals(3, local.value.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { Pair(local, semaphore) }) { (local, semaphore) -> + semaphore.incrementAndGet() + while (semaphore.value < 2) { + } + + local.value.a + } + + while (semaphore.value < 1) { + } + local.value.freeze() + semaphore.incrementAndGet() + + val value = future.result + assertEquals(3, value) + worker.requestTermination().result + } + + @Test + fun localOnMainThread() { + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, {}) { + WorkerBoundReference(C(3)) + } + + assertEquals(3, future.result.value.a) + + worker.requestTermination().result + } + + @Test + fun localOnMainThreadFrozen() { + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, {}) { + WorkerBoundReference(C(3)).freeze() + } + + val value = future.result + assertEquals(3, value.value.a) + assertEquals(value.value, value.valueOrNull) + + worker.requestTermination().result + } + + @Test + fun localModificationFrozen() { + val semaphore = AtomicInt(0) + + val local = WorkerBoundReference(C(3)).freeze() + assertEquals(3, local.value.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { Pair(local, semaphore) }) { (local, semaphore) -> + semaphore.incrementAndGet() + while (semaphore.value < 2) { + } + local + } + + while (semaphore.value < 1) { + } + local.value.a = 4 + semaphore.incrementAndGet() + + val value = future.result + assertEquals(4, value.value.a) + assertEquals(4, value.valueOrNull?.a) + worker.requestTermination().result + } + + @Test + fun localGetWorkerFrozen() { + val local = WorkerBoundReference(C(3)).freeze() + + val ownerId = Worker.current.id + assertEquals(ownerId, local.worker.id) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { Pair(local, ownerId) }) { (local, ownerId) -> + assertEquals(ownerId, local.worker.id) + } + + future.result + worker.requestTermination().result + } + + @Test + fun localForeignGetWorker() { + val worker = Worker.start() + val ownerId = worker.id + val future = worker.execute(TransferMode.SAFE, { ownerId }) { ownerId -> + val local = WorkerBoundReference(C(3)) + assertEquals(ownerId, local.worker.id) + local + } + + val value = future.result + assertEquals(ownerId, value.worker.id) + + worker.requestTermination().result + } + + @Test + fun localForeignGetWorkerFrozen() { + val worker = Worker.start() + val ownerId = worker.id + val future = worker.execute(TransferMode.SAFE, { ownerId }) { ownerId -> + val local = WorkerBoundReference(C(3)).freeze() + assertEquals(ownerId, local.worker.id) + local + } + + val value = future.result + assertEquals(ownerId, value.worker.id) + + worker.requestTermination().result + } + + @Test + fun localWithWrapperFrozen() { + val local = Wrapper(WorkerBoundReference(C(3))).freeze() + assertEquals(3, local.ref.value.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { local }) { local -> + local + } + + val value = future.result + assertEquals(3, value.ref.value.a) + worker.requestTermination().result + } + + @Test + fun localAccessWithWrapperFrozen() { + val local = Wrapper(WorkerBoundReference(C(3))).freeze() + assertEquals(3, local.ref.value.a) + + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, { local }) { local -> + assertEquals(local.ref.value, local.ref.valueOrNull) + local.ref.value.a + } + + val value = future.result + assertEquals(3, value) + worker.requestTermination().result + } + + @Test + fun concurrentAccessFrozen() { + val workerCount = 10 + val workerUnlocker = AtomicInt(0) + + val ref = WorkerBoundReference(C(3)).freeze() + assertEquals(3, ref.value.a) + + val workers = Array(workerCount) { + Worker.start() + } + val futures = Array(workers.size) { + workers[it].execute(TransferMode.SAFE, { Pair(ref, workerUnlocker) }) { (ref, workerUnlocker) -> + while (workerUnlocker.value < 1) { + } + + ref.value.a + } + } + workerUnlocker.incrementAndGet() + + for (future in futures) { + val value = future.result + assertEquals(3, value) + } + + for (worker in workers) { + worker.requestTermination().result + } + } + + @Test + fun doubleFreeze() { + val ref = WorkerBoundReference(C(3)) + val wrapper = Wrapper(ref) + ref.freeze() + ref.freeze() + wrapper.freeze() + } +} \ No newline at end of file diff --git a/native/native.tests/build.gradle.kts b/native/native.tests/build.gradle.kts index d523fbd4163..d3821b17d2f 100644 --- a/native/native.tests/build.gradle.kts +++ b/native/native.tests/build.gradle.kts @@ -56,6 +56,7 @@ val debuggerTest = nativeTest("debuggerTest", "debugger") val cachesTest = nativeTest("cachesTest", "caches") val klibTest = nativeTest("klibTest", "klib") val standaloneTest = nativeTest("standaloneTest", "standalone") +val gcTest = nativeTest("gcTest", "gc") val testTags = findProperty("kotlin.native.tests.tags")?.toString() // Note: arbitrary JUnit tag expressions can be used in this property. diff --git a/kotlin-native/backend.native/tests/runtime/memory/array_out_of_memory.kt b/native/native.tests/stress/testData/array_out_of_memory.kt similarity index 74% rename from kotlin-native/backend.native/tests/runtime/memory/array_out_of_memory.kt rename to native/native.tests/stress/testData/array_out_of_memory.kt index 216918ceebf..1f350c614c7 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/array_out_of_memory.kt +++ b/native/native.tests/stress/testData/array_out_of_memory.kt @@ -1,8 +1,5 @@ -/* - * Copyright 2010-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - +// This test allocs a large array that may make Linux kill any process inlcuding Gradle with OOM-killer +// DISABLE_NATIVE: targetFamily=LINUX import kotlin.test.* fun testArrayAllocation(size: Int) { diff --git a/kotlin-native/backend.native/tests/runtime/memory/stress_gc_allocations.kt b/native/native.tests/stress/testData/stress_gc_allocations.kt similarity index 93% rename from kotlin-native/backend.native/tests/runtime/memory/stress_gc_allocations.kt rename to native/native.tests/stress/testData/stress_gc_allocations.kt index 43313b3d1da..e7f776b7ce9 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/stress_gc_allocations.kt +++ b/native/native.tests/stress/testData/stress_gc_allocations.kt @@ -1,7 +1,8 @@ -/* - * Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ +// KIND: STANDALONE_NO_TR +// DISABLE_NATIVE: gcType=NOOP +// DISABLE_NATIVE: gcScheduler=AGGRESSIVE +// The test checks GC, we need to allocate everything on the heap. +// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative -Xdisable-phases=EscapeAnalysis @file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, kotlin.native.concurrent.ObsoleteWorkersApi::class) import kotlin.concurrent.AtomicInt diff --git a/native/native.tests/stress/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStressTestGenerated.java b/native/native.tests/stress/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStressTestGenerated.java index 7e3df6b161f..21397c8525d 100644 --- a/native/native.tests/stress/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStressTestGenerated.java +++ b/native/native.tests/stress/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStressTestGenerated.java @@ -7,8 +7,10 @@ package org.jetbrains.kotlin.konan.test.blackbox; import com.intellij.testFramework.TestDataPath; import org.jetbrains.kotlin.test.util.KtTestUtil; -import org.jetbrains.kotlin.konan.test.blackbox.support.group.UseStandardTestCaseGroupProvider; import org.junit.jupiter.api.Tag; +import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty; +import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty; +import org.jetbrains.kotlin.konan.test.blackbox.support.group.UseStandardTestCaseGroupProvider; import org.jetbrains.kotlin.konan.test.blackbox.support.group.FirPipeline; import org.jetbrains.kotlin.test.TestMetadata; import org.junit.jupiter.api.Test; @@ -20,6 +22,8 @@ import java.util.regex.Pattern; @SuppressWarnings("all") @TestMetadata("native/native.tests/stress/testData") @TestDataPath("$PROJECT_ROOT") +@Tag("stress") +@EnforcedProperty(property = ClassLevelProperty.EXECUTION_TIMEOUT, propertyValue = "5m") @UseStandardTestCaseGroupProvider() @Tag("frontend-fir") @FirPipeline() @@ -29,9 +33,21 @@ public class FirNativeStressTestGenerated extends AbstractNativeBlackBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/stress/testData"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @Test + @TestMetadata("array_out_of_memory.kt") + public void testArray_out_of_memory() { + runTest("native/native.tests/stress/testData/array_out_of_memory.kt"); + } + @Test @TestMetadata("kt63423_dispose_on_main_stress.kt") public void testKt63423_dispose_on_main_stress() { runTest("native/native.tests/stress/testData/kt63423_dispose_on_main_stress.kt"); } + + @Test + @TestMetadata("stress_gc_allocations.kt") + public void testStress_gc_allocations() { + runTest("native/native.tests/stress/testData/stress_gc_allocations.kt"); + } } diff --git a/native/native.tests/stress/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStressTestGenerated.java b/native/native.tests/stress/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStressTestGenerated.java index e73cece5b4e..aac7663fd39 100644 --- a/native/native.tests/stress/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStressTestGenerated.java +++ b/native/native.tests/stress/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStressTestGenerated.java @@ -7,6 +7,9 @@ package org.jetbrains.kotlin.konan.test.blackbox; import com.intellij.testFramework.TestDataPath; import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.junit.jupiter.api.Tag; +import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty; +import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty; import org.jetbrains.kotlin.konan.test.blackbox.support.group.UseStandardTestCaseGroupProvider; import org.jetbrains.kotlin.test.TestMetadata; import org.junit.jupiter.api.Test; @@ -18,6 +21,8 @@ import java.util.regex.Pattern; @SuppressWarnings("all") @TestMetadata("native/native.tests/stress/testData") @TestDataPath("$PROJECT_ROOT") +@Tag("stress") +@EnforcedProperty(property = ClassLevelProperty.EXECUTION_TIMEOUT, propertyValue = "5m") @UseStandardTestCaseGroupProvider() public class NativeStressTestGenerated extends AbstractNativeBlackBoxTest { @Test @@ -25,9 +30,21 @@ public class NativeStressTestGenerated extends AbstractNativeBlackBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/stress/testData"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @Test + @TestMetadata("array_out_of_memory.kt") + public void testArray_out_of_memory() { + runTest("native/native.tests/stress/testData/array_out_of_memory.kt"); + } + @Test @TestMetadata("kt63423_dispose_on_main_stress.kt") public void testKt63423_dispose_on_main_stress() { runTest("native/native.tests/stress/testData/kt63423_dispose_on_main_stress.kt"); } + + @Test + @TestMetadata("stress_gc_allocations.kt") + public void testStress_gc_allocations() { + runTest("native/native.tests/stress/testData/stress_gc_allocations.kt"); + } } diff --git a/native/native.tests/testData/codegen/enum/identity.kt b/native/native.tests/testData/codegen/enum/identity.kt new file mode 100644 index 00000000000..c01fd465f8c --- /dev/null +++ b/native/native.tests/testData/codegen/enum/identity.kt @@ -0,0 +1,16 @@ +import kotlin.test.* +import kotlin.native.concurrent.* + +enum class A { + A, B +} + +data class Foo(val kind: A) + +// Enums are shared between threads so identity should be kept. +fun box(): String = withWorker { + val result = execute(TransferMode.SAFE, { Foo(A.B) }) { input -> + input.kind === A.B + }.result + return if (result) "OK" else "FAIL" +} \ No newline at end of file diff --git a/native/native.tests/testData/codegen/exceptions/throw_cleanup.kt b/native/native.tests/testData/codegen/exceptions/throw_cleanup.kt new file mode 100644 index 00000000000..7b393036b80 --- /dev/null +++ b/native/native.tests/testData/codegen/exceptions/throw_cleanup.kt @@ -0,0 +1,17 @@ +fun box(): String { + foo(false) + try { + foo(true) + } catch (e: Error) { + return "OK" + } + return "FAIL" +} + +private fun foo(b: Boolean): Any { + var result = Any() + if (b) { + throw Error() + } + return result +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/basic/initializers6.kt b/native/native.tests/testData/codegen/initializers/initializers6.kt similarity index 98% rename from kotlin-native/backend.native/tests/runtime/basic/initializers6.kt rename to native/native.tests/testData/codegen/initializers/initializers6.kt index 62ff673cb66..f9bdeabfb5e 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/initializers6.kt +++ b/native/native.tests/testData/codegen/initializers/initializers6.kt @@ -45,7 +45,7 @@ fun produceB(): String { return "B+${A.a}" } -@Test fun runTest() { +fun box(): String { val aWorker = Worker.start() aWorkerId.value = aWorker.id val bWorkers = Array(bWorkersCount, { _ -> Worker.start() }) @@ -73,4 +73,5 @@ fun produceB(): String { worker.requestTermination().result } aWorker.requestTermination().result + return "OK" } diff --git a/kotlin-native/backend.native/tests/runtime/memory/var1.kt b/native/native.tests/testData/codegen/objectDeclaration/compileTime.kt similarity index 57% rename from kotlin-native/backend.native/tests/runtime/memory/var1.kt rename to native/native.tests/testData/codegen/objectDeclaration/compileTime.kt index 2d4b2581175..763da28c493 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/var1.kt +++ b/native/native.tests/testData/codegen/objectDeclaration/compileTime.kt @@ -1,38 +1,5 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package runtime.memory.var1 - import kotlin.test.* -class Integer(val value: Int) { - operator fun inc() = Integer(value + 1) -} - -fun foo(x: Any, y: Any) { - x.use() - y.use() -} - -@Test fun runTest1() { - var x = Integer(0) - - for (i in 0..1) { - val c = Integer(0) - if (i == 0) x = c - } - - // x refcount is 1. - - foo(x, ++x) -} - -fun Any?.use() { - var x = this -} - @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") @kotlin.native.internal.CanBePrecreated object CompileTime { @@ -47,11 +14,7 @@ object CompileTime { const val char = Char.MIN_VALUE } -class AClass { - companion object {} -} - -@Test fun runTest2() { +fun box(): String { assertEquals(Int.MIN_VALUE, CompileTime.int) assertEquals(Byte.MIN_VALUE, CompileTime.byte) assertEquals(Short.MIN_VALUE, CompileTime.short) @@ -60,4 +23,5 @@ class AClass { assertEquals(1.0f, CompileTime.float) assertEquals(1.0, CompileTime.double) assertEquals(Char.MIN_VALUE, CompileTime.char) + return "OK" } \ No newline at end of file diff --git a/native/native.tests/testData/codegen/variables/var1.kt b/native/native.tests/testData/codegen/variables/var1.kt new file mode 100644 index 00000000000..66ede00323a --- /dev/null +++ b/native/native.tests/testData/codegen/variables/var1.kt @@ -0,0 +1,28 @@ +import kotlin.test.* + +private class Integer(val value: Int) { + operator fun inc() = Integer(value + 1) +} + +private fun foo(x: Any, y: Any) { + x.use() + y.use() +} + +fun box(): String { + var x = Integer(0) + + for (i in 0..1) { + val c = Integer(0) + if (i == 0) x = c + } + + // x refcount is 1. + + foo(x, ++x) + return "OK" +} + +private fun Any?.use() { + var x = this +} diff --git a/kotlin-native/backend.native/tests/runtime/memory/var2.kt b/native/native.tests/testData/codegen/variables/var2.kt similarity index 52% rename from kotlin-native/backend.native/tests/runtime/memory/var2.kt rename to native/native.tests/testData/codegen/variables/var2.kt index 690f9a04738..7c0082dbbe6 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/var2.kt +++ b/native/native.tests/testData/codegen/variables/var2.kt @@ -1,13 +1,6 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package runtime.memory.var2 - import kotlin.test.* -@Test fun runTest() { +fun box(): String { var x = Any() for (i in 0..1) { @@ -24,8 +17,9 @@ import kotlin.test.* } y.use() + return "OK" } -fun Any?.use() { +private fun Any?.use() { var x = this } \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/memory/var3.kt b/native/native.tests/testData/codegen/variables/var3.kt similarity index 51% rename from kotlin-native/backend.native/tests/runtime/memory/var3.kt rename to native/native.tests/testData/codegen/variables/var3.kt index 08534402ce3..7663d6af6b8 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/var3.kt +++ b/native/native.tests/testData/codegen/variables/var3.kt @@ -1,17 +1,11 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package runtime.memory.var3 - import kotlin.test.* -@Test fun runTest() { +fun box(): String { foo().use() + return "OK" } -fun foo(): Any { +private fun foo(): Any { var x = Any() for (i in 0..1) { @@ -28,6 +22,6 @@ fun foo(): Any { } } -fun Any?.use() { +private fun Any?.use() { var x = this } \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/memory/var4.kt b/native/native.tests/testData/codegen/variables/var4.kt similarity index 58% rename from kotlin-native/backend.native/tests/runtime/memory/var4.kt rename to native/native.tests/testData/codegen/variables/var4.kt index 4e2892a562e..ffc16a21fd5 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/var4.kt +++ b/native/native.tests/testData/codegen/variables/var4.kt @@ -1,13 +1,6 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package runtime.memory.var4 - import kotlin.test.* -@Test fun runTest() { +fun box(): String { var x = Error() for (i in 0..1) { @@ -26,8 +19,9 @@ import kotlin.test.* } catch (e: Error) { e.use() } + return "OK" } -fun Any?.use() { +private fun Any?.use() { var x = this } \ No newline at end of file diff --git a/native/native.tests/testData/compilerOutput/runtimeLogging/empty.txt b/native/native.tests/testData/compilerOutput/runtimeLogging/empty.txt new file mode 100644 index 00000000000..a0aba9318ad --- /dev/null +++ b/native/native.tests/testData/compilerOutput/runtimeLogging/empty.txt @@ -0,0 +1 @@ +OK \ No newline at end of file diff --git a/native/native.tests/testData/compilerOutput/runtimeLogging/logging_cache_warning.txt b/native/native.tests/testData/compilerOutput/runtimeLogging/logging_cache_warning.txt new file mode 100644 index 00000000000..ffae0bcd8e0 --- /dev/null +++ b/native/native.tests/testData/compilerOutput/runtimeLogging/logging_cache_warning.txt @@ -0,0 +1,2 @@ +warning: cached libraries will not be used with runtime logs +OK \ No newline at end of file diff --git a/native/native.tests/testData/compilerOutput/runtimeLogging/logging_invalid_error.txt b/native/native.tests/testData/compilerOutput/runtimeLogging/logging_invalid_error.txt new file mode 100644 index 00000000000..785fba7ac2f --- /dev/null +++ b/native/native.tests/testData/compilerOutput/runtimeLogging/logging_invalid_error.txt @@ -0,0 +1,3 @@ +warning: failed to parse log tag at "invalid". No logging will be performed. +warning: failed to parse log level at "unknown". No logging will be performed. +OK \ No newline at end of file diff --git a/native/native.tests/testData/compilerOutput/runtimeLogging/main.kt b/native/native.tests/testData/compilerOutput/runtimeLogging/main.kt new file mode 100644 index 00000000000..78e3db2779f --- /dev/null +++ b/native/native.tests/testData/compilerOutput/runtimeLogging/main.kt @@ -0,0 +1 @@ +fun main() {} \ No newline at end of file diff --git a/native/native.tests/testData/gc/basic0.kt b/native/native.tests/testData/gc/basic0.kt new file mode 100644 index 00000000000..55b402fcbeb --- /dev/null +++ b/native/native.tests/testData/gc/basic0.kt @@ -0,0 +1,12 @@ +import kotlin.test.* + +class A { + var field: B? = null +} + +class B(var field: Int) + +@Test fun runTest() { + val a = A() + a.field = B(2) +} diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_basic.kt b/native/native.tests/testData/gc/cleaner_basic.kt similarity index 57% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_basic.kt rename to native/native.tests/testData/gc/cleaner_basic.kt index 59b3298d41d..35562581d78 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/cleaner_basic.kt +++ b/native/native.tests/testData/gc/cleaner_basic.kt @@ -1,11 +1,5 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, FreezingIsDeprecated::class, - kotlin.native.runtime.NativeRuntimeApi::class, kotlinx.cinterop.ExperimentalForeignApi::class) - -package runtime.basic.cleaner_basic +// DISABLE_NATIVE: gcType=NOOP +// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative,kotlin.native.runtime.NativeRuntimeApi,kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi import kotlin.test.* @@ -21,10 +15,6 @@ import kotlin.native.runtime.GC class AtomicBoolean(initialValue: Boolean) { private val impl = AtomicInt(if (initialValue) 1 else 0) - init { - freeze() - } - public var value: Boolean get() = impl.value != 0 set(new) { impl.value = if (new) 1 else 0 } @@ -38,34 +28,6 @@ class FunBox(private val impl: () -> Unit) { @Test fun testCleanerLambda() { - val called = AtomicBoolean(false); - var funBoxWeak: WeakReference? = null - var cleanerWeak: WeakReference? = null - { - val cleaner = { - val funBox = FunBox { called.value = true }.freeze() - funBoxWeak = WeakReference(funBox) - createCleaner(funBox) { it.call() } - }() - GC.collect() // Make sure local funBox reference is gone - cleanerWeak = WeakReference(cleaner) - assertFalse(called.value) - }() - - GC.collect() - performGCOnCleanerWorker() - - assertNull(cleanerWeak!!.value) - assertTrue(called.value) - assertNull(funBoxWeak!!.value) -} - -@Test -fun testCleanerNonSharedLambda() { - // Only for experimental MM. - if (Platform.memoryModel != MemoryModel.EXPERIMENTAL) { - return - } val called = AtomicBoolean(false); var funBoxWeak: WeakReference? = null var cleanerWeak: WeakReference? = null @@ -90,34 +52,6 @@ fun testCleanerNonSharedLambda() { @Test fun testCleanerAnonymousFunction() { - val called = AtomicBoolean(false); - var funBoxWeak: WeakReference? = null - var cleanerWeak: WeakReference? = null - { - val cleaner = { - val funBox = FunBox { called.value = true }.freeze() - funBoxWeak = WeakReference(funBox) - createCleaner(funBox, fun (it: FunBox) { it.call() }) - }() - GC.collect() // Make sure local funBox reference is gone - cleanerWeak = WeakReference(cleaner) - assertFalse(called.value) - }() - - GC.collect() - performGCOnCleanerWorker() - - assertNull(cleanerWeak!!.value) - assertTrue(called.value) - assertNull(funBoxWeak!!.value) -} - -@Test -fun testCleanerNonSharedAnonymousFunction() { - // Only for experimental MM. - if (Platform.memoryModel != MemoryModel.EXPERIMENTAL) { - return - } val called = AtomicBoolean(false); var funBoxWeak: WeakReference? = null var cleanerWeak: WeakReference? = null @@ -142,34 +76,6 @@ fun testCleanerNonSharedAnonymousFunction() { @Test fun testCleanerFunctionReference() { - val called = AtomicBoolean(false); - var funBoxWeak: WeakReference? = null - var cleanerWeak: WeakReference? = null - { - val cleaner = { - val funBox = FunBox { called.value = true }.freeze() - funBoxWeak = WeakReference(funBox) - createCleaner(funBox, FunBox::call) - }() - GC.collect() // Make sure local funBox reference is gone - cleanerWeak = WeakReference(cleaner) - assertFalse(called.value) - }() - - GC.collect() - performGCOnCleanerWorker() - - assertNull(cleanerWeak!!.value) - assertTrue(called.value) - assertNull(funBoxWeak!!.value) -} - -@Test -fun testCleanerNonSharedFunctionReference() { - // Only for experimental MM. - if (Platform.memoryModel != MemoryModel.EXPERIMENTAL) { - return - } val called = AtomicBoolean(false); var funBoxWeak: WeakReference? = null var cleanerWeak: WeakReference? = null @@ -192,18 +98,6 @@ fun testCleanerNonSharedFunctionReference() { assertNull(funBoxWeak!!.value) } -@Test -fun testCleanerFailWithNonShareableArgument() { - // Only for legacy MM. - if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { - return - } - val funBox = FunBox {} - assertFailsWith { - createCleaner(funBox) {} - } -} - @Test fun testCleanerCleansWithoutGC() { val called = AtomicBoolean(false); @@ -211,12 +105,11 @@ fun testCleanerCleansWithoutGC() { var cleanerWeak: WeakReference? = null { val cleaner = { - val funBox = FunBox { called.value = true }.freeze() + val funBox = FunBox { called.value = true } funBoxWeak = WeakReference(funBox) createCleaner(funBox) { it.call() } }() GC.collect() // Make sure local funBox reference is gone - cleaner.freeze() cleanerWeak = WeakReference(cleaner) assertFalse(called.value) }() @@ -228,12 +121,6 @@ fun testCleanerCleansWithoutGC() { waitCleanerWorker() assertTrue(called.value) - - // Only for legacy MM. - if (Platform.memoryModel != MemoryModel.EXPERIMENTAL) { - // If this fails, GC has somehow ran on the cleaners worker. - assertNotNull(funBoxWeak!!.value) - } } val globalInt = AtomicInt(0) @@ -244,7 +131,7 @@ fun testCleanerWithInt() { { val cleaner = createCleaner(42) { globalInt.value = it - }.freeze() + } cleanerWeak = WeakReference(cleaner) assertEquals(0, globalInt.value) }() @@ -282,7 +169,7 @@ fun testCleanerWithException() { var funBoxWeak: WeakReference? = null var cleanerWeak: WeakReference? = null { - val funBox = FunBox { called.value = true }.freeze() + val funBox = FunBox { called.value = true } funBoxWeak = WeakReference(funBox) val cleaner = createCleaner(funBox) { it.call() diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_tls_worker.kt b/native/native.tests/testData/gc/cleaner_in_tls_worker.kt similarity index 67% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_in_tls_worker.kt rename to native/native.tests/testData/gc/cleaner_in_tls_worker.kt index e8ba79ada16..8307468e7c9 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_tls_worker.kt +++ b/native/native.tests/testData/gc/cleaner_in_tls_worker.kt @@ -1,8 +1,5 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class) +// DISABLE_NATIVE: gcType=NOOP +// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative,kotlin.native.runtime.NativeRuntimeApi,kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi import kotlin.test.* @@ -18,7 +15,8 @@ var tlsCleaner: Cleaner? = null val value = AtomicInt(0) -fun main() { +@Test +fun test() { val worker = Worker.start() worker.execute(TransferMode.SAFE, {}) { diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_workers.kt b/native/native.tests/testData/gc/cleaner_workers.kt similarity index 86% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_workers.kt rename to native/native.tests/testData/gc/cleaner_workers.kt index d8591d7e275..5a78a7676ae 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/cleaner_workers.kt +++ b/native/native.tests/testData/gc/cleaner_workers.kt @@ -1,10 +1,5 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ -@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class, kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class) - -package runtime.basic.cleaner_workers +// DISABLE_NATIVE: gcType=NOOP +// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative,kotlin.native.runtime.NativeRuntimeApi,kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi import kotlin.test.* @@ -20,10 +15,6 @@ import kotlin.native.runtime.GC class AtomicBoolean(initialValue: Boolean) { private val impl = AtomicInt(if (initialValue) 1 else 0) - init { - freeze() - } - public var value: Boolean get() = impl.value != 0 set(new) { impl.value = if (new) 1 else 0 } @@ -43,7 +34,7 @@ fun testCleanerDestroyInChild() { var funBoxWeak: WeakReference? = null var cleanerWeak: WeakReference? = null worker.execute(TransferMode.SAFE, { - val funBox = FunBox { called.value = true }.freeze() + val funBox = FunBox { called.value = true } funBoxWeak = WeakReference(funBox) val cleaner = createCleaner(funBox) { it.call() } cleanerWeak = WeakReference(cleaner) @@ -71,7 +62,7 @@ fun testCleanerDestroyWithChild() { var funBoxWeak: WeakReference? = null var cleanerWeak: WeakReference? = null worker.execute(TransferMode.SAFE, { - val funBox = FunBox { called.value = true }.freeze() + val funBox = FunBox { called.value = true } funBoxWeak = WeakReference(funBox) val cleaner = createCleaner(funBox) { it.call() } cleanerWeak = WeakReference(cleaner) @@ -100,7 +91,7 @@ fun testCleanerDestroyInMain() { var cleanerWeak: WeakReference? = null { val result = worker.execute(TransferMode.SAFE, { called }) { called -> - val funBox = FunBox { called.value = true }.freeze() + val funBox = FunBox { called.value = true } val cleaner = createCleaner(funBox) { it.call() } Triple(cleaner, WeakReference(funBox), WeakReference(cleaner)) }.result @@ -130,7 +121,7 @@ fun testCleanerDestroyShared() { var cleanerWeak: WeakReference? = null val cleanerHolder: AtomicReference = AtomicReference(null); { - val funBox = FunBox { called.value = true }.freeze() + val funBox = FunBox { called.value = true } funBoxWeak = WeakReference(funBox) val cleaner = createCleaner(funBox) { it.call() } cleanerWeak = WeakReference(cleaner) diff --git a/native/native.tests/testData/gc/collect.kt b/native/native.tests/testData/gc/collect.kt new file mode 100644 index 00000000000..44bfb0e8c29 --- /dev/null +++ b/native/native.tests/testData/gc/collect.kt @@ -0,0 +1,8 @@ +import kotlin.native.runtime.GC +import kotlin.test.* + +@OptIn(kotlin.native.runtime.NativeRuntimeApi::class) +@Test +fun test() { + GC.collect() +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/memory/cycles0.kt b/native/native.tests/testData/gc/cycles0.kt similarity index 85% rename from kotlin-native/backend.native/tests/runtime/memory/cycles0.kt rename to native/native.tests/testData/gc/cycles0.kt index 838a195993d..1a48e91d731 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/cycles0.kt +++ b/native/native.tests/testData/gc/cycles0.kt @@ -1,10 +1,4 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package runtime.memory.cycles0 - +// DISABLE_NATIVE: gcType=NOOP import kotlin.test.* data class Node(val data: Int, var next: Node?, var prev: Node?, val outer: Node?) @@ -51,5 +45,5 @@ fun createCycles(junk: Node) { createCycles(outer) kotlin.native.runtime.GC.collect() // Ensure outer is not collected. - println(outer.data) + assertEquals(42, outer.data) } diff --git a/native/native.tests/testData/gc/cycles1.kt b/native/native.tests/testData/gc/cycles1.kt new file mode 100644 index 00000000000..5b6ffbc9868 --- /dev/null +++ b/native/native.tests/testData/gc/cycles1.kt @@ -0,0 +1,19 @@ +// DISABLE_NATIVE: gcType=NOOP + +import kotlin.test.* +import kotlin.native.ref.* + +@OptIn(kotlin.native.runtime.NativeRuntimeApi::class, kotlin.experimental.ExperimentalNativeApi::class) +@Test fun runTest() { + val weakRefToTrashCycle = createLoop() + kotlin.native.runtime.GC.collect() + assertNull(weakRefToTrashCycle.get()) +} + +@OptIn(kotlin.experimental.ExperimentalNativeApi::class) +private fun createLoop(): WeakReference { + val loop = Array(1, { null }) + loop[0] = loop + + return WeakReference(loop) +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/memory/escape0.kt b/native/native.tests/testData/gc/escape0.kt similarity index 83% rename from kotlin-native/backend.native/tests/runtime/memory/escape0.kt rename to native/native.tests/testData/gc/escape0.kt index 5e60deef32c..96809954045 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/escape0.kt +++ b/native/native.tests/testData/gc/escape0.kt @@ -1,10 +1,3 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package runtime.memory.escape0 - import kotlin.test.* //fun foo1(arg: String) : String = foo0(arg) diff --git a/native/native.tests/testData/gc/escape1.kt b/native/native.tests/testData/gc/escape1.kt new file mode 100644 index 00000000000..9bcee266397 --- /dev/null +++ b/native/native.tests/testData/gc/escape1.kt @@ -0,0 +1,16 @@ +import kotlin.test.* + +class B(val s: String) + +class A { + val b = B("zzz") +} + +fun foo(): B { + val a = A() + return a.b +} + +@Test fun runTest() { + assertEquals("zzz", foo().s) +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/memory/escape2.kt b/native/native.tests/testData/gc/escape2.kt similarity index 54% rename from kotlin-native/backend.native/tests/runtime/memory/escape2.kt rename to native/native.tests/testData/gc/escape2.kt index 935ff63f4ad..f87481fa57c 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/escape2.kt +++ b/native/native.tests/testData/gc/escape2.kt @@ -1,10 +1,3 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package runtime.memory.escape2 - import kotlin.test.* class A(val s: String) @@ -29,5 +22,5 @@ val global = B() @Test fun runTest() { bar(global) - println(global.a!!.s) + assertEquals("zzz", global.a!!.s) } \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/memory/gcStats.kt b/native/native.tests/testData/gc/gcStats.kt similarity index 79% rename from kotlin-native/backend.native/tests/runtime/memory/gcStats.kt rename to native/native.tests/testData/gc/gcStats.kt index 158265e2c25..15e19e4398b 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/gcStats.kt +++ b/native/native.tests/testData/gc/gcStats.kt @@ -1,14 +1,8 @@ -/* - * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(kotlin.ExperimentalStdlibApi::class, kotlin.native.runtime.NativeRuntimeApi::class, kotlinx.cinterop.ExperimentalForeignApi::class) - +// DISABLE_NATIVE: gcType=NOOP +// FREE_COMPILER_ARGS: -Xbinary=gcSchedulerType=manual -opt-in=kotlin.native.runtime.NativeRuntimeApi,kotlin.ExperimentalStdlibApi,kotlinx.cinterop.ExperimentalForeignApi import kotlin.native.runtime.GC import kotlin.test.* - @Test fun `nothing new collected`() { GC.collect() diff --git a/native/native.tests/testData/gc/lazy2.kt b/native/native.tests/testData/gc/lazy2.kt new file mode 100644 index 00000000000..d213e2981a4 --- /dev/null +++ b/native/native.tests/testData/gc/lazy2.kt @@ -0,0 +1,23 @@ +// DISABLE_NATIVE: gcType=NOOP +import kotlin.native.runtime.GC +import kotlin.test.* + +object Foo { + val bar = Bar() +} + +class Bar { + val f by lazy { + foo() + } + + fun foo() = 123 +} + +@OptIn(kotlin.native.runtime.NativeRuntimeApi::class) +@Test +fun test() { + assertEquals(123, Foo.bar.f) + GC.collect() + assertEquals(123, Foo.bar.f) +} \ No newline at end of file diff --git a/native/native.tests/testData/gc/lazy3.kt b/native/native.tests/testData/gc/lazy3.kt new file mode 100644 index 00000000000..73b3b6a8286 --- /dev/null +++ b/native/native.tests/testData/gc/lazy3.kt @@ -0,0 +1,29 @@ +// DISABLE_NATIVE: gcType=NOOP +import kotlin.native.ref.WeakReference +import kotlin.native.runtime.GC +import kotlin.test.* + +@OptIn(kotlin.experimental.ExperimentalNativeApi::class) +private fun makeWeakRef(create: () -> Any) = WeakReference(create()) + +@OptIn(kotlin.native.runtime.NativeRuntimeApi::class, kotlin.experimental.ExperimentalNativeApi::class) +private fun ensureGetsCollected(create: () -> Any) { + val ref = makeWeakRef(create) + GC.collect() + assertNull(ref.get()) +} + +class LazyCapturesThis { + fun foo() = 42 + val bar by lazy { foo() } +} + +@Test +fun test() { + ensureGetsCollected { LazyCapturesThis() } + ensureGetsCollected { + val l = LazyCapturesThis() + l.bar + l + } +} diff --git a/native/native.tests/testData/gc/throwable.kt b/native/native.tests/testData/gc/throwable.kt new file mode 100644 index 00000000000..0b3e0f2326e --- /dev/null +++ b/native/native.tests/testData/gc/throwable.kt @@ -0,0 +1,25 @@ +// DISABLE_NATIVE: gcType=NOOP +import kotlin.native.ref.WeakReference +import kotlin.native.runtime.GC +import kotlin.test.* + +@OptIn(kotlin.experimental.ExperimentalNativeApi::class) +private fun makeWeakRef(create: () -> Any) = WeakReference(create()) + +@OptIn(kotlin.native.runtime.NativeRuntimeApi::class, kotlin.experimental.ExperimentalNativeApi::class) +private fun ensureGetsCollected(create: () -> Any) { + val ref = makeWeakRef(create) + GC.collect() + assertNull(ref.get()) +} + +@OptIn(kotlin.experimental.ExperimentalNativeApi::class) +@Test +fun test() { + ensureGetsCollected { Throwable() } + ensureGetsCollected { + val throwable = Throwable() + throwable.getStackTrace() + throwable + } +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/memory/weak0.kt b/native/native.tests/testData/gc/weak0.kt similarity index 63% rename from kotlin-native/backend.native/tests/runtime/memory/weak0.kt rename to native/native.tests/testData/gc/weak0.kt index 57a97bb4654..81e34c7e0ae 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/weak0.kt +++ b/native/native.tests/testData/gc/weak0.kt @@ -1,24 +1,18 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) - -package runtime.memory.weak0 - +// DISABLE_NATIVE: gcType=NOOP import kotlin.test.* import kotlin.native.ref.* data class Data(val s: String) +@OptIn(kotlin.experimental.ExperimentalNativeApi::class) fun localWeak(): WeakReference { val x = Data("Hello") val weak = WeakReference(x) - println(weak.get()) + assertSame(x, weak.get()) return weak } +@OptIn(kotlin.experimental.ExperimentalNativeApi::class) fun multiWeak(): Array> { val x = Data("Hello") val weaks = Array(100, { WeakReference(x) } ) @@ -28,12 +22,11 @@ fun multiWeak(): Array> { return weaks } -@OptIn(kotlin.native.runtime.NativeRuntimeApi::class) +@OptIn(kotlin.native.runtime.NativeRuntimeApi::class, kotlin.experimental.ExperimentalNativeApi::class) @Test fun runTest() { val weak = localWeak() kotlin.native.runtime.GC.collect() - val value = weak.get() - println(value?.toString()) + assertNull(weak.get()) val weaks = multiWeak() @@ -42,5 +35,4 @@ fun multiWeak(): Array> { weaks.forEach { it -> if (it.get()?.s != null) throw Error("not null") } - println("OK") } \ No newline at end of file diff --git a/native/native.tests/testData/gc/weak1.kt b/native/native.tests/testData/gc/weak1.kt new file mode 100644 index 00000000000..fe18c701d94 --- /dev/null +++ b/native/native.tests/testData/gc/weak1.kt @@ -0,0 +1,13 @@ +import kotlin.test.* +import kotlin.native.ref.* + +class Node(var next: Node?) + +@OptIn(kotlin.experimental.ExperimentalNativeApi::class) +@Test fun runTest1() { + val node1 = Node(null) + val node2 = Node(node1) + node1.next = node2 + + WeakReference(node1) +} diff --git a/kotlin-native/backend.native/tests/runtime/workers/worker10.kt b/native/native.tests/testData/gc/worker10.kt similarity index 78% rename from kotlin-native/backend.native/tests/runtime/workers/worker10.kt rename to native/native.tests/testData/gc/worker10.kt index 4daf225646c..4729d75ba86 100644 --- a/kotlin-native/backend.native/tests/runtime/workers/worker10.kt +++ b/native/native.tests/testData/gc/worker10.kt @@ -1,6 +1,6 @@ -@file:OptIn(FreezingIsDeprecated::class, kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class, kotlinx.cinterop.ExperimentalForeignApi::class) - -package runtime.workers.worker10 +// OUTPUT_DATA_FILE: worker10.out +// DISABLE_NATIVE: gcType=NOOP +// FREE_COMPILER_ARGS: -opt-in=kotlin.experimental.ExperimentalNativeApi,kotlin.native.runtime.NativeRuntimeApi,kotlinx.cinterop.ExperimentalForeignApi import kotlin.test.* import kotlin.concurrent.AtomicReference @@ -42,33 +42,21 @@ val topSharedData = Data(43) } worker.execute(TransferMode.SAFE, { -> }, { - it -> try { - topStringVar == "string" - } catch (e: IncorrectDereferenceException) { - false - } + it -> topStringVar == "string" }).consume { - result -> assertEquals(Platform.memoryModel != MemoryModel.STRICT, result) + result -> assertTrue(result) } worker.execute(TransferMode.SAFE, { -> }, { - it -> try { - topSharedStringWithGetter == "top" - } catch (e: IncorrectDereferenceException) { - false - } + it -> topSharedStringWithGetter == "top" }).consume { - result -> assertEquals(true, result) + result -> assertTrue(result) } worker.execute(TransferMode.SAFE, { -> }, { - it -> try { - topData.x == 42 - } catch (e: IncorrectDereferenceException) { - false - } + it -> topData.x == 42 }).consume { - result -> assertEquals(Platform.memoryModel != MemoryModel.STRICT, result) + result -> assertTrue(result) } worker.execute(TransferMode.SAFE, { -> }, { @@ -78,15 +66,15 @@ val topSharedData = Data(43) false } }).consume { - result -> assertEquals(true, result) + result -> assertTrue(result) } worker.requestTermination().result println("OK") } -val atomicRef = AtomicReference(Any().freeze()) -val stableRef = StableRef.create(Any().freeze()) +val atomicRef = AtomicReference(Any()) +val stableRef = StableRef.create(Any()) val semaphore = AtomicInt(0) @Test fun runTest2() { @@ -127,7 +115,7 @@ fun ensureWeakIs(weak: WeakReference, expected: T?) { assertEquals(expected, weak.get()) } -val stableHolder1 = StableRef.create(("hello" to "world").freeze()) +val stableHolder1 = StableRef.create(("hello" to "world")) @Test fun runTest4() { val worker = Worker.start() @@ -147,7 +135,7 @@ val stableHolder1 = StableRef.create(("hello" to "world").freeze()) worker.requestTermination().result } -val stableHolder2 = StableRef.create(("hello" to "world").freeze()) +val stableHolder2 = StableRef.create(("hello" to "world")) @Test fun runTest5() { val worker = Worker.start() @@ -167,7 +155,7 @@ val stableHolder2 = StableRef.create(("hello" to "world").freeze()) worker.requestTermination().result } -val atomicRef2 = AtomicReference(Any().freeze()) +val atomicRef2 = AtomicReference(Any()) @Test fun runTest6() { semaphore.value = 0 val worker = Worker.start() diff --git a/kotlin-native/backend.native/tests/runtime/workers/worker10.out b/native/native.tests/testData/gc/worker10.out similarity index 100% rename from kotlin-native/backend.native/tests/runtime/workers/worker10.out rename to native/native.tests/testData/gc/worker10.out diff --git a/native/native.tests/testData/gc/worker_bound_reference0.kt b/native/native.tests/testData/gc/worker_bound_reference0.kt new file mode 100644 index 00000000000..5cf22e5f047 --- /dev/null +++ b/native/native.tests/testData/gc/worker_bound_reference0.kt @@ -0,0 +1,340 @@ +// DISABLE_NATIVE: gcType=NOOP +// FREE_COMPILER_ARGS: -opt-in=kotlin.experimental.ExperimentalNativeApi,kotlin.native.runtime.NativeRuntimeApi,kotlin.native.FreezingIsDeprecated + +import kotlin.test.* + +import kotlin.concurrent.AtomicInt +import kotlin.concurrent.AtomicReference +import kotlin.native.concurrent.* +import kotlin.native.* +import kotlin.native.ref.WeakReference +import kotlin.native.runtime.GC + +class A(var a: Int) + +class Wrapper(val ref: WorkerBoundReference) + +fun getOwnerAndWeaks(initial: Int): Triple?>, WeakReference>, WeakReference> { + val ref = WorkerBoundReference(A(initial)) + val refOwner: AtomicReference?> = AtomicReference(ref) + val refWeak = WeakReference(ref) + val refValueWeak = WeakReference(ref.value) + + return Triple(refOwner, refWeak, refValueWeak) +} + +@Test +fun testCollect() { + val (refOwner, refWeak, refValueWeak) = getOwnerAndWeaks(3) + + refOwner.value = null + GC.collect() + + // Last reference to WorkerBoundReference is gone, so it and it's referent are destroyed. + assertNull(refWeak.value) + assertNull(refValueWeak.value) +} + +fun getOwnerAndWeaksFrozen(initial: Int): Triple?>, WeakReference>, WeakReference> { + val ref = WorkerBoundReference(A(initial)).freeze() + val refOwner: AtomicReference?> = AtomicReference(ref) + val refWeak = WeakReference(ref) + val refValueWeak = WeakReference(ref.value) + + return Triple(refOwner, refWeak, refValueWeak) +} + +@Test +fun testCollectFrozen() { + val (refOwner, refWeak, refValueWeak) = getOwnerAndWeaksFrozen(3) + + refOwner.value = null + if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { + // This runs the finalizer on the WorkerBoundReference, which schedules removing A from the root set + GC.collect() + // This actually frees A + GC.collect() + } else { + GC.collect() + } + + // Last reference to WorkerBoundReference is gone, so it and it's referent are destroyed. + assertNull(refWeak.value) + assertNull(refValueWeak.value) +} + +fun collectInWorkerFrozen(worker: Worker, semaphore: AtomicInt): Pair, Future> { + val (refOwner, _, refValueWeak) = getOwnerAndWeaksFrozen(3) + + val future = worker.execute(TransferMode.SAFE, { Pair(refOwner, semaphore) }) { (refOwner, semaphore) -> + semaphore.incrementAndGet() + while (semaphore.value < 2) { + } + + refOwner.value = null + GC.collect() + } + + while (semaphore.value < 1) { + } + // At this point worker is spinning on semaphore. refOwner still contains reference to + // WorkerBoundReference, so referent is kept alive. + GC.collect() + assertNotNull(refValueWeak.value) + + return Pair(refValueWeak, future) +} + +@Test +fun testCollectInWorkerFrozen() { + val semaphore: AtomicInt = AtomicInt(0) + + val worker = Worker.start() + + val (refValueWeak, future) = collectInWorkerFrozen(worker, semaphore) + semaphore.incrementAndGet() + future.result + + // At this point WorkerBoundReference no longer has a reference, so it's referent is destroyed. + GC.collect() + assertNull(refValueWeak.value) + + worker.requestTermination().result +} + +fun doNotCollectInWorkerFrozen(worker: Worker, semaphore: AtomicInt): Future> { + val ref = WorkerBoundReference(A(3)).freeze() + + return worker.execute(TransferMode.SAFE, { Pair(ref, semaphore) }) { (ref, semaphore) -> + semaphore.incrementAndGet() + while (semaphore.value < 2) { + } + + GC.collect() + ref + } +} + +@Test +fun testDoNotCollectInWorkerFrozen() { + val semaphore: AtomicInt = AtomicInt(0) + + val worker = Worker.start() + + val future = doNotCollectInWorkerFrozen(worker, semaphore) + while (semaphore.value < 1) { + } + GC.collect() + semaphore.incrementAndGet() + + val value = future.result + assertEquals(3, value.value.a) + worker.requestTermination().result +} + +class B1 { + lateinit var b2: WorkerBoundReference +} + +data class B2(val b1: WorkerBoundReference) + +fun createCyclicGarbage(): Triple?>, WeakReference, WeakReference> { + val ref1 = WorkerBoundReference(B1()) + val ref1Owner: AtomicReference?> = AtomicReference(ref1) + val ref1Weak = WeakReference(ref1.value) + + val ref2 = WorkerBoundReference(B2(ref1)) + val ref2Weak = WeakReference(ref2.value) + + ref1.value.b2 = ref2 + + return Triple(ref1Owner, ref1Weak, ref2Weak) +} + +@Test +fun collectCyclicGarbage() { + val (ref1Owner, ref1Weak, ref2Weak) = createCyclicGarbage() + + ref1Owner.value = null + GC.collect() + + assertNull(ref1Weak.value) + assertNull(ref2Weak.value) +} + +fun createCyclicGarbageFrozen(): Triple?>, WeakReference, WeakReference> { + val ref1 = WorkerBoundReference(B1()).freeze() + val ref1Owner: AtomicReference?> = AtomicReference(ref1) + val ref1Weak = WeakReference(ref1.value) + + val ref2 = WorkerBoundReference(B2(ref1)).freeze() + val ref2Weak = WeakReference(ref2.value) + + ref1.value.b2 = ref2 + + return Triple(ref1Owner, ref1Weak, ref2Weak) +} + +@Test +fun doesNotCollectCyclicGarbageFrozen() { + if (!Platform.isFreezingEnabled) return + val (ref1Owner, ref1Weak, ref2Weak) = createCyclicGarbageFrozen() + + ref1Owner.value = null + GC.collect() + + // If these asserts fail, that means WorkerBoundReference managed to clean up cyclic garbage all by itself. + assertNotNull(ref1Weak.value) + assertNotNull(ref2Weak.value) +} + +fun createCrossThreadCyclicGarbageFrozen( + worker: Worker +): Triple?>, WeakReference, WeakReference> { + val ref1 = WorkerBoundReference(B1()).freeze() + val ref1Owner: AtomicReference?> = AtomicReference(ref1) + val ref1Weak = WeakReference(ref1.value) + + val future = worker.execute(TransferMode.SAFE, { ref1 }) { ref1 -> + val ref2 = WorkerBoundReference(B2(ref1)).freeze() + Pair(ref2, WeakReference(ref2.value)) + } + val (ref2, ref2Weak) = future.result + + ref1.value.b2 = ref2 + + return Triple(ref1Owner, ref1Weak, ref2Weak) +} + +@Test +fun doesNotCollectCrossThreadCyclicGarbageFrozen() { + if (!Platform.isFreezingEnabled) return + val worker = Worker.start() + + val (ref1Owner, ref1Weak, ref2Weak) = createCrossThreadCyclicGarbageFrozen(worker) + + ref1Owner.value = null + GC.collect() + worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result + + // If these asserts fail, that means WorkerBoundReference managed to clean up cyclic garbage all by itself. + assertNotNull(ref1Weak.value) + assertNotNull(ref2Weak.value) + + worker.requestTermination().result +} + +class C1 { + lateinit var c2: AtomicReference?> + + fun dispose() { + c2.value = null + } +} + +data class C2(val c1: AtomicReference>) + +fun createCyclicGarbageWithAtomicsFrozen(): Triple?>, WeakReference, WeakReference> { + val ref1 = WorkerBoundReference(C1()).freeze() + val ref1Weak = WeakReference(ref1.value) + + val ref2 = WorkerBoundReference(C2(AtomicReference(ref1))).freeze() + val ref2Weak = WeakReference(ref2.value) + + ref1.value.c2 = AtomicReference(ref2) + + return Triple(AtomicReference(ref1), ref1Weak, ref2Weak) +} + +fun dispose(refOwner: AtomicReference?>) { + refOwner.value!!.value.dispose() + refOwner.value = null +} + +@Test +fun doesNotCollectCyclicGarbageWithAtomicsFrozen() { + if (!Platform.isFreezingEnabled) return + val (ref1Owner, ref1Weak, ref2Weak) = createCyclicGarbageWithAtomicsFrozen() + + ref1Owner.value = null + GC.collect() + + // If these asserts fail, that means AtomicReference managed to clean up cyclic garbage all by itself. + assertNotNull(ref1Weak.value) + assertNotNull(ref2Weak.value) +} + +@Test +fun collectCyclicGarbageWithAtomicsFrozen() { + val (ref1Owner, ref1Weak, ref2Weak) = createCyclicGarbageWithAtomicsFrozen() + + dispose(ref1Owner) + if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) { + // Finalizes WorkerBoundReference and schedules C2 removal from the root set + GC.collect() + // Frees C2, finalizes WorkerBoundReference and schedules C1 removal from the root set + GC.collect() + // Frees C1 + GC.collect() + } else { + GC.collect() + } + + assertNull(ref1Weak.value) + assertNull(ref2Weak.value) +} + +fun createCrossThreadCyclicGarbageWithAtomicsFrozen( + worker: Worker +): Triple?>, WeakReference, WeakReference> { + val ref1 = WorkerBoundReference(C1()).freeze() + val ref1Weak = WeakReference(ref1.value) + + val future = worker.execute(TransferMode.SAFE, { ref1 }) { ref1 -> + val ref2 = WorkerBoundReference(C2(AtomicReference(ref1))).freeze() + Pair(ref2, WeakReference(ref2.value)) + } + val (ref2, ref2Weak) = future.result + + ref1.value.c2 = AtomicReference(ref2) + + return Triple(AtomicReference(ref1), ref1Weak, ref2Weak) +} + +@Test +fun doesNotCollectCrossThreadCyclicGarbageWithAtomicsFrozen() { + if (!Platform.isFreezingEnabled) return + val worker = Worker.start() + + val (ref1Owner, ref1Weak, ref2Weak) = createCrossThreadCyclicGarbageWithAtomicsFrozen(worker) + + ref1Owner.value = null + GC.collect() + worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result + + // If these asserts fail, that means AtomicReference managed to clean up cyclic garbage all by itself. + assertNotNull(ref1Weak.value) + assertNotNull(ref2Weak.value) + + worker.requestTermination().result +} + +@Test +fun collectCrossThreadCyclicGarbageWithAtomicsFrozen() { + val worker = Worker.start() + + val (ref1Owner, ref1Weak, ref2Weak) = createCrossThreadCyclicGarbageWithAtomicsFrozen(worker) + + dispose(ref1Owner) + // This marks C2 as gone on the main thread + GC.collect() + // This cleans up all the references from the worker thread and destroys C2, but C1 is still alive. + worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result + // And this finally destroys C1 + GC.collect() + + assertNull(ref1Weak.value) + assertNull(ref2Weak.value) + + worker.requestTermination().result +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_main_with_checker.kt b/native/native.tests/testData/standalone/checkers/cleaner_in_main_with_checker.kt similarity index 81% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_in_main_with_checker.kt rename to native/native.tests/testData/standalone/checkers/cleaner_in_main_with_checker.kt index 397d2dbaa65..ce17cc03abe 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_main_with_checker.kt +++ b/native/native.tests/testData/standalone/checkers/cleaner_in_main_with_checker.kt @@ -1,7 +1,5 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ +// OUTPUT_DATA_FILE: cleaner_in_main_with_checker.out +// DISABLE_NATIVE: gcType=NOOP @file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) import kotlin.native.ref.Cleaner diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_main_with_checker.out b/native/native.tests/testData/standalone/checkers/cleaner_in_main_with_checker.out similarity index 100% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_in_main_with_checker.out rename to native/native.tests/testData/standalone/checkers/cleaner_in_main_with_checker.out diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_main_without_checker.kt b/native/native.tests/testData/standalone/checkers/cleaner_in_main_without_checker.kt similarity index 80% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_in_main_without_checker.kt rename to native/native.tests/testData/standalone/checkers/cleaner_in_main_without_checker.kt index 6bd1005c893..d9d26d584f5 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_main_without_checker.kt +++ b/native/native.tests/testData/standalone/checkers/cleaner_in_main_without_checker.kt @@ -1,7 +1,4 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ +// OUTPUT_DATA_FILE: cleaner_in_main_without_checker.out @file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) import kotlin.native.ref.createCleaner diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_main_without_checker.out b/native/native.tests/testData/standalone/checkers/cleaner_in_main_without_checker.out similarity index 100% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_in_main_without_checker.out rename to native/native.tests/testData/standalone/checkers/cleaner_in_main_without_checker.out diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_tls_main_with_checker.kt b/native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_with_checker.kt similarity index 81% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_in_tls_main_with_checker.kt rename to native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_with_checker.kt index 7478e31d307..03ad3e8b0db 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_tls_main_with_checker.kt +++ b/native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_with_checker.kt @@ -1,7 +1,6 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ +// DISABLE_NATIVE: gcType=NOOP +// EXIT_CODE: !0 +// OUTPUT_REGEX: Cleaner (0x)?[0-9a-fA-F]+ was disposed during program exit.* @file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) import kotlin.test.* diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_tls_main_without_checker.kt b/native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_without_checker.kt similarity index 81% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_in_tls_main_without_checker.kt rename to native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_without_checker.kt index 1a3fe810ad4..e17e01e302f 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/cleaner_in_tls_main_without_checker.kt +++ b/native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_without_checker.kt @@ -1,7 +1,3 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ @file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) import kotlin.test.* diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_leak_with_checker.kt b/native/native.tests/testData/standalone/checkers/cleaner_leak_with_checker.kt similarity index 76% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_leak_with_checker.kt rename to native/native.tests/testData/standalone/checkers/cleaner_leak_with_checker.kt index be422caeeee..be8ef9f5f10 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/cleaner_leak_with_checker.kt +++ b/native/native.tests/testData/standalone/checkers/cleaner_leak_with_checker.kt @@ -1,7 +1,6 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ +// DISABLE_NATIVE: gcType=NOOP +// EXIT_CODE: !0 +// OUTPUT_REGEX: Cleaner (0x)?[0-9a-fA-F]+ was disposed during program exit.* @file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) import kotlin.test.* diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_leak_without_checker.kt b/native/native.tests/testData/standalone/checkers/cleaner_leak_without_checker.kt similarity index 72% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_leak_without_checker.kt rename to native/native.tests/testData/standalone/checkers/cleaner_leak_without_checker.kt index b034df09e96..013154a2481 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/cleaner_leak_without_checker.kt +++ b/native/native.tests/testData/standalone/checkers/cleaner_leak_without_checker.kt @@ -1,7 +1,4 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ +// OUTPUT_DATA_FILE: cleaner_leak_without_checker.out @file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) import kotlin.test.* diff --git a/kotlin-native/backend.native/tests/runtime/basic/cleaner_leak_without_checker.out b/native/native.tests/testData/standalone/checkers/cleaner_leak_without_checker.out similarity index 100% rename from kotlin-native/backend.native/tests/runtime/basic/cleaner_leak_without_checker.out rename to native/native.tests/testData/standalone/checkers/cleaner_leak_without_checker.out diff --git a/kotlin-native/backend.native/tests/runtime/memory/leak_memory.kt b/native/native.tests/testData/standalone/checkers/leak_memory.kt similarity index 61% rename from kotlin-native/backend.native/tests/runtime/memory/leak_memory.kt rename to native/native.tests/testData/standalone/checkers/leak_memory.kt index 600321eceb4..5f4dc63dbd4 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/leak_memory.kt +++ b/native/native.tests/testData/standalone/checkers/leak_memory.kt @@ -1,4 +1,4 @@ -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) +@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ExperimentalForeignApi::class) import kotlinx.cinterop.* import kotlin.native.Platform diff --git a/kotlin-native/backend.native/tests/runtime/memory/leak_memory_test_runner.kt b/native/native.tests/testData/standalone/checkers/leak_memory_test_runner.kt similarity index 62% rename from kotlin-native/backend.native/tests/runtime/memory/leak_memory_test_runner.kt rename to native/native.tests/testData/standalone/checkers/leak_memory_test_runner.kt index bfd109cae66..24e32629868 100644 --- a/kotlin-native/backend.native/tests/runtime/memory/leak_memory_test_runner.kt +++ b/native/native.tests/testData/standalone/checkers/leak_memory_test_runner.kt @@ -1,4 +1,5 @@ -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class) +// KIND: REGULAR +// FREE_COMPILER_ARGS: -opt-in=kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi import kotlin.test.* diff --git a/kotlin-native/backend.native/tests/runtime/workers/leak_memory_with_worker_termination.kt b/native/native.tests/testData/standalone/checkers/leak_memory_with_worker_termination.kt similarity index 87% rename from kotlin-native/backend.native/tests/runtime/workers/leak_memory_with_worker_termination.kt rename to native/native.tests/testData/standalone/checkers/leak_memory_with_worker_termination.kt index 774d05723e6..970932edeba 100644 --- a/kotlin-native/backend.native/tests/runtime/workers/leak_memory_with_worker_termination.kt +++ b/native/native.tests/testData/standalone/checkers/leak_memory_with_worker_termination.kt @@ -1,4 +1,4 @@ -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ObsoleteWorkersApi::class) +@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ObsoleteWorkersApi::class, ExperimentalForeignApi::class) import kotlin.native.concurrent.* import kotlin.native.Platform import kotlinx.cinterop.* diff --git a/kotlin-native/backend.native/tests/runtime/workers/leak_worker.kt b/native/native.tests/testData/standalone/checkers/leak_worker.kt similarity index 63% rename from kotlin-native/backend.native/tests/runtime/workers/leak_worker.kt rename to native/native.tests/testData/standalone/checkers/leak_worker.kt index 20beeab01b0..9782d1deaf2 100644 --- a/kotlin-native/backend.native/tests/runtime/workers/leak_worker.kt +++ b/native/native.tests/testData/standalone/checkers/leak_worker.kt @@ -1,4 +1,6 @@ -@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ObsoleteWorkersApi::class) +// EXIT_CODE: !0 +// OUTPUT_REGEX: Unfinished workers detected, 1 workers leaked!.* +@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ExperimentalForeignApi::class) import kotlin.native.concurrent.* import kotlin.native.Platform import kotlinx.cinterop.* diff --git a/kotlin-native/backend.native/tests/runtime/workers/worker_threadlocal_no_leak.kt b/native/native.tests/testData/standalone/checkers/worker_threadlocal_no_leak.kt similarity index 73% rename from kotlin-native/backend.native/tests/runtime/workers/worker_threadlocal_no_leak.kt rename to native/native.tests/testData/standalone/checkers/worker_threadlocal_no_leak.kt index 0d03366c333..a7871c677c8 100644 --- a/kotlin-native/backend.native/tests/runtime/workers/worker_threadlocal_no_leak.kt +++ b/native/native.tests/testData/standalone/checkers/worker_threadlocal_no_leak.kt @@ -1,8 +1,3 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - @file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ObsoleteWorkersApi::class) import kotlin.native.concurrent.* import kotlin.native.Platform diff --git a/kotlin-native/backend.native/tests/runtime/basic/init.kt b/native/native.tests/testData/standalone/initRuntimeInGlobal.kt similarity index 95% rename from kotlin-native/backend.native/tests/runtime/basic/init.kt rename to native/native.tests/testData/standalone/initRuntimeInGlobal.kt index 780339071d5..bc8b15c7065 100644 --- a/kotlin-native/backend.native/tests/runtime/basic/init.kt +++ b/native/native.tests/testData/standalone/initRuntimeInGlobal.kt @@ -1,4 +1,4 @@ val x = initRuntimeIfNeeded() fun main() { -} +} \ No newline at end of file diff --git a/native/native.tests/testData/standalone/runtimeLogging/logging.kt b/native/native.tests/testData/standalone/runtimeLogging/logging.kt new file mode 100644 index 00000000000..4daa5ca54bf --- /dev/null +++ b/native/native.tests/testData/standalone/runtimeLogging/logging.kt @@ -0,0 +1,6 @@ +// FREE_COMPILER_ARGS: -Xruntime-logs=gc=info,mm=warning,tls=error,logging=debug +// IGNORE_NATIVE: cacheMode=STATIC_ONLY_DIST +// IGNORE_NATIVE: cacheMode=STATIC_EVERYWHERE +// IGNORE_NATIVE: cacheMode=STATIC_PER_FILE_EVERYWHERE +// OUTPUT_REGEX: \[INFO\]\[logging\].*Logging enabled for: logging = DEBUG, gc = INFO, mm = WARNING, tls = ERROR.*\[INFO\]\[gc\].* +fun main() {} \ No newline at end of file diff --git a/native/native.tests/testData/standalone/runtimeLogging/logging_override.kt b/native/native.tests/testData/standalone/runtimeLogging/logging_override.kt new file mode 100644 index 00000000000..1a008b1da9c --- /dev/null +++ b/native/native.tests/testData/standalone/runtimeLogging/logging_override.kt @@ -0,0 +1,6 @@ +// FREE_COMPILER_ARGS: -Xruntime-logs=logging=info,logging=debug,logging=error +// IGNORE_NATIVE: cacheMode=STATIC_ONLY_DIST +// IGNORE_NATIVE: cacheMode=STATIC_EVERYWHERE +// IGNORE_NATIVE: cacheMode=STATIC_PER_FILE_EVERYWHERE +// OUTPUT_REGEX: ^$ +fun main() {} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/workers/worker5.kt b/native/native.tests/testData/standalone/termination/terminateMainThreadWorker.kt similarity index 79% rename from kotlin-native/backend.native/tests/runtime/workers/worker5.kt rename to native/native.tests/testData/standalone/termination/terminateMainThreadWorker.kt index 93f59a12048..dda2fff79f3 100644 --- a/kotlin-native/backend.native/tests/runtime/workers/worker5.kt +++ b/native/native.tests/testData/standalone/termination/terminateMainThreadWorker.kt @@ -1,7 +1,4 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ +// OUTPUT_REGEX: ^$ @file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class) import kotlin.test.* diff --git a/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate_current.kt b/native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfter.kt similarity index 50% rename from kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate_current.kt rename to native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfter.kt index cf22f6bb3ea..ae8b04d7009 100644 --- a/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate_current.kt +++ b/native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfter.kt @@ -1,11 +1,14 @@ -@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class) +// EXIT_CODE: !0 +// OUTPUT_REGEX: .*an error.* +// OUTPUT_REGEX: (?!.*Will not happen.*).* +import kotlin.test.* import kotlin.native.concurrent.* fun main() { Worker.current.executeAfter(0L, { - throw Error("some error") - }.freeze()) + throw Error("an error") + }) Worker.current.processQueue() println("Will not happen") -} +} \ No newline at end of file diff --git a/native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt b/native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt new file mode 100644 index 00000000000..735d9b24b4e --- /dev/null +++ b/native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt @@ -0,0 +1,18 @@ +// No termination is going on here. But that's the closest location to other unhandled exception hook tests. +// KIND: REGULAR +// OUTPUT_REGEX: hook called\R +import kotlin.test.* + +import kotlin.native.concurrent.* + +@OptIn(kotlin.experimental.ExperimentalNativeApi::class) +@Test +fun testExecuteAfterStartQuiet() { + setUnhandledExceptionHook { + println("hook called") + } + Worker.current.executeAfter(0L, { + throw Error("an error") + }) + Worker.current.processQueue() +} \ No newline at end of file diff --git a/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecute.kt b/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecute.kt new file mode 100644 index 00000000000..9569ff51be1 --- /dev/null +++ b/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecute.kt @@ -0,0 +1,18 @@ +// No termination is going on here. But that's the closest location to other unhandled exception hook tests. +// KIND: REGULAR +// OUTPUT_REGEX: .*an error.* +import kotlin.test.* + +import kotlin.native.concurrent.* + +@Test +fun testExecuteStart() { + val worker = Worker.start() + val future = worker.execute(TransferMode.SAFE, {}) { + throw Error("an error") + } + assertFailsWith { + future.result + } + worker.requestTermination().result +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate.kt b/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfter.kt similarity index 54% rename from kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate.kt rename to native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfter.kt index 2bf0eefd813..cf04cb011f6 100644 --- a/kotlin-native/backend.native/tests/runtime/workers/worker_exceptions_terminate.kt +++ b/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfter.kt @@ -1,12 +1,15 @@ -@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class) +// EXIT_CODE: !0 +// OUTPUT_REGEX: .*an error.* +// OUTPUT_REGEX: (?!.*Will not happen.*).* +import kotlin.test.* import kotlin.native.concurrent.* fun main() { val worker = Worker.start() worker.executeAfter(0L, { - throw Error("some error") - }.freeze()) + throw Error("an error") + }) worker.requestTermination().result println("Will not happen") -} +} \ No newline at end of file diff --git a/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterQuiet.kt b/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterQuiet.kt new file mode 100644 index 00000000000..65348f0384d --- /dev/null +++ b/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterQuiet.kt @@ -0,0 +1,15 @@ +// No termination is going on here. But that's the closest location to other unhandled exception hook tests. +// KIND: REGULAR +// OUTPUT_REGEX: (?!.*an error.*) +import kotlin.test.* + +import kotlin.native.concurrent.* + +@Test +fun testExecuteAfterStartQuiet() { + val worker = Worker.start(errorReporting = false) + worker.executeAfter(0L, { + throw Error("an error") + }) + worker.requestTermination().result +} \ No newline at end of file diff --git a/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterWithHook.kt b/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterWithHook.kt new file mode 100644 index 00000000000..0b716a85247 --- /dev/null +++ b/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterWithHook.kt @@ -0,0 +1,19 @@ +// No termination is going on here. But that's the closest location to other unhandled exception hook tests. +// KIND: REGULAR +// OUTPUT_REGEX: hook called\R +import kotlin.test.* + +import kotlin.native.concurrent.* + +@OptIn(kotlin.experimental.ExperimentalNativeApi::class) +@Test +fun testExecuteAfterStartQuiet() { + setUnhandledExceptionHook { + println("hook called") + } + val worker = Worker.start() + worker.executeAfter(0L, { + throw Error("an error") + }) + worker.requestTermination().result +} \ No newline at end of file diff --git a/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteQuiet.kt b/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteQuiet.kt new file mode 100644 index 00000000000..f353accd558 --- /dev/null +++ b/native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteQuiet.kt @@ -0,0 +1,18 @@ +// No termination is going on here. But that's the closest location to other unhandled exception hook tests. +// KIND: REGULAR +// OUTPUT_REGEX: (?!.*an error.*) +import kotlin.test.* + +import kotlin.native.concurrent.* + +@Test +fun testExecuteStartQuiet() { + val worker = Worker.start(errorReporting = false) + val future = worker.execute(TransferMode.SAFE, {}) { + throw Error("an error") + } + assertFailsWith { + future.result + } + worker.requestTermination().result +} \ No newline at end of file diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenLocalTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenLocalTestGenerated.java index 8bfec7e35b4..370bc79d2b4 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenLocalTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenLocalTestGenerated.java @@ -647,6 +647,12 @@ public class FirNativeCodegenLocalTestGenerated extends AbstractNativeCodegenBox KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/enum"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); } + @Test + @TestMetadata("identity.kt") + public void testIdentity() { + runTest("native/native.tests/testData/codegen/enum/identity.kt"); + } + @Test @TestMetadata("isFrozen.kt") public void testIsFrozen() { @@ -697,6 +703,25 @@ public class FirNativeCodegenLocalTestGenerated extends AbstractNativeCodegenBox } } + @Nested + @TestMetadata("native/native.tests/testData/codegen/exceptions") + @TestDataPath("$PROJECT_ROOT") + @Tag("frontend-fir") + @FirPipeline() + @UseExtTestCaseGroupProvider() + public class Exceptions { + @Test + public void testAllFilesPresentInExceptions() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/exceptions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); + } + + @Test + @TestMetadata("throw_cleanup.kt") + public void testThrow_cleanup() { + runTest("native/native.tests/testData/codegen/exceptions/throw_cleanup.kt"); + } + } + @Nested @TestMetadata("native/native.tests/testData/codegen/fileCheck") @TestDataPath("$PROJECT_ROOT") @@ -1074,6 +1099,12 @@ public class FirNativeCodegenLocalTestGenerated extends AbstractNativeCodegenBox KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/initializers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); } + @Test + @TestMetadata("initializers6.kt") + public void testInitializers6() { + runTest("native/native.tests/testData/codegen/initializers/initializers6.kt"); + } + @Test @TestMetadata("multipleModules2.kt") public void testMultipleModules2() { @@ -1551,6 +1582,12 @@ public class FirNativeCodegenLocalTestGenerated extends AbstractNativeCodegenBox KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/objectDeclaration"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); } + @Test + @TestMetadata("compileTime.kt") + public void testCompileTime() { + runTest("native/native.tests/testData/codegen/objectDeclaration/compileTime.kt"); + } + @Test @TestMetadata("globalConstants_checkComputedField.kt") public void testGlobalConstants_checkComputedField() { @@ -1656,6 +1693,43 @@ public class FirNativeCodegenLocalTestGenerated extends AbstractNativeCodegenBox } } + @Nested + @TestMetadata("native/native.tests/testData/codegen/variables") + @TestDataPath("$PROJECT_ROOT") + @Tag("frontend-fir") + @FirPipeline() + @UseExtTestCaseGroupProvider() + public class Variables { + @Test + public void testAllFilesPresentInVariables() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/variables"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); + } + + @Test + @TestMetadata("var1.kt") + public void testVar1() { + runTest("native/native.tests/testData/codegen/variables/var1.kt"); + } + + @Test + @TestMetadata("var2.kt") + public void testVar2() { + runTest("native/native.tests/testData/codegen/variables/var2.kt"); + } + + @Test + @TestMetadata("var3.kt") + public void testVar3() { + runTest("native/native.tests/testData/codegen/variables/var3.kt"); + } + + @Test + @TestMetadata("var4.kt") + public void testVar4() { + runTest("native/native.tests/testData/codegen/variables/var4.kt"); + } + } + @Nested @TestMetadata("native/native.tests/testData/codegen/vector") @TestDataPath("$PROJECT_ROOT") diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeGCTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeGCTestGenerated.java new file mode 100644 index 00000000000..b82f196a538 --- /dev/null +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeGCTestGenerated.java @@ -0,0 +1,140 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.konan.test.blackbox; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.junit.jupiter.api.Tag; +import org.jetbrains.kotlin.konan.test.blackbox.support.group.UseStandardTestCaseGroupProvider; +import org.jetbrains.kotlin.konan.test.blackbox.support.group.FirPipeline; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("native/native.tests/testData/gc") +@TestDataPath("$PROJECT_ROOT") +@Tag("gc") +@UseStandardTestCaseGroupProvider() +@Tag("frontend-fir") +@FirPipeline() +public class FirNativeGCTestGenerated extends AbstractNativeBlackBoxTest { + @Test + public void testAllFilesPresentInGc() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/gc"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("basic0.kt") + public void testBasic0() { + runTest("native/native.tests/testData/gc/basic0.kt"); + } + + @Test + @TestMetadata("cleaner_basic.kt") + public void testCleaner_basic() { + runTest("native/native.tests/testData/gc/cleaner_basic.kt"); + } + + @Test + @TestMetadata("cleaner_in_tls_worker.kt") + public void testCleaner_in_tls_worker() { + runTest("native/native.tests/testData/gc/cleaner_in_tls_worker.kt"); + } + + @Test + @TestMetadata("cleaner_workers.kt") + public void testCleaner_workers() { + runTest("native/native.tests/testData/gc/cleaner_workers.kt"); + } + + @Test + @TestMetadata("collect.kt") + public void testCollect() { + runTest("native/native.tests/testData/gc/collect.kt"); + } + + @Test + @TestMetadata("cycles0.kt") + public void testCycles0() { + runTest("native/native.tests/testData/gc/cycles0.kt"); + } + + @Test + @TestMetadata("cycles1.kt") + public void testCycles1() { + runTest("native/native.tests/testData/gc/cycles1.kt"); + } + + @Test + @TestMetadata("escape0.kt") + public void testEscape0() { + runTest("native/native.tests/testData/gc/escape0.kt"); + } + + @Test + @TestMetadata("escape1.kt") + public void testEscape1() { + runTest("native/native.tests/testData/gc/escape1.kt"); + } + + @Test + @TestMetadata("escape2.kt") + public void testEscape2() { + runTest("native/native.tests/testData/gc/escape2.kt"); + } + + @Test + @TestMetadata("gcStats.kt") + public void testGcStats() { + runTest("native/native.tests/testData/gc/gcStats.kt"); + } + + @Test + @TestMetadata("lazy2.kt") + public void testLazy2() { + runTest("native/native.tests/testData/gc/lazy2.kt"); + } + + @Test + @TestMetadata("lazy3.kt") + public void testLazy3() { + runTest("native/native.tests/testData/gc/lazy3.kt"); + } + + @Test + @TestMetadata("throwable.kt") + public void testThrowable() { + runTest("native/native.tests/testData/gc/throwable.kt"); + } + + @Test + @TestMetadata("weak0.kt") + public void testWeak0() { + runTest("native/native.tests/testData/gc/weak0.kt"); + } + + @Test + @TestMetadata("weak1.kt") + public void testWeak1() { + runTest("native/native.tests/testData/gc/weak1.kt"); + } + + @Test + @TestMetadata("worker10.kt") + public void testWorker10() { + runTest("native/native.tests/testData/gc/worker10.kt"); + } + + @Test + @TestMetadata("worker_bound_reference0.kt") + public void testWorker_bound_reference0() { + runTest("native/native.tests/testData/gc/worker_bound_reference0.kt"); + } +} diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStandaloneTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStandaloneTestGenerated.java index 1dead826fe6..db6d8565ba4 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStandaloneTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeStandaloneTestGenerated.java @@ -40,6 +40,12 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest runTest("native/native.tests/testData/standalone/funptr.kt"); } + @Test + @TestMetadata("initRuntimeInGlobal.kt") + public void testInitRuntimeInGlobal() { + runTest("native/native.tests/testData/standalone/initRuntimeInGlobal.kt"); + } + @Test @TestMetadata("kt56048.kt") public void testKt56048() { @@ -66,6 +72,42 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/checkers"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @Test + @TestMetadata("cleaner_in_main_with_checker.kt") + public void testCleaner_in_main_with_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_in_main_with_checker.kt"); + } + + @Test + @TestMetadata("cleaner_in_main_without_checker.kt") + public void testCleaner_in_main_without_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_in_main_without_checker.kt"); + } + + @Test + @TestMetadata("cleaner_in_tls_main_with_checker.kt") + public void testCleaner_in_tls_main_with_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_with_checker.kt"); + } + + @Test + @TestMetadata("cleaner_in_tls_main_without_checker.kt") + public void testCleaner_in_tls_main_without_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_without_checker.kt"); + } + + @Test + @TestMetadata("cleaner_leak_with_checker.kt") + public void testCleaner_leak_with_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_leak_with_checker.kt"); + } + + @Test + @TestMetadata("cleaner_leak_without_checker.kt") + public void testCleaner_leak_without_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_leak_without_checker.kt"); + } + @Test @TestMetadata("leakMemoryWithRunningThreadChecked.kt") public void testLeakMemoryWithRunningThreadChecked() { @@ -77,6 +119,36 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest public void testLeakMemoryWithRunningThreadUnchecked() { runTest("native/native.tests/testData/standalone/checkers/leakMemoryWithRunningThreadUnchecked.kt"); } + + @Test + @TestMetadata("leak_memory.kt") + public void testLeak_memory() { + runTest("native/native.tests/testData/standalone/checkers/leak_memory.kt"); + } + + @Test + @TestMetadata("leak_memory_test_runner.kt") + public void testLeak_memory_test_runner() { + runTest("native/native.tests/testData/standalone/checkers/leak_memory_test_runner.kt"); + } + + @Test + @TestMetadata("leak_memory_with_worker_termination.kt") + public void testLeak_memory_with_worker_termination() { + runTest("native/native.tests/testData/standalone/checkers/leak_memory_with_worker_termination.kt"); + } + + @Test + @TestMetadata("leak_worker.kt") + public void testLeak_worker() { + runTest("native/native.tests/testData/standalone/checkers/leak_worker.kt"); + } + + @Test + @TestMetadata("worker_threadlocal_no_leak.kt") + public void testWorker_threadlocal_no_leak() { + runTest("native/native.tests/testData/standalone/checkers/worker_threadlocal_no_leak.kt"); + } } @Nested @@ -205,6 +277,33 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest } } + @Nested + @TestMetadata("native/native.tests/testData/standalone/runtimeLogging") + @TestDataPath("$PROJECT_ROOT") + @Tag("standalone") + @EnforcedProperty(property = ClassLevelProperty.TEST_KIND, propertyValue = "STANDALONE_NO_TR") + @UseStandardTestCaseGroupProvider() + @Tag("frontend-fir") + @FirPipeline() + public class RuntimeLogging { + @Test + public void testAllFilesPresentInRuntimeLogging() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/runtimeLogging"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("logging.kt") + public void testLogging() { + runTest("native/native.tests/testData/standalone/runtimeLogging/logging.kt"); + } + + @Test + @TestMetadata("logging_override.kt") + public void testLogging_override() { + runTest("native/native.tests/testData/standalone/runtimeLogging/logging_override.kt"); + } + } + @Nested @TestMetadata("native/native.tests/testData/standalone/termination") @TestDataPath("$PROJECT_ROOT") @@ -249,6 +348,12 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest runTest("native/native.tests/testData/standalone/termination/processUnhandledException.kt"); } + @Test + @TestMetadata("terminateMainThreadWorker.kt") + public void testTerminateMainThreadWorker() { + runTest("native/native.tests/testData/standalone/termination/terminateMainThreadWorker.kt"); + } + @Test @TestMetadata("terminateWithUnhandledException.kt") public void testTerminateWithUnhandledException() { @@ -303,10 +408,52 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest runTest("native/native.tests/testData/standalone/termination/unhandledExceptionHookWithProcess.kt"); } + @Test + @TestMetadata("unhandledExceptionInCurrentWorkerExecuteAfter.kt") + public void testUnhandledExceptionInCurrentWorkerExecuteAfter() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfter.kt"); + } + + @Test + @TestMetadata("unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt") + public void testUnhandledExceptionInCurrentWorkerExecuteAfterWithHook() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt"); + } + @Test @TestMetadata("unhandledExceptionInForeignThread.kt") public void testUnhandledExceptionInForeignThread() { runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInForeignThread.kt"); } + + @Test + @TestMetadata("unhandledExceptionInWorkerExecute.kt") + public void testUnhandledExceptionInWorkerExecute() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecute.kt"); + } + + @Test + @TestMetadata("unhandledExceptionInWorkerExecuteAfter.kt") + public void testUnhandledExceptionInWorkerExecuteAfter() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfter.kt"); + } + + @Test + @TestMetadata("unhandledExceptionInWorkerExecuteAfterQuiet.kt") + public void testUnhandledExceptionInWorkerExecuteAfterQuiet() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterQuiet.kt"); + } + + @Test + @TestMetadata("unhandledExceptionInWorkerExecuteAfterWithHook.kt") + public void testUnhandledExceptionInWorkerExecuteAfterWithHook() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterWithHook.kt"); + } + + @Test + @TestMetadata("unhandledExceptionInWorkerExecuteQuiet.kt") + public void testUnhandledExceptionInWorkerExecuteQuiet() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteQuiet.kt"); + } } } diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenLocalTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenLocalTestGenerated.java index c7b837db42c..436a84c34f6 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenLocalTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenLocalTestGenerated.java @@ -621,6 +621,12 @@ public class NativeCodegenLocalTestGenerated extends AbstractNativeCodegenBoxTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/enum"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); } + @Test + @TestMetadata("identity.kt") + public void testIdentity() { + runTest("native/native.tests/testData/codegen/enum/identity.kt"); + } + @Test @TestMetadata("isFrozen.kt") public void testIsFrozen() { @@ -669,6 +675,23 @@ public class NativeCodegenLocalTestGenerated extends AbstractNativeCodegenBoxTes } } + @Nested + @TestMetadata("native/native.tests/testData/codegen/exceptions") + @TestDataPath("$PROJECT_ROOT") + @UseExtTestCaseGroupProvider() + public class Exceptions { + @Test + public void testAllFilesPresentInExceptions() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/exceptions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); + } + + @Test + @TestMetadata("throw_cleanup.kt") + public void testThrow_cleanup() { + runTest("native/native.tests/testData/codegen/exceptions/throw_cleanup.kt"); + } + } + @Nested @TestMetadata("native/native.tests/testData/codegen/fileCheck") @TestDataPath("$PROJECT_ROOT") @@ -1034,6 +1057,12 @@ public class NativeCodegenLocalTestGenerated extends AbstractNativeCodegenBoxTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/initializers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); } + @Test + @TestMetadata("initializers6.kt") + public void testInitializers6() { + runTest("native/native.tests/testData/codegen/initializers/initializers6.kt"); + } + @Test @TestMetadata("multipleModules2.kt") public void testMultipleModules2() { @@ -1481,6 +1510,12 @@ public class NativeCodegenLocalTestGenerated extends AbstractNativeCodegenBoxTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/objectDeclaration"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); } + @Test + @TestMetadata("compileTime.kt") + public void testCompileTime() { + runTest("native/native.tests/testData/codegen/objectDeclaration/compileTime.kt"); + } + @Test @TestMetadata("globalConstants_checkComputedField.kt") public void testGlobalConstants_checkComputedField() { @@ -1582,6 +1617,41 @@ public class NativeCodegenLocalTestGenerated extends AbstractNativeCodegenBoxTes } } + @Nested + @TestMetadata("native/native.tests/testData/codegen/variables") + @TestDataPath("$PROJECT_ROOT") + @UseExtTestCaseGroupProvider() + public class Variables { + @Test + public void testAllFilesPresentInVariables() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/variables"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); + } + + @Test + @TestMetadata("var1.kt") + public void testVar1() { + runTest("native/native.tests/testData/codegen/variables/var1.kt"); + } + + @Test + @TestMetadata("var2.kt") + public void testVar2() { + runTest("native/native.tests/testData/codegen/variables/var2.kt"); + } + + @Test + @TestMetadata("var3.kt") + public void testVar3() { + runTest("native/native.tests/testData/codegen/variables/var3.kt"); + } + + @Test + @TestMetadata("var4.kt") + public void testVar4() { + runTest("native/native.tests/testData/codegen/variables/var4.kt"); + } + } + @Nested @TestMetadata("native/native.tests/testData/codegen/vector") @TestDataPath("$PROJECT_ROOT") diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeGCTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeGCTestGenerated.java new file mode 100644 index 00000000000..11315c2a957 --- /dev/null +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeGCTestGenerated.java @@ -0,0 +1,137 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.konan.test.blackbox; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.junit.jupiter.api.Tag; +import org.jetbrains.kotlin.konan.test.blackbox.support.group.UseStandardTestCaseGroupProvider; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("native/native.tests/testData/gc") +@TestDataPath("$PROJECT_ROOT") +@Tag("gc") +@UseStandardTestCaseGroupProvider() +public class NativeGCTestGenerated extends AbstractNativeBlackBoxTest { + @Test + public void testAllFilesPresentInGc() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/gc"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("basic0.kt") + public void testBasic0() { + runTest("native/native.tests/testData/gc/basic0.kt"); + } + + @Test + @TestMetadata("cleaner_basic.kt") + public void testCleaner_basic() { + runTest("native/native.tests/testData/gc/cleaner_basic.kt"); + } + + @Test + @TestMetadata("cleaner_in_tls_worker.kt") + public void testCleaner_in_tls_worker() { + runTest("native/native.tests/testData/gc/cleaner_in_tls_worker.kt"); + } + + @Test + @TestMetadata("cleaner_workers.kt") + public void testCleaner_workers() { + runTest("native/native.tests/testData/gc/cleaner_workers.kt"); + } + + @Test + @TestMetadata("collect.kt") + public void testCollect() { + runTest("native/native.tests/testData/gc/collect.kt"); + } + + @Test + @TestMetadata("cycles0.kt") + public void testCycles0() { + runTest("native/native.tests/testData/gc/cycles0.kt"); + } + + @Test + @TestMetadata("cycles1.kt") + public void testCycles1() { + runTest("native/native.tests/testData/gc/cycles1.kt"); + } + + @Test + @TestMetadata("escape0.kt") + public void testEscape0() { + runTest("native/native.tests/testData/gc/escape0.kt"); + } + + @Test + @TestMetadata("escape1.kt") + public void testEscape1() { + runTest("native/native.tests/testData/gc/escape1.kt"); + } + + @Test + @TestMetadata("escape2.kt") + public void testEscape2() { + runTest("native/native.tests/testData/gc/escape2.kt"); + } + + @Test + @TestMetadata("gcStats.kt") + public void testGcStats() { + runTest("native/native.tests/testData/gc/gcStats.kt"); + } + + @Test + @TestMetadata("lazy2.kt") + public void testLazy2() { + runTest("native/native.tests/testData/gc/lazy2.kt"); + } + + @Test + @TestMetadata("lazy3.kt") + public void testLazy3() { + runTest("native/native.tests/testData/gc/lazy3.kt"); + } + + @Test + @TestMetadata("throwable.kt") + public void testThrowable() { + runTest("native/native.tests/testData/gc/throwable.kt"); + } + + @Test + @TestMetadata("weak0.kt") + public void testWeak0() { + runTest("native/native.tests/testData/gc/weak0.kt"); + } + + @Test + @TestMetadata("weak1.kt") + public void testWeak1() { + runTest("native/native.tests/testData/gc/weak1.kt"); + } + + @Test + @TestMetadata("worker10.kt") + public void testWorker10() { + runTest("native/native.tests/testData/gc/worker10.kt"); + } + + @Test + @TestMetadata("worker_bound_reference0.kt") + public void testWorker_bound_reference0() { + runTest("native/native.tests/testData/gc/worker_bound_reference0.kt"); + } +} diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStandaloneTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStandaloneTestGenerated.java index 4a95d5cb703..a624130409e 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStandaloneTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeStandaloneTestGenerated.java @@ -37,6 +37,12 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest { runTest("native/native.tests/testData/standalone/funptr.kt"); } + @Test + @TestMetadata("initRuntimeInGlobal.kt") + public void testInitRuntimeInGlobal() { + runTest("native/native.tests/testData/standalone/initRuntimeInGlobal.kt"); + } + @Test @TestMetadata("kt56048.kt") public void testKt56048() { @@ -61,6 +67,42 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/checkers"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @Test + @TestMetadata("cleaner_in_main_with_checker.kt") + public void testCleaner_in_main_with_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_in_main_with_checker.kt"); + } + + @Test + @TestMetadata("cleaner_in_main_without_checker.kt") + public void testCleaner_in_main_without_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_in_main_without_checker.kt"); + } + + @Test + @TestMetadata("cleaner_in_tls_main_with_checker.kt") + public void testCleaner_in_tls_main_with_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_with_checker.kt"); + } + + @Test + @TestMetadata("cleaner_in_tls_main_without_checker.kt") + public void testCleaner_in_tls_main_without_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_without_checker.kt"); + } + + @Test + @TestMetadata("cleaner_leak_with_checker.kt") + public void testCleaner_leak_with_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_leak_with_checker.kt"); + } + + @Test + @TestMetadata("cleaner_leak_without_checker.kt") + public void testCleaner_leak_without_checker() { + runTest("native/native.tests/testData/standalone/checkers/cleaner_leak_without_checker.kt"); + } + @Test @TestMetadata("leakMemoryWithRunningThreadChecked.kt") public void testLeakMemoryWithRunningThreadChecked() { @@ -72,6 +114,36 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest { public void testLeakMemoryWithRunningThreadUnchecked() { runTest("native/native.tests/testData/standalone/checkers/leakMemoryWithRunningThreadUnchecked.kt"); } + + @Test + @TestMetadata("leak_memory.kt") + public void testLeak_memory() { + runTest("native/native.tests/testData/standalone/checkers/leak_memory.kt"); + } + + @Test + @TestMetadata("leak_memory_test_runner.kt") + public void testLeak_memory_test_runner() { + runTest("native/native.tests/testData/standalone/checkers/leak_memory_test_runner.kt"); + } + + @Test + @TestMetadata("leak_memory_with_worker_termination.kt") + public void testLeak_memory_with_worker_termination() { + runTest("native/native.tests/testData/standalone/checkers/leak_memory_with_worker_termination.kt"); + } + + @Test + @TestMetadata("leak_worker.kt") + public void testLeak_worker() { + runTest("native/native.tests/testData/standalone/checkers/leak_worker.kt"); + } + + @Test + @TestMetadata("worker_threadlocal_no_leak.kt") + public void testWorker_threadlocal_no_leak() { + runTest("native/native.tests/testData/standalone/checkers/worker_threadlocal_no_leak.kt"); + } } @Nested @@ -196,6 +268,31 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest { } } + @Nested + @TestMetadata("native/native.tests/testData/standalone/runtimeLogging") + @TestDataPath("$PROJECT_ROOT") + @Tag("standalone") + @EnforcedProperty(property = ClassLevelProperty.TEST_KIND, propertyValue = "STANDALONE_NO_TR") + @UseStandardTestCaseGroupProvider() + public class RuntimeLogging { + @Test + public void testAllFilesPresentInRuntimeLogging() { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/runtimeLogging"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("logging.kt") + public void testLogging() { + runTest("native/native.tests/testData/standalone/runtimeLogging/logging.kt"); + } + + @Test + @TestMetadata("logging_override.kt") + public void testLogging_override() { + runTest("native/native.tests/testData/standalone/runtimeLogging/logging_override.kt"); + } + } + @Nested @TestMetadata("native/native.tests/testData/standalone/termination") @TestDataPath("$PROJECT_ROOT") @@ -238,6 +335,12 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest { runTest("native/native.tests/testData/standalone/termination/processUnhandledException.kt"); } + @Test + @TestMetadata("terminateMainThreadWorker.kt") + public void testTerminateMainThreadWorker() { + runTest("native/native.tests/testData/standalone/termination/terminateMainThreadWorker.kt"); + } + @Test @TestMetadata("terminateWithUnhandledException.kt") public void testTerminateWithUnhandledException() { @@ -292,10 +395,52 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest { runTest("native/native.tests/testData/standalone/termination/unhandledExceptionHookWithProcess.kt"); } + @Test + @TestMetadata("unhandledExceptionInCurrentWorkerExecuteAfter.kt") + public void testUnhandledExceptionInCurrentWorkerExecuteAfter() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfter.kt"); + } + + @Test + @TestMetadata("unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt") + public void testUnhandledExceptionInCurrentWorkerExecuteAfterWithHook() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt"); + } + @Test @TestMetadata("unhandledExceptionInForeignThread.kt") public void testUnhandledExceptionInForeignThread() { runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInForeignThread.kt"); } + + @Test + @TestMetadata("unhandledExceptionInWorkerExecute.kt") + public void testUnhandledExceptionInWorkerExecute() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecute.kt"); + } + + @Test + @TestMetadata("unhandledExceptionInWorkerExecuteAfter.kt") + public void testUnhandledExceptionInWorkerExecuteAfter() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfter.kt"); + } + + @Test + @TestMetadata("unhandledExceptionInWorkerExecuteAfterQuiet.kt") + public void testUnhandledExceptionInWorkerExecuteAfterQuiet() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterQuiet.kt"); + } + + @Test + @TestMetadata("unhandledExceptionInWorkerExecuteAfterWithHook.kt") + public void testUnhandledExceptionInWorkerExecuteAfterWithHook() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterWithHook.kt"); + } + + @Test + @TestMetadata("unhandledExceptionInWorkerExecuteQuiet.kt") + public void testUnhandledExceptionInWorkerExecuteQuiet() { + runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteQuiet.kt"); + } } } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt b/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt index 83d658b8012..528e12ec547 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt @@ -531,6 +531,7 @@ fun main() { testClass( suiteTestClassName = "NativeStressTestGenerated", annotations = listOf( + *stress(), provider(), ) ) { @@ -539,6 +540,7 @@ fun main() { testClass( suiteTestClassName = "FirNativeStressTestGenerated", annotations = listOf( + *stress(), provider(), *frontendFir(), ) @@ -546,6 +548,28 @@ fun main() { model("") } } + // GC tests + testGroup("native/native.tests/tests-gen", "native/native.tests/testData") { + testClass( + suiteTestClassName = "NativeGCTestGenerated", + annotations = listOf( + *gc(), + provider(), + ) + ) { + model("gc") + } + testClass( + suiteTestClassName = "FirNativeGCTestGenerated", + annotations = listOf( + *gc(), + provider(), + *frontendFir(), + ) + ) { + model("gc") + } + } } } @@ -608,3 +632,14 @@ private fun cinterfaceMode(mode: String = "V1") = annotation( "property" to ClassLevelProperty.C_INTERFACE_MODE, "propertyValue" to mode ) +private fun gc() = arrayOf( + annotation(Tag::class.java, "gc"), +) +private fun stress() = arrayOf( + annotation(Tag::class.java, "stress"), + annotation( + EnforcedProperty::class.java, + "property" to ClassLevelProperty.EXECUTION_TIMEOUT, + "propertyValue" to "5m" + ) +) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/CompilerOutputTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/CompilerOutputTest.kt index b35e9731463..1d60140c9bf 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/CompilerOutputTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/CompilerOutputTest.kt @@ -9,16 +9,15 @@ import com.intellij.testFramework.TestDataPath import org.jetbrains.kotlin.cli.AbstractCliTest import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.konan.test.blackbox.support.* import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty -import org.jetbrains.kotlin.konan.test.blackbox.support.LoggedData -import org.jetbrains.kotlin.konan.test.blackbox.support.TestCompilerArgs +import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.* import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.LibraryCompilation import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.ObjCFrameworkCompilation -import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilationArtifact -import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilationResult import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilationResult.Companion.assertSuccess import org.jetbrains.kotlin.konan.test.blackbox.support.group.FirPipeline +import org.jetbrains.kotlin.konan.test.blackbox.support.settings.CacheMode import org.jetbrains.kotlin.konan.test.blackbox.support.settings.PipelineType import org.jetbrains.kotlin.konan.test.blackbox.support.settings.Settings import org.jetbrains.kotlin.test.KotlinTestUtils @@ -162,6 +161,57 @@ abstract class CompilerOutputTestBase : AbstractNativeSimpleTest() { dir ) } + + @Test + fun testLoggingWarningWithDistCache() { + val rootDir = File("native/native.tests/testData/compilerOutput/runtimeLogging") + val testCase = generateTestCaseWithSingleFile( + rootDir.resolve("main.kt"), + freeCompilerArgs = TestCompilerArgs("-Xruntime-logs=gc=info"), + extras = TestCase.NoTestRunnerExtras("main"), + testKind = TestKind.STANDALONE_NO_TR, + ) + val expectedArtifact = TestCompilationArtifact.Executable(buildDir.resolve("logging_warning_with_cache")) + val compilation = ExecutableCompilation( + testRunSettings, + freeCompilerArgs = testCase.freeCompilerArgs, + sourceModules = testCase.modules, + extras = testCase.extras, + dependencies = emptyList(), + expectedArtifact = expectedArtifact, + ) + val compilationResult = compilation.result + val goldenData = rootDir.resolve( + if (testRunSettings.get().useStaticCacheForDistributionLibraries) "logging_cache_warning.txt" else "empty.txt" + ) + + KotlinTestUtils.assertEqualsToFile(goldenData, compilationResult.toOutput()) + } + + @Test + fun testLoggingInvalid() { + Assumptions.assumeFalse(testRunSettings.get().useStaticCacheForDistributionLibraries) + val rootDir = File("native/native.tests/testData/compilerOutput/runtimeLogging") + val testCase = generateTestCaseWithSingleFile( + rootDir.resolve("main.kt"), + freeCompilerArgs = TestCompilerArgs("-Xruntime-logs=invalid=unknown,logging=debug"), + extras = TestCase.NoTestRunnerExtras("main"), + testKind = TestKind.STANDALONE_NO_TR, + ) + val expectedArtifact = TestCompilationArtifact.Executable(buildDir.resolve("logging_invalid")) + val compilation = ExecutableCompilation( + testRunSettings, + freeCompilerArgs = testCase.freeCompilerArgs, + sourceModules = testCase.modules, + extras = testCase.extras, + dependencies = emptyList(), + expectedArtifact = expectedArtifact, + ) + val compilationResult = compilation.result + val goldenData = rootDir.resolve("logging_invalid_error.txt") + + KotlinTestUtils.assertEqualsToFile(goldenData, compilationResult.toOutput()) + } } @Suppress("JUnitTestCaseWithNoTests") diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestDirectives.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestDirectives.kt index 662e1cc8f2b..a5be6bff771 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestDirectives.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/TestDirectives.kt @@ -448,11 +448,12 @@ internal fun parseProgramArguments(registeredDirectives: RegisteredDirectives): internal fun parseOutputRegex(registeredDirectives: RegisteredDirectives): TestRunCheck.OutputMatcher? { if (OUTPUT_REGEX !in registeredDirectives) return null - val regexStr = registeredDirectives.singleValue(OUTPUT_REGEX) - val regex = regexStr.toRegex(RegexOption.DOT_MATCHES_ALL) + val regexes = registeredDirectives[OUTPUT_REGEX].map { it.toRegex(RegexOption.DOT_MATCHES_ALL) } return TestRunCheck.OutputMatcher { - assertTrue(regex.matches(it)) { - "Regex `$regex` failed to match `$it`" + regexes.forEach { regex -> + assertTrue(regex.matches(it)) { + "Regex `$regex` failed to match `$it`" + } } true }