[K/N] Implement Lazy for new mm

This commit is contained in:
Pavel Kunyavskiy
2021-07-12 11:51:52 +03:00
committed by Space
parent 2f2e608502
commit d88a665fa8
4 changed files with 168 additions and 35 deletions
@@ -8,53 +8,93 @@ package runtime.workers.lazy1
import kotlin.test.*
import kotlin.native.concurrent.*
class Lazy {
private var y = 20
class Lazy(mode: LazyThreadSafetyMode) {
val x = 17
val self by lazy { this }
val recursion: Int by lazy {
val self by lazy(mode) { this }
val recursion: Int by lazy(mode) {
if (x < 17) 42 else recursion
}
val freezer: Int by lazy {
val finiteRecursion : Int by lazy(mode) {
if (y < 17) 42 else {
y -= 1
finiteRecursion + 1
}
}
val freezer: Int by lazy(mode) {
freeze()
42
}
val thrower: String by lazy {
val thrower: String by lazy(mode) {
if (x < 100) throw IllegalArgumentException()
"FAIL"
}
}
private val checkedLazyModes =
if (Platform.memoryModel != MemoryModel.EXPERIMENTAL)
listOf(LazyThreadSafetyMode.PUBLICATION)
else
listOf(LazyThreadSafetyMode.SYNCHRONIZED, LazyThreadSafetyMode.PUBLICATION)
@Test fun runTest1() {
assertFailsWith<IllegalStateException> {
println(Lazy().recursion)
}
assertFailsWith<IllegalStateException> {
println(Lazy().freeze().recursion)
for (mode in checkedLazyModes) {
// We decided to synchonaize behaviour to be consistent with jvm version.
// Anyway, it's doesn't looks like well-defined case
if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) {
val expected = if (mode == LazyThreadSafetyMode.SYNCHRONIZED) 46 else 42
y = 20
assertEquals(Lazy(mode).finiteRecursion, expected)
y = 20
assertEquals(Lazy(mode).freeze().finiteRecursion, expected)
} else {
assertFailsWith<IllegalStateException> {
println(Lazy(mode).recursion)
}
assertFailsWith<IllegalStateException> {
println(Lazy(mode).freeze().recursion)
}
y = 20
assertFailsWith<IllegalStateException> {
println(Lazy(mode).finiteRecursion)
}
y = 20
assertFailsWith<IllegalStateException> {
println(Lazy(mode).freeze().finiteRecursion)
}
}
}
}
@Test fun runTest2() {
var sum = 0
for (i in 1 .. 100) {
val self = Lazy().freeze()
assertEquals(self, self.self)
sum += self.self.hashCode()
for (mode in checkedLazyModes) {
var sum = 0
for (i in 1..100) {
val self = Lazy(mode).freeze()
assertEquals(self, self.self)
sum += self.self.hashCode()
}
}
println("OK")
}
@Test fun runTest3() {
assertFailsWith<InvalidMutabilityException> {
println(Lazy().freezer)
for (mode in checkedLazyModes) {
assertFailsWith<InvalidMutabilityException> {
println(Lazy(mode).freezer)
}
}
}
@Test fun runTest4() {
val self = Lazy()
repeat(10) {
assertFailsWith<IllegalArgumentException> {
println(self.thrower)
for (mode in checkedLazyModes) {
val self = Lazy(mode)
repeat(10) {
assertFailsWith<IllegalArgumentException> {
println(self.thrower)
}
}
}
}
@@ -11,16 +11,20 @@ import kotlin.native.concurrent.*
const val WORKERS_COUNT = 20
class C(private val initializer: () -> Int) {
val data by lazy { initializer() }
class IntHolder(val value:Int)
class C(mode: LazyThreadSafetyMode, private val initializer: () -> IntHolder) {
val data by lazy(mode) { initializer() }
}
fun concurrentLazyAccess(freeze: Boolean) {
fun concurrentLazyAccess(freeze: Boolean, mode: LazyThreadSafetyMode) {
// in old mm PUBLICATION is in fact SYNCHRONIZED, while SYNCHRONIZED is not supported
val argumentMode = if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) mode else LazyThreadSafetyMode.PUBLICATION
val initializerCallCount = AtomicInt(0)
val c = C {
val c = C(argumentMode) {
initializerCallCount.increment()
42
IntHolder(42)
}
if (freeze) {
c.freeze()
@@ -40,14 +44,18 @@ fun concurrentLazyAccess(freeze: Boolean) {
while (inited.value < workers.size) {}
canStart.value = 1
futures.forEach {
assertEquals(42, it.result)
val results = futures.map { it.result }
results.forEach {
assertEquals(42, it.value)
assertSame(results[0], it)
}
workers.forEach {
it.requestTermination().result
}
assertEquals(1, initializerCallCount.value)
if (mode == LazyThreadSafetyMode.SYNCHRONIZED) {
assertEquals(1, initializerCallCount.value)
}
}
@Test
@@ -55,11 +63,13 @@ fun concurrentLazyAccessUnfrozen() {
if (Platform.memoryModel != MemoryModel.EXPERIMENTAL) {
return
}
concurrentLazyAccess(false)
concurrentLazyAccess(false, LazyThreadSafetyMode.SYNCHRONIZED)
concurrentLazyAccess(false, LazyThreadSafetyMode.PUBLICATION)
}
@Test
fun concurrentLazyAccessFrozen() {
concurrentLazyAccess(true)
concurrentLazyAccess(true, LazyThreadSafetyMode.SYNCHRONIZED)
concurrentLazyAccess(true, LazyThreadSafetyMode.PUBLICATION)
}