[K/N] Tests for volatile
^KT-54944
This commit is contained in:
committed by
Space Team
parent
a11f6fd9cb
commit
fc95b88eef
@@ -0,0 +1,26 @@
|
||||
// TARGET_BACKEND: NATIVE
|
||||
// test is disabled now because of https://youtrack.jetbrains.com/issue/KT-55426
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
|
||||
// MODULE: lib
|
||||
// FILE: lib.kt
|
||||
@file:OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.concurrent.*
|
||||
|
||||
class Box(@Volatile var value: String)
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: main.kt
|
||||
|
||||
@file:Suppress("INVISIBLE_MEMBER")
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.concurrent.*
|
||||
|
||||
fun box() : String {
|
||||
val o = "O"
|
||||
val x = Box(o)
|
||||
return x.compareAndSwapField(Box::value, o, "K") + x.value
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
// TARGET_BACKEND: NATIVE
|
||||
// KT-55904
|
||||
// IGNORE_BACKEND_K2: NATIVE
|
||||
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
@file:OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.concurrent.*
|
||||
|
||||
interface Wrapper<T> {
|
||||
fun compareAndSwap(expected: T, new: T): T
|
||||
fun compareAndSet(expected: T, new: T): Boolean
|
||||
fun getAndSet(expected: T): T
|
||||
}
|
||||
|
||||
interface IncWrapper<T> : Wrapper<T> {
|
||||
fun getAndAdd(expected: T): T
|
||||
}
|
||||
|
||||
interface RefWrapper<T> : Wrapper<T> {
|
||||
}
|
||||
|
||||
|
||||
class IntWrapper(@Volatile var x : Int) : IncWrapper<Int> {
|
||||
override fun compareAndSwap(expected: Int, new: Int) = compareAndSwapField(IntWrapper::x, expected, new)
|
||||
override fun compareAndSet(expected: Int, new: Int) = compareAndSetField(IntWrapper::x, expected, new)
|
||||
override fun getAndSet(new: Int) = getAndSetField(IntWrapper::x, new)
|
||||
override fun getAndAdd(delta: Int) = getAndAddField(IntWrapper::x, delta)
|
||||
}
|
||||
|
||||
class LongWrapper(@Volatile var x : Long) : IncWrapper<Long> {
|
||||
override fun compareAndSwap(expected: Long, new: Long) = compareAndSwapField(LongWrapper::x, expected, new)
|
||||
override fun compareAndSet(expected: Long, new: Long) = compareAndSetField(LongWrapper::x, expected, new)
|
||||
override fun getAndSet(new: Long) = getAndSetField(LongWrapper::x, new)
|
||||
override fun getAndAdd(delta: Long) = getAndAddField(LongWrapper::x, delta)
|
||||
}
|
||||
|
||||
class ShortWrapper(@Volatile var x : Short) : IncWrapper<Short> {
|
||||
override fun compareAndSwap(expected: Short, new: Short) = compareAndSwapField(ShortWrapper::x, expected, new)
|
||||
override fun compareAndSet(expected: Short, new: Short) = compareAndSetField(ShortWrapper::x, expected, new)
|
||||
override fun getAndSet(new: Short) = getAndSetField(ShortWrapper::x, new)
|
||||
override fun getAndAdd(delta: Short) = getAndAddField(ShortWrapper::x, delta)
|
||||
}
|
||||
|
||||
class ByteWrapper(@Volatile var x : Byte) : IncWrapper<Byte> {
|
||||
override fun compareAndSwap(expected: Byte, new: Byte) = compareAndSwapField(ByteWrapper::x, expected, new)
|
||||
override fun compareAndSet(expected: Byte, new: Byte) = compareAndSetField(ByteWrapper::x, expected, new)
|
||||
override fun getAndSet(new: Byte) = getAndSetField(ByteWrapper::x, new)
|
||||
override fun getAndAdd(delta: Byte) = getAndAddField(ByteWrapper::x, delta)
|
||||
}
|
||||
|
||||
|
||||
class StringWrapper(@Volatile var x : String) : RefWrapper<String> {
|
||||
override fun compareAndSwap(expected: String, new: String) = compareAndSwapField(StringWrapper::x, expected, new)
|
||||
override fun compareAndSet(expected: String, new: String) = compareAndSetField(StringWrapper::x, expected, new)
|
||||
override fun getAndSet(new: String) = getAndSetField(StringWrapper::x, new)
|
||||
}
|
||||
|
||||
class GenericWrapper<T>(@Volatile var x : T) : RefWrapper<T> {
|
||||
override fun compareAndSwap(expected: T, new: T) = compareAndSwapField(GenericWrapper<T>::x, expected, new)
|
||||
override fun compareAndSet(expected: T, new: T) = compareAndSetField(GenericWrapper<T>::x, expected, new)
|
||||
override fun getAndSet(new: T) = getAndSetField(GenericWrapper<T>::x, new)
|
||||
}
|
||||
|
||||
|
||||
inline fun testFail(block: () -> Unit, onSuccess: () -> Nothing) {
|
||||
try {
|
||||
block()
|
||||
onSuccess()
|
||||
} catch (ignored: IllegalArgumentException) {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> test(one: T, two: T, three: T, wrap: (T) -> Wrapper<T>) : String? {
|
||||
val w = wrap(one)
|
||||
if (!isExperimentalMM() && w is RefWrapper<*>) {
|
||||
testFail({ w.compareAndSwap(one, two) }) { return "FAIL 1" }
|
||||
testFail({ w.compareAndSet(one, two) }) { return "FAIL 2" }
|
||||
testFail({ w.getAndSet(one) }) { return "FAIL 3" }
|
||||
return null
|
||||
}
|
||||
if (w.compareAndSet(one, two) != true) return "FAIL 4"
|
||||
if (w.compareAndSet(one, two) != false) return "FAIL 5"
|
||||
if (w.getAndSet(one) != two) return "FAIL 6"
|
||||
if (w.getAndSet(one) != one) return "FAIL 7"
|
||||
if (w.compareAndSwap(one, two) != one) return "FAIL 8"
|
||||
if (w.compareAndSwap(one, two) != two) return "FAIL 9"
|
||||
if (w.compareAndSwap(one, two) != two) return "FAIL 10"
|
||||
if (w.compareAndSwap(two, one) != two) return "FAIL 11"
|
||||
if (w is IncWrapper<T>) {
|
||||
if (w.getAndAdd(one) != one) return "FAIL 12"
|
||||
if (w.getAndAdd(one) != two) return "FAIL 13"
|
||||
if (w.getAndAdd(one) != three) return "FAIL 14"
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
fun box() : String {
|
||||
test(1, 2, 3, ::IntWrapper)?.let { return "Int: $it" }
|
||||
test(1, 2, 3, ::LongWrapper)?.let { return "Long: $it" }
|
||||
test(1, 2, 3, ::ShortWrapper)?.let { return "Short: $it" }
|
||||
test(1, 2, 3, ::ByteWrapper)?.let { return "Byte: $it" }
|
||||
test("1", "2", "3", ::StringWrapper)?.let { return "String: $it" }
|
||||
test("1", "2", "3", { GenericWrapper<String>(it) })?.let { return "Generic<String>: $it" }
|
||||
test(1, 2, 3, { GenericWrapper<Int>(it) })?.let { return "Generic<Int>: $it" }
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// TARGET_BACKEND: NATIVE
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.concurrent.*
|
||||
|
||||
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
@Volatile var x = 0
|
||||
var y = -1
|
||||
|
||||
fun box() : String {
|
||||
if (Platform.memoryModel != MemoryModel.EXPERIMENTAL) {
|
||||
// The test doesn't make sense for legacy mm, you can't have anything non-atomic to protect with @Volatile var
|
||||
return "OK"
|
||||
}
|
||||
val w1 = Worker.start()
|
||||
val w2 = Worker.start()
|
||||
|
||||
val f1 = w1.execute(TransferMode.SAFE, { -> }) {
|
||||
repeat(10000) {
|
||||
while (x != 0) {}
|
||||
y = it
|
||||
x = 1
|
||||
}
|
||||
"O"
|
||||
}
|
||||
val f2 = w2.execute(TransferMode.SAFE, { -> }) {
|
||||
var result = "K"
|
||||
repeat(10000) {
|
||||
while (x != 1) {}
|
||||
if (y != it) result = "FAIL"
|
||||
x = 0
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
return (f1.result + f2.result).also {
|
||||
w1.requestTermination().result
|
||||
w2.requestTermination().result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: WASM, JS
|
||||
// IGNORE_BACKEND_K1: JS_IR
|
||||
// !API_VERSION: 1.9
|
||||
|
||||
import kotlin.concurrent.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
class BoolWrapper(@Volatile var x: Boolean)
|
||||
|
||||
val global = BoolWrapper(false)
|
||||
|
||||
fun box() : String {
|
||||
val local = BoolWrapper(false)
|
||||
if (global.x || local.x) return "FAIL"
|
||||
global.x = true
|
||||
local.x = true
|
||||
return if (global.x && local.x) "OK" else "FAIL"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: WASM, JS
|
||||
// IGNORE_BACKEND_K1: JS_IR
|
||||
// !API_VERSION: 1.9
|
||||
|
||||
import kotlin.concurrent.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
class ByteWrapper(@Volatile var x: Byte)
|
||||
|
||||
val global = ByteWrapper(1)
|
||||
|
||||
fun box() : String {
|
||||
val local = ByteWrapper(2)
|
||||
if (global.x + local.x != 3) return "FAIL"
|
||||
global.x = 5
|
||||
local.x = 6
|
||||
return if (global.x + local.x != 11) return "FAIL" else "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: WASM, JS
|
||||
// IGNORE_BACKEND_K1: JS_IR
|
||||
// !API_VERSION: 1.9
|
||||
|
||||
import kotlin.concurrent.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
class DoubleWrapper(@Volatile var x: Double)
|
||||
|
||||
val global = DoubleWrapper(1.5)
|
||||
|
||||
fun box() : String {
|
||||
val local = DoubleWrapper(2.5)
|
||||
if (global.x + local.x != 4.0) return "FAIL"
|
||||
global.x = 5.5
|
||||
local.x = 6.5
|
||||
return if (global.x + local.x != 12.0) return "FAIL" else "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: WASM, JS
|
||||
// IGNORE_BACKEND_K1: JS_IR
|
||||
// !API_VERSION: 1.9
|
||||
|
||||
import kotlin.concurrent.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
class FloatWrapper(@Volatile var x: Float)
|
||||
|
||||
val global = FloatWrapper(1.5f)
|
||||
|
||||
fun box() : String {
|
||||
val local = FloatWrapper(2.5f)
|
||||
if (global.x + local.x != 4.0f) return "FAIL"
|
||||
global.x = 5.5f
|
||||
local.x = 6.5f
|
||||
return if (global.x + local.x != 12.0f) return "FAIL" else "OK"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: WASM, JS
|
||||
// IGNORE_BACKEND_K1: JS_IR
|
||||
// !API_VERSION: 1.9
|
||||
|
||||
import kotlin.concurrent.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
class GenericWrapper<T>(@Volatile var x: T)
|
||||
|
||||
val global = GenericWrapper("FA")
|
||||
val globalLong = GenericWrapper(1L)
|
||||
|
||||
fun box() : String {
|
||||
val local = GenericWrapper("IL")
|
||||
val localLong = GenericWrapper(2L)
|
||||
if (global.x + local.x != "FAIL") return "FAIL 1"
|
||||
if (globalLong.x + localLong.x != 3L) return "FAIL 2"
|
||||
global.x = "O"
|
||||
local.x = "K"
|
||||
globalLong.x = 5L
|
||||
localLong.x = 6L
|
||||
if (globalLong.x + localLong.x != 11L) return "FAIL 3"
|
||||
return global.x + local.x
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: WASM, JS
|
||||
// IGNORE_BACKEND_K1: JS_IR
|
||||
// !API_VERSION: 1.9
|
||||
|
||||
import kotlin.concurrent.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
class IntWrapper(@Volatile var x: Int)
|
||||
|
||||
val global = IntWrapper(1)
|
||||
|
||||
fun box() : String {
|
||||
val local = IntWrapper(2)
|
||||
if (global.x + local.x != 3) return "FAIL"
|
||||
global.x = 5
|
||||
local.x = 6
|
||||
return if (global.x + local.x != 11) return "FAIL" else "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: WASM, JS
|
||||
// IGNORE_BACKEND_K1: JS_IR
|
||||
// !API_VERSION: 1.9
|
||||
|
||||
import kotlin.concurrent.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
class LongWrapper(@Volatile var x: Long)
|
||||
|
||||
val global = LongWrapper(1)
|
||||
|
||||
fun box() : String {
|
||||
val local = LongWrapper(2)
|
||||
if (global.x + local.x != 3L) return "FAIL"
|
||||
global.x = 5
|
||||
local.x = 6
|
||||
return if (global.x + local.x != 11L) return "FAIL" else "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: WASM, JS
|
||||
// IGNORE_BACKEND_K1: JS_IR
|
||||
// !API_VERSION: 1.9
|
||||
|
||||
import kotlin.concurrent.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
class ShortWrapper(@Volatile var x: Short)
|
||||
|
||||
val global = ShortWrapper(1)
|
||||
|
||||
fun box() : String {
|
||||
val local = ShortWrapper(2)
|
||||
if (global.x + local.x != 3) return "FAIL"
|
||||
global.x = 5
|
||||
local.x = 6
|
||||
return if (global.x + local.x != 11) return "FAIL" else "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: WASM, JS
|
||||
// IGNORE_BACKEND_K1: JS_IR
|
||||
// !API_VERSION: 1.9
|
||||
|
||||
import kotlin.concurrent.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
class StringWrapper(@Volatile var x: String)
|
||||
|
||||
val global = StringWrapper("FA")
|
||||
|
||||
fun box() : String {
|
||||
val local = StringWrapper("IL")
|
||||
if (global.x + local.x != "FAIL") return "FAIL"
|
||||
global.x = "O"
|
||||
local.x = "K"
|
||||
return global.x + local.x
|
||||
}
|
||||
Reference in New Issue
Block a user