[K/N][tests] Migrate various runtime/ tests ^KT-61259
This commit is contained in:
committed by
Space Team
parent
7ad4e58a7a
commit
d88092aa94
@@ -56,6 +56,7 @@ val debuggerTest = nativeTest("debuggerTest", "debugger")
|
||||
val cachesTest = nativeTest("cachesTest", "caches")
|
||||
val klibTest = nativeTest("klibTest", "klib")
|
||||
val standaloneTest = nativeTest("standaloneTest", "standalone")
|
||||
val gcTest = nativeTest("gcTest", "gc")
|
||||
|
||||
val testTags = findProperty("kotlin.native.tests.tags")?.toString()
|
||||
// Note: arbitrary JUnit tag expressions can be used in this property.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// This test allocs a large array that may make Linux kill any process inlcuding Gradle with OOM-killer
|
||||
// DISABLE_NATIVE: targetFamily=LINUX
|
||||
import kotlin.test.*
|
||||
|
||||
fun testArrayAllocation(size: Int) {
|
||||
val arr = IntArray(size)
|
||||
// Force a write into the memory.
|
||||
// TODO: How to make sure the optimizer never deletes this write?
|
||||
arr[size - 1] = 42
|
||||
assertEquals(42, arr[size - 1])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sanity() {
|
||||
// Should always succeed everywhere
|
||||
testArrayAllocation(1 shl 10)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test() {
|
||||
// Will fail on 32 bits.
|
||||
testArrayAllocation(1 shl 30)
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
// KIND: STANDALONE_NO_TR
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
// DISABLE_NATIVE: gcScheduler=AGGRESSIVE
|
||||
// The test checks GC, we need to allocate everything on the heap.
|
||||
// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative -Xdisable-phases=EscapeAnalysis
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, kotlin.native.concurrent.ObsoleteWorkersApi::class)
|
||||
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.concurrent.Volatile
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.identityHashCode
|
||||
import kotlin.native.internal.MemoryUsageInfo
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.random.Random
|
||||
|
||||
// Copying what's done in kotlinx.benchmark
|
||||
// TODO: Could we benefit, if this was in stdlib, and the compiler just new about it?
|
||||
object Blackhole {
|
||||
@Volatile
|
||||
var i0: Int = Random.nextInt()
|
||||
var i1 = i0 + 1
|
||||
|
||||
fun consume(value: Any?) {
|
||||
consume(value.identityHashCode())
|
||||
}
|
||||
|
||||
fun consume(i: Int) {
|
||||
if ((i0 == i) && (i1 == i)) {
|
||||
i0 = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ArrayOfBytes(bytes: Int) {
|
||||
val data = ByteArray(bytes)
|
||||
init {
|
||||
// Write into every OS page.
|
||||
for (i in 0 until data.size step 4096) {
|
||||
data[i] = 42
|
||||
}
|
||||
Blackhole.consume(data)
|
||||
}
|
||||
}
|
||||
|
||||
class ArrayOfBytesWithFinalizer(bytes: Int) {
|
||||
val impl = ArrayOfBytes(bytes)
|
||||
val cleaner = createCleaner(impl) {
|
||||
Blackhole.consume(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun allocateGarbage() {
|
||||
// Total amount of objects here:
|
||||
// - 1 big object with finalizer
|
||||
// - 9 big objects
|
||||
// - 2490 small objects with finalizers
|
||||
// - 97500 small objects without finalizers
|
||||
// And total size is ~50MiB
|
||||
for (i in 0..100_000) {
|
||||
val obj: Any = when {
|
||||
i == 50_000 -> ArrayOfBytesWithFinalizer(1_000_000) // ~1MiB
|
||||
i % 10_000 == 0 -> ArrayOfBytes(1_000_000) // ~1MiB
|
||||
i % 40 == 0 -> ArrayOfBytesWithFinalizer(((i / 100) % 10) * 80) // ~1-100 pointers
|
||||
else -> ArrayOfBytes(((i / 100) % 10) * 80) // ~1-100 pointers
|
||||
}
|
||||
Blackhole.consume(obj)
|
||||
}
|
||||
}
|
||||
|
||||
class PeakRSSChecker(private val rssDiffLimitBytes: Long) {
|
||||
// On Linux, the child process might immediately commit the same amount of memory as the parent.
|
||||
// So, measure difference between peak RSS measurements.
|
||||
private val initialBytes = MemoryUsageInfo.peakResidentSetSizeBytes.also {
|
||||
check(it != 0L) { "Error trying to obtain peak RSS. Check if current platform is supported" }
|
||||
}
|
||||
|
||||
fun check(): Long {
|
||||
val diffBytes = MemoryUsageInfo.peakResidentSetSizeBytes - initialBytes
|
||||
check(diffBytes <= rssDiffLimitBytes) { "Increased peak RSS by $diffBytes bytes which is more than $rssDiffLimitBytes" }
|
||||
return diffBytes
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
// allocateGarbage allocates ~50MiB. Make total amount per mutator ~5GiB.
|
||||
val count = 100
|
||||
// Total amount overall is ~20GiB
|
||||
val threadCount = 4
|
||||
val progressReportsCount = 10
|
||||
// Setting the initial boundary to ~50MiB. The scheduler will adapt this value
|
||||
// dynamically with no upper limit.
|
||||
kotlin.native.runtime.GC.targetHeapBytes = 50_000_000
|
||||
kotlin.native.runtime.GC.minHeapBytes = 50_000_000
|
||||
// Limit memory usage at ~200MiB. 4 times the initial boundary yet still
|
||||
// way less than total expected allocated amount.
|
||||
val peakRSSChecker = PeakRSSChecker(200_000_000L)
|
||||
|
||||
val workers = Array(threadCount) { Worker.start() }
|
||||
val globalCount = AtomicInt(0)
|
||||
val finalGlobalCount = count * workers.size
|
||||
workers.forEach {
|
||||
it.executeAfter(0L) {
|
||||
for (i in 0 until count) {
|
||||
allocateGarbage()
|
||||
peakRSSChecker.check()
|
||||
globalCount.getAndAdd(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val reportStep = finalGlobalCount / progressReportsCount
|
||||
var lastReportCount = -reportStep
|
||||
while (true) {
|
||||
val diffPeakRss = peakRSSChecker.check()
|
||||
val currentCount = globalCount.value
|
||||
if (currentCount >= finalGlobalCount) {
|
||||
break
|
||||
}
|
||||
if (lastReportCount + reportStep <= currentCount) {
|
||||
println("Allocating iteration $currentCount of $finalGlobalCount with peak RSS increase: $diffPeakRss bytes")
|
||||
lastReportCount = currentCount
|
||||
}
|
||||
}
|
||||
|
||||
workers.forEach {
|
||||
it.requestTermination().result
|
||||
}
|
||||
peakRSSChecker.check()
|
||||
}
|
||||
+17
-1
@@ -7,8 +7,10 @@ package org.jetbrains.kotlin.konan.test.blackbox;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.group.UseStandardTestCaseGroupProvider;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty;
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty;
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.group.UseStandardTestCaseGroupProvider;
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.group.FirPipeline;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -20,6 +22,8 @@ import java.util.regex.Pattern;
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("native/native.tests/stress/testData")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@Tag("stress")
|
||||
@EnforcedProperty(property = ClassLevelProperty.EXECUTION_TIMEOUT, propertyValue = "5m")
|
||||
@UseStandardTestCaseGroupProvider()
|
||||
@Tag("frontend-fir")
|
||||
@FirPipeline()
|
||||
@@ -29,9 +33,21 @@ public class FirNativeStressTestGenerated extends AbstractNativeBlackBoxTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/stress/testData"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("array_out_of_memory.kt")
|
||||
public void testArray_out_of_memory() {
|
||||
runTest("native/native.tests/stress/testData/array_out_of_memory.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt63423_dispose_on_main_stress.kt")
|
||||
public void testKt63423_dispose_on_main_stress() {
|
||||
runTest("native/native.tests/stress/testData/kt63423_dispose_on_main_stress.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("stress_gc_allocations.kt")
|
||||
public void testStress_gc_allocations() {
|
||||
runTest("native/native.tests/stress/testData/stress_gc_allocations.kt");
|
||||
}
|
||||
}
|
||||
|
||||
+17
@@ -7,6 +7,9 @@ package org.jetbrains.kotlin.konan.test.blackbox;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty;
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty;
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.group.UseStandardTestCaseGroupProvider;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -18,6 +21,8 @@ import java.util.regex.Pattern;
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("native/native.tests/stress/testData")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@Tag("stress")
|
||||
@EnforcedProperty(property = ClassLevelProperty.EXECUTION_TIMEOUT, propertyValue = "5m")
|
||||
@UseStandardTestCaseGroupProvider()
|
||||
public class NativeStressTestGenerated extends AbstractNativeBlackBoxTest {
|
||||
@Test
|
||||
@@ -25,9 +30,21 @@ public class NativeStressTestGenerated extends AbstractNativeBlackBoxTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/stress/testData"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("array_out_of_memory.kt")
|
||||
public void testArray_out_of_memory() {
|
||||
runTest("native/native.tests/stress/testData/array_out_of_memory.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt63423_dispose_on_main_stress.kt")
|
||||
public void testKt63423_dispose_on_main_stress() {
|
||||
runTest("native/native.tests/stress/testData/kt63423_dispose_on_main_stress.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("stress_gc_allocations.kt")
|
||||
public void testStress_gc_allocations() {
|
||||
runTest("native/native.tests/stress/testData/stress_gc_allocations.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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(ObsoleteWorkersApi::class)
|
||||
package runtime.basic.initializers6
|
||||
|
||||
import kotlin.test.*
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.concurrent.*
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
val aWorkerId = AtomicInt(0)
|
||||
val bWorkersCount = 3
|
||||
|
||||
val aWorkerUnlocker = AtomicInt(0)
|
||||
val bWorkerUnlocker = AtomicInt(0)
|
||||
|
||||
object A {
|
||||
init {
|
||||
// Must be called by aWorker only.
|
||||
assertEquals(aWorkerId.value, Worker.current.id)
|
||||
// Only allow b workers to run, when a worker has started initialization.
|
||||
bWorkerUnlocker.incrementAndGet()
|
||||
// Only proceed with initialization, when all b workers have started executing.
|
||||
while (aWorkerUnlocker.value < bWorkersCount) {}
|
||||
// And now wait a bit, to increase probability of races.
|
||||
Worker.current.park(100 * 1000L)
|
||||
}
|
||||
val a = produceA()
|
||||
val b = produceB()
|
||||
}
|
||||
|
||||
fun produceA(): String {
|
||||
// Must've been called by aWorker only.
|
||||
assertEquals(aWorkerId.value, Worker.current.id)
|
||||
return "A"
|
||||
}
|
||||
|
||||
fun produceB(): String {
|
||||
// Must've been called by aWorker only.
|
||||
assertEquals(aWorkerId.value, Worker.current.id)
|
||||
// Also check that it's ok to get A.a while initializing A.b.
|
||||
return "B+${A.a}"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val aWorker = Worker.start()
|
||||
aWorkerId.value = aWorker.id
|
||||
val bWorkers = Array(bWorkersCount, { _ -> Worker.start() })
|
||||
|
||||
val aFuture = aWorker.execute(TransferMode.SAFE, {}, {
|
||||
A.b
|
||||
})
|
||||
val bFutures = Array(bWorkers.size, {
|
||||
bWorkers[it].execute(TransferMode.SAFE, {}, {
|
||||
// Wait until A has started to initialize.
|
||||
while (bWorkerUnlocker.value < 1) {}
|
||||
// Now allow A initialization to continue.
|
||||
aWorkerUnlocker.incrementAndGet()
|
||||
// And this should not've tried to init A itself.
|
||||
A.a + A.b
|
||||
})
|
||||
})
|
||||
|
||||
for (future in bFutures) {
|
||||
assertEquals("AB+A", future.result)
|
||||
}
|
||||
assertEquals("B+A", aFuture.result)
|
||||
|
||||
for (worker in bWorkers) {
|
||||
worker.requestTermination().result
|
||||
}
|
||||
aWorker.requestTermination().result
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import kotlin.test.*
|
||||
|
||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||
@kotlin.native.internal.CanBePrecreated
|
||||
object CompileTime {
|
||||
|
||||
const val int = Int.MIN_VALUE
|
||||
const val byte = Byte.MIN_VALUE
|
||||
const val short = Short.MIN_VALUE
|
||||
const val long = Long.MIN_VALUE
|
||||
const val boolean = true
|
||||
const val float = 1.0f
|
||||
const val double = 1.0
|
||||
const val char = Char.MIN_VALUE
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(Int.MIN_VALUE, CompileTime.int)
|
||||
assertEquals(Byte.MIN_VALUE, CompileTime.byte)
|
||||
assertEquals(Short.MIN_VALUE, CompileTime.short)
|
||||
assertEquals(Long.MIN_VALUE, CompileTime.long)
|
||||
assertEquals(true, CompileTime.boolean)
|
||||
assertEquals(1.0f, CompileTime.float)
|
||||
assertEquals(1.0, CompileTime.double)
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import kotlin.test.*
|
||||
|
||||
fun box(): String {
|
||||
var x = Any()
|
||||
|
||||
for (i in 0..1) {
|
||||
val c = Any()
|
||||
if (i == 0) x = c
|
||||
}
|
||||
|
||||
// x refcount is 1.
|
||||
|
||||
val y = try {
|
||||
x
|
||||
} finally {
|
||||
x = Any()
|
||||
}
|
||||
|
||||
y.use()
|
||||
return "OK"
|
||||
}
|
||||
|
||||
private fun Any?.use() {
|
||||
var x = this
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import kotlin.test.*
|
||||
|
||||
fun box(): String {
|
||||
foo().use()
|
||||
return "OK"
|
||||
}
|
||||
|
||||
private fun foo(): Any {
|
||||
var x = Any()
|
||||
|
||||
for (i in 0..1) {
|
||||
val c = Any()
|
||||
if (i == 0) x = c
|
||||
}
|
||||
|
||||
// x refcount is 1.
|
||||
|
||||
try {
|
||||
return x
|
||||
} finally {
|
||||
x = Any()
|
||||
}
|
||||
}
|
||||
|
||||
private fun Any?.use() {
|
||||
var x = this
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import kotlin.test.*
|
||||
|
||||
fun box(): String {
|
||||
var x = Error()
|
||||
|
||||
for (i in 0..1) {
|
||||
val c = Error()
|
||||
if (i == 0) x = c
|
||||
}
|
||||
|
||||
// x refcount is 1.
|
||||
|
||||
try {
|
||||
try {
|
||||
throw x
|
||||
} finally {
|
||||
x = Error()
|
||||
}
|
||||
} catch (e: Error) {
|
||||
e.use()
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
|
||||
private fun Any?.use() {
|
||||
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)
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative,kotlin.native.runtime.NativeRuntimeApi,kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.internal.*
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.concurrent.AtomicNativePtr
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.WeakReference
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.runtime.GC
|
||||
|
||||
class AtomicBoolean(initialValue: Boolean) {
|
||||
private val impl = AtomicInt(if (initialValue) 1 else 0)
|
||||
|
||||
public var value: Boolean
|
||||
get() = impl.value != 0
|
||||
set(new) { impl.value = if (new) 1 else 0 }
|
||||
}
|
||||
|
||||
class FunBox(private val impl: () -> Unit) {
|
||||
fun call() {
|
||||
impl()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerLambda() {
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }
|
||||
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 testCleanerAnonymousFunction() {
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }
|
||||
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 testCleanerFunctionReference() {
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }
|
||||
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 testCleanerCleansWithoutGC() {
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = {
|
||||
val funBox = FunBox { called.value = true }
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
createCleaner(funBox) { it.call() }
|
||||
}()
|
||||
GC.collect() // Make sure local funBox reference is gone
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertFalse(called.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
|
||||
waitCleanerWorker()
|
||||
|
||||
assertTrue(called.value)
|
||||
}
|
||||
|
||||
val globalInt = AtomicInt(0)
|
||||
|
||||
@Test
|
||||
fun testCleanerWithInt() {
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = createCleaner(42) {
|
||||
globalInt.value = it
|
||||
}
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertEquals(0, globalInt.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertEquals(42, globalInt.value)
|
||||
}
|
||||
|
||||
val globalPtr = AtomicNativePtr(NativePtr.NULL)
|
||||
|
||||
@Test
|
||||
fun testCleanerWithNativePtr() {
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val cleaner = createCleaner(NativePtr.NULL + 42L) {
|
||||
globalPtr.value = it
|
||||
}
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
assertEquals(NativePtr.NULL, globalPtr.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertEquals(NativePtr.NULL + 42L, globalPtr.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerWithException() {
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val funBox = FunBox { called.value = true }
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
val cleaner = createCleaner(funBox) {
|
||||
it.call()
|
||||
error("Cleaner block failed")
|
||||
}
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
// Cleaners block started executing.
|
||||
assertTrue(called.value)
|
||||
// Even though the block failed, the captured funBox is freed.
|
||||
assertNull(funBoxWeak!!.value)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative,kotlin.native.runtime.NativeRuntimeApi,kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.internal.*
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.runtime.GC
|
||||
|
||||
@ThreadLocal
|
||||
var tlsCleaner: Cleaner? = null
|
||||
|
||||
val value = AtomicInt(0)
|
||||
|
||||
@Test
|
||||
fun test() {
|
||||
val worker = Worker.start()
|
||||
|
||||
worker.execute(TransferMode.SAFE, {}) {
|
||||
tlsCleaner = createCleaner(42) {
|
||||
value.value = it
|
||||
}
|
||||
}
|
||||
|
||||
worker.requestTermination().result
|
||||
waitWorkerTermination(worker)
|
||||
GC.collect()
|
||||
waitCleanerWorker()
|
||||
|
||||
assertEquals(42, value.value)
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
// FREE_COMPILER_ARGS: -opt-in=kotlin.native.internal.InternalForKotlinNative,kotlin.native.runtime.NativeRuntimeApi,kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.internal.*
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.concurrent.AtomicReference
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.WeakReference
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.runtime.GC
|
||||
|
||||
class AtomicBoolean(initialValue: Boolean) {
|
||||
private val impl = AtomicInt(if (initialValue) 1 else 0)
|
||||
|
||||
public var value: Boolean
|
||||
get() = impl.value != 0
|
||||
set(new) { impl.value = if (new) 1 else 0 }
|
||||
}
|
||||
|
||||
class FunBox(private val impl: () -> Unit) {
|
||||
fun call() {
|
||||
impl()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerDestroyInChild() {
|
||||
val worker = Worker.start()
|
||||
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
worker.execute(TransferMode.SAFE, {
|
||||
val funBox = FunBox { called.value = true }
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
val cleaner = createCleaner(funBox) { it.call() }
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
Pair(called, cleaner)
|
||||
}) { (called, cleaner) ->
|
||||
assertFalse(called.value)
|
||||
}.result
|
||||
|
||||
GC.collect()
|
||||
worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerDestroyWithChild() {
|
||||
val worker = Worker.start()
|
||||
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
worker.execute(TransferMode.SAFE, {
|
||||
val funBox = FunBox { called.value = true }
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
val cleaner = createCleaner(funBox) { it.call() }
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
Pair(called, cleaner)
|
||||
}) { (called, cleaner) ->
|
||||
assertFalse(called.value)
|
||||
}.result
|
||||
|
||||
GC.collect()
|
||||
worker.requestTermination().result
|
||||
waitWorkerTermination(worker)
|
||||
|
||||
performGCOnCleanerWorker() // Collect cleaners stack
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerDestroyInMain() {
|
||||
val worker = Worker.start()
|
||||
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
{
|
||||
val result = worker.execute(TransferMode.SAFE, { called }) { called ->
|
||||
val funBox = FunBox { called.value = true }
|
||||
val cleaner = createCleaner(funBox) { it.call() }
|
||||
Triple(cleaner, WeakReference(funBox), WeakReference(cleaner))
|
||||
}.result
|
||||
val cleaner = result.first
|
||||
funBoxWeak = result.second
|
||||
cleanerWeak = result.third
|
||||
assertFalse(called.value)
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCleanerDestroyShared() {
|
||||
val worker = Worker.start()
|
||||
|
||||
val called = AtomicBoolean(false);
|
||||
var funBoxWeak: WeakReference<FunBox>? = null
|
||||
var cleanerWeak: WeakReference<Cleaner>? = null
|
||||
val cleanerHolder: AtomicReference<Cleaner?> = AtomicReference(null);
|
||||
{
|
||||
val funBox = FunBox { called.value = true }
|
||||
funBoxWeak = WeakReference(funBox)
|
||||
val cleaner = createCleaner(funBox) { it.call() }
|
||||
cleanerWeak = WeakReference(cleaner)
|
||||
cleanerHolder.value = cleaner
|
||||
worker.execute(TransferMode.SAFE, { Pair(called, cleanerHolder) }) { (called, cleanerHolder) ->
|
||||
cleanerHolder.value = null
|
||||
assertFalse(called.value)
|
||||
}.result
|
||||
}()
|
||||
|
||||
GC.collect()
|
||||
worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertNull(cleanerWeak!!.value)
|
||||
assertTrue(called.value)
|
||||
assertNull(funBoxWeak!!.value)
|
||||
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@ThreadLocal
|
||||
var tlsValue = 11
|
||||
|
||||
@Test
|
||||
fun testCleanerWithTLS() {
|
||||
val worker = Worker.start()
|
||||
|
||||
tlsValue = 12
|
||||
|
||||
val value = AtomicInt(0)
|
||||
worker.execute(TransferMode.SAFE, {value}) {
|
||||
tlsValue = 13
|
||||
createCleaner(it) {
|
||||
it.value = tlsValue
|
||||
}
|
||||
Unit
|
||||
}.result
|
||||
|
||||
worker.execute(TransferMode.SAFE, {}) { GC.collect() }.result
|
||||
performGCOnCleanerWorker()
|
||||
|
||||
assertEquals(11, value.value)
|
||||
|
||||
worker.requestTermination().result
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import kotlin.native.runtime.GC
|
||||
import kotlin.test.*
|
||||
|
||||
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
|
||||
@Test
|
||||
fun test() {
|
||||
GC.collect()
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
import kotlin.test.*
|
||||
|
||||
data class Node(val data: Int, var next: Node?, var prev: Node?, val outer: Node?)
|
||||
|
||||
fun makeCycle(len: Int, outer: Node?): Node {
|
||||
val start = Node(0, null, null, outer)
|
||||
var prev = start
|
||||
for (i in 1 .. len - 1) {
|
||||
prev = Node(i, prev, null, outer)
|
||||
}
|
||||
start.next = prev
|
||||
return start
|
||||
}
|
||||
|
||||
fun makeDoubleCycle(len: Int): Node {
|
||||
val start = makeCycle(len, null)
|
||||
var prev = start
|
||||
var cur = prev.next
|
||||
while (cur != start) {
|
||||
cur!!.prev = prev
|
||||
prev = cur
|
||||
cur = cur.next
|
||||
}
|
||||
start.prev = prev
|
||||
return start
|
||||
}
|
||||
|
||||
fun createCycles(junk: Node) {
|
||||
val cycle1 = makeCycle(1, junk)
|
||||
val cycle2 = makeCycle(2, junk)
|
||||
val cycle10 = makeCycle(10, junk)
|
||||
val cycle100 = makeCycle(100, junk)
|
||||
val dcycle1 = makeDoubleCycle(1)
|
||||
val dcycle2 = makeDoubleCycle(2)
|
||||
val dcycle10 = makeDoubleCycle(10)
|
||||
val dcycle100 = makeDoubleCycle(100)
|
||||
|
||||
}
|
||||
|
||||
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
|
||||
@Test fun runTest() {
|
||||
// Create outer link from cyclic garbage.
|
||||
val outer = Node(42, null, null, null)
|
||||
createCycles(outer)
|
||||
kotlin.native.runtime.GC.collect()
|
||||
// Ensure outer is not collected.
|
||||
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)
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
import kotlin.test.*
|
||||
|
||||
//fun foo1(arg: String) : String = foo0(arg)
|
||||
fun foo1(arg: Any) : Any = foo0(arg)
|
||||
|
||||
fun foo0(arg: Any) : Any = Any()
|
||||
|
||||
var global : Any = Any()
|
||||
|
||||
fun foo0_escape(arg: Any) : Any{
|
||||
global = arg
|
||||
return Any()
|
||||
}
|
||||
|
||||
class Node(var previous: Node?)
|
||||
|
||||
fun zoo3() : Node {
|
||||
var current = Node(null)
|
||||
for (i in 1 .. 5) {
|
||||
current = Node(current)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
fun zoo4(arg: Int) : Any {
|
||||
var a = Any()
|
||||
var b = Any()
|
||||
var c = Any()
|
||||
a = b
|
||||
val x = 3
|
||||
a = when {
|
||||
x < arg -> b
|
||||
else -> c
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
fun zoo5(arg: Any) : Any{
|
||||
foo1(arg)
|
||||
return arg
|
||||
}
|
||||
|
||||
fun zoo6(arg: Any) : Any {
|
||||
return zoo7(arg, "foo", 11)
|
||||
}
|
||||
|
||||
fun zoo7(arg1: Any, arg2: Any, selector: Int) : Any {
|
||||
return if (selector < 2) arg1 else arg2;
|
||||
}
|
||||
|
||||
@Test fun runTest() {
|
||||
//val z = zoo7(Any(), Any(), 1)
|
||||
val x = zoo5(Any())
|
||||
//println(bar(foo1(foo2("")), foo2(foo1(""))))
|
||||
}
|
||||
+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)
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import kotlin.test.*
|
||||
|
||||
class A(val s: String)
|
||||
|
||||
class B {
|
||||
var a: A? = null
|
||||
}
|
||||
|
||||
class C(val b: B)
|
||||
|
||||
fun foo(c: C) {
|
||||
c.b.a = A("zzz")
|
||||
}
|
||||
|
||||
fun bar(b: B) {
|
||||
val c = C(b)
|
||||
foo(c)
|
||||
}
|
||||
|
||||
@ThreadLocal
|
||||
val global = B()
|
||||
|
||||
@Test fun runTest() {
|
||||
bar(global)
|
||||
assertEquals("zzz", global.a!!.s)
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
// FREE_COMPILER_ARGS: -Xbinary=gcSchedulerType=manual -opt-in=kotlin.native.runtime.NativeRuntimeApi,kotlin.ExperimentalStdlibApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||
import kotlin.native.runtime.GC
|
||||
import kotlin.test.*
|
||||
|
||||
@Test
|
||||
fun `nothing new collected`() {
|
||||
GC.collect()
|
||||
GC.collect()
|
||||
val stat = GC.lastGCInfo
|
||||
assertNotNull(stat)
|
||||
for (key in stat.sweepStatistics.keys) {
|
||||
assertEquals(stat.sweepStatistics[key]!!.sweptCount, 0L)
|
||||
}
|
||||
}
|
||||
|
||||
object Global {
|
||||
val x = listOf(1, 2, 3)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `stable refs in root set`() {
|
||||
GC.collect()
|
||||
val stat0 = GC.lastGCInfo
|
||||
assertNotNull(stat0)
|
||||
val rootSet0 = stat0.rootSet
|
||||
assertNotNull(rootSet0)
|
||||
val x = listOf(1, 2, 3)
|
||||
val stable = kotlinx.cinterop.StableRef.create(x)
|
||||
GC.collect();
|
||||
val stat1 = GC.lastGCInfo
|
||||
assertNotNull(stat1)
|
||||
val rootSet1 = stat1.rootSet
|
||||
assertNotNull(rootSet1)
|
||||
assertEquals(rootSet0.stableReferences + 1, rootSet1.stableReferences)
|
||||
stable.dispose()
|
||||
Global.x // to initialize and register global object
|
||||
GC.collect();
|
||||
val stat2 = GC.lastGCInfo
|
||||
assertNotNull(stat2)
|
||||
val rootSet2 = stat2.rootSet
|
||||
assertNotNull(rootSet2)
|
||||
assertEquals(rootSet0.stableReferences, rootSet2.stableReferences)
|
||||
assertEquals(rootSet1.globalReferences + 1, rootSet2.globalReferences)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `check everything is filled at the end`() {
|
||||
GC.collect()
|
||||
val stat = GC.lastGCInfo
|
||||
assertNotNull(stat)
|
||||
// GC.collect is waiting for finalizers, so it should bet not null
|
||||
assertNotNull(stat.postGcCleanupTimeNs)
|
||||
}
|
||||
|
||||
+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
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
import kotlin.test.*
|
||||
import kotlin.native.ref.*
|
||||
|
||||
data class Data(val s: String)
|
||||
|
||||
@OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
fun localWeak(): WeakReference<Data> {
|
||||
val x = Data("Hello")
|
||||
val weak = WeakReference(x)
|
||||
assertSame(x, weak.get())
|
||||
return weak
|
||||
}
|
||||
|
||||
@OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
fun multiWeak(): Array<WeakReference<Data>> {
|
||||
val x = Data("Hello")
|
||||
val weaks = Array(100, { WeakReference(x) } )
|
||||
weaks.forEach {
|
||||
it -> if (it.get()?.s != "Hello") throw Error("bad reference")
|
||||
}
|
||||
return weaks
|
||||
}
|
||||
|
||||
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class, kotlin.experimental.ExperimentalNativeApi::class)
|
||||
@Test fun runTest() {
|
||||
val weak = localWeak()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
assertNull(weak.get())
|
||||
|
||||
val weaks = multiWeak()
|
||||
|
||||
kotlin.native.runtime.GC.collect()
|
||||
|
||||
weaks.forEach {
|
||||
it -> if (it.get()?.s != null) throw Error("not null")
|
||||
}
|
||||
}
|
||||
+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)
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
// OUTPUT_DATA_FILE: worker10.out
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
// FREE_COMPILER_ARGS: -opt-in=kotlin.experimental.ExperimentalNativeApi,kotlin.native.runtime.NativeRuntimeApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||
|
||||
import kotlin.test.*
|
||||
import kotlin.concurrent.AtomicReference
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.concurrent.*
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.WeakReference
|
||||
import kotlinx.cinterop.StableRef
|
||||
|
||||
class Data(val x: Int)
|
||||
|
||||
val topInt = 1
|
||||
val topString = "string"
|
||||
var topStringVar = "string"
|
||||
val topSharedStringWithGetter: String
|
||||
get() = "top"
|
||||
val topData = Data(42)
|
||||
val topSharedData = Data(43)
|
||||
|
||||
@Test fun runTest1() {
|
||||
val worker = Worker.start()
|
||||
|
||||
assertEquals(1, topInt)
|
||||
assertEquals("string", topString)
|
||||
assertEquals(42, topData.x)
|
||||
assertEquals(43, topSharedData.x)
|
||||
assertEquals("top", topSharedStringWithGetter)
|
||||
|
||||
worker.execute(TransferMode.SAFE, { -> }, {
|
||||
it -> topInt == 1
|
||||
}).consume {
|
||||
result -> assertEquals(true, result)
|
||||
}
|
||||
|
||||
worker.execute(TransferMode.SAFE, { -> }, {
|
||||
it -> topString == "string"
|
||||
}).consume {
|
||||
result -> assertEquals(true, result)
|
||||
}
|
||||
|
||||
worker.execute(TransferMode.SAFE, { -> }, {
|
||||
it -> topStringVar == "string"
|
||||
}).consume {
|
||||
result -> assertTrue(result)
|
||||
}
|
||||
|
||||
worker.execute(TransferMode.SAFE, { -> }, {
|
||||
it -> topSharedStringWithGetter == "top"
|
||||
}).consume {
|
||||
result -> assertTrue(result)
|
||||
}
|
||||
|
||||
worker.execute(TransferMode.SAFE, { -> }, {
|
||||
it -> topData.x == 42
|
||||
}).consume {
|
||||
result -> assertTrue(result)
|
||||
}
|
||||
|
||||
worker.execute(TransferMode.SAFE, { -> }, {
|
||||
it -> try {
|
||||
topSharedData.x == 43
|
||||
} catch (e: Throwable) {
|
||||
false
|
||||
}
|
||||
}).consume {
|
||||
result -> assertTrue(result)
|
||||
}
|
||||
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
|
||||
val atomicRef = AtomicReference<Any?>(Any())
|
||||
val stableRef = StableRef.create(Any())
|
||||
val semaphore = AtomicInt(0)
|
||||
|
||||
@Test fun runTest2() {
|
||||
semaphore.value = 0
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { null }) {
|
||||
val value = atomicRef.value
|
||||
semaphore.incrementAndGet()
|
||||
while (semaphore.value != 2) {}
|
||||
println(value.toString() != "")
|
||||
}
|
||||
while (semaphore.value != 1) {}
|
||||
atomicRef.value = null
|
||||
kotlin.native.runtime.GC.collect()
|
||||
semaphore.incrementAndGet()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@Test fun runTest3() {
|
||||
semaphore.value = 0
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { null }) {
|
||||
val value = stableRef.get()
|
||||
semaphore.incrementAndGet()
|
||||
while (semaphore.value != 2) {}
|
||||
println(value.toString() != "")
|
||||
}
|
||||
while (semaphore.value != 1) {}
|
||||
stableRef.dispose()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
semaphore.incrementAndGet()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
fun <T: Any> ensureWeakIs(weak: WeakReference<T>, expected: T?) {
|
||||
assertEquals(expected, weak.get())
|
||||
}
|
||||
|
||||
val stableHolder1 = StableRef.create(("hello" to "world"))
|
||||
|
||||
@Test fun runTest4() {
|
||||
val worker = Worker.start()
|
||||
semaphore.value = 0
|
||||
val future = worker.execute(TransferMode.SAFE, { WeakReference(stableHolder1.get()) }) {
|
||||
ensureWeakIs(it, "hello" to "world")
|
||||
semaphore.incrementAndGet()
|
||||
while (semaphore.value != 2) {}
|
||||
kotlin.native.runtime.GC.collect()
|
||||
ensureWeakIs(it, null)
|
||||
}
|
||||
while (semaphore.value != 1) {}
|
||||
stableHolder1.dispose()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
semaphore.incrementAndGet()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
val stableHolder2 = StableRef.create(("hello" to "world"))
|
||||
|
||||
@Test fun runTest5() {
|
||||
val worker = Worker.start()
|
||||
semaphore.value = 0
|
||||
val future = worker.execute(TransferMode.SAFE, { WeakReference(stableHolder2.get()) }) {
|
||||
val value = it.get()
|
||||
semaphore.incrementAndGet()
|
||||
while (semaphore.value != 2) {}
|
||||
kotlin.native.runtime.GC.collect()
|
||||
assertEquals("hello" to "world", value)
|
||||
}
|
||||
while (semaphore.value != 1) {}
|
||||
stableHolder2.dispose()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
semaphore.incrementAndGet()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
val atomicRef2 = AtomicReference<Any?>(Any())
|
||||
@Test fun runTest6() {
|
||||
semaphore.value = 0
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { null }) {
|
||||
val value = atomicRef2.compareAndExchange(null, null)
|
||||
semaphore.incrementAndGet()
|
||||
while (semaphore.value != 2) {}
|
||||
assertEquals(true, value.toString() != "")
|
||||
}
|
||||
while (semaphore.value != 1) {}
|
||||
atomicRef2.value = null
|
||||
kotlin.native.runtime.GC.collect()
|
||||
semaphore.incrementAndGet()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
OK
|
||||
true
|
||||
true
|
||||
@@ -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
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// OUTPUT_DATA_FILE: cleaner_in_main_with_checker.out
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.Platform
|
||||
|
||||
fun main() {
|
||||
// Cleaner holds onto a finalization lambda. If it doesn't get executed,
|
||||
// the memory will leak. Suppress memory leak checker to check for cleaners
|
||||
// leak only.
|
||||
Platform.isMemoryLeakCheckerActive = false
|
||||
Platform.isCleanersLeakCheckerActive = true
|
||||
// This cleaner will run, because with the checker active this cleaner
|
||||
// will get collected, block scheduled and executed before cleaners are disabled.
|
||||
createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
42
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// OUTPUT_DATA_FILE: cleaner_in_main_without_checker.out
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.Platform
|
||||
|
||||
fun main() {
|
||||
// Cleaner holds onto a finalization lambda. If it doesn't get executed,
|
||||
// the memory will leak. Suppress memory leak checker to check for cleaners
|
||||
// leak only.
|
||||
Platform.isMemoryLeakCheckerActive = false
|
||||
Platform.isCleanersLeakCheckerActive = false
|
||||
// This cleaner will not run, because with the checker inactive this cleaner
|
||||
// will not get collected before cleaners are disabled.
|
||||
createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
// EXIT_CODE: !0
|
||||
// OUTPUT_REGEX: Cleaner (0x)?[0-9a-fA-F]+ was disposed during program exit.*
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.Platform
|
||||
|
||||
@ThreadLocal
|
||||
var tlsCleaner: Cleaner? = null
|
||||
|
||||
fun main() {
|
||||
// Cleaner holds onto a finalization lambda. If it doesn't get executed,
|
||||
// the memory will leak. Suppress memory leak checker to check for cleaners
|
||||
// leak only.
|
||||
Platform.isMemoryLeakCheckerActive = false
|
||||
Platform.isCleanersLeakCheckerActive = true
|
||||
// This cleaner won't be run
|
||||
tlsCleaner = createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.Platform
|
||||
|
||||
@ThreadLocal
|
||||
var tlsCleaner: Cleaner? = null
|
||||
|
||||
fun main() {
|
||||
// Cleaner holds onto a finalization lambda. If it doesn't get executed,
|
||||
// the memory will leak. Suppress memory leak checker to check for cleaners
|
||||
// leak only.
|
||||
Platform.isMemoryLeakCheckerActive = false
|
||||
Platform.isCleanersLeakCheckerActive = false
|
||||
// This cleaner won't be run
|
||||
tlsCleaner = createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// DISABLE_NATIVE: gcType=NOOP
|
||||
// EXIT_CODE: !0
|
||||
// OUTPUT_REGEX: Cleaner (0x)?[0-9a-fA-F]+ was disposed during program exit.*
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
import kotlin.native.Platform
|
||||
|
||||
// This cleaner won't be run, because it's deinitialized with globals after
|
||||
// cleaners are disabled.
|
||||
val globalCleaner = createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
|
||||
fun main() {
|
||||
Platform.isCleanersLeakCheckerActive = true
|
||||
// Make sure cleaner is initialized.
|
||||
assertNotNull(globalCleaner)
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// OUTPUT_DATA_FILE: cleaner_leak_without_checker.out
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.ref.Cleaner
|
||||
import kotlin.native.ref.createCleaner
|
||||
|
||||
// This cleaner won't be run, because it's deinitialized with globals after
|
||||
// cleaners are disabled.
|
||||
val globalCleaner = createCleaner(42) {
|
||||
println(it)
|
||||
}
|
||||
|
||||
fun main() {
|
||||
// Make sure cleaner is initialized.
|
||||
assertNotNull(globalCleaner)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ExperimentalForeignApi::class)
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import kotlin.native.Platform
|
||||
|
||||
fun main() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
StableRef.create(Any())
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// KIND: REGULAR
|
||||
// FREE_COMPILER_ARGS: -opt-in=kotlin.experimental.ExperimentalNativeApi,kotlinx.cinterop.ExperimentalForeignApi
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import kotlin.native.Platform
|
||||
|
||||
@BeforeTest
|
||||
fun enableMemoryChecker() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test() {
|
||||
StableRef.create(Any())
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ObsoleteWorkersApi::class, ExperimentalForeignApi::class)
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.Platform
|
||||
import kotlinx.cinterop.*
|
||||
|
||||
fun main() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
val worker = Worker.start()
|
||||
// Make sure worker is initialized.
|
||||
worker.execute(TransferMode.SAFE, {}, {}).result;
|
||||
StableRef.create(Any())
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// EXIT_CODE: !0
|
||||
// OUTPUT_REGEX: Unfinished workers detected, 1 workers leaked!.*
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ExperimentalForeignApi::class)
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.Platform
|
||||
import kotlinx.cinterop.*
|
||||
|
||||
fun main() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
val worker = Worker.start()
|
||||
// Make sure worker is initialized.
|
||||
worker.execute(TransferMode.SAFE, {}, {}).result;
|
||||
StableRef.create(Any())
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class, ObsoleteWorkersApi::class)
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.Platform
|
||||
|
||||
@ThreadLocal
|
||||
var x = Any()
|
||||
|
||||
fun main() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
val worker = Worker.start()
|
||||
|
||||
worker.execute(TransferMode.SAFE, {}) {
|
||||
println(x) // Make sure x is initialized
|
||||
}.result
|
||||
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
val x = initRuntimeIfNeeded()
|
||||
|
||||
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() {}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// OUTPUT_REGEX: ^$
|
||||
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
// Ensure that termination of current worker on main thread doesn't lead to problems.
|
||||
fun main() {
|
||||
val worker = Worker.current
|
||||
val future = worker.requestTermination(false)
|
||||
worker.processQueue()
|
||||
assertEquals(future.state, FutureState.COMPUTED)
|
||||
future.consume {}
|
||||
// After termination request this worker is no longer addressable.
|
||||
assertFailsWith<IllegalStateException> { worker.executeAfter(0, {
|
||||
println("BUG!")
|
||||
})}
|
||||
}
|
||||
native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfter.kt
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
// EXIT_CODE: !0
|
||||
// OUTPUT_REGEX: .*an error.*
|
||||
// OUTPUT_REGEX: (?!.*Will not happen.*).*
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun main() {
|
||||
Worker.current.executeAfter(0L, {
|
||||
throw Error("an error")
|
||||
})
|
||||
Worker.current.processQueue()
|
||||
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
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
// EXIT_CODE: !0
|
||||
// OUTPUT_REGEX: .*an error.*
|
||||
// OUTPUT_REGEX: (?!.*Will not happen.*).*
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun main() {
|
||||
val worker = Worker.start()
|
||||
worker.executeAfter(0L, {
|
||||
throw Error("an error")
|
||||
})
|
||||
worker.requestTermination().result
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("identity.kt")
|
||||
public void testIdentity() {
|
||||
runTest("native/native.tests/testData/codegen/enum/identity.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("isFrozen.kt")
|
||||
public void testIsFrozen() {
|
||||
@@ -697,6 +703,25 @@ public class FirNativeCodegenLocalTestGenerated extends AbstractNativeCodegenBox
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/codegen/exceptions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@Tag("frontend-fir")
|
||||
@FirPipeline()
|
||||
@UseExtTestCaseGroupProvider()
|
||||
public class Exceptions {
|
||||
@Test
|
||||
public void testAllFilesPresentInExceptions() {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/exceptions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("throw_cleanup.kt")
|
||||
public void testThrow_cleanup() {
|
||||
runTest("native/native.tests/testData/codegen/exceptions/throw_cleanup.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/codegen/fileCheck")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@@ -1074,6 +1099,12 @@ public class FirNativeCodegenLocalTestGenerated extends AbstractNativeCodegenBox
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/initializers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("initializers6.kt")
|
||||
public void testInitializers6() {
|
||||
runTest("native/native.tests/testData/codegen/initializers/initializers6.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multipleModules2.kt")
|
||||
public void testMultipleModules2() {
|
||||
@@ -1551,6 +1582,12 @@ public class FirNativeCodegenLocalTestGenerated extends AbstractNativeCodegenBox
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/objectDeclaration"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compileTime.kt")
|
||||
public void testCompileTime() {
|
||||
runTest("native/native.tests/testData/codegen/objectDeclaration/compileTime.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("globalConstants_checkComputedField.kt")
|
||||
public void testGlobalConstants_checkComputedField() {
|
||||
@@ -1656,6 +1693,43 @@ public class FirNativeCodegenLocalTestGenerated extends AbstractNativeCodegenBox
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/codegen/variables")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@Tag("frontend-fir")
|
||||
@FirPipeline()
|
||||
@UseExtTestCaseGroupProvider()
|
||||
public class Variables {
|
||||
@Test
|
||||
public void testAllFilesPresentInVariables() {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/variables"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("var1.kt")
|
||||
public void testVar1() {
|
||||
runTest("native/native.tests/testData/codegen/variables/var1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("var2.kt")
|
||||
public void testVar2() {
|
||||
runTest("native/native.tests/testData/codegen/variables/var2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("var3.kt")
|
||||
public void testVar3() {
|
||||
runTest("native/native.tests/testData/codegen/variables/var3.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("var4.kt")
|
||||
public void testVar4() {
|
||||
runTest("native/native.tests/testData/codegen/variables/var4.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/codegen/vector")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("initRuntimeInGlobal.kt")
|
||||
public void testInitRuntimeInGlobal() {
|
||||
runTest("native/native.tests/testData/standalone/initRuntimeInGlobal.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt56048.kt")
|
||||
public void testKt56048() {
|
||||
@@ -66,6 +72,42 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/checkers"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_in_main_with_checker.kt")
|
||||
public void testCleaner_in_main_with_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_in_main_with_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_in_main_without_checker.kt")
|
||||
public void testCleaner_in_main_without_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_in_main_without_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_in_tls_main_with_checker.kt")
|
||||
public void testCleaner_in_tls_main_with_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_with_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_in_tls_main_without_checker.kt")
|
||||
public void testCleaner_in_tls_main_without_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_without_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_leak_with_checker.kt")
|
||||
public void testCleaner_leak_with_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_leak_with_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_leak_without_checker.kt")
|
||||
public void testCleaner_leak_without_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_leak_without_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("leakMemoryWithRunningThreadChecked.kt")
|
||||
public void testLeakMemoryWithRunningThreadChecked() {
|
||||
@@ -77,6 +119,36 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest
|
||||
public void testLeakMemoryWithRunningThreadUnchecked() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/leakMemoryWithRunningThreadUnchecked.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("leak_memory.kt")
|
||||
public void testLeak_memory() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/leak_memory.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("leak_memory_test_runner.kt")
|
||||
public void testLeak_memory_test_runner() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/leak_memory_test_runner.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("leak_memory_with_worker_termination.kt")
|
||||
public void testLeak_memory_with_worker_termination() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/leak_memory_with_worker_termination.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("leak_worker.kt")
|
||||
public void testLeak_worker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/leak_worker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("worker_threadlocal_no_leak.kt")
|
||||
public void testWorker_threadlocal_no_leak() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/worker_threadlocal_no_leak.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -205,6 +277,33 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/standalone/runtimeLogging")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@Tag("standalone")
|
||||
@EnforcedProperty(property = ClassLevelProperty.TEST_KIND, propertyValue = "STANDALONE_NO_TR")
|
||||
@UseStandardTestCaseGroupProvider()
|
||||
@Tag("frontend-fir")
|
||||
@FirPipeline()
|
||||
public class RuntimeLogging {
|
||||
@Test
|
||||
public void testAllFilesPresentInRuntimeLogging() {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/runtimeLogging"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("logging.kt")
|
||||
public void testLogging() {
|
||||
runTest("native/native.tests/testData/standalone/runtimeLogging/logging.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("logging_override.kt")
|
||||
public void testLogging_override() {
|
||||
runTest("native/native.tests/testData/standalone/runtimeLogging/logging_override.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/standalone/termination")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@@ -249,6 +348,12 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest
|
||||
runTest("native/native.tests/testData/standalone/termination/processUnhandledException.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("terminateMainThreadWorker.kt")
|
||||
public void testTerminateMainThreadWorker() {
|
||||
runTest("native/native.tests/testData/standalone/termination/terminateMainThreadWorker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("terminateWithUnhandledException.kt")
|
||||
public void testTerminateWithUnhandledException() {
|
||||
@@ -303,10 +408,52 @@ public class FirNativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionHookWithProcess.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInCurrentWorkerExecuteAfter.kt")
|
||||
public void testUnhandledExceptionInCurrentWorkerExecuteAfter() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt")
|
||||
public void testUnhandledExceptionInCurrentWorkerExecuteAfterWithHook() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInForeignThread.kt")
|
||||
public void testUnhandledExceptionInForeignThread() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInForeignThread.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInWorkerExecute.kt")
|
||||
public void testUnhandledExceptionInWorkerExecute() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecute.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInWorkerExecuteAfter.kt")
|
||||
public void testUnhandledExceptionInWorkerExecuteAfter() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInWorkerExecuteAfterQuiet.kt")
|
||||
public void testUnhandledExceptionInWorkerExecuteAfterQuiet() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterQuiet.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInWorkerExecuteAfterWithHook.kt")
|
||||
public void testUnhandledExceptionInWorkerExecuteAfterWithHook() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterWithHook.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInWorkerExecuteQuiet.kt")
|
||||
public void testUnhandledExceptionInWorkerExecuteQuiet() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteQuiet.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+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);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("identity.kt")
|
||||
public void testIdentity() {
|
||||
runTest("native/native.tests/testData/codegen/enum/identity.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("isFrozen.kt")
|
||||
public void testIsFrozen() {
|
||||
@@ -669,6 +675,23 @@ public class NativeCodegenLocalTestGenerated extends AbstractNativeCodegenBoxTes
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/codegen/exceptions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@UseExtTestCaseGroupProvider()
|
||||
public class Exceptions {
|
||||
@Test
|
||||
public void testAllFilesPresentInExceptions() {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/exceptions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("throw_cleanup.kt")
|
||||
public void testThrow_cleanup() {
|
||||
runTest("native/native.tests/testData/codegen/exceptions/throw_cleanup.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/codegen/fileCheck")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@@ -1034,6 +1057,12 @@ public class NativeCodegenLocalTestGenerated extends AbstractNativeCodegenBoxTes
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/initializers"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("initializers6.kt")
|
||||
public void testInitializers6() {
|
||||
runTest("native/native.tests/testData/codegen/initializers/initializers6.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multipleModules2.kt")
|
||||
public void testMultipleModules2() {
|
||||
@@ -1481,6 +1510,12 @@ public class NativeCodegenLocalTestGenerated extends AbstractNativeCodegenBoxTes
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/objectDeclaration"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compileTime.kt")
|
||||
public void testCompileTime() {
|
||||
runTest("native/native.tests/testData/codegen/objectDeclaration/compileTime.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("globalConstants_checkComputedField.kt")
|
||||
public void testGlobalConstants_checkComputedField() {
|
||||
@@ -1582,6 +1617,41 @@ public class NativeCodegenLocalTestGenerated extends AbstractNativeCodegenBoxTes
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/codegen/variables")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@UseExtTestCaseGroupProvider()
|
||||
public class Variables {
|
||||
@Test
|
||||
public void testAllFilesPresentInVariables() {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/codegen/variables"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("var1.kt")
|
||||
public void testVar1() {
|
||||
runTest("native/native.tests/testData/codegen/variables/var1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("var2.kt")
|
||||
public void testVar2() {
|
||||
runTest("native/native.tests/testData/codegen/variables/var2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("var3.kt")
|
||||
public void testVar3() {
|
||||
runTest("native/native.tests/testData/codegen/variables/var3.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("var4.kt")
|
||||
public void testVar4() {
|
||||
runTest("native/native.tests/testData/codegen/variables/var4.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/codegen/vector")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("initRuntimeInGlobal.kt")
|
||||
public void testInitRuntimeInGlobal() {
|
||||
runTest("native/native.tests/testData/standalone/initRuntimeInGlobal.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt56048.kt")
|
||||
public void testKt56048() {
|
||||
@@ -61,6 +67,42 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/checkers"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_in_main_with_checker.kt")
|
||||
public void testCleaner_in_main_with_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_in_main_with_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_in_main_without_checker.kt")
|
||||
public void testCleaner_in_main_without_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_in_main_without_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_in_tls_main_with_checker.kt")
|
||||
public void testCleaner_in_tls_main_with_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_with_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_in_tls_main_without_checker.kt")
|
||||
public void testCleaner_in_tls_main_without_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_in_tls_main_without_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_leak_with_checker.kt")
|
||||
public void testCleaner_leak_with_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_leak_with_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cleaner_leak_without_checker.kt")
|
||||
public void testCleaner_leak_without_checker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/cleaner_leak_without_checker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("leakMemoryWithRunningThreadChecked.kt")
|
||||
public void testLeakMemoryWithRunningThreadChecked() {
|
||||
@@ -72,6 +114,36 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest {
|
||||
public void testLeakMemoryWithRunningThreadUnchecked() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/leakMemoryWithRunningThreadUnchecked.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("leak_memory.kt")
|
||||
public void testLeak_memory() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/leak_memory.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("leak_memory_test_runner.kt")
|
||||
public void testLeak_memory_test_runner() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/leak_memory_test_runner.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("leak_memory_with_worker_termination.kt")
|
||||
public void testLeak_memory_with_worker_termination() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/leak_memory_with_worker_termination.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("leak_worker.kt")
|
||||
public void testLeak_worker() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/leak_worker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("worker_threadlocal_no_leak.kt")
|
||||
public void testWorker_threadlocal_no_leak() {
|
||||
runTest("native/native.tests/testData/standalone/checkers/worker_threadlocal_no_leak.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -196,6 +268,31 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/standalone/runtimeLogging")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@Tag("standalone")
|
||||
@EnforcedProperty(property = ClassLevelProperty.TEST_KIND, propertyValue = "STANDALONE_NO_TR")
|
||||
@UseStandardTestCaseGroupProvider()
|
||||
public class RuntimeLogging {
|
||||
@Test
|
||||
public void testAllFilesPresentInRuntimeLogging() {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/standalone/runtimeLogging"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("logging.kt")
|
||||
public void testLogging() {
|
||||
runTest("native/native.tests/testData/standalone/runtimeLogging/logging.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("logging_override.kt")
|
||||
public void testLogging_override() {
|
||||
runTest("native/native.tests/testData/standalone/runtimeLogging/logging_override.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("native/native.tests/testData/standalone/termination")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@@ -238,6 +335,12 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest {
|
||||
runTest("native/native.tests/testData/standalone/termination/processUnhandledException.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("terminateMainThreadWorker.kt")
|
||||
public void testTerminateMainThreadWorker() {
|
||||
runTest("native/native.tests/testData/standalone/termination/terminateMainThreadWorker.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("terminateWithUnhandledException.kt")
|
||||
public void testTerminateWithUnhandledException() {
|
||||
@@ -292,10 +395,52 @@ public class NativeStandaloneTestGenerated extends AbstractNativeBlackBoxTest {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionHookWithProcess.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInCurrentWorkerExecuteAfter.kt")
|
||||
public void testUnhandledExceptionInCurrentWorkerExecuteAfter() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt")
|
||||
public void testUnhandledExceptionInCurrentWorkerExecuteAfterWithHook() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInCurrentWorkerExecuteAfterWithHook.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInForeignThread.kt")
|
||||
public void testUnhandledExceptionInForeignThread() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInForeignThread.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInWorkerExecute.kt")
|
||||
public void testUnhandledExceptionInWorkerExecute() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecute.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInWorkerExecuteAfter.kt")
|
||||
public void testUnhandledExceptionInWorkerExecuteAfter() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfter.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInWorkerExecuteAfterQuiet.kt")
|
||||
public void testUnhandledExceptionInWorkerExecuteAfterQuiet() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterQuiet.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInWorkerExecuteAfterWithHook.kt")
|
||||
public void testUnhandledExceptionInWorkerExecuteAfterWithHook() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteAfterWithHook.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unhandledExceptionInWorkerExecuteQuiet.kt")
|
||||
public void testUnhandledExceptionInWorkerExecuteQuiet() {
|
||||
runTest("native/native.tests/testData/standalone/termination/unhandledExceptionInWorkerExecuteQuiet.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
@@ -531,6 +531,7 @@ fun main() {
|
||||
testClass<AbstractNativeBlackBoxTest>(
|
||||
suiteTestClassName = "NativeStressTestGenerated",
|
||||
annotations = listOf(
|
||||
*stress(),
|
||||
provider<UseStandardTestCaseGroupProvider>(),
|
||||
)
|
||||
) {
|
||||
@@ -539,6 +540,7 @@ fun main() {
|
||||
testClass<AbstractNativeBlackBoxTest>(
|
||||
suiteTestClassName = "FirNativeStressTestGenerated",
|
||||
annotations = listOf(
|
||||
*stress(),
|
||||
provider<UseStandardTestCaseGroupProvider>(),
|
||||
*frontendFir(),
|
||||
)
|
||||
@@ -546,6 +548,28 @@ fun main() {
|
||||
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,
|
||||
"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.common.ExitCode
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.*
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.EnforcedProperty
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.LoggedData
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.TestCompilerArgs
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.*
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.LibraryCompilation
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.ObjCFrameworkCompilation
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilationArtifact
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilationResult
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.compilation.TestCompilationResult.Companion.assertSuccess
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.group.FirPipeline
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.CacheMode
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.PipelineType
|
||||
import org.jetbrains.kotlin.konan.test.blackbox.support.settings.Settings
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
@@ -162,6 +161,57 @@ abstract class CompilerOutputTestBase : AbstractNativeSimpleTest() {
|
||||
dir
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLoggingWarningWithDistCache() {
|
||||
val rootDir = File("native/native.tests/testData/compilerOutput/runtimeLogging")
|
||||
val testCase = generateTestCaseWithSingleFile(
|
||||
rootDir.resolve("main.kt"),
|
||||
freeCompilerArgs = TestCompilerArgs("-Xruntime-logs=gc=info"),
|
||||
extras = TestCase.NoTestRunnerExtras("main"),
|
||||
testKind = TestKind.STANDALONE_NO_TR,
|
||||
)
|
||||
val expectedArtifact = TestCompilationArtifact.Executable(buildDir.resolve("logging_warning_with_cache"))
|
||||
val compilation = ExecutableCompilation(
|
||||
testRunSettings,
|
||||
freeCompilerArgs = testCase.freeCompilerArgs,
|
||||
sourceModules = testCase.modules,
|
||||
extras = testCase.extras,
|
||||
dependencies = emptyList(),
|
||||
expectedArtifact = expectedArtifact,
|
||||
)
|
||||
val compilationResult = compilation.result
|
||||
val goldenData = rootDir.resolve(
|
||||
if (testRunSettings.get<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")
|
||||
|
||||
+5
-4
@@ -448,11 +448,12 @@ internal fun parseProgramArguments(registeredDirectives: RegisteredDirectives):
|
||||
internal fun parseOutputRegex(registeredDirectives: RegisteredDirectives): TestRunCheck.OutputMatcher? {
|
||||
if (OUTPUT_REGEX !in registeredDirectives)
|
||||
return null
|
||||
val regexStr = registeredDirectives.singleValue(OUTPUT_REGEX)
|
||||
val regex = regexStr.toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
val regexes = registeredDirectives[OUTPUT_REGEX].map { it.toRegex(RegexOption.DOT_MATCHES_ALL) }
|
||||
return TestRunCheck.OutputMatcher {
|
||||
assertTrue(regex.matches(it)) {
|
||||
"Regex `$regex` failed to match `$it`"
|
||||
regexes.forEach { regex ->
|
||||
assertTrue(regex.matches(it)) {
|
||||
"Regex `$regex` failed to match `$it`"
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user