diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 86ef9dfe833..910f5d1a28b 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -4284,32 +4284,68 @@
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt b/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt
index d1f27e93d7a..9ed2ad24351 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/generators/tests/GenerateNativeTests.kt
@@ -267,6 +267,16 @@ fun main() {
}
}
+ // Atomicfu compiler plugin native tests.
+ testGroup("plugins/atomicfu/atomicfu-compiler/test", "plugins/atomicfu/atomicfu-compiler/testData") {
+ testClass(
+ suiteTestClassName = "AtomicfuNativeTestGenerated",
+ annotations = listOf(atomicfuNative(), provider())
+ ) {
+ model("nativeBox")
+ }
+ }
+
generateTestGroupSuiteWithJUnit5 {
testGroup("native/native.tests/tests-gen", "compiler/util-klib-abi/testData") {
testClass(
@@ -345,4 +355,4 @@ private fun debugger() = annotation(Tag::class.java, "debugger")
private fun infrastructure() = annotation(Tag::class.java, "infrastructure")
private fun k1libContents() = annotation(Tag::class.java, "k1libContents")
private fun k2libContents() = annotation(Tag::class.java, "k2libContents")
-private fun atomicfu() = annotation(Tag::class.java, "atomicfu")
+private fun atomicfuNative() = annotation(Tag::class.java, "atomicfu-native")
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/ConfigurationProperties.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/ConfigurationProperties.kt
index ad794c7770b..8bfde34aefe 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/ConfigurationProperties.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/ConfigurationProperties.kt
@@ -56,6 +56,7 @@ internal class EnforcedProperties(testClass: Class<*>) {
internal enum class ClassLevelProperty(shortName: String) {
TEST_TARGET("target"),
TEST_MODE("mode"),
+ COMPILER_PLUGINS("compilerPlugins"),
CUSTOM_KLIBS("customKlibs"),
FORCE_STANDALONE("forceStandalone"),
COMPILE_ONLY("compileOnly"),
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeTestSupport.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeTestSupport.kt
index 66a13d03887..1a7d4425e20 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeTestSupport.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/NativeTestSupport.kt
@@ -190,6 +190,7 @@ private object NativeTestSupport {
output += sanitizer
output += CacheMode::class to cacheMode
output += computeTestMode(enforcedProperties)
+ output += computeCompilerPlugins(enforcedProperties)
output += computeCustomKlibs(enforcedProperties)
output += computeForcedStandaloneTestKind(enforcedProperties)
output += computeForcedNoopTestRunner(enforcedProperties)
@@ -277,6 +278,15 @@ private object NativeTestSupport {
private fun computeTestMode(enforcedProperties: EnforcedProperties): TestMode =
ClassLevelProperty.TEST_MODE.readValue(enforcedProperties, TestMode.values(), default = TestMode.TWO_STAGE_MULTI_MODULE)
+ private fun computeCompilerPlugins(enforcedProperties: EnforcedProperties): CompilerPlugins =
+ CompilerPlugins(
+ ClassLevelProperty.COMPILER_PLUGINS.readValue(
+ enforcedProperties,
+ { it.split(':', ';').mapToSet(::File) },
+ default = emptySet()
+ )
+ )
+
private fun computeCustomKlibs(enforcedProperties: EnforcedProperties): CustomKlibs =
CustomKlibs(
ClassLevelProperty.CUSTOM_KLIBS.readValue(
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt
index 3592d065e36..be259142566 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt
@@ -35,6 +35,7 @@ internal abstract class BasicCompilation(
private val optimizationMode: OptimizationMode,
private val compilerOutputInterceptor: CompilerOutputInterceptor,
protected val freeCompilerArgs: TestCompilerArgs,
+ protected val compilerPlugins: CompilerPlugins,
protected val dependencies: CategorizedDependencies,
protected val expectedArtifact: A
) : TestCompilation() {
@@ -67,6 +68,10 @@ internal abstract class BasicCompilation(
add(freeCompilerArgs.compilerArgs)
}
+ private fun ArgsBuilder.applyCompilerPlugins() {
+ add(compilerPlugins.compilerPluginJars) { compilerPluginJar -> "-Xplugin=${compilerPluginJar.path}" }
+ }
+
private fun ArgsBuilder.applySources() {
addFlattenedTwice(sourceModules, { it.files }) { it.location.path }
}
@@ -79,6 +84,7 @@ internal abstract class BasicCompilation(
applySpecificArgs(this)
applyDependencies(this)
applyFreeArgs()
+ applyCompilerPlugins()
applySources()
}
@@ -135,6 +141,7 @@ internal abstract class SourceBasedCompilation(
private val allocator: Allocator,
private val pipelineType: PipelineType,
freeCompilerArgs: TestCompilerArgs,
+ compilerPlugins: CompilerPlugins,
override val sourceModules: Collection,
dependencies: CategorizedDependencies,
expectedArtifact: A
@@ -145,6 +152,7 @@ internal abstract class SourceBasedCompilation(
optimizationMode = optimizationMode,
compilerOutputInterceptor = compilerOutputInterceptor,
freeCompilerArgs = freeCompilerArgs,
+ compilerPlugins = compilerPlugins,
dependencies = dependencies,
expectedArtifact = expectedArtifact
) {
@@ -197,6 +205,7 @@ internal class LibraryCompilation(
allocator = settings.get(),
pipelineType = settings.get(),
freeCompilerArgs = freeCompilerArgs,
+ compilerPlugins = settings.get(),
sourceModules = sourceModules,
dependencies = CategorizedDependencies(dependencies),
expectedArtifact = expectedArtifact
@@ -231,6 +240,7 @@ internal class ObjCFrameworkCompilation(
allocator = settings.get(),
pipelineType = settings.getStageDependentPipelineType(),
freeCompilerArgs = freeCompilerArgs,
+ compilerPlugins = settings.get(),
sourceModules = sourceModules,
dependencies = CategorizedDependencies(dependencies),
expectedArtifact = expectedArtifact
@@ -317,6 +327,7 @@ internal class ExecutableCompilation(
allocator = settings.get(),
pipelineType = settings.getStageDependentPipelineType(),
freeCompilerArgs = freeCompilerArgs,
+ compilerPlugins = settings.get(),
sourceModules = sourceModules,
dependencies = CategorizedDependencies(dependencies),
expectedArtifact = expectedArtifact
@@ -409,6 +420,7 @@ internal class StaticCacheCompilation(
optimizationMode = settings.get(),
compilerOutputInterceptor = settings.get(),
freeCompilerArgs = freeCompilerArgs,
+ compilerPlugins = settings.get(),
dependencies = CategorizedDependencies(dependencies),
expectedArtifact = expectedArtifact
) {
diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt
index 2e810ba377c..aa5a8d40f21 100644
--- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt
+++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt
@@ -77,6 +77,19 @@ internal enum class TestMode(private val description: String) {
override fun toString() = description
}
+/**
+ * Kotlin compiler plugins to be used together with the the Kotlin/Native compiler.
+ */
+@JvmInline
+internal value class CompilerPlugins(val compilerPluginJars: Set) {
+ init {
+ val invalidJars = compilerPluginJars.filterNot { it.isDirectory || (it.isFile && it.extension == "jar") }
+ assertTrue(invalidJars.isEmpty()) {
+ "There are invalid compiler plugin JARs that should be passed for the Kotlin/Native compiler: ${invalidJars.joinToString { "[$it]" }}"
+ }
+ }
+}
+
/**
* The set of custom (external) klibs that should be passed to the Kotlin/Native compiler.
*/
diff --git a/plugins/atomicfu/atomicfu-compiler/build.gradle.kts b/plugins/atomicfu/atomicfu-compiler/build.gradle.kts
index 627468bca8f..2e1e572faf5 100644
--- a/plugins/atomicfu/atomicfu-compiler/build.gradle.kts
+++ b/plugins/atomicfu/atomicfu-compiler/build.gradle.kts
@@ -41,8 +41,6 @@ val atomicfuNativeKlib by configurations.creating {
attribute(KotlinNativeTarget.konanTargetAttribute, nativeTargetName)
attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API))
attribute(KotlinPlatformType.attribute, KotlinPlatformType.native)
- // todo: don't add platform specific attribute
- attribute(KotlinNativeTarget.konanTargetAttribute, org.jetbrains.kotlin.konan.target.KonanTarget.MACOS_X64.toString())
}
}
@@ -54,6 +52,8 @@ val atomicfuJsIrRuntimeForTests by configurations.creating {
}
}
+val atomicfuCompilerPluginForTests by configurations.creating
+
repositories {
mavenCentral()
}
@@ -105,7 +105,7 @@ dependencies {
testImplementation(projectTests(":compiler:tests-common"))
testImplementation(projectTests(":compiler:tests-common-new"))
testImplementation(projectTests(":compiler:test-infrastructure"))
- testCompileOnly("org.jetbrains.kotlinx:atomicfu:0.17.1") // todo: do not hardcode atomicfu version
+ testCompileOnly("org.jetbrains.kotlinx:atomicfu:0.21.0")
testApiJUnit5()
@@ -114,10 +114,32 @@ dependencies {
testRuntimeOnly(project(":compiler:backend-common"))
testRuntimeOnly(commonDependency("org.fusesource.jansi", "jansi"))
- atomicfuJsClasspath("org.jetbrains.kotlinx:atomicfu-js:0.17.1") { isTransitive = false }
+ atomicfuJsClasspath("org.jetbrains.kotlinx:atomicfu-js:0.21.0") { isTransitive = false }
atomicfuJsIrRuntimeForTests(project(":kotlinx-atomicfu-runtime")) { isTransitive = false }
- atomicfuJvmClasspath("org.jetbrains.kotlinx:atomicfu:0.17.1") { isTransitive = false }
- atomicfuNativeKlib("org.jetbrains.kotlinx:atomicfu:0.17.1") { isTransitive = false }
+ atomicfuJvmClasspath("org.jetbrains.kotlinx:atomicfu:0.21.0") { isTransitive = false }
+ atomicfuNativeKlib("org.jetbrains.kotlinx:atomicfu:0.21.0") { isTransitive = false }
+ atomicfuCompilerPluginForTests(project(":kotlin-atomicfu-compiler-plugin"))
+ // Implicit dependencies on native artifacts to run native tests on CI
+ implicitDependencies("org.jetbrains.kotlinx:atomicfu-linuxx64:0.21.0") {
+ attributes {
+ attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API))
+ }
+ }
+ implicitDependencies("org.jetbrains.kotlinx:atomicfu-macosarm64:0.21.0"){
+ attributes {
+ attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API))
+ }
+ }
+ implicitDependencies("org.jetbrains.kotlinx:atomicfu-macosx64:0.21.0"){
+ attributes {
+ attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API))
+ }
+ }
+ implicitDependencies("org.jetbrains.kotlinx:atomicfu-mingwx64:0.21.0"){
+ attributes {
+ attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API))
+ }
+ }
embedded(project(":kotlinx-atomicfu-runtime")) {
attributes {
@@ -128,7 +150,7 @@ dependencies {
isTransitive = false
}
- testImplementation("org.jetbrains.kotlinx:atomicfu:0.17.1")
+ testImplementation("org.jetbrains.kotlinx:atomicfu:0.21.0")
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.9.1")
}
@@ -146,7 +168,10 @@ testsJar()
useD8Plugin()
projectTest(jUnitMode = JUnitMode.JUnit5) {
- useJUnitPlatform()
+ useJUnitPlatform {
+ // Exclude all tests with the "atomicfu-native" tag. They should be launched by another test task.
+ excludeTags("atomicfu-native")
+ }
useJsIrBoxTests(version = version, buildDir = "$buildDir/")
workingDir = rootDir
@@ -154,6 +179,12 @@ projectTest(jUnitMode = JUnitMode.JUnit5) {
dependsOn(":dist")
dependsOn(atomicfuJsIrRuntimeForTests)
+ // Depend on the test task that launches Native tests so that it will also run together with tests
+ // for all other targets if K/N is enabled
+ if (kotlinBuildProperties.isKotlinNativeEnabled) {
+ dependsOn(nativeTest)
+ }
+
val localAtomicfuJsIrRuntimeForTests: FileCollection = atomicfuJsIrRuntimeForTests
val localAtomicfuJsClasspath: FileCollection = atomicfuJsClasspath
val localAtomicfuJvmClasspath: FileCollection = atomicfuJvmClasspath
@@ -168,10 +199,11 @@ projectTest(jUnitMode = JUnitMode.JUnit5) {
publish()
standardPublicJars()
-val nativeBoxTest = nativeTest(
- taskName = "nativeBoxTest",
- tag = "atomicfu",
+val nativeTest = nativeTest(
+ taskName = "nativeTest",
+ tag = "atomicfu-native", // Include all tests with the "atomicfu-native" tag.
requirePlatformLibs = true,
- customDependencies = listOf(atomicfuJvmClasspath),
- customKlibDependencies = listOf(atomicfuNativeKlib)
+ customCompilerDependencies = listOf(atomicfuJvmClasspath),
+ customTestDependencies = listOf(atomicfuNativeKlib),
+ compilerPluginDependencies = listOf(atomicfuCompilerPluginForTests)
)
diff --git a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlin/konan/blackboxtest/AtomicfuNativeTestGenerated.java b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlin/konan/blackboxtest/AtomicfuNativeTestGenerated.java
new file mode 100644
index 00000000000..4b6b64e5bb9
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlin/konan/blackboxtest/AtomicfuNativeTestGenerated.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2010-2023 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.blackboxtest;
+
+import com.intellij.testFramework.TestDataPath;
+import org.jetbrains.kotlin.test.util.KtTestUtil;
+import org.junit.jupiter.api.Tag;
+import org.jetbrains.kotlin.konan.blackboxtest.support.group.UseStandardTestCaseGroupProvider;
+import org.jetbrains.kotlin.test.TestMetadata;
+import org.junit.jupiter.api.Nested;
+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("plugins/atomicfu/atomicfu-compiler/testData/nativeBox")
+@TestDataPath("$PROJECT_ROOT")
+@Tag("atomicfu-native")
+@UseStandardTestCaseGroupProvider()
+public class AtomicfuNativeTestGenerated extends AbstractNativeBlackBoxTest {
+ @Test
+ public void testAllFilesPresentInNativeBox() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ }
+
+ @Nested
+ @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions")
+ @TestDataPath("$PROJECT_ROOT")
+ @Tag("atomicfu-native")
+ @UseStandardTestCaseGroupProvider()
+ public class Atomic_extensions {
+ @Test
+ public void testAllFilesPresentInAtomic_extensions() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ }
+
+ @Test
+ @TestMetadata("ArrayInlineExtensionTest.kt")
+ public void testArrayInlineExtensionTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayInlineExtensionTest.kt");
+ }
+
+ @Test
+ @TestMetadata("ArrayLoopTest.kt")
+ public void testArrayLoopTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayLoopTest.kt");
+ }
+
+ @Test
+ @TestMetadata("ComplexLoopTest.kt")
+ public void testComplexLoopTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ComplexLoopTest.kt");
+ }
+
+ @Test
+ @TestMetadata("ExtensionLoopTest.kt")
+ public void testExtensionLoopTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionLoopTest.kt");
+ }
+
+ @Test
+ @TestMetadata("ExtensionsTest.kt")
+ public void testExtensionsTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionsTest.kt");
+ }
+
+ @Test
+ @TestMetadata("InlineExtensionWithTypeParameterTest.kt")
+ public void testInlineExtensionWithTypeParameterTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/InlineExtensionWithTypeParameterTest.kt");
+ }
+
+ @Test
+ @TestMetadata("LambdaTest.kt")
+ public void testLambdaTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LambdaTest.kt");
+ }
+
+ @Test
+ @TestMetadata("LockFreeIntBitsTest.kt")
+ public void testLockFreeIntBitsTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockFreeIntBitsTest.kt");
+ }
+
+ @Test
+ @TestMetadata("LockTest.kt")
+ public void testLockTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockTest.kt");
+ }
+
+ @Test
+ @TestMetadata("ParameterizedInlineFunExtensionTest.kt")
+ public void testParameterizedInlineFunExtensionTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ParameterizedInlineFunExtensionTest.kt");
+ }
+ }
+
+ @Nested
+ @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic")
+ @TestDataPath("$PROJECT_ROOT")
+ @Tag("atomicfu-native")
+ @UseStandardTestCaseGroupProvider()
+ public class Atomics_basic {
+ @Test
+ public void testAllFilesPresentInAtomics_basic() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ }
+
+ @Test
+ @TestMetadata("ArithmeticTest.kt")
+ public void testArithmeticTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ArithmeticTest.kt");
+ }
+
+ @Test
+ @TestMetadata("AtomicArrayTest.kt")
+ public void testAtomicArrayTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/AtomicArrayTest.kt");
+ }
+
+ @Test
+ @TestMetadata("IndexArrayElementGetterTest.kt")
+ public void testIndexArrayElementGetterTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/IndexArrayElementGetterTest.kt");
+ }
+
+ @Test
+ @TestMetadata("InitializationOrderTest.kt")
+ public void testInitializationOrderTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/InitializationOrderTest.kt");
+ }
+
+ @Test
+ @TestMetadata("LateinitPropertiesTest.kt")
+ public void testLateinitPropertiesTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LateinitPropertiesTest.kt");
+ }
+
+ @Test
+ @TestMetadata("LockFreeLongCounterTest.kt")
+ public void testLockFreeLongCounterTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeLongCounterTest.kt");
+ }
+
+ @Test
+ @TestMetadata("LockFreeQueueTest.kt")
+ public void testLockFreeQueueTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeQueueTest.kt");
+ }
+
+ @Test
+ @TestMetadata("LockFreeStackTest.kt")
+ public void testLockFreeStackTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeStackTest.kt");
+ }
+
+ @Test
+ @TestMetadata("LoopTest.kt")
+ public void testLoopTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LoopTest.kt");
+ }
+
+ @Test
+ @TestMetadata("MultiInitTest.kt")
+ public void testMultiInitTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/MultiInitTest.kt");
+ }
+
+ @Test
+ @TestMetadata("ScopeTest.kt")
+ public void testScopeTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ScopeTest.kt");
+ }
+
+ @Test
+ @TestMetadata("SimpleLockTest.kt")
+ public void testSimpleLockTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/SimpleLockTest.kt");
+ }
+
+ @Test
+ @TestMetadata("UncheckedCastTest.kt")
+ public void testUncheckedCastTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/UncheckedCastTest.kt");
+ }
+ }
+
+ @Nested
+ @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated")
+ @TestDataPath("$PROJECT_ROOT")
+ @Tag("atomicfu-native")
+ @UseStandardTestCaseGroupProvider()
+ public class Delegated {
+ @Test
+ public void testAllFilesPresentInDelegated() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ }
+
+ @Test
+ @TestMetadata("DelegatedPropertiesTest.kt")
+ public void testDelegatedPropertiesTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated/DelegatedPropertiesTest.kt");
+ }
+ }
+
+ @Nested
+ @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks")
+ @TestDataPath("$PROJECT_ROOT")
+ @Tag("atomicfu-native")
+ @UseStandardTestCaseGroupProvider()
+ public class Locks {
+ @Test
+ public void testAllFilesPresentInLocks() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ }
+
+ @Test
+ @TestMetadata("ReentrantLockTest.kt")
+ public void testReentrantLockTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/ReentrantLockTest.kt");
+ }
+
+ @Test
+ @TestMetadata("SynchronizedObjectTest.kt")
+ public void testSynchronizedObjectTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/SynchronizedObjectTest.kt");
+ }
+ }
+
+ @Nested
+ @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level")
+ @TestDataPath("$PROJECT_ROOT")
+ @Tag("atomicfu-native")
+ @UseStandardTestCaseGroupProvider()
+ public class Top_level {
+ @Test
+ public void testAllFilesPresentInTop_level() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ }
+
+ @Test
+ @TestMetadata("FieldInObjectTest.kt")
+ public void testFieldInObjectTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/FieldInObjectTest.kt");
+ }
+
+ @Test
+ @TestMetadata("TopLevelTest.kt")
+ public void testTopLevelTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/TopLevelTest.kt");
+ }
+ }
+
+ @Nested
+ @TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace")
+ @TestDataPath("$PROJECT_ROOT")
+ @Tag("atomicfu-native")
+ @UseStandardTestCaseGroupProvider()
+ public class Trace {
+ @Test
+ public void testAllFilesPresentInTrace() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ }
+
+ @Test
+ @TestMetadata("TraceTest.kt")
+ public void testTraceTest() throws Exception {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace/TraceTest.kt");
+ }
+ }
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayInlineExtensionTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayInlineExtensionTest.kt
new file mode 100644
index 00000000000..154381d28f4
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayInlineExtensionTest.kt
@@ -0,0 +1,228 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class AtomicIntArrayInlineExtensionTest {
+ private val intArr = AtomicIntArray(10)
+ private val a = atomic(0)
+
+ private inline fun casLoop(to: Int): Int {
+ intArr[0].loop { cur ->
+ if (intArr[0].compareAndSet(cur, to)) return intArr[0].value
+ return 777
+ }
+ }
+
+ private inline fun casLoopExpression(to: Int): Int = intArr[3].loop { cur ->
+ if (intArr[3].compareAndSet(cur, to)) return intArr[3].value
+ return 777
+ }
+
+ private inline fun AtomicInt.extensionLoop(to: Int): Int {
+ loop { cur ->
+ if (compareAndSet(cur, to)) return value
+ return 777
+ }
+ }
+
+ private inline fun AtomicInt.extensionLoopExpression(to: Int): Int = loop { cur ->
+ lazySet(cur + 10)
+ return if (compareAndSet(cur, to)) value else incrementAndGet()
+ }
+
+ private inline fun AtomicInt.extensionLoopMixedReceivers(first: Int, second: Int, index: Int): Int {
+ loop { cur ->
+ compareAndSet(cur, first)
+ intArr[index].compareAndSet(first, second)
+ return value
+ }
+ }
+
+ private inline fun AtomicInt.extensionLoopRecursive(to: Int): Int {
+ loop { cur ->
+ compareAndSet(cur, to)
+ a.extensionLoop(5)
+ return value
+ }
+ }
+
+ private inline fun AtomicInt.foo(to: Int): Int {
+ loop { cur ->
+ if (compareAndSet(cur, to)) return 777
+ else return value
+ }
+ }
+
+ private inline fun AtomicInt.bar(delta: Int): Int {
+ return foo(value + delta)
+ }
+
+ fun test() {
+ assertEquals(5, casLoop(5))
+ assertEquals(6, casLoopExpression(6))
+ assertEquals(66, intArr[1].extensionLoop(66))
+ assertEquals(66, intArr[2].extensionLoop(66))
+ assertEquals(77, intArr[1].extensionLoopExpression(777))
+ assertEquals(99, intArr[1].extensionLoopMixedReceivers(88, 99, 1))
+ assertEquals(100, intArr[1].extensionLoopRecursive(100))
+ assertEquals(777, intArr[1].bar(100))
+ }
+}
+
+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(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.extensionLoop(to: String): String? {
+ loop { cur ->
+ if (compareAndSet(cur, to)) return value
+ else "incorrect"
+ }
+ }
+
+ private inline fun AtomicRef.extensionLoopExpression(to: String): String? = loop { cur ->
+ lazySet("aaa")
+ return if (compareAndSet(cur, to)) value else "CAS_failed"
+ }
+
+ private inline fun AtomicRef.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))
+ }
+}
+
+@Test
+fun box() {
+ AtomicIntArrayInlineExtensionTest().test()
+ AtomicLongArrayInlineExtensionTest().test()
+ AtomicBooleanArrayInlineExtensionTest().test()
+ AtomicRefArrayInlineExtensionTest().test()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayLoopTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayLoopTest.kt
new file mode 100644
index 00000000000..d216fe3446f
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ArrayLoopTest.kt
@@ -0,0 +1,127 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class AtomicIntArrayAtomicfuInlineFunctionsTest {
+ private val intArr = AtomicIntArray(10)
+
+ fun testSetArrayElementValueInLoop() {
+ intArr[0].loop { cur ->
+ assertTrue(intArr[0].compareAndSet(cur, 555))
+ assertEquals(555, intArr[0].value)
+ return
+ }
+ }
+
+ private fun action(cur: Int): Int = cur * 1000
+
+ fun testArrayElementUpdate() {
+ intArr[0].lazySet(5)
+ intArr[0].update { cur -> action(cur) }
+ assertEquals(intArr[0].value, 5000)
+ }
+
+ fun testArrayElementGetAndUpdate() {
+ intArr[0].lazySet(5)
+ assertEquals(intArr[0].getAndUpdate{ cur -> action(cur) }, 5)
+ assertEquals(intArr[0].value, 5000)
+ }
+
+ fun testArrayElementUpdateAndGet() {
+ intArr[0].lazySet(5)
+ assertEquals(intArr[0].updateAndGet{ cur -> action(cur) }, 5000)
+ }
+
+ fun test() {
+ testSetArrayElementValueInLoop()
+ testArrayElementUpdate()
+ testArrayElementGetAndUpdate()
+ testArrayElementUpdateAndGet()
+ }
+}
+
+class AtomicBooleanArrayAtomicfuInlineFunctionsTest {
+ private val booleanArr = AtomicBooleanArray(10)
+
+ fun testSetArrayElementValueInLoop() {
+ booleanArr[0].loop { cur ->
+ assertTrue(booleanArr[0].compareAndSet(cur, true))
+ assertEquals(true, booleanArr[0].value)
+ return
+ }
+ }
+
+ private fun action(cur: Boolean) = !cur
+
+ fun testArrayElementUpdate() {
+ booleanArr[0].lazySet(true)
+ booleanArr[0].update{ cur -> action(cur) }
+ assertEquals(booleanArr[0].value, false)
+ }
+
+ fun testArrayElementGetAndUpdate() {
+ booleanArr[0].lazySet(true)
+ assertEquals(booleanArr[0].getAndUpdate{ cur -> action(cur) }, true)
+ assertEquals(booleanArr[0].value, false)
+ }
+
+ fun testArrayElementUpdateAndGet() {
+ booleanArr[0].lazySet(true)
+ assertEquals(booleanArr[0].updateAndGet{ cur -> action(cur) }, false)
+ }
+
+ fun test() {
+ testSetArrayElementValueInLoop()
+ testArrayElementUpdate()
+ testArrayElementGetAndUpdate()
+ testArrayElementUpdateAndGet()
+ }
+}
+
+class AtomicArrayAtomicfuInlineFunctionsTest {
+ private val anyArr = atomicArrayOfNulls(5)
+ private val refArr = atomicArrayOfNulls(5)
+
+ private data class Box(val n: Int)
+
+ fun testSetArrayElementValueInLoop() {
+ anyArr[0].loop { cur ->
+ assertTrue(anyArr[0].compareAndSet(cur, IntArray(5)))
+ return
+ }
+ }
+
+ private fun action(cur: Box?) = cur?.let { Box(cur.n * 10) }
+
+ fun testArrayElementUpdate() {
+ refArr[0].lazySet(Box(5))
+ refArr[0].update { cur -> cur?.let { Box(cur.n * 10) } }
+ assertEquals(refArr[0].value!!.n, 50)
+ }
+
+ fun testArrayElementGetAndUpdate() {
+ refArr[0].lazySet(Box(5))
+ assertEquals(refArr[0].getAndUpdate { cur -> action(cur) }!!.n, 5)
+ assertEquals(refArr[0].value!!.n, 50)
+ }
+
+ fun testArrayElementUpdateAndGet() {
+ refArr[0].lazySet(Box(5))
+ assertEquals(refArr[0].updateAndGet { cur -> action(cur) }!!.n, 50)
+ }
+
+ fun test() {
+ testSetArrayElementValueInLoop()
+ testArrayElementUpdate()
+ testArrayElementGetAndUpdate()
+ testArrayElementUpdateAndGet()
+ }
+}
+
+
+
+@Test
+fun box() {
+ AtomicIntArrayAtomicfuInlineFunctionsTest().test()
+ AtomicBooleanArrayAtomicfuInlineFunctionsTest().test()
+ AtomicArrayAtomicfuInlineFunctionsTest().test()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ComplexLoopTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ComplexLoopTest.kt
new file mode 100644
index 00000000000..4732ebc3982
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ComplexLoopTest.kt
@@ -0,0 +1,75 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+private val topLevelA = atomic(0)
+
+class ComplexLoopTest {
+ private val a = atomic(10)
+ private val long = atomic(6757L)
+ private val b = atomic(11)
+ private val c = atomic(12)
+ private val r = atomic("aaa")
+ private val intArr = AtomicIntArray(10)
+
+ private inline fun AtomicInt.fooInt() {
+ loop { cur ->
+ if (compareAndSet(cur, 67)) return
+ }
+ }
+
+ private inline fun AtomicLong.fooLong() {
+ loop { cur ->
+ if (compareAndSet(cur, 67L)) return
+ }
+ }
+
+ private inline fun embeddedLoops(to: Int): Int =
+ a.loop { aValue ->
+ if (!a.compareAndSet(aValue, to)) return 666
+ b.loop { bValue ->
+ return if (b.compareAndSet(bValue, to)) a.value + b.value else 777
+ }
+ }
+
+ private inline fun AtomicInt.extensionEmbeddedLoops(to: Int): Int =
+ loop { cur1 ->
+ compareAndSet(cur1, to)
+ loop { cur2 ->
+ return cur2
+ }
+ }
+
+ private inline fun embeddedUpdate(to: Int): Int =
+ a.loop { aValue ->
+ a.compareAndSet(aValue, to)
+ return a.updateAndGet { cur -> cur + 100 }
+ }
+
+ private inline fun AtomicRef.extesntionEmbeddedRefUpdate(to: String): String =
+ loop { value ->
+ compareAndSet(value, to)
+ return updateAndGet { cur -> "${cur}AAA" }
+ }
+
+ fun test() {
+ a.fooInt()
+ assertEquals(67, a.value)
+ b.fooInt()
+ assertEquals(67, b.value)
+ c.fooInt()
+ assertEquals(67, c.value)
+ long.fooLong()
+ assertEquals(67L, long.value)
+ assertEquals(24, embeddedLoops(12))
+ assertEquals(77, c.extensionEmbeddedLoops(77))
+ assertEquals(66, intArr[0].extensionEmbeddedLoops(66))
+ assertEquals(166, embeddedUpdate(66))
+ assertEquals("bbbAAA", r.extesntionEmbeddedRefUpdate("bbb"))
+ }
+}
+
+@Test
+fun testComplexLoopTest() {
+ val testClass = ComplexLoopTest()
+ testClass.test()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionLoopTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionLoopTest.kt
new file mode 100644
index 00000000000..d57018eecac
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionLoopTest.kt
@@ -0,0 +1,92 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class ExtensionLoopTest {
+ private val a = atomic(0)
+ private val b = atomic(true)
+ private val l = atomic(5000000000)
+ private val r = atomic(A("aaaa"))
+ private val rs = atomic("bbbb")
+
+ class A(val s: String)
+
+ private inline fun casLoop(to: Int): Int {
+ a.loop { cur ->
+ if (a.compareAndSet(cur, to)) return a.value
+ return 777
+ }
+ }
+
+ private inline fun casLoopExpression(to: Int): Int = a.loop { cur ->
+ if (a.compareAndSet(cur, to)) return a.value
+ return 777
+ }
+
+ private inline fun AtomicInt.extensionLoop(to: Int): Int {
+ loop { cur ->
+ if (compareAndSet(cur, to)) return value
+ return 777
+ }
+ }
+
+ private inline fun AtomicInt.extensionLoopExpression(to: Int): Int = loop { cur ->
+ lazySet(cur + 10)
+ return if (compareAndSet(cur, to)) value + 1 else incrementAndGet()
+ }
+
+ private inline fun AtomicInt.extensionLoopRecursive(to: Int): Int {
+ loop { cur ->
+ compareAndSet(cur, to)
+ extensionLoop(5)
+ return value
+ }
+ }
+
+ private inline fun AtomicInt.foo(to: Int): Int {
+ loop { cur ->
+ if (compareAndSet(cur, to)) return 777
+ else return value
+ }
+ }
+
+ private inline fun AtomicInt.bar(delta: Int): Int {
+ return foo(value + delta)
+ }
+
+ private inline fun AtomicInt.extensionEmbeddedLoops(to: Int): Int =
+ loop { cur1 ->
+ compareAndSet(value, to)
+ loop { cur2 ->
+ return cur2
+ }
+ }
+
+ fun testIntExtensionLoops() {
+ assertEquals(5, casLoop(5))
+ assertEquals(45, a.extensionEmbeddedLoops(45))
+ assertEquals(6, casLoopExpression(6))
+ assertEquals(17, a.extensionLoopExpression(777))
+ assertEquals(66, a.extensionLoop(66))
+ assertEquals(5, a.extensionLoopRecursive(100))
+ assertEquals(777, a.bar(100))
+ }
+}
+
+
+private val ref = atomic("aaa")
+
+private inline fun AtomicRef.topLevelExtensionLoop(to: String): String = loop { cur ->
+ lazySet(cur + to)
+ return value
+}
+
+fun testTopLevelExtensionLoop() {
+ assertEquals("aaattt", ref.topLevelExtensionLoop("ttt"))
+}
+
+@Test
+fun testExtensionLoop() {
+ val testClass = ExtensionLoopTest()
+ testClass.testIntExtensionLoops()
+ testTopLevelExtensionLoop()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionsTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionsTest.kt
new file mode 100644
index 00000000000..f7355303600
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ExtensionsTest.kt
@@ -0,0 +1,114 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class ExtensionsTest {
+ private val a = atomic(0)
+ private val l = atomic(0L)
+ private val s = atomic(null)
+ private val b = atomic(true)
+
+ fun testScopedFieldGetters() {
+ check(a.value == 0)
+ val update = 3
+ a.lazySet(update)
+ check(a.compareAndSet(update, 8))
+ a.lazySet(1)
+ check(a.value == 1)
+ check(a.getAndSet(2) == 1)
+ check(a.value == 2)
+ check(a.getAndIncrement() == 2)
+ check(a.value == 3)
+ check(a.getAndDecrement() == 3)
+ check(a.value == 2)
+ check(a.getAndAdd(2) == 2)
+ check(a.value == 4)
+ check(a.addAndGet(3) == 7)
+ check(a.value == 7)
+ check(a.incrementAndGet() == 8)
+ check(a.value == 8)
+ check(a.decrementAndGet() == 7)
+ check(a.value == 7)
+ check(a.compareAndSet(7, 10))
+ }
+
+ private inline fun AtomicInt.intExtensionArithmetic() {
+ value = 0
+ check(value == 0)
+ val update = 3
+ lazySet(update)
+ check(compareAndSet(update, 8))
+ lazySet(1)
+ check(value == 1)
+ check(getAndSet(2) == 1)
+ check(value == 2)
+ check(getAndIncrement() == 2)
+ check(value == 3)
+ check(getAndDecrement() == 3)
+ check(value == 2)
+ check(getAndAdd(2) == 2)
+ check(value == 4)
+ check(addAndGet(3) == 7)
+ check(value == 7)
+ check(incrementAndGet() == 8)
+ check(value == 8)
+ check(decrementAndGet() == 7)
+ check(value == 7)
+ check(compareAndSet(7, 10))
+ check(compareAndSet(value, 55))
+ check(value == 55)
+ }
+
+ private inline fun AtomicLong.longExtensionArithmetic() {
+ value = 2424920024888888848
+ check(value == 2424920024888888848)
+ lazySet(8424920024888888848)
+ check(value == 8424920024888888848)
+ check(getAndSet(8924920024888888848) == 8424920024888888848)
+ check(value == 8924920024888888848)
+ check(incrementAndGet() == 8924920024888888849) // fails
+ check(value == 8924920024888888849)
+ check(getAndDecrement() == 8924920024888888849)
+ check(value == 8924920024888888848)
+ check(getAndAdd(100000000000000000) == 8924920024888888848)
+ check(value == 9024920024888888848)
+ check(addAndGet(-9223372036854775807) == -198452011965886959)
+ check(value == -198452011965886959)
+ check(incrementAndGet() == -198452011965886958)
+ check(value == -198452011965886958)
+ check(decrementAndGet() == -198452011965886959)
+ check(value == -198452011965886959)
+ }
+
+ private inline fun AtomicRef.refExtension() {
+ value = "aaa"
+ check(value == "aaa")
+ lazySet("bb")
+ check(value == "bb")
+ check(getAndSet("ccc") == "bb")
+ check(value == "ccc")
+ }
+
+ private inline fun AtomicBoolean.booleanExtensionArithmetic() {
+ value = false
+ check(!value)
+ lazySet(true)
+ check(value)
+ check(getAndSet(true))
+ check(compareAndSet(value, false))
+ check(!value)
+ }
+
+ fun testExtension() {
+ a.intExtensionArithmetic()
+ l.longExtensionArithmetic()
+ s.refExtension()
+ b.booleanExtensionArithmetic()
+ }
+}
+
+@Test
+fun box() {
+ val testClass = ExtensionsTest()
+ testClass.testScopedFieldGetters()
+ testClass.testExtension()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/InlineExtensionWithTypeParameterTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/InlineExtensionWithTypeParameterTest.kt
new file mode 100644
index 00000000000..3f151af9fbf
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/InlineExtensionWithTypeParameterTest.kt
@@ -0,0 +1,33 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class InlineExtensionWithTypeParameterTest {
+ abstract class Segment>(val id: Int)
+ class SemaphoreSegment(id: Int) : Segment(id)
+
+ private inline fun > AtomicRef.foo(
+ id: Int,
+ startFrom: S
+ ): Int {
+ lazySet(startFrom)
+ return value.getSegmentId()
+ }
+
+ private inline fun > S.getSegmentId(): Int {
+ var cur: S = this
+ return cur.id
+ }
+
+ private val sref = atomic(SemaphoreSegment(0))
+
+ fun testInlineExtensionWithTypeParameter() {
+ val s = SemaphoreSegment(77)
+ assertEquals(77, sref.foo(0, s))
+ }
+}
+
+@Test
+fun box() {
+ val testClass = InlineExtensionWithTypeParameterTest()
+ testClass.testInlineExtensionWithTypeParameter()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LambdaTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LambdaTest.kt
new file mode 100644
index 00000000000..4bb558874d0
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LambdaTest.kt
@@ -0,0 +1,52 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class LambdaTest {
+ private val a = atomic(0)
+ private val rs = atomic("bbbb")
+
+ private inline fun inlineLambda(
+ arg: T,
+ crossinline block: (T) -> Unit
+ ) = block(arg)
+
+ fun loopInLambda1(to: Int) = inlineLambda(to) sc@ { arg ->
+ a.loop { value ->
+ a.compareAndSet(value, arg)
+ return@sc
+ }
+ }
+
+ fun loopInLambda2(to: Int) = inlineLambda(to) { arg1 ->
+ inlineLambda(arg1) sc@ { arg2 ->
+ a.loop { value ->
+ a.compareAndSet(value, arg2)
+ return@sc
+ }
+ }
+ }
+
+ fun loopInLambda2Ref(to: String) = inlineLambda(to) { arg1 ->
+ inlineLambda(arg1) sc@ { arg2 ->
+ rs.loop { value ->
+ rs.compareAndSet(value, arg2)
+ return@sc
+ }
+ }
+ }
+
+ fun test() {
+ loopInLambda1(34)
+ assertEquals(34, a.value)
+ loopInLambda1(77)
+ assertEquals(77, a.value)
+ loopInLambda2Ref("bbb")
+ assertEquals("bbb", rs.value)
+ }
+}
+
+@Test
+fun box() {
+ val testClass = LambdaTest()
+ testClass.test()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockFreeIntBitsTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockFreeIntBitsTest.kt
new file mode 100644
index 00000000000..7b7e7358d06
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockFreeIntBitsTest.kt
@@ -0,0 +1,57 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class LockFreeIntBitsTest {
+ fun testBasic() {
+ val bs = LockFreeIntBits()
+ assertTrue(!bs[0])
+ assertTrue(bs.bitSet(0))
+ assertTrue(bs[0])
+ assertTrue(!bs.bitSet(0))
+
+ assertTrue(!bs[1])
+ assertTrue(bs.bitSet(1))
+ assertTrue(bs[1])
+ assertTrue(!bs.bitSet(1))
+ assertTrue(!bs.bitSet(0))
+
+ assertTrue(bs[0])
+ assertTrue(bs.bitClear(0))
+ assertTrue(!bs.bitClear(0))
+
+ assertTrue(bs[1])
+ }
+}
+
+class LockFreeIntBits {
+ private val bits = atomic(0)
+
+ private fun Int.mask() = 1 shl this
+
+ operator fun get(index: Int): Boolean = bits.value and index.mask() != 0
+
+ // User-defined private inline function
+ private inline fun bitUpdate(check: (Int) -> Boolean, upd: (Int) -> Int): Boolean {
+ bits.update {
+ if (check(it)) return false
+ upd(it)
+ }
+ return true
+ }
+
+ fun bitSet(index: Int): Boolean {
+ val mask = index.mask()
+ return bitUpdate({ it and mask != 0 }, { it or mask })
+ }
+
+ fun bitClear(index: Int): Boolean {
+ val mask = index.mask()
+ return bitUpdate({ it and mask == 0 }, { it and mask.inv() })
+ }
+}
+
+@Test
+fun box() {
+ val testClass = LockFreeIntBitsTest()
+ testClass.testBasic()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockTest.kt
new file mode 100644
index 00000000000..f9c1b7b4877
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/LockTest.kt
@@ -0,0 +1,29 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class LockTest {
+ private val inProgressLock = atomic(false)
+
+ fun testLock() {
+ var result = ""
+ if (inProgressLock.tryAcquire()) {
+ result = "OK"
+ }
+ assertEquals("OK", result)
+ }
+}
+
+// This function will be removed by transformer
+@Suppress("NOTHING_TO_INLINE")
+private inline fun AtomicBoolean.tryAcquire(): Boolean = compareAndSet(false, true)
+
+// This function is here to test if the Kotlin metadata still consistent after transform
+// It is used in ReflectionTest, DO NOT REMOVE
+@Suppress("UNUSED_PARAMETER")
+fun String.reflectionTest(mapParam: Map): List = error("no impl")
+
+@Test
+fun box() {
+ val testClass = LockTest()
+ testClass.testLock()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ParameterizedInlineFunExtensionTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ParameterizedInlineFunExtensionTest.kt
new file mode 100644
index 00000000000..8841f87e644
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomic_extensions/ParameterizedInlineFunExtensionTest.kt
@@ -0,0 +1,28 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class ParameterizedInlineFunExtensionTest {
+
+ private inline fun AtomicRef.foo(res1: S, res2: S, foo: (S) -> S): S {
+ val res = bar(res1, res2)
+ return res
+ }
+
+ private inline fun AtomicRef.bar(res1: S, res2: S): S {
+ return res2
+ }
+
+ private val tail = atomic("aaa")
+
+ fun testClose() {
+ assertEquals("bbb", tail.bar("aaa", "bbb"))
+ val res = tail.foo("bbb", "ccc") { s -> s }
+ assertEquals("ccc", res)
+ }
+}
+
+@Test
+fun testParameterizedInlineFunExtensionTest() {
+ val testClass = ParameterizedInlineFunExtensionTest()
+ testClass.testClose()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ArithmeticTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ArithmeticTest.kt
new file mode 100644
index 00000000000..e2e6e9d1757
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ArithmeticTest.kt
@@ -0,0 +1,130 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class IntArithmetic {
+ private val _x = atomic(0)
+ val x get() = _x.value
+
+ private val local = atomic(0)
+
+ private fun testGetValue() {
+ _x.value = 5
+ assertEquals(5, _x.value)
+ var aValue = _x.value
+ assertEquals(5, aValue)
+ assertEquals(5, x)
+
+ local.value = 555
+ aValue = local.value
+ assertEquals(aValue, local.value)
+ }
+
+ private fun testAtomicCallPlaces() {
+ _x.value = 5
+ _x.compareAndSet(5, 42)
+ val res = _x.compareAndSet(42, 45)
+ assertTrue(res)
+ assertTrue(_x.compareAndSet(45, 77))
+ assertFalse(_x.compareAndSet(95, 77))
+ assertTrue(_x.compareAndSet(77, 88))
+ }
+
+ private fun testInt() {
+ _x.value = 0
+ assertEquals(0, x)
+ val update = 3
+ assertEquals(0, _x.getAndSet(update))
+ assertTrue(_x.compareAndSet(update, 8))
+ _x.lazySet(1)
+ assertEquals(1, x)
+ assertEquals(1, _x.getAndSet(2))
+ assertEquals(2, x)
+ assertEquals(2, _x.getAndIncrement())
+ assertEquals(3, x)
+ assertEquals(3, _x.getAndDecrement())
+ assertEquals(2, x)
+ assertEquals(2, _x.getAndAdd(2))
+ assertEquals(4, x)
+ assertEquals(7, _x.addAndGet(3))
+ assertEquals(7, x)
+ assertEquals(8, _x.incrementAndGet())
+ assertEquals(8, x)
+ assertEquals(7, _x.decrementAndGet())
+ assertEquals(7, x)
+ assertTrue(_x.compareAndSet(7, 10))
+ }
+
+ fun test() {
+ testGetValue()
+ testAtomicCallPlaces()
+ testInt()
+ }
+}
+
+class LongArithmetic {
+ private val _x = atomic(4294967296)
+ val x get() = _x.value
+ private val y = atomic(5000000000)
+ private val z = atomic(2424920024888888848)
+ private val max = atomic(9223372036854775807)
+
+ fun testLong() {
+ assertEquals(2424920024888888848, z.value)
+ z.lazySet(8424920024888888848)
+ assertEquals(8424920024888888848, z.value)
+ assertEquals(8424920024888888848, z.getAndSet(8924920024888888848))
+ assertEquals(8924920024888888848, z.value)
+ assertEquals(8924920024888888849, z.incrementAndGet())
+ assertEquals(8924920024888888849, z.value)
+ assertEquals(8924920024888888849, z.getAndDecrement())
+ assertEquals(8924920024888888848, z.value)
+ assertEquals(8924920024888888848, z.getAndAdd(100000000000000000))
+ assertEquals(9024920024888888848, z.value)
+ assertEquals(-198452011965886959, z.addAndGet(-9223372036854775807))
+ assertEquals(-198452011965886959, z.value)
+ assertEquals(-198452011965886958, z.incrementAndGet())
+ assertEquals(-198452011965886958, z.value)
+ assertEquals(-198452011965886959, z.decrementAndGet())
+ assertEquals(-198452011965886959, z.value)
+ }
+}
+
+class BooleanArithmetic {
+ private val _x = atomic(false)
+ val x get() = _x.value
+
+ fun testBoolean() {
+ assertEquals(false, _x.value)
+ assertFalse(x)
+ _x.lazySet(true)
+ assertTrue(x)
+ assertTrue(_x.getAndSet(true))
+ assertTrue(_x.compareAndSet(true, false))
+ assertFalse(x)
+ }
+}
+
+class ReferenceArithmetic {
+ private val _x = atomic(null)
+
+ fun testReference() {
+ _x.value = "aaa"
+ assertEquals("aaa", _x.value)
+ _x.lazySet("bb")
+ assertEquals("bb", _x.value)
+ assertEquals("bb", _x.getAndSet("ccc"))
+ assertEquals("ccc", _x.value)
+ }
+}
+
+@Test
+fun test() {
+ val intClass = IntArithmetic()
+ intClass.test()
+ val longClass = LongArithmetic()
+ longClass.testLong()
+ val booleanClass = BooleanArithmetic()
+ booleanClass.testBoolean()
+ val refClass = ReferenceArithmetic()
+ refClass.testReference()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/AtomicArrayTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/AtomicArrayTest.kt
new file mode 100644
index 00000000000..9feae853170
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/AtomicArrayTest.kt
@@ -0,0 +1,109 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class AtomicArrayTest {
+
+ fun testIntArray() {
+ val A = AtomicArrayClass()
+ assertTrue(A.intArr[0].compareAndSet(0, 3))
+ assertEquals(0, A.intArr[1].value)
+ A.intArr[0].lazySet(5)
+ assertEquals(5, A.intArr[0].value + A.intArr[1].value + A.intArr[2].value)
+ assertTrue(A.intArr[0].compareAndSet(5, 10))
+ assertEquals(10, A.intArr[0].getAndDecrement())
+ assertEquals(9, A.intArr[0].value)
+ A.intArr[2].value = 2
+ assertEquals(2, A.intArr[2].value)
+ assertTrue(A.intArr[2].compareAndSet(2, 34))
+ assertEquals(34, A.intArr[2].value)
+ }
+
+ fun testLongArray() {
+ val A = AtomicArrayClass()
+ A.longArr[0].value = 2424920024888888848
+ assertEquals(2424920024888888848, A.longArr[0].value)
+ A.longArr[0].lazySet(8424920024888888848)
+ assertEquals(8424920024888888848, A.longArr[0].value)
+ val ac = A.longArr[0].value
+ A.longArr[3].value = ac
+ assertEquals(8424920024888888848, A.longArr[3].getAndSet(8924920024888888848))
+ assertEquals(8924920024888888848, A.longArr[3].value)
+ val ac1 = A.longArr[3].value
+ A.longArr[4].value = ac1
+ assertEquals(8924920024888888849, A.longArr[4].incrementAndGet())
+ assertEquals(8924920024888888849, A.longArr[4].value)
+ assertEquals(8924920024888888849, A.longArr[4].getAndDecrement())
+ assertEquals(8924920024888888848, A.longArr[4].value)
+ A.longArr[4].value = 8924920024888888848
+ assertEquals(8924920024888888848, A.longArr[4].getAndAdd(100000000000000000))
+ val ac2 = A.longArr[4].value
+ A.longArr[1].value = ac2
+ assertEquals(9024920024888888848, A.longArr[1].value)
+ assertEquals(-198452011965886959, A.longArr[1].addAndGet(-9223372036854775807))
+ assertEquals(-198452011965886959, A.longArr[1].value)
+ assertEquals(-198452011965886958, A.longArr[1].incrementAndGet())
+ assertEquals(-198452011965886958, A.longArr[1].value)
+ assertEquals(-198452011965886959, A.longArr[1].decrementAndGet())
+ assertEquals(-198452011965886959, A.longArr[1].value)
+ }
+
+ fun testBooleanArray() {
+ val A = AtomicArrayClass()
+ assertFalse(A.booleanArr[1].value)
+ assertTrue(A.booleanArr[1].compareAndSet(false, true))
+ A.booleanArr[0].lazySet(true)
+ assertFalse(A.booleanArr[2].getAndSet(true))
+ assertTrue(A.booleanArr[0].value && A.booleanArr[1].value && A.booleanArr[2].value)
+ A.booleanArr[0].value = false
+ assertFalse(A.booleanArr[0].value)
+ }
+
+ fun testRefArray() {
+ val A = AtomicArrayClass()
+ val a2 = ARef(2)
+ val a3 = ARef(3)
+ A.refArr[0].value = a2
+ assertEquals(2, A.refArr[0].value!!.n)
+ assertTrue(A.refArr[0].compareAndSet(a2, a3))
+ assertEquals(3, A.refArr[0].value!!.n)
+ val r0 = A.refArr[0].value
+ A.refArr[3].value = r0
+ assertEquals(3, A.refArr[3].value!!.n)
+ val a = A.a.value
+ assertTrue(A.refArr[3].compareAndSet(a3, a))
+ }
+
+ fun testAnyArray() {
+ val A = AtomicArrayClass()
+ val s1 = "aaa"
+ val s2 = "bbb"
+ A.anyArr[0].value = s1
+ assertEquals("aaa", A.anyArr[0].value)
+ assertTrue(A.anyArr[0].compareAndSet(s1, s2))
+ assertEquals("bbb", A.anyArr[0].value)
+ val r0 = A.anyArr[0].value
+ A.anyArr[3].value = r0
+ assertEquals("bbb", A.anyArr[3].value)
+ }
+}
+
+private class AtomicArrayClass {
+ val intArr = AtomicIntArray(10)
+ val longArr = AtomicLongArray(10)
+ val booleanArr = AtomicBooleanArray(10)
+ val refArr = atomicArrayOfNulls(10)
+ val anyArr = atomicArrayOfNulls(10)
+ internal val a = atomic(ARef(8))
+}
+
+data class ARef(val n: Int)
+
+@Test
+fun test() {
+ val testClass = AtomicArrayTest()
+ testClass.testIntArray()
+ testClass.testLongArray()
+ testClass.testBooleanArray()
+ testClass.testRefArray()
+ testClass.testAnyArray()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/IndexArrayElementGetterTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/IndexArrayElementGetterTest.kt
new file mode 100644
index 00000000000..21391296ff4
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/IndexArrayElementGetterTest.kt
@@ -0,0 +1,32 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class IndexArrayElementGetterTest {
+ private val clazz = AtomicArrayClass()
+
+ fun fib(a: Int): Int = if (a == 0 || a == 1) a else fib(a - 1) + fib(a - 2)
+
+ fun testIndexArrayElementGetting() {
+ clazz.intArr[8].value = 3
+ val i = fib(4)
+ val j = fib(5)
+ assertEquals(3, clazz.intArr[i + j].value)
+ assertEquals(3, clazz.intArr[fib(4) + fib(5)].value)
+ clazz.longArr[3].value = 100
+ assertEquals(100, clazz.longArr[fib(6) - fib(5)].value)
+ assertEquals(100, clazz.longArr[(fib(6) + fib(4)) % 8].value)
+ assertEquals(100, clazz.longArr[(fib(6) + fib(4)) % 8].value)
+ assertEquals(100, clazz.longArr[(fib(4) + fib(5)) % fib(5)].value)
+ }
+
+ private class AtomicArrayClass {
+ val intArr = AtomicIntArray(10)
+ val longArr = AtomicLongArray(10)
+ }
+}
+
+@Test
+fun box() {
+ val testClass = IndexArrayElementGetterTest()
+ testClass.testIndexArrayElementGetting()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/InitializationOrderTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/InitializationOrderTest.kt
new file mode 100644
index 00000000000..3be4c4013de
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/InitializationOrderTest.kt
@@ -0,0 +1,33 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+private class AAA {
+ private val _counter = atomic(5L)
+ val counterValue: Long get() = _counter.value
+ val delegateCounterValue by _counter
+ val lateInitInt: AtomicInt
+ val intArr: AtomicIntArray
+
+ // test ensures that transformation does not change the order of initialization
+ init {
+ lateInitInt = atomic(10)
+ assertTrue(lateInitInt.compareAndSet(10, 100))
+ assertEquals(100, lateInitInt.value)
+ intArr = AtomicIntArray(10)
+ intArr[0].value = 10
+ assertTrue(intArr[0].compareAndSet(10, 100))
+ intArr[1].value = 20
+ }
+
+ init {
+ assertEquals(5L, _counter.value)
+ assertEquals(5L,counterValue)
+ assertEquals(5L, delegateCounterValue)
+ assertEquals(120, intArr[0].value + intArr[1].value)
+ }
+}
+
+@Test
+fun box() {
+ val intClass = AAA()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LateinitPropertiesTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LateinitPropertiesTest.kt
new file mode 100644
index 00000000000..1a56f806c46
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LateinitPropertiesTest.kt
@@ -0,0 +1,38 @@
+import kotlinx.atomicfu.*
+import kotlinx.atomicfu.locks.*
+import kotlin.test.*
+
+class LateinitPropertiesTest {
+ private val a: AtomicInt
+ private val head: AtomicRef
+ private val dataRef: AtomicRef
+ private val lateIntArr: AtomicIntArray
+ private val lateRefArr: AtomicArray
+
+ private class Data(val n: Int)
+
+ init {
+ a = atomic(0)
+ head = atomic("AAA")
+ lateIntArr = AtomicIntArray(55)
+ val data = Data(77)
+ dataRef = atomic(data)
+ val size = 10
+ lateRefArr = atomicArrayOfNulls(size)
+ }
+
+ fun test() {
+ assertEquals(0, a.value)
+ assertTrue(head.compareAndSet("AAA", "BBB"))
+ assertEquals("BBB", head.value)
+ assertEquals(0, lateIntArr[35].value)
+ assertEquals(77, dataRef.value.n)
+ assertEquals(null, lateRefArr[5].value)
+ }
+}
+
+@Test
+fun box() {
+ val testClass = LateinitPropertiesTest()
+ testClass.test()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeLongCounterTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeLongCounterTest.kt
new file mode 100644
index 00000000000..dbc5f86c008
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeLongCounterTest.kt
@@ -0,0 +1,61 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class LockFreeLongCounterTest {
+ private inline fun testWith(g: LockFreeLongCounter.() -> Long) {
+ val c = LockFreeLongCounter()
+ assertEquals(0L, c.g())
+ assertEquals(1L, c.increment())
+ assertEquals(1L, c.g())
+ assertEquals(2L, c.increment())
+ assertEquals(2L, c.g())
+ }
+
+ fun testBasic() = testWith { get() }
+
+ fun testGetInner() = testWith { getInner() }
+
+ fun testAdd2() {
+ val c = LockFreeLongCounter()
+ c.add2()
+ assertEquals(2L, c.get())
+ c.add2()
+ assertEquals(4L, c.get())
+ }
+
+ fun testSetM2() {
+ val c = LockFreeLongCounter()
+ c.setM2()
+ assertEquals(-2L, c.get())
+ }
+}
+
+class LockFreeLongCounter {
+ private val counter = atomic(0L)
+
+ fun get(): Long = counter.value
+
+ fun increment(): Long = counter.incrementAndGet()
+
+ fun add2() = counter.getAndAdd(2)
+
+ fun setM2() {
+ counter.value = -2L // LDC instruction here
+ }
+
+ fun getInner(): Long = Inner().getFromOuter()
+
+ // testing how an inner class can get access to it
+ private inner class Inner {
+ fun getFromOuter(): Long = counter.value
+ }
+}
+
+@Test
+fun box() {
+ val testClass = LockFreeLongCounterTest()
+ testClass.testBasic()
+ testClass.testAdd2()
+ testClass.testSetM2()
+ testClass.testGetInner()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeQueueTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeQueueTest.kt
new file mode 100644
index 00000000000..42151442090
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeQueueTest.kt
@@ -0,0 +1,55 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class LockFreeQueueTest {
+ fun testBasic() {
+ val q = LockFreeQueue()
+ assertEquals(-1, q.dequeue())
+ q.enqueue(42)
+ assertEquals(42, q.dequeue())
+ assertEquals(-1, q.dequeue())
+ q.enqueue(1)
+ q.enqueue(2)
+ assertEquals(1, q.dequeue())
+ assertEquals(2, q.dequeue())
+ assertEquals(-1, q.dequeue())
+ }
+}
+
+// MS-queue
+public class LockFreeQueue {
+ private val head = atomic(Node(0))
+ private val tail = atomic(head.value)
+
+ private class Node(val value: Int) {
+ val next = atomic(null)
+ }
+
+ public fun enqueue(value: Int) {
+ val node = Node(value)
+ tail.loop { curTail ->
+ val curNext = curTail.next.value
+ if (curNext != null) {
+ tail.compareAndSet(curTail, curNext)
+ return@loop
+ }
+ if (curTail.next.compareAndSet(null, node)) {
+ tail.compareAndSet(curTail, node)
+ return
+ }
+ }
+ }
+
+ public fun dequeue(): Int {
+ head.loop { curHead ->
+ val next = curHead.next.value ?: return -1
+ if (head.compareAndSet(curHead, next)) return next.value
+ }
+ }
+}
+
+@Test
+fun box() {
+ val testClass = LockFreeQueueTest()
+ testClass.testBasic()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeStackTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeStackTest.kt
new file mode 100644
index 00000000000..89512d3f15a
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LockFreeStackTest.kt
@@ -0,0 +1,70 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class LockFreeStackTest {
+ fun testClear() {
+ val s = LockFreeStack()
+ assertTrue(s.isEmpty())
+ s.pushLoop("A")
+ assertTrue(!s.isEmpty())
+ s.clear()
+ assertTrue(s.isEmpty())
+ }
+
+ fun testPushPopLoop() {
+ val s = LockFreeStack()
+ assertTrue(s.isEmpty())
+ s.pushLoop("A")
+ assertTrue(!s.isEmpty())
+ assertEquals("A", s.popLoop())
+ assertTrue(s.isEmpty())
+ }
+
+ fun testPushPopUpdate() {
+ val s = LockFreeStack()
+ assertTrue(s.isEmpty())
+ s.pushUpdate("A")
+ assertTrue(!s.isEmpty())
+ assertEquals("A", s.popUpdate())
+ assertTrue(s.isEmpty())
+ }
+}
+
+class LockFreeStack {
+ private val top = atomic?>(null)
+
+ private class Node(val value: T, val next: Node?)
+
+ fun isEmpty() = top.value == null
+
+ fun clear() { top.value = null }
+
+ fun pushLoop(value: T) {
+ top.loop { cur ->
+ val upd = Node(value, cur)
+ if (top.compareAndSet(cur, upd)) return
+ }
+ }
+
+ fun popLoop(): T? {
+ top.loop { cur ->
+ if (cur == null) return null
+ if (top.compareAndSet(cur, cur.next)) return cur.value
+ }
+ }
+
+ fun pushUpdate(value: T) {
+ top.update { cur -> Node(value, cur) }
+ }
+
+ fun popUpdate(): T? =
+ top.getAndUpdate { cur -> cur?.next } ?.value
+}
+
+@Test
+fun box() {
+ val testClass = LockFreeStackTest()
+ testClass.testClear()
+ testClass.testPushPopLoop()
+ testClass.testPushPopUpdate()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LoopTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LoopTest.kt
new file mode 100644
index 00000000000..a614935cefb
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/LoopTest.kt
@@ -0,0 +1,128 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class LoopTest {
+ private val a = atomic(0)
+ private val a1 = atomic(1)
+ private val b = atomic(true)
+ private val l = atomic(5000000000L)
+ private val r = atomic(A("aaaa"))
+ private val rs = atomic("bbbb")
+
+ class A(val s: String)
+
+ fun atomicfuIntLoopTest() {
+ a.loop { value ->
+ if (a.compareAndSet(value, 777)) {
+ assertEquals(777, a.value)
+ return
+ }
+ }
+ }
+
+ fun atomicfuBooleanLoopTest() {
+ b.loop { value ->
+ assertTrue(value)
+ if (!b.value) return
+ if (b.compareAndSet(value, false)) {
+ return
+ }
+ }
+ }
+
+ fun atomicfuLongLoopTest() {
+ l.loop { cur ->
+ if (l.compareAndSet(5000000003, 9000000000)) {
+ return
+ } else {
+ l.incrementAndGet()
+ }
+ }
+ }
+
+ fun atomicfuRefLoopTest() {
+ r.loop { cur ->
+ assertEquals("aaaa", cur.s)
+ if (r.compareAndSet(cur, A("bbbb"))) {
+ return
+ }
+ }
+ }
+
+ fun atomicfuLoopTest() {
+ atomicfuIntLoopTest()
+ assertEquals(777, a.value)
+ atomicfuBooleanLoopTest()
+ assertFalse(b.value)
+ atomicfuLongLoopTest()
+ assertEquals(9000000000, l.value)
+ atomicfuRefLoopTest()
+ assertEquals("bbbb", r.value.s)
+ }
+
+ fun atomicfuUpdateTest() {
+ a.value = 0
+ a.update { value ->
+ val newValue = value + 1000
+ if (newValue >= 0) Int.MAX_VALUE else newValue
+ }
+ assertEquals(Int.MAX_VALUE, a.value)
+ b.update { true }
+ assertEquals(true, b.value)
+ assertTrue(b.value)
+ l.value = 0L
+ l.update { cur ->
+ val newValue = cur + 1000
+ if (newValue >= 0L) Long.MAX_VALUE else newValue
+ }
+ assertEquals(Long.MAX_VALUE, l.value)
+ r.lazySet(A("aaaa"))
+ r.update { cur ->
+ A("cccc${cur.s}")
+ }
+ assertEquals("ccccaaaa", r.value.s)
+ }
+
+ fun atomicfuUpdateAndGetTest() {
+ val res1 = a.updateAndGet { value ->
+ if (value >= 0) Int.MAX_VALUE else value
+ }
+ assertEquals(Int.MAX_VALUE, res1)
+ assertEquals(true, b.updateAndGet { true })
+ assertEquals(Long.MAX_VALUE, l.updateAndGet { cur ->
+ if (cur >= 0L) Long.MAX_VALUE else cur
+ })
+ r.lazySet(A("aaaa"))
+ val res3 = r.updateAndGet { cur ->
+ A("cccc${cur.s}")
+ }
+ assertEquals("ccccaaaa", res3.s)
+ }
+
+ fun atomicfuGetAndUpdateTest() {
+ a.getAndUpdate { value ->
+ if (value >= 0) Int.MAX_VALUE else value
+ }
+ assertEquals(Int.MAX_VALUE, a.value)
+ b.getAndUpdate { true }
+ assertTrue(b.value)
+ l.getAndUpdate { cur ->
+ if (cur >= 0L) Long.MAX_VALUE else cur
+ }
+ assertEquals(Long.MAX_VALUE, l.value)
+ r.lazySet(A("aaaa"))
+ r.getAndUpdate { cur ->
+ A("cccc${cur.s}")
+ }
+ assertEquals("ccccaaaa", r.value.s)
+ }
+}
+
+@Test
+fun box() {
+ val testClass = LoopTest()
+ testClass.atomicfuLoopTest()
+ testClass.atomicfuUpdateTest()
+ testClass.atomicfuUpdateAndGetTest()
+ testClass.atomicfuGetAndUpdateTest()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/MultiInitTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/MultiInitTest.kt
new file mode 100644
index 00000000000..d2e808b861e
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/MultiInitTest.kt
@@ -0,0 +1,30 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class MultiInitTest {
+ fun testBasic() {
+ val t = MultiInit()
+ check(t.incA() == 1)
+ check(t.incA() == 2)
+ check(t.incB() == 1)
+ check(t.incB() == 2)
+ }
+}
+
+class MultiInit {
+ private val a = atomic(0)
+ private val b = atomic(0)
+
+ fun incA() = a.incrementAndGet()
+ fun incB() = b.incrementAndGet()
+
+ companion object {
+ fun foo() {} // just to force some clinit in outer file
+ }
+}
+
+@Test
+fun box() {
+ val testClass = MultiInitTest()
+ testClass.testBasic()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ScopeTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ScopeTest.kt
new file mode 100644
index 00000000000..24407586f64
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/ScopeTest.kt
@@ -0,0 +1,45 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class AA(val value: Int) {
+ val b = B(value + 1)
+ val c = C(D(E(value + 1)))
+
+ fun updateToB(affected: Any): Boolean {
+ (affected as AtomicState).state.compareAndSet(this, b)
+ return (affected.state.value is B && (affected.state.value as B).value == value + 1)
+ }
+
+ fun manyProperties(affected: Any): Boolean {
+ (affected as AtomicState).state.compareAndSet(this, c.d.e)
+ return (affected.state.value is E && (affected.state.value as E).x == value + 1)
+ }
+}
+
+class B (val value: Int)
+
+class C (val d: D)
+class D (val e: E)
+class E (val x: Int)
+
+
+private class AtomicState(value: Any) {
+ val state = atomic(value)
+}
+
+class ScopeTest {
+ fun scopeTest() {
+ val a = AA(0)
+ val affected: Any = AtomicState(a)
+ check(a.updateToB(affected))
+ val a1 = AA(0)
+ val affected1: Any = AtomicState(a1)
+ check(a1.manyProperties(affected1))
+ }
+}
+
+@Test
+fun box() {
+ val testClass = ScopeTest()
+ testClass.scopeTest()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/SimpleLockTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/SimpleLockTest.kt
new file mode 100644
index 00000000000..d1b51b031df
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/SimpleLockTest.kt
@@ -0,0 +1,36 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class SimpleLockTest {
+ fun withLock() {
+ val lock = SimpleLock()
+ val result = lock.withLock {
+ "OK"
+ }
+ assertEquals("OK", result)
+ }
+}
+
+class SimpleLock {
+ private val _locked = atomic(0)
+
+ fun withLock(block: () -> T): T {
+ // this contrieves construct triggers Kotlin compiler to reuse local variable slot #2 for
+ // the exception in `finally` clause
+ try {
+ _locked.loop { locked ->
+ check(locked == 0)
+ if (!_locked.compareAndSet(0, 1)) return@loop // continue
+ return block()
+ }
+ } finally {
+ _locked.value = 0
+ }
+ }
+}
+
+@Test
+fun box() {
+ val testClass = SimpleLockTest()
+ testClass.withLock()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/UncheckedCastTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/UncheckedCastTest.kt
new file mode 100644
index 00000000000..637b9719951
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/atomics_basic/UncheckedCastTest.kt
@@ -0,0 +1,54 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+private val topLevelS = atomic(arrayOf("A", "B"))
+
+class UncheckedCastTest {
+ private val s = atomic("AAA")
+ private val bs = atomic(null)
+
+ @Suppress("UNCHECKED_CAST")
+ fun testAtomicValUncheckedCast() {
+ assertEquals((s as AtomicRef).value, "AAA")
+ bs.lazySet(arrayOf(arrayOf(Box(1), Box(2))))
+ assertEquals((bs as AtomicRef>>).value[0]!![0].b * 10, 10)
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ fun testTopLevelValUnchekedCast() {
+ assertEquals((topLevelS as AtomicRef>).value[1], "B")
+ }
+
+ private data class Box(val b: Int)
+
+ @Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
+ private inline fun AtomicRef.getString(): String =
+ (this as AtomicRef).value
+
+ fun testInlineFunc() {
+ assertEquals("AAA", s.getString())
+ }
+
+ private val a = atomicArrayOfNulls(10)
+
+ fun testArrayValueUncheckedCast() {
+ a[0].value = "OK"
+ @Suppress("UNCHECKED_CAST")
+ assertEquals("OK", (a[0] as AtomicRef).value)
+ }
+
+ fun testArrayValueUncheckedCastInlineFunc() {
+ a[0].value = "OK"
+ assertEquals("OK", a[0].getString())
+ }
+}
+
+@Test
+fun box() {
+ val testClass = UncheckedCastTest()
+ testClass.testAtomicValUncheckedCast()
+ testClass.testTopLevelValUnchekedCast()
+ testClass.testArrayValueUncheckedCast()
+ testClass.testArrayValueUncheckedCastInlineFunc()
+ testClass.testInlineFunc()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated/DelegatedPropertiesTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated/DelegatedPropertiesTest.kt
new file mode 100644
index 00000000000..67d847b53b8
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/delegated/DelegatedPropertiesTest.kt
@@ -0,0 +1,150 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+private val _topLevelInt = atomic(42)
+var topLevelInt: Int by _topLevelInt
+
+private var topLevelVolatile by atomic(56)
+
+class DelegatedProperties {
+ // Delegated properties should be declared in the same scope as the original atomic values
+ private val _a = atomic(42)
+ var a: Int by _a
+ private var privateA: Int by _a
+
+ private val _l = atomic(55555555555)
+ private var l: Long by _l
+
+ private val _b = atomic(false)
+ private var b: Boolean by _b
+
+ private val _ref = atomic(A(B(77)))
+ private var ref: A by _ref
+
+ private var vInt by atomic(77)
+
+ private var vLong by atomic(777777777)
+
+ private var vBoolean by atomic(false)
+
+ private var vRef by atomic(A(B(77)))
+
+ class A (val b: B)
+ class B (val n: Int)
+
+ fun testDelegatedAtomicInt() {
+ assertEquals(42, a)
+ assertEquals(42, privateA)
+ _a.compareAndSet(42, 56)
+ assertEquals(56, a)
+ assertEquals(56, privateA)
+ a = 77
+ _a.compareAndSet(77, 66)
+ privateA = 88
+ _a.compareAndSet(88, 66)
+ assertEquals(66, _a.value)
+ assertEquals(66, a)
+ assertEquals(66, privateA)
+
+ val aValue = a + privateA
+ assertEquals(132, aValue)
+ }
+
+ fun testDelegatedAtomicLong() {
+ assertEquals(55555555555, l)
+ _l.getAndIncrement()
+ assertEquals(55555555556, l)
+ l = 7777777777777
+ assertTrue(_l.compareAndSet(7777777777777, 66666666666))
+ assertEquals(66666666666, _l.value)
+ assertEquals(66666666666, l)
+ }
+
+ fun testDelegatedAtomicBoolean() {
+ assertEquals(false, b)
+ _b.lazySet(true)
+ assertEquals(true, b)
+ b = false
+ assertTrue(_b.compareAndSet(false, true))
+ assertEquals(true, _b.value)
+ assertEquals(true, b)
+ }
+
+ fun testDelegatedAtomicRef() {
+ assertEquals(77, ref.b.n)
+ _ref.lazySet(A(B(66)))
+ assertEquals(66, ref.b.n)
+ assertTrue(_ref.compareAndSet(_ref.value, A(B(56))))
+ assertEquals(56, ref.b.n)
+ ref = A(B(99))
+ assertEquals(99, _ref.value.b.n)
+ }
+
+ fun testVolatileInt() {
+ assertEquals(77, vInt)
+ vInt = 55
+ assertEquals(110, vInt * 2)
+ }
+
+ fun testVolatileLong() {
+ assertEquals(777777777, vLong)
+ vLong = 55
+ assertEquals(55, vLong)
+ }
+
+ fun testVolatileBoolean() {
+ assertEquals(false, vBoolean)
+ vBoolean = true
+ assertEquals(true, vBoolean)
+ }
+
+ fun testVolatileRef() {
+ assertEquals(77, vRef.b.n)
+ vRef = A(B(99))
+ assertEquals(99, vRef.b.n)
+ }
+
+ fun testDelegatedVariablesFlow() {
+ _a.lazySet(55)
+ assertEquals(55, _a.value)
+ assertEquals(55, a)
+ var aValue = a
+ assertEquals(55, aValue)
+ }
+
+ fun test() {
+ testDelegatedAtomicInt()
+ testDelegatedAtomicLong()
+ testDelegatedAtomicBoolean()
+ testDelegatedAtomicRef()
+ testVolatileInt()
+ testVolatileBoolean()
+ testVolatileLong()
+ testVolatileRef()
+ testDelegatedVariablesFlow()
+ }
+}
+
+fun testTopLevelDelegatedProperties() {
+ assertEquals(42, topLevelInt)
+ _topLevelInt.compareAndSet(42, 56)
+ assertEquals(56, topLevelInt)
+ topLevelInt = 77
+ _topLevelInt.compareAndSet(77, 66)
+ assertEquals(66, _topLevelInt.value)
+ assertEquals(66, topLevelInt)
+}
+
+fun testTopLevelVolatileProperties() {
+ assertEquals(56, topLevelVolatile)
+ topLevelVolatile = 55
+ assertEquals(110, topLevelVolatile * 2)
+}
+
+@Test
+fun box() {
+ val testClass = DelegatedProperties()
+ testClass.test()
+ testTopLevelDelegatedProperties()
+ testTopLevelVolatileProperties()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/ReentrantLockTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/ReentrantLockTest.kt
new file mode 100644
index 00000000000..1f070d8191a
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/ReentrantLockTest.kt
@@ -0,0 +1,22 @@
+import kotlinx.atomicfu.locks.*
+import kotlin.test.*
+
+class ReentrantLockFieldTest {
+ private val lock = reentrantLock()
+ private var state = 0
+
+ fun testLock() {
+ lock.withLock {
+ state = 1
+ }
+ assertEquals(1, state)
+ assertTrue(lock.tryLock())
+ lock.unlock()
+ }
+}
+
+@Test
+fun box() {
+ val testClass = ReentrantLockFieldTest()
+ testClass.testLock()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/SynchronizedObjectTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/SynchronizedObjectTest.kt
new file mode 100644
index 00000000000..87df2af2463
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/locks/SynchronizedObjectTest.kt
@@ -0,0 +1,21 @@
+import kotlinx.atomicfu.locks.*
+import kotlin.test.*
+
+class SynchronizedObjectTest : SynchronizedObject() {
+
+ fun testSync() {
+ val result = synchronized(this) { bar() }
+ assertEquals("OK", result)
+ }
+
+ private fun bar(): String =
+ synchronized(this) {
+ "OK"
+ }
+}
+
+@Test
+fun box() {
+ val testClass = SynchronizedObjectTest()
+ testClass.testSync()
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/FieldInObjectTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/FieldInObjectTest.kt
new file mode 100644
index 00000000000..2e6a11a3451
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/FieldInObjectTest.kt
@@ -0,0 +1,67 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+import kotlin.random.*
+
+private object Provider {
+ private val port = atomic(Random.nextInt(20, 90) * 100)
+ fun next(): Int = port.incrementAndGet()
+
+ private val _l = atomic(2424920024888888848)
+ fun getL() = _l.incrementAndGet()
+
+ val _ref = atomic(null)
+
+ val _x = atomic(false)
+
+ val intArr = AtomicIntArray(10)
+ val longArr = AtomicLongArray(10)
+ val refArr = atomicArrayOfNulls(5)
+}
+
+private object DelegatedProvider {
+ internal val _a = atomic(42)
+ var a: Int by _a
+
+ var vInt by atomic(77)
+}
+
+private fun testFieldInObject() {
+ val port = Provider.next()
+ assertEquals(port + 1, Provider.next())
+
+ assertEquals(2424920024888888849, Provider.getL())
+
+ Provider._ref.compareAndSet(null, "abc")
+ assertEquals("abc", Provider._ref.value)
+
+ assertFalse(Provider._x.value)
+
+ Provider.intArr[8].value = 454
+ assertEquals(455, Provider.intArr[8].incrementAndGet())
+
+ Provider.longArr[8].value = 4544096409680468
+ assertEquals(4544096409680470, Provider.longArr[8].addAndGet(2))
+
+ Provider.refArr[1].value = Provider._ref.value
+ assertEquals("abc", Provider.refArr[1].value)
+}
+
+private fun testDelegatedPropertiesInObject() {
+ assertEquals(42, DelegatedProvider.a)
+ DelegatedProvider._a.compareAndSet(42, 56)
+ assertEquals(56, DelegatedProvider.a)
+ DelegatedProvider.a = 77
+ DelegatedProvider._a.compareAndSet(77, 66)
+ assertEquals(66, DelegatedProvider._a.value)
+ assertEquals(66, DelegatedProvider.a)
+
+ assertEquals(77, DelegatedProvider.vInt)
+ DelegatedProvider.vInt = 55
+ assertEquals(110, DelegatedProvider.vInt * 2)
+}
+
+@Test
+fun box() {
+ testFieldInObject()
+ testDelegatedPropertiesInObject()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/TopLevelTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/TopLevelTest.kt
new file mode 100644
index 00000000000..e823cc6a7d2
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/top-level/TopLevelTest.kt
@@ -0,0 +1,182 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+private val a = atomic(0)
+private val b = atomic(2424920024888888848)
+private val c = atomic(true)
+private val abcNode = atomic(ANode(BNode(CNode(8))))
+private val any = atomic(null)
+
+internal val a_internal = atomic(0)
+internal val b_internal = atomic(2424920024888888848)
+internal val c_internal = atomic(true)
+internal val abcNode_internal = atomic(ANode(BNode(CNode(8))))
+internal val any_internal = atomic(null)
+
+private val intArr = AtomicIntArray(3)
+private val longArr = AtomicLongArray(5)
+private val booleanArr = AtomicBooleanArray(4)
+private val refArr = atomicArrayOfNulls>>(5)
+private val anyRefArr = atomicArrayOfNulls(10)
+
+private val stringAtomicNullArr = atomicArrayOfNulls(10)
+
+class TopLevelPrimitiveTest {
+
+ fun testTopLevelInt() {
+ assertEquals(0, a.value)
+ assertEquals(0, a.getAndSet(3))
+ assertTrue(a.compareAndSet(3, 8))
+ a.lazySet(1)
+ assertEquals(1, a.value)
+ assertEquals(1, a.getAndSet(2))
+ assertEquals(2, a.value)
+ assertEquals(2, a.getAndIncrement())
+ assertEquals(3, a.value)
+ assertEquals(3, a.getAndDecrement())
+ assertEquals(2, a.value)
+ assertEquals(2, a.getAndAdd(2))
+ assertEquals(4, a.value)
+ assertEquals(7, a.addAndGet(3))
+ assertEquals(7, a.value)
+ assertEquals(8, a.incrementAndGet())
+ assertEquals(8, a.value)
+ assertEquals(7, a.decrementAndGet())
+ assertEquals(7, a.value)
+ assertTrue(a.compareAndSet(7, 10))
+ }
+
+ fun testTopLevelLong() {
+ assertEquals(2424920024888888848, b.value)
+ b.lazySet(8424920024888888848)
+ assertEquals(8424920024888888848, b.value)
+ assertEquals(8424920024888888848, b.getAndSet(8924920024888888848))
+ assertEquals(8924920024888888848, b.value)
+ assertEquals(8924920024888888849, b.incrementAndGet())
+ assertEquals(8924920024888888849, b.value)
+ assertEquals(8924920024888888849, b.getAndDecrement())
+ assertEquals(8924920024888888848, b.value)
+ assertEquals(8924920024888888848, b.getAndAdd(100000000000000000))
+ assertEquals(9024920024888888848, b.value)
+ assertEquals(-198452011965886959, b.addAndGet(-9223372036854775807))
+ assertEquals(-198452011965886959, b.value)
+ assertEquals(-198452011965886958, b.incrementAndGet())
+ assertEquals(-198452011965886958, b.value)
+ assertEquals(-198452011965886959, b.decrementAndGet())
+ assertEquals(-198452011965886959, b.value)
+ }
+
+ fun testTopLevelBoolean() {
+ assertTrue(c.value)
+ c.lazySet(false)
+ assertFalse(c.value)
+ assertTrue(!c.getAndSet(true))
+ assertTrue(c.compareAndSet(true, false))
+ assertFalse(c.value)
+ }
+
+ fun testTopLevelRef() {
+ assertEquals(8, abcNode.value.b.c.d)
+ val newNode = ANode(BNode(CNode(76)))
+ assertEquals(8, abcNode.getAndSet(newNode).b.c.d)
+ assertEquals(76, abcNode.value.b.c.d)
+ val l = IntArray(4){i -> i}
+ any.lazySet(l)
+ assertEquals(2, (any.value as IntArray)[2])
+ }
+
+ fun testTopLevelArrayOfNulls() {
+ assertEquals(null, stringAtomicNullArr[0].value)
+ assertTrue(stringAtomicNullArr[0].compareAndSet(null, "aa"))
+ stringAtomicNullArr[1].lazySet("aa")
+ assertTrue(stringAtomicNullArr[0].value == stringAtomicNullArr[1].value)
+ }
+}
+
+class TopLevelArrayTest {
+
+ fun testIntArray() {
+ assertTrue(intArr[0].compareAndSet(0, 3))
+ assertEquals(0, intArr[1].value)
+ intArr[0].lazySet(5)
+ assertEquals(5, intArr[0].value + intArr[1].value + intArr[2].value)
+ assertTrue(intArr[0].compareAndSet(5, 10))
+ assertEquals(10, intArr[0].getAndDecrement())
+ assertEquals(9, intArr[0].value)
+ intArr[2].value = 2
+ assertEquals(2, intArr[2].value)
+ assertTrue(intArr[2].compareAndSet(2, 34))
+ assertEquals(34, intArr[2].value)
+ }
+
+ fun testLongArray() {
+ longArr[0].value = 2424920024888888848
+ assertEquals(2424920024888888848, longArr[0].value)
+ longArr[0].lazySet(8424920024888888848)
+ assertEquals(8424920024888888848, longArr[0].value)
+ val ac = longArr[0].value
+ longArr[3].value = ac
+ assertEquals(8424920024888888848, longArr[3].getAndSet(8924920024888888848))
+ assertEquals(8924920024888888848, longArr[3].value)
+ val ac1 = longArr[3].value
+ longArr[4].value = ac1
+ assertEquals(8924920024888888849, longArr[4].incrementAndGet())
+ assertEquals(8924920024888888849, longArr[4].value)
+ assertEquals(8924920024888888849, longArr[4].getAndDecrement())
+ assertEquals(8924920024888888848, longArr[4].value)
+ longArr[4].value = 8924920024888888848
+ assertEquals(8924920024888888848, longArr[4].getAndAdd(100000000000000000))
+ val ac2 = longArr[4].value
+ longArr[1].value = ac2
+ assertEquals(9024920024888888848, longArr[1].value)
+ assertEquals(-198452011965886959, longArr[1].addAndGet(-9223372036854775807))
+ assertEquals(-198452011965886959, longArr[1].value)
+ assertEquals(-198452011965886958, longArr[1].incrementAndGet())
+ assertEquals(-198452011965886958, longArr[1].value)
+ assertEquals(-198452011965886959, longArr[1].decrementAndGet())
+ assertEquals(-198452011965886959, longArr[1].value)
+ }
+
+ fun testBooleanArray() {
+ assertFalse(booleanArr[1].value)
+ booleanArr[1].compareAndSet(false, true)
+ booleanArr[0].lazySet(true)
+ assertFalse(booleanArr[2].getAndSet(true))
+ assertTrue(booleanArr[0].value && booleanArr[1].value && booleanArr[2].value)
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ fun testRefArray() {
+ val a2 = ANode(BNode(CNode(2)))
+ val a3 = ANode(BNode(CNode(3)))
+ refArr[0].value = a2
+ assertEquals(2, refArr[0].value!!.b.c.d)
+ assertTrue(refArr[0].compareAndSet(a2, a3))
+ assertEquals(3, refArr[0].value!!.b.c.d)
+ val r0 = refArr[0].value
+ refArr[3].value = r0
+ assertEquals(3, refArr[3].value!!.b.c.d)
+ val a = abcNode.value
+ assertTrue(refArr[3].compareAndSet(a3, a))
+ }
+}
+
+data class ANode(val b: T)
+data class BNode(val c: T)
+data class CNode(val d: Int)
+
+@Test
+fun box() {
+ val primitiveTest = TopLevelPrimitiveTest()
+ primitiveTest.testTopLevelInt()
+ primitiveTest.testTopLevelLong()
+ primitiveTest.testTopLevelBoolean()
+ primitiveTest.testTopLevelRef()
+ primitiveTest.testTopLevelArrayOfNulls()
+
+ val arrayTest = TopLevelArrayTest()
+ arrayTest.testIntArray()
+ arrayTest.testLongArray()
+ arrayTest.testBooleanArray()
+ arrayTest.testRefArray()
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace/TraceTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace/TraceTest.kt
new file mode 100644
index 00000000000..8567a991c8c
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/nativeBox/trace/TraceTest.kt
@@ -0,0 +1,106 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class TraceTest {
+ private val defaultTrace = Trace()
+ private val a1 = atomic(5, defaultTrace)
+
+ private val traceWithSize = Trace(30)
+ private val a2 = atomic(1, traceWithSize)
+
+ private val traceWithFormat = Trace(format = TraceFormat { i, text -> "[$i: $text]" })
+ private val a = atomic(0, traceWithFormat)
+
+ private val traceWithSizeAndFormat = Trace(30, TraceFormat { id, text -> "$id: $text"})
+ private val a3 = atomic(2)
+
+ private val shortTrace = Trace(4)
+ private val s = atomic(0, shortTrace.named("s"))
+
+ fun testDefaultTrace() {
+ val oldValue = a1.value
+ defaultTrace { "before CAS value = $oldValue" }
+ val res = a1.compareAndSet(oldValue, oldValue * 10)
+ val newValue = a1.value
+ defaultTrace { "after CAS value = $newValue" }
+ }
+
+ fun testTraceWithSize() {
+ val oldValue = a2.value
+ traceWithSize { "before CAS value = $oldValue" }
+ assertTrue(a2.compareAndSet(oldValue, oldValue * 10))
+ traceWithSize { "after CAS value = ${a2.value}" }
+ traceWithSize { "before getAndDecrement value = ${a2.value}" }
+ a2.getAndDecrement()
+ assertEquals(9, a2.value)
+ traceWithSize { "after getAndDecrement value = ${a2.value}" }
+ }
+
+ fun testTraceWithFormat() {
+ val oldValue = a3.value
+ traceWithFormat { "before CAS value = $oldValue" }
+ assertTrue(a3.compareAndSet(oldValue, oldValue * 10))
+ traceWithFormat { "after CAS value = ${a3.value}" }
+ traceWithFormat { "before getAndDecrement value = ${a3.value}" }
+ a3.getAndDecrement()
+ assertEquals(19, a3.value)
+ traceWithFormat { "after getAndDecrement value = ${a3.value}" }
+ }
+
+ fun testNamedTrace() {
+ s.value = 5
+ shortTrace { "before CAS value = ${s.value}" }
+ s.compareAndSet(5, -2)
+ assertEquals(-2, s.value)
+ shortTrace { "after CAS value = ${s.value}" }
+ }
+
+ private enum class Status { START, END }
+
+ fun testMultipleAppend() {
+ val i = 1
+ traceWithFormat.append(i, Status.START)
+ assertEquals(0, a.value)
+ a.incrementAndGet()
+ traceWithFormat.append(i, a.value, "incAndGet")
+ assertEquals(1, a.value)
+ a.lazySet(10)
+ traceWithFormat.append(i, a.value, "lazySet")
+ assertEquals(10, a.value)
+ traceWithFormat.append(i, Status.END)
+ }
+
+ fun testTraceInBlock() {
+ a1.lazySet(5)
+ if (a1.value == 5) {
+ defaultTrace { "Value checked" }
+ if (a1.compareAndSet(5, 10)) {
+ defaultTrace { "CAS succeeded" }
+ }
+ }
+ assertEquals(10, a1.value)
+ while (true) {
+ if (a1.value == 10) {
+ defaultTrace.append("Value checked", a1.value)
+ a1.value = 15
+ break
+ } else {
+ defaultTrace.append("Wrong value", a1.value)
+ }
+ }
+ }
+
+ fun test() {
+ testDefaultTrace()
+ testTraceWithSize()
+ testTraceWithFormat()
+ testNamedTrace()
+ testMultipleAppend()
+ testTraceInBlock()
+ }
+}
+
+@Test
+fun box() {
+ TraceTest().test()
+}
\ No newline at end of file
diff --git a/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/nativeTest.kt b/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/nativeTest.kt
index 5ffaa58d46f..379b6e2d508 100644
--- a/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/nativeTest.kt
+++ b/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/nativeTest.kt
@@ -12,6 +12,7 @@ private enum class TestProperty(shortName: String) {
// effect on other Gradle tasks (ex: :kotlin-native:dist) that might be executed along with test task.
KOTLIN_NATIVE_HOME("nativeHome"),
COMPILER_CLASSPATH("compilerClasspath"),
+ COMPILER_PLUGINS("compilerPlugins"),
CUSTOM_KLIBS("customKlibs"),
TEST_TARGET("target"),
TEST_MODE("mode"),
@@ -77,12 +78,23 @@ private class ComputedTestProperties(private val task: Test) {
private fun Test.ComputedTestProperties(init: ComputedTestProperties.() -> Unit): ComputedTestProperties =
ComputedTestProperties(this).apply { init() }
+/**
+ * @param taskName Name of Gradle task.
+ * @param tag Optional JUnit test tag. See https://junit.org/junit5/docs/current/user-guide/#writing-tests-tagging-and-filtering
+ * @param requirePlatformLibs Where platform KLIBs from the Kotlin/Native distribution are required for running this test.
+ * @param customCompilerDependencies The [Configuration]s that provide additional JARs to be added to the compiler's classpath.
+ * @param customTestDependencies The [Configuration]s that provide KLIBs to be added to Kotlin/Native compiler dependencies list
+ * along with Kotlin/Native stdlib KLIB and Kotlin/Native platform KLIBs (the latter only if [requirePlatformLibs] is `true`).
+ * @param compilerPluginDependencies The [Configuration]s that provide compiler plugins to be enabled for the Kotlin/Native compiler
+ * for the duration of test execution.
+ */
fun Project.nativeTest(
taskName: String,
tag: String?,
requirePlatformLibs: Boolean = false,
- customDependencies: List = emptyList(),
- customKlibDependencies: List = emptyList()
+ customCompilerDependencies: List = emptyList(),
+ customTestDependencies: List = emptyList(),
+ compilerPluginDependencies: List = emptyList()
) = projectTest(
taskName,
jUnitMode = JUnitMode.JUnit5,
@@ -141,7 +153,7 @@ fun Project.nativeTest(
else
null
- customDependencies.forEach(::dependsOn)
+ customCompilerDependencies.forEach(::dependsOn)
lazyClassPath {
if (customNativeHome == null) {
@@ -151,13 +163,18 @@ fun Project.nativeTest(
this += file(customNativeHome).resolve("konan/lib/trove4j.jar")
}
- customDependencies.flatMapTo(this) { it.files }
+ customCompilerDependencies.flatMapTo(this) { it.files }
}
}
+ computeLazy(COMPILER_PLUGINS) {
+ compilerPluginDependencies.forEach(::dependsOn)
+ lazyClassPath { compilerPluginDependencies.flatMapTo(this) { it.files } }
+ }
+
computeLazy(CUSTOM_KLIBS) {
- customKlibDependencies.forEach(::dependsOn)
- lazyClassPath { customKlibDependencies.flatMapTo(this) { it.files } }
+ customTestDependencies.forEach(::dependsOn)
+ lazyClassPath { customTestDependencies.flatMapTo(this) { it.files } }
}
// Pass Gradle properties as JVM properties so test process can read them.