[K/N][tests] Migrate various runtime/ tests ^KT-61259
This commit is contained in:
committed by
Space Team
parent
7ad4e58a7a
commit
d88092aa94
@@ -285,195 +285,6 @@ Task dynamicTest(String name, Closure<KonanDynamicTest> configureClosure) {
|
|||||||
// source = "codegen/object/constructor.kt"
|
// 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") {
|
standaloneTest("initializers_testInfrastructure") {
|
||||||
source = "codegen/initializers/testInfrastructure.kt"
|
source = "codegen/initializers/testInfrastructure.kt"
|
||||||
flags = ["-tr"]
|
flags = ["-tr"]
|
||||||
@@ -571,128 +382,6 @@ standaloneTest("throw_from_except_constr") {
|
|||||||
source = "runtime/exceptions/throw_from_except_constr.kt"
|
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) {
|
tasks.register("vararg0", KonanLocalTest) {
|
||||||
source = "lower/vararg.kt"
|
source = "lower/vararg.kt"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {}
|
|
||||||
@@ -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<A> = 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<A> = 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<IncorrectDereferenceException> {
|
|
||||||
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<A> = 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<A> = 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<A> = 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<A> = 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<A> = 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<IncorrectDereferenceException> {
|
|
||||||
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<IncorrectDereferenceException> {
|
|
||||||
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<A>)
|
|
||||||
|
|
||||||
@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<IncorrectDereferenceException> {
|
|
||||||
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<AtomicReference<WorkerBoundReference<A>?>, WeakReference<WorkerBoundReference<A>>, WeakReference<A>> {
|
|
||||||
val ref = WorkerBoundReference(A(initial))
|
|
||||||
val refOwner: AtomicReference<WorkerBoundReference<A>?> = 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<AtomicReference<WorkerBoundReference<A>?>, WeakReference<WorkerBoundReference<A>>, WeakReference<A>> {
|
|
||||||
val ref = WorkerBoundReference(A(initial)).freeze()
|
|
||||||
val refOwner: AtomicReference<WorkerBoundReference<A>?> = 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<A>, 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<WeakReference<A>, Future<Unit>> {
|
|
||||||
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<WorkerBoundReference<A>> {
|
|
||||||
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<B2>
|
|
||||||
}
|
|
||||||
|
|
||||||
data class B2(val b1: WorkerBoundReference<B1>)
|
|
||||||
|
|
||||||
fun createCyclicGarbage(): Triple<AtomicReference<WorkerBoundReference<B1>?>, WeakReference<B1>, WeakReference<B2>> {
|
|
||||||
val ref1 = WorkerBoundReference(B1())
|
|
||||||
val ref1Owner: AtomicReference<WorkerBoundReference<B1>?> = 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<AtomicReference<WorkerBoundReference<B1>?>, WeakReference<B1>, WeakReference<B2>> {
|
|
||||||
val ref1 = WorkerBoundReference(B1()).freeze()
|
|
||||||
val ref1Owner: AtomicReference<WorkerBoundReference<B1>?> = 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<AtomicReference<WorkerBoundReference<B1>?>, WeakReference<B1>, WeakReference<B2>> {
|
|
||||||
val ref1 = WorkerBoundReference(B1()).freeze()
|
|
||||||
val ref1Owner: AtomicReference<WorkerBoundReference<B1>?> = 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<WorkerBoundReference<C2>?>
|
|
||||||
|
|
||||||
fun dispose() {
|
|
||||||
c2.value = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class C2(val c1: AtomicReference<WorkerBoundReference<C1>>)
|
|
||||||
|
|
||||||
fun createCyclicGarbageWithAtomicsFrozen(): Triple<AtomicReference<WorkerBoundReference<C1>?>, WeakReference<C1>, WeakReference<C2>> {
|
|
||||||
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<WorkerBoundReference<C1>?>) {
|
|
||||||
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<WorkerBoundReference> 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<C2> and schedules C2 removal from the root set
|
|
||||||
GC.collect()
|
|
||||||
// Frees C2, finalizes WorkerBoundReference<C1> 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<AtomicReference<WorkerBoundReference<C1>?>, WeakReference<C1>, WeakReference<C2>> {
|
|
||||||
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<WorkerBoundReference> 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<IncorrectDereferenceException> {
|
|
||||||
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<IncorrectDereferenceException> {
|
|
||||||
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<FreezingException> {
|
|
||||||
wrapper.freeze()
|
|
||||||
}
|
|
||||||
ref.freeze()
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
42
|
|
||||||
@@ -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<Any> {
|
|
||||||
val loop = Array<Any?>(1, { null })
|
|
||||||
loop[0] = loop
|
|
||||||
|
|
||||||
return WeakReference(loop)
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
zzz
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
zzz
|
|
||||||
@@ -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<String>) {
|
|
||||||
kotlin.native.runtime.GC.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Ok
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
Data(s=Hello)
|
|
||||||
null
|
|
||||||
OK
|
|
||||||
@@ -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")
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
OK
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
true
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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<String>) {
|
|
||||||
printAll()
|
|
||||||
kotlin.native.runtime.GC.collect()
|
|
||||||
println("OK")
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
123
|
|
||||||
OK
|
|
||||||
@@ -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())
|
|
||||||
@@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<Throwable> {
|
|
||||||
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<Throwable> {
|
|
||||||
future.result
|
|
||||||
}
|
|
||||||
worker.requestTermination().result
|
|
||||||
}
|
|
||||||
-17
@@ -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")
|
|
||||||
}
|
|
||||||
-15
@@ -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")
|
|
||||||
}
|
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<C>)
|
||||||
|
|
||||||
|
private val global1: WorkerBoundReference<C> = WorkerBoundReference(C(3))
|
||||||
|
private val global2: WorkerBoundReference<C> = WorkerBoundReference(C(3))
|
||||||
|
private val global3: WorkerBoundReference<C> = WorkerBoundReference(C(3).freeze())
|
||||||
|
private val global4: WorkerBoundReference<C> = WorkerBoundReference(C(3))
|
||||||
|
private val global5: WorkerBoundReference<C> = WorkerBoundReference(C(3))
|
||||||
|
private val global6: WorkerBoundReference<C> = WorkerBoundReference(C(3))
|
||||||
|
private val global7: WorkerBoundReference<C> = 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,6 +56,7 @@ val debuggerTest = nativeTest("debuggerTest", "debugger")
|
|||||||
val cachesTest = nativeTest("cachesTest", "caches")
|
val cachesTest = nativeTest("cachesTest", "caches")
|
||||||
val klibTest = nativeTest("klibTest", "klib")
|
val klibTest = nativeTest("klibTest", "klib")
|
||||||
val standaloneTest = nativeTest("standaloneTest", "standalone")
|
val standaloneTest = nativeTest("standaloneTest", "standalone")
|
||||||
|
val gcTest = nativeTest("gcTest", "gc")
|
||||||
|
|
||||||
val testTags = findProperty("kotlin.native.tests.tags")?.toString()
|
val testTags = findProperty("kotlin.native.tests.tags")?.toString()
|
||||||
// Note: arbitrary JUnit tag expressions can be used in this property.
|
// Note: arbitrary JUnit tag expressions can be used in this property.
|
||||||
|
|||||||
+2
-5
@@ -1,8 +1,5 @@
|
|||||||
/*
|
// This test allocs a large array that may make Linux kill any process inlcuding Gradle with OOM-killer
|
||||||
* Copyright 2010-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
// DISABLE_NATIVE: targetFamily=LINUX
|
||||||
* that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
fun testArrayAllocation(size: Int) {
|
fun testArrayAllocation(size: Int) {
|
||||||
+5
-4
@@ -1,7 +1,8 @@
|
|||||||
/*
|
// KIND: STANDALONE_NO_TR
|
||||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
* that can be found in the LICENSE file.
|
// 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)
|
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, kotlin.native.concurrent.ObsoleteWorkersApi::class)
|
||||||
|
|
||||||
import kotlin.concurrent.AtomicInt
|
import kotlin.concurrent.AtomicInt
|
||||||
+17
-1
@@ -7,8 +7,10 @@ package org.jetbrains.kotlin.konan.test.blackbox;
|
|||||||
|
|
||||||
import com.intellij.testFramework.TestDataPath;
|
import com.intellij.testFramework.TestDataPath;
|
||||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
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.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.konan.test.blackbox.support.group.FirPipeline;
|
||||||
import org.jetbrains.kotlin.test.TestMetadata;
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -20,6 +22,8 @@ import java.util.regex.Pattern;
|
|||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
@TestMetadata("native/native.tests/stress/testData")
|
@TestMetadata("native/native.tests/stress/testData")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@Tag("stress")
|
||||||
|
@EnforcedProperty(property = ClassLevelProperty.EXECUTION_TIMEOUT, propertyValue = "5m")
|
||||||
@UseStandardTestCaseGroupProvider()
|
@UseStandardTestCaseGroupProvider()
|
||||||
@Tag("frontend-fir")
|
@Tag("frontend-fir")
|
||||||
@FirPipeline()
|
@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);
|
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
|
@Test
|
||||||
@TestMetadata("kt63423_dispose_on_main_stress.kt")
|
@TestMetadata("kt63423_dispose_on_main_stress.kt")
|
||||||
public void testKt63423_dispose_on_main_stress() {
|
public void testKt63423_dispose_on_main_stress() {
|
||||||
runTest("native/native.tests/stress/testData/kt63423_dispose_on_main_stress.kt");
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
@@ -7,6 +7,9 @@ package org.jetbrains.kotlin.konan.test.blackbox;
|
|||||||
|
|
||||||
import com.intellij.testFramework.TestDataPath;
|
import com.intellij.testFramework.TestDataPath;
|
||||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
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.konan.test.blackbox.support.group.UseStandardTestCaseGroupProvider;
|
||||||
import org.jetbrains.kotlin.test.TestMetadata;
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -18,6 +21,8 @@ import java.util.regex.Pattern;
|
|||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
@TestMetadata("native/native.tests/stress/testData")
|
@TestMetadata("native/native.tests/stress/testData")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@Tag("stress")
|
||||||
|
@EnforcedProperty(property = ClassLevelProperty.EXECUTION_TIMEOUT, propertyValue = "5m")
|
||||||
@UseStandardTestCaseGroupProvider()
|
@UseStandardTestCaseGroupProvider()
|
||||||
public class NativeStressTestGenerated extends AbstractNativeBlackBoxTest {
|
public class NativeStressTestGenerated extends AbstractNativeBlackBoxTest {
|
||||||
@Test
|
@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);
|
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
|
@Test
|
||||||
@TestMetadata("kt63423_dispose_on_main_stress.kt")
|
@TestMetadata("kt63423_dispose_on_main_stress.kt")
|
||||||
public void testKt63423_dispose_on_main_stress() {
|
public void testKt63423_dispose_on_main_stress() {
|
||||||
runTest("native/native.tests/stress/testData/kt63423_dispose_on_main_stress.kt");
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
+2
-1
@@ -45,7 +45,7 @@ fun produceB(): String {
|
|||||||
return "B+${A.a}"
|
return "B+${A.a}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun runTest() {
|
fun box(): String {
|
||||||
val aWorker = Worker.start()
|
val aWorker = Worker.start()
|
||||||
aWorkerId.value = aWorker.id
|
aWorkerId.value = aWorker.id
|
||||||
val bWorkers = Array(bWorkersCount, { _ -> Worker.start() })
|
val bWorkers = Array(bWorkersCount, { _ -> Worker.start() })
|
||||||
@@ -73,4 +73,5 @@ fun produceB(): String {
|
|||||||
worker.requestTermination().result
|
worker.requestTermination().result
|
||||||
}
|
}
|
||||||
aWorker.requestTermination().result
|
aWorker.requestTermination().result
|
||||||
|
return "OK"
|
||||||
}
|
}
|
||||||
+2
-38
@@ -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.*
|
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")
|
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||||
@kotlin.native.internal.CanBePrecreated
|
@kotlin.native.internal.CanBePrecreated
|
||||||
object CompileTime {
|
object CompileTime {
|
||||||
@@ -47,11 +14,7 @@ object CompileTime {
|
|||||||
const val char = Char.MIN_VALUE
|
const val char = Char.MIN_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
class AClass {
|
fun box(): String {
|
||||||
companion object {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun runTest2() {
|
|
||||||
assertEquals(Int.MIN_VALUE, CompileTime.int)
|
assertEquals(Int.MIN_VALUE, CompileTime.int)
|
||||||
assertEquals(Byte.MIN_VALUE, CompileTime.byte)
|
assertEquals(Byte.MIN_VALUE, CompileTime.byte)
|
||||||
assertEquals(Short.MIN_VALUE, CompileTime.short)
|
assertEquals(Short.MIN_VALUE, CompileTime.short)
|
||||||
@@ -60,4 +23,5 @@ class AClass {
|
|||||||
assertEquals(1.0f, CompileTime.float)
|
assertEquals(1.0f, CompileTime.float)
|
||||||
assertEquals(1.0, CompileTime.double)
|
assertEquals(1.0, CompileTime.double)
|
||||||
assertEquals(Char.MIN_VALUE, CompileTime.char)
|
assertEquals(Char.MIN_VALUE, CompileTime.char)
|
||||||
|
return "OK"
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
+3
-9
@@ -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.*
|
import kotlin.test.*
|
||||||
|
|
||||||
@Test fun runTest() {
|
fun box(): String {
|
||||||
var x = Any()
|
var x = Any()
|
||||||
|
|
||||||
for (i in 0..1) {
|
for (i in 0..1) {
|
||||||
@@ -24,8 +17,9 @@ import kotlin.test.*
|
|||||||
}
|
}
|
||||||
|
|
||||||
y.use()
|
y.use()
|
||||||
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Any?.use() {
|
private fun Any?.use() {
|
||||||
var x = this
|
var x = this
|
||||||
}
|
}
|
||||||
+4
-10
@@ -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.*
|
import kotlin.test.*
|
||||||
|
|
||||||
@Test fun runTest() {
|
fun box(): String {
|
||||||
foo().use()
|
foo().use()
|
||||||
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun foo(): Any {
|
private fun foo(): Any {
|
||||||
var x = Any()
|
var x = Any()
|
||||||
|
|
||||||
for (i in 0..1) {
|
for (i in 0..1) {
|
||||||
@@ -28,6 +22,6 @@ fun foo(): Any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Any?.use() {
|
private fun Any?.use() {
|
||||||
var x = this
|
var x = this
|
||||||
}
|
}
|
||||||
+3
-9
@@ -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.*
|
import kotlin.test.*
|
||||||
|
|
||||||
@Test fun runTest() {
|
fun box(): String {
|
||||||
var x = Error()
|
var x = Error()
|
||||||
|
|
||||||
for (i in 0..1) {
|
for (i in 0..1) {
|
||||||
@@ -26,8 +19,9 @@ import kotlin.test.*
|
|||||||
} catch (e: Error) {
|
} catch (e: Error) {
|
||||||
e.use()
|
e.use()
|
||||||
}
|
}
|
||||||
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Any?.use() {
|
private fun Any?.use() {
|
||||||
var x = this
|
var x = this
|
||||||
}
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
OK
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
warning: cached libraries will not be used with runtime logs
|
||||||
|
OK
|
||||||
+3
@@ -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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
fun main() {}
|
||||||
+12
@@ -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)
|
||||||
|
}
|
||||||
+5
-118
@@ -1,11 +1,5 @@
|
|||||||
/*
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative,kotlin.native.runtime.NativeRuntimeApi,kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||||
* 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
|
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
@@ -21,10 +15,6 @@ import kotlin.native.runtime.GC
|
|||||||
class AtomicBoolean(initialValue: Boolean) {
|
class AtomicBoolean(initialValue: Boolean) {
|
||||||
private val impl = AtomicInt(if (initialValue) 1 else 0)
|
private val impl = AtomicInt(if (initialValue) 1 else 0)
|
||||||
|
|
||||||
init {
|
|
||||||
freeze()
|
|
||||||
}
|
|
||||||
|
|
||||||
public var value: Boolean
|
public var value: Boolean
|
||||||
get() = impl.value != 0
|
get() = impl.value != 0
|
||||||
set(new) { impl.value = if (new) 1 else 0 }
|
set(new) { impl.value = if (new) 1 else 0 }
|
||||||
@@ -38,34 +28,6 @@ class FunBox(private val impl: () -> Unit) {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCleanerLambda() {
|
fun testCleanerLambda() {
|
||||||
val called = AtomicBoolean(false);
|
|
||||||
var funBoxWeak: WeakReference<FunBox>? = null
|
|
||||||
var cleanerWeak: WeakReference<Cleaner>? = 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);
|
val called = AtomicBoolean(false);
|
||||||
var funBoxWeak: WeakReference<FunBox>? = null
|
var funBoxWeak: WeakReference<FunBox>? = null
|
||||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||||
@@ -90,34 +52,6 @@ fun testCleanerNonSharedLambda() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCleanerAnonymousFunction() {
|
fun testCleanerAnonymousFunction() {
|
||||||
val called = AtomicBoolean(false);
|
|
||||||
var funBoxWeak: WeakReference<FunBox>? = null
|
|
||||||
var cleanerWeak: WeakReference<Cleaner>? = 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);
|
val called = AtomicBoolean(false);
|
||||||
var funBoxWeak: WeakReference<FunBox>? = null
|
var funBoxWeak: WeakReference<FunBox>? = null
|
||||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||||
@@ -142,34 +76,6 @@ fun testCleanerNonSharedAnonymousFunction() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCleanerFunctionReference() {
|
fun testCleanerFunctionReference() {
|
||||||
val called = AtomicBoolean(false);
|
|
||||||
var funBoxWeak: WeakReference<FunBox>? = null
|
|
||||||
var cleanerWeak: WeakReference<Cleaner>? = 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);
|
val called = AtomicBoolean(false);
|
||||||
var funBoxWeak: WeakReference<FunBox>? = null
|
var funBoxWeak: WeakReference<FunBox>? = null
|
||||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||||
@@ -192,18 +98,6 @@ fun testCleanerNonSharedFunctionReference() {
|
|||||||
assertNull(funBoxWeak!!.value)
|
assertNull(funBoxWeak!!.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCleanerFailWithNonShareableArgument() {
|
|
||||||
// Only for legacy MM.
|
|
||||||
if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val funBox = FunBox {}
|
|
||||||
assertFailsWith<IllegalArgumentException> {
|
|
||||||
createCleaner(funBox) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCleanerCleansWithoutGC() {
|
fun testCleanerCleansWithoutGC() {
|
||||||
val called = AtomicBoolean(false);
|
val called = AtomicBoolean(false);
|
||||||
@@ -211,12 +105,11 @@ fun testCleanerCleansWithoutGC() {
|
|||||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||||
{
|
{
|
||||||
val cleaner = {
|
val cleaner = {
|
||||||
val funBox = FunBox { called.value = true }.freeze()
|
val funBox = FunBox { called.value = true }
|
||||||
funBoxWeak = WeakReference(funBox)
|
funBoxWeak = WeakReference(funBox)
|
||||||
createCleaner(funBox) { it.call() }
|
createCleaner(funBox) { it.call() }
|
||||||
}()
|
}()
|
||||||
GC.collect() // Make sure local funBox reference is gone
|
GC.collect() // Make sure local funBox reference is gone
|
||||||
cleaner.freeze()
|
|
||||||
cleanerWeak = WeakReference(cleaner)
|
cleanerWeak = WeakReference(cleaner)
|
||||||
assertFalse(called.value)
|
assertFalse(called.value)
|
||||||
}()
|
}()
|
||||||
@@ -228,12 +121,6 @@ fun testCleanerCleansWithoutGC() {
|
|||||||
waitCleanerWorker()
|
waitCleanerWorker()
|
||||||
|
|
||||||
assertTrue(called.value)
|
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)
|
val globalInt = AtomicInt(0)
|
||||||
@@ -244,7 +131,7 @@ fun testCleanerWithInt() {
|
|||||||
{
|
{
|
||||||
val cleaner = createCleaner(42) {
|
val cleaner = createCleaner(42) {
|
||||||
globalInt.value = it
|
globalInt.value = it
|
||||||
}.freeze()
|
}
|
||||||
cleanerWeak = WeakReference(cleaner)
|
cleanerWeak = WeakReference(cleaner)
|
||||||
assertEquals(0, globalInt.value)
|
assertEquals(0, globalInt.value)
|
||||||
}()
|
}()
|
||||||
@@ -282,7 +169,7 @@ fun testCleanerWithException() {
|
|||||||
var funBoxWeak: WeakReference<FunBox>? = null
|
var funBoxWeak: WeakReference<FunBox>? = null
|
||||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||||
{
|
{
|
||||||
val funBox = FunBox { called.value = true }.freeze()
|
val funBox = FunBox { called.value = true }
|
||||||
funBoxWeak = WeakReference(funBox)
|
funBoxWeak = WeakReference(funBox)
|
||||||
val cleaner = createCleaner(funBox) {
|
val cleaner = createCleaner(funBox) {
|
||||||
it.call()
|
it.call()
|
||||||
+4
-6
@@ -1,8 +1,5 @@
|
|||||||
/*
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative,kotlin.native.runtime.NativeRuntimeApi,kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||||
* that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class)
|
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
@@ -18,7 +15,8 @@ var tlsCleaner: Cleaner? = null
|
|||||||
|
|
||||||
val value = AtomicInt(0)
|
val value = AtomicInt(0)
|
||||||
|
|
||||||
fun main() {
|
@Test
|
||||||
|
fun test() {
|
||||||
val worker = Worker.start()
|
val worker = Worker.start()
|
||||||
|
|
||||||
worker.execute(TransferMode.SAFE, {}) {
|
worker.execute(TransferMode.SAFE, {}) {
|
||||||
+6
-15
@@ -1,10 +1,5 @@
|
|||||||
/*
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative,kotlin.native.runtime.NativeRuntimeApi,kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||||
* 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
|
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
@@ -20,10 +15,6 @@ import kotlin.native.runtime.GC
|
|||||||
class AtomicBoolean(initialValue: Boolean) {
|
class AtomicBoolean(initialValue: Boolean) {
|
||||||
private val impl = AtomicInt(if (initialValue) 1 else 0)
|
private val impl = AtomicInt(if (initialValue) 1 else 0)
|
||||||
|
|
||||||
init {
|
|
||||||
freeze()
|
|
||||||
}
|
|
||||||
|
|
||||||
public var value: Boolean
|
public var value: Boolean
|
||||||
get() = impl.value != 0
|
get() = impl.value != 0
|
||||||
set(new) { impl.value = if (new) 1 else 0 }
|
set(new) { impl.value = if (new) 1 else 0 }
|
||||||
@@ -43,7 +34,7 @@ fun testCleanerDestroyInChild() {
|
|||||||
var funBoxWeak: WeakReference<FunBox>? = null
|
var funBoxWeak: WeakReference<FunBox>? = null
|
||||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||||
worker.execute(TransferMode.SAFE, {
|
worker.execute(TransferMode.SAFE, {
|
||||||
val funBox = FunBox { called.value = true }.freeze()
|
val funBox = FunBox { called.value = true }
|
||||||
funBoxWeak = WeakReference(funBox)
|
funBoxWeak = WeakReference(funBox)
|
||||||
val cleaner = createCleaner(funBox) { it.call() }
|
val cleaner = createCleaner(funBox) { it.call() }
|
||||||
cleanerWeak = WeakReference(cleaner)
|
cleanerWeak = WeakReference(cleaner)
|
||||||
@@ -71,7 +62,7 @@ fun testCleanerDestroyWithChild() {
|
|||||||
var funBoxWeak: WeakReference<FunBox>? = null
|
var funBoxWeak: WeakReference<FunBox>? = null
|
||||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||||
worker.execute(TransferMode.SAFE, {
|
worker.execute(TransferMode.SAFE, {
|
||||||
val funBox = FunBox { called.value = true }.freeze()
|
val funBox = FunBox { called.value = true }
|
||||||
funBoxWeak = WeakReference(funBox)
|
funBoxWeak = WeakReference(funBox)
|
||||||
val cleaner = createCleaner(funBox) { it.call() }
|
val cleaner = createCleaner(funBox) { it.call() }
|
||||||
cleanerWeak = WeakReference(cleaner)
|
cleanerWeak = WeakReference(cleaner)
|
||||||
@@ -100,7 +91,7 @@ fun testCleanerDestroyInMain() {
|
|||||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||||
{
|
{
|
||||||
val result = worker.execute(TransferMode.SAFE, { called }) { called ->
|
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() }
|
val cleaner = createCleaner(funBox) { it.call() }
|
||||||
Triple(cleaner, WeakReference(funBox), WeakReference(cleaner))
|
Triple(cleaner, WeakReference(funBox), WeakReference(cleaner))
|
||||||
}.result
|
}.result
|
||||||
@@ -130,7 +121,7 @@ fun testCleanerDestroyShared() {
|
|||||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||||
val cleanerHolder: AtomicReference<Cleaner?> = AtomicReference(null);
|
val cleanerHolder: AtomicReference<Cleaner?> = AtomicReference(null);
|
||||||
{
|
{
|
||||||
val funBox = FunBox { called.value = true }.freeze()
|
val funBox = FunBox { called.value = true }
|
||||||
funBoxWeak = WeakReference(funBox)
|
funBoxWeak = WeakReference(funBox)
|
||||||
val cleaner = createCleaner(funBox) { it.call() }
|
val cleaner = createCleaner(funBox) { it.call() }
|
||||||
cleanerWeak = WeakReference(cleaner)
|
cleanerWeak = WeakReference(cleaner)
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
import kotlin.native.runtime.GC
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
|
||||||
|
@Test
|
||||||
|
fun test() {
|
||||||
|
GC.collect()
|
||||||
|
}
|
||||||
+2
-8
@@ -1,10 +1,4 @@
|
|||||||
/*
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
* 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
|
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
data class Node(val data: Int, var next: Node?, var prev: Node?, val outer: Node?)
|
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)
|
createCycles(outer)
|
||||||
kotlin.native.runtime.GC.collect()
|
kotlin.native.runtime.GC.collect()
|
||||||
// Ensure outer is not collected.
|
// Ensure outer is not collected.
|
||||||
println(outer.data)
|
assertEquals(42, outer.data)
|
||||||
}
|
}
|
||||||
+19
@@ -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<Any> {
|
||||||
|
val loop = Array<Any?>(1, { null })
|
||||||
|
loop[0] = loop
|
||||||
|
|
||||||
|
return WeakReference(loop)
|
||||||
|
}
|
||||||
-7
@@ -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.*
|
import kotlin.test.*
|
||||||
|
|
||||||
//fun foo1(arg: String) : String = foo0(arg)
|
//fun foo1(arg: String) : String = foo0(arg)
|
||||||
+16
@@ -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)
|
||||||
|
}
|
||||||
+1
-8
@@ -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.*
|
import kotlin.test.*
|
||||||
|
|
||||||
class A(val s: String)
|
class A(val s: String)
|
||||||
@@ -29,5 +22,5 @@ val global = B()
|
|||||||
|
|
||||||
@Test fun runTest() {
|
@Test fun runTest() {
|
||||||
bar(global)
|
bar(global)
|
||||||
println(global.a!!.s)
|
assertEquals("zzz", global.a!!.s)
|
||||||
}
|
}
|
||||||
+2
-8
@@ -1,14 +1,8 @@
|
|||||||
/*
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
// FREE_COMPILER_ARGS: -Xbinary=gcSchedulerType=manual -opt-in=kotlin.native.runtime.NativeRuntimeApi,kotlin.ExperimentalStdlibApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||||
* 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)
|
|
||||||
|
|
||||||
import kotlin.native.runtime.GC
|
import kotlin.native.runtime.GC
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `nothing new collected`() {
|
fun `nothing new collected`() {
|
||||||
GC.collect()
|
GC.collect()
|
||||||
+23
@@ -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)
|
||||||
|
}
|
||||||
+29
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-14
@@ -1,24 +1,18 @@
|
|||||||
/*
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
* 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
|
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
import kotlin.native.ref.*
|
import kotlin.native.ref.*
|
||||||
|
|
||||||
data class Data(val s: String)
|
data class Data(val s: String)
|
||||||
|
|
||||||
|
@OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||||
fun localWeak(): WeakReference<Data> {
|
fun localWeak(): WeakReference<Data> {
|
||||||
val x = Data("Hello")
|
val x = Data("Hello")
|
||||||
val weak = WeakReference(x)
|
val weak = WeakReference(x)
|
||||||
println(weak.get())
|
assertSame(x, weak.get())
|
||||||
return weak
|
return weak
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||||
fun multiWeak(): Array<WeakReference<Data>> {
|
fun multiWeak(): Array<WeakReference<Data>> {
|
||||||
val x = Data("Hello")
|
val x = Data("Hello")
|
||||||
val weaks = Array(100, { WeakReference(x) } )
|
val weaks = Array(100, { WeakReference(x) } )
|
||||||
@@ -28,12 +22,11 @@ fun multiWeak(): Array<WeakReference<Data>> {
|
|||||||
return weaks
|
return weaks
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
|
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class, kotlin.experimental.ExperimentalNativeApi::class)
|
||||||
@Test fun runTest() {
|
@Test fun runTest() {
|
||||||
val weak = localWeak()
|
val weak = localWeak()
|
||||||
kotlin.native.runtime.GC.collect()
|
kotlin.native.runtime.GC.collect()
|
||||||
val value = weak.get()
|
assertNull(weak.get())
|
||||||
println(value?.toString())
|
|
||||||
|
|
||||||
val weaks = multiWeak()
|
val weaks = multiWeak()
|
||||||
|
|
||||||
@@ -42,5 +35,4 @@ fun multiWeak(): Array<WeakReference<Data>> {
|
|||||||
weaks.forEach {
|
weaks.forEach {
|
||||||
it -> if (it.get()?.s != null) throw Error("not null")
|
it -> if (it.get()?.s != null) throw Error("not null")
|
||||||
}
|
}
|
||||||
println("OK")
|
|
||||||
}
|
}
|
||||||
+13
@@ -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)
|
||||||
|
}
|
||||||
+15
-27
@@ -1,6 +1,6 @@
|
|||||||
@file:OptIn(FreezingIsDeprecated::class, kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class, kotlinx.cinterop.ExperimentalForeignApi::class)
|
// OUTPUT_DATA_FILE: worker10.out
|
||||||
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
package runtime.workers.worker10
|
// FREE_COMPILER_ARGS: -opt-in=kotlin.experimental.ExperimentalNativeApi,kotlin.native.runtime.NativeRuntimeApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
import kotlin.concurrent.AtomicReference
|
import kotlin.concurrent.AtomicReference
|
||||||
@@ -42,33 +42,21 @@ val topSharedData = Data(43)
|
|||||||
}
|
}
|
||||||
|
|
||||||
worker.execute(TransferMode.SAFE, { -> }, {
|
worker.execute(TransferMode.SAFE, { -> }, {
|
||||||
it -> try {
|
it -> topStringVar == "string"
|
||||||
topStringVar == "string"
|
|
||||||
} catch (e: IncorrectDereferenceException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}).consume {
|
}).consume {
|
||||||
result -> assertEquals(Platform.memoryModel != MemoryModel.STRICT, result)
|
result -> assertTrue(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.execute(TransferMode.SAFE, { -> }, {
|
worker.execute(TransferMode.SAFE, { -> }, {
|
||||||
it -> try {
|
it -> topSharedStringWithGetter == "top"
|
||||||
topSharedStringWithGetter == "top"
|
|
||||||
} catch (e: IncorrectDereferenceException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}).consume {
|
}).consume {
|
||||||
result -> assertEquals(true, result)
|
result -> assertTrue(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.execute(TransferMode.SAFE, { -> }, {
|
worker.execute(TransferMode.SAFE, { -> }, {
|
||||||
it -> try {
|
it -> topData.x == 42
|
||||||
topData.x == 42
|
|
||||||
} catch (e: IncorrectDereferenceException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}).consume {
|
}).consume {
|
||||||
result -> assertEquals(Platform.memoryModel != MemoryModel.STRICT, result)
|
result -> assertTrue(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.execute(TransferMode.SAFE, { -> }, {
|
worker.execute(TransferMode.SAFE, { -> }, {
|
||||||
@@ -78,15 +66,15 @@ val topSharedData = Data(43)
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}).consume {
|
}).consume {
|
||||||
result -> assertEquals(true, result)
|
result -> assertTrue(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.requestTermination().result
|
worker.requestTermination().result
|
||||||
println("OK")
|
println("OK")
|
||||||
}
|
}
|
||||||
|
|
||||||
val atomicRef = AtomicReference<Any?>(Any().freeze())
|
val atomicRef = AtomicReference<Any?>(Any())
|
||||||
val stableRef = StableRef.create(Any().freeze())
|
val stableRef = StableRef.create(Any())
|
||||||
val semaphore = AtomicInt(0)
|
val semaphore = AtomicInt(0)
|
||||||
|
|
||||||
@Test fun runTest2() {
|
@Test fun runTest2() {
|
||||||
@@ -127,7 +115,7 @@ fun <T: Any> ensureWeakIs(weak: WeakReference<T>, expected: T?) {
|
|||||||
assertEquals(expected, weak.get())
|
assertEquals(expected, weak.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
val stableHolder1 = StableRef.create(("hello" to "world").freeze())
|
val stableHolder1 = StableRef.create(("hello" to "world"))
|
||||||
|
|
||||||
@Test fun runTest4() {
|
@Test fun runTest4() {
|
||||||
val worker = Worker.start()
|
val worker = Worker.start()
|
||||||
@@ -147,7 +135,7 @@ val stableHolder1 = StableRef.create(("hello" to "world").freeze())
|
|||||||
worker.requestTermination().result
|
worker.requestTermination().result
|
||||||
}
|
}
|
||||||
|
|
||||||
val stableHolder2 = StableRef.create(("hello" to "world").freeze())
|
val stableHolder2 = StableRef.create(("hello" to "world"))
|
||||||
|
|
||||||
@Test fun runTest5() {
|
@Test fun runTest5() {
|
||||||
val worker = Worker.start()
|
val worker = Worker.start()
|
||||||
@@ -167,7 +155,7 @@ val stableHolder2 = StableRef.create(("hello" to "world").freeze())
|
|||||||
worker.requestTermination().result
|
worker.requestTermination().result
|
||||||
}
|
}
|
||||||
|
|
||||||
val atomicRef2 = AtomicReference<Any?>(Any().freeze())
|
val atomicRef2 = AtomicReference<Any?>(Any())
|
||||||
@Test fun runTest6() {
|
@Test fun runTest6() {
|
||||||
semaphore.value = 0
|
semaphore.value = 0
|
||||||
val worker = Worker.start()
|
val worker = Worker.start()
|
||||||
@@ -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<A>)
|
||||||
|
|
||||||
|
fun getOwnerAndWeaks(initial: Int): Triple<AtomicReference<WorkerBoundReference<A>?>, WeakReference<WorkerBoundReference<A>>, WeakReference<A>> {
|
||||||
|
val ref = WorkerBoundReference(A(initial))
|
||||||
|
val refOwner: AtomicReference<WorkerBoundReference<A>?> = 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<AtomicReference<WorkerBoundReference<A>?>, WeakReference<WorkerBoundReference<A>>, WeakReference<A>> {
|
||||||
|
val ref = WorkerBoundReference(A(initial)).freeze()
|
||||||
|
val refOwner: AtomicReference<WorkerBoundReference<A>?> = 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<A>, 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<WeakReference<A>, Future<Unit>> {
|
||||||
|
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<WorkerBoundReference<A>> {
|
||||||
|
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<B2>
|
||||||
|
}
|
||||||
|
|
||||||
|
data class B2(val b1: WorkerBoundReference<B1>)
|
||||||
|
|
||||||
|
fun createCyclicGarbage(): Triple<AtomicReference<WorkerBoundReference<B1>?>, WeakReference<B1>, WeakReference<B2>> {
|
||||||
|
val ref1 = WorkerBoundReference(B1())
|
||||||
|
val ref1Owner: AtomicReference<WorkerBoundReference<B1>?> = 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<AtomicReference<WorkerBoundReference<B1>?>, WeakReference<B1>, WeakReference<B2>> {
|
||||||
|
val ref1 = WorkerBoundReference(B1()).freeze()
|
||||||
|
val ref1Owner: AtomicReference<WorkerBoundReference<B1>?> = 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<AtomicReference<WorkerBoundReference<B1>?>, WeakReference<B1>, WeakReference<B2>> {
|
||||||
|
val ref1 = WorkerBoundReference(B1()).freeze()
|
||||||
|
val ref1Owner: AtomicReference<WorkerBoundReference<B1>?> = 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<WorkerBoundReference<C2>?>
|
||||||
|
|
||||||
|
fun dispose() {
|
||||||
|
c2.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class C2(val c1: AtomicReference<WorkerBoundReference<C1>>)
|
||||||
|
|
||||||
|
fun createCyclicGarbageWithAtomicsFrozen(): Triple<AtomicReference<WorkerBoundReference<C1>?>, WeakReference<C1>, WeakReference<C2>> {
|
||||||
|
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<WorkerBoundReference<C1>?>) {
|
||||||
|
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<WorkerBoundReference> 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<C2> and schedules C2 removal from the root set
|
||||||
|
GC.collect()
|
||||||
|
// Frees C2, finalizes WorkerBoundReference<C1> 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<AtomicReference<WorkerBoundReference<C1>?>, WeakReference<C1>, WeakReference<C2>> {
|
||||||
|
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<WorkerBoundReference> 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
|
||||||
|
}
|
||||||
+2
-4
@@ -1,7 +1,5 @@
|
|||||||
/*
|
// OUTPUT_DATA_FILE: cleaner_in_main_with_checker.out
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
* that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||||
|
|
||||||
import kotlin.native.ref.Cleaner
|
import kotlin.native.ref.Cleaner
|
||||||
+1
-4
@@ -1,7 +1,4 @@
|
|||||||
/*
|
// OUTPUT_DATA_FILE: cleaner_in_main_without_checker.out
|
||||||
* 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)
|
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||||
|
|
||||||
import kotlin.native.ref.createCleaner
|
import kotlin.native.ref.createCleaner
|
||||||
+3
-4
@@ -1,7 +1,6 @@
|
|||||||
/*
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
// EXIT_CODE: !0
|
||||||
* that can be found in the LICENSE file.
|
// OUTPUT_REGEX: Cleaner (0x)?[0-9a-fA-F]+ was disposed during program exit.*
|
||||||
*/
|
|
||||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
-4
@@ -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)
|
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
+3
-4
@@ -1,7 +1,6 @@
|
|||||||
/*
|
// DISABLE_NATIVE: gcType=NOOP
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
// EXIT_CODE: !0
|
||||||
* that can be found in the LICENSE file.
|
// OUTPUT_REGEX: Cleaner (0x)?[0-9a-fA-F]+ was disposed during program exit.*
|
||||||
*/
|
|
||||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
+1
-4
@@ -1,7 +1,4 @@
|
|||||||
/*
|
// OUTPUT_DATA_FILE: cleaner_leak_without_checker.out
|
||||||
* 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)
|
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ExperimentalForeignApi::class)
|
||||||
|
|
||||||
import kotlinx.cinterop.*
|
import kotlinx.cinterop.*
|
||||||
import kotlin.native.Platform
|
import kotlin.native.Platform
|
||||||
+2
-1
@@ -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.*
|
import kotlin.test.*
|
||||||
|
|
||||||
+1
-1
@@ -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.concurrent.*
|
||||||
import kotlin.native.Platform
|
import kotlin.native.Platform
|
||||||
import kotlinx.cinterop.*
|
import kotlinx.cinterop.*
|
||||||
+3
-1
@@ -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.concurrent.*
|
||||||
import kotlin.native.Platform
|
import kotlin.native.Platform
|
||||||
import kotlinx.cinterop.*
|
import kotlinx.cinterop.*
|
||||||
-5
@@ -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)
|
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ObsoleteWorkersApi::class)
|
||||||
import kotlin.native.concurrent.*
|
import kotlin.native.concurrent.*
|
||||||
import kotlin.native.Platform
|
import kotlin.native.Platform
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
val x = initRuntimeIfNeeded()
|
val x = initRuntimeIfNeeded()
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
}
|
}
|
||||||
@@ -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() {}
|
||||||
@@ -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() {}
|
||||||
+1
-4
@@ -1,7 +1,4 @@
|
|||||||
/*
|
// OUTPUT_REGEX: ^$
|
||||||
* 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(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
|
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
+7
-4
@@ -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.*
|
import kotlin.native.concurrent.*
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
Worker.current.executeAfter(0L, {
|
Worker.current.executeAfter(0L, {
|
||||||
throw Error("some error")
|
throw Error("an error")
|
||||||
}.freeze())
|
})
|
||||||
Worker.current.processQueue()
|
Worker.current.processQueue()
|
||||||
println("Will not happen")
|
println("Will not happen")
|
||||||
}
|
}
|
||||||
+18
@@ -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()
|
||||||
|
}
|
||||||
+18
@@ -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<Throwable> {
|
||||||
|
future.result
|
||||||
|
}
|
||||||
|
worker.requestTermination().result
|
||||||
|
}
|
||||||
+7
-4
@@ -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.*
|
import kotlin.native.concurrent.*
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val worker = Worker.start()
|
val worker = Worker.start()
|
||||||
worker.executeAfter(0L, {
|
worker.executeAfter(0L, {
|
||||||
throw Error("some error")
|
throw Error("an error")
|
||||||
}.freeze())
|
})
|
||||||
worker.requestTermination().result
|
worker.requestTermination().result
|
||||||
println("Will not happen")
|
println("Will not happen")
|
||||||
}
|
}
|
||||||
Vendored
+15
@@ -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
|
||||||
|
}
|
||||||
+19
@@ -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
|
||||||
|
}
|
||||||
Vendored
+18
@@ -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<Throwable> {
|
||||||
|
future.result
|
||||||
|
}
|
||||||
|
worker.requestTermination().result
|
||||||
|
}
|
||||||
+74
@@ -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);
|
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
|
@Test
|
||||||
@TestMetadata("isFrozen.kt")
|
@TestMetadata("isFrozen.kt")
|
||||||
public void testIsFrozen() {
|
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
|
@Nested
|
||||||
@TestMetadata("native/native.tests/testData/codegen/fileCheck")
|
@TestMetadata("native/native.tests/testData/codegen/fileCheck")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@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);
|
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
|
@Test
|
||||||
@TestMetadata("multipleModules2.kt")
|
@TestMetadata("multipleModules2.kt")
|
||||||
public void testMultipleModules2() {
|
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);
|
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
|
@Test
|
||||||
@TestMetadata("globalConstants_checkComputedField.kt")
|
@TestMetadata("globalConstants_checkComputedField.kt")
|
||||||
public void testGlobalConstants_checkComputedField() {
|
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
|
@Nested
|
||||||
@TestMetadata("native/native.tests/testData/codegen/vector")
|
@TestMetadata("native/native.tests/testData/codegen/vector")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeGCTestGenerated.java
Generated
+140
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
+147
@@ -40,6 +40,12 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest
|
|||||||
runTest("native/native.tests/testData/standalone/funptr.kt");
|
runTest("native/native.tests/testData/standalone/funptr.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("initRuntimeInGlobal.kt")
|
||||||
|
public void testInitRuntimeInGlobal() {
|
||||||
|
runTest("native/native.tests/testData/standalone/initRuntimeInGlobal.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("kt56048.kt")
|
@TestMetadata("kt56048.kt")
|
||||||
public void testKt56048() {
|
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);
|
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
|
@Test
|
||||||
@TestMetadata("leakMemoryWithRunningThreadChecked.kt")
|
@TestMetadata("leakMemoryWithRunningThreadChecked.kt")
|
||||||
public void testLeakMemoryWithRunningThreadChecked() {
|
public void testLeakMemoryWithRunningThreadChecked() {
|
||||||
@@ -77,6 +119,36 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest
|
|||||||
public void testLeakMemoryWithRunningThreadUnchecked() {
|
public void testLeakMemoryWithRunningThreadUnchecked() {
|
||||||
runTest("native/native.tests/testData/standalone/checkers/leakMemoryWithRunningThreadUnchecked.kt");
|
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
|
@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
|
@Nested
|
||||||
@TestMetadata("native/native.tests/testData/standalone/termination")
|
@TestMetadata("native/native.tests/testData/standalone/termination")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@@ -249,6 +348,12 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest
|
|||||||
runTest("native/native.tests/testData/standalone/termination/processUnhandledException.kt");
|
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
|
@Test
|
||||||
@TestMetadata("terminateWithUnhandledException.kt")
|
@TestMetadata("terminateWithUnhandledException.kt")
|
||||||
public void testTerminateWithUnhandledException() {
|
public void testTerminateWithUnhandledException() {
|
||||||
@@ -303,10 +408,52 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest
|
|||||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionHookWithProcess.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unhandledExceptionInForeignThread.kt")
|
@TestMetadata("unhandledExceptionInForeignThread.kt")
|
||||||
public void testUnhandledExceptionInForeignThread() {
|
public void testUnhandledExceptionInForeignThread() {
|
||||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInForeignThread.kt");
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+70
@@ -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);
|
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
|
@Test
|
||||||
@TestMetadata("isFrozen.kt")
|
@TestMetadata("isFrozen.kt")
|
||||||
public void testIsFrozen() {
|
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
|
@Nested
|
||||||
@TestMetadata("native/native.tests/testData/codegen/fileCheck")
|
@TestMetadata("native/native.tests/testData/codegen/fileCheck")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@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);
|
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
|
@Test
|
||||||
@TestMetadata("multipleModules2.kt")
|
@TestMetadata("multipleModules2.kt")
|
||||||
public void testMultipleModules2() {
|
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);
|
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
|
@Test
|
||||||
@TestMetadata("globalConstants_checkComputedField.kt")
|
@TestMetadata("globalConstants_checkComputedField.kt")
|
||||||
public void testGlobalConstants_checkComputedField() {
|
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
|
@Nested
|
||||||
@TestMetadata("native/native.tests/testData/codegen/vector")
|
@TestMetadata("native/native.tests/testData/codegen/vector")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
Generated
+137
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
+145
@@ -37,6 +37,12 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest {
|
|||||||
runTest("native/native.tests/testData/standalone/funptr.kt");
|
runTest("native/native.tests/testData/standalone/funptr.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("initRuntimeInGlobal.kt")
|
||||||
|
public void testInitRuntimeInGlobal() {
|
||||||
|
runTest("native/native.tests/testData/standalone/initRuntimeInGlobal.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("kt56048.kt")
|
@TestMetadata("kt56048.kt")
|
||||||
public void testKt56048() {
|
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);
|
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
|
@Test
|
||||||
@TestMetadata("leakMemoryWithRunningThreadChecked.kt")
|
@TestMetadata("leakMemoryWithRunningThreadChecked.kt")
|
||||||
public void testLeakMemoryWithRunningThreadChecked() {
|
public void testLeakMemoryWithRunningThreadChecked() {
|
||||||
@@ -72,6 +114,36 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest {
|
|||||||
public void testLeakMemoryWithRunningThreadUnchecked() {
|
public void testLeakMemoryWithRunningThreadUnchecked() {
|
||||||
runTest("native/native.tests/testData/standalone/checkers/leakMemoryWithRunningThreadUnchecked.kt");
|
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
|
@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
|
@Nested
|
||||||
@TestMetadata("native/native.tests/testData/standalone/termination")
|
@TestMetadata("native/native.tests/testData/standalone/termination")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@@ -238,6 +335,12 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest {
|
|||||||
runTest("native/native.tests/testData/standalone/termination/processUnhandledException.kt");
|
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
|
@Test
|
||||||
@TestMetadata("terminateWithUnhandledException.kt")
|
@TestMetadata("terminateWithUnhandledException.kt")
|
||||||
public void testTerminateWithUnhandledException() {
|
public void testTerminateWithUnhandledException() {
|
||||||
@@ -292,10 +395,52 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest {
|
|||||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionHookWithProcess.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unhandledExceptionInForeignThread.kt")
|
@TestMetadata("unhandledExceptionInForeignThread.kt")
|
||||||
public void testUnhandledExceptionInForeignThread() {
|
public void testUnhandledExceptionInForeignThread() {
|
||||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInForeignThread.kt");
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
@@ -531,6 +531,7 @@ fun main() {
|
|||||||
testClass<AbstractNativeBlackBoxTest>(
|
testClass<AbstractNativeBlackBoxTest>(
|
||||||
suiteTestClassName = "NativeStressTestGenerated",
|
suiteTestClassName = "NativeStressTestGenerated",
|
||||||
annotations = listOf(
|
annotations = listOf(
|
||||||
|
*stress(),
|
||||||
provider<UseStandardTestCaseGroupProvider>(),
|
provider<UseStandardTestCaseGroupProvider>(),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@@ -539,6 +540,7 @@ fun main() {
|
|||||||
testClass<AbstractNativeBlackBoxTest>(
|
testClass<AbstractNativeBlackBoxTest>(
|
||||||
suiteTestClassName = "FirNativeStressTestGenerated",
|
suiteTestClassName = "FirNativeStressTestGenerated",
|
||||||
annotations = listOf(
|
annotations = listOf(
|
||||||
|
*stress(),
|
||||||
provider<UseStandardTestCaseGroupProvider>(),
|
provider<UseStandardTestCaseGroupProvider>(),
|
||||||
*frontendFir(),
|
*frontendFir(),
|
||||||
)
|
)
|
||||||
@@ -546,6 +548,28 @@ fun main() {
|
|||||||
model("")
|
model("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// GC tests
|
||||||
|
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
|
||||||
|
testClass<AbstractNativeBlackBoxTest>(
|
||||||
|
suiteTestClassName = "NativeGCTestGenerated",
|
||||||
|
annotations = listOf(
|
||||||
|
*gc(),
|
||||||
|
provider<UseStandardTestCaseGroupProvider>(),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
model("gc")
|
||||||
|
}
|
||||||
|
testClass<AbstractNativeBlackBoxTest>(
|
||||||
|
suiteTestClassName = "FirNativeGCTestGenerated",
|
||||||
|
annotations = listOf(
|
||||||
|
*gc(),
|
||||||
|
provider<UseStandardTestCaseGroupProvider>(),
|
||||||
|
*frontendFir(),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
model("gc")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,3 +632,14 @@ private fun cinterfaceMode(mode: String = "V1") = annotation(
|
|||||||
"property" to ClassLevelProperty.C_INTERFACE_MODE,
|
"property" to ClassLevelProperty.C_INTERFACE_MODE,
|
||||||
"propertyValue" to 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"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|||||||
+54
-4
@@ -9,16 +9,15 @@ import com.intellij.testFramework.TestDataPath
|
|||||||
import org.jetbrains.kotlin.cli.AbstractCliTest
|
import org.jetbrains.kotlin.cli.AbstractCliTest
|
||||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||||
import org.jetbrains.kotlin.config.LanguageVersion
|
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.ClassLevelProperty
|
||||||
import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty
|
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.compilation.*
|
||||||
import org.jetbrains.kotlin.konan.test.blackbox.support.TestCompilerArgs
|
|
||||||
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.LibraryCompilation
|
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.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.compilation.TestCompilationResult.Companion.assertSuccess
|
||||||
import org.jetbrains.kotlin.konan.test.blackbox.support.group.FirPipeline
|
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.PipelineType
|
||||||
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.Settings
|
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.Settings
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
@@ -162,6 +161,57 @@ abstract class CompilerOutputTestBase : AbstractNativeSimpleTest() {
|
|||||||
dir
|
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<CacheMode>().useStaticCacheForDistributionLibraries) "logging_cache_warning.txt" else "empty.txt"
|
||||||
|
)
|
||||||
|
|
||||||
|
KotlinTestUtils.assertEqualsToFile(goldenData, compilationResult.toOutput())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLoggingInvalid() {
|
||||||
|
Assumptions.assumeFalse(testRunSettings.get<CacheMode>().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")
|
@Suppress("JUnitTestCaseWithNoTests")
|
||||||
|
|||||||
+5
-4
@@ -448,11 +448,12 @@ internal fun parseProgramArguments(registeredDirectives: RegisteredDirectives):
|
|||||||
internal fun parseOutputRegex(registeredDirectives: RegisteredDirectives): TestRunCheck.OutputMatcher? {
|
internal fun parseOutputRegex(registeredDirectives: RegisteredDirectives): TestRunCheck.OutputMatcher? {
|
||||||
if (OUTPUT_REGEX !in registeredDirectives)
|
if (OUTPUT_REGEX !in registeredDirectives)
|
||||||
return null
|
return null
|
||||||
val regexStr = registeredDirectives.singleValue(OUTPUT_REGEX)
|
val regexes = registeredDirectives[OUTPUT_REGEX].map { it.toRegex(RegexOption.DOT_MATCHES_ALL) }
|
||||||
val regex = regexStr.toRegex(RegexOption.DOT_MATCHES_ALL)
|
|
||||||
return TestRunCheck.OutputMatcher {
|
return TestRunCheck.OutputMatcher {
|
||||||
assertTrue(regex.matches(it)) {
|
regexes.forEach { regex ->
|
||||||
"Regex `$regex` failed to match `$it`"
|
assertTrue(regex.matches(it)) {
|
||||||
|
"Regex `$regex` failed to match `$it`"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user