[K/N] Do not compile for deprecated targets and legacy MM

^KT-56533
^KT-58853
This commit is contained in:
Alexander Shabalin
2023-05-12 16:02:48 +02:00
committed by Space Team
parent d1ce55cbd2
commit aea8bac7d2
54 changed files with 128 additions and 2191 deletions
@@ -1,61 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.test.*
import kotlin.native.concurrent.*
import kotlin.native.internal.Frozen
class NonFrozenClass
@Frozen
class FrozenClass
val globalNonFrozen = NonFrozenClass()
@SharedImmutable
val sharedImmutableNonFrozen = NonFrozenClass()
val globalFrozen = FrozenClass()
@SharedImmutable
val sharedImmutableFrozen = FrozenClass()
fun main(args: Array<String>) {
val mode = args.first()
val localNonFrozen = NonFrozenClass()
val localFrozen = FrozenClass()
when (mode) {
"full" -> {
checkFreezeCheck(localNonFrozen, false, true)
checkFreezeCheck(localFrozen, true, true)
checkFreezeCheck(globalNonFrozen, false, true)
checkFreezeCheck(sharedImmutableNonFrozen, true, true)
checkFreezeCheck(globalFrozen, true, true)
checkFreezeCheck(sharedImmutableFrozen, true, true)
}
"disabled" -> {
checkFreezeCheck(localNonFrozen, false, false)
checkFreezeCheck(localFrozen, false, false)
checkFreezeCheck(globalNonFrozen, false, false)
checkFreezeCheck(sharedImmutableNonFrozen, false, false)
checkFreezeCheck(globalFrozen, false, false)
checkFreezeCheck(sharedImmutableFrozen, false, false)
}
"explicitOnly" -> {
checkFreezeCheck(localNonFrozen, false, true)
checkFreezeCheck(localFrozen, false, true)
checkFreezeCheck(globalNonFrozen, false, true)
checkFreezeCheck(sharedImmutableNonFrozen, false, true)
checkFreezeCheck(globalFrozen, false, true)
checkFreezeCheck(sharedImmutableFrozen, false, true)
}
}
}
private fun checkFreezeCheck(arg: Any, isFrozenBefore: Boolean, isFrozenAfter: Boolean) {
assertEquals(isFrozenBefore, arg.isFrozen)
arg.freeze()
assertEquals(isFrozenAfter, arg.isFrozen)
}
@@ -1,194 +0,0 @@
@file:OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
import kotlin.native.concurrent.*
import kotlin.native.runtime.GC
import kotlin.native.Platform
import kotlin.test.*
fun test1() {
val a = AtomicReference<Any?>(null)
val b = AtomicReference<Any?>(null)
a.value = b
b.value = a
}
class Holder(var other: Any?)
fun test2() {
val array = arrayOf(AtomicReference<Any?>(null), AtomicReference<Any?>(null))
val obj1 = Holder(array).freeze()
array[0].value = obj1
}
fun test3() {
val a1 = FreezableAtomicReference<Any?>(null)
val head = Holder(null)
var current = head
repeat(30) {
val next = Holder(null)
current.other = next
current = next
}
a1.value = head
current.other = a1
current.freeze()
}
fun makeIt(): Holder {
val atomic = AtomicReference<Holder?>(null)
val holder = Holder(atomic).freeze()
atomic.value = holder
return holder
}
fun test4() {
val holder = makeIt()
// To clean rc count coming from rememberNewContainer().
kotlin.native.runtime.GC.collect()
// Request cyclic collection.
kotlin.native.runtime.GC.collectCyclic()
// Ensure we processed delayed release.
repeat(10) {
// Wait a bit and process queue.
Worker.current.park(10)
Worker.current.processQueue()
kotlin.native.runtime.GC.collect()
}
val value = @Suppress("UNCHECKED_CAST") (holder.other as? AtomicReference<Holder?>?)
assertTrue(value != null)
assertTrue(value.value == holder)
}
fun createRef(): AtomicReference<Any?> {
val atomic1 = AtomicReference<Any?>(null)
val atomic2 = AtomicReference<Any?>(null)
atomic1.value = atomic2
atomic2.value = atomic1
return atomic1
}
class Holder2(var value: AtomicReference<Any?>) {
fun switch() {
value = value.value as AtomicReference<Any?>
}
}
fun createHolder2() = Holder2(createRef())
fun test5() {
val holder = createHolder2()
kotlin.native.runtime.GC.collect()
kotlin.native.runtime.GC.collectCyclic()
Worker.current.park(100 * 1000)
holder.switch()
kotlin.native.runtime.GC.collect()
Worker.current.park(100 * 1000)
withWorker {
executeAfter(0L, {
kotlin.native.runtime.GC.collect()
}.freeze())
}
Worker.current.park(1000)
assertTrue(holder.value.value != null)
}
fun test6() {
val atomic = AtomicReference<Any?>(null)
atomic.value = Pair(atomic, Holder(atomic)).freeze()
}
fun createRoot(): AtomicReference<Any?> {
val ref1 = AtomicReference<Any?>(null)
val ref2 = AtomicReference<Any?>(null)
ref1.value = Holder(ref2).freeze()
ref2.value = Any().freeze()
return ref1
}
fun test7() {
val ref1 = createRoot()
kotlin.native.runtime.GC.collect()
kotlin.native.runtime.GC.collectCyclic()
Worker.current.park(500 * 1000L)
withWorker {
executeAfter(0L, {}.freeze())
Worker.current.park(500 * 1000L)
val node = ref1.value as Holder
val ref2 = node.other as AtomicReference<Any?>
assertTrue(ref2.value != null)
}
}
fun array(size: Int) = Array<Any?>(size, { null })
fun test8() {
val ref = AtomicReference<Any?>(null)
val obj1 = array(2)
val obj2 = array(1)
val obj3 = array(2)
obj1[0] = obj2
obj1[1] = obj3
obj2[0] = obj3
obj3[0] = obj2
obj3[1] = ref
ref.value = obj1.freeze()
}
fun createNode1(): Holder {
val ref = AtomicReference<Any?>(null)
val node2 = Holder(ref)
val node1 = Holder(node2)
ref.value = node1.freeze()
return node1
}
fun getNode2(): Holder {
val node1 = createNode1()
GC.collect()
return node1.other as Holder
}
fun test9() {
withWorker {
val node2 = getNode2()
executeAfter(10 * 1000L, { GC.collectCyclic() }.freeze())
GC.collect()
Worker.current.park(50 * 1000L)
execute(TransferMode.SAFE, {}, {}).result
val ref = node2.other as AtomicReference<Any?>
assertTrue(ref.value != null)
}
}
fun main() {
Platform.isMemoryLeakCheckerActive = true
kotlin.native.runtime.GC.cyclicCollectorEnabled = true
test1()
test2()
test3()
test4()
repeat(10) {
test5()
}
test6()
test7()
test8()
test9()
}
@@ -1,16 +0,0 @@
import kotlin.native.concurrent.*
import kotlin.test.*
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
fun main() {
kotlin.native.runtime.GC.cyclicCollectorEnabled = true
repeat(10000) {
// Create atomic cyclic garbage:
val ref = AtomicReference<Any?>(null)
ref.value = ref
}
// main thread will then run cycle collector termination, which involves running it and cleaning everything up.
// 10000 references should hit [kGcThreshold] then.
}
@@ -1,201 +0,0 @@
@file:OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
import kotlin.native.concurrent.*
import kotlin.native.runtime.GC
import kotlin.native.Platform
import kotlin.test.*
class Holder(var other: Any?)
class Holder2(var field1: Any?, var field2: Any?)
val <T> Array<T>.description: String
get() {
val result = StringBuilder()
result.append('[')
for (elem in this) {
result.append(elem.toString())
result.append(',')
}
result.append(']')
return result.toString()
}
fun assertArrayEquals(
expected: Array<Any>,
actual: Array<Any>
): Unit {
val lazyMessage: () -> String? = {
"Expected <${expected.description}>, actual <${actual.description}>."
}
asserter.assertTrue(lazyMessage, expected.size == actual.size)
for (i in expected.indices) {
asserter.assertTrue(lazyMessage, expected[i] == actual[i])
}
}
@BeforeTest
fun enableMemoryChecker() {
Platform.isMemoryLeakCheckerActive = true
}
@Test
fun noCycles() {
val atomic1 = AtomicReference<Any?>(null)
val atomic2 = AtomicReference<Any?>(null)
try {
atomic1.value = atomic2
val cycles = GC.detectCycles()!!
assertEquals(0, cycles.size)
assertNull(GC.findCycle(atomic1));
assertNull(GC.findCycle(atomic2));
} finally {
atomic1.value = null
atomic2.value = null
}
}
@Test
fun oneCycle() {
val atomic = AtomicReference<Any?>(null)
try {
atomic.value = atomic
val cycles = GC.detectCycles()!!
assertEquals(1, cycles.size)
assertArrayEquals(arrayOf(atomic, atomic), GC.findCycle(cycles[0])!!)
} finally {
atomic.value = null
}
}
@Test
fun oneCycleWithHolder() {
val atomic = AtomicReference<Any?>(null)
try {
atomic.value = Holder(atomic).freeze()
val cycles = GC.detectCycles()!!
assertEquals(1, cycles.size)
assertArrayEquals(arrayOf(atomic, atomic.value!!, atomic), GC.findCycle(cycles[0])!!)
assertArrayEquals(arrayOf(atomic.value!!, atomic, atomic.value!!), GC.findCycle(atomic.value!!)!!)
} finally {
atomic.value = null
}
}
@Test
fun oneCycleWithArray() {
val array = arrayOf(AtomicReference<Any?>(null), AtomicReference<Any?>(null))
try {
array[0].value = Holder(array).freeze()
val cycles = GC.detectCycles()!!
assertEquals(1, cycles.size)
assertArrayEquals(arrayOf(array[0], array[0].value!!, array, array[0]), GC.findCycle(cycles[0])!!)
} finally {
array[0].value = null
array[1].value = null
}
}
@Test
fun oneCycleWithLongChain() {
val atomic = AtomicReference<Any?>(null)
try {
val head = Holder(null)
var current = head
repeat(30) {
val next = Holder(null)
current.other = next
current = next
}
current.other = atomic
atomic.value = head.freeze()
val cycles = GC.detectCycles()!!
assertEquals(1, cycles.size)
val cycle = GC.findCycle(cycles[0])!!
assertEquals(33, cycle.size)
} finally {
atomic.value = null
}
}
@Test
fun twoCycles() {
val atomic1 = AtomicReference<Any?>(null)
val atomic2 = AtomicReference<Any?>(null)
try {
atomic1.value = atomic2
atomic2.value = atomic1
val cycles = GC.detectCycles()!!
assertEquals(2, cycles.size)
assertArrayEquals(arrayOf(atomic2, atomic1, atomic2), GC.findCycle(cycles[0])!!)
assertArrayEquals(arrayOf(atomic1, atomic2, atomic1), GC.findCycle(cycles[1])!!)
} finally {
atomic1.value = null
atomic2.value = null
}
}
@Test
fun twoCyclesWithHolder() {
val atomic1 = AtomicReference<Any?>(null)
val atomic2 = AtomicReference<Any?>(null)
try {
atomic1.value = atomic2
atomic2.value = Holder(atomic1).freeze()
val cycles = GC.detectCycles()!!
assertEquals(2, cycles.size)
assertArrayEquals(arrayOf(atomic2, atomic2.value!!, atomic1, atomic2), GC.findCycle(cycles[0])!!)
assertArrayEquals(arrayOf(atomic1, atomic2, atomic2.value!!, atomic1), GC.findCycle(cycles[1])!!)
} finally {
atomic1.value = null
atomic2.value = null
}
}
@Test
fun threeSeparateCycles() {
val atomic1 = AtomicReference<Any?>(null)
val atomic2 = AtomicReference<Any?>(null)
val atomic3 = AtomicReference<Any?>(null)
try {
atomic1.value = atomic1
atomic2.value = Holder2(atomic1, atomic2).freeze()
atomic3.value = Holder2(atomic3, atomic1).freeze()
val cycles = GC.detectCycles()!!
assertEquals(3, cycles.size)
assertArrayEquals(arrayOf(atomic3, atomic3.value!!, atomic3), GC.findCycle(cycles[0])!!)
assertArrayEquals(arrayOf(atomic2, atomic2.value!!, atomic2), GC.findCycle(cycles[1])!!)
assertArrayEquals(arrayOf(atomic1, atomic1), GC.findCycle(cycles[2])!!)
} finally {
atomic1.value = null
atomic2.value = null
atomic3.value = null
}
}
@Test
fun noCyclesWithFreezableAtomicReference() {
val atomic = FreezableAtomicReference<Any?>(null)
try {
atomic.value = atomic
val cycles = GC.detectCycles()!!
assertEquals(0, cycles.size)
} finally {
atomic.value = null
}
}
@Test
fun oneCycleWithFrozenFreezableAtomicReference() {
val atomic = FreezableAtomicReference<Any?>(null)
try {
atomic.value = atomic
atomic.freeze()
val cycles = GC.detectCycles()!!
assertEquals(1, cycles.size)
assertArrayEquals(arrayOf(atomic, atomic), GC.findCycle(cycles[0])!!)
} finally {
atomic.value = null
}
}
@@ -1,33 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.freeze0
import kotlin.test.*
import kotlin.native.concurrent.*
data class SharedDataMember(val double: Double)
data class SharedData(val string: String, val int: Int, val member: SharedDataMember)
@Test fun runTest() {
val worker = Worker.start()
// Create immutable shared data.
val immutable = SharedData("Hello", 10, SharedDataMember(0.1)).freeze()
println("frozen bit is ${immutable.isFrozen}")
val future = worker.execute(TransferMode.SAFE, { immutable } ) {
input ->
println("Worker: $input")
input
}
future.consume {
result -> println("Main: $result")
}
worker.requestTermination().result
println("OK")
}
@@ -1,4 +0,0 @@
frozen bit is true
Worker: SharedData(string=Hello, int=10, member=SharedDataMember(double=0.1))
Main: SharedData(string=Hello, int=10, member=SharedDataMember(double=0.1))
OK
@@ -1,47 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze1
import kotlin.test.*
import kotlin.native.concurrent.*
data class Node(var previous: Node?, var data: Int)
fun makeCycle(count: Int): Node {
val first = Node(null, 0)
var current = first
for (index in 1 .. count - 1) {
current = Node(current, index)
}
first.previous = current
return first
}
data class Node2(var leaf1: Node2?, var leaf2: Node2?)
fun makeDiamond(): Node2 {
val bottom = Node2(null, null)
val mid1prime = Node2(bottom, null)
val mid1 = Node2(mid1prime, null)
val mid2 = Node2(bottom, null)
return Node2(mid1, mid2)
}
@Test fun runTest() {
makeCycle(10).freeze()
// Must be able to freeze diamond shaped graph.
val diamond = makeDiamond().freeze()
val immutable = Node(null, 4).freeze()
try {
immutable.data = 42
} catch (e: InvalidMutabilityException) {
println("OK, cannot mutate frozen")
}
}
@@ -1 +0,0 @@
OK, cannot mutate frozen
@@ -1,91 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.freeze2
import kotlin.test.*
import kotlin.native.concurrent.*
data class Data(var int: Int)
@Test fun runTest() {
// Ensure that we can not mutate frozen objects and arrays.
val a0 = Data(2)
a0.int++
a0.freeze()
assertFailsWith<InvalidMutabilityException> {a0.int++ }
val a1 = ByteArray(2)
a1[1]++
a1.freeze()
assertFailsWith<InvalidMutabilityException> { a1[1]++ }
val a2 = ShortArray(2)
a2[1]++
a2.freeze()
assertFailsWith<InvalidMutabilityException> { a2[1]++ }
val a3 = IntArray(2)
a3[1]++
a3.freeze()
assertFailsWith<InvalidMutabilityException> { a3[1]++ }
val a4 = LongArray(2)
a4[1]++
a4.freeze()
assertFailsWith<InvalidMutabilityException> { a4[1]++ }
val a5 = BooleanArray(2)
a5[1] = true
a5.freeze()
assertFailsWith<InvalidMutabilityException> { a5[1] = false }
val a6 = CharArray(2)
a6[1] = 'a'
a6.freeze()
assertFailsWith<InvalidMutabilityException> { a6[1] = 'b' }
val a7 = FloatArray(2)
a7[1] = 1.0f
a7.freeze()
assertFailsWith<InvalidMutabilityException> { a7[1] = 2.0f }
val a8 = DoubleArray(2)
a8[1] = 1.0
a8.freeze()
assertFailsWith<InvalidMutabilityException> { a8[1] = 2.0 }
// Ensure that String and integral boxes are frozen by default, by passing local to the worker.
val worker = Worker.start()
var data: Any = "Hello" + " " + "world"
assertTrue(data.isFrozen)
worker.execute(TransferMode.SAFE, { data } ) {
input -> println("Worker 1: $input")
}.result
data = 42
assertTrue(data.isFrozen)
worker.execute(TransferMode.SAFE, { data } ) {
input -> println("Worker2: $input")
}.result
data = 239.0
assertTrue(data.isFrozen)
worker.execute(TransferMode.SAFE, { data } ) {
input -> println("Worker3: $input")
}.result
data = 'a'
assertTrue(data.isFrozen)
worker.execute(TransferMode.SAFE, { data } ) {
input -> println("Worker4: $input")
}.result
worker.requestTermination().result
println("OK")
}
@@ -1,5 +0,0 @@
Worker 1: Hello world
Worker2: 42
Worker3: 239.0
Worker4: a
OK
@@ -1,51 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.freeze3
import kotlin.test.*
import kotlin.native.concurrent.*
object AnObject {
var x = 1
}
@ThreadLocal
object Mutable {
var x = 2
}
val topLevelInline: ULong = 0xc3a5c85c97cb3127U
@Test fun runTest1() {
assertEquals(1, AnObject.x)
if (Platform.memoryModel == MemoryModel.STRICT) {
assertFailsWith<InvalidMutabilityException> {
AnObject.x++
}
assertEquals(1, AnObject.x)
} else {
AnObject.x++
assertEquals(2, AnObject.x)
}
Mutable.x++
assertEquals(3, Mutable.x)
println("OK")
}
@Test fun runTest2() {
val ok = AtomicInt(0)
withWorker() {
executeAfter(0, {
assertEquals(0xc3a5c85c97cb3127U, topLevelInline)
ok.increment()
}.freeze())
}
assertEquals(1, ok.value)
}
@@ -1 +0,0 @@
OK
@@ -1,30 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze4
import kotlin.test.*
import kotlin.native.concurrent.*
data class Data(val x: Int, val s: String, val next: Data? = null)
@Test fun runTest() {
val data1 = Data(1, "")
data1.freeze()
assertFailsWith<FreezingException> {
data1.ensureNeverFrozen()
}
val dataNF = Data(42, "42")
dataNF.ensureNeverFrozen()
val data2 = Data(2, "2", dataNF)
assertFailsWith<FreezingException> {
data2.freeze()
}
assert(!data2.isFrozen)
println("OK")
}
@@ -1 +0,0 @@
OK
@@ -1,48 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package runtime.workers.freeze5
import kotlin.test.*
object Keys {
internal val myMap: Map<String, List<String>> = mapOf(
"val1" to listOf("a1", "a2", "a3"),
"val2" to listOf("b1", "b2")
)
fun getKey(name: String): String {
for (key in myMap.keys) {
if (key == name) {
return key
}
}
return ""
}
fun getValue(name: String): String {
for (value in myMap.values) {
if (value.contains(name)) {
return name
}
}
return ""
}
fun getEntry(name: String): String {
for (entry in myMap.entries) {
if (entry.key == name) {
return entry.key
}
}
return ""
}
}
@Test fun runTest() {
assertEquals("val2", Keys.getKey("val2"))
assertEquals("a1", Keys.getValue("a1"))
assertEquals("val1", Keys.getEntry("val1"))
println("OK")
}
@@ -1 +0,0 @@
OK
@@ -1,160 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class, kotlin.native.runtime.NativeRuntimeApi::class)
package runtime.workers.freeze6
import kotlin.test.*
import kotlin.native.concurrent.*
import kotlin.native.ref.*
data class Hi(val s: String)
data class Nested(val hi: Hi)
@Test
fun ensureNeverFrozenNoFreezeChild(){
val noFreeze = Hi("qwert")
noFreeze.ensureNeverFrozen()
val nested = Nested(noFreeze)
assertFails { nested.freeze() }
println("OK")
}
@Test
fun ensureNeverFrozenFailsTarget(){
val noFreeze = Hi("qwert")
noFreeze.ensureNeverFrozen()
assertFalse(noFreeze.isFrozen)
assertFails { noFreeze.freeze() }
assertFalse(noFreeze.isFrozen)
println("OK")
}
fun createRef1(): FreezableAtomicReference<Any?> {
val ref = FreezableAtomicReference<Any?>(null)
ref.value = ref
ref.freeze()
ref.value = null
return ref
}
var global = 0
@Test
fun ensureFreezableHandlesCycles1() {
val ref = createRef1()
kotlin.native.runtime.GC.collect()
val obj: Any = ref
global = obj.hashCode()
}
class Node(var ref: Any?)
/**
* ref1 -> Node <- ref3
* | /\
* V |
* ref2 ---
*/
fun createRef2(): Pair<FreezableAtomicReference<Node?>, Any> {
val ref1 = FreezableAtomicReference<Node?>(null)
val node = Node(null)
val ref3 = FreezableAtomicReference<Any?>(node)
val ref2 = FreezableAtomicReference<Any?>(ref3)
node.ref = ref2
ref1.value = node
ref1.freeze()
ref3.value = null
assertTrue(node.isFrozen)
assertTrue(ref1.isFrozen)
assertTrue(ref2.isFrozen)
assertTrue(ref3.isFrozen)
return ref1 to ref2
}
@Test
fun ensureFreezableHandlesCycles2() {
val (ref, obj) = createRef2()
kotlin.native.runtime.GC.collect()
assertTrue(obj.toString().length > 0)
global = ref.value!!.ref!!.hashCode()
}
fun createRef3(): FreezableAtomicReference<Any?> {
val ref = FreezableAtomicReference<Any?>(null)
val node = Node(ref)
ref.value = node
ref.freeze()
assertTrue(node.isFrozen)
assertTrue(ref.isFrozen)
return ref
}
@Test
fun ensureFreezableHandlesCycles3() {
val ref = createRef3()
ref.value = null
kotlin.native.runtime.GC.collect()
val obj: Any = ref
assertTrue(obj.toString().length > 0)
global = obj.hashCode()
}
lateinit var weakRef: WeakReference<Any>
fun createRef4(): FreezableAtomicReference<Any?> {
val ref = FreezableAtomicReference<Any?>(null)
val node = Node(ref)
weakRef = WeakReference(node)
ref.value = node
ref.freeze()
assertTrue(weakRef.get() != null)
return ref
}
@Test
fun ensureWeakRefNotLeaks1() {
val ref = createRef4()
ref.value = null
// We cannot check weakRef.get() here, as value read will be stored in the stack slot,
// and thus hold weak reference from release.
kotlin.native.runtime.GC.collect()
assertTrue(weakRef.get() == null)
}
lateinit var node1: Node
lateinit var weakNode2: WeakReference<Node>
fun createRef5() {
val ref = FreezableAtomicReference<Any?>(null)
node1 = Node(ref)
val node2 = Node(node1)
weakNode2 = WeakReference(node2)
ref.value = node2
node1.freeze()
assertTrue(weakNode2.get() != null)
ref.value = null
}
@Test
fun ensureWeakRefNotLeaks2() {
createRef5()
kotlin.native.runtime.GC.collect()
assertTrue(weakNode2.get() == null)
}
@@ -1,2 +0,0 @@
OK
OK
@@ -1,152 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze_stress
import kotlin.test.*
import kotlin.native.concurrent.*
class Random(private var seed: Int) {
fun next(): Int {
seed = (1103515245 * seed + 12345) and 0x7fffffff
return seed
}
fun next(maxExclusiveValue: Int) = if (maxExclusiveValue == 0) 0 else next() % maxExclusiveValue
fun next(minInclusiveValue: Int, maxInclusiveValue: Int) =
minInclusiveValue + next(maxInclusiveValue - minInclusiveValue + 1)
}
class Node(val id: Int) {
var numberOfEdges = 0
lateinit var edge0: Node
lateinit var edge1: Node
lateinit var edge2: Node
lateinit var edge3: Node
lateinit var edge4: Node
lateinit var edge5: Node
lateinit var edge6: Node
lateinit var edge7: Node
lateinit var edge8: Node
lateinit var edge9: Node
fun addEdge(child: Node) {
when (numberOfEdges) {
0 -> edge0 = child
1 -> edge1 = child
2 -> edge2 = child
3 -> edge3 = child
4 -> edge4 = child
5 -> edge5 = child
6 -> edge6 = child
7 -> edge7 = child
8 -> edge8 = child
9 -> edge9 = child
else -> error("Too many edges")
}
++numberOfEdges
}
fun getEdges(): List<Node> {
val result = mutableListOf<Node>()
if (numberOfEdges > 0) result += edge0
if (numberOfEdges > 1) result += edge1
if (numberOfEdges > 2) result += edge2
if (numberOfEdges > 3) result += edge3
if (numberOfEdges > 4) result += edge4
if (numberOfEdges > 5) result += edge5
if (numberOfEdges > 6) result += edge6
if (numberOfEdges > 7) result += edge7
if (numberOfEdges > 8) result += edge8
if (numberOfEdges > 9) result += edge9
return result
}
}
class Graph(val nodes: List<Node>, val roots: List<Node>)
fun min(x: Int, y: Int) = if (x < y) x else y
fun max(x: Int, y: Int) = if (x > y) x else y
@ThreadLocal
val random = Random(42)
fun generate(condensationSize: Int, branchingFactor: Int, swellingFactor: Int): Graph {
var id = 0
val nodes = mutableListOf<Node>()
fun genDAG(n: Int): Node {
val node = Node(id++)
nodes += node
if (n == 1) return node
val numberOfChildren = random.next(1, min(n - 1, branchingFactor))
val used = BooleanArray(n)
val points = IntArray(numberOfChildren + 1)
points[0] = 0
points[numberOfChildren] = n - 1
used[0] = true
used[n - 1] = true
for (i in 1 until numberOfChildren) {
var p: Int
do {
p = random.next(1, n - 1)
} while (used[p])
used[p] = true
points[i] = p
}
points.sort()
for (i in 1..numberOfChildren) {
val childSize = points[i] - points[i - 1]
val child = genDAG(childSize)
if (random.next(2) == 0)
node.addEdge(child)
else
child.addEdge(node)
}
return node
}
genDAG(condensationSize)
val numberOfEnters = IntArray(condensationSize)
for (node in nodes)
for (edge in node.getEdges())
++numberOfEnters[edge.id]
val roots = nodes.filter { numberOfEnters[it.id] == 0 }
for (i in 0 until condensationSize) {
val node = nodes[i]
val componentSize = random.next(1, swellingFactor)
if (componentSize == 1 && random.next(2) == 0)
continue
val component = Array(componentSize) {
if (it == 0) node else Node(id++).also { nodes += it }
}
for (j in 0 until componentSize)
component[j].addEdge(component[(j - 1 + componentSize) % componentSize])
val numberOfAdditionalEdges = random.next((componentSize + 1) / 2)
for (j in 0 until numberOfAdditionalEdges)
component[random.next(componentSize)].addEdge(component[random.next(componentSize)])
}
return Graph(nodes, roots)
}
fun freezeOneGraph() {
val graph = generate(100, 5, 20)
graph.roots.forEach { it.freeze() }
for (node in graph.nodes)
assert (node.isFrozen, { "All nodes should be frozen" })
}
@Test fun runTest() {
for (i in 0..1000) {
freezeOneGraph()
}
println("OK")
}
@@ -1,94 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.worker9
import kotlin.test.*
import kotlin.native.concurrent.*
@Test fun runTest1() {
withLock { println("zzz") }
val worker = Worker.start()
val future = worker.execute(TransferMode.SAFE, {}) {
withLock {
println("42")
}
}
future.result
worker.requestTermination().result
println("OK")
}
fun withLock(op: () -> Unit) {
op()
}
@Test fun runTest2() {
val worker = Worker.start()
val future = worker.execute(TransferMode.SAFE, {}) {
val me = Worker.current
var x = 1
me.executeAfter (20000) {
println("second ${++x}")
}
me.executeAfter(10000) {
println("first ${++x}")
}
}
worker.requestTermination().result
}
@Test fun runTest3() {
val worker = Worker.start()
if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) {
worker.executeAfter {
println("unfrozen OK")
}
} else {
assertFailsWith<IllegalStateException> {
val message = "shall not happen"
worker.executeAfter {
println(message)
}
}
}
assertFailsWith<IllegalArgumentException> {
val message = "shall not happen"
worker.executeAfter(-1, {
println(message)
}.freeze())
}
worker.executeAfter(0, {
println("frozen OK")
}.freeze())
worker.requestTermination().result
}
class Node(var node: Node?, var outher: Node?)
fun makeCyclic(): Node {
val inner = Node(null, null)
inner.node = inner
val outer = Node(null, null)
inner.outher = outer
return outer
}
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
@Test fun runTest4() {
val worker = Worker.start()
val future = worker.execute(TransferMode.SAFE, { }) {
makeCyclic().also {
kotlin.native.runtime.GC.collect()
}
}
assert(future.result != null)
worker.requestTermination().result
}
@@ -1,6 +0,0 @@
zzz
42
OK
first 2
second 3
frozen OK