[atomicfu-K/N]: Support Native backend in atomicfu compiler plugin

Atomicfu compiler plugin supported transformations for K/N:
* atomic properties are replaced with volatile properties and all the operations are delegated to native atomic intrinsics
* atomic arrays are replaced with kotlin.concurrent.Atomic*Arrays
* all other features available on JVM are covered as well (custom atomic extensions, delegated properties, debug tracing)

See (KT-58358, https://github.com/Kotlin/kotlinx-atomicfu/issues/261)

Merge-request: KT-MR-11253
Merged-by: Maria Sokolova <maria.sokolova@jetbrains.com>
This commit is contained in:
mvicsokolova
2023-07-31 14:48:28 +00:00
committed by Space Team
parent 15b2ad4943
commit bed16f92b1
14 changed files with 1210 additions and 78 deletions
@@ -1,13 +1,9 @@
import kotlinx.atomicfu.*
import kotlin.test.*
class ArrayInlineExtensionTest {
class AtomicIntArrayInlineExtensionTest {
private val intArr = AtomicIntArray(10)
private val a = atomic(100)
private val longArr = AtomicLongArray(10)
private val refArr = atomicArrayOfNulls<Any?>(5)
class A(val s: String)
private val a = atomic(0)
private inline fun casLoop(to: Int): Int {
intArr[0].loop { cur ->
@@ -16,8 +12,8 @@ class ArrayInlineExtensionTest {
}
}
private inline fun casLoopExpression(to: Long): Long = longArr[3].loop { cur ->
if (longArr[3].compareAndSet(cur, to)) return longArr[3].value
private inline fun casLoopExpression(to: Int): Int = intArr[3].loop { cur ->
if (intArr[3].compareAndSet(cur, to)) return intArr[3].value
return 777
}
@@ -60,7 +56,7 @@ class ArrayInlineExtensionTest {
return foo(value + delta)
}
fun testIntExtensionLoops() {
fun test() {
assertEquals(5, casLoop(5))
assertEquals(6, casLoopExpression(6))
assertEquals(66, intArr[1].extensionLoop(66))
@@ -72,8 +68,161 @@ class ArrayInlineExtensionTest {
}
}
class AtomicLongArrayInlineExtensionTest {
private val longArr = AtomicLongArray(10)
private val a = atomic(0L)
private inline fun casLoop(to: Long): Long {
longArr[0].loop { cur ->
if (longArr[0].compareAndSet(cur, to)) return longArr[0].value
return 777L
}
}
private inline fun casLoopExpression(to: Long): Long = longArr[3].loop { cur ->
if (longArr[3].compareAndSet(cur, to)) return longArr[3].value
return 777L
}
private inline fun AtomicLong.extensionLoop(to: Long): Long {
loop { cur ->
if (compareAndSet(cur, to)) return value
return 777L
}
}
private inline fun AtomicLong.extensionLoopExpression(to: Long): Long = loop { cur ->
lazySet(cur + 10L)
return if (compareAndSet(cur, to)) value else incrementAndGet()
}
private inline fun AtomicLong.extensionLoopMixedReceivers(first: Long, second: Long, index: Int): Long {
loop { cur ->
compareAndSet(cur, first)
longArr[index].compareAndSet(first, second)
return value
}
}
private inline fun AtomicLong.extensionLoopRecursive(to: Long): Long {
loop { cur ->
compareAndSet(cur, to)
a.extensionLoop(5L)
return value
}
}
private inline fun AtomicLong.foo(to: Long): Long {
loop { cur ->
if (compareAndSet(cur, to)) return 777L
else return value
}
}
private inline fun AtomicLong.bar(delta: Long): Long {
return foo(value + delta)
}
fun test() {
assertEquals(5L, casLoop(5L))
assertEquals(6L, casLoopExpression(6L))
assertEquals(66L, longArr[1].extensionLoop(66L))
assertEquals(66L, longArr[2].extensionLoop(66L))
assertEquals(77L, longArr[1].extensionLoopExpression(777L))
assertEquals(99L, longArr[1].extensionLoopMixedReceivers(88L, 99L, 1))
assertEquals(100L, longArr[1].extensionLoopRecursive(100L))
assertEquals(777L, longArr[1].bar(100L))
}
}
class AtomicBooleanArrayInlineExtensionTest {
private val booleanArr = AtomicBooleanArray(10)
private inline fun casLoop(to: Boolean): Boolean {
booleanArr[0].loop { cur ->
if (booleanArr[0].compareAndSet(cur, to)) return booleanArr[0].value
}
}
private inline fun casLoopExpression(to: Boolean): Boolean = booleanArr[3].loop { cur ->
if (booleanArr[3].compareAndSet(cur, to)) return booleanArr[3].value
}
private inline fun AtomicBoolean.extensionLoop(to: Boolean): Boolean {
loop { cur ->
if (compareAndSet(cur, to)) return value
}
}
private inline fun AtomicBoolean.extensionLoopExpression(to: Boolean): Boolean = loop { cur ->
lazySet(false)
return if (compareAndSet(cur, to)) value else !value
}
private inline fun AtomicBoolean.extensionLoopMixedReceivers(first: Boolean, second: Boolean, index: Int): Boolean {
loop { cur ->
compareAndSet(cur, first)
booleanArr[index].compareAndSet(first, second)
return value
}
}
fun test() {
assertEquals(true, casLoop(true))
assertEquals(true, casLoopExpression(true))
assertEquals(true, booleanArr[1].extensionLoop(true))
assertEquals(true, booleanArr[1].extensionLoopExpression(true))
assertEquals(false, booleanArr[7].extensionLoopMixedReceivers(true, false, 7))
}
}
class AtomicRefArrayInlineExtensionTest {
private val refArr = atomicArrayOfNulls<String?>(10)
private val a = atomic(0L)
private inline fun casLoop(to: String): String? {
refArr[0].loop { cur ->
if (refArr[0].compareAndSet(cur, to)) return refArr[0].value
}
}
private inline fun casLoopExpression(to: String): String? = refArr[3].loop { cur ->
if (refArr[3].compareAndSet(cur, to)) return refArr[3].value
}
private inline fun AtomicRef<String?>.extensionLoop(to: String): String? {
loop { cur ->
if (compareAndSet(cur, to)) return value
else "incorrect"
}
}
private inline fun AtomicRef<String?>.extensionLoopExpression(to: String): String? = loop { cur ->
lazySet("aaa")
return if (compareAndSet(cur, to)) value else "CAS_failed"
}
private inline fun AtomicRef<String?>.extensionLoopMixedReceivers(first: String, second: String, index: Int): String? {
loop { cur ->
compareAndSet(cur, first)
refArr[index].compareAndSet(first, second)
return value
}
}
fun test() {
assertEquals("aaa", casLoop("aaa"))
assertEquals("bbb", casLoopExpression("bbb"))
assertEquals("ccc", refArr[1].extensionLoop("ccc"))
assertEquals("CAS_failed", refArr[1].extensionLoopExpression("ccc"))
assertEquals("bbb", refArr[7].extensionLoopMixedReceivers("aaa", "bbb", 7))
}
}
fun box(): String {
val testClass = ArrayInlineExtensionTest()
testClass.testIntExtensionLoops()
AtomicIntArrayInlineExtensionTest().test()
AtomicLongArrayInlineExtensionTest().test()
AtomicBooleanArrayInlineExtensionTest().test()
AtomicRefArrayInlineExtensionTest().test()
return "OK"
}
@@ -1,26 +1,40 @@
@kotlin.Metadata
public final class ArrayInlineExtensionTest$A {
public final class ArrayInlineExtensionTestKt {
// source: 'ArrayInlineExtensionTest.kt'
private final @org.jetbrains.annotations.NotNull field s: java.lang.String
public method <init>(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
public final @org.jetbrains.annotations.NotNull method getS(): java.lang.String
public final inner class ArrayInlineExtensionTest$A
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
}
@kotlin.Metadata
public final class ArrayInlineExtensionTest {
public final class AtomicBooleanArrayInlineExtensionTest {
// source: 'ArrayInlineExtensionTest.kt'
private synthetic final field booleanArr: java.util.concurrent.atomic.AtomicIntegerArray
public method <init>(): void
private final method casLoop(p0: boolean): boolean
private final method casLoopExpression(p0: boolean): boolean
private synthetic final method extensionLoop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: boolean): boolean
private synthetic final method extensionLoop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: boolean): boolean
private synthetic final method extensionLoopExpression$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: boolean): boolean
private synthetic final method extensionLoopExpression$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: boolean): boolean
private synthetic final method extensionLoopMixedReceivers$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: boolean, p3: boolean, p4: int): boolean
private synthetic final method extensionLoopMixedReceivers$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: boolean, p3: boolean, p4: int): boolean
private synthetic final method getBooleanArr(): java.util.concurrent.atomic.AtomicIntegerArray
private synthetic final method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: kotlin.jvm.functions.Function1): void
private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): void
public final method test(): void
}
@kotlin.Metadata
public final class AtomicIntArrayInlineExtensionTest {
// source: 'ArrayInlineExtensionTest.kt'
private synthetic final static field a$volatile$FU: java.util.concurrent.atomic.AtomicIntegerFieldUpdater
private synthetic volatile field a$volatile: int
private synthetic final field intArr: java.util.concurrent.atomic.AtomicIntegerArray
private synthetic final field longArr: java.util.concurrent.atomic.AtomicLongArray
private synthetic final field refArr: java.util.concurrent.atomic.AtomicReferenceArray
static method <clinit>(): void
public method <init>(): void
private synthetic final method bar$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int
private synthetic final method bar$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int
private final method casLoop(p0: int): int
private final method casLoopExpression(p0: long): long
private final method casLoopExpression(p0: int): int
private synthetic final method extensionLoop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int
private synthetic final method extensionLoop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: int): int
private synthetic final method extensionLoopExpression$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: int): int
@@ -34,18 +48,64 @@ public final class ArrayInlineExtensionTest {
private synthetic final static method getA$volatile$FU(): java.util.concurrent.atomic.AtomicIntegerFieldUpdater
private synthetic final method getA$volatile(): int
private synthetic final method getIntArr(): java.util.concurrent.atomic.AtomicIntegerArray
private synthetic final method getLongArr(): java.util.concurrent.atomic.AtomicLongArray
private synthetic final method getRefArr(): java.util.concurrent.atomic.AtomicReferenceArray
private synthetic final method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicIntegerArray, p1: int, p2: kotlin.jvm.functions.Function1): void
private synthetic final method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicLongArray, p1: int, p2: kotlin.jvm.functions.Function1): void
private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicIntegerFieldUpdater, p2: kotlin.jvm.functions.Function1): void
private synthetic final method setA$volatile(p0: int): void
public final method testIntExtensionLoops(): void
public final inner class ArrayInlineExtensionTest$A
public final method test(): void
}
@kotlin.Metadata
public final class ArrayInlineExtensionTestKt {
public final class AtomicLongArrayInlineExtensionTest {
// source: 'ArrayInlineExtensionTest.kt'
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
private synthetic final static field a$volatile$FU: java.util.concurrent.atomic.AtomicLongFieldUpdater
private synthetic volatile field a$volatile: long
private synthetic final field longArr: java.util.concurrent.atomic.AtomicLongArray
static method <clinit>(): void
public method <init>(): void
private synthetic final method bar$atomicfu$array(p0: java.util.concurrent.atomic.AtomicLongArray, p1: int, p2: long): long
private synthetic final method bar$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: long): long
private final method casLoop(p0: long): long
private final method casLoopExpression(p0: long): long
private synthetic final method extensionLoop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicLongArray, p1: int, p2: long): long
private synthetic final method extensionLoop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: long): long
private synthetic final method extensionLoopExpression$atomicfu$array(p0: java.util.concurrent.atomic.AtomicLongArray, p1: int, p2: long): long
private synthetic final method extensionLoopExpression$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: long): long
private synthetic final method extensionLoopMixedReceivers$atomicfu$array(p0: java.util.concurrent.atomic.AtomicLongArray, p1: int, p2: long, p3: long, p4: int): long
private synthetic final method extensionLoopMixedReceivers$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: long, p3: long, p4: int): long
private synthetic final method extensionLoopRecursive$atomicfu$array(p0: java.util.concurrent.atomic.AtomicLongArray, p1: int, p2: long): long
private synthetic final method extensionLoopRecursive$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: long): long
private synthetic final method foo$atomicfu$array(p0: java.util.concurrent.atomic.AtomicLongArray, p1: int, p2: long): long
private synthetic final method foo$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: long): long
private synthetic final static method getA$volatile$FU(): java.util.concurrent.atomic.AtomicLongFieldUpdater
private synthetic final method getA$volatile(): long
private synthetic final method getLongArr(): java.util.concurrent.atomic.AtomicLongArray
private synthetic final method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicLongArray, p1: int, p2: kotlin.jvm.functions.Function1): void
private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicLongFieldUpdater, p2: kotlin.jvm.functions.Function1): void
private synthetic final method setA$volatile(p0: long): void
public final method test(): void
}
@kotlin.Metadata
public final class AtomicRefArrayInlineExtensionTest {
// source: 'ArrayInlineExtensionTest.kt'
private synthetic final static field a$volatile$FU: java.util.concurrent.atomic.AtomicLongFieldUpdater
private synthetic volatile field a$volatile: long
private synthetic final field refArr: java.util.concurrent.atomic.AtomicReferenceArray
static method <clinit>(): void
public method <init>(): void
private final method casLoop(p0: java.lang.String): java.lang.String
private final method casLoopExpression(p0: java.lang.String): java.lang.String
private synthetic final method extensionLoop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: java.lang.String): java.lang.String
private synthetic final method extensionLoop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: java.lang.String): java.lang.String
private synthetic final method extensionLoopExpression$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: java.lang.String): java.lang.String
private synthetic final method extensionLoopExpression$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: java.lang.String): java.lang.String
private synthetic final method extensionLoopMixedReceivers$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: java.lang.String, p3: java.lang.String, p4: int): java.lang.String
private synthetic final method extensionLoopMixedReceivers$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: java.lang.String, p3: java.lang.String, p4: int): java.lang.String
private synthetic final static method getA$volatile$FU(): java.util.concurrent.atomic.AtomicLongFieldUpdater
private synthetic final method getA$volatile(): long
private synthetic final method getRefArr(): java.util.concurrent.atomic.AtomicReferenceArray
private synthetic final method loop$atomicfu$array(p0: java.util.concurrent.atomic.AtomicReferenceArray, p1: int, p2: kotlin.jvm.functions.Function1): void
private synthetic final method loop$atomicfu(p0: java.lang.Object, p1: java.util.concurrent.atomic.AtomicReferenceFieldUpdater, p2: kotlin.jvm.functions.Function1): void
private synthetic final method setA$volatile(p0: long): void
public final method test(): void
}