From 1201d18b4cedd364671fbdb8dd4ab91a0c7ef01f Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Tue, 18 May 2021 17:20:38 +0300 Subject: ASM 9.1 for Java 15+ support (#190) Fixes #188 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index ce4f84c..5d9ae90 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ version=0.16.0-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.5.0 -asm_version=7.2 +asm_version=9.1 slf4j_version=1.8.0-alpha2 junit_version=4.12 kotlinx_metadata_version=0.2.0 -- cgit v1.2.3 From 2cc9b45afd1e1896af0fb27c9eda4e815be20bd6 Mon Sep 17 00:00:00 2001 From: SokolovaMaria Date: Fri, 28 May 2021 16:39:08 +0300 Subject: Removing extra atomicfu references from LVT for Kotlin 1.5.20 --- .../main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt index c7c262c..3f50f9a 100644 --- a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt +++ b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt @@ -715,11 +715,16 @@ class AtomicFUTransformer( i = i.next hasErrors = true } + // make sure all kotlinx/atomicfu references removed + removeAtomicReferencesFromLVT() // save transformed method if not in analysis phase if (!hasErrors && !analyzePhase2) accept(mv) } + private fun removeAtomicReferencesFromLVT() = + localVariables?.removeIf { getType(it.desc) in AFU_TYPES } + private fun FieldInsnNode.checkCopyToDelegate(): AbstractInsnNode? { val fieldId = FieldId(owner, name, desc) if (fieldId in fieldDelegates) { -- cgit v1.2.3 From 5a4b10e973f49f2646d3eb6ea038f4a05ef1d4d1 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Tue, 6 Jul 2021 17:09:11 +0300 Subject: Update Kotlin to 1.5.20 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 5d9ae90..bb48b66 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ version=0.16.0-SNAPSHOT group=org.jetbrains.kotlinx -kotlin_version=1.5.0 +kotlin_version=1.5.20 asm_version=9.1 slf4j_version=1.8.0-alpha2 junit_version=4.12 -- cgit v1.2.3 From e85739779b615a636f8e01ec83ea420974a148c1 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Thu, 13 May 2021 22:48:39 +0300 Subject: It seems like because of https://github.com/JetBrains/kotlin/commit/a29762e30301bef5a507250829d687dd98b31213#diff-22c3d54b52dd863ad546e639e0b3e7ed5b85d1486afa9e55c0f733b540b78645R44 outputFile now resolved to String property instead of File. This change introduced since Kotlin 1.5.20-M1-61 --- atomicfu/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomicfu/build.gradle b/atomicfu/build.gradle index 66cfcb8..65adf89 100644 --- a/atomicfu/build.gradle +++ b/atomicfu/build.gradle @@ -163,7 +163,7 @@ compileJsLegacy.configure { kotlinOptions { // NOTE: Module base-name must be equal to the package name declared in package.json def baseName = "kotlinx-atomicfu" - outputFile = new File(outputFile.parent, baseName + ".js") + outputFile = new File(new File(outputFile).parent, baseName + ".js") } } @@ -188,7 +188,7 @@ compileTestJsLegacy.configure { kotlinOptions { // NOTE: Module base-name must be equal to the package name declared in package.json def baseName = "kotlinx-atomicfu" - outputFile = new File(outputFile.parent, baseName + ".js") + outputFile = new File(new File(outputFile).parent, baseName + ".js") } } def originalJsFile = compileTestJsLegacy.kotlinOptions.outputFile -- cgit v1.2.3 From 299a7cd46067bd695cf2cc7ae18da177f9dc7516 Mon Sep 17 00:00:00 2001 From: Margarita Bobova Date: Wed, 26 May 2021 16:04:40 +0300 Subject: Fix deprecation --- atomicfu/src/nativeMain/kotlin/kotlinx/atomicfu/locks/Synchronized.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomicfu/src/nativeMain/kotlin/kotlinx/atomicfu/locks/Synchronized.kt b/atomicfu/src/nativeMain/kotlin/kotlinx/atomicfu/locks/Synchronized.kt index ff81a5a..76e5d7a 100644 --- a/atomicfu/src/nativeMain/kotlin/kotlinx/atomicfu/locks/Synchronized.kt +++ b/atomicfu/src/nativeMain/kotlin/kotlinx/atomicfu/locks/Synchronized.kt @@ -190,7 +190,7 @@ class MutexPool(capacity: Int) { init { for (i in 0 until capacity) { - release(interpretCPointer(mutexes.rawValue.plus(i * mutex_node_t.size))!!) + release(interpretCPointer(mutexes.rawValue.plus(i * sizeOf()))!!) } } -- cgit v1.2.3 From 80fe08c40eff429e02730aa36690366b47369c83 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Tue, 6 Jul 2021 17:28:39 +0300 Subject: Version 0.16.2 --- CHANGES.md | 6 ++++++ README.md | 6 +++--- gradle.properties | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1ad8836..097b5a2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change log for kotlinx.atomicfu +# Version 0.16.2 + +* Update Kotlin to 1.5.20. +* ASM 9.1 for Java 15+ support (#190). +* Removing extra atomicfu references from LVT. + # Version 0.16.0 * Update Kotlin to 1.5.0. diff --git a/README.md b/README.md index 3f86a27..88d912b 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.16.0' + ext.atomicfu_version = '0.16.2' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -155,7 +155,7 @@ There are the following additional parameters (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.16.0' // set to null to turn-off auto dependencies + dependenciesVersion = '0.16.2' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation transformJs = true // set to false to turn off JS transformation variant = "FU" // JVM transformation variant: FU,VH, or BOTH @@ -169,7 +169,7 @@ Declare AtomicFU version: ```xml - 0.16.0 + 0.16.2 ``` diff --git a/gradle.properties b/gradle.properties index bb48b66..10f7bf0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.16.0-SNAPSHOT +version=0.16.2-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.5.20 -- cgit v1.2.3 From 54271e7c5cb2b1ea438ca6464d80e6f772cf36fd Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Tue, 10 Aug 2021 13:59:25 +0300 Subject: Migrate inline to value classes in Native --- .../src/nativeMain/kotlin/kotlinx/atomicfu/AtomicFU.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/atomicfu/src/nativeMain/kotlin/kotlinx/atomicfu/AtomicFU.kt b/atomicfu/src/nativeMain/kotlin/kotlinx/atomicfu/AtomicFU.kt index 55ed452..b369540 100644 --- a/atomicfu/src/nativeMain/kotlin/kotlinx/atomicfu/AtomicFU.kt +++ b/atomicfu/src/nativeMain/kotlin/kotlinx/atomicfu/AtomicFU.kt @@ -25,8 +25,8 @@ public actual fun atomic(initial: Boolean): AtomicBoolean = atomic(initial, None // ==================================== AtomicRef ==================================== -@Suppress("ACTUAL_WITHOUT_EXPECT", "EXPERIMENTAL_FEATURE_WARNING", "NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS") -public actual inline class AtomicRef internal constructor(@PublishedApi internal val a: KAtomicRef) { +@Suppress("ACTUAL_WITHOUT_EXPECT") +public actual value class AtomicRef internal constructor(@PublishedApi internal val a: KAtomicRef) { public actual inline var value: T get() = a.value set(value) { @@ -62,8 +62,8 @@ public actual inline class AtomicRef internal constructor(@PublishedApi inter // ==================================== AtomicBoolean ==================================== -@Suppress("ACTUAL_WITHOUT_EXPECT", "EXPERIMENTAL_FEATURE_WARNING", "NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS") -public actual inline class AtomicBoolean internal constructor(@PublishedApi internal val a: KAtomicInt) { +@Suppress("ACTUAL_WITHOUT_EXPECT") +public actual value class AtomicBoolean internal constructor(@PublishedApi internal val a: KAtomicInt) { public actual inline var value: Boolean get() = a.value != 0 set(value) { a.value = if (value) 1 else 0 } @@ -94,8 +94,8 @@ public actual inline class AtomicBoolean internal constructor(@PublishedApi inte // ==================================== AtomicInt ==================================== -@Suppress("ACTUAL_WITHOUT_EXPECT", "EXPERIMENTAL_FEATURE_WARNING", "NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS") -public actual inline class AtomicInt internal constructor(@PublishedApi internal val a: KAtomicInt) { +@Suppress("ACTUAL_WITHOUT_EXPECT") +public actual value class AtomicInt internal constructor(@PublishedApi internal val a: KAtomicInt) { public actual inline var value: Int get() = a.value set(value) { a.value = value } @@ -132,8 +132,8 @@ public actual inline class AtomicInt internal constructor(@PublishedApi internal // ==================================== AtomicLong ==================================== -@Suppress("ACTUAL_WITHOUT_EXPECT", "EXPERIMENTAL_FEATURE_WARNING", "NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS") -public actual inline class AtomicLong internal constructor(@PublishedApi internal val a: KAtomicLong) { +@Suppress("ACTUAL_WITHOUT_EXPECT") +public actual value class AtomicLong internal constructor(@PublishedApi internal val a: KAtomicLong) { public actual inline var value: Long get() = a.value set(value) { a.value = value } -- cgit v1.2.3 From c925ee669b18b3ddf901e4061e980df5f62dad71 Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Wed, 25 Aug 2021 12:54:57 +0300 Subject: Update Kotlin to 1.5.30, add M1 native targets --- atomicfu/build.gradle | 5 +++++ gradle.properties | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/atomicfu/build.gradle b/atomicfu/build.gradle index 65adf89..a516fb1 100644 --- a/atomicfu/build.gradle +++ b/atomicfu/build.gradle @@ -89,6 +89,11 @@ if (rootProject.ext.native_targets_enabled) { addTarget(presets.watchosArm64) addTarget(presets.watchosX86) addTarget(presets.watchosX64) + + addTarget(presets.iosSimulatorArm64) + addTarget(presets.watchosSimulatorArm64) + addTarget(presets.tvosSimulatorArm64) + addTarget(presets.macosArm64) } } diff --git a/gradle.properties b/gradle.properties index 10f7bf0..58e9a6f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ version=0.16.2-SNAPSHOT group=org.jetbrains.kotlinx -kotlin_version=1.5.20 +kotlin_version=1.5.30 asm_version=9.1 slf4j_version=1.8.0-alpha2 junit_version=4.12 -- cgit v1.2.3 From fb2a88f37d5e0ef5bc5013cfc4abac8bdc30f52d Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Wed, 25 Aug 2021 12:56:38 +0300 Subject: Remove bintray references --- .../kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt | 2 -- atomicfu-maven-plugin/build.gradle | 15 --------------- build.gradle | 18 ------------------ buildSrc/src/main/kotlin/Publishing.kt | 14 -------------- gradle/publishing.gradle | 12 ++---------- 5 files changed, 2 insertions(+), 59 deletions(-) diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt index f3f49e1..f2e06a9 100644 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt @@ -84,8 +84,6 @@ class Project(val projectDir: File) { jcenter() mavenCentral() maven { url 'https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev' } - maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' } - maven { url 'https://dl.bintray.com/kotlin/kotlin-dev' } maven { url 'https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev' } maven { url "https://oss.sonatype.org/content/repositories/snapshots" } } diff --git a/atomicfu-maven-plugin/build.gradle b/atomicfu-maven-plugin/build.gradle index 8929be9..b48d856 100644 --- a/atomicfu-maven-plugin/build.gradle +++ b/atomicfu-maven-plugin/build.gradle @@ -43,26 +43,11 @@ task generatePomFile(dependsOn: [compileKotlin, ':atomicfu-transformer:publishTo appendNode('project.build.sourceEncoding', 'UTF-8') } appendNode('repositories').with { - appendNode('repository').with { - appendNode('id', 'kotlin-eap') - appendNode('url', 'https://kotlin.bintray.com/kotlin-eap') - } - - appendNode('repository').with { - appendNode('id', 'kotlin-dev') - appendNode('url', 'https://kotlin.bintray.com/kotlin-dev') - } - appendNode('repository').with { appendNode('id', 'dev') appendNode('url', 'https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev') } - appendNode('repository').with { - appendNode('id', 'kotlinx') - appendNode('url', 'https://kotlin.bintray.com/kotlinx') - } - if (buildSnapshots) { appendNode('repository').with { appendNode('id', 'kotlin-snapshots') diff --git a/build.gradle b/build.gradle index 12f531d..09a62fe 100644 --- a/build.gradle +++ b/build.gradle @@ -34,15 +34,6 @@ buildscript { maven { url "https://plugins.gradle.org/m2/" } // Future replacement for kotlin-dev, with cache redirector maven { url "https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" } - maven { - url "https://kotlin.bintray.com/kotlin-dev" - credentials { - username = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') ?: "" - password = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') ?: "" - } - } - maven { url "https://kotlin.bintray.com/kotlin-eap" } - maven { url "https://jetbrains.bintray.com/kotlin-native-dependencies" } maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" } } @@ -66,17 +57,8 @@ allprojects { println "Using Kotlin $kotlin_version for project $it" repositories { jcenter() - maven { url "https://kotlin.bintray.com/kotlin-eap" } // Future replacement for kotlin-dev, with cache redirector maven { url "https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" } - maven { - url "https://kotlin.bintray.com/kotlin-dev" - credentials { - username = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') ?: "" - password = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') ?: "" - } - } - maven { url "https://kotlin.bintray.com/kotlinx" } maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" } } diff --git a/buildSrc/src/main/kotlin/Publishing.kt b/buildSrc/src/main/kotlin/Publishing.kt index 6844ad7..3db911f 100644 --- a/buildSrc/src/main/kotlin/Publishing.kt +++ b/buildSrc/src/main/kotlin/Publishing.kt @@ -44,20 +44,6 @@ fun MavenPom.configureMavenCentralMetadata(project: Project) { } } -fun configureBintrayPublication(rh: RepositoryHandler, project: Project) { - rh.maven { - val user = "kotlin" - val repo = "kotlinx" - val name = "kotlinx.atomicfu" - url = URI("https://api.bintray.com/maven/$user/$repo/$name/;publish=0;override=0") - - credentials { - username = project.findProperty("bintrayUser") as? String ?: System.getenv("BINTRAY_USER") - password = project.findProperty("bintrayApiKey") as? String ?: System.getenv("BINTRAY_API_KEY") - } - } -} - fun mavenRepositoryUri(): URI { // TODO -SNAPSHOT detection can be made here as well val repositoryId: String? = System.getenv("libs.repository.id") diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index 0ca4788..e9e4372 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -27,15 +27,9 @@ task javadocJar(type: Jar) { archiveClassifier = 'javadoc' } -def bintrayUpload = System.getenv("libs.bintray.upload") != null - publishing { repositories { // this: closure - if (bintrayUpload) { - PublishingKt.configureBintrayPublication(delegate, project) - } else { - PublishingKt.configureMavenPublication(delegate, project) - } + PublishingKt.configureMavenPublication(delegate, project) } if (!isMultiplatform) { @@ -61,9 +55,7 @@ publishing { publications.all { PublishingKt.configureMavenCentralMetadata(pom, project) - if (!bintrayUpload) { - PublishingKt.signPublicationIfKeyPresent(project, it) - } + PublishingKt.signPublicationIfKeyPresent(project, it) // add empty javadocs if (it.name != "kotlinMultiplatform") { // The root module gets the JVM's javadoc JAR -- cgit v1.2.3 From 935e12598b0b49e0d217c0211d20f531092e3916 Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Wed, 25 Aug 2021 13:57:01 +0300 Subject: Update kotlinx-metadata --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 58e9a6f..e15771b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ kotlin_version=1.5.30 asm_version=9.1 slf4j_version=1.8.0-alpha2 junit_version=4.12 -kotlinx_metadata_version=0.2.0 +kotlinx_metadata_version=0.3.0 maven_version=3.5.3 -- cgit v1.2.3 From acd4dc796cda6b9a0bbb207d9430efd7d6cec069 Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Wed, 25 Aug 2021 14:05:06 +0300 Subject: Update kotlinx-metadata --- .../main/kotlin/kotlinx/atomicfu/transformer/MetadataTransformer.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/MetadataTransformer.kt b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/MetadataTransformer.kt index f8bcaf1..13c5366 100644 --- a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/MetadataTransformer.kt +++ b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/MetadataTransformer.kt @@ -26,7 +26,6 @@ class MetadataTransformer( val hdr = KotlinClassHeader( kind = map["k"] as Int?, metadataVersion = (map["mv"] as? List)?.toIntArray(), - bytecodeVersion = (map["bv"] as? List)?.toIntArray(), data1 = (map["d1"] as? List)?.toTypedArray(), data2 = (map["d2"] as? List)?.toTypedArray(), extraString = map["xs"] as String?, @@ -229,4 +228,4 @@ private fun AnnotationNode.setKey(key: String, value: Any?) { } } error("Annotation key '$key' is not found") -} \ No newline at end of file +} -- cgit v1.2.3 From 56e7485adeba7fb524480abe33029355489a85c3 Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Wed, 25 Aug 2021 14:05:18 +0300 Subject: Version 0.16.3 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index e15771b..b0398f6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.16.2-SNAPSHOT +version=0.16.3-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.5.30 -- cgit v1.2.3 From de4e55674c51f58cbc1f16b097d68c4ba42a5e7b Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Wed, 25 Aug 2021 18:07:31 +0300 Subject: Changelog for 0.16.3 --- CHANGES.md | 6 ++++++ README.md | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 097b5a2..99cab30 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change log for kotlinx.atomicfu +# Version 0.16.3 + +* Kotlin is updated to 1.5.30. +* All references to Bintray are removed from artefacts POMs. +* Added new Apple Silicon targets for K/N. + # Version 0.16.2 * Update Kotlin to 1.5.20. diff --git a/README.md b/README.md index 88d912b..4f1e1c1 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.16.2' + ext.atomicfu_version = '0.16.3' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -155,7 +155,7 @@ There are the following additional parameters (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.16.2' // set to null to turn-off auto dependencies + dependenciesVersion = '0.16.3' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation transformJs = true // set to false to turn off JS transformation variant = "FU" // JVM transformation variant: FU,VH, or BOTH @@ -169,7 +169,7 @@ Declare AtomicFU version: ```xml - 0.16.2 + 0.16.3 ``` -- cgit v1.2.3 From fe0950adcf0da67cd074503c2a78467656c5aa0f Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Mon, 20 Sep 2021 13:49:36 +0300 Subject: Update the minimal ASM api version to ASM7 (#203) Fixes #199 --- .../kotlinx/atomicfu/transformer/AtomicFUTransformer.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt index 3f50f9a..b8f804f 100644 --- a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt +++ b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt @@ -126,7 +126,7 @@ private inline fun code(mv: MethodVisitor, block: InstructionAdapter.() -> Unit) } private inline fun insns(block: InstructionAdapter.() -> Unit): InsnList { - val node = MethodNode(ASM5) + val node = MethodNode(ASM9) block(InstructionAdapter(node)) return node.instructions } @@ -280,7 +280,7 @@ class AtomicFUTransformer( return cw.toByteArray() // write transformed bytes } - private abstract inner class CV(cv: ClassVisitor?) : ClassVisitor(ASM5, cv) { + private abstract inner class CV(cv: ClassVisitor?) : ClassVisitor(ASM9, cv) { lateinit var className: String override fun visit( @@ -348,7 +348,7 @@ class AtomicFUTransformer( private inner class AccessorCollectorMV( private val className: String, access: Int, name: String, desc: String, signature: String?, exceptions: Array? - ) : MethodNode(ASM5, access, name, desc, signature, exceptions) { + ) : MethodNode(ASM9, access, name, desc, signature, exceptions) { override fun visitEnd() { val insns = instructions.listUseful(4) if (insns.size == 3 && @@ -398,7 +398,7 @@ class AtomicFUTransformer( private inner class DelegateFieldsCollectorMV( access: Int, name: String, desc: String, signature: String?, exceptions: Array? - ) : MethodNode(ASM5, access, name, desc, signature, exceptions) { + ) : MethodNode(ASM9, access, name, desc, signature, exceptions) { override fun visitEnd() { // register delegate field and the corresponding original atomic field // getfield a: *Atomic @@ -460,7 +460,7 @@ class AtomicFUTransformer( private var originalClinit: MethodNode? = null private var newClinit: MethodNode? = null - private fun newClinit() = MethodNode(ASM5, ACC_STATIC, "", "()V", null, null) + private fun newClinit() = MethodNode(ASM9, ACC_STATIC, "", "()V", null, null) fun getOrCreateNewClinit(): MethodNode = newClinit ?: newClinit().also { newClinit = it } override fun visitSource(source: String?, debug: String?) { @@ -607,7 +607,7 @@ class AtomicFUTransformer( val superMV = if (name == "" && desc == "()V") { if (access and ACC_STATIC == 0) abort(" method not marked as static") // defer writing class initialization method - val node = MethodNode(ASM5, access, name, desc, signature, exceptions) + val node = MethodNode(ASM9, access, name, desc, signature, exceptions) if (originalClinit != null) abort("Multiple methods found") originalClinit = node node @@ -673,7 +673,7 @@ class AtomicFUTransformer( private val packageName: String, private val vh: Boolean, private val analyzePhase2: Boolean // true in Phase 2 when we are analyzing file for refs (not transforming yet) - ) : MethodNode(ASM5, access, name, desc, signature, exceptions) { + ) : MethodNode(ASM9, access, name, desc, signature, exceptions) { init { this.mv = mv } -- cgit v1.2.3 From ef89f2c3adec9aee0fedc7a79a0e5ae15436267d Mon Sep 17 00:00:00 2001 From: Forrest Pangborn Date: Mon, 27 Sep 2021 07:29:39 -0400 Subject: Correct artifact name for instructions on use within common sourceset. (#204) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f1e1c1..ebb127f 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ See [gradle.properties](gradle.properties) in AtomicFU project for its `kotlin_v ### Common -If you write a common code that should get compiled or different platforms, add `org.jetbrains.kotlinx:atomicfu-common` +If you write a common code that should get compiled or different platforms, add `org.jetbrains.kotlinx:atomicfu` to your common code dependencies or apply `kotlinx-atomicfu` plugin that adds this dependency automatically: ```groovy -- cgit v1.2.3 From 6922e0c98410945b567f9126dc347c6d47150fc8 Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Wed, 18 Aug 2021 17:59:14 +0300 Subject: Remove obsolete and no longer used LockFreedomTestEnvironment and AtomicOperationInterceptor --- .../jvmMain/kotlin/kotlinx/atomicfu/AtomicFU.kt | 122 ++---- .../jvmMain/kotlin/kotlinx/atomicfu/Interceptor.kt | 46 -- .../kotlinx/atomicfu/LockFreedomTestEnvironment.kt | 482 --------------------- .../kotlinx/atomicfu/test/LockFreeQueueLFTest.kt | 33 -- .../kotlin/kotlinx/atomicfu/test/TraceLFTest.kt | 76 ---- 5 files changed, 29 insertions(+), 730 deletions(-) delete mode 100644 atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/Interceptor.kt delete mode 100644 atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/LockFreedomTestEnvironment.kt delete mode 100644 atomicfu/src/jvmTest/kotlin/kotlinx/atomicfu/test/LockFreeQueueLFTest.kt delete mode 100644 atomicfu/src/jvmTest/kotlin/kotlinx/atomicfu/test/TraceLFTest.kt diff --git a/atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/AtomicFU.kt b/atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/AtomicFU.kt index 20dc5f2..ddaf1dc 100644 --- a/atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/AtomicFU.kt +++ b/atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/AtomicFU.kt @@ -80,10 +80,8 @@ public actual class AtomicRef internal constructor(value: T, val trace: Trace @Volatile public actual var value: T = value set(value) { - interceptor.beforeUpdate(this) field = value - if (trace !== TraceBase.None) trace { "set($value)" } - interceptor.afterSet(this, value) + if (trace !== None) trace { "set($value)" } } public actual inline operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value @@ -94,22 +92,16 @@ public actual class AtomicRef internal constructor(value: T, val trace: Trace * Maps to [AtomicReferenceFieldUpdater.lazySet]. */ public actual fun lazySet(value: T) { - interceptor.beforeUpdate(this) FU.lazySet(this, value) - if (trace !== TraceBase.None) trace { "lazySet($value)" } - interceptor.afterSet(this, value) + if (trace !== None) trace { "lazySet($value)" } } /** * Maps to [AtomicReferenceFieldUpdater.compareAndSet]. */ public actual fun compareAndSet(expect: T, update: T): Boolean { - interceptor.beforeUpdate(this) val result = FU.compareAndSet(this, expect, update) - if (result) { - if (trace !== TraceBase.None) trace { "CAS($expect, $update)" } - interceptor.afterRMW(this, expect, update) - } + if (result && trace !== None) trace { "CAS($expect, $update)" } return result } @@ -117,10 +109,8 @@ public actual class AtomicRef internal constructor(value: T, val trace: Trace * Maps to [AtomicReferenceFieldUpdater.getAndSet]. */ public actual fun getAndSet(value: T): T { - interceptor.beforeUpdate(this) val oldValue = FU.getAndSet(this, value) as T - if (trace !== TraceBase.None) trace { "getAndSet($value):$oldValue" } - interceptor.afterRMW(this, oldValue, value) + if (trace !== None) trace { "getAndSet($value):$oldValue" } return oldValue } @@ -155,35 +145,27 @@ public actual class AtomicBoolean internal constructor(v: Boolean, val trace: Tr public actual var value: Boolean get() = _value != 0 set(value) { - interceptor.beforeUpdate(this) _value = if (value) 1 else 0 - if (trace !== TraceBase.None) trace { "set($value)" } - interceptor.afterSet(this, value) + if (trace !== None) trace { "set($value)" } } /** * Maps to [AtomicIntegerFieldUpdater.lazySet]. */ public actual fun lazySet(value: Boolean) { - interceptor.beforeUpdate(this) val v = if (value) 1 else 0 FU.lazySet(this, v) - if (trace !== TraceBase.None) trace { "lazySet($value)" } - interceptor.afterSet(this, value) + if (trace !== None) trace { "lazySet($value)" } } /** * Maps to [AtomicIntegerFieldUpdater.compareAndSet]. */ public actual fun compareAndSet(expect: Boolean, update: Boolean): Boolean { - interceptor.beforeUpdate(this) val e = if (expect) 1 else 0 val u = if (update) 1 else 0 val result = FU.compareAndSet(this, e, u) - if (result) { - if (trace !== TraceBase.None) trace { "CAS($expect, $update)" } - interceptor.afterRMW(this, expect, update) - } + if (result && trace !== None) trace { "CAS($expect, $update)" } return result } @@ -191,11 +173,9 @@ public actual class AtomicBoolean internal constructor(v: Boolean, val trace: Tr * Maps to [AtomicIntegerFieldUpdater.getAndSet]. */ public actual fun getAndSet(value: Boolean): Boolean { - interceptor.beforeUpdate(this) val v = if (value) 1 else 0 val oldValue = FU.getAndSet(this, v) - if (trace !== TraceBase.None) trace { "getAndSet($value):$oldValue" } - interceptor.afterRMW(this, (oldValue == 1), value) + if (trace !== None) trace { "getAndSet($value):$oldValue" } return oldValue == 1 } @@ -220,10 +200,8 @@ public actual class AtomicInt internal constructor(value: Int, val trace: TraceB @Volatile public actual var value: Int = value set(value) { - interceptor.beforeUpdate(this) field = value - if (trace !== TraceBase.None) trace { "set($value)" } - interceptor.afterSet(this, value) + if (trace !== None) trace { "set($value)" } } public actual inline operator fun getValue(thisRef: Any?, property: KProperty<*>): Int = value @@ -234,22 +212,16 @@ public actual class AtomicInt internal constructor(value: Int, val trace: TraceB * Maps to [AtomicIntegerFieldUpdater.lazySet]. */ public actual fun lazySet(value: Int) { - interceptor.beforeUpdate(this) FU.lazySet(this, value) - if (trace !== TraceBase.None) trace { "lazySet($value)" } - interceptor.afterSet(this, value) + if (trace !== None) trace { "lazySet($value)" } } /** * Maps to [AtomicIntegerFieldUpdater.compareAndSet]. */ public actual fun compareAndSet(expect: Int, update: Int): Boolean { - interceptor.beforeUpdate(this) val result = FU.compareAndSet(this, expect, update) - if (result) { - if (trace !== TraceBase.None) trace { "CAS($expect, $update)" } - interceptor.afterRMW(this, expect, update) - } + if (result && trace !== None) trace { "CAS($expect, $update)" } return result } @@ -257,10 +229,8 @@ public actual class AtomicInt internal constructor(value: Int, val trace: TraceB * Maps to [AtomicIntegerFieldUpdater.getAndSet]. */ public actual fun getAndSet(value: Int): Int { - interceptor.beforeUpdate(this) val oldValue = FU.getAndSet(this, value) - if (trace !== TraceBase.None) trace { "getAndSet($value):$oldValue" } - interceptor.afterRMW(this, oldValue, value) + if (trace !== None) trace { "getAndSet($value):$oldValue" } return oldValue } @@ -268,10 +238,8 @@ public actual class AtomicInt internal constructor(value: Int, val trace: TraceB * Maps to [AtomicIntegerFieldUpdater.getAndIncrement]. */ public actual fun getAndIncrement(): Int { - interceptor.beforeUpdate(this) val oldValue = FU.getAndIncrement(this) - if (trace !== TraceBase.None) trace { "getAndInc():$oldValue" } - interceptor.afterRMW(this, oldValue, oldValue + 1) + if (trace !== None) trace { "getAndInc():$oldValue" } return oldValue } @@ -279,10 +247,8 @@ public actual class AtomicInt internal constructor(value: Int, val trace: TraceB * Maps to [AtomicIntegerFieldUpdater.getAndDecrement]. */ public actual fun getAndDecrement(): Int { - interceptor.beforeUpdate(this) val oldValue = FU.getAndDecrement(this) - if (trace !== TraceBase.None) trace { "getAndDec():$oldValue" } - interceptor.afterRMW(this, oldValue, oldValue - 1) + if (trace !== None) trace { "getAndDec():$oldValue" } return oldValue } @@ -290,10 +256,8 @@ public actual class AtomicInt internal constructor(value: Int, val trace: TraceB * Maps to [AtomicIntegerFieldUpdater.getAndAdd]. */ public actual fun getAndAdd(delta: Int): Int { - interceptor.beforeUpdate(this) val oldValue = FU.getAndAdd(this, delta) - if (trace !== TraceBase.None) trace { "getAndAdd($delta):$oldValue" } - interceptor.afterRMW(this, oldValue, oldValue + delta) + if (trace !== None) trace { "getAndAdd($delta):$oldValue" } return oldValue } @@ -301,10 +265,8 @@ public actual class AtomicInt internal constructor(value: Int, val trace: TraceB * Maps to [AtomicIntegerFieldUpdater.addAndGet]. */ public actual fun addAndGet(delta: Int): Int { - interceptor.beforeUpdate(this) val newValue = FU.addAndGet(this, delta) - if (trace !== TraceBase.None) trace { "addAndGet($delta):$newValue" } - interceptor.afterRMW(this, newValue - delta, newValue) + if (trace !== None) trace { "addAndGet($delta):$newValue" } return newValue } @@ -312,10 +274,8 @@ public actual class AtomicInt internal constructor(value: Int, val trace: TraceB * Maps to [AtomicIntegerFieldUpdater.incrementAndGet]. */ public actual fun incrementAndGet(): Int { - interceptor.beforeUpdate(this) val newValue = FU.incrementAndGet(this) - if (trace !== TraceBase.None) trace { "incAndGet():$newValue" } - interceptor.afterRMW(this, newValue - 1, newValue) + if (trace !== None) trace { "incAndGet():$newValue" } return newValue } @@ -323,10 +283,8 @@ public actual class AtomicInt internal constructor(value: Int, val trace: TraceB * Maps to [AtomicIntegerFieldUpdater.decrementAndGet]. */ public actual fun decrementAndGet(): Int { - interceptor.beforeUpdate(this) val newValue = FU.decrementAndGet(this) - if (trace !== TraceBase.None) trace { "decAndGet():$newValue" } - interceptor.afterRMW(this, newValue + 1, newValue) + if (trace !== None) trace { "decAndGet():$newValue" } return newValue } @@ -365,10 +323,8 @@ public actual class AtomicLong internal constructor(value: Long, val trace: Trac @Volatile public actual var value: Long = value set(value) { - interceptor.beforeUpdate(this) field = value - if (trace !== TraceBase.None) trace { "set($value)" } - interceptor.afterSet(this, value) + if (trace !== None) trace { "set($value)" } } public actual inline operator fun getValue(thisRef: Any?, property: KProperty<*>): Long = value @@ -379,22 +335,16 @@ public actual class AtomicLong internal constructor(value: Long, val trace: Trac * Maps to [AtomicLongFieldUpdater.lazySet]. */ public actual fun lazySet(value: Long) { - interceptor.beforeUpdate(this) FU.lazySet(this, value) - if (trace !== TraceBase.None) trace { "lazySet($value)" } - interceptor.afterSet(this, value) + if (trace !== None) trace { "lazySet($value)" } } /** * Maps to [AtomicLongFieldUpdater.compareAndSet]. */ public actual fun compareAndSet(expect: Long, update: Long): Boolean { - interceptor.beforeUpdate(this) val result = FU.compareAndSet(this, expect, update) - if (result) { - if (trace !== TraceBase.None) trace { "CAS($expect, $update)" } - interceptor.afterRMW(this, expect, update) - } + if (result && trace !== None) trace { "CAS($expect, $update)" } return result } @@ -402,10 +352,8 @@ public actual class AtomicLong internal constructor(value: Long, val trace: Trac * Maps to [AtomicLongFieldUpdater.getAndSet]. */ public actual fun getAndSet(value: Long): Long { - interceptor.beforeUpdate(this) val oldValue = FU.getAndSet(this, value) - if (trace !== TraceBase.None) trace { "getAndSet($value):$oldValue" } - interceptor.afterRMW(this, oldValue, value) + if (trace !== None) trace { "getAndSet($value):$oldValue" } return oldValue } @@ -413,10 +361,8 @@ public actual class AtomicLong internal constructor(value: Long, val trace: Trac * Maps to [AtomicLongFieldUpdater.getAndIncrement]. */ public actual fun getAndIncrement(): Long { - interceptor.beforeUpdate(this) val oldValue = FU.getAndIncrement(this) - if (trace !== TraceBase.None) trace { "getAndInc():$oldValue" } - interceptor.afterRMW(this, oldValue, oldValue + 1) + if (trace !== None) trace { "getAndInc():$oldValue" } return oldValue } @@ -424,10 +370,8 @@ public actual class AtomicLong internal constructor(value: Long, val trace: Trac * Maps to [AtomicLongFieldUpdater.getAndDecrement]. */ public actual fun getAndDecrement(): Long { - interceptor.beforeUpdate(this) val oldValue = FU.getAndDecrement(this) - if (trace !== TraceBase.None) trace { "getAndDec():$oldValue" } - interceptor.afterRMW(this, oldValue, oldValue - 1) + if (trace !== None) trace { "getAndDec():$oldValue" } return oldValue } @@ -435,10 +379,8 @@ public actual class AtomicLong internal constructor(value: Long, val trace: Trac * Maps to [AtomicLongFieldUpdater.getAndAdd]. */ public actual fun getAndAdd(delta: Long): Long { - interceptor.beforeUpdate(this) val oldValue = FU.getAndAdd(this, delta) - if (trace !== TraceBase.None) trace { "getAndAdd($delta):$oldValue" } - interceptor.afterRMW(this, oldValue, oldValue + delta) + if (trace !== None) trace { "getAndAdd($delta):$oldValue" } return oldValue } @@ -446,10 +388,8 @@ public actual class AtomicLong internal constructor(value: Long, val trace: Trac * Maps to [AtomicLongFieldUpdater.addAndGet]. */ public actual fun addAndGet(delta: Long): Long { - interceptor.beforeUpdate(this) val newValue = FU.addAndGet(this, delta) - if (trace !== TraceBase.None) trace { "addAndGet($delta):$newValue" } - interceptor.afterRMW(this, newValue - delta, newValue) + if (trace !== None) trace { "addAndGet($delta):$newValue" } return newValue } @@ -457,10 +397,8 @@ public actual class AtomicLong internal constructor(value: Long, val trace: Trac * Maps to [AtomicLongFieldUpdater.incrementAndGet]. */ public actual fun incrementAndGet(): Long { - interceptor.beforeUpdate(this) val newValue = FU.incrementAndGet(this) - if (trace !== TraceBase.None) trace { "incAndGet():$newValue" } - interceptor.afterRMW(this, newValue - 1, newValue) + if (trace !== None) trace { "incAndGet():$newValue" } return newValue } @@ -468,10 +406,8 @@ public actual class AtomicLong internal constructor(value: Long, val trace: Trac * Maps to [AtomicLongFieldUpdater.decrementAndGet]. */ public actual fun decrementAndGet(): Long { - interceptor.beforeUpdate(this) val newValue = FU.decrementAndGet(this) - if (trace !== TraceBase.None) trace { "decAndGet():$newValue" } - interceptor.afterRMW(this, newValue + 1, newValue) + if (trace !== None) trace { "decAndGet():$newValue" } return newValue } @@ -494,4 +430,4 @@ public actual class AtomicLong internal constructor(value: Long, val trace: Trac private companion object { private val FU = AtomicLongFieldUpdater.newUpdater(AtomicLong::class.java, "value") } -} \ No newline at end of file +} diff --git a/atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/Interceptor.kt b/atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/Interceptor.kt deleted file mode 100644 index 28d989b..0000000 --- a/atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/Interceptor.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu - -import java.util.concurrent.locks.ReentrantLock - -internal var interceptor: AtomicOperationInterceptor = DefaultInterceptor - private set -private val interceptorLock = ReentrantLock() - -internal fun lockAndSetInterceptor(impl: AtomicOperationInterceptor) { - if (!interceptorLock.tryLock() || interceptor !== DefaultInterceptor) { - error("Interceptor is locked by another test: $interceptor") - } - interceptor = impl -} - -internal fun unlockAndResetInterceptor(impl: AtomicOperationInterceptor) { - check(interceptor === impl) { "Unexpected interceptor found: $interceptor" } - interceptor = DefaultInterceptor - interceptorLock.unlock() -} - -/** - * Interceptor for modifications of atomic variables. - */ -internal open class AtomicOperationInterceptor { - open fun beforeUpdate(ref: AtomicRef) {} - open fun beforeUpdate(ref: AtomicInt) {} - open fun beforeUpdate(ref: AtomicLong) {} - open fun beforeUpdate(ref: AtomicBoolean){} - open fun afterSet(ref: AtomicRef, newValue: T) {} - open fun afterSet(ref: AtomicInt, newValue: Int) {} - open fun afterSet(ref: AtomicLong, newValue: Long) {} - open fun afterSet(ref: AtomicBoolean, newValue: Boolean) {} - open fun afterRMW(ref: AtomicRef, oldValue: T, newValue: T) {} - open fun afterRMW(ref: AtomicInt, oldValue: Int, newValue: Int) {} - open fun afterRMW(ref: AtomicLong, oldValue: Long, newValue: Long) {} - open fun afterRMW(ref: AtomicBoolean, oldValue: Boolean, newValue: Boolean) {} -} - -private object DefaultInterceptor : AtomicOperationInterceptor() { - override fun toString(): String = "DefaultInterceptor" -} diff --git a/atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/LockFreedomTestEnvironment.kt b/atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/LockFreedomTestEnvironment.kt deleted file mode 100644 index 0208feb..0000000 --- a/atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/LockFreedomTestEnvironment.kt +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -@file:Suppress("RedundantVisibilityModifier") - -package kotlinx.atomicfu - -import java.util.* -import java.util.concurrent.atomic.* -import java.util.concurrent.locks.* -import kotlin.coroutines.* -import kotlin.coroutines.intrinsics.* - -private const val PAUSE_EVERY_N_STEPS = 1000 -private const val STALL_LIMIT_MS = 15_000L // 15s -private const val SHUTDOWN_CHECK_MS = 10L // 10ms - -private const val STATUS_DONE = Int.MAX_VALUE - -private const val MAX_PARK_NANOS = 1_000_000L // part for at most 1ms just in case of loosing unpark signal - -/** - * Environment for performing lock-freedom tests for lock-free data structures - * that are written with [atomic] variables. - */ -public open class LockFreedomTestEnvironment( - private val name: String, - private val allowSuspendedThreads: Int = 0 -) { - private val interceptor = Interceptor() - private val threads = mutableListOf() - private val performedOps = LongAdder() - private val uncaughtException = AtomicReference() - private var started = false - private var performedResumes = 0 - - @Volatile - private var completed = false - private val onCompletion = mutableListOf<() -> Unit>() - - private val ueh = Thread.UncaughtExceptionHandler { t, e -> - synchronized(System.out) { - println("Uncaught exception in thread $t") - e.printStackTrace(System.out) - uncaughtException.compareAndSet(null, e) - } - } - - // status < 0 - inv paused thread id - // status >= 0 - no. of performed resumes so far (==last epoch) - // status == STATUS_DONE - done working - private val status = AtomicInteger() - private val globalPauseProgress = AtomicInteger() - private val suspendedThreads = ArrayList() - - @Volatile - private var isActive = true - - // ---------- API ---------- - - /** - * Starts lock-freedom test for a given duration in seconds, - * invoking [progress] every second (it will be invoked `seconds + 1` times). - */ - public fun performTest(seconds: Int, progress: () -> Unit = {}) { - check(isActive) { "Can perform test at most once on this instance" } - println("=== $name") - val minThreads = 2 + allowSuspendedThreads - check(threads.size >= minThreads) { "Must define at least $minThreads test threads" } - lockAndSetInterceptor(interceptor) - started = true - var nextTime = System.currentTimeMillis() - threads.forEach { thread -> - thread.setUncaughtExceptionHandler(ueh) - thread.lastOpTime = nextTime - thread.start() - } - try { - var second = 0 - while (uncaughtException.get() == null) { - waitUntil(nextTime) - println("--- $second: Performed ${performedOps.sum()} operations${resumeStr()}") - progress() - checkStalled() - if (++second > seconds) break - nextTime += 1000L - } - } finally { - complete() - } - println("------ Done with ${performedOps.sum()} operations${resumeStr()}") - progress() - } - - private fun complete() { - val activeNonPausedThreads: MutableMap> = mutableMapOf() - val shutdownDeadline = System.currentTimeMillis() + STALL_LIMIT_MS - try { - completed = true - // perform custom completion blocks. For testing of things like channels, these custom completion - // blocks close all the channels, so that all suspended coroutines shall get resumed. - onCompletion.forEach { it() } - // signal shutdown to all threads (non-paused threads will terminate) - isActive = false - // wait for threads to terminate - while (System.currentTimeMillis() < shutdownDeadline) { - // Check all threads while shutting down: - // All terminated threads are considered to make progress for the purpose of resuming stalled ones - activeNonPausedThreads.clear() - for (t in threads) { - when { - !t.isAlive -> t.makeProgress(getPausedEpoch()) // not alive - makes progress - t.index.inv() == status.get() -> {} // active, paused -- skip - else -> { - val stackTrace = t.stackTrace - if (t.isAlive) activeNonPausedThreads[t] = stackTrace - } - } - } - if (activeNonPausedThreads.isEmpty()) break - checkStalled() - Thread.sleep(SHUTDOWN_CHECK_MS) - } - activeNonPausedThreads.forEach { (t, stackTrack) -> - println("=== $t had failed to shutdown in time") - stackTrack.forEach { println("\tat $it") } - } - } finally { - shutdown(shutdownDeadline) - } - // if no other exception was throws & we had threads that did not shut down -- still fails - if (activeNonPausedThreads.isNotEmpty()) error("Some threads had failed to shutdown in time") - } - - private fun shutdown(shutdownDeadline: Long) { - // forcefully unpause paused threads to shut them down (if any left) - val curStatus = status.getAndSet(STATUS_DONE) - if (curStatus < 0) LockSupport.unpark(threads[curStatus.inv()]) - threads.forEach { - val remaining = shutdownDeadline - System.currentTimeMillis() - if (remaining > 0) it.join(remaining) - } - // abort waiting threads (if still any left) - threads.forEach { it.abortWait() } - // cleanup & be done - unlockAndResetInterceptor(interceptor) - uncaughtException.get()?.let { throw it } - threads.find { it.isAlive }?.let { dumpThreadsError("A thread is still alive: $it")} - } - - private fun checkStalled() { - val stallLimit = System.currentTimeMillis() - STALL_LIMIT_MS - val stalled = threads.filter { it.lastOpTime < stallLimit } - if (stalled.isNotEmpty()) dumpThreadsError("Progress stalled in threads ${stalled.map { it.name }}") - } - - private fun resumeStr(): String { - val resumes = performedResumes - return if (resumes == 0) "" else " (pause/resumes $resumes)" - } - - private fun waitUntil(nextTime: Long) { - while (true) { - val curTime = System.currentTimeMillis() - if (curTime >= nextTime) break - Thread.sleep(nextTime - curTime) - } - } - - private fun dumpThreadsError(message: String) : Nothing { - val traces = threads.associate { it to it.stackTrace } - println("!!! $message") - println("=== Dumping live thread stack traces") - for ((thread, trace) in traces) { - if (trace.isEmpty()) continue - println("Thread \"${thread.name}\" ${thread.state}") - for (t in trace) println("\tat ${t.className}.${t.methodName}(${t.fileName}:${t.lineNumber})") - println() - } - println("===") - error(message) - } - - /** - * Returns true when test was completed. - * Sets to true before calling [onCompletion] blocks. - */ - public val isCompleted: Boolean get() = completed - - /** - * Performs a given block of code on test's completion - */ - public fun onCompletion(block: () -> Unit) { - onCompletion += block - } - - /** - * Creates a new test thread in this environment that is executes a given lock-free [operation] - * in a loop while this environment [isActive]. - */ - public fun testThread(name: String? = null, operation: suspend TestThread.() -> Unit): TestThread = - TestThread(name, operation) - - /** - * Test thread. - */ - @Suppress("LeakingThis") - public inner class TestThread internal constructor( - name: String?, - private val operation: suspend TestThread.() -> Unit - ) : Thread(composeThreadName(name)) { - internal val index: Int - - internal @Volatile var lastOpTime = 0L - internal @Volatile var pausedEpoch = -1 - - private val random = Random() - - // thread-local stuff - private var operationEpoch = -1 - private var progressEpoch = -1 - private var sink = 0 - - init { - check(!started) - index = threads.size - threads += this - } - - public override fun run() { - while (isActive) { - callOperation() - } - } - - /** - * Use it to insert an arbitrary intermission between lock-free operations. - */ - public inline fun intermission(block: () -> T): T { - afterLockFreeOperation() - return try { block() } - finally { beforeLockFreeOperation() } - } - - @PublishedApi - internal fun beforeLockFreeOperation() { - operationEpoch = getPausedEpoch() - } - - @PublishedApi - internal fun afterLockFreeOperation() { - makeProgress(operationEpoch) - lastOpTime = System.currentTimeMillis() - performedOps.add(1) - } - - internal fun makeProgress(epoch: Int) { - if (epoch <= progressEpoch) return - progressEpoch = epoch - val total = globalPauseProgress.incrementAndGet() - if (total >= threads.size - 1) { - check(total == threads.size - 1) - check(globalPauseProgress.compareAndSet(threads.size - 1, 0)) - resumeImpl() - } - } - - /** - * Inserts random spin wait between multiple lock-free operations in [operation]. - */ - public fun randomSpinWaitIntermission() { - intermission { - if (random.nextInt(100) < 95) return // be quick, no wait 95% of time - do { - val x = random.nextInt(100) - repeat(x) { sink += it } - } while (x >= 90) - } - } - - internal fun stepImpl() { - if (random.nextInt(PAUSE_EVERY_N_STEPS) == 0) pauseImpl() - } - - internal fun pauseImpl() { - while (true) { - val curStatus = status.get() - if (curStatus < 0 || curStatus == STATUS_DONE) return // some other thread paused or done - pausedEpoch = curStatus + 1 - val newStatus = index.inv() - if (status.compareAndSet(curStatus, newStatus)) { - while (status.get() == newStatus) LockSupport.parkNanos(MAX_PARK_NANOS) // wait - return - } - } - } - - // ----- Lightweight support for suspending operations ----- - - private fun callOperation() { - beforeLockFreeOperation() - beginRunningOperation() - val result = operation.startCoroutineUninterceptedOrReturn(this, completion) - when { - result === Unit -> afterLockFreeOperation() // operation completed w/o suspension -- done - result === COROUTINE_SUSPENDED -> waitUntilCompletion() // operation had suspended - else -> error("Unexpected result of operation: $result") - } - try { - doneRunningOperation() - } catch(e: IllegalStateException) { - throw IllegalStateException("${e.message}; original start result=$result", e) - } - } - - private var runningOperation = false - private var result: Result? = null - private var continuation: Continuation? = null - - private fun waitUntilCompletion() { - try { - while (true) { - afterLockFreeOperation() - val result: Result = waitForResult() - val continuation = takeContinuation() - if (continuation == null) { // done - check(result.getOrThrow() === Unit) - return - } - removeSuspended(this) - beforeLockFreeOperation() - continuation.resumeWith(result) - } - } finally { - removeSuspended(this) - } - } - - private fun beginRunningOperation() { - runningOperation = true - result = null - continuation = null - } - - @Synchronized - private fun doneRunningOperation() { - check(runningOperation) { "Should be running operation" } - check(result == null && continuation == null) { - "Callback invoked with result=$result, continuation=$continuation" - } - runningOperation = false - } - - @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") - @Synchronized - private fun resumeWith(result: Result, continuation: Continuation?) { - check(runningOperation) { "Should be running operation" } - check(this.result == null && this.continuation == null) { - "Resumed again with result=$result, continuation=$continuation, when this: result=${this.result}, continuation=${this.continuation}" - } - this.result = result - this.continuation = continuation - (this as Object).notifyAll() - } - - @Suppress("RESULT_CLASS_IN_RETURN_TYPE", "PLATFORM_CLASS_MAPPED_TO_KOTLIN") - @Synchronized - private fun waitForResult(): Result { - while (true) { - val result = this.result - if (result != null) return result - val index = addSuspended(this) - if (index < allowSuspendedThreads) { - // This suspension was permitted, so assume progress is happening while it is suspended - makeProgress(getPausedEpoch()) - } - (this as Object).wait(10) // at most 10 ms - } - } - - @Synchronized - private fun takeContinuation(): Continuation? = - continuation.also { - this.result = null - this.continuation = null - } - - @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") - @Synchronized - fun abortWait() { - this.result = Result.failure(IllegalStateException("Aborted at the end of test")) - (this as Object).notifyAll() - } - - private val interceptor: CoroutineContext = object : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor { - override fun interceptContinuation(continuation: Continuation): Continuation = - Continuation(this) { - @Suppress("UNCHECKED_CAST") - resumeWith(it, continuation as Continuation) - } - } - - private val completion = Continuation(interceptor) { - resumeWith(it, null) - } - } - - // ---------- Implementation ---------- - - @Synchronized - private fun addSuspended(thread: TestThread): Int { - val index = suspendedThreads.indexOf(thread) - if (index >= 0) return index - suspendedThreads.add(thread) - return suspendedThreads.size - 1 - } - - @Synchronized - private fun removeSuspended(thread: TestThread) { - suspendedThreads.remove(thread) - } - - private fun getPausedEpoch(): Int { - while (true) { - val curStatus = status.get() - if (curStatus >= 0) return -1 // not paused - val thread = threads[curStatus.inv()] - val pausedEpoch = thread.pausedEpoch - if (curStatus == status.get()) return pausedEpoch - } - } - - internal fun step() { - val thread = Thread.currentThread() as? TestThread ?: return - thread.stepImpl() - } - - private fun resumeImpl() { - while (true) { - val curStatus = status.get() - if (curStatus == STATUS_DONE) return // done - check(curStatus < 0) - val thread = threads[curStatus.inv()] - performedResumes = thread.pausedEpoch - if (status.compareAndSet(curStatus, thread.pausedEpoch)) { - LockSupport.unpark(thread) - return - } - } - } - - private fun composeThreadName(threadName: String?): String { - if (threadName != null) return "$name-$threadName" - return name + "-${threads.size + 1}" - } - - private inner class Interceptor : AtomicOperationInterceptor() { - override fun beforeUpdate(ref: AtomicRef) = step() - override fun beforeUpdate(ref: AtomicInt) = step() - override fun beforeUpdate(ref: AtomicLong) = step() - override fun afterSet(ref: AtomicRef, newValue: T) = step() - override fun afterSet(ref: AtomicInt, newValue: Int) = step() - override fun afterSet(ref: AtomicLong, newValue: Long) = step() - override fun afterRMW(ref: AtomicRef, oldValue: T, newValue: T) = step() - override fun afterRMW(ref: AtomicInt, oldValue: Int, newValue: Int) = step() - override fun afterRMW(ref: AtomicLong, oldValue: Long, newValue: Long) = step() - override fun toString(): String = "LockFreedomTestEnvironment($name)" - } -} - -/** - * Manual pause for on-going lock-free operation in a specified piece of code. - * Use it for targeted debugging of specific places in code. It does nothing - * when invoked outside of test thread. - * - * **Don't use it in production code.** - */ -public fun pauseLockFreeOp() { - val thread = Thread.currentThread() as? LockFreedomTestEnvironment.TestThread ?: return - thread.pauseImpl() -} \ No newline at end of file diff --git a/atomicfu/src/jvmTest/kotlin/kotlinx/atomicfu/test/LockFreeQueueLFTest.kt b/atomicfu/src/jvmTest/kotlin/kotlinx/atomicfu/test/LockFreeQueueLFTest.kt deleted file mode 100644 index 5179638..0000000 --- a/atomicfu/src/jvmTest/kotlin/kotlinx/atomicfu/test/LockFreeQueueLFTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.test - -import kotlinx.atomicfu.LockFreedomTestEnvironment -import org.junit.Test -import java.util.* - -class LockFreeQueueLFTest : LockFreedomTestEnvironment("LockFreeQueueLFTest") { - val nEnqueuers = 2 - val nDequeuers = 2 - val nSeconds = 5 - - val queue = LockFreeQueue() - - @Test - fun testLockFreedom() { - repeat(nEnqueuers) { id -> - val rnd = Random() - testThread("Enqueue-$id") { - queue.enqueue(rnd.nextInt(1000)) - } - } - repeat(nDequeuers) { id -> - testThread("Dequeue-$id") { - queue.dequeue() - } - } - performTest(nSeconds) - } -} \ No newline at end of file diff --git a/atomicfu/src/jvmTest/kotlin/kotlinx/atomicfu/test/TraceLFTest.kt b/atomicfu/src/jvmTest/kotlin/kotlinx/atomicfu/test/TraceLFTest.kt deleted file mode 100644 index 32ea8d8..0000000 --- a/atomicfu/src/jvmTest/kotlin/kotlinx/atomicfu/test/TraceLFTest.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.test - -import kotlinx.atomicfu.* -import kotlin.test.Test - -class Counter { - private val t = Trace(64, TraceFormat { index, text -> - "$index: [${Thread.currentThread().name}] $text" - }) - private val a = atomic(0, t) - - fun inc(): Int { - t { "inc() invoked" } - val x = a.incrementAndGet() - t { "inc() = $x" } - return x - } - - internal fun get() = a.value -} - -class CounterDefaultAtomic { - private val a = atomic(0) - private val trace = Trace(64) - - fun inc(): Int { - trace { "inc() invoked" } - val x = a.incrementAndGet() - trace { "inc() = $x" } - return x - } - - internal fun get() = a.value -} - -class CounterLFTest : LockFreedomTestEnvironment("CounterLFTest") { - private val c = Counter() - private val c1 = CounterDefaultAtomic() - - @Test - fun testCounterDefault() { - repeat(10) { id -> - testThread ("Inc-$id") { - c1.inc() - } - } - repeat(2) { id -> - testThread("Get-$id") { - c1.get() - } - } - performTest(10) - println(c1.get()) - } - - @Test - fun testLockFreedom() { - repeat(10) { id -> - testThread("Inc-$id") { - c.inc() - } - } - repeat(2) { id -> - testThread("Get-$id") { - c.get() - } - } - performTest(10) - println(c.get()) - } -} - -- cgit v1.2.3 From 1374b220404611079abd1235fcbf5066fc77e087 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Fri, 22 Oct 2021 19:29:14 +0300 Subject: Update Kotlin to 1.6.0-RC --- atomicfu-gradle-plugin/build.gradle | 4 ++-- gradle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atomicfu-gradle-plugin/build.gradle b/atomicfu-gradle-plugin/build.gradle index 28091b6..58ee3a1 100644 --- a/atomicfu-gradle-plugin/build.gradle +++ b/atomicfu-gradle-plugin/build.gradle @@ -14,8 +14,8 @@ if (rootProject.ext.jvm_ir_enabled) { // Gradle plugin must be compiled targeting the same Kotlin version as used by Gradle kotlin.sourceSets.all { languageSettings { - apiVersion = "1.3" - languageVersion = "1.3" + apiVersion = "1.4" + languageVersion = "1.4" } } diff --git a/gradle.properties b/gradle.properties index b0398f6..5f46afc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ version=0.16.3-SNAPSHOT group=org.jetbrains.kotlinx -kotlin_version=1.5.30 +kotlin_version=1.6.0-RC asm_version=9.1 slf4j_version=1.8.0-alpha2 junit_version=4.12 -- cgit v1.2.3 From 0e8dec54104a18e007088e8c34d80a1fe31d60cb Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Fri, 22 Oct 2021 19:32:56 +0300 Subject: WA for the issue caused by different versions of kotlin-stdlib used in compile and runtime (#202) --- .../src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt | 2 +- .../src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt index 2201199..e4017ad 100644 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt @@ -22,7 +22,7 @@ class JsProjectTest : BaseKotlinGradleTest() { checkOutcomes(TaskOutcome.SUCCESS, *tasksToCheck) val testCompileClasspathFiles = projectDir.resolve("build/test_compile_classpath.txt") - .readLines().asSequence().flatMap { File(it).walk().filter(File::isFile) }.toHashSet() + .readLines().asSequence().flatMap { File(it).walk().filter { it.isFile } }.toHashSet() projectDir.resolve("build/classes/kotlin/main/js-simple.js").let { it.checkExists() diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt index 6dd7fa1..9820f86 100644 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt @@ -26,9 +26,9 @@ class MppProjectTest : BaseKotlinGradleTest() { fun checkPlatform(platform: String, fileInMainName: String) { val isJs = platform == "js" val testCompileClasspathFiles = projectDir.resolve("build/classpath/$platform/test_compile.txt") - .readLines().asSequence().flatMapTo(HashSet()) { File(it).walk().filter(File::isFile) } + .readLines().asSequence().flatMapTo(HashSet()) { File(it).walk().filter { it.isFile } } val testRuntimeClasspathFiles = if (isJs) emptySet() else projectDir.resolve("build/classpath/$platform/test_runtime.txt") - .readLines().asSequence().flatMapTo(HashSet()) { File(it).walk().filter(File::isFile) } + .readLines().asSequence().flatMapTo(HashSet()) { File(it).walk().filter { it.isFile } } projectDir.resolve("build/classes/kotlin/$platform/main/$fileInMainName").let { it.checkExists() -- cgit v1.2.3 From 9347bc66dc5ac1d660a8d0f0a58e42559df04114 Mon Sep 17 00:00:00 2001 From: fxshlein Date: Tue, 16 Nov 2021 09:41:30 +0100 Subject: Move variant to the correct plugin in the README (#208) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ebb127f..ca15a6f 100644 --- a/README.md +++ b/README.md @@ -207,8 +207,6 @@ which is then transformed to a regular `classes` directory to be used later by t ${project.build.directory}/classes-pre-atomicfu - - FU @@ -225,6 +223,8 @@ which is then transformed to a regular `classes` directory to be used later by t ${project.build.directory}/classes-pre-atomicfu + + FU -- cgit v1.2.3 From 8e489e72c6d8ab3c79b2187927aba48197024b39 Mon Sep 17 00:00:00 2001 From: Gerard de Leeuw Date: Tue, 16 Nov 2021 19:57:04 +0100 Subject: Add explicit module-info for JPMS compatibility (#201) * Add explicit module-info for JPMS compatibility * Kotlin 1.5.30 * Moved module-info compilation task to inline build script --- atomicfu/build.gradle | 63 +++++++++++++++++++++++++++++ atomicfu/src/jvmMain/java9/module-info.java | 6 +++ gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 atomicfu/src/jvmMain/java9/module-info.java diff --git a/atomicfu/build.gradle b/atomicfu/build.gradle index a516fb1..c44d969 100644 --- a/atomicfu/build.gradle +++ b/atomicfu/build.gradle @@ -324,6 +324,68 @@ tasks.withType(Test) { } } +task compileJavaModuleInfo(type: JavaCompile) { + def moduleName = "kotlinx.atomicfu" // this module's name + def compileKotlinJvm = kotlin.targets["jvm"].compilations["main"].compileKotlinTask + def sourceDir = file("src/jvmMain/java9/") + def targetDir = file("${compileKotlinJvm.destinationDir}/../java9/") + + // Use a Java 11 compiler for the module info. + javaCompiler.set(project.javaToolchains.compilerFor { languageVersion.set(JavaLanguageVersion.of(11)) }) + + // Always compile kotlin classes before the module descriptor. + dependsOn(compileKotlinJvm) + + // Add the module-info source file. + source(sourceDir) + + // Also add the module-info.java source file to the Kotlin compile task. + // The Kotlin compiler will parse and check module dependencies, + // but it currently won't compile to a module-info.class file. + // Note that module checking only works on JDK 9+, + // because the JDK built-in base modules are not available in earlier versions. + def javaVersion = compileKotlinJvm.kotlinJavaToolchain.javaVersion.getOrNull() + if (javaVersion?.isJava9Compatible() == true) { + logger.info("Module-info checking is enabled; $compileKotlinJvm is compiled using Java $javaVersion") + compileKotlinJvm.source(sourceDir) + } else { + logger.info("Module-info checking is disabled") + } + + // Set the task outputs and destination dir + outputs.dir(targetDir) + destinationDir = targetDir + + // Configure JVM compatibility + sourceCompatibility = JavaVersion.VERSION_1_9.toString() + targetCompatibility = JavaVersion.VERSION_1_9.toString() + + // Set the Java release version. + options.release.set(9) + + // Ignore warnings about using 'requires transitive' on automatic modules. + // not needed when compiling with recent JDKs, e.g. 17 + options.compilerArgs.add("-Xlint:-requires-transitive-automatic") + + // Patch the compileKotlinJvm output classes into the compilation so exporting packages works correctly. + options.compilerArgs.addAll(["--patch-module", "$moduleName=${compileKotlinJvm.destinationDir}"]) + + // Use the classpath of the compileKotlinJvm task. + // Also ensure that the module path is used instead of classpath. + classpath = compileKotlinJvm.classpath + modularity.inferModulePath.set(true) +} + +// Configure the JAR task so that it will include the compiled module-info class file. +tasks.named("jvmJar") { + manifest { + attributes(["Multi-Release": true]) + } + from(compileJavaModuleInfo) { + into("META-INF/versions/9/") + } +} + jvmTest { exclude "**/AtomicfuBytecodeTest*", "**/AtomicfuReferenceJsTest*", '**/TopLevelGeneratedDeclarationsReflectionTest.*', '**/SyntheticFUFieldsTest.*' // run them only for transformed code } @@ -342,3 +404,4 @@ afterEvaluate { tasks.matching { it.name == "generatePomFileForKotlinMultiplatformPublication" }.configureEach { dependsOn(tasks["generatePomFileForJvmPublication"]) } + diff --git a/atomicfu/src/jvmMain/java9/module-info.java b/atomicfu/src/jvmMain/java9/module-info.java new file mode 100644 index 0000000..e68d750 --- /dev/null +++ b/atomicfu/src/jvmMain/java9/module-info.java @@ -0,0 +1,6 @@ +module kotlinx.atomicfu { + requires transitive kotlin.stdlib; + + exports kotlinx.atomicfu; + exports kotlinx.atomicfu.locks; +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4c83d2a..703238f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-all.zip -- cgit v1.2.3 From a6da7fc8cf1c46fdaed7c8c3b4dfbcd1ebaa2328 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Tue, 16 Nov 2021 22:05:13 +0300 Subject: Update Kotlin to 1.6.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 5f46afc..ce5b5c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ version=0.16.3-SNAPSHOT group=org.jetbrains.kotlinx -kotlin_version=1.6.0-RC +kotlin_version=1.6.0 asm_version=9.1 slf4j_version=1.8.0-alpha2 junit_version=4.12 -- cgit v1.2.3 From 4b5fc434ede3a15b4084fb29894b5232c839aabc Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Tue, 16 Nov 2021 22:09:51 +0300 Subject: Fix Nexus repository link in the release checklist --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 6f5e71d..d603b5d 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -51,7 +51,7 @@ To release new `` of `kotlinx-atomicfu`: * Create a release named ``. * Cut & paste lines from [`CHANGES.md`](CHANGES.md) into description. -13. In [Sonatype](oss.sonatype.org/#stagingRepositories) admin interface: +13. In [Nexus](https://oss.sonatype.org/#stagingRepositories) admin interface: * Close the repository and wait for it to verify. * Release it. -- cgit v1.2.3 From 1c9f04c3d584e2e6d8ceab133abb8b19d3c0ff51 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Tue, 16 Nov 2021 22:27:50 +0300 Subject: Version 0.17.0 --- CHANGES.md | 6 ++++++ README.md | 6 +++--- gradle.properties | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 99cab30..ced0c22 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change log for kotlinx.atomicfu +# Version 0.17.0 + +* Update Kotlin to 1.6.0. +* Update ASM minimal api version to ASM7 (#203). +* Add explicit module-info for JPMS compatibility (#201). + # Version 0.16.3 * Kotlin is updated to 1.5.30. diff --git a/README.md b/README.md index ca15a6f..1b2eb81 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.16.3' + ext.atomicfu_version = '0.17.0' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -155,7 +155,7 @@ There are the following additional parameters (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.16.3' // set to null to turn-off auto dependencies + dependenciesVersion = '0.17.0' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation transformJs = true // set to false to turn off JS transformation variant = "FU" // JVM transformation variant: FU,VH, or BOTH @@ -169,7 +169,7 @@ Declare AtomicFU version: ```xml - 0.16.3 + 0.17.0 ``` diff --git a/gradle.properties b/gradle.properties index ce5b5c1..8b0fca2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.16.3-SNAPSHOT +version=0.17.0-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.6.0 -- cgit v1.2.3 From 4fd7b2e0700a492e1ec8fd03c105d6a368d1df6b Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Thu, 27 Jan 2022 17:06:44 +0300 Subject: Fix maven-central badge in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b2eb81..70c03d3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![JetBrains incubator project](https://jb.gg/badges/incubator.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -[![Download](https://api.bintray.com/packages/kotlin/kotlinx/kotlinx.atomicfu/images/download.svg) ](https://bintray.com/kotlin/kotlinx/kotlinx.atomicfu/_latestVersion) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.17.0/pom) The idiomatic way to use atomic operations in Kotlin. -- cgit v1.2.3 From c27c2eb75563a6bce9176df68892a1f91be4a7ec Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Tue, 1 Feb 2022 17:17:04 +0300 Subject: Update Kotlin/Js plugin name to 'org.jetbrains.kotlin.js' ('kotlin2js' is deprecated) --- .../kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index bb619a5..edb1849 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -43,7 +43,7 @@ private fun Project.configureDependencies() { ) dependencies.add(TEST_IMPLEMENTATION_CONFIGURATION, getAtomicfuDependencyNotation(Platform.JVM, version)) } - withPluginWhenEvaluatedDependencies("kotlin2js") { version -> + withPluginWhenEvaluatedDependencies("org.jetbrains.kotlin.js") { version -> dependencies.add( if (config.transformJs) COMPILE_ONLY_CONFIGURATION else IMPLEMENTATION_CONFIGURATION, getAtomicfuDependencyNotation(Platform.JS, version) @@ -70,9 +70,9 @@ private fun Project.configureTasks() { } } } - withPluginWhenEvaluated("kotlin2js") { + withPluginWhenEvaluated("org.jetbrains.kotlin.js") { if (config.transformJs) { - configureTransformTasks("compileTestKotlin2Js") { sourceSet, transformedDir, originalDir -> + configureTransformTasks("compileTestKotlinJs") { sourceSet, transformedDir, originalDir -> createJsTransformTask(sourceSet).configureJsTask( sourceSet.classesTaskName, transformedDir, -- cgit v1.2.3 From 67e9e77035db2682358ee96e94bcb96edba2828e Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Fri, 4 Feb 2022 13:25:53 +0300 Subject: Support of `org.jetbrains.kotlin.js` plugin in AtomicfuGradlePlugin (#218) * Fix for Kotlin/JS projects support in AtomicfuGradlePlugin * Ignore old atomicfu-gradle-plugin tests --- .../atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 134 ++++++++++----------- .../atomicfu/plugin/gradle/JsProjectTest.kt | 3 +- .../atomicfu/plugin/gradle/MppProjectTest.kt | 3 +- 3 files changed, 68 insertions(+), 72 deletions(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index edb1849..3aa6423 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -59,7 +59,7 @@ private fun Project.configureTasks() { val config = config withPluginWhenEvaluated("kotlin") { if (config.transformJvm) { - configureTransformTasks("compileTestKotlin") { sourceSet, transformedDir, originalDir -> + configureJvmTransformation("compileTestKotlin") { sourceSet, transformedDir, originalDir -> createJvmTransformTask(sourceSet).configureJvmTask( sourceSet.compileClasspath, sourceSet.classesTaskName, @@ -71,19 +71,10 @@ private fun Project.configureTasks() { } } withPluginWhenEvaluated("org.jetbrains.kotlin.js") { - if (config.transformJs) { - configureTransformTasks("compileTestKotlinJs") { sourceSet, transformedDir, originalDir -> - createJsTransformTask(sourceSet).configureJsTask( - sourceSet.classesTaskName, - transformedDir, - originalDir, - config - ) - } - } + if (config.transformJs) configureJsTransformation() } withPluginWhenEvaluated("kotlin-multiplatform") { - configureMultiplatformPluginTasks() + configureMultiplatformTransformation() } } @@ -153,69 +144,75 @@ private fun KotlinCommonOptions.addFriendPaths(friendPathsFileCollection: FileCo freeCompilerArgs = freeCompilerArgs + "$argName=${friendPathsFileCollection.joinToString(",")}" } -fun Project.configureMultiplatformPluginTasks() { - val originalDirsByCompilation = hashMapOf, FileCollection>() - val config = config +fun Project.configureJsTransformation() = + configureTransformationForTarget((kotlinExtension as KotlinJsProjectExtension).js()) + +fun Project.configureMultiplatformTransformation() = withKotlinTargets { target -> if (target.platformType == KotlinPlatformType.common || target.platformType == KotlinPlatformType.native) { return@withKotlinTargets // skip the common & native targets -- no transformation for them } - target.compilations.all compilations@{ compilation -> - val compilationType = compilation.name.compilationNameToType() - ?: return@compilations // skip unknown compilations - val classesDirs = compilation.output.classesDirs - // make copy of original classes directory - val originalClassesDirs: FileCollection = - project.files(classesDirs.from.toTypedArray()).filter { it.exists() } - originalDirsByCompilation[compilation] = originalClassesDirs - val transformedClassesDir = - project.buildDir.resolve("classes/atomicfu/${target.name}/${compilation.name}") - val transformTask = when (target.platformType) { - KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> { - if (!config.transformJvm) return@compilations // skip when transformation is turned off - project.createJvmTransformTask(compilation).configureJvmTask( - compilation.compileDependencyFiles, - compilation.compileAllTaskName, - transformedClassesDir, - originalClassesDirs, - config - ) - } - KotlinPlatformType.js -> { - if (!config.transformJs) return@compilations // skip when transformation is turned off - project.createJsTransformTask(compilation).configureJsTask( - compilation.compileAllTaskName, - transformedClassesDir, - originalClassesDirs, - config - ) - } - else -> error("Unsupported transformation platform '${target.platformType}'") - } - //now transformTask is responsible for compiling this source set into the classes directory - classesDirs.setFrom(transformedClassesDir) - classesDirs.builtBy(transformTask) - (tasks.findByName(target.artifactsTaskName) as? Jar)?.apply { - setupJarManifest(multiRelease = config.variant.toVariant() == Variant.BOTH) + configureTransformationForTarget(target) + } + +private fun Project.configureTransformationForTarget(target: KotlinTarget) { + val originalDirsByCompilation = hashMapOf, FileCollection>() + val config = config + target.compilations.all compilations@{ compilation -> + val compilationType = compilation.name.compilationNameToType() + ?: return@compilations // skip unknown compilations + val classesDirs = compilation.output.classesDirs + // make copy of original classes directory + val originalClassesDirs: FileCollection = + project.files(classesDirs.from.toTypedArray()).filter { it.exists() } + originalDirsByCompilation[compilation] = originalClassesDirs + val transformedClassesDir = + project.buildDir.resolve("classes/atomicfu/${target.name}/${compilation.name}") + val transformTask = when (target.platformType) { + KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> { + if (!config.transformJvm) return@compilations // skip when transformation is turned off + project.createJvmTransformTask(compilation).configureJvmTask( + compilation.compileDependencyFiles, + compilation.compileAllTaskName, + transformedClassesDir, + originalClassesDirs, + config + ) } - // test should compile and run against original production binaries - if (compilationType == CompilationType.TEST) { - val mainCompilation = - compilation.target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) - val originalMainClassesDirs = project.files( - // use Callable because there is no guarantee that main is configured before test - Callable { originalDirsByCompilation[mainCompilation]!! } + KotlinPlatformType.js -> { + if (!config.transformJs) return@compilations // skip when transformation is turned off + project.createJsTransformTask(compilation).configureJsTask( + compilation.compileAllTaskName, + transformedClassesDir, + originalClassesDirs, + config ) + } + else -> error("Unsupported transformation platform '${target.platformType}'") + } + //now transformTask is responsible for compiling this source set into the classes directory + classesDirs.setFrom(transformedClassesDir) + classesDirs.builtBy(transformTask) + (tasks.findByName(target.artifactsTaskName) as? Jar)?.apply { + setupJarManifest(multiRelease = config.variant.toVariant() == Variant.BOTH) + } + // test should compile and run against original production binaries + if (compilationType == CompilationType.TEST) { + val mainCompilation = + compilation.target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) + val originalMainClassesDirs = project.files( + // use Callable because there is no guarantee that main is configured before test + Callable { originalDirsByCompilation[mainCompilation]!! } + ) - (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractCompile)?.classpath = - originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs + (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractCompile)?.classpath = + originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs - (tasks.findByName("${target.name}${compilation.name.capitalize()}") as? Test)?.classpath = - originalMainClassesDirs + (compilation as KotlinCompilationToRunnableFiles).runtimeDependencyFiles - mainCompilation.output.classesDirs + (tasks.findByName("${target.name}${compilation.name.capitalize()}") as? Test)?.classpath = + originalMainClassesDirs + (compilation as KotlinCompilationToRunnableFiles).runtimeDependencyFiles - mainCompilation.output.classesDirs - compilation.compileKotlinTask.doFirst { - compilation.kotlinOptions.addFriendPaths(originalMainClassesDirs) - } + compilation.compileKotlinTask.doFirst { + compilation.kotlinOptions.addFriendPaths(originalMainClassesDirs) } } } @@ -285,7 +282,7 @@ fun Project.configureMultiplatformPluginDependencies(version: String) { } } -fun Project.configureTransformTasks( +fun Project.configureJvmTransformation( testTaskName: String, createTransformTask: (sourceSet: SourceSet, transformedDir: File, originalDir: FileCollection) -> Task ) { @@ -348,9 +345,6 @@ fun Project.createJsTransformTask(compilation: KotlinCompilation<*>): AtomicFUTr fun Project.createJvmTransformTask(sourceSet: SourceSet): AtomicFUTransformTask = tasks.create(sourceSet.getTaskName("transform", "atomicfuClasses"), AtomicFUTransformTask::class.java) -fun Project.createJsTransformTask(sourceSet: SourceSet): AtomicFUTransformJsTask = - tasks.create(sourceSet.getTaskName("transform", "atomicfuJsFiles"), AtomicFUTransformJsTask::class.java) - fun AtomicFUTransformTask.configureJvmTask( classpath: FileCollection, classesTaskName: String, diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt index e4017ad..72c1157 100644 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt @@ -5,10 +5,11 @@ package kotlinx.atomicfu.plugin.gradle import org.gradle.testkit.runner.TaskOutcome -import org.junit.Test +import org.junit.* import java.io.File class JsProjectTest : BaseKotlinGradleTest() { + @Ignore @Test fun testKotlin2JsPlugin() = project("js-simple") { val tasksToCheck = arrayOf( diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt index 9820f86..1e87645 100644 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt @@ -5,10 +5,11 @@ package kotlinx.atomicfu.plugin.gradle import org.gradle.testkit.runner.TaskOutcome -import org.junit.Test +import org.junit.* import java.io.File class MppProjectTest : BaseKotlinGradleTest() { + @Ignore @Test fun testKotlinMultiplatformPlugin() = project("mpp-simple") { val tasksToCheck = arrayOf( -- cgit v1.2.3 From fd1131433f120b024c0e8e95b3d6fcc96863dbfe Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Mon, 7 Feb 2022 12:57:50 +0300 Subject: Fixed configuration cache bug caused by capturing compilation object into lambda. (#216) Fixes #212 --- .../main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 3aa6423..4617f18 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -211,8 +211,9 @@ private fun Project.configureTransformationForTarget(target: KotlinTarget) { (tasks.findByName("${target.name}${compilation.name.capitalize()}") as? Test)?.classpath = originalMainClassesDirs + (compilation as KotlinCompilationToRunnableFiles).runtimeDependencyFiles - mainCompilation.output.classesDirs + val kotlinOptions = compilation.kotlinOptions compilation.compileKotlinTask.doFirst { - compilation.kotlinOptions.addFriendPaths(originalMainClassesDirs) + kotlinOptions.addFriendPaths(originalMainClassesDirs) } } } -- cgit v1.2.3 From 25bf2042a04f9681c39a3d2a504e82f640672b64 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Mon, 7 Feb 2022 16:15:19 +0300 Subject: New atomicfu-gradle-plugin tests (#217) --- .../atomicfu/plugin/gradle/BaseKotlinGradleTest.kt | 29 ----- .../atomicfu/plugin/gradle/EmptyProjectTest.kt | 14 --- .../atomicfu/plugin/gradle/JsProjectTest.kt | 44 ------- .../atomicfu/plugin/gradle/JvmProjectTest.kt | 63 ---------- .../atomicfu/plugin/gradle/MppProjectTest.kt | 56 --------- .../kotlinx/atomicfu/plugin/gradle/Project.kt | 97 --------------- .../atomicfu/plugin/gradle/internal/Assert.kt | 32 +++++ .../atomicfu/plugin/gradle/internal/TestDsl.kt | 131 +++++++++++++++++++++ .../atomicfu/plugin/gradle/internal/utils.kt | 13 ++ .../plugin/gradle/test/BaseKotlinGradleTest.kt | 46 ++++++++ .../atomicfu/plugin/gradle/test/JsProjectTest.kt | 52 ++++++++ .../atomicfu/plugin/gradle/test/JvmProjectTest.kt | 56 +++++++++ .../atomicfu/plugin/gradle/test/MppProjectTest.kt | 58 +++++++++ .../kotlin/kotlinx/atomicfu/plugin/gradle/utils.kt | 36 ------ .../src/test/resources/projects/empty/build.gradle | 10 -- .../test/resources/projects/js-simple/build.gradle | 18 --- .../projects/js-simple/js-simple.gradle.kts | 38 ++++++ .../projects/js-simple/settings.gradle.kts | 1 + .../resources/projects/jvm-simple/build.gradle | 30 ----- .../projects/jvm-simple/jvm-simple.gradle.kts | 41 +++++++ .../projects/jvm-simple/settings.gradle.kts | 1 + .../resources/projects/mpp-simple/build.gradle | 73 ------------ .../projects/mpp-simple/mpp-simple.gradle.kts | 90 ++++++++++++++ .../projects/mpp-simple/settings.gradle.kts | 1 + 24 files changed, 560 insertions(+), 470 deletions(-) delete mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/BaseKotlinGradleTest.kt delete mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/EmptyProjectTest.kt delete mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt delete mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JvmProjectTest.kt delete mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt delete mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt create mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/Assert.kt create mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt create mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/utils.kt create mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt create mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt create mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt create mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt delete mode 100644 atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/utils.kt delete mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/empty/build.gradle delete mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/js-simple/build.gradle create mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts create mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/js-simple/settings.gradle.kts delete mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/build.gradle create mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts create mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/settings.gradle.kts delete mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/build.gradle create mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts create mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/settings.gradle.kts diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/BaseKotlinGradleTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/BaseKotlinGradleTest.kt deleted file mode 100644 index b81a0c9..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/BaseKotlinGradleTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.internal.impldep.com.google.common.io.Files -import org.junit.After -import org.junit.Before -import java.io.File - -abstract class BaseKotlinGradleTest { - private lateinit var workingDir: File - - fun project(name: String, suffix: String = "", fn: Project.() -> Unit) { - workingDir = File("build${File.separator}test-$name$suffix").absoluteFile - workingDir.deleteRecursively() - workingDir.mkdirs() - val testResources = File("src/test/resources") - val originalProjectDir = testResources.resolve("projects/$name").apply { checkExists() } - val projectDir = workingDir.resolve(name).apply { mkdirs() } - originalProjectDir.listFiles().forEach { it.copyRecursively(projectDir.resolve(it.name)) } - - // Add an empty setting.gradle - projectDir.resolve("settings.gradle").writeText("// this file is intentionally left empty") - - Project(projectDir = projectDir).fn() - } -} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/EmptyProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/EmptyProjectTest.kt deleted file mode 100644 index b542f2b..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/EmptyProjectTest.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.junit.Test - -class EmptyProjectTest : BaseKotlinGradleTest() { - @Test - fun testEmpty() = project("empty") { - build("build") {} - } -} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt deleted file mode 100644 index 72c1157..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JsProjectTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.testkit.runner.TaskOutcome -import org.junit.* -import java.io.File - -class JsProjectTest : BaseKotlinGradleTest() { - @Ignore - @Test - fun testKotlin2JsPlugin() = project("js-simple") { - val tasksToCheck = arrayOf( - ":compileKotlin2Js", - ":compileTestKotlin2Js", - ":transformAtomicfuJsFiles", - ":transformTestAtomicfuJsFiles" - ) - - build("build") { - checkOutcomes(TaskOutcome.SUCCESS, *tasksToCheck) - - val testCompileClasspathFiles = projectDir.resolve("build/test_compile_classpath.txt") - .readLines().asSequence().flatMap { File(it).walk().filter { it.isFile } }.toHashSet() - - projectDir.resolve("build/classes/kotlin/main/js-simple.js").let { - it.checkExists() - check(it in testCompileClasspathFiles) { "Original '$it' is missing from test compile classpath" } - // todo: check test runtime classpath when js test tasks are supported in plugin - } - - projectDir.resolve("build/classes/atomicfu/main/js-simple.js").let { - it.checkExists() - check(it !in testCompileClasspathFiles) { "Transformed '$it' is present in test compile classpath" } - } - } - - build("build") { - checkOutcomes(TaskOutcome.UP_TO_DATE, *tasksToCheck) - } - } -} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JvmProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JvmProjectTest.kt deleted file mode 100644 index e017f05..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/JvmProjectTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.testkit.runner.TaskOutcome -import org.junit.Test -import java.io.File - -class JvmProjectTest : BaseKotlinGradleTest() { - @Test - fun testKotlinPlugin() = - project("jvm-simple") { - doSimpleTest() - } - - @Test - fun testKotlinPlatformJvmPlugin() = - project("jvm-simple", "-platform") { - projectDir.resolve("build.gradle").modify { - it.checkedReplace("apply plugin: 'kotlin'", "apply plugin: 'kotlin-platform-jvm'") - } - doSimpleTest() - } - - private fun Project.doSimpleTest() { - val tasksToCheck = arrayOf( - ":compileKotlin", - ":compileTestKotlin", - ":transformAtomicfuClasses", - ":transformTestAtomicfuClasses" - ) - - build("build") { - checkOutcomes(TaskOutcome.SUCCESS, *tasksToCheck) - - val testCompileClasspathFiles = filesFrom("build/test_compile_classpath.txt") - val testRuntimeClasspathFiles = filesFrom("build/test_runtime_classpath.txt") - - projectDir.resolve("build/classes/kotlin/main/IntArithmetic.class").let { - it.checkExists() - check(it in testCompileClasspathFiles) { "Original '$it' is missing from test compile classpath" } - check(it in testRuntimeClasspathFiles) { "Original '$it' is missing from test runtime classpath" } - } - - projectDir.resolve("build/classes/atomicfu/main/IntArithmetic.class").let { - it.checkExists() - check(it !in testCompileClasspathFiles) { "Transformed '$it' is present in test compile classpath" } - check(it !in testRuntimeClasspathFiles) { "Transformed '$it' is present in test runtime classpath" } - } - } - - build("build") { - checkOutcomes(TaskOutcome.UP_TO_DATE, *tasksToCheck) - } - } - - private fun Project.filesFrom(name: String) = projectDir.resolve(name) - .readLines().asSequence().flatMap { listFiles(it) }.toHashSet() - - private fun listFiles(dir: String): Sequence = File(dir).walk().filter { it.isFile } -} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt deleted file mode 100644 index 1e87645..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/MppProjectTest.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.testkit.runner.TaskOutcome -import org.junit.* -import java.io.File - -class MppProjectTest : BaseKotlinGradleTest() { - @Ignore - @Test - fun testKotlinMultiplatformPlugin() = project("mpp-simple") { - val tasksToCheck = arrayOf( - ":compileKotlinJvm", - ":compileTestKotlinJvm", - ":transformJvmMainAtomicfu", - ":transformJvmTestAtomicfu", - ":compileKotlinJs", - ":transformJsMainAtomicfu" - ) - - build("build") { - checkOutcomes(TaskOutcome.SUCCESS, *tasksToCheck) - - fun checkPlatform(platform: String, fileInMainName: String) { - val isJs = platform == "js" - val testCompileClasspathFiles = projectDir.resolve("build/classpath/$platform/test_compile.txt") - .readLines().asSequence().flatMapTo(HashSet()) { File(it).walk().filter { it.isFile } } - val testRuntimeClasspathFiles = if (isJs) emptySet() else projectDir.resolve("build/classpath/$platform/test_runtime.txt") - .readLines().asSequence().flatMapTo(HashSet()) { File(it).walk().filter { it.isFile } } - - projectDir.resolve("build/classes/kotlin/$platform/main/$fileInMainName").let { - it.checkExists() - check(it in testCompileClasspathFiles) { "Original '$it' is missing from $platform test compile classpath" } - if (!isJs) check(it in testRuntimeClasspathFiles) { "Original '$it' is missing from $platform test runtime classpath" } - } - - projectDir.resolve("build/classes/atomicfu/jvm/main/IntArithmetic.class").let { - it.checkExists() - check(it !in testCompileClasspathFiles) { "Transformed '$it' is present in $platform test compile classpath" } - if (!isJs) check(it !in testRuntimeClasspathFiles) { "Transformed '$it' is present in $platform test runtime classpath" } - } - - } - - checkPlatform("jvm", "IntArithmetic.class") - checkPlatform("js", "mpp-simple.js") - } - - build("build") { - checkOutcomes(TaskOutcome.UP_TO_DATE, *tasksToCheck) - } - } -} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt deleted file mode 100644 index f2e06a9..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/Project.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.testkit.runner.BuildResult -import org.gradle.testkit.runner.GradleRunner -import java.io.File - -class Project(val projectDir: File) { - init { - projectDir.resolve("build.gradle").modify { - buildScript + "\n\n" + it - } - } - - private var isDebug = false - private var printStdout = false - - @Deprecated("Should be used for debug only!") - @Suppress("unused") - fun debug() { - isDebug = true - } - - /** - * Redirects Gradle runner output to stdout. Useful for debugging. - */ - @Deprecated("Should be used for debug only!") - @Suppress("unused") - fun printStdout() { - printStdout = true - } - - fun gradle(vararg tasks: String): GradleRunner = - GradleRunner.create() - .withDebug(isDebug) - .withProjectDir(projectDir) - .withArguments(*(defaultArguments() + tasks)) - .run { - if (printStdout) { - forwardStdOutput(System.out.bufferedWriter()) - } else { - this - } - } - - fun build(vararg tasks: String, fn: BuildResult.() -> Unit = {}) { - val gradle = gradle(*tasks) - val buildResult = gradle.build() - buildResult.fn() - } - - @Suppress("unused") - fun buildAndFail(vararg tasks: String, fn: BuildResult.() -> Unit = {}) { - val gradle = gradle(*tasks) - val buildResult = gradle.buildAndFail() - buildResult.fn() - } - - private fun defaultArguments(): Array = - arrayOf("--stacktrace") - - companion object { - private fun readFileList(fileName: String): String { - val resource = Project::class.java.classLoader.getResource(fileName) - ?: throw IllegalStateException("Could not find resource '$fileName'") - val files = File(resource.toURI()) - .readLines() - .map { File(it).absolutePath.replace("\\", "\\\\") } // escape backslashes in Windows paths - return files.joinToString(", ") { "'$it'" } - } - - private val buildScript = run { - """ - buildscript { - dependencies { - classpath files(${readFileList("plugin-classpath.txt")}) - } - } - - repositories { - jcenter() - mavenCentral() - maven { url 'https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev' } - maven { url 'https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev' } - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - } - - def atomicfuJvm = files(${readFileList("atomicfu-jvm.txt")}) - def atomicfuJs = files(${readFileList("atomicfu-js.txt")}) - def atomicfuMetadata = files(${readFileList("atomicfu-metadata.txt")}) - """.trimIndent() - } - } -} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/Assert.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/Assert.kt new file mode 100644 index 0000000..f55e38a --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/Assert.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2016-2022 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.atomicfu.plugin.gradle.internal + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome +import kotlin.test.assertEquals + +/** + * Helper `fun` for asserting a [TaskOutcome] to be equal to [TaskOutcome.SUCCESS] + */ +internal fun BuildResult.assertTaskSuccess(task: String) { + assertTaskOutcome(TaskOutcome.SUCCESS, task) +} + +/** + * Helper `fun` for asserting a [TaskOutcome] to be equal to [TaskOutcome.FAILED] + */ +internal fun BuildResult.assertTaskFailure(task: String) { + assertTaskOutcome(TaskOutcome.FAILED, task) +} + +internal fun BuildResult.assertTaskUpToDate(task: String) { + assertTaskOutcome(TaskOutcome.UP_TO_DATE, task) +} + +private fun BuildResult.assertTaskOutcome(taskOutcome: TaskOutcome, taskName: String) { + assertEquals(taskOutcome, task(taskName)?.outcome) +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt new file mode 100644 index 0000000..2a51f1b --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2016-2022 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.atomicfu.plugin.gradle.internal + +import kotlinx.atomicfu.plugin.gradle.test.* +import org.gradle.testkit.runner.* +import java.io.* + +internal fun BaseKotlinGradleTest.test(fn: BaseKotlinScope.() -> Unit): GradleRunner { + val baseKotlinScope = BaseKotlinScope() + fn(baseKotlinScope) + + baseKotlinScope.files.forEach { scope -> + val fileWriteTo = rootProjectDir.resolve(scope.filePath) + .apply { + parentFile.mkdirs() + createNewFile() + } + + scope.files.forEach { + val fileContent = readFileList(it) + fileWriteTo.appendText(fileContent) + } + } + + return GradleRunner.create() + .withProjectDir(rootProjectDir) + .withArguments(baseKotlinScope.runner.arguments) + .withPluginClasspath() + .addPluginTestRuntimeClasspath() +} + +/** + * same as [file][FileContainer.file], but prepends "src/${sourceSet}/kotlin" before given `classFileName` + */ +internal fun FileContainer.kotlin(classFileName: String, sourceSet: String = "main", fn: AppendableScope.() -> Unit) { + require(classFileName.endsWith(".kt")) { + "ClassFileName must end with '.kt'" + } + + val fileName = "src/${sourceSet}/kotlin/$classFileName" + file(fileName, fn) +} + +/** + * Shortcut for creating a `build.gradle.kts` by using [file][FileContainer.file] + */ +internal fun FileContainer.buildGradleKts(fn: AppendableScope.() -> Unit) { + val fileName = "build.gradle.kts" + file(fileName, fn) +} + +/** + * Shortcut for creating a `settings.gradle.kts` by using [file][FileContainer.file] + */ +internal fun FileContainer.settingsGradleKts(fn: AppendableScope.() -> Unit) { + val fileName = "settings.gradle.kts" + file(fileName, fn) +} + +/** + * Declares a directory with the given [dirName] inside the current container. + * All calls creating files within this scope will create the files nested in this directory. + * + * Note that it is valid to call this method multiple times at the same level with the same [dirName]. + * Files declared within 2 independent calls to [dir] will be added to the same directory. + */ +internal fun FileContainer.dir(dirName: String, fn: DirectoryScope.() -> Unit) { + DirectoryScope(dirName, this).fn() +} + +internal fun BaseKotlinScope.runner(fn: Runner.() -> Unit) { + val runner = Runner() + fn(runner) + + this.runner = runner +} + +internal fun AppendableScope.resolve(fileName: String) { + this.files.add(fileName) +} + +internal interface FileContainer { + fun file(fileName: String, fn: AppendableScope.() -> Unit) +} + +internal class BaseKotlinScope : FileContainer { + var files: MutableList = mutableListOf() + var runner: Runner = Runner() + + override fun file(fileName: String, fn: AppendableScope.() -> Unit) { + val appendableScope = AppendableScope(fileName) + fn(appendableScope) + files.add(appendableScope) + } +} + +internal class DirectoryScope( + val dirPath: String, + val parent: FileContainer +): FileContainer { + + override fun file(fileName: String, fn: AppendableScope.() -> Unit) { + parent.file("$dirPath/$fileName", fn) + } +} + +internal class AppendableScope(val filePath: String) { + val files: MutableList = mutableListOf() +} + +internal class Runner { + val arguments: MutableList = mutableListOf() +} + +internal fun readFileList(fileName: String): String = + getFile(fileName).readText() + +internal fun getFile(fileName: String): File { + val resource = BaseKotlinGradleTest::class.java.classLoader.getResource(fileName) + ?: throw IllegalStateException("Could not find resource '$fileName'") + return File(resource.toURI()) +} + +internal fun GradleRunner.addPluginTestRuntimeClasspath() = apply { + val pluginClasspath = getFile("plugin-classpath.txt").readLines().map { File(it) } + withPluginClasspath(pluginClasspath) +} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/utils.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/utils.kt new file mode 100644 index 0000000..49856f2 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/utils.kt @@ -0,0 +1,13 @@ +package kotlinx.atomicfu.plugin.gradle.internal + +import java.io.* +import kotlin.test.* + +fun File.checkExists() { + assertTrue(exists(), "File does not exist: $canonicalPath") +} + +fun File.filesFrom(relative: String) = resolve(relative) + .readLines().asSequence().flatMap { listFiles(it) }.toHashSet() + +fun listFiles(dir: String): Sequence = File(dir).walk().filter { it.isFile } \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt new file mode 100644 index 0000000..f6ec8ef --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.atomicfu.plugin.gradle.test + +import kotlinx.atomicfu.plugin.gradle.internal.* +import java.io.File + +open class BaseKotlinGradleTest(private val projectName: String) { + internal val rootProjectDir: File + + init { + rootProjectDir = File("build${File.separator}test-$projectName").absoluteFile + rootProjectDir.deleteRecursively() + rootProjectDir.mkdirs() + } + + fun checkJvmCompilationClasspath(originalClassFile: String, transformedClassFile: String) { + // check that test compilation depends on transformed main sources + val testCompileClasspathFiles = rootProjectDir.filesFrom("build/test_compile_jvm_classpath.txt") + val testRuntimeClasspathFiles = rootProjectDir.filesFrom("build/test_runtime_jvm_classpath.txt") + + rootProjectDir.resolve(transformedClassFile).let { + it.checkExists() + check(it in testCompileClasspathFiles) { "Original '$it' is missing from test compile classpath" } + check(it in testRuntimeClasspathFiles) { "Original '$it' is missing from test runtime classpath" } + } + + rootProjectDir.resolve(originalClassFile).let { + it.checkExists() + check(it !in testCompileClasspathFiles) { "Transformed '$it' is present in test compile classpath" } + check(it !in testRuntimeClasspathFiles) { "Transformed '$it' is present in test runtime classpath" } + } + } + + fun checkJsCompilationClasspath() { + // check that test compilation depends on transformed main sources + val testCompileClasspathFiles = rootProjectDir.filesFrom("build/test_compile_js_classpath.txt") + + rootProjectDir.resolve("build/classes/atomicfu/js/main/$projectName.js").let { + it.checkExists() + check(it in testCompileClasspathFiles) { "Original '$it' is missing from test compile classpath" } + } + } +} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt new file mode 100644 index 0000000..8630f70 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt @@ -0,0 +1,52 @@ +package kotlinx.atomicfu.plugin.gradle.test + +import kotlinx.atomicfu.plugin.gradle.internal.* +import kotlinx.atomicfu.plugin.gradle.internal.BaseKotlinScope +import org.junit.Test + +class JsProjectTest : BaseKotlinGradleTest("js-simple") { + private fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/js-simple/js-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/js-simple/settings.gradle.kts") + } + dir("src/main/kotlin") {} + kotlin("IntArithmetic.kt", "main") { + resolve("projects/js-simple/src/main/kotlin/IntArithmetic.kt") + } + dir("src/test/kotlin") {} + kotlin("ArithmeticTest.kt", "test") { + resolve("projects/js-simple/src/test/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPlugin() { + val runner = test { + createProject() + runner { + arguments.add(":build") + } + } + val tasksToCheck = arrayOf( + ":compileKotlinJs", + ":transformJsMainAtomicfu", + ":compileTestKotlinJs", + ":transformJsTestAtomicfu" + ) + runner.build().apply { + tasksToCheck.forEach { + assertTaskSuccess(it) + } + } + // check that task outcomes are cached for the second build + runner.build().apply { + tasksToCheck.forEach { + assertTaskUpToDate(it) + } + } + checkJsCompilationClasspath() + } +} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt new file mode 100644 index 0000000..838d091 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt @@ -0,0 +1,56 @@ +package kotlinx.atomicfu.plugin.gradle.test + +import kotlinx.atomicfu.plugin.gradle.internal.* +import kotlinx.atomicfu.plugin.gradle.internal.BaseKotlinScope +import org.junit.Test + +class JvmProjectTest : BaseKotlinGradleTest("jvm-simple") { + + private fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/jvm-simple/jvm-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/jvm-simple/settings.gradle.kts") + } + dir("src/main/kotlin") {} + kotlin("IntArithmetic.kt", "main") { + resolve("projects/jvm-simple/src/main/kotlin/IntArithmetic.kt") + } + dir("src/test/kotlin") {} + kotlin("ArithmeticTest.kt", "test") { + resolve("projects/jvm-simple/src/test/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPlugin() { + val runner = test { + createProject() + runner { + arguments.add(":build") + } + } + val tasksToCheck = arrayOf( + ":compileKotlin", + ":transformAtomicfuClasses", + ":compileTestKotlin", + ":transformTestAtomicfuClasses" + ) + runner.build().apply { + tasksToCheck.forEach { + assertTaskSuccess(it) + } + } + // check that task outcomes are cached for the second build + runner.build().apply { + tasksToCheck.forEach { + assertTaskUpToDate(it) + } + } + checkJvmCompilationClasspath( + originalClassFile = "build/classes/kotlin/main/IntArithmetic.class", + transformedClassFile = "build/classes/atomicfu/main/IntArithmetic.class" + ) + } +} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt new file mode 100644 index 0000000..cbeefa2 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt @@ -0,0 +1,58 @@ +package kotlinx.atomicfu.plugin.gradle.test + +import kotlinx.atomicfu.plugin.gradle.internal.* +import org.junit.* + +class MppProjectTest : BaseKotlinGradleTest("mpp-simple") { + private fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/mpp-simple/mpp-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/mpp-simple/settings.gradle.kts") + } + dir("src/commonMain/kotlin") {} + kotlin("IntArithmetic.kt", "commonMain") { + resolve("projects/mpp-simple/src/commonMain/kotlin/IntArithmetic.kt") + } + dir("src/commonTest/kotlin") {} + kotlin("ArithmeticTest.kt", "commonTest") { + resolve("projects/mpp-simple/src/commonTest/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPlugin() { + val runner = test { + createProject() + runner { + arguments.add(":build") + } + } + val tasksToCheck = arrayOf( + ":compileKotlinJvm", + ":compileTestKotlinJvm", + ":transformJvmMainAtomicfu", + ":transformJvmTestAtomicfu", + ":compileKotlinJs", + ":transformJsMainAtomicfu" + ) + runner.build().apply { + tasksToCheck.forEach { + assertTaskSuccess(it) + } + } + // check that task outcomes are cached for the second build + runner.build().apply { + tasksToCheck.forEach { + assertTaskUpToDate(it) + } + } + + checkJvmCompilationClasspath( + originalClassFile = "build/classes/kotlin/jvm/main/IntArithmetic.class", + transformedClassFile = "build/classes/atomicfu/jvm/main/IntArithmetic.class" + ) + checkJsCompilationClasspath() + } +} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/utils.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/utils.kt deleted file mode 100644 index 2a8d0f7..0000000 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/utils.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.atomicfu.plugin.gradle - -import org.gradle.testkit.runner.BuildResult -import org.gradle.testkit.runner.TaskOutcome -import java.io.File -import kotlin.test.assertTrue - -fun BuildResult.checkOutcomes(expected: TaskOutcome, vararg tasks: String) { - val unexpectedOutcomes = tasks - .map { it to task(it)?.outcome } - .filter { (_, outcome) -> outcome != expected } - if (unexpectedOutcomes.isNotEmpty()) { - throw AssertionError("Unexpected outcomes for tasks." + - "\nExpected: $expected." + - "\nGot:" + - "\n${unexpectedOutcomes.joinToString("\n") { (task, outcome) -> "* $task -> $outcome" }}") - - } -} - -fun File.checkExists() { - assertTrue(exists(), "File does not exist: $canonicalPath") -} - -fun File.modify(fn: (String) -> String) { - writeText(fn(readText())) -} - -fun String.checkedReplace(oldValue: String, newValue: String, ignoreCase: Boolean = false): String { - check(contains(oldValue, ignoreCase)) { "String must contain '$oldValue'" } - return replace(oldValue, newValue, ignoreCase) -} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/empty/build.gradle b/atomicfu-gradle-plugin/src/test/resources/projects/empty/build.gradle deleted file mode 100644 index f4add41..0000000 --- a/atomicfu-gradle-plugin/src/test/resources/projects/empty/build.gradle +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -apply plugin: 'kotlinx-atomicfu' -apply plugin: 'base' - -repositories { - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } -} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/build.gradle b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/build.gradle deleted file mode 100644 index 31dbec6..0000000 --- a/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -apply plugin: 'kotlinx-atomicfu' -apply plugin: 'kotlin2js' - -dependencies { - compileOnly atomicfuJs - testRuntime atomicfuJs - - compile 'org.jetbrains.kotlin:kotlin-stdlib-js' - testCompile 'org.jetbrains.kotlin:kotlin-test-js' -} - -compileTestKotlin2Js.doLast { - file("$buildDir/test_compile_classpath.txt").text = classpath.join("\n") -} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts new file mode 100644 index 0000000..a284a87 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts @@ -0,0 +1,38 @@ +import kotlinx.atomicfu.plugin.gradle.* + +buildscript { + dependencies { + classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.0") + } +} + +plugins { + kotlin("js") version "1.6.0" +} + +apply(plugin = "kotlinx-atomicfu") + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + implementation(kotlin("stdlib-js")) + implementation(kotlin("test-junit")) + implementation("org.jetbrains.kotlin:kotlin-test-js") +} + +kotlin { + js { + nodejs() + } + + tasks.named("compileTestKotlinJs") { + doLast { + file("$buildDir/test_compile_js_classpath.txt").writeText( + target.compilations["test"].compileDependencyFiles.joinToString("\n") + ) + } + } +} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/settings.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/settings.gradle.kts new file mode 100644 index 0000000..bd39e74 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "js-simple" \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/build.gradle b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/build.gradle deleted file mode 100644 index 7e21215..0000000 --- a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -apply plugin: 'kotlinx-atomicfu' -apply plugin: 'kotlin' - -// This flag is enabled to be able using JVM IR compiled dependencies (when build is ran with -Penable_jvm_ir) -kotlin.target.compilations.all { - kotlinOptions.freeCompilerArgs += '-Xallow-jvm-ir-dependencies' -} - -dependencies { - compileOnly atomicfuJvm - testRuntime atomicfuJvm - - compile 'org.jetbrains.kotlin:kotlin-stdlib' - - testCompile 'org.jetbrains.kotlin:kotlin-test' - testCompile 'org.jetbrains.kotlin:kotlin-test-junit' - testCompile 'junit:junit:4.12' -} - -compileTestKotlin.doLast { - file("$buildDir/test_compile_classpath.txt").text = classpath.join("\n") -} - -test.doLast { - file("$buildDir/test_runtime_classpath.txt").text = classpath.join("\n") -} \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts new file mode 100644 index 0000000..fa1f4d8 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts @@ -0,0 +1,41 @@ +import org.gradle.api.tasks.compile.* +import org.jetbrains.kotlin.gradle.plugin.* + +buildscript { + dependencies { + classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.0") + } +} + +plugins { + kotlin("jvm") version "1.6.0" +} + +apply(plugin = "kotlinx-atomicfu") + +repositories { + mavenCentral() +} + +dependencies { + implementation(kotlin("stdlib")) + implementation(kotlin("test-junit")) +} + +kotlin { + tasks.compileTestKotlin { + doLast { + file("$buildDir/test_compile_jvm_classpath.txt").writeText( + target.compilations["test"].compileDependencyFiles.joinToString("\n") + ) + } + } + + tasks.test { + doLast { + file("$buildDir/test_runtime_jvm_classpath.txt").writeText( + (target.compilations["test"] as KotlinCompilationToRunnableFiles<*>).runtimeDependencyFiles.joinToString("\n") + ) + } + } +} diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/settings.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/settings.gradle.kts new file mode 100644 index 0000000..2f5327f --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "jvm-simple" \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/build.gradle b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/build.gradle deleted file mode 100644 index fc95366..0000000 --- a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/build.gradle +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -apply plugin: 'kotlinx-atomicfu' -apply plugin: 'kotlin-multiplatform' - -kotlin { - // This flag is enabled to be able using JVM IR compiled dependencies (when build is ran with -Penable_jvm_ir) - jvm() { - compilations.all { - kotlinOptions.freeCompilerArgs += '-Xallow-jvm-ir-dependencies' - } - } - js() - - sourceSets { - commonMain.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib-common' - compileOnly atomicfuMetadata - - } - commonTest.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test-common' - implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common' - runtimeOnly atomicfuMetadata - - } - jsMain.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib-js' - compileOnly atomicfuJs - - } - jsTest.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test-js' - runtimeOnly atomicfuJs - } - jvmMain.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib' - compileOnly atomicfuJvm - } - jvmTest.dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test' - implementation 'org.jetbrains.kotlin:kotlin-test-junit' - implementation "junit:junit:4.12" - runtimeOnly atomicfuJvm - } - } -} - -def File classpathFile(String platform, String fileName) { - def dir = file("$buildDir/classpath/$platform") - dir.mkdirs() - return file("$dir/$fileName") -} - - -compileTestKotlinJvm.doLast { - classpathFile("jvm", "test_compile.txt").text = classpath.files.join("\n") -} - -jvmTest.doLast { - classpathFile("jvm", "test_runtime.txt").text = classpath.files.join("\n") -} - - -compileTestKotlinJs.doLast { - classpathFile("js", "test_compile.txt").text = classpath.files.join("\n") -} - -jsTest.dependsOn(":compileTestKotlinJs") -jsTest.dependsOn(":transformJsTestAtomicfu") -check.dependsOn(":jsTest") \ No newline at end of file diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts new file mode 100644 index 0000000..f289821 --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts @@ -0,0 +1,90 @@ +import org.jetbrains.kotlin.gradle.plugin.* + +buildscript { + dependencies { + classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.0") + } +} + +plugins { + kotlin("multiplatform") version "1.6.0" +} + +apply(plugin = "kotlinx-atomicfu") + +repositories { + mavenCentral() +} + +kotlin { + targets { + jvm { + compilations.all { + kotlinOptions.jvmTarget = "1.8" + } + testRuns["test"].executionTask.configure { + useJUnit() + } + } + js { + nodejs() + } + } + sourceSets { + val commonMain by getting { + dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib-common") + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + } + } + val jvmMain by getting { + dependencies { + implementation(kotlin("stdlib")) + } + } + val jvmTest by getting { + dependencies { + implementation(kotlin("test-junit")) + } + } + val jsMain by getting { + dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib-js") + } + } + val jsTest by getting { + dependencies { + implementation("org.jetbrains.kotlin:kotlin-test-js") + } + } + } + + tasks.named("compileTestKotlinJvm") { + doLast { + file("$buildDir/test_compile_jvm_classpath.txt").writeText( + targets["jvm"].compilations["test"].compileDependencyFiles.joinToString("\n") + ) + } + } + + tasks.named("jvmTest") { + doLast { + file("$buildDir/test_runtime_jvm_classpath.txt").writeText( + (targets["jvm"].compilations["test"] as KotlinCompilationToRunnableFiles).runtimeDependencyFiles.joinToString("\n") + ) + } + } + + tasks.named("compileTestKotlinJs") { + doLast { + file("$buildDir/test_compile_js_classpath.txt").writeText( + targets["js"].compilations["test"].compileDependencyFiles.joinToString("\n") + ) + } + } +} diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/settings.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/settings.gradle.kts new file mode 100644 index 0000000..5a4e5ab --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "mpp-simple" \ No newline at end of file -- cgit v1.2.3 From dcf8566fb1b5a89b3dad5d9d0fdb887aed123c1b Mon Sep 17 00:00:00 2001 From: SokolovaMaria Date: Mon, 7 Feb 2022 16:15:40 +0300 Subject: Bug fixes for delegated fields support (#179) * Js transformer: checking owner class of the delegated fields * JVM transformer: does not rely on the generated name of the field delegate * Top-level delegated properties for JVM and JS Co-authored-by: SokolovaMaria --- .../kotlin/kotlinx/atomicfu/transformer/AsmUtil.kt | 13 ++ .../atomicfu/transformer/AtomicFUTransformer.kt | 171 +++++++++++++-------- .../atomicfu/transformer/AtomicFUTransformerJS.kt | 104 +++++++++---- .../atomicfu/test/DelegatedPropertiesTest.kt | 112 +++++++++++++- 4 files changed, 308 insertions(+), 92 deletions(-) diff --git a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AsmUtil.kt b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AsmUtil.kt index ba08fbc..0687f38 100644 --- a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AsmUtil.kt +++ b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AsmUtil.kt @@ -4,7 +4,9 @@ package kotlinx.atomicfu.transformer +import org.objectweb.asm.* import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.Type.* import org.objectweb.asm.tree.* import org.objectweb.asm.util.* @@ -69,12 +71,23 @@ fun AbstractInsnNode.isGetField(owner: String) = fun AbstractInsnNode.isGetStatic(owner: String) = this is FieldInsnNode && this.opcode == GETSTATIC && this.owner == owner +fun AbstractInsnNode.isGetFieldOrGetStatic() = + this is FieldInsnNode && (this.opcode == GETFIELD || this.opcode == GETSTATIC) + fun AbstractInsnNode.isAreturn() = this.opcode == ARETURN fun AbstractInsnNode.isReturn() = this.opcode == RETURN +fun AbstractInsnNode.isTypeReturn(type: Type) = + opcode == when (type) { + INT_TYPE -> IRETURN + LONG_TYPE -> LRETURN + BOOLEAN_TYPE -> IRETURN + else -> ARETURN + } + fun AbstractInsnNode.isInvokeVirtual() = this.opcode == INVOKEVIRTUAL diff --git a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt index b8f804f..ca6c143 100644 --- a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt +++ b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt @@ -91,7 +91,6 @@ private val TRACE_APPEND_3 = MethodId(TRACE_BASE_CLS, "append", getMethodDescrip private val TRACE_APPEND_4 = MethodId(TRACE_BASE_CLS, "append", getMethodDescriptor(VOID_TYPE, OBJECT_TYPE, OBJECT_TYPE, OBJECT_TYPE, OBJECT_TYPE), INVOKEVIRTUAL) private val TRACE_DEFAULT_ARGS = "I${OBJECT_TYPE.descriptor}" private const val DEFAULT = "\$default" -private const val DELEGATE = "\$delegate" private val TRACE_FACTORY = MethodId(TRACE_KT, TRACE, "(IL$AFU_PKG/$TRACE_FORMAT;)L$AFU_PKG/$TRACE_BASE;", INVOKESTATIC) private val TRACE_PARTIAL_ARGS_FACTORY = MethodId(TRACE_KT, "$TRACE$DEFAULT", "(IL$AFU_PKG/$TRACE_FORMAT;$TRACE_DEFAULT_ARGS)L$AFU_PKG/$TRACE_BASE;", INVOKESTATIC) @@ -188,6 +187,7 @@ class AtomicFUTransformer( private val traceFields = mutableSetOf() private val traceAccessors = mutableSetOf() private val fieldDelegates = mutableMapOf() + private val delegatedPropertiesAccessors = mutableMapOf() private val removeMethods = mutableSetOf() override fun transform() { @@ -341,6 +341,10 @@ class AtomicFUTransformer( // check for copying atomic values into delegate fields and register potential delegate fields return DelegateFieldsCollectorMV(access, name, desc, signature, exceptions) } + // collect accessors of potential delegated properties + if (methodType.argumentTypes.isEmpty()) { + return DelegatedFieldAccessorCollectorMV(className, methodType.returnType, access, name, desc, signature, exceptions) + } return null } } @@ -396,6 +400,43 @@ class AtomicFUTransformer( } } + private inner class DelegatedFieldAccessorCollectorMV( + private val className: String, private val returnType: Type, + access: Int, name: String, desc: String, signature: String?, exceptions: Array? + ) : MethodNode(ASM5, access, name, desc, signature, exceptions) { + override fun visitEnd() { + // check for pattern of a delegated property getter + // getfield/getstatic a$delegate: Atomic* + // astore_i ... + // aload_i + // invokevirtual Atomic*.getValue() + // ireturn + var cur = instructions.first + while (cur != null && !(cur.isGetFieldOrGetStatic() && getType((cur as FieldInsnNode).desc) in AFU_TYPES)) { + cur = cur.next + } + if (cur != null && cur.next.opcode == ASTORE) { + val fi = cur as FieldInsnNode + val fieldDelegate = FieldId(className, fi.name, fi.desc) + val atomicType = getType(fi.desc) + val v = (cur.next as VarInsnNode).`var` + while (!(cur is VarInsnNode && cur.opcode == ALOAD && cur.`var` == v)) { + cur = cur.next + } + val invokeVirtual = cur.next + if (invokeVirtual.opcode == INVOKEVIRTUAL && (invokeVirtual as MethodInsnNode).name == GET_VALUE && invokeVirtual.owner == atomicType.internalName) { + // followed by RETURN operation + val next = invokeVirtual.nextUseful + val ret = if (next?.opcode == CHECKCAST) next.nextUseful else next + if (ret != null && ret.isTypeReturn(returnType)) { + // register delegated property accessor + delegatedPropertiesAccessors[fieldDelegate] = MethodId(className, name, desc, accessToInvokeOpcode(access)) + } + } + } + } + } + private inner class DelegateFieldsCollectorMV( access: Int, name: String, desc: String, signature: String?, exceptions: Array? ) : MethodNode(ASM9, access, name, desc, signature, exceptions) { @@ -408,7 +449,7 @@ class AtomicFUTransformer( insn.checkGetFieldOrGetStatic()?.let { getfieldId -> val next = insn.next (next as? FieldInsnNode)?.checkPutFieldOrPutStatic()?.let { delegateFieldId -> - if (delegateFieldId.name.endsWith(DELEGATE)) { + if (getfieldId in fields && delegateFieldId in fields) { // original atomic value is copied to the synthetic delegate atomic field $delegate val originalField = fields[getfieldId]!! fieldDelegates[delegateFieldId] = originalField @@ -420,11 +461,12 @@ class AtomicFUTransformer( val methodId = MethodId(insn.owner, insn.name, insn.desc, insn.opcode) if (methodId in FACTORIES) { (insn.nextUseful as? FieldInsnNode)?.checkPutFieldOrPutStatic()?.let { delegateFieldId -> - if (delegateFieldId.name.endsWith(DELEGATE)) { + val fieldType = getType(insn.desc).returnType + if (fieldType in AFU_TYPES) { + val isStatic = insn.nextUseful!!.opcode == PUTSTATIC // delegate field is initialized by a factory invocation - val fieldType = getType(insn.desc).returnType // for volatile delegated properties store FieldInfo of the delegate field itself - fieldDelegates[delegateFieldId] = FieldInfo(delegateFieldId, fieldType) + fieldDelegates[delegateFieldId] = FieldInfo(delegateFieldId, fieldType, isStatic) } } } @@ -447,6 +489,8 @@ class AtomicFUTransformer( return if (fieldId in fields) fieldId else null } + private fun FieldId.isFieldDelegate() = this in fieldDelegates && delegatedPropertiesAccessors.contains(this) + private inner class TransformerCV( cv: ClassVisitor?, private val vh: Boolean, @@ -478,8 +522,8 @@ class AtomicFUTransformer( val fieldType = getType(desc) if (fieldType.sort == OBJECT && fieldType.internalName in AFU_CLASSES) { val fieldId = FieldId(className, name, desc) - // skip delegate field - if (fieldId in fieldDelegates && (fieldId != fieldDelegates[fieldId]!!.fieldId)) { + // skip field delegates except volatile delegated properties (e.g. val a: Int by atomic(0)) + if (fieldId.isFieldDelegate() && (fieldId != fieldDelegates[fieldId]!!.fieldId)) { transformed = true return null } @@ -727,7 +771,7 @@ class AtomicFUTransformer( private fun FieldInsnNode.checkCopyToDelegate(): AbstractInsnNode? { val fieldId = FieldId(owner, name, desc) - if (fieldId in fieldDelegates) { + if (fieldId.isFieldDelegate()) { // original atomic value is copied to the synthetic delegate atomic field $delegate val originalField = fieldDelegates[fieldId]!! val getField = previous as FieldInsnNode @@ -753,51 +797,29 @@ class AtomicFUTransformer( if (iv.name == GET_VALUE || iv.name == SET_VALUE) { check(!f.isArray || onArrayElement) { "getValue/setValue can only be called on elements of arrays" } val setInsn = iv.name == SET_VALUE - if (!onArrayElement) { - val primitiveType = f.getPrimitiveType(vh) - val owner = if (!vh && f.isStatic) f.refVolatileClassName else f.owner - if (!vh && f.isStatic) { - val getOwnerClass = FieldInsnNode( - GETSTATIC, - f.owner, - f.staticRefVolatileField, - getObjectType(owner).descriptor - ) - instructions.insert(ld, getOwnerClass) - } - instructions.remove(ld) // drop getstatic (we don't need field updater) - val j = FieldInsnNode( - when { - iv.name == GET_VALUE -> if (f.isStatic && vh) GETSTATIC else GETFIELD - else -> if (f.isStatic && vh) PUTSTATIC else PUTFIELD - }, owner, f.name, primitiveType.descriptor - ) - instructions.set(iv, j) // replace invokevirtual with get/setfield - return j.next + if (!onArrayElement) return getPureTypeField(ld, f, iv) + var methodType = getMethodType(iv.desc) + if (f.typeInfo.originalType != f.typeInfo.transformedType && !vh) { + val ret = f.typeInfo.transformedType.elementType + iv.desc = if (setInsn) getMethodDescriptor(methodType.returnType, ret) else getMethodDescriptor(ret, *methodType.argumentTypes) + methodType = getMethodType(iv.desc) + } + iv.name = iv.name.substring(0, 3) + if (!vh) { + // map to j.u.c.a.Atomic*Array get or set + iv.owner = descToName(f.fuType.descriptor) + iv.desc = getMethodDescriptor(methodType.returnType, INT_TYPE, *methodType.argumentTypes) } else { - var methodType = getMethodType(iv.desc) - if (f.typeInfo.originalType != f.typeInfo.transformedType && !vh) { - val ret = f.typeInfo.transformedType.elementType - iv.desc = if (setInsn) getMethodDescriptor(methodType.returnType, ret) else getMethodDescriptor(ret, *methodType.argumentTypes) - methodType = getMethodType(iv.desc) - } - iv.name = iv.name.substring(0, 3) - if (!vh) { - // map to j.u.c.a.Atomic*Array get or set - iv.owner = descToName(f.fuType.descriptor) - iv.desc = getMethodDescriptor(methodType.returnType, INT_TYPE, *methodType.argumentTypes) - } else { - // map to VarHandle get or set - iv.owner = descToName(VH_TYPE.descriptor) - iv.desc = getMethodDescriptor( - methodType.returnType, - f.getPrimitiveType(vh), - INT_TYPE, - *methodType.argumentTypes - ) - } - return iv + // map to VarHandle get or set + iv.owner = descToName(VH_TYPE.descriptor) + iv.desc = getMethodDescriptor( + methodType.returnType, + f.getPrimitiveType(vh), + INT_TYPE, + *methodType.argumentTypes + ) } + return iv } if (f.isArray && iv.name == GET_SIZE) { if (!vh) { @@ -860,6 +882,29 @@ class AtomicFUTransformer( return iv.next } + private fun getPureTypeField(ld: FieldInsnNode, f: FieldInfo, iv: MethodInsnNode): AbstractInsnNode? { + val primitiveType = f.getPrimitiveType(vh) + val owner = if (!vh && f.isStatic) f.refVolatileClassName else f.owner + if (!vh && f.isStatic) { + val getOwnerClass = FieldInsnNode( + GETSTATIC, + f.owner, + f.staticRefVolatileField, + getObjectType(owner).descriptor + ) + instructions.insert(ld, getOwnerClass) + } + instructions.remove(ld) // drop getfield/getstatic of the atomic field + val j = FieldInsnNode( + when { + iv.name == GET_VALUE -> if (f.isStatic && vh) GETSTATIC else GETFIELD + else -> if (f.isStatic && vh) PUTSTATIC else PUTFIELD + }, owner, f.name, primitiveType.descriptor + ) + instructions.set(iv, j) // replace invokevirtual with get/setfield + return j.next + } + private fun vhOperation(iv: MethodInsnNode, typeInfo: TypeInfo, f: FieldInfo) { val methodType = getMethodType(iv.desc) val args = methodType.argumentTypes @@ -1310,7 +1355,7 @@ class AtomicFUTransformer( is FieldInsnNode -> { val fieldId = FieldId(i.owner, i.name, i.desc) if ((i.opcode == GETFIELD || i.opcode == GETSTATIC) && fieldId in fields) { - if (fieldId in fieldDelegates && i.next.opcode == ASTORE) { + if (fieldId.isFieldDelegate() && i.next.opcode == ASTORE) { return transformDelegatedFieldAccessor(i, fieldId) } (i.next as? FieldInsnNode)?.checkCopyToDelegate()?.let { return it } // atomic field is copied to delegate field @@ -1343,29 +1388,25 @@ class AtomicFUTransformer( return i.next } - private fun transformDelegatedFieldAccessor(i: FieldInsnNode, fieldId: FieldId): AbstractInsnNode { + private fun transformDelegatedFieldAccessor(i: FieldInsnNode, fieldId: FieldId): AbstractInsnNode? { val f = fieldDelegates[fieldId]!! - val astore = (i.next as? VarInsnNode) ?: abort("Method $name does not match the pattern of a delegated field accessor") - val v = astore.`var` - var cur: AbstractInsnNode = i + val v = (i.next as VarInsnNode).`var` + // remove instructions [astore_v .. aload_v] + var cur: AbstractInsnNode = i.next while (!(cur is VarInsnNode && cur.opcode == ALOAD && cur.`var` == v)) { val next = cur.next instructions.remove(cur) cur = next } - val invokeVirtual = FlowAnalyzer(cur.next).execute() - instructions.remove(cur) - check(invokeVirtual.isAtomicGetValueOrSetValue()) { "Aload of the field delegate $f should be followed with Atomic*.getValue()/setValue() invocation" } - val accessorName = (invokeVirtual as MethodInsnNode).name.substring(0, 3) - val isGetter = accessorName == "get" - val primitiveType = f.getPrimitiveType(vh) - val j = FieldInsnNode(if (isGetter) GETFIELD else PUTFIELD, f.owner, f.name, primitiveType.descriptor) - instructions.set(invokeVirtual, j) + val iv = FlowAnalyzer(cur.next).execute() + check(iv.isAtomicGetValueOrSetValue()) { "Aload of the field delegate $f should be followed with Atomic*.getValue()/setValue() invocation" } + val isGetter = (iv as MethodInsnNode).name == GET_VALUE + instructions.remove(cur) // remove aload_v localVariables.removeIf { !(getType(it.desc).internalName == f.owner || (!isGetter && getType(it.desc) == getType(desc).argumentTypes.first() && it.name == "")) } - return j.next + return getPureTypeField(i, f, iv) } private fun AbstractInsnNode.isAtomicGetFieldOrGetStatic() = diff --git a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformerJS.kt b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformerJS.kt index 91f3037..de8f94a 100644 --- a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformerJS.kt +++ b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformerJS.kt @@ -52,8 +52,8 @@ class AtomicFUTransformerJS( outputDir: File ) : AtomicFUTransformerBase(inputDir, outputDir) { private val atomicConstructors = mutableSetOf() - private val fieldDelegates = mutableMapOf() - private val delegatedProperties = mutableMapOf() + private val delegateToOriginalAtomicField = mutableMapOf() + private val topLevelDelegatedFieldAccessorToOriginalField = mutableMapOf() private val atomicArrayConstructors = mutableMapOf() private val traceConstructors = mutableSetOf() private val traceFormatObjects = mutableSetOf() @@ -81,6 +81,7 @@ class AtomicFUTransformerJS( root.visit(AtomicConstructorDetector()) root.visit(FieldDelegatesVisitor()) root.visit(DelegatedPropertyAccessorsVisitor()) + root.visit(TopLevelDelegatedFieldsAccessorVisitor()) root.visit(TransformVisitor()) root.visit(AtomicOperationsInliner()) return root.eraseGetValue().toByteArray() @@ -283,12 +284,17 @@ class AtomicFUTransformerJS( if (stmt is ExpressionStatement) { if (stmt.expression is Assignment) { val delegateAssignment = stmt.expression as Assignment - if (delegateAssignment.right is PropertyGet) { - val initializer = delegateAssignment.right as PropertyGet - if (initializer.toSource() == atomicField.toSource()) { - // register field delegate and the original atomic field - fieldDelegates[(delegateAssignment.left as PropertyGet).property.toSource()] = - (atomicField as PropertyGet).property.toSource() + val initializer = delegateAssignment.right + if (initializer.toSource() == atomicField.toSource()) { + if (delegateAssignment.right is PropertyGet) { // initialization of a class field + // delegate${owner_class} to original atomic field + val delegateFieldName = (delegateAssignment.left as PropertyGet).property.toSource() + val ownerClassName = constructorBlock.enclosingFunction.functionName.identifier + delegateToOriginalAtomicField["$delegateFieldName\$$ownerClassName"] = + (atomicField as PropertyGet).property + } else { // top-level delegated fields + val delegateFieldName = delegateAssignment.left.toSource() + delegateToOriginalAtomicField[delegateFieldName] = atomicField as Name } } } @@ -303,22 +309,74 @@ class AtomicFUTransformerJS( inner class DelegatedPropertyAccessorsVisitor : NodeVisitor { override fun visit(node: AstNode?): Boolean { - if (node is PropertyGet) { - if (node.target is PropertyGet) { - if ((node.target as PropertyGet).property.toSource() in fieldDelegates && node.property.toSource() == MANGLED_VALUE_PROP) { - if (node.parent is ReturnStatement) { - val getter = ((((node.parent.parent as? Block)?.parent as? FunctionNode)?.parent as? ObjectProperty)?.parent as? ObjectLiteral) - ?: abort("Incorrect tree structure of the accessor for the property delegated " + - "to the atomic field ${fieldDelegates[node.target.toSource()]}") - val definePropertyCall = getter.parent as FunctionCall - val stringLiteral = definePropertyCall.arguments[1] as? StringLiteral - ?: abort ("Object.defineProperty invocation should take a property name as the second argument") - val delegatedProperty = stringLiteral.value.toString() - delegatedProperties[delegatedProperty] = (node.target as PropertyGet).property.toSource() + // find ObjectLiteral with accessors of the delegated field (get: FunctionNode, set: FunctionNode) + // redirect getter/setter from generated delegate field to the original atomic field + if (node is ObjectLiteral && node.parent is FunctionCall && + ((node.elements.size == 2 && node.elements[1].left.toSource() == "get") || + (node.elements.size == 3 && node.elements[1].left.toSource() == "get" && node.elements[2].left.toSource() == "set"))) { + // check that these are accessors of the atomic delegate field (check only getter) + if (node.elements[1].right is FunctionNode) { + val getter = node.elements[1].right as FunctionNode + if (getter.body.hasChildren() && getter.body.firstChild is ReturnStatement) { + val returnStmt = getter.body.firstChild as ReturnStatement + if (returnStmt.returnValue is PropertyGet && (returnStmt.returnValue as PropertyGet).property.toSource() == MANGLED_VALUE_PROP) { + val delegateField = ((returnStmt.returnValue as PropertyGet).target as PropertyGet).property.toSource() + val ownerClassName = ((node.parent as FunctionCall).arguments[0] as PropertyGet).target.toSource() + val key = "$delegateField\$$ownerClassName" + delegateToOriginalAtomicField[key]?.let { atomicField -> + // get() = a$delegate.value -> _a.value + getter.replaceAccessedField(true, atomicField) + if (node.elements.size == 3) { + // set(v: T) { a$delegate.value = v } -> { _a.value = v } + val setter = node.elements[2].right as FunctionNode + setter.replaceAccessedField(false, atomicField) + } + } + } + } + } + } + if (node is ObjectLiteral && node.parent is FunctionCall && ((node.elements.size == 1 && node.elements[0].left.toSource() == "get") || + node.elements.size == 2 && node.elements[0].left.toSource() == "get" && node.elements[1].left.toSource() == "set")) { + val parent = node.parent as FunctionCall + if (parent.arguments.size == 3 && parent.arguments[1] is StringLiteral) { + val topLevelDelegatedFieldName = (parent.arguments[1] as StringLiteral).value + if (topLevelDelegatedFieldName in delegateToOriginalAtomicField) { + val originalAtomicFieldName = delegateToOriginalAtomicField[topLevelDelegatedFieldName]!! + val getterName = node.elements[0].right.toSource() + topLevelDelegatedFieldAccessorToOriginalField[getterName] = originalAtomicFieldName + if (node.elements.size == 2) { + val setterName = node.elements[1].right.toSource() + topLevelDelegatedFieldAccessorToOriginalField[setterName] = originalAtomicFieldName } } } + } + return true + } + } + private fun FunctionNode.replaceAccessedField(isGetter: Boolean, newField: Name) { + val propertyGet = if (isGetter) { + (body.firstChild as ReturnStatement).returnValue as PropertyGet + } else { + ((body.firstChild as ExpressionStatement).expression as Assignment).left as PropertyGet + } + if (propertyGet.target is PropertyGet) { // class member + (propertyGet.target as PropertyGet).property = newField + } else { // top-level field + propertyGet.target = newField + } + } + + inner class TopLevelDelegatedFieldsAccessorVisitor : NodeVisitor { + override fun visit(node: AstNode?): Boolean { + if (node is FunctionNode && node.name.toString() in topLevelDelegatedFieldAccessorToOriginalField) { + val accessorName = node.name.toString() + val atomicField = topLevelDelegatedFieldAccessorToOriginalField[accessorName]!! + // function get_topLevelDelegatedField() = a.value -> _a.value + // function set_topLevelDelegatedField(v: T) { a.value = v } -> { _a.value = v } + node.replaceAccessedField(accessorName.startsWith("get"), atomicField) } return true } @@ -388,12 +446,6 @@ class AtomicFUTransformerJS( rr.receiver?.let { node.target = it } } } - if (node.property.toSource() in delegatedProperties) { - // replace delegated property name with the name of the original atomic field - val fieldDelegate = delegatedProperties[node.property.toSource()] - val originalField = fieldDelegates[fieldDelegate]!! - node.property = Name().apply { identifier = originalField } - } // replace Atomic*Array.size call with `length` property on the pure type js array if (node.property.toSource() == ARRAY_SIZE) { node.property = Name().also { it.identifier = LENGTH } diff --git a/atomicfu/src/commonTest/kotlin/kotlinx/atomicfu/test/DelegatedPropertiesTest.kt b/atomicfu/src/commonTest/kotlin/kotlinx/atomicfu/test/DelegatedPropertiesTest.kt index 1b24e6d..4521c09 100644 --- a/atomicfu/src/commonTest/kotlin/kotlinx/atomicfu/test/DelegatedPropertiesTest.kt +++ b/atomicfu/src/commonTest/kotlin/kotlinx/atomicfu/test/DelegatedPropertiesTest.kt @@ -5,8 +5,27 @@ package kotlinx.atomicfu.test import kotlinx.atomicfu.atomic import kotlin.test.* -class DelegatedProperties { +private val topLevelIntOriginalAtomic = atomic(77) +var topLevelIntDelegatedProperty: Int by topLevelIntOriginalAtomic + +private val _topLevelLong = atomic(55555555555) +var topLevelDelegatedPropertyLong: Long by _topLevelLong + +private val _topLevelBoolean = atomic(false) +var topLevelDelegatedPropertyBoolean: Boolean by _topLevelBoolean + +private val _topLevelRef = atomic(listOf("a", "b")) +var topLevelDelegatedPropertyRef: List by _topLevelRef + +var vTopLevelInt by atomic(77) + +var vTopLevelLong by atomic(777777777) +var vTopLevelBoolean by atomic(false) + +var vTopLevelRef by atomic(listOf("a", "b")) + +class DelegatedProperties { private val _a = atomic(42) var a: Int by _a @@ -99,6 +118,76 @@ class DelegatedProperties { assertEquals(99, vRef.b.n) } + @Test + fun testTopLevelDelegatedPropertiesInt() { + assertEquals(77, topLevelIntDelegatedProperty) + topLevelIntOriginalAtomic.compareAndSet(77, 56) + assertEquals(56, topLevelIntDelegatedProperty) + topLevelIntDelegatedProperty = 88 + topLevelIntOriginalAtomic.compareAndSet(88, 66) + assertEquals(66, topLevelIntOriginalAtomic.value) + assertEquals(66, topLevelIntDelegatedProperty) + } + + @Test + fun testTopLevelDelegatedPropertiesLong() { + assertEquals(55555555555, topLevelDelegatedPropertyLong) + _topLevelLong.getAndIncrement() + assertEquals(55555555556, topLevelDelegatedPropertyLong) + topLevelDelegatedPropertyLong = 7777777777777 + assertTrue(_topLevelLong.compareAndSet(7777777777777, 66666666666)) + assertEquals(66666666666, _topLevelLong.value) + assertEquals(66666666666, topLevelDelegatedPropertyLong) + } + + @Test + fun testTopLevelDelegatedPropertiesBoolean() { + assertEquals(false, topLevelDelegatedPropertyBoolean) + _topLevelBoolean.lazySet(true) + assertEquals(true, topLevelDelegatedPropertyBoolean) + topLevelDelegatedPropertyBoolean = false + assertTrue(_topLevelBoolean.compareAndSet(false, true)) + assertEquals(true, _topLevelBoolean.value) + assertEquals(true, topLevelDelegatedPropertyBoolean) + } + + @Test + fun testTopLevelDelegatedPropertiesRef() { + assertEquals("b", topLevelDelegatedPropertyRef[1]) + _topLevelRef.lazySet(listOf("c")) + assertEquals("c", topLevelDelegatedPropertyRef[0]) + topLevelDelegatedPropertyRef = listOf("d", "e") + assertEquals("e", _topLevelRef.value[1]) + } + + @Test + fun testVolatileTopLevelInt() { + assertEquals(77, vTopLevelInt) + vTopLevelInt = 55 + assertEquals(110, vTopLevelInt * 2) + } + + @Test + fun testVolatileTopLevelLong() { + assertEquals(777777777, vTopLevelLong) + vTopLevelLong = 55 + assertEquals(55, vTopLevelLong) + } + + @Test + fun testVolatileTopLevelBoolean() { + assertEquals(false, vTopLevelBoolean) + vTopLevelBoolean = true + assertEquals(true, vTopLevelBoolean) + } + + @Test + fun testVolatileTopLevelRef() { + assertEquals("a", vTopLevelRef[0]) + vTopLevelRef = listOf("c") + assertEquals("c", vTopLevelRef[0]) + } + class A (val b: B) class B (val n: Int) } @@ -144,4 +233,25 @@ class ExposedDelegatedPropertiesAccessorsTest { cl.vInt = 99 assertEquals(99, cl.vInt) } +} + +class ClashedNamesTest { + private class A1 { + val _a = atomic(0) + val a: Int by _a + } + + private class A2 { + val _a = atomic(0) + val a: Int by _a + } + + @Test + fun testClashedDelegatedPropertiesNames() { + val a1Class = A1() + val a2Class = A2() + a1Class._a.compareAndSet(0, 77) + assertEquals(77, a1Class.a) + assertEquals(0, a2Class.a) + } } \ No newline at end of file -- cgit v1.2.3 From a4b7257392995710b9b7268151e63d0d022fbc10 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Mon, 7 Feb 2022 16:36:05 +0300 Subject: Version 0.17.1 --- CHANGES.md | 6 ++++++ README.md | 8 ++++---- gradle.properties | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ced0c22..acb51de 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change log for kotlinx.atomicfu +# Version 0.17.1 + +* Support of `org.jetbrains.kotlin.js` plugin (#218). +* Fixed configuration cache bug. (#216). +* Bug fixes for delegated fields support (#179). + # Version 0.17.0 * Update Kotlin to 1.6.0. diff --git a/README.md b/README.md index 70c03d3..665036b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![JetBrains incubator project](https://jb.gg/badges/incubator.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.17.0/pom) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.17.1/pom) The idiomatic way to use atomic operations in Kotlin. @@ -107,7 +107,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.17.0' + ext.atomicfu_version = '0.17.1' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -155,7 +155,7 @@ There are the following additional parameters (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.17.0' // set to null to turn-off auto dependencies + dependenciesVersion = '0.17.1' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation transformJs = true // set to false to turn off JS transformation variant = "FU" // JVM transformation variant: FU,VH, or BOTH @@ -169,7 +169,7 @@ Declare AtomicFU version: ```xml - 0.17.0 + 0.17.1 ``` diff --git a/gradle.properties b/gradle.properties index 8b0fca2..f4df647 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.17.0-SNAPSHOT +version=0.17.1-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.6.0 -- cgit v1.2.3 From 0cf0811b9316fa6edf1c7b30ad723eccd226bb15 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Tue, 15 Mar 2022 15:01:12 +0300 Subject: Update kotlinx.metadata version to 0.4.2 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8b0fca2..f5def0c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ kotlin_version=1.6.0 asm_version=9.1 slf4j_version=1.8.0-alpha2 junit_version=4.12 -kotlinx_metadata_version=0.3.0 +kotlinx_metadata_version=0.4.2 maven_version=3.5.3 -- cgit v1.2.3 From 3dfc7d69ee34e65e67e6d36538aade71dc9a9cb7 Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Tue, 22 Mar 2022 16:41:52 +0300 Subject: Use module-name for file names and transformed file as input file property --- atomicfu/build.gradle | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/atomicfu/build.gradle b/atomicfu/build.gradle index c44d969..cfee622 100644 --- a/atomicfu/build.gradle +++ b/atomicfu/build.gradle @@ -24,6 +24,7 @@ kotlin { // JS -- always js { + moduleName = "kotlinx-atomicfu" // TODO: Commented out because browser tests do not work on TeamCity // browser() nodejs() @@ -164,14 +165,6 @@ tasks.withType(compileJsLegacy.getClass()) { } } -compileJsLegacy.configure { - kotlinOptions { - // NOTE: Module base-name must be equal to the package name declared in package.json - def baseName = "kotlinx-atomicfu" - outputFile = new File(new File(outputFile).parent, baseName + ".js") - } -} - apply from: file("$rootProject.projectDir/gradle/node-js.gradle") apply from: file("$rootProject.projectDir/gradle/publish-npm-js.gradle") @@ -208,8 +201,14 @@ task transformJS(type: JavaExec, dependsOn: [compileTestJsLegacy]) { if (project.tasks.findByName('jsLegacyNodeTest')) { jsLegacyNodeTest.dependsOn transformJS + jsLegacyNodeTest.configure { + inputFileProperty.set(new File(transformedJsFile)) + } } else { jsNodeTest.dependsOn transformJS + jsNodeTest.configure { + inputFileProperty.set(new File(transformedJsFile)) + } } // ==== CONFIGURE JVM ===== -- cgit v1.2.3 From 49a27dcd816fd713a582b771d9fa32293178f5eb Mon Sep 17 00:00:00 2001 From: Lin Zhang Date: Wed, 16 Feb 2022 22:29:03 +0800 Subject: Update README.md Remove `common` in common module dependency --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 665036b..87b54d5 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ to your common code dependencies or apply `kotlinx-atomicfu` plugin that adds th ```groovy dependencies { - compile "org.jetbrains.kotlinx:atomicfu-common:$atomicfu_version" + compile "org.jetbrains.kotlinx:atomicfu:$atomicfu_version" } ``` -- cgit v1.2.3 From e5333e5fb36ba1163961e4fc657af63babc182e6 Mon Sep 17 00:00:00 2001 From: Lin Zhang Date: Wed, 6 Apr 2022 14:46:05 +0800 Subject: Update README.md (#220) Remove `common` in common module dependency --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 665036b..87b54d5 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ to your common code dependencies or apply `kotlinx-atomicfu` plugin that adds th ```groovy dependencies { - compile "org.jetbrains.kotlinx:atomicfu-common:$atomicfu_version" + compile "org.jetbrains.kotlinx:atomicfu:$atomicfu_version" } ``` -- cgit v1.2.3 From 00feda8edeb0fc796671788414d1eb7fbaabbd1c Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Mon, 11 Apr 2022 17:20:07 +0300 Subject: Update Kotlin to 1.6.20 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 5fb040a..3f78cb6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ version=0.17.1-SNAPSHOT group=org.jetbrains.kotlinx -kotlin_version=1.6.0 +kotlin_version=1.6.20 asm_version=9.1 slf4j_version=1.8.0-alpha2 junit_version=4.12 -- cgit v1.2.3 From c88a89bcc9cc1b3f3769dfbee10fa8c75ccac989 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Thu, 7 Apr 2022 17:35:30 +0300 Subject: Add wasm platform type --- .../main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 4617f18..16953d1 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -268,7 +268,7 @@ fun Project.configureMultiplatformPluginDependencies(version: String) { KotlinPlatformType.common -> Platform.MULTIPLATFORM KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> Platform.JVM KotlinPlatformType.js -> Platform.JS - KotlinPlatformType.native -> Platform.NATIVE + KotlinPlatformType.native, KotlinPlatformType.wasm -> Platform.NATIVE } val configurationName = when { // impl dependency for native (there is no transformation) -- cgit v1.2.3 From ac8e045e6522c81f031b4dab3b6f944dc3328598 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Tue, 12 Apr 2022 15:57:29 +0300 Subject: ASM 9.3 for Java 18 support (#223) Fixes #221 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3f78cb6..a039835 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ version=0.17.1-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.6.20 -asm_version=9.1 +asm_version=9.3 slf4j_version=1.8.0-alpha2 junit_version=4.12 kotlinx_metadata_version=0.4.2 -- cgit v1.2.3 From 8e1f8b3a0d883785ffe5b157ebc4df6bad9db543 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Thu, 14 Apr 2022 15:15:25 +0300 Subject: Atomicfu Js/Ir compiler plugin supported in the gradle plugin (#215) * Atomicfu Js/Ir compiler plugin supported in the gradle plugin * Fix: apply atomicfu compiler plugin by default * Add gradle.properties option to turn on IR transformations * Fix README.md Co-authored-by: Vsevolod Tolstopyatov * Fix README.md Co-authored-by: Vsevolod Tolstopyatov * Property value toBooleanStrict Co-authored-by: Vsevolod Tolstopyatov --- README.md | 59 +++++++++++++------- atomicfu-gradle-plugin/build.gradle | 2 + .../atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 65 ++++++++++++++++++---- .../kotlinx/atomicfu/plugin/TransformMojo.kt | 8 +-- .../atomicfu/transformer/AtomicFUTransformer.kt | 10 ++-- 5 files changed, 103 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 87b54d5..9944900 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ apply plugin: 'kotlinx-atomicfu' ### JS -Configure add apply plugin just like for [JVM](#jvm). +Configure add apply plugin just like for [JVM](#jvm). ### Native @@ -149,16 +149,49 @@ dependencies { } ``` -### Additional configuration +## IR transformation for Kotlin/JS -There are the following additional parameters (with their defaults): +There is a new option to turn on IR transformation for Kotlin/JS backend. +You can add `kotlinx.atomicfu.enableIrTransformation=true` to your `gradle.properties` file in order to enable it. +Here is how transformation is performed for different [JS compiler modes](https://kotlinlang.org/docs/js-ir-compiler.html) with this option enabled: + +- `kotlin.js.compiler=legacy`: JavaScript transformer from the library is applied to the final compiled *.js files. +- `kotlin.js.compiler=ir`: compiler plugin transformations are appiled to the generated IR. +- `kotlin.js.compiler=both`: compiler plugin transformations are appiled to all compilations of IR targets, while compilations of legacy targets are transformed by the library. + +## Additional configuration + +To set configuration options you should create `atomicfu` section in a `build.gradle` file, +like this: +```groovy +atomicfu { + dependenciesVersion = '0.17.1' +} +``` + +### JVM transformation options + +To turn off transformation for Kotlin/JVM set option `transformJvm` to `false`. + +Configuration option `jvmVariant` defines the Java class that replaces atomics during bytecode transformation. +Here are the valid options: +- `FU` – atomics are replaced with [AtomicXxxFieldUpdater](https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.html). +- `VH` – atomics are replaced with [VarHandle](https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/VarHandle.html), + this option is supported for JDK 9+. +- `BOTH` – [multi-release jar file](https://openjdk.java.net/jeps/238) will be created with both `AtomicXxxFieldUpdater` for JDK <= 8 and `VarHandle` for JDK 9+. + +### JS transformation options + +To turn off transformation for Kotlin/JS set option `transformJs` to `false`. + +Here are all available configuration options (with their defaults): ```groovy atomicfu { dependenciesVersion = '0.17.1' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation - transformJs = true // set to false to turn off JS transformation - variant = "FU" // JVM transformation variant: FU,VH, or BOTH + jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH + jsVariant = "JS" // JS transformation variant: JS or IR verbose = false // set to true to be more verbose } ``` @@ -237,22 +270,6 @@ which is then transformed to a regular `classes` directory to be used later by t AtomicFU provides some additional features that you can optionally use. -### VarHandles with Java 9 - -AtomicFU can produce code that uses Java 9 -[VarHandle](https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/VarHandle.html) -instead of `AtomicXxxFieldUpdater`. Configure transformation `variant` in Gradle build file: - -```groovy -atomicfu { - variant = "VH" -} -``` - -It can also create [JEP 238](https://openjdk.java.net/jeps/238) multi-release jar file with both -`AtomicXxxFieldUpdater` for JDK<=8 and `VarHandle` for for JDK9+ if you -set `variant` to `"BOTH"`. - ### Arrays of atomic values You can declare arrays of all supported atomic value types. diff --git a/atomicfu-gradle-plugin/build.gradle b/atomicfu-gradle-plugin/build.gradle index 58ee3a1..79ba241 100644 --- a/atomicfu-gradle-plugin/build.gradle +++ b/atomicfu-gradle-plugin/build.gradle @@ -25,6 +25,8 @@ dependencies { compile 'org.jetbrains.kotlin:kotlin-stdlib' compileOnly "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + // atomicfu compiler plugin dependency will be loaded to kotlinCompilerPluginClasspath + implementation "org.jetbrains.kotlin:atomicfu:$kotlin_version" testCompile gradleTestKit() testCompile 'org.jetbrains.kotlin:kotlin-test' diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 16953d1..b1dd098 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -18,18 +18,25 @@ import org.jetbrains.kotlin.gradle.plugin.* import java.io.* import java.util.* import java.util.concurrent.* +import org.jetbrains.kotlin.gradle.targets.js.* +import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget +import org.jetbrains.kotlinx.atomicfu.gradle.* private const val EXTENSION_NAME = "atomicfu" private const val ORIGINAL_DIR_NAME = "originalClassesDir" private const val COMPILE_ONLY_CONFIGURATION = "compileOnly" private const val IMPLEMENTATION_CONFIGURATION = "implementation" private const val TEST_IMPLEMENTATION_CONFIGURATION = "testImplementation" +private const val ENABLE_IR_TRANSFORMATION = "kotlinx.atomicfu.enableIrTransformation" open class AtomicFUGradlePlugin : Plugin { override fun apply(project: Project) = project.run { val pluginVersion = rootProject.buildscript.configurations.findByName("classpath") ?.allDependencies?.find { it.name == "atomicfu-gradle-plugin" }?.version extensions.add(EXTENSION_NAME, AtomicFUPluginExtension(pluginVersion)) + if (rootProject.getBooleanProperty(ENABLE_IR_TRANSFORMATION)) { + plugins.apply(AtomicfuKotlinGradleSubplugin::class.java) + } configureDependencies() configureTasks() } @@ -49,6 +56,7 @@ private fun Project.configureDependencies() { getAtomicfuDependencyNotation(Platform.JS, version) ) dependencies.add(TEST_IMPLEMENTATION_CONFIGURATION, getAtomicfuDependencyNotation(Platform.JS, version)) + addCompilerPluginDependency() } withPluginWhenEvaluatedDependencies("kotlin-multiplatform") { version -> configureMultiplatformPluginDependencies(version) @@ -78,6 +86,36 @@ private fun Project.configureTasks() { } } +private fun Project.getBooleanProperty(name: String) = + rootProject.findProperty(name)?.toString()?.toBooleanStrict() ?: false + +private fun String.toBooleanStrict(): Boolean = when (this) { + "true" -> true + "false" -> false + else -> throw IllegalArgumentException("The string doesn't represent a boolean value: $this") +} + +private fun Project.needsJsIrTransformation(target: KotlinTarget): Boolean = + config.transformJs && target.isJsIrTarget() + +private fun KotlinTarget.isJsIrTarget() = (this is KotlinJsTarget && this.irTarget != null) || this is KotlinJsIrTarget + +private fun Project.addCompilerPluginDependency() { + val kotlinVersion = rootProject.buildscript.configurations.findByName("classpath") + ?.allDependencies?.find { it.name == "kotlin-gradle-plugin" }?.version + withKotlinTargets { target -> + if (needsJsIrTransformation(target)) { + target.compilations.forEach { kotlinCompilation -> + kotlinCompilation.dependencies { + // add atomicfu compiler plugin dependency + // to provide the `kotlinx-atomicfu-runtime` library used during compiler plugin transformation + compileOnly("org.jetbrains.kotlin:atomicfu:$kotlinVersion") + } + } + } + } +} + private enum class Platform(val suffix: String) { JVM("-jvm"), JS("-js"), @@ -129,9 +167,9 @@ fun Project.withKotlinTargets(fn: (KotlinTarget) -> Unit) { extensions.findByType(KotlinProjectExtension::class.java)?.let { kotlinExtension -> val targetsExtension = (kotlinExtension as? ExtensionAware)?.extensions?.findByName("targets") @Suppress("UNCHECKED_CAST") - val targets = targetsExtension as NamedDomainObjectContainer + val targets = targetsExtension as? NamedDomainObjectContainer // find all compilations given sourceSet belongs to - targets.all { target -> fn(target) } + targets?.all { target -> fn(target) } } } @@ -180,7 +218,10 @@ private fun Project.configureTransformationForTarget(target: KotlinTarget) { ) } KotlinPlatformType.js -> { - if (!config.transformJs) return@compilations // skip when transformation is turned off + // skip when js transformation is not needed or when IR is transformed + if (!config.transformJs || (needsJsIrTransformation(target))) { + return@compilations + } project.createJsTransformTask(compilation).configureJsTask( compilation.compileAllTaskName, transformedClassesDir, @@ -194,7 +235,7 @@ private fun Project.configureTransformationForTarget(target: KotlinTarget) { classesDirs.setFrom(transformedClassesDir) classesDirs.builtBy(transformTask) (tasks.findByName(target.artifactsTaskName) as? Jar)?.apply { - setupJarManifest(multiRelease = config.variant.toVariant() == Variant.BOTH) + setupJarManifest(multiRelease = config.jvmVariant.toJvmVariant() == JvmVariant.BOTH) } // test should compile and run against original production binaries if (compilationType == CompilationType.TEST) { @@ -232,7 +273,8 @@ fun Project.sourceSetsByCompilation(): Map + addCompilerPluginDependency() val platformTypes = compilations.map { it.platformType }.toSet() val compilationNames = compilations.map { it.compilationName }.toSet() if (compilationNames.size != 1) @@ -303,7 +346,7 @@ fun Project.configureJvmTransformation( //now transformTask is responsible for compiling this source set into the classes directory sourceSet.compiledBy(transformTask) (tasks.findByName(sourceSet.jarTaskName) as? Jar)?.apply { - setupJarManifest(multiRelease = config.variant.toVariant() == Variant.BOTH) + setupJarManifest(multiRelease = config.jvmVariant.toJvmVariant() == JvmVariant.BOTH) } // test should compile and run against original production binaries if (compilationType == CompilationType.TEST) { @@ -329,7 +372,7 @@ fun Project.configureJvmTransformation( } } -fun String.toVariant(): Variant = enumValueOf(toUpperCase(Locale.US)) +fun String.toJvmVariant(): JvmVariant = enumValueOf(toUpperCase(Locale.US)) fun Project.createJvmTransformTask(compilation: KotlinCompilation<*>): AtomicFUTransformTask = tasks.create( @@ -358,7 +401,7 @@ fun AtomicFUTransformTask.configureJvmTask( classPath = classpath inputFiles = originalClassesDir outputDir = transformedClassesDir - variant = config.variant + jvmVariant = config.jvmVariant verbose = config.verbose } @@ -390,7 +433,7 @@ class AtomicFUPluginExtension(pluginVersion: String?) { var dependenciesVersion = pluginVersion var transformJvm = true var transformJs = true - var variant: String = "FU" + var jvmVariant: String = "FU" var verbose: Boolean = false } @@ -408,7 +451,7 @@ open class AtomicFUTransformTask : ConventionTask() { lateinit var classPath: FileCollection @Input - var variant = "FU" + var jvmVariant = "FU" @Input var verbose = false @@ -417,7 +460,7 @@ open class AtomicFUTransformTask : ConventionTask() { val cp = classPath.files.map { it.absolutePath } inputFiles.files.forEach { inputDir -> AtomicFUTransformer(cp, inputDir, outputDir).let { t -> - t.variant = variant.toVariant() + t.jvmVariant = jvmVariant.toJvmVariant() t.verbose = verbose t.transform() } diff --git a/atomicfu-maven-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/TransformMojo.kt b/atomicfu-maven-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/TransformMojo.kt index 28580d8..5f45f3e 100644 --- a/atomicfu-maven-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/TransformMojo.kt +++ b/atomicfu-maven-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/TransformMojo.kt @@ -17,7 +17,7 @@ package kotlinx.atomicfu.plugin import kotlinx.atomicfu.transformer.AtomicFUTransformer -import kotlinx.atomicfu.transformer.Variant +import kotlinx.atomicfu.transformer.JvmVariant import org.apache.maven.plugin.AbstractMojo import org.apache.maven.plugins.annotations.LifecyclePhase import org.apache.maven.plugins.annotations.Mojo @@ -50,8 +50,8 @@ class TransformMojo : AbstractMojo() { /** * Transformation variant: "FU", "VH", or "BOTH". */ - @Parameter(defaultValue = "FU", property = "variant", required = true) - lateinit var variant: Variant + @Parameter(defaultValue = "FU", property = "jvmVariant", required = true) + lateinit var jvmVariant: JvmVariant /** * Verbose debug info. @@ -60,7 +60,7 @@ class TransformMojo : AbstractMojo() { var verbose: Boolean = false override fun execute() { - val t = AtomicFUTransformer(classpath, input, output, variant) + val t = AtomicFUTransformer(classpath, input, output, jvmVariant) t.verbose = verbose t.transform() } diff --git a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt index ca6c143..a138422 100644 --- a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt +++ b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt @@ -168,13 +168,13 @@ class FieldInfo( override fun toString(): String = "${owner.prettyStr()}::$name" } -enum class Variant { FU, VH, BOTH } +enum class JvmVariant { FU, VH, BOTH } class AtomicFUTransformer( classpath: List, inputDir: File, outputDir: File = inputDir, - var variant: Variant = Variant.FU + var jvmVariant: JvmVariant = JvmVariant.FU ) : AtomicFUTransformerBase(inputDir, outputDir) { private val classPathLoader = URLClassLoader( @@ -195,7 +195,7 @@ class AtomicFUTransformer( val files = inputDir.walk().filter { it.isFile }.toList() val needTransform = analyzeFilesForFields(files) if (needTransform || outputDir == inputDir) { - val vh = variant == Variant.VH + val vh = jvmVariant == JvmVariant.VH // visit method bodies for external references to fields, runs all logic, fails if anything is wrong val needsTransform = analyzeFilesForRefs(files, vh) // perform transformation @@ -205,7 +205,7 @@ class AtomicFUTransformer( val outBytes = if (file.isClassFile() && file in needsTransform) transformFile(file, bytes, vh) else bytes val outFile = file.toOutputFile() outFile.mkdirsAndWrite(outBytes) - if (variant == Variant.BOTH && outBytes !== bytes) { + if (jvmVariant == JvmVariant.BOTH && outBytes !== bytes) { val vhBytes = transformFile(file, bytes, true) val vhFile = outputDir / "META-INF" / "versions" / "9" / file.relativeTo(inputDir).toString() vhFile.mkdirsAndWrite(vhBytes) @@ -1512,7 +1512,7 @@ fun main(args: Array) { } val t = AtomicFUTransformer(emptyList(), File(args[0])) if (args.size > 1) t.outputDir = File(args[1]) - if (args.size > 2) t.variant = enumValueOf(args[2].toUpperCase(Locale.US)) + if (args.size > 2) t.jvmVariant = enumValueOf(args[2].toUpperCase(Locale.US)) t.verbose = true t.transform() } -- cgit v1.2.3 From 450b056efa4c8e4f922f2a3f8d1958404513b1f7 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Thu, 14 Apr 2022 15:34:49 +0300 Subject: Version 0.17.2 --- CHANGES.md | 7 +++++++ README.md | 10 +++++----- gradle.properties | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index acb51de..2864b1c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,12 @@ # Change log for kotlinx.atomicfu +# Version 0.17.2 + +* Update Kotlin to 1.6.20. +* IR transformation for Kotlin/JS. (#215). +* Update ASM to 9.3 for Java 18 support (#223) +* Update kotlinx.metadata to 0.4.2. + # Version 0.17.1 * Support of `org.jetbrains.kotlin.js` plugin (#218). diff --git a/README.md b/README.md index 9944900..d7e8006 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![JetBrains incubator project](https://jb.gg/badges/incubator.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.17.1/pom) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.17.2/pom) The idiomatic way to use atomic operations in Kotlin. @@ -107,7 +107,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.17.1' + ext.atomicfu_version = '0.17.2' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -166,7 +166,7 @@ To set configuration options you should create `atomicfu` section in a `build.gr like this: ```groovy atomicfu { - dependenciesVersion = '0.17.1' + dependenciesVersion = '0.17.2' } ``` @@ -188,7 +188,7 @@ To turn off transformation for Kotlin/JS set option `transformJs` to `false`. Here are all available configuration options (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.17.1' // set to null to turn-off auto dependencies + dependenciesVersion = '0.17.2' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH jsVariant = "JS" // JS transformation variant: JS or IR @@ -202,7 +202,7 @@ Declare AtomicFU version: ```xml - 0.17.1 + 0.17.2 ``` diff --git a/gradle.properties b/gradle.properties index a039835..b0eb1d1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.17.1-SNAPSHOT +version=0.17.2-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.6.20 -- cgit v1.2.3 From 5527be00db846303a0dddef6a0b96c9b9823ab94 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Mon, 16 May 2022 16:20:49 +0300 Subject: Add compiler plugin dependency only for projects with KGP >= 1.6.20 (#226) * Add compiler plugin dependency only for projects with KGP >= 1.6.20 Fixes #225 * fixup --- .../atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 29 ++++++++++++++-------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index b1dd098..baeffd1 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -34,7 +34,7 @@ open class AtomicFUGradlePlugin : Plugin { val pluginVersion = rootProject.buildscript.configurations.findByName("classpath") ?.allDependencies?.find { it.name == "atomicfu-gradle-plugin" }?.version extensions.add(EXTENSION_NAME, AtomicFUPluginExtension(pluginVersion)) - if (rootProject.getBooleanProperty(ENABLE_IR_TRANSFORMATION)) { + if (rootProject.getBooleanProperty(ENABLE_IR_TRANSFORMATION) && isCompilerPluginAvailable()) { plugins.apply(AtomicfuKotlinGradleSubplugin::class.java) } configureDependencies() @@ -86,6 +86,15 @@ private fun Project.configureTasks() { } } +private fun Project.isCompilerPluginAvailable(): Boolean { + // kotlinx-atomicfu compiler plugin is available for KGP >= 1.6.20 + val (majorVersion, minorVersion, patch) = getKotlinPluginVersion() + .split('.') + .take(3) + .map { it.toInt() } + return majorVersion == 1 && (minorVersion == 6 && patch >= 20 || minorVersion > 6) +} + private fun Project.getBooleanProperty(name: String) = rootProject.findProperty(name)?.toString()?.toBooleanStrict() ?: false @@ -101,15 +110,15 @@ private fun Project.needsJsIrTransformation(target: KotlinTarget): Boolean = private fun KotlinTarget.isJsIrTarget() = (this is KotlinJsTarget && this.irTarget != null) || this is KotlinJsIrTarget private fun Project.addCompilerPluginDependency() { - val kotlinVersion = rootProject.buildscript.configurations.findByName("classpath") - ?.allDependencies?.find { it.name == "kotlin-gradle-plugin" }?.version - withKotlinTargets { target -> - if (needsJsIrTransformation(target)) { - target.compilations.forEach { kotlinCompilation -> - kotlinCompilation.dependencies { - // add atomicfu compiler plugin dependency - // to provide the `kotlinx-atomicfu-runtime` library used during compiler plugin transformation - compileOnly("org.jetbrains.kotlin:atomicfu:$kotlinVersion") + if (isCompilerPluginAvailable()) { + withKotlinTargets { target -> + if (needsJsIrTransformation(target)) { + target.compilations.forEach { kotlinCompilation -> + kotlinCompilation.dependencies { + // add atomicfu compiler plugin dependency + // to provide the `kotlinx-atomicfu-runtime` library used during compiler plugin transformation + compileOnly("org.jetbrains.kotlin:atomicfu:${getKotlinPluginVersion()}") + } } } } -- cgit v1.2.3 From d2e1011c9faacbc75a733843db92e25543345377 Mon Sep 17 00:00:00 2001 From: Egor Tolstoy Date: Wed, 25 May 2022 12:14:32 +0300 Subject: Update README.md (#228) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d7e8006..3b4cdb5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # AtomicFU -[![JetBrains incubator project](https://jb.gg/badges/incubator.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) +[![Kotlin Beta](https://kotl.in/badges/beta.svg)](https://kotlinlang.org/docs/components-stability.html) +[![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) [![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.17.2/pom) -- cgit v1.2.3 From cffaf0bf8490140766dd7ddb1baa042d34138cc0 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Mon, 30 May 2022 14:30:29 +0300 Subject: Add transitive dependency to `kotlinx-atomicfu-runtime` required for compiler plugin application (#230) Fixes #229 --- .../main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index baeffd1..5bd2f6b 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -117,7 +117,7 @@ private fun Project.addCompilerPluginDependency() { kotlinCompilation.dependencies { // add atomicfu compiler plugin dependency // to provide the `kotlinx-atomicfu-runtime` library used during compiler plugin transformation - compileOnly("org.jetbrains.kotlin:atomicfu:${getKotlinPluginVersion()}") + implementation("org.jetbrains.kotlin:atomicfu:${getKotlinPluginVersion()}") } } } -- cgit v1.2.3 From 9f8dcb1a55873807022af032b0c8627148033cc7 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Mon, 30 May 2022 14:54:04 +0300 Subject: Version 0.17.3 --- CHANGES.md | 6 ++++++ README.md | 10 +++++----- gradle.properties | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 2864b1c..907197d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change log for kotlinx.atomicfu +# Version 0.17.3 + +* Adding compiler plugin dependency only for projects with KGP >= 1.6.20 (#226). +* Compiler plugin runtime dependency fixes (#230). +* Update README badges (#228). + # Version 0.17.2 * Update Kotlin to 1.6.20. diff --git a/README.md b/README.md index 3b4cdb5..8ddded4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Kotlin Beta](https://kotl.in/badges/beta.svg)](https://kotlinlang.org/docs/components-stability.html) [![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.17.2/pom) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.17.3/pom) The idiomatic way to use atomic operations in Kotlin. @@ -108,7 +108,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.17.2' + ext.atomicfu_version = '0.17.3' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -167,7 +167,7 @@ To set configuration options you should create `atomicfu` section in a `build.gr like this: ```groovy atomicfu { - dependenciesVersion = '0.17.2' + dependenciesVersion = '0.17.3' } ``` @@ -189,7 +189,7 @@ To turn off transformation for Kotlin/JS set option `transformJs` to `false`. Here are all available configuration options (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.17.2' // set to null to turn-off auto dependencies + dependenciesVersion = '0.17.3' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH jsVariant = "JS" // JS transformation variant: JS or IR @@ -203,7 +203,7 @@ Declare AtomicFU version: ```xml - 0.17.2 + 0.17.3 ``` diff --git a/gradle.properties b/gradle.properties index b0eb1d1..286914c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.17.2-SNAPSHOT +version=0.17.3-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.6.20 -- cgit v1.2.3 From 6fee8d2315721bca8912b537b20db7c0333e6ca2 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Thu, 2 Jun 2022 15:34:35 +0300 Subject: Kotlin version format fix in AGP --- .../kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 5bd2f6b..7488799 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -88,10 +88,12 @@ private fun Project.configureTasks() { private fun Project.isCompilerPluginAvailable(): Boolean { // kotlinx-atomicfu compiler plugin is available for KGP >= 1.6.20 - val (majorVersion, minorVersion, patch) = getKotlinPluginVersion() + val kotlinVersion = getKotlinPluginVersion() + val (majorVersion, minorVersion) = kotlinVersion .split('.') - .take(3) + .take(2) .map { it.toInt() } + val patch = kotlinVersion.substringAfterLast('.').substringBefore('-').toInt() return majorVersion == 1 && (minorVersion == 6 && patch >= 20 || minorVersion > 6) } -- cgit v1.2.3 From 62907985d590f29ebb9feaecef51da3905c239e9 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Fri, 10 Jun 2022 18:04:19 +0300 Subject: Add compiler plugin dependency only if ENABLE_IR_TRANSFORMATION property is true --- .../main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 7488799..fe887c4 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -107,7 +107,7 @@ private fun String.toBooleanStrict(): Boolean = when (this) { } private fun Project.needsJsIrTransformation(target: KotlinTarget): Boolean = - config.transformJs && target.isJsIrTarget() + rootProject.getBooleanProperty(ENABLE_IR_TRANSFORMATION) && target.isJsIrTarget() private fun KotlinTarget.isJsIrTarget() = (this is KotlinJsTarget && this.irTarget != null) || this is KotlinJsIrTarget -- cgit v1.2.3 From d096806d0d2704d260403997f16bae489197e744 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Fri, 18 Feb 2022 14:24:40 +0300 Subject: Get rid of `useExperimentalAnnotation()` --- gradle/compile-options.gradle | 2 -- 1 file changed, 2 deletions(-) diff --git a/gradle/compile-options.gradle b/gradle/compile-options.gradle index e6b4432..b6ce532 100644 --- a/gradle/compile-options.gradle +++ b/gradle/compile-options.gradle @@ -21,8 +21,6 @@ ext.configureKotlin = { isMultiplatform -> languageSettings { apiVersion = "1.4" languageVersion = "1.4" - useExperimentalAnnotation("kotlin.Experimental") - useExperimentalAnnotation("kotlin.ExperimentalStdlibApi") } } } -- cgit v1.2.3 From a6104229b3f94af0998efbe8659ad56889f2d866 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Fri, 25 Mar 2022 19:18:10 +0100 Subject: Update script to be compatible with KGP breaking changes --- atomicfu-maven-plugin/build.gradle | 11 ++++++----- atomicfu/build.gradle | 10 +++++++--- gradle/interop-as-source-set-klib.gradle | 2 +- gradle/publish-npm-js.gradle | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/atomicfu-maven-plugin/build.gradle b/atomicfu-maven-plugin/build.gradle index b48d856..a165769 100644 --- a/atomicfu-maven-plugin/build.gradle +++ b/atomicfu-maven-plugin/build.gradle @@ -18,7 +18,7 @@ dependencies { } def pomFile = file("$buildDir/pom.xml") -def outputDir = compileKotlin.destinationDir +def outputDir = compileKotlin.destinationDirectory def buildSnapshots = rootProject.properties['build_snapshot_train'] != null evaluationDependsOn(':atomicfu-transformer') @@ -37,7 +37,7 @@ task generatePomFile(dependsOn: [compileKotlin, ':atomicfu-transformer:publishTo asNode().with { appendNode('build').with { appendNode('directory', buildDir) - appendNode('outputDirectory', outputDir) + appendNode('outputDirectory', outputDir.get().getAsFile()) } appendNode('properties').with { appendNode('project.build.sourceEncoding', 'UTF-8') @@ -69,7 +69,7 @@ String mavenRepoLocal = System.getProperty("maven.repo.local") // runs the plugin description generator task generatePluginDescriptor(type: Exec, dependsOn: generatePomFile) { - def pluginDescriptorFile = new File(outputDir, 'META-INF/maven/plugin.xml') + def pluginDescriptorFile = outputDir.file('META-INF/maven/plugin.xml') workingDir projectDir boolean isWindows = System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0 @@ -85,8 +85,9 @@ task generatePluginDescriptor(type: Exec, dependsOn: generatePomFile) { ]) commandLine args doLast { - assert pluginDescriptorFile.file, "$pluginDescriptorFile: was not generated" - logger.info("Plugin descriptor is generated in $pluginDescriptorFile") + def descriptorFile = pluginDescriptorFile.get().getAsFile() + assert descriptorFile, "$descriptorFile: was not generated" + logger.info("Plugin descriptor is generated in $descriptorFile") } } diff --git a/atomicfu/build.gradle b/atomicfu/build.gradle index cfee622..2374d59 100644 --- a/atomicfu/build.gradle +++ b/atomicfu/build.gradle @@ -327,7 +327,7 @@ task compileJavaModuleInfo(type: JavaCompile) { def moduleName = "kotlinx.atomicfu" // this module's name def compileKotlinJvm = kotlin.targets["jvm"].compilations["main"].compileKotlinTask def sourceDir = file("src/jvmMain/java9/") - def targetDir = file("${compileKotlinJvm.destinationDir}/../java9/") + def targetDir = compileKotlinJvm.destinationDirectory.map { it.dir("../java9/") } // Use a Java 11 compiler for the module info. javaCompiler.set(project.javaToolchains.compilerFor { languageVersion.set(JavaLanguageVersion.of(11)) }) @@ -353,7 +353,7 @@ task compileJavaModuleInfo(type: JavaCompile) { // Set the task outputs and destination dir outputs.dir(targetDir) - destinationDir = targetDir + destinationDirectory.set(targetDir) // Configure JVM compatibility sourceCompatibility = JavaVersion.VERSION_1_9.toString() @@ -367,12 +367,16 @@ task compileJavaModuleInfo(type: JavaCompile) { options.compilerArgs.add("-Xlint:-requires-transitive-automatic") // Patch the compileKotlinJvm output classes into the compilation so exporting packages works correctly. - options.compilerArgs.addAll(["--patch-module", "$moduleName=${compileKotlinJvm.destinationDir}"]) + options.compilerArgs.addAll(["--patch-module", "$moduleName=${compileKotlinJvm.destinationDirectory.get().getAsFile()}"]) // Use the classpath of the compileKotlinJvm task. // Also ensure that the module path is used instead of classpath. classpath = compileKotlinJvm.classpath modularity.inferModulePath.set(true) + + doFirst { + logger.warn("Task destination directory: ${destinationDirectory.get().getAsFile()}") + } } // Configure the JAR task so that it will include the compiled module-info class file. diff --git a/gradle/interop-as-source-set-klib.gradle b/gradle/interop-as-source-set-klib.gradle index 62f2b77..25cb0c2 100644 --- a/gradle/interop-as-source-set-klib.gradle +++ b/gradle/interop-as-source-set-klib.gradle @@ -7,7 +7,7 @@ project.ext.registerInteropAsSourceSetOutput = { interop, sourceSet -> def cinteropTask = tasks.named(interop.interopProcessingTaskName) def cinteropKlib = cinteropTask.map { it.outputFile } def fakeCinteropCompilation = kotlin.targets["metadata"].compilations[sourceSet.name] - def destination = fakeCinteropCompilation.compileKotlinTask.destinationDir + def destination = fakeCinteropCompilation.compileKotlinTask.destinationDirectory def tempDir = "$buildDir/tmp/${sourceSet.name}UnpackedInteropKlib" diff --git a/gradle/publish-npm-js.gradle b/gradle/publish-npm-js.gradle index e6760a7..b7e7264 100644 --- a/gradle/publish-npm-js.gradle +++ b/gradle/publish-npm-js.gradle @@ -29,7 +29,7 @@ task preparePublishNpm(type: Copy, dependsOn: [compileJsLegacy]) { from(npmTemplateDir) { expand (project.properties + [kotlinDependency: "\"kotlin\": \"$kotlin_version\""]) } - from(compileJsLegacy.destinationDir) + from(compileJsLegacy.destinationDirectory) into npmDeployDir } -- cgit v1.2.3 From de4a1a3a91624d17ca6596198b077d25b1e91481 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Wed, 6 Apr 2022 14:48:51 +0300 Subject: Fix kotlin 1.7 compatibility (#222) * Update Gradle plugin dependencies configuration Exclude dependencies provided by Gradle via runtime. * Fix Gradle plugin compatibility with Kotlin 1.7.0 release Backward compatability should also work. --- atomicfu-gradle-plugin/build.gradle | 16 +++++++++------- .../atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 19 +++++++++++++++++-- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/atomicfu-gradle-plugin/build.gradle b/atomicfu-gradle-plugin/build.gradle index 79ba241..c80dd0d 100644 --- a/atomicfu-gradle-plugin/build.gradle +++ b/atomicfu-gradle-plugin/build.gradle @@ -20,18 +20,20 @@ kotlin.sourceSets.all { } dependencies { - compile gradleApi() - compile project(":atomicfu-transformer") - compile 'org.jetbrains.kotlin:kotlin-stdlib' + implementation(project(":atomicfu-transformer")) { + exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib' + } + compileOnly gradleApi() + compileOnly 'org.jetbrains.kotlin:kotlin-stdlib' compileOnly "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // atomicfu compiler plugin dependency will be loaded to kotlinCompilerPluginClasspath implementation "org.jetbrains.kotlin:atomicfu:$kotlin_version" - testCompile gradleTestKit() - testCompile 'org.jetbrains.kotlin:kotlin-test' - testCompile 'org.jetbrains.kotlin:kotlin-test-junit' - testCompile 'junit:junit:4.12' + testImplementation gradleTestKit() + testImplementation 'org.jetbrains.kotlin:kotlin-test' + testImplementation 'org.jetbrains.kotlin:kotlin-test-junit' + testImplementation 'junit:junit:4.12' } configurations { diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index fe887c4..40c3410 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -21,6 +21,7 @@ import java.util.concurrent.* import org.jetbrains.kotlin.gradle.targets.js.* import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget import org.jetbrains.kotlinx.atomicfu.gradle.* +import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool private const val EXTENSION_NAME = "atomicfu" private const val ORIGINAL_DIR_NAME = "originalClassesDir" @@ -257,8 +258,22 @@ private fun Project.configureTransformationForTarget(target: KotlinTarget) { Callable { originalDirsByCompilation[mainCompilation]!! } ) - (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractCompile)?.classpath = - originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs + // KGP >= 1.7.0 has breaking changes in task hierarchy: + // https://youtrack.jetbrains.com/issue/KT-32805#focus=Comments-27-5915479.0-0 + val (majorVersion, minorVersion) = getKotlinPluginVersion() + .split('.') + .take(2) + .map { it.toInt() } + if (majorVersion == 1 && minorVersion < 7) { + (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractCompile)?.classpath = + originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs + } else { + (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractKotlinCompileTool<*>) + ?.libraries + ?.setFrom( + originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs + ) + } (tasks.findByName("${target.name}${compilation.name.capitalize()}") as? Test)?.classpath = originalMainClassesDirs + (compilation as KotlinCompilationToRunnableFiles).runtimeDependencyFiles - mainCompilation.output.classesDirs -- cgit v1.2.3 From 8e2a68eaa37afc2e9d583ed75a7cfc008e68f7c2 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Sat, 23 Apr 2022 01:03:59 +0200 Subject: Update JVM target to 1.8 See KT-45165. --- atomicfu/build.gradle | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/atomicfu/build.gradle b/atomicfu/build.gradle index 2374d59..6ef8b0b 100644 --- a/atomicfu/build.gradle +++ b/atomicfu/build.gradle @@ -220,7 +220,7 @@ def classesPostTransformBOTH = file("$buildDir/classes/kotlin/jvm/postTransforme tasks.withType(compileTestKotlinJvm.getClass()) { kotlinOptions { - jvmTarget = "1.6" + jvmTarget = "1.8" } } @@ -248,24 +248,6 @@ task transformVH(type: JavaExec, dependsOn: compileTestKotlinJvm) { outputs.dir(classesPostTransformVH) } -task checkJdk16() { - doLast { - if (!System.env.JDK_16) { - throw new GradleException("JDK_16 environment variable is not defined. " + - "Can't build against JDK 1.6 runtime and run JDK 1.6 compatibility tests. " + - "Please ensure JDK 1.6 is installed and that JDK_16 points to it.") - } - } -} - -task transformedTestFU_6(type: Test, dependsOn: [checkJdk16, transformFU]) { - executable = "$System.env.JDK_16/bin/java" - classpath = configurations.jvmTestRuntimeClasspath + project.files(classesPostTransformFU) - testClassesDirs = project.files(classesPostTransformFU) - exclude '**/*LFTest.*', '**/TraceToStringTest.*', '**/AtomicfuReferenceJsTest.*' - filter { setFailOnNoMatchingTests(false) } // to run excluded tests in Idea -} - task transformedTestFU_current(type: Test, dependsOn: transformFU) { classpath = files(configurations.jvmTestRuntimeClasspath, classesPostTransformFU) testClassesDirs = project.files(classesPostTransformFU) @@ -273,14 +255,6 @@ task transformedTestFU_current(type: Test, dependsOn: transformFU) { filter { setFailOnNoMatchingTests(false) } } -task transformedTestBOTH_6(type: Test, dependsOn: [checkJdk16, transformBOTH]) { - executable = "$System.env.JDK_16/bin/java" - classpath = files(configurations.jvmTestRuntimeClasspath, classesPostTransformBOTH) - testClassesDirs = project.files(classesPostTransformBOTH) - exclude '**/*LFTest.*', '**/TraceToStringTest.*', '**/TopLevelGeneratedDeclarationsReflectionTest.*', '**/SyntheticFUFieldsTest.*', '**/AtomicfuReferenceJsTest.*' - filter { setFailOnNoMatchingTests(false) } -} - task transformedTestBOTH_current(type: Test, dependsOn: transformBOTH) { classpath = files(configurations.jvmTestRuntimeClasspath, classesPostTransformBOTH) testClassesDirs = project.files(classesPostTransformBOTH) @@ -309,9 +283,7 @@ task testAtomicfuReferenceJs(type: Test, dependsOn: [compileTestKotlinJvm, trans } task jvmTestAll(dependsOn: [ - transformedTestFU_6, transformedTestFU_current, - transformedTestBOTH_6, transformedTestBOTH_current, transformedTestVH, testAtomicfuReferenceJs]) -- cgit v1.2.3 From 5fd4c7589ea36c2fcf5eea6ce04eb5510e7c4441 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Wed, 15 Jun 2022 19:16:20 +0300 Subject: Update Kotlin to 1.7.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 286914c..6837f00 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ version=0.17.3-SNAPSHOT group=org.jetbrains.kotlinx -kotlin_version=1.6.20 +kotlin_version=1.7.0 asm_version=9.3 slf4j_version=1.8.0-alpha2 junit_version=4.12 -- cgit v1.2.3 From 4e794f961df59d5b35311056229a0d3b90a03645 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Wed, 15 Jun 2022 20:01:07 +0300 Subject: Fix compatibility with KGP 1.7.0 for atomicfu-gradle-plugin --- atomicfu-gradle-plugin/build.gradle | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/atomicfu-gradle-plugin/build.gradle b/atomicfu-gradle-plugin/build.gradle index c80dd0d..5312551 100644 --- a/atomicfu-gradle-plugin/build.gradle +++ b/atomicfu-gradle-plugin/build.gradle @@ -37,7 +37,18 @@ dependencies { } configurations { - testPluginClasspath + testPluginClasspath { + attributes { + attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage.class, Usage.JAVA_RUNTIME) + ) + attribute( + Category.CATEGORY_ATTRIBUTE, + project.objects.named(Category.class, Category.LIBRARY) + ) + } + } } dependencies { -- cgit v1.2.3 From b1251612c5903c6792ac4e33be5104f74c09d7fe Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Wed, 15 Jun 2022 20:17:02 +0300 Subject: Update Kotlin version for atomicfu-gradle-plugin tests --- .../src/test/resources/projects/js-simple/js-simple.gradle.kts | 4 ++-- .../src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts | 2 +- .../src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts index a284a87..37a41e5 100644 --- a/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts +++ b/atomicfu-gradle-plugin/src/test/resources/projects/js-simple/js-simple.gradle.kts @@ -7,7 +7,7 @@ buildscript { } plugins { - kotlin("js") version "1.6.0" + kotlin("js") } apply(plugin = "kotlinx-atomicfu") @@ -35,4 +35,4 @@ kotlin { ) } } -} \ No newline at end of file +} diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts index fa1f4d8..db644ef 100644 --- a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts +++ b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/jvm-simple.gradle.kts @@ -8,7 +8,7 @@ buildscript { } plugins { - kotlin("jvm") version "1.6.0" + kotlin("jvm") } apply(plugin = "kotlinx-atomicfu") diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts index f289821..ed15d3d 100644 --- a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/mpp-simple.gradle.kts @@ -7,7 +7,7 @@ buildscript { } plugins { - kotlin("multiplatform") version "1.6.0" + kotlin("multiplatform") } apply(plugin = "kotlinx-atomicfu") -- cgit v1.2.3 From f24c7480a3897c0a7c33ef0aeee57632b4ef7c7f Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Wed, 15 Jun 2022 20:56:12 +0300 Subject: Version 0.18.0 --- CHANGES.md | 7 +++++++ README.md | 10 +++++----- gradle.properties | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 907197d..33a75eb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,12 @@ # Change log for kotlinx.atomicfu +# Version 0.18.0 + +* Update Kotlin to 1.7.0. +* Fix kotlin 1.7 compatibility (#222). +* Update JVM target to 1.8 (see KT-45165). +* Fix for parsing Kotlin version in AtomicfuGradlePlugin. + # Version 0.17.3 * Adding compiler plugin dependency only for projects with KGP >= 1.6.20 (#226). diff --git a/README.md b/README.md index 8ddded4..9c18bb5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Kotlin Beta](https://kotl.in/badges/beta.svg)](https://kotlinlang.org/docs/components-stability.html) [![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.17.3/pom) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.0/pom) The idiomatic way to use atomic operations in Kotlin. @@ -108,7 +108,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.17.3' + ext.atomicfu_version = '0.18.0' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -167,7 +167,7 @@ To set configuration options you should create `atomicfu` section in a `build.gr like this: ```groovy atomicfu { - dependenciesVersion = '0.17.3' + dependenciesVersion = '0.18.0' } ``` @@ -189,7 +189,7 @@ To turn off transformation for Kotlin/JS set option `transformJs` to `false`. Here are all available configuration options (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.17.3' // set to null to turn-off auto dependencies + dependenciesVersion = '0.18.0' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH jsVariant = "JS" // JS transformation variant: JS or IR @@ -203,7 +203,7 @@ Declare AtomicFU version: ```xml - 0.17.3 + 0.18.0 ``` diff --git a/gradle.properties b/gradle.properties index 6837f00..7856f9c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.17.3-SNAPSHOT +version=0.18.0-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.7.0 -- cgit v1.2.3 From e15ab1e9e553c303c8fe5dcfd7e5d8dead2f62de Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Wed, 29 Jun 2022 19:06:47 +0200 Subject: For kotlin >= 1.7.10 add published atomicfu-runtime dependency to the project --- .../atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 40c3410..574e514 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -118,9 +118,20 @@ private fun Project.addCompilerPluginDependency() { if (needsJsIrTransformation(target)) { target.compilations.forEach { kotlinCompilation -> kotlinCompilation.dependencies { - // add atomicfu compiler plugin dependency - // to provide the `kotlinx-atomicfu-runtime` library used during compiler plugin transformation - implementation("org.jetbrains.kotlin:atomicfu:${getKotlinPluginVersion()}") + val kotlinVersion = getKotlinPluginVersion() + val (majorVersion, minorVersion) = kotlinVersion + .split('.') + .take(2) + .map { it.toInt() } + val patch = kotlinVersion.substringAfterLast('.').substringBefore('-').toInt() + if (majorVersion == 1 && (minorVersion == 7 && patch >= 10 || minorVersion > 7)) { + // since Kotlin 1.7.10 we can add `atomicfu-runtime` dependency directly + implementation("org.jetbrains.kotlin:atomicfu-runtime:$kotlinVersion") + } else { + // add atomicfu compiler plugin dependency + // to provide the `atomicfu-runtime` library used during compiler plugin transformation + implementation("org.jetbrains.kotlin:atomicfu:$kotlinVersion") + } } } } -- cgit v1.2.3 From 0d1e8838df2d887df4e141dced11ce96505a52dd Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Thu, 30 Jun 2022 00:35:24 +0200 Subject: Version 0.18.1 --- CHANGES.md | 4 ++++ README.md | 10 +++++----- gradle.properties | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 33a75eb..3f284ae 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,9 @@ # Change log for kotlinx.atomicfu +# Version 0.18.1 + +* Fix for the compatibility issue: add `atomicfu-runtime` dependency directly since Kotlin 1.7.10. + # Version 0.18.0 * Update Kotlin to 1.7.0. diff --git a/README.md b/README.md index 9c18bb5..a29cfc5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Kotlin Beta](https://kotl.in/badges/beta.svg)](https://kotlinlang.org/docs/components-stability.html) [![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.0/pom) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.1/pom) The idiomatic way to use atomic operations in Kotlin. @@ -108,7 +108,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.18.0' + ext.atomicfu_version = '0.18.1' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -167,7 +167,7 @@ To set configuration options you should create `atomicfu` section in a `build.gr like this: ```groovy atomicfu { - dependenciesVersion = '0.18.0' + dependenciesVersion = '0.18.1' } ``` @@ -189,7 +189,7 @@ To turn off transformation for Kotlin/JS set option `transformJs` to `false`. Here are all available configuration options (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.18.0' // set to null to turn-off auto dependencies + dependenciesVersion = '0.18.1' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH jsVariant = "JS" // JS transformation variant: JS or IR @@ -203,7 +203,7 @@ Declare AtomicFU version: ```xml - 0.18.0 + 0.18.1 ``` diff --git a/gradle.properties b/gradle.properties index 7856f9c..9927821 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.18.0-SNAPSHOT +version=0.18.1-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.7.0 -- cgit v1.2.3 From 8f500b2c20abc2c614ad7d3d01bf5430f987f68c Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Thu, 30 Jun 2022 14:23:09 +0200 Subject: Revert incompatible change of the atomicfu-runtime module name. --- .../main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 574e514..21311ae 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -126,7 +126,7 @@ private fun Project.addCompilerPluginDependency() { val patch = kotlinVersion.substringAfterLast('.').substringBefore('-').toInt() if (majorVersion == 1 && (minorVersion == 7 && patch >= 10 || minorVersion > 7)) { // since Kotlin 1.7.10 we can add `atomicfu-runtime` dependency directly - implementation("org.jetbrains.kotlin:atomicfu-runtime:$kotlinVersion") + implementation("org.jetbrains.kotlin:kotlinx-atomicfu-runtime:$kotlinVersion") } else { // add atomicfu compiler plugin dependency // to provide the `atomicfu-runtime` library used during compiler plugin transformation -- cgit v1.2.3 From af28afafacb92d702673b7f8dc1b02e86edc4bb8 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Thu, 30 Jun 2022 16:24:10 +0200 Subject: Version 0.18.2 --- CHANGES.md | 6 ++++++ README.md | 10 +++++----- gradle.properties | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 3f284ae..7964ec6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change log for kotlinx.atomicfu +# Version 0.18.2 + +* In Kotlin 1.7.10 the name of `atomicfu-runtime` module was reverted back to `kotlinx-atomicfu-runtime`, + as the renaming was an incompatible change. + Fixed `atomicfu-gradle-plugin` to add `kotlinx-atomicfu-runtime` dependency directly. + # Version 0.18.1 * Fix for the compatibility issue: add `atomicfu-runtime` dependency directly since Kotlin 1.7.10. diff --git a/README.md b/README.md index a29cfc5..4f91495 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Kotlin Beta](https://kotl.in/badges/beta.svg)](https://kotlinlang.org/docs/components-stability.html) [![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.1/pom) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.2/pom) The idiomatic way to use atomic operations in Kotlin. @@ -108,7 +108,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.18.1' + ext.atomicfu_version = '0.18.2' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -167,7 +167,7 @@ To set configuration options you should create `atomicfu` section in a `build.gr like this: ```groovy atomicfu { - dependenciesVersion = '0.18.1' + dependenciesVersion = '0.18.2' } ``` @@ -189,7 +189,7 @@ To turn off transformation for Kotlin/JS set option `transformJs` to `false`. Here are all available configuration options (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.18.1' // set to null to turn-off auto dependencies + dependenciesVersion = '0.18.2' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH jsVariant = "JS" // JS transformation variant: JS or IR @@ -203,7 +203,7 @@ Declare AtomicFU version: ```xml - 0.18.1 + 0.18.2 ``` diff --git a/gradle.properties b/gradle.properties index 9927821..002bfbe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.18.1-SNAPSHOT +version=0.18.2-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.7.0 -- cgit v1.2.3 From c9fadaad76ac9485e9563562aa946e78f7374fe9 Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Wed, 20 Jul 2022 18:22:06 +0200 Subject: Fix of usage targets on extensions --- .../kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 21311ae..d91af4c 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -187,8 +187,8 @@ fun Project.withPluginWhenEvaluatedDependencies(plugin: String, fn: Project.(ver } fun Project.withKotlinTargets(fn: (KotlinTarget) -> Unit) { - extensions.findByType(KotlinProjectExtension::class.java)?.let { kotlinExtension -> - val targetsExtension = (kotlinExtension as? ExtensionAware)?.extensions?.findByName("targets") + extensions.findByType(KotlinTargetsContainer::class.java)?.let { kotlinExtension -> + val targetsExtension = kotlinExtension.targets @Suppress("UNCHECKED_CAST") val targets = targetsExtension as? NamedDomainObjectContainer // find all compilations given sourceSet belongs to -- cgit v1.2.3 From b40401ea459cf5cbc616e20d5b30281ad072dd72 Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Thu, 21 Jul 2022 10:57:57 +0200 Subject: Simplify withKotlinTargets --- .../atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 62 +++++++++++----------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index d91af4c..5c81462 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -188,11 +188,9 @@ fun Project.withPluginWhenEvaluatedDependencies(plugin: String, fn: Project.(ver fun Project.withKotlinTargets(fn: (KotlinTarget) -> Unit) { extensions.findByType(KotlinTargetsContainer::class.java)?.let { kotlinExtension -> - val targetsExtension = kotlinExtension.targets - @Suppress("UNCHECKED_CAST") - val targets = targetsExtension as? NamedDomainObjectContainer // find all compilations given sourceSet belongs to - targets?.all { target -> fn(target) } + kotlinExtension.targets + .all { target -> fn(target) } } } @@ -269,22 +267,22 @@ private fun Project.configureTransformationForTarget(target: KotlinTarget) { Callable { originalDirsByCompilation[mainCompilation]!! } ) - // KGP >= 1.7.0 has breaking changes in task hierarchy: - // https://youtrack.jetbrains.com/issue/KT-32805#focus=Comments-27-5915479.0-0 - val (majorVersion, minorVersion) = getKotlinPluginVersion() - .split('.') - .take(2) - .map { it.toInt() } - if (majorVersion == 1 && minorVersion < 7) { - (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractCompile)?.classpath = + // KGP >= 1.7.0 has breaking changes in task hierarchy: + // https://youtrack.jetbrains.com/issue/KT-32805#focus=Comments-27-5915479.0-0 + val (majorVersion, minorVersion) = getKotlinPluginVersion() + .split('.') + .take(2) + .map { it.toInt() } + if (majorVersion == 1 && minorVersion < 7) { + (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractCompile)?.classpath = + originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs + } else { + (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractKotlinCompileTool<*>) + ?.libraries + ?.setFrom( originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs - } else { - (tasks.findByName(compilation.compileKotlinTaskName) as? AbstractKotlinCompileTool<*>) - ?.libraries - ?.setFrom( - originalMainClassesDirs + compilation.compileDependencyFiles - mainCompilation.output.classesDirs - ) - } + ) + } (tasks.findByName("${target.name}${compilation.name.capitalize()}") as? Test)?.classpath = originalMainClassesDirs + (compilation as KotlinCompilationToRunnableFiles).runtimeDependencyFiles - mainCompilation.output.classesDirs @@ -313,13 +311,13 @@ fun Project.configureMultiplatformPluginDependencies(version: String) { if (rootProject.getBooleanProperty("kotlin.mpp.enableGranularSourceSetsMetadata")) { addCompilerPluginDependency() val mainConfigurationName = project.extensions.getByType(KotlinMultiplatformExtension::class.java).sourceSets - .getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) - .compileOnlyConfigurationName + .getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) + .compileOnlyConfigurationName dependencies.add(mainConfigurationName, getAtomicfuDependencyNotation(Platform.MULTIPLATFORM, version)) val testConfigurationName = project.extensions.getByType(KotlinMultiplatformExtension::class.java).sourceSets - .getByName(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) - .implementationConfigurationName + .getByName(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) + .implementationConfigurationName dependencies.add(testConfigurationName, getAtomicfuDependencyNotation(Platform.MULTIPLATFORM, version)) // For each source set that is only used in Native compilations, add an implementation dependency so that it @@ -341,15 +339,15 @@ fun Project.configureMultiplatformPluginDependencies(version: String) { if (compilationNames.size != 1) error("Source set '${sourceSet.name}' of project '$name' is part of several compilations $compilationNames") val compilationType = compilationNames.single().compilationNameToType() - ?: return@forEach // skip unknown compilations + ?: return@forEach // skip unknown compilations val platform = - if (platformTypes.size > 1) Platform.MULTIPLATFORM else // mix of platform types -> "common" - when (platformTypes.single()) { - KotlinPlatformType.common -> Platform.MULTIPLATFORM - KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> Platform.JVM - KotlinPlatformType.js -> Platform.JS - KotlinPlatformType.native, KotlinPlatformType.wasm -> Platform.NATIVE - } + if (platformTypes.size > 1) Platform.MULTIPLATFORM else // mix of platform types -> "common" + when (platformTypes.single()) { + KotlinPlatformType.common -> Platform.MULTIPLATFORM + KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> Platform.JVM + KotlinPlatformType.js -> Platform.JS + KotlinPlatformType.native, KotlinPlatformType.wasm -> Platform.NATIVE + } val configurationName = when { // impl dependency for native (there is no transformation) platform == Platform.NATIVE -> sourceSet.implementationConfigurationName @@ -489,6 +487,7 @@ open class AtomicFUTransformTask : ConventionTask() { @Input var jvmVariant = "FU" + @Input var verbose = false @@ -513,6 +512,7 @@ open class AtomicFUTransformJsTask : ConventionTask() { @OutputDirectory lateinit var outputDir: File + @Input var verbose = false -- cgit v1.2.3 From 17d336385814a87311601b3f350e0afc4b3cd239 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Thu, 21 Jul 2022 18:15:37 +0200 Subject: Version 0.18.3 --- CHANGES.md | 4 ++++ README.md | 10 +++++----- gradle.properties | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7964ec6..a4df5fd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,9 @@ # Change log for kotlinx.atomicfu +# Version 0.18.3 + +* Fix for atomicfu-gradle-plugin application to the MPP project (for Kotlin 1.7.20). + # Version 0.18.2 * In Kotlin 1.7.10 the name of `atomicfu-runtime` module was reverted back to `kotlinx-atomicfu-runtime`, diff --git a/README.md b/README.md index 4f91495..5d42a79 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Kotlin Beta](https://kotl.in/badges/beta.svg)](https://kotlinlang.org/docs/components-stability.html) [![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.2/pom) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.3/pom) The idiomatic way to use atomic operations in Kotlin. @@ -108,7 +108,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.18.2' + ext.atomicfu_version = '0.18.3' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -167,7 +167,7 @@ To set configuration options you should create `atomicfu` section in a `build.gr like this: ```groovy atomicfu { - dependenciesVersion = '0.18.2' + dependenciesVersion = '0.18.3' } ``` @@ -189,7 +189,7 @@ To turn off transformation for Kotlin/JS set option `transformJs` to `false`. Here are all available configuration options (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.18.2' // set to null to turn-off auto dependencies + dependenciesVersion = '0.18.3' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH jsVariant = "JS" // JS transformation variant: JS or IR @@ -203,7 +203,7 @@ Declare AtomicFU version: ```xml - 0.18.2 + 0.18.3 ``` diff --git a/gradle.properties b/gradle.properties index 002bfbe..3ee91aa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.18.2-SNAPSHOT +version=0.18.3-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.7.0 -- cgit v1.2.3 From 797ec3b6c38c5de0ab02abad5c21d8abc005696d Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Tue, 30 Aug 2022 17:05:21 +0300 Subject: Update README to better reflect its experimental status (#243) --- README.md | 57 ++++++++++----------------------------------------------- 1 file changed, 10 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 5d42a79..b92141e 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,16 @@ [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) [![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.3/pom) +>Note on Beta status: the plugin is in its active development phase and changes from release to release. +>We do provide a compatibility of atomicfu-transformed artifacts between releases, but we do not provide +>strict compatibility guarantees on plugin API and its general stability between Kotlin versions. + The idiomatic way to use atomic operations in Kotlin. * Code it like `AtomicReference/Int/Long`, but run it in production efficiently as `AtomicXxxFieldUpdater` on Kotlin/JVM and as plain unboxed values on Kotlin/JS. * Use Kotlin-specific extensions (e.g. inline `updateAndGet` and `getAndUpdate` functions). -* Compile-time dependency only (no runtime dependencies). +* Compile-time dependency only for JVM and JS/IR (no runtime dependencies). * Post-compilation bytecode transformer that declares all the relevant field updaters for you on [Kotlin/JVM](#jvm). * Post-compilation JavaScript files transformer on [Kotlin/JS](#js). * Multiplatform: @@ -23,7 +27,6 @@ The idiomatic way to use atomic operations in Kotlin. * [Arrays of atomic values](#arrays-of-atomic-values). * [User-defined extensions on atomics](#user-defined-extensions-on-atomics) * [Locks](#locks) - * [Testing of lock-free data structures](#testing-lock-free-data-structures-on-jvm). * [Tracing operations](#tracing-operations) ## Example @@ -101,9 +104,8 @@ Building with Gradle is supported for all platforms. ### JVM -You will need Gradle 4.10 or later. -Add and apply AtomicFU plugin. It adds all the corresponding dependencies -and transformations automatically. +You will need Gradle 6.8 or later. +Add and apply AtomicFU plugin. It adds all the corresponding dependencies and transformations automatically. See [additional configuration](#additional-configuration) if that needs tweaking. ```groovy @@ -125,8 +127,6 @@ Configure add apply plugin just like for [JVM](#jvm). ### Native This library is available for Kotlin/Native (`atomicfu-native`). -Kotlin/Native uses Gradle metadata and needs Gradle version 5.3 or later. -See [Gradle Metadata 1.0 announcement](https://blog.gradle.org/gradle-metadata-1.0) for more details. Apply the corresponding plugin just like for [JVM](#jvm). Atomic references for Kotlin/Native are based on @@ -315,46 +315,9 @@ use `lock`/`tryLock`/`unlock` functions or `lock.withLock { ... }` extension fun [jucl.ReentrantLock](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReentrantLock.html) is used on JVM. On JVM it is a typealias to the later class, erased on JS. -Condition variables (`notify`/`wait` and `signal`/`await`) are not supported. - -### Testing lock-free data structures on JVM - -You can optionally test lock-freedomness of lock-free data structures using -[`LockFreedomTestEnvironment`](atomicfu/src/jvmMain/kotlin/kotlinx/atomicfu/LockFreedomTestEnvironment.kt) class. -See example in [`LockFreeQueueLFTest`](atomicfu/src/jvmTest/kotlin/kotlinx/atomicfu/test/LockFreeQueueLFTest.kt). -Testing is performed by pausing one (random) thread before or after a random state-update operation and -making sure that all other threads can still make progress. - -In order to make those test to actually perform lock-freedomness testing you need to configure an additional -execution of tests with the original (non-transformed) classes for Maven: - -```xml - - - - - maven-surefire-plugin - - - lockfree-test - test - - test - - - ${project.build.directory}/classes-pre-atomicfu - - **/*LFTest.* - - - - - - - -``` - -For Gradle there is nothing else to add. Tests are always run using original (non-transformed) classes. +> Note that package `kotlinx.atomicfu.locks` is experimental explicitly even while atomicfu is experimental itself, +> meaning that no ABI guarantees are provided whatsoever. API from this package is not recommended to use in libraries +> that other projects depend on. ### Tracing operations -- cgit v1.2.3 From 97c9a52b3cd92c851a05c96ef1c1eff4e9563aa0 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Wed, 14 Sep 2022 23:15:38 +0200 Subject: Update kotlinx.metadata to 0.5.0 (#245) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3ee91aa..693ffa4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ kotlin_version=1.7.0 asm_version=9.3 slf4j_version=1.8.0-alpha2 junit_version=4.12 -kotlinx_metadata_version=0.4.2 +kotlinx_metadata_version=0.5.0 maven_version=3.5.3 -- cgit v1.2.3 From 497fd6f28a9cbe0437f589941d43bb587a5fd849 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Thu, 15 Sep 2022 15:58:37 +0200 Subject: Update gradle version to 6.8.3 (#244) --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 703238f..0904b9b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-all.zip -- cgit v1.2.3 From b09e1b29760dee9b1840b8b79512e0e88d62cb80 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Wed, 28 Sep 2022 17:06:20 +0200 Subject: Pass friendPaths via BaseKotlinCompile$friendPath (#247) Fix for KT-54167 --- .../atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 23 +++++++--------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 5c81462..9cb2a1a 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -14,14 +14,15 @@ import org.gradle.api.tasks.compile.* import org.gradle.api.tasks.testing.* import org.gradle.jvm.tasks.* import org.jetbrains.kotlin.gradle.dsl.* +import org.jetbrains.kotlin.gradle.dsl.KotlinCompile import org.jetbrains.kotlin.gradle.plugin.* import java.io.* import java.util.* import java.util.concurrent.* import org.jetbrains.kotlin.gradle.targets.js.* import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget +import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlinx.atomicfu.gradle.* -import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool private const val EXTENSION_NAME = "atomicfu" private const val ORIGINAL_DIR_NAME = "originalClassesDir" @@ -194,14 +195,9 @@ fun Project.withKotlinTargets(fn: (KotlinTarget) -> Unit) { } } -private fun KotlinCommonOptions.addFriendPaths(friendPathsFileCollection: FileCollection) { - val argName = when (this) { - is KotlinJvmOptions -> "-Xfriend-paths" - is KotlinJsOptions -> "-Xfriend-modules" - else -> return - } - freeCompilerArgs = freeCompilerArgs + "$argName=${friendPathsFileCollection.joinToString(",")}" -} +// Fixes KT-KT-54167 (works only for KGP 1.7.0+) +private fun BaseKotlinCompile.setFriendPaths(friendPathsFileCollection: FileCollection) = + friendPaths.from(friendPathsFileCollection) fun Project.configureJsTransformation() = configureTransformationForTarget((kotlinExtension as KotlinJsProjectExtension).js()) @@ -287,10 +283,7 @@ private fun Project.configureTransformationForTarget(target: KotlinTarget) { (tasks.findByName("${target.name}${compilation.name.capitalize()}") as? Test)?.classpath = originalMainClassesDirs + (compilation as KotlinCompilationToRunnableFiles).runtimeDependencyFiles - mainCompilation.output.classesDirs - val kotlinOptions = compilation.kotlinOptions - compilation.compileKotlinTask.doFirst { - kotlinOptions.addFriendPaths(originalMainClassesDirs) - } + (compilation.compileKotlinTask as BaseKotlinCompile).setFriendPaths(originalMainClassesDirs) } } } @@ -395,9 +388,7 @@ fun Project.configureJvmTransformation( classpath = originalMainClassesDirs + sourceSet.compileClasspath - mainSourceSet.output.classesDirs - (this as? KotlinCompile<*>)?.doFirst { - kotlinOptions.addFriendPaths(originalMainClassesDirs) - } + (this as? BaseKotlinCompile)?.setFriendPaths(originalMainClassesDirs) } // todo: fix test runtime classpath for JS? -- cgit v1.2.3 From ea661bc5aecdcd3a0a19c3f1c4faf4f39d4fac08 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Wed, 5 Oct 2022 11:07:40 +0200 Subject: Backward compatibility for the passing the friendPaths (#249) --- .../atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 9cb2a1a..4a53251 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -195,9 +195,18 @@ fun Project.withKotlinTargets(fn: (KotlinTarget) -> Unit) { } } -// Fixes KT-KT-54167 (works only for KGP 1.7.0+) -private fun BaseKotlinCompile.setFriendPaths(friendPathsFileCollection: FileCollection) = - friendPaths.from(friendPathsFileCollection) +private fun KotlinCompile<*>.setFriendPaths(friendPathsFileCollection: FileCollection) { + val (majorVersion, minorVersion) = project.getKotlinPluginVersion() + .split('.') + .take(2) + .map { it.toInt() } + if (majorVersion == 1 && minorVersion < 7) { + (this as? AbstractKotlinCompile<*>)?.friendPaths?.from(friendPathsFileCollection) + } else { + // See KT-KT-54167 (works only for KGP 1.7.0+) + (this as BaseKotlinCompile).friendPaths.from(friendPathsFileCollection) + } +} fun Project.configureJsTransformation() = configureTransformationForTarget((kotlinExtension as KotlinJsProjectExtension).js()) @@ -283,7 +292,7 @@ private fun Project.configureTransformationForTarget(target: KotlinTarget) { (tasks.findByName("${target.name}${compilation.name.capitalize()}") as? Test)?.classpath = originalMainClassesDirs + (compilation as KotlinCompilationToRunnableFiles).runtimeDependencyFiles - mainCompilation.output.classesDirs - (compilation.compileKotlinTask as BaseKotlinCompile).setFriendPaths(originalMainClassesDirs) + compilation.compileKotlinTask.setFriendPaths(originalMainClassesDirs) } } } @@ -388,7 +397,7 @@ fun Project.configureJvmTransformation( classpath = originalMainClassesDirs + sourceSet.compileClasspath - mainSourceSet.output.classesDirs - (this as? BaseKotlinCompile)?.setFriendPaths(originalMainClassesDirs) + (this as? KotlinCompile<*>)?.setFriendPaths(originalMainClassesDirs) } // todo: fix test runtime classpath for JS? -- cgit v1.2.3 From 0cc46d69fe3883c0283640024994289bb2a1a2f4 Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Fri, 7 Oct 2022 09:34:02 +0200 Subject: Version 0.18.4 --- CHANGES.md | 6 ++++++ README.md | 10 +++++----- gradle.properties | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a4df5fd..4225c92 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change log for kotlinx.atomicfu +# Version 0.18.4 + +* Fix KGP compatibility bug with freeCompilerArgs modification (#247). +* Update kotlinx.metadata to 0.5.0 (#245). +* Update gradle version to 6.8.3 (#244) + # Version 0.18.3 * Fix for atomicfu-gradle-plugin application to the MPP project (for Kotlin 1.7.20). diff --git a/README.md b/README.md index b92141e..c34cd44 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Kotlin Beta](https://kotl.in/badges/beta.svg)](https://kotlinlang.org/docs/components-stability.html) [![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.3/pom) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.4/pom) >Note on Beta status: the plugin is in its active development phase and changes from release to release. >We do provide a compatibility of atomicfu-transformed artifacts between releases, but we do not provide @@ -110,7 +110,7 @@ See [additional configuration](#additional-configuration) if that needs tweaking ```groovy buildscript { - ext.atomicfu_version = '0.18.3' + ext.atomicfu_version = '0.18.4' dependencies { classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" @@ -167,7 +167,7 @@ To set configuration options you should create `atomicfu` section in a `build.gr like this: ```groovy atomicfu { - dependenciesVersion = '0.18.3' + dependenciesVersion = '0.18.4' } ``` @@ -189,7 +189,7 @@ To turn off transformation for Kotlin/JS set option `transformJs` to `false`. Here are all available configuration options (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.18.3' // set to null to turn-off auto dependencies + dependenciesVersion = '0.18.4' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH jsVariant = "JS" // JS transformation variant: JS or IR @@ -203,7 +203,7 @@ Declare AtomicFU version: ```xml - 0.18.3 + 0.18.4 ``` diff --git a/gradle.properties b/gradle.properties index 693ffa4..de1cd79 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.18.3-SNAPSHOT +version=0.18.4-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.7.0 -- cgit v1.2.3 From d6ecd362540ac03adf62447bf6f9bdd003832535 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Tue, 18 Oct 2022 15:35:47 +0200 Subject: Support JVM IR compiler plugin in AtomicfuGradlePlugin (#246) * Support a new compiler plugin extension with flags, allowing to apply the plugin separately to JS ans JVM targets * Use kotlin.targets in dsl * Update Kotlin to 1.7.20 Co-authored-by: Margarita Bobova --- .../atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt | 68 ++++++++++++++++------ atomicfu/build.gradle | 6 +- gradle.properties | 2 +- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt index 4a53251..b77e95b 100644 --- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt +++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt @@ -29,16 +29,18 @@ private const val ORIGINAL_DIR_NAME = "originalClassesDir" private const val COMPILE_ONLY_CONFIGURATION = "compileOnly" private const val IMPLEMENTATION_CONFIGURATION = "implementation" private const val TEST_IMPLEMENTATION_CONFIGURATION = "testImplementation" -private const val ENABLE_IR_TRANSFORMATION = "kotlinx.atomicfu.enableIrTransformation" +// If the project uses KGP <= 1.6.20, only JS IR compiler plugin is available, and it is turned on via setting this property. +// The property is supported for backwards compatibility. +private const val ENABLE_JS_IR_TRANSFORMATION_LEGACY = "kotlinx.atomicfu.enableIrTransformation" +private const val ENABLE_JS_IR_TRANSFORMATION = "kotlinx.atomicfu.enableJsIrTransformation" +private const val ENABLE_JVM_IR_TRANSFORMATION = "kotlinx.atomicfu.enableJvmIrTransformation" open class AtomicFUGradlePlugin : Plugin { override fun apply(project: Project) = project.run { val pluginVersion = rootProject.buildscript.configurations.findByName("classpath") ?.allDependencies?.find { it.name == "atomicfu-gradle-plugin" }?.version extensions.add(EXTENSION_NAME, AtomicFUPluginExtension(pluginVersion)) - if (rootProject.getBooleanProperty(ENABLE_IR_TRANSFORMATION) && isCompilerPluginAvailable()) { - plugins.apply(AtomicfuKotlinGradleSubplugin::class.java) - } + applyAtomicfuCompilerPlugin() configureDependencies() configureTasks() } @@ -69,6 +71,8 @@ private fun Project.configureTasks() { val config = config withPluginWhenEvaluated("kotlin") { if (config.transformJvm) { + // skip transformation task if ir transformation is enabled + if (rootProject.getBooleanProperty(ENABLE_JVM_IR_TRANSFORMATION)) return@withPluginWhenEvaluated configureJvmTransformation("compileTestKotlin") { sourceSet, transformedDir, originalDir -> createJvmTransformTask(sourceSet).configureJvmTask( sourceSet.compileClasspath, @@ -88,15 +92,45 @@ private fun Project.configureTasks() { } } -private fun Project.isCompilerPluginAvailable(): Boolean { - // kotlinx-atomicfu compiler plugin is available for KGP >= 1.6.20 +private data class KotlinVersion(val major: Int, val minor: Int, val patch: Int) + +private fun Project.getKotlinVersion(): KotlinVersion { val kotlinVersion = getKotlinPluginVersion() - val (majorVersion, minorVersion) = kotlinVersion + val (major, minor) = kotlinVersion .split('.') .take(2) .map { it.toInt() } val patch = kotlinVersion.substringAfterLast('.').substringBefore('-').toInt() - return majorVersion == 1 && (minorVersion == 6 && patch >= 20 || minorVersion > 6) + return KotlinVersion(major, minor, patch) +} + +private fun KotlinVersion.atLeast(major: Int, minor: Int, patch: Int) = + this.major == major && (this.minor == minor && this.patch >= patch || this.minor > minor) || this.major > major + +// kotlinx-atomicfu compiler plugin is available for KGP >= 1.6.20 +private fun Project.isCompilerPluginAvailable() = getKotlinVersion().atLeast(1, 6, 20) + +private fun Project.applyAtomicfuCompilerPlugin() { + val kotlinVersion = getKotlinVersion() + // for KGP >= 1.7.20: + // compiler plugin for JS IR is applied via the property `kotlinx.atomicfu.enableJsIrTransformation` + // compiler plugin for JVM IR is applied via the property `kotlinx.atomicfu.enableJvmIrTransformation` + if (kotlinVersion.atLeast(1, 7, 20)) { + plugins.apply(AtomicfuKotlinGradleSubplugin::class.java) + extensions.getByType(AtomicfuKotlinGradleSubplugin.AtomicfuKotlinGradleExtension::class.java).apply { + isJsIrTransformationEnabled = rootProject.getBooleanProperty(ENABLE_JS_IR_TRANSFORMATION) + isJvmIrTransformationEnabled = rootProject.getBooleanProperty(ENABLE_JVM_IR_TRANSFORMATION) + } + } else { + // for KGP >= 1.6.20 && KGP <= 1.7.20: + // compiler plugin for JS IR is applied via the property `kotlinx.atomicfu.enableIrTransformation` + // compiler plugin for JVM IR is not supported yet + if (kotlinVersion.atLeast(1, 6, 20)) { + if (rootProject.getBooleanProperty(ENABLE_JS_IR_TRANSFORMATION_LEGACY)) { + plugins.apply(AtomicfuKotlinGradleSubplugin::class.java) + } + } + } } private fun Project.getBooleanProperty(name: String) = @@ -109,7 +143,8 @@ private fun String.toBooleanStrict(): Boolean = when (this) { } private fun Project.needsJsIrTransformation(target: KotlinTarget): Boolean = - rootProject.getBooleanProperty(ENABLE_IR_TRANSFORMATION) && target.isJsIrTarget() + (rootProject.getBooleanProperty(ENABLE_JS_IR_TRANSFORMATION) || rootProject.getBooleanProperty(ENABLE_JS_IR_TRANSFORMATION_LEGACY)) + && target.isJsIrTarget() private fun KotlinTarget.isJsIrTarget() = (this is KotlinJsTarget && this.irTarget != null) || this is KotlinJsIrTarget @@ -119,19 +154,13 @@ private fun Project.addCompilerPluginDependency() { if (needsJsIrTransformation(target)) { target.compilations.forEach { kotlinCompilation -> kotlinCompilation.dependencies { - val kotlinVersion = getKotlinPluginVersion() - val (majorVersion, minorVersion) = kotlinVersion - .split('.') - .take(2) - .map { it.toInt() } - val patch = kotlinVersion.substringAfterLast('.').substringBefore('-').toInt() - if (majorVersion == 1 && (minorVersion == 7 && patch >= 10 || minorVersion > 7)) { + if (getKotlinVersion().atLeast(1, 7, 10)) { // since Kotlin 1.7.10 we can add `atomicfu-runtime` dependency directly - implementation("org.jetbrains.kotlin:kotlinx-atomicfu-runtime:$kotlinVersion") + implementation("org.jetbrains.kotlin:kotlinx-atomicfu-runtime:${getKotlinPluginVersion()}") } else { // add atomicfu compiler plugin dependency // to provide the `atomicfu-runtime` library used during compiler plugin transformation - implementation("org.jetbrains.kotlin:atomicfu:$kotlinVersion") + implementation("org.jetbrains.kotlin:atomicfu:${getKotlinPluginVersion()}") } } } @@ -234,7 +263,8 @@ private fun Project.configureTransformationForTarget(target: KotlinTarget) { project.buildDir.resolve("classes/atomicfu/${target.name}/${compilation.name}") val transformTask = when (target.platformType) { KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> { - if (!config.transformJvm) return@compilations // skip when transformation is turned off + // skip transformation task if transformation is turned off or ir transformation is enabled + if (!config.transformJvm || rootProject.getBooleanProperty(ENABLE_JVM_IR_TRANSFORMATION)) return@compilations project.createJvmTransformTask(compilation).configureJvmTask( compilation.compileDependencyFiles, compilation.compileAllTaskName, diff --git a/atomicfu/build.gradle b/atomicfu/build.gradle index 6ef8b0b..063c9a3 100644 --- a/atomicfu/build.gradle +++ b/atomicfu/build.gradle @@ -18,8 +18,10 @@ ext { } kotlin { - targets.metaClass.addTarget = { preset -> - addNative(delegate.fromPreset(preset, preset.name)) + targets { + delegate.metaClass.addTarget = { preset -> + addNative(delegate.fromPreset(preset, preset.name)) + } } // JS -- always diff --git a/gradle.properties b/gradle.properties index de1cd79..988e974 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ version=0.18.4-SNAPSHOT group=org.jetbrains.kotlinx -kotlin_version=1.7.0 +kotlin_version=1.7.20 asm_version=9.3 slf4j_version=1.8.0-alpha2 junit_version=4.12 -- cgit v1.2.3 From 4a6eac1aefbd271196f7bb81f1d3f975930f0793 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Tue, 25 Oct 2022 12:54:39 +0200 Subject: More tests for atomicfu-gradle-plugin (#255) * Added tests for atomicfu-gradle-plugin --- .../atomicfu/plugin/gradle/internal/TestDsl.kt | 10 +- .../plugin/gradle/test/BaseKotlinGradleTest.kt | 78 +++++++- .../atomicfu/plugin/gradle/test/JsProjectTest.kt | 49 +++-- .../atomicfu/plugin/gradle/test/JvmProjectTest.kt | 104 +++++++--- .../atomicfu/plugin/gradle/test/MppProjectTest.kt | 217 ++++++++++++++++++--- .../projects/jvm-simple/gradle.properties | 1 + .../projects/mpp-simple/gradle.properties_both | 3 + .../projects/mpp-simple/gradle.properties_js | 2 + .../projects/mpp-simple/gradle.properties_jvm | 1 + 9 files changed, 376 insertions(+), 89 deletions(-) create mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/gradle.properties create mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_both create mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_js create mode 100644 atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_jvm diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt index 2a51f1b..2541b41 100644 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/internal/TestDsl.kt @@ -61,6 +61,14 @@ internal fun FileContainer.settingsGradleKts(fn: AppendableScope.() -> Unit) { file(fileName, fn) } +/** + * Shortcut for creating a `gradle.properties` by using [file][FileContainer.file] + */ +internal fun FileContainer.gradleProperties(fn: AppendableScope.() -> Unit) { + val fileName = "gradle.properties" + file(fileName, fn) +} + /** * Declares a directory with the given [dirName] inside the current container. * All calls creating files within this scope will create the files nested in this directory. @@ -128,4 +136,4 @@ internal fun getFile(fileName: String): File { internal fun GradleRunner.addPluginTestRuntimeClasspath() = apply { val pluginClasspath = getFile("plugin-classpath.txt").readLines().map { File(it) } withPluginClasspath(pluginClasspath) -} \ No newline at end of file +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt index f6ec8ef..e9ff7bb 100644 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/BaseKotlinGradleTest.kt @@ -5,10 +5,14 @@ package kotlinx.atomicfu.plugin.gradle.test import kotlinx.atomicfu.plugin.gradle.internal.* +import org.objectweb.asm.* import java.io.File +import kotlin.test.* -open class BaseKotlinGradleTest(private val projectName: String) { +abstract class BaseKotlinGradleTest(private val projectName: String) { internal val rootProjectDir: File + private val ATOMIC_FU_REF = "Lkotlinx/atomicfu/".toByteArray() + private val KOTLIN_METADATA_DESC = "Lkotlin/Metadata;" init { rootProjectDir = File("build${File.separator}test-$projectName").absoluteFile @@ -16,21 +20,48 @@ open class BaseKotlinGradleTest(private val projectName: String) { rootProjectDir.mkdirs() } + internal abstract fun BaseKotlinScope.createProject() + + val runner = test { + createProject() + runner { + arguments.add(":build") + } + } + + fun checkTaskOutcomes(executedTasks: List, excludedTasks: List) { + runner.build().apply { + val tasks = tasks.map { it.path } + excludedTasks.forEach { + check(it !in tasks) { "Post-compilation transformation task $it was added in the compiler plugin mode" } + } + executedTasks.forEach { + assertTaskSuccess(it) + } + } + // check that task outcomes are cached for the second build + runner.build().apply { + executedTasks.forEach { + assertTaskUpToDate(it) + } + } + } + fun checkJvmCompilationClasspath(originalClassFile: String, transformedClassFile: String) { - // check that test compilation depends on transformed main sources + // check that test compile and runtime classpath does not contain original non-transformed classes val testCompileClasspathFiles = rootProjectDir.filesFrom("build/test_compile_jvm_classpath.txt") val testRuntimeClasspathFiles = rootProjectDir.filesFrom("build/test_runtime_jvm_classpath.txt") rootProjectDir.resolve(transformedClassFile).let { it.checkExists() - check(it in testCompileClasspathFiles) { "Original '$it' is missing from test compile classpath" } - check(it in testRuntimeClasspathFiles) { "Original '$it' is missing from test runtime classpath" } + check(it in testCompileClasspathFiles) { "Transformed '$it' is missing from test compile classpath" } + check(it in testRuntimeClasspathFiles) { "Transformed '$it' is missing from test runtime classpath" } } rootProjectDir.resolve(originalClassFile).let { it.checkExists() - check(it !in testCompileClasspathFiles) { "Transformed '$it' is present in test compile classpath" } - check(it !in testRuntimeClasspathFiles) { "Transformed '$it' is present in test runtime classpath" } + check(it !in testCompileClasspathFiles) { "Original '$it' is present in test compile classpath" } + check(it !in testRuntimeClasspathFiles) { "Original '$it' is present in test runtime classpath" } } } @@ -40,7 +71,38 @@ open class BaseKotlinGradleTest(private val projectName: String) { rootProjectDir.resolve("build/classes/atomicfu/js/main/$projectName.js").let { it.checkExists() - check(it in testCompileClasspathFiles) { "Original '$it' is missing from test compile classpath" } + check(it in testCompileClasspathFiles) { "Transformed '$it' is missing from test compile classpath" } } } -} \ No newline at end of file + + fun checkBytecode(classFilePath: String) { + rootProjectDir.resolve(classFilePath).let { + it.checkExists() + assertFalse(it.readBytes().findAtomicfuRef(), "Found 'Lkotlinx/atomicfu/' reference in $it" ) + } + } + + private fun ByteArray.findAtomicfuRef(): Boolean { + val bytes = this.eraseMetadata() + loop@for (i in 0 until bytes.size - ATOMIC_FU_REF.size) { + for (j in 0 until ATOMIC_FU_REF.size) { + if (bytes[i + j] != ATOMIC_FU_REF[j]) continue@loop + } + return true + } + return false + } + + // The atomicfu compiler plugin does not remove atomic properties from metadata, + // so for now we check that there are no ATOMIC_FU_REF left in the class bytecode excluding metadata. + // This may be reverted after the fix in the compiler plugin transformer (See #254). + private fun ByteArray.eraseMetadata(): ByteArray { + val cw = ClassWriter(ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES) + ClassReader(this).accept(object : ClassVisitor(Opcodes.ASM9, cw) { + override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? { + return if (descriptor == KOTLIN_METADATA_DESC) null else super.visitAnnotation(descriptor, visible) + } + }, ClassReader.SKIP_FRAMES) + return cw.toByteArray() + } +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt index 8630f70..0b34955 100644 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JsProjectTest.kt @@ -4,8 +4,15 @@ import kotlinx.atomicfu.plugin.gradle.internal.* import kotlinx.atomicfu.plugin.gradle.internal.BaseKotlinScope import org.junit.Test -class JsProjectTest : BaseKotlinGradleTest("js-simple") { - private fun BaseKotlinScope.createProject() { +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the JS project: + * - post-compilation js transformation tasks are created + * (legacy transformation is tested here, compiler plugin is not applied). + * - original non-transformed classes are not left in compile/runtime classpath. + */ +class JsLegacyTransformationTest : BaseKotlinGradleTest("js-simple") { + + override fun BaseKotlinScope.createProject() { buildGradleKts { resolve("projects/js-simple/js-simple.gradle.kts") } @@ -23,30 +30,20 @@ class JsProjectTest : BaseKotlinGradleTest("js-simple") { } @Test - fun testPlugin() { - val runner = test { - createProject() - runner { - arguments.add(":build") - } - } - val tasksToCheck = arrayOf( - ":compileKotlinJs", - ":transformJsMainAtomicfu", - ":compileTestKotlinJs", - ":transformJsTestAtomicfu" + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlinJs", + ":transformJsMainAtomicfu", + ":compileTestKotlinJs", + ":transformJsTestAtomicfu" + ), + excludedTasks = emptyList() ) - runner.build().apply { - tasksToCheck.forEach { - assertTaskSuccess(it) - } - } - // check that task outcomes are cached for the second build - runner.build().apply { - tasksToCheck.forEach { - assertTaskUpToDate(it) - } - } + + @Test + fun testClasspath() { + runner.build() checkJsCompilationClasspath() } -} \ No newline at end of file +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt index 838d091..2545e0e 100644 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/JvmProjectTest.kt @@ -4,9 +4,16 @@ import kotlinx.atomicfu.plugin.gradle.internal.* import kotlinx.atomicfu.plugin.gradle.internal.BaseKotlinScope import org.junit.Test -class JvmProjectTest : BaseKotlinGradleTest("jvm-simple") { +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the JVM project: + * - post-compilation bytecode transformation tasks are created + * (legacy transformation is tested here, compiler plugin is not applied). + * - original non-transformed classes are not left in compile/runtime classpath. + * - no `kotlinx/atomicfu` references are left in the transformed bytecode. + */ +class JvmLegacyTransformationTest : BaseKotlinGradleTest("jvm-simple") { - private fun BaseKotlinScope.createProject() { + override fun BaseKotlinScope.createProject() { buildGradleKts { resolve("projects/jvm-simple/jvm-simple.gradle.kts") } @@ -24,33 +31,78 @@ class JvmProjectTest : BaseKotlinGradleTest("jvm-simple") { } @Test - fun testPlugin() { - val runner = test { - createProject() - runner { - arguments.add(":build") - } - } - val tasksToCheck = arrayOf( - ":compileKotlin", - ":transformAtomicfuClasses", - ":compileTestKotlin", - ":transformTestAtomicfuClasses" + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlin", + ":transformAtomicfuClasses", + ":compileTestKotlin", + ":transformTestAtomicfuClasses" + ), + excludedTasks = emptyList() ) - runner.build().apply { - tasksToCheck.forEach { - assertTaskSuccess(it) - } - } - // check that task outcomes are cached for the second build - runner.build().apply { - tasksToCheck.forEach { - assertTaskUpToDate(it) - } - } + + @Test + fun testClasspath() { + runner.build() checkJvmCompilationClasspath( originalClassFile = "build/classes/kotlin/main/IntArithmetic.class", transformedClassFile = "build/classes/atomicfu/main/IntArithmetic.class" ) } -} \ No newline at end of file + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/atomicfu/main/IntArithmetic.class") + } +} + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the JVM project, + * - JVM IR compiler plugin transformation (kotlinx.atomicfu.enableJvmIrTransformation=true) + * - no post-compilation bytecode transforming tasks created + * - no `kotlinx/atomicfu` references are left in the resulting bytecode after IR transformation. + */ +class JvmIrTransformationTest : BaseKotlinGradleTest("jvm-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/jvm-simple/jvm-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/jvm-simple/settings.gradle.kts") + } + // set kotlinx.atomicfu.enableJvmIrTransformation=true to apply compiler plugin + gradleProperties { + resolve("projects/jvm-simple/gradle.properties") + } + dir("src/main/kotlin") {} + kotlin("IntArithmetic.kt", "main") { + resolve("projects/jvm-simple/src/main/kotlin/IntArithmetic.kt") + } + dir("src/test/kotlin") {} + kotlin("ArithmeticTest.kt", "test") { + resolve("projects/jvm-simple/src/test/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlin", + ":compileTestKotlin" + ), + excludedTasks = listOf( + ":transformAtomicfuClasses", + ":transformTestAtomicfuClasses" + ) + ) + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/kotlin/main/IntArithmetic.class") + } +} diff --git a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt index cbeefa2..e95b091 100644 --- a/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt +++ b/atomicfu-gradle-plugin/src/test/kotlin/kotlinx/atomicfu/plugin/gradle/test/MppProjectTest.kt @@ -3,8 +3,16 @@ package kotlinx.atomicfu.plugin.gradle.test import kotlinx.atomicfu.plugin.gradle.internal.* import org.junit.* -class MppProjectTest : BaseKotlinGradleTest("mpp-simple") { - private fun BaseKotlinScope.createProject() { +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the MPP project: + * - post-compilation bytecode transformation tasks are created + * (legacy transformation is tested here, compiler plugin is not applied). + * - original non-transformed classes are not left in compile/runtime classpath. + * - no `kotlinx/atomicfu` references are left in the transformed bytecode. + */ +class MppLegacyTransformationTest : BaseKotlinGradleTest("mpp-simple") { + + override fun BaseKotlinScope.createProject() { buildGradleKts { resolve("projects/mpp-simple/mpp-simple.gradle.kts") } @@ -22,37 +30,190 @@ class MppProjectTest : BaseKotlinGradleTest("mpp-simple") { } @Test - fun testPlugin() { - val runner = test { - createProject() - runner { - arguments.add(":build") - } - } - val tasksToCheck = arrayOf( - ":compileKotlinJvm", - ":compileTestKotlinJvm", - ":transformJvmMainAtomicfu", - ":transformJvmTestAtomicfu", - ":compileKotlinJs", - ":transformJsMainAtomicfu" + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlinJvm", + ":compileTestKotlinJvm", + ":transformJvmMainAtomicfu", + ":transformJvmTestAtomicfu", + ":compileKotlinJs", + ":transformJsMainAtomicfu" + ), + excludedTasks = emptyList() ) - runner.build().apply { - tasksToCheck.forEach { - assertTaskSuccess(it) - } - } - // check that task outcomes are cached for the second build - runner.build().apply { - tasksToCheck.forEach { - assertTaskUpToDate(it) - } - } + @Test + fun testClasspath() { + runner.build() checkJvmCompilationClasspath( originalClassFile = "build/classes/kotlin/jvm/main/IntArithmetic.class", transformedClassFile = "build/classes/atomicfu/jvm/main/IntArithmetic.class" ) checkJsCompilationClasspath() } -} \ No newline at end of file + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/atomicfu/jvm/main/IntArithmetic.class") + } +} + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the MPP project, + * - JVM IR compiler plugin transformation (kotlinx.atomicfu.enableJvmIrTransformation=true) + * - no post-compilation bytecode transformation tasks are created + * - post-compilation js file transformation task created (as only JVM IR transformation applied, js is transformed in legacy mode) + * - no `kotlinx/atomicfu` references are left in the transformed bytecode. + */ +class MppJvmIrTransformationTest : BaseKotlinGradleTest("mpp-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/mpp-simple/mpp-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/mpp-simple/settings.gradle.kts") + } + gradleProperties { + resolve("projects/mpp-simple/gradle.properties_jvm") + } + dir("src/commonMain/kotlin") {} + kotlin("IntArithmetic.kt", "commonMain") { + resolve("projects/mpp-simple/src/commonMain/kotlin/IntArithmetic.kt") + } + dir("src/commonTest/kotlin") {} + kotlin("ArithmeticTest.kt", "commonTest") { + resolve("projects/mpp-simple/src/commonTest/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlinJvm", + ":compileTestKotlinJvm", + ":compileKotlinJs", + // legacy JS transformation + ":transformJsMainAtomicfu", + ":transformJsTestAtomicfu" + ), + excludedTasks = listOf( + ":transformJvmMainAtomicfu", + ":transformJvmTestAtomicfu" + ) + ) + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/kotlin/jvm/main/IntArithmetic.class") + } +} + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the MPP project, + * - JS IR compiler plugin transformation (kotlinx.atomicfu.enableJsIrTransformation=true) + * - post-compilation bytecode transformation tasks are created (only JS IR transformation is applied, jvm is transformed in legacy mode) + * - no post-compilation js file transformation tasks are created + * - no `kotlinx/atomicfu` references are left in the transformed bytecode. + */ +class MppJsIrTransformationTest : BaseKotlinGradleTest("mpp-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/mpp-simple/mpp-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/mpp-simple/settings.gradle.kts") + } + gradleProperties { + resolve("projects/mpp-simple/gradle.properties_js") + } + dir("src/commonMain/kotlin") {} + kotlin("IntArithmetic.kt", "commonMain") { + resolve("projects/mpp-simple/src/commonMain/kotlin/IntArithmetic.kt") + } + dir("src/commonTest/kotlin") {} + kotlin("ArithmeticTest.kt", "commonTest") { + resolve("projects/mpp-simple/src/commonTest/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlinJvm", + ":compileTestKotlinJvm", + ":compileKotlinJs", + // legacy JVM transformation + ":transformJvmMainAtomicfu", + ":transformJvmTestAtomicfu" + ), + excludedTasks = listOf( + ":transformJsMainAtomicfu", + ":transformJsTestAtomicfu" + ) + ) + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/atomicfu/jvm/main/IntArithmetic.class") + } +} + +/** + * Test that ensures correctness of `atomicfu-gradle-plugin` application to the MPP project, + * - JS IR and JVM IR compiler plugin transformation + * - no post-compilation bytecode transformation tasks are created (only JS IR transformation is applied, jvm is transformed in legacy mode) + * - no post-compilation js file transformation tasks are created + * - no `kotlinx/atomicfu` references are left in the transformed bytecode. + */ +class MppBothIrTransformationTest : BaseKotlinGradleTest("mpp-simple") { + + override fun BaseKotlinScope.createProject() { + buildGradleKts { + resolve("projects/mpp-simple/mpp-simple.gradle.kts") + } + settingsGradleKts { + resolve("projects/mpp-simple/settings.gradle.kts") + } + gradleProperties { + resolve("projects/mpp-simple/gradle.properties_both") + } + dir("src/commonMain/kotlin") {} + kotlin("IntArithmetic.kt", "commonMain") { + resolve("projects/mpp-simple/src/commonMain/kotlin/IntArithmetic.kt") + } + dir("src/commonTest/kotlin") {} + kotlin("ArithmeticTest.kt", "commonTest") { + resolve("projects/mpp-simple/src/commonTest/kotlin/ArithmeticTest.kt") + } + } + + @Test + fun testPluginApplication() = + checkTaskOutcomes( + executedTasks = listOf( + ":compileKotlinJvm", + ":compileTestKotlinJvm", + ":compileKotlinJs" + ), + excludedTasks = listOf( + ":transformJvmMainAtomicfu", + ":transformJvmTestAtomicfu", + ":transformJsMainAtomicfu", + ":transformJsTestAtomicfu" + ) + ) + + @Test + fun testAtomicfuReferences() { + runner.build() + checkBytecode("build/classes/kotlin/jvm/main/IntArithmetic.class") + } +} diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/gradle.properties b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/gradle.properties new file mode 100644 index 0000000..fa37a2c --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/jvm-simple/gradle.properties @@ -0,0 +1 @@ +kotlinx.atomicfu.enableJvmIrTransformation=true diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_both b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_both new file mode 100644 index 0000000..5d28ccd --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_both @@ -0,0 +1,3 @@ +kotlin.js.compiler=ir +kotlinx.atomicfu.enableJvmIrTransformation=true +kotlinx.atomicfu.enableJsIrTransformation=true diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_js b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_js new file mode 100644 index 0000000..b57875b --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_js @@ -0,0 +1,2 @@ +kotlin.js.compiler=ir +kotlinx.atomicfu.enableJsIrTransformation=true diff --git a/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_jvm b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_jvm new file mode 100644 index 0000000..fa37a2c --- /dev/null +++ b/atomicfu-gradle-plugin/src/test/resources/projects/mpp-simple/gradle.properties_jvm @@ -0,0 +1 @@ +kotlinx.atomicfu.enableJvmIrTransformation=true -- cgit v1.2.3 From c1a5a280f5352bf607b3d735e9d7b4604ed0aa17 Mon Sep 17 00:00:00 2001 From: mvicsokolova <82594708+mvicsokolova@users.noreply.github.com> Date: Tue, 25 Oct 2022 12:55:08 +0200 Subject: Readme update (#256) * README update * minor fixes --- README.md | 351 ++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 207 insertions(+), 144 deletions(-) diff --git a/README.md b/README.md index c34cd44..251bb0e 100644 --- a/README.md +++ b/README.md @@ -9,26 +9,41 @@ >We do provide a compatibility of atomicfu-transformed artifacts between releases, but we do not provide >strict compatibility guarantees on plugin API and its general stability between Kotlin versions. -The idiomatic way to use atomic operations in Kotlin. - -* Code it like `AtomicReference/Int/Long`, but run it in production efficiently as `AtomicXxxFieldUpdater` on Kotlin/JVM - and as plain unboxed values on Kotlin/JS. -* Use Kotlin-specific extensions (e.g. inline `updateAndGet` and `getAndUpdate` functions). -* Compile-time dependency only for JVM and JS/IR (no runtime dependencies). - * Post-compilation bytecode transformer that declares all the relevant field updaters for you on [Kotlin/JVM](#jvm). - * Post-compilation JavaScript files transformer on [Kotlin/JS](#js). -* Multiplatform: - * [Kotlin/Native](#native) is supported. - * However, Kotlin/Native works as library dependency at the moment (unlike Kotlin/JVM and Kotlin/JS). - * This enables writing [common](#common) Kotlin code with atomics that compiles for JVM, JS, and Native. -* [Gradle](#gradle-build-setup) for all platforms and [Maven](#maven-build-setup) for JVM are supported. -* [Additional features](#additional-features) include: - * [JDK9 VarHandle](#varhandles-with-java-9). - * [Arrays of atomic values](#arrays-of-atomic-values). - * [User-defined extensions on atomics](#user-defined-extensions-on-atomics) - * [Locks](#locks) - * [Tracing operations](#tracing-operations) - +**Atomicfu** is a multiplatform library that provides the idiomatic and effective way of using atomic operations in Kotlin. + +## Table of contents +- [Features](#features) +- [Example](#example) +- [Quickstart](#quickstart) + - [Apply plugin to a project](#apply-plugin) + - [Gradle configuration](#gradle-configuration) + - [Maven configuration](#maven-configuration) +- [Usage constraints](#usage-constraints) +- [Transformation modes](#transformation-modes) + - [Atomicfu compiler plugin](#atomicfu-compiler-plugin) +- [Options for post-compilation transformation](#options-for-post-compilation-transformation) + - [JVM options](#jvm-options) + - [JS options](#js-options) +- [More features](#more-features) + - [Arrays of atomic values](#arrays-of-atomic-values) + - [User-defined extensions on atomics](#user-defined-extensions-on-atomics) + - [Locks](#locks) + - [Tracing operations](#tracing-operations) +- [Kotlin/Native support](#kotlin-native-support) + + +## Features + +* Code it like a boxed value `atomic(0)`, but run it in production efficiently: + * as `java.util.concurrent.atomic.AtomicXxxFieldUpdater` on Kotlin/JVM + * as a plain unboxed value on Kotlin/JS +* Multiplatform: write common Kotlin code with atomics that compiles for Kotlin JVM, JS, and Native backends: + * Compile-only dependency for JVM and JS (no runtime dependencies) + * Compile and runtime dependency for Kotlin/Native +* Use Kotlin-specific extensions (e.g. inline `loop`, `update`, `updateAndGet` functions). +* Use atomic arrays, user-defined extensions on atomics and locks (see [more features](#more-features)). +* [Tracing operations](#tracing-operations) for debugging. + ## Example Let us declare a `top` variable for a lock-free stack implementation: @@ -78,14 +93,140 @@ val myLong = atomic(0L) // note: long initial value Integer and long atomics provide all the usual `getAndIncrement`, `incrementAndGet`, `getAndAdd`, `addAndGet`, and etc operations. They can be also atomically modified via `+=` and `-=` operators. -## Dos and Don'ts +## Quickstart +### Apply plugin +#### Gradle configuration + +Gradle configuration is supported for all platforms, minimal version is Gradle 6.8. + +In top-level build file: + +
+Kotlin + +```kotlin +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.18.4") + } +} + +apply(plugin = "kotlinx-atomicfu") +``` +
+ +
+Groovy + +```groovy +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.18.4' + } +} + +apply plugin: 'kotlinx-atomicfu' +``` +
+ +#### Maven configuration + +Maven configuration is supported for JVM projects. + + +
+Declare atomicfu version + +```xml + + 0.18.4 + +``` + +
+ +
+Declare provided dependency on the AtomicFU library + +```xml + + + org.jetbrains.kotlinx + atomicfu + ${atomicfu.version} + provided + + +``` + +
+ +Configure build steps so that Kotlin compiler puts classes into a different `classes-pre-atomicfu` directory, +which is then transformed to a regular `classes` directory to be used later by tests and delivery. + +
+Build steps + +```xml + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + ${project.build.directory}/classes-pre-atomicfu + + + + + + + org.jetbrains.kotlinx + atomicfu-maven-plugin + ${atomicfu.version} + + + + transform + + + ${project.build.directory}/classes-pre-atomicfu + + FU + + + + + + +``` + +
+ +## Usage constraints * Declare atomic variables as `private val` or `internal val`. You can use just (public) `val`, but make sure they are not directly accessed outside of your Kotlin module (outside of the source set). Access to the atomic variable itself shall be encapsulated. * Only simple operations on atomic variables _directly_ are supported. * Do not read references on atomic variables into local variables, - e.g. `top.compareAndSet(...)` is Ok, while `val tmp = top; tmp...` is not. + e.g. `top.compareAndSet(...)` is ok, while `val tmp = top; tmp...` is not. * Do not leak references on atomic variables in other way (return, pass as params, etc). * Do not introduce complex data flow in parameters to atomic variable operations, i.e. `top.value = complex_expression` and `top.compareAndSet(cur, complex_expression)` are not supported @@ -96,72 +237,53 @@ operations. They can be also atomically modified via `+=` and `-=` operators. ```kotlin private val _foo = atomic(initial) // private atomic, convention is to name it with leading underscore public var foo: T by _foo // public delegated property (val/var) -``` +``` -## Gradle build setup +## Transformation modes -Building with Gradle is supported for all platforms. +Basically, Atomicfu library provides an effective usage of atomic values by performing the transformations of the compiled code. +For JVM and JS there 2 transformation modes available: +* **Post-compilation transformation** that modifies the compiled bytecode or `*.js` files. +* **IR transformation** that is performed by the atomicfu compiler plugin. -### JVM +### Atomicfu compiler plugin -You will need Gradle 6.8 or later. -Add and apply AtomicFU plugin. It adds all the corresponding dependencies and transformations automatically. -See [additional configuration](#additional-configuration) if that needs tweaking. +Compiler plugin transformation is less fragile than transformation of the compiled sources +as it depends on the compiler IR tree. -```groovy -buildscript { - ext.atomicfu_version = '0.18.4' +To turn on IR transformation set these properties in your `gradle.properties` file: - dependencies { - classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" - } -} +
+For Kotlin >= 1.7.20 -apply plugin: 'kotlinx-atomicfu' +```groovy +kotlinx.atomicfu.enableJvmIrTransformation=true // for JVM IR transformation +kotlinx.atomicfu.enableJsIrTransformation=true // for JS IR transformation ``` -### JS - -Configure add apply plugin just like for [JVM](#jvm). +
-### Native +
-This library is available for Kotlin/Native (`atomicfu-native`). -Apply the corresponding plugin just like for [JVM](#jvm). -Atomic references for Kotlin/Native are based on -[FreezableAtomicReference](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-freezable-atomic-reference/-init-.html) -and every reference that is stored to the previously -[frozen](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/freeze.html) -(shared with another thread) atomic is automatically frozen, too. + For Kotlin >= 1.6.20 and Kotlin < 1.7.20 -Since Kotlin/Native does not generally provide binary compatibility between versions, -you should use the same version of Kotlin compiler as was used to build AtomicFU. -See [gradle.properties](gradle.properties) in AtomicFU project for its `kotlin_version`. +```groovy +kotlinx.atomicfu.enableIrTransformation=true // only JS IR transformation is supported +``` -### Common +
-If you write a common code that should get compiled or different platforms, add `org.jetbrains.kotlinx:atomicfu` -to your common code dependencies or apply `kotlinx-atomicfu` plugin that adds this dependency automatically: +Also for JS backend make sure that `ir` or `both` compiler mode is set: ```groovy -dependencies { - compile "org.jetbrains.kotlinx:atomicfu:$atomicfu_version" -} +kotlin.js.compiler=ir // or both ``` -## IR transformation for Kotlin/JS - -There is a new option to turn on IR transformation for Kotlin/JS backend. -You can add `kotlinx.atomicfu.enableIrTransformation=true` to your `gradle.properties` file in order to enable it. -Here is how transformation is performed for different [JS compiler modes](https://kotlinlang.org/docs/js-ir-compiler.html) with this option enabled: +## Options for post-compilation transformation -- `kotlin.js.compiler=legacy`: JavaScript transformer from the library is applied to the final compiled *.js files. -- `kotlin.js.compiler=ir`: compiler plugin transformations are appiled to the generated IR. -- `kotlin.js.compiler=both`: compiler plugin transformations are appiled to all compilations of IR targets, while compilations of legacy targets are transformed by the library. - -## Additional configuration +Some configuration options are available for _post-compilation transform tasks_ on JVM and JS. To set configuration options you should create `atomicfu` section in a `build.gradle` file, like this: @@ -171,7 +293,7 @@ atomicfu { } ``` -### JVM transformation options +### JVM options To turn off transformation for Kotlin/JVM set option `transformJvm` to `false`. @@ -182,7 +304,7 @@ Here are the valid options: this option is supported for JDK 9+. - `BOTH` – [multi-release jar file](https://openjdk.java.net/jeps/238) will be created with both `AtomicXxxFieldUpdater` for JDK <= 8 and `VarHandle` for JDK 9+. -### JS transformation options +### JS options To turn off transformation for Kotlin/JS set option `transformJs` to `false`. @@ -191,85 +313,14 @@ Here are all available configuration options (with their defaults): atomicfu { dependenciesVersion = '0.18.4' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation - jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH - jsVariant = "JS" // JS transformation variant: JS or IR - verbose = false // set to true to be more verbose + jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH + transformJs = true // set to false to turn off JVM transformation } ``` -## Maven build setup - -Declare AtomicFU version: - -```xml - - 0.18.4 - -``` - -Declare _provided_ dependency on the AtomicFU library -(the users of the resulting artifact will not have a dependency on AtomicFU library): - -```xml - - - org.jetbrains.kotlinx - atomicfu - ${atomicfu.version} - provided - - -``` - -Configure build steps so that Kotlin compiler puts classes into a different `classes-pre-atomicfu` directory, -which is then transformed to a regular `classes` directory to be used later by tests and delivery. - -```xml - - - - - org.jetbrains.kotlin - kotlin-maven-plugin - ${kotlin.version} - - - compile - compile - - compile - - - ${project.build.directory}/classes-pre-atomicfu - - - - - - - org.jetbrains.kotlinx - atomicfu-maven-plugin - ${atomicfu.version} - - - - transform - - - ${project.build.directory}/classes-pre-atomicfu - - FU - - - - - - -``` +## More features -## Additional features - -AtomicFU provides some additional features that you can optionally use. +AtomicFU provides some additional features that you can use. ### Arrays of atomic values @@ -350,3 +401,15 @@ private val trace = Trace(size = 64) { `trace` is only seen before transformation and completely erased after on Kotlin/JVM and Kotlin/JS. +## Kotlin Native support + +Atomic references for Kotlin/Native are based on +[FreezableAtomicReference](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-freezable-atomic-reference/-init-.html) +and every reference that is stored to the previously +[frozen](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/freeze.html) +(shared with another thread) atomic is automatically frozen, too. + +Since Kotlin/Native does not generally provide binary compatibility between versions, +you should use the same version of Kotlin compiler as was used to build AtomicFU. +See [gradle.properties](gradle.properties) in AtomicFU project for its `kotlin_version`. + -- cgit v1.2.3 From 7969167e17502efbb1ee626b37e8c157b2bdb12b Mon Sep 17 00:00:00 2001 From: mvicsokolova Date: Tue, 25 Oct 2022 13:25:44 +0200 Subject: Version 0.18.5 --- CHANGES.md | 6 ++++++ README.md | 12 ++++++------ gradle.properties | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4225c92..1303cb4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change log for kotlinx.atomicfu +# Version 0.18.5 + +* Support JVM IR compiler plugin (#246). +* Update Kotlin to 1.7.20. +* Added more tests for atomicfu-gradle-plugin (#255). + # Version 0.18.4 * Fix KGP compatibility bug with freeCompilerArgs modification (#247). diff --git a/README.md b/README.md index 251bb0e..e3dd5b3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Kotlin Beta](https://kotl.in/badges/beta.svg)](https://kotlinlang.org/docs/components-stability.html) [![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.4/pom) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.18.5/pom) >Note on Beta status: the plugin is in its active development phase and changes from release to release. >We do provide a compatibility of atomicfu-transformed artifacts between releases, but we do not provide @@ -111,7 +111,7 @@ buildscript { } dependencies { - classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.18.4") + classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.18.5") } } @@ -128,7 +128,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.18.4' + classpath 'org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.18.5' } } @@ -146,7 +146,7 @@ Maven configuration is supported for JVM projects. ```xml - 0.18.4 + 0.18.5 ``` @@ -289,7 +289,7 @@ To set configuration options you should create `atomicfu` section in a `build.gr like this: ```groovy atomicfu { - dependenciesVersion = '0.18.4' + dependenciesVersion = '0.18.5' } ``` @@ -311,7 +311,7 @@ To turn off transformation for Kotlin/JS set option `transformJs` to `false`. Here are all available configuration options (with their defaults): ```groovy atomicfu { - dependenciesVersion = '0.18.4' // set to null to turn-off auto dependencies + dependenciesVersion = '0.18.5' // set to null to turn-off auto dependencies transformJvm = true // set to false to turn off JVM transformation jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH transformJs = true // set to false to turn off JVM transformation diff --git a/gradle.properties b/gradle.properties index 988e974..903d60d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. # -version=0.18.4-SNAPSHOT +version=0.18.5-SNAPSHOT group=org.jetbrains.kotlinx kotlin_version=1.7.20 -- cgit v1.2.3