Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WebAssembly target #334

Merged
merged 22 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6605824
Add WebAssembly target
skuzmich Aug 17, 2022
fc4a6b2
Transformation task for wasm
igoriakovlev Jul 7, 2023
c6c422d
CODEREVIEW Run wasm tests with nodejs
igoriakovlev Aug 15, 2023
e9a340c
CODEREVIEW Combine js and wasm implementation to reduce code duplication
igoriakovlev Aug 15, 2023
db9f965
CODEREVIEW Remove transform task for wasm
igoriakovlev Aug 16, 2023
6f84341
CODEREVIEW Comment for OptionalJsName
igoriakovlev Aug 16, 2023
54f2fec
Wasm 1.9.20 platform
igoriakovlev Aug 22, 2023
5736f2d
Ignore of new MPP inspections
igoriakovlev Aug 22, 2023
d72b403
AMMEND
igoriakovlev Aug 23, 2023
d9659b0
Train: Put mavenLocal repo after other repos
woainikk Aug 29, 2023
c0566c5
AMMEND (upgrade kotlin to 1.9.20-Beta3 and nodejs to canary)
igoriakovlev Sep 21, 2023
1dadd03
AMMEND (move js and wasm shared code into jsAndWasmSharedMain directory)
igoriakovlev Nov 1, 2023
b58cc61
AMMEND (upgrade kotlin to 1.9.20)
igoriakovlev Nov 1, 2023
b3b7573
Added integration tests for wasmJs and wasmWasi targets
mvicsokolova Nov 13, 2023
e10743b
Mentioned support of the Wasm target in README
mvicsokolova Nov 13, 2023
7646c47
Update build.gradle
mvicsokolova Nov 13, 2023
e297675
Update atomicfu/src/jsMain/kotlin/kotlinx/atomicfu/OptionalJsName.kt
mvicsokolova Nov 13, 2023
02ed0db
Update atomicfu/src/commonMain/kotlin/kotlinx/atomicfu/OptionalJsName.kt
mvicsokolova Nov 13, 2023
53ec20e
Readme fixup
mvicsokolova Nov 13, 2023
59a8a52
Fixup: replace assert with assertTrue in MppProjectTest
mvicsokolova Nov 14, 2023
1161b06
Removed @Suppress("ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_MEMBERS_AS_NO…
mvicsokolova Nov 14, 2023
50bb985
Changed id of the warning: @Suppress("ACTUAL_CLASSIFIER_MUST_HAVE_THE…
mvicsokolova Nov 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,11 @@ Starting from version `0.22.0` of the library your project is required to use:

## Features

* Complete multiplatform support: JVM, Native, JS and Wasm (since Kotlin 1.9.20).
fzhinkin marked this conversation as resolved.
Show resolved Hide resolved
* 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
* For **JVM**: an atomic value is represented as a plain value atomically updated with `java.util.concurrent.atomic.AtomicXxxFieldUpdater` from the Java standard library.
* For **JS**: an atomic value is represented as a plain value.
* For **Native** and **Wasm**: an atomic value is not transformed, it remains boxed, and `kotlinx-atomicfu` library is used as a runtime dependency.
* 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.
Expand Down
mvicsokolova marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,15 @@ private fun Project.needsJvmIrTransformation(target: KotlinTarget): Boolean =
rootProject.getBooleanProperty(ENABLE_JVM_IR_TRANSFORMATION) &&
(target.platformType == KotlinPlatformType.jvm || target.platformType == KotlinPlatformType.androidJvm)

private fun KotlinTarget.isJsIrTarget() = (this is KotlinJsTarget && this.irTarget != null) || this is KotlinJsIrTarget
private fun KotlinTarget.isJsIrTarget() =
mvicsokolova marked this conversation as resolved.
Show resolved Hide resolved
(this is KotlinJsTarget && this.irTarget != null) ||
(this is KotlinJsIrTarget && this.platformType != KotlinPlatformType.wasm)

private fun Project.isTransformationDisabled(target: KotlinTarget): Boolean {
val platformType = target.platformType
return !config.transformJvm && (platformType == KotlinPlatformType.jvm || platformType == KotlinPlatformType.androidJvm) ||
!config.transformJs && platformType == KotlinPlatformType.js
!config.transformJs && platformType == KotlinPlatformType.js ||
platformType == KotlinPlatformType.wasm
}

// Adds kotlinx-atomicfu-runtime as an implementation dependency to the JS IR target:
Expand Down Expand Up @@ -286,8 +289,11 @@ private fun Project.configureJsTransformation() =

private 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
if (target.platformType == KotlinPlatformType.common ||
target.platformType == KotlinPlatformType.native ||
target.platformType == KotlinPlatformType.wasm
) {
return@withKotlinTargets // skip creation of transformation task for common, native and wasm targets
}
configureTransformationForTarget(target)
}
Expand Down
54 changes: 42 additions & 12 deletions atomicfu/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*/

import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
import static KotlinVersion.*

apply plugin: 'kotlin-multiplatform'
apply from: rootProject.file("gradle/targets.gradle")
Expand All @@ -20,10 +19,6 @@ ext {
}
}

// TODO: this block should be removed when Kotlin version is updated to 1.9.20
// Right now it is used for conditional removal of native targets that will be removed in 1.9.20 (iosArm32, watchosX86)
// and is necessary for testing of Kotlin dev builds.
def enableDeprecatedNativeTargets = !isKotlinVersionAtLeast(ext.kotlin_version, 1, 9, 20)

kotlin {
targets {
Expand All @@ -43,6 +38,15 @@ kotlin {
// JVM -- always
jvm()

// Wasm -- always
wasmJs {
nodejs()
}

wasmWasi {
nodejs()
}

sourceSets {
commonMain {
dependencies {
Expand All @@ -55,7 +59,13 @@ kotlin {
implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
}
}

jsAndWasmSharedMain {
dependsOn(sourceSets.commonMain)
}

jsMain {
dependsOn(sourceSets.jsAndWasmSharedMain)
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-js'
}
Expand All @@ -65,6 +75,32 @@ kotlin {
implementation 'org.jetbrains.kotlin:kotlin-test-js'
}
}

wasmJsMain {
dependsOn(sourceSets.jsAndWasmSharedMain)
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-wasm-js'
}
}

wasmJsTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test-wasm-js'
}
}

wasmWasiMain {
dependsOn(sourceSets.jsAndWasmSharedMain)
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-wasm-wasi'
}
}
wasmWasiTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test-wasm-wasi'
}
}

jvmMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib'
Expand Down Expand Up @@ -116,12 +152,6 @@ if (rootProject.ext.native_targets_enabled) {
addTarget(presets.androidNativeX64)
addTarget(presets.mingwX64)
addTarget(presets.watchosDeviceArm64)

// These targets will be removed in 1.9.20, remove them conditionally for the train builds
if (enableDeprecatedNativeTargets) {
addTarget(presets.iosArm32)
addTarget(presets.watchosX86)
}
}
}

Expand Down Expand Up @@ -331,4 +361,4 @@ tasks.clean {
setDelete(layout.buildDirectory.asFileTree.matching {
exclude("tmp/.cache/expanded/expanded.lock")
})
}
}
27 changes: 13 additions & 14 deletions atomicfu/src/commonMain/kotlin/kotlinx/atomicfu/AtomicFU.common.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

package kotlinx.atomicfu

import kotlin.js.JsName
import kotlin.internal.InlineOnly
import kotlinx.atomicfu.TraceBase.None
import kotlin.reflect.KProperty
Expand Down Expand Up @@ -110,7 +109,7 @@ public expect fun atomic(initial: Boolean): AtomicBoolean
/**
* Creates array of AtomicRef<T> of specified size, where each element is initialised with null value
*/
@JsName(ATOMIC_ARRAY_OF_NULLS)
@OptionalJsName(ATOMIC_ARRAY_OF_NULLS)
public fun <T> atomicArrayOfNulls(size: Int): AtomicArray<T?> = AtomicArray(size)

// ==================================== AtomicRef ====================================
Expand Down Expand Up @@ -508,15 +507,15 @@ public inline fun AtomicLong.updateAndGet(function: (Long) -> Long): Long {
/**
* Creates a new array of AtomicInt values of the specified size, where each element is initialised with 0
*/
@JsName(ATOMIC_INT_ARRAY)
@OptionalJsName(ATOMIC_INT_ARRAY)
public class AtomicIntArray(size: Int) {
private val array = Array(size) { atomic(0) }

@JsName(ARRAY_SIZE)
@OptionalJsName(ARRAY_SIZE)
public val size: Int
get() = array.size

@JsName(ARRAY_ELEMENT_GET)
@OptionalJsName(ARRAY_ELEMENT_GET)
public operator fun get(index: Int): AtomicInt = array[index]
}

Expand All @@ -525,15 +524,15 @@ public class AtomicIntArray(size: Int) {
/**
* Creates a new array of AtomicLong values of the specified size, where each element is initialised with 0L
*/
@JsName(ATOMIC_LONG_ARRAY)
@OptionalJsName(ATOMIC_LONG_ARRAY)
public class AtomicLongArray(size: Int) {
private val array = Array(size) { atomic(0L) }

@JsName(ARRAY_SIZE)
@OptionalJsName(ARRAY_SIZE)
public val size: Int
get() = array.size

@JsName(ARRAY_ELEMENT_GET)
@OptionalJsName(ARRAY_ELEMENT_GET)
public operator fun get(index: Int): AtomicLong = array[index]
}

Expand All @@ -542,29 +541,29 @@ public class AtomicLongArray(size: Int) {
/**
* Creates a new array of AtomicBoolean values of the specified size, where each element is initialised with false
*/
@JsName(ATOMIC_BOOLEAN_ARRAY)
@OptionalJsName(ATOMIC_BOOLEAN_ARRAY)
public class AtomicBooleanArray(size: Int) {
private val array = Array(size) { atomic(false) }

@JsName(ARRAY_SIZE)
@OptionalJsName(ARRAY_SIZE)
public val size: Int
get() = array.size

@JsName(ARRAY_ELEMENT_GET)
@OptionalJsName(ARRAY_ELEMENT_GET)
public operator fun get(index: Int): AtomicBoolean = array[index]
}


// ==================================== AtomicArray ====================================

@JsName(ATOMIC_REF_ARRAY)
@OptionalJsName(ATOMIC_REF_ARRAY)
public class AtomicArray<T> internal constructor(size: Int) {
private val array = Array(size) { atomic<T?>(null) }

@JsName(ARRAY_SIZE)
@OptionalJsName(ARRAY_SIZE)
public val size: Int
get() = array.size

@JsName(ARRAY_ELEMENT_GET)
@OptionalJsName(ARRAY_ELEMENT_GET)
public operator fun get(index: Int): AtomicRef<T?> = array[index]
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package kotlinx.atomicfu

/**
* All atomicfu declarations are annotated with [@JsName][kotlin.js.JsName] to have specific names in JS output.
* All atomicfu declarations are annotated with [@OptionalJsName][kotlin.js.JsName] to have specific names in JS output.
* JS output transformer relies on these mangled names to erase all atomicfu references.
*/

Expand Down
17 changes: 17 additions & 0 deletions atomicfu/src/commonMain/kotlin/kotlinx/atomicfu/OptionalJsName.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package kotlinx.atomicfu

/**
* This annotation actualized with JsName in JS platform and not actualized in others.
*/
@OptIn(ExperimentalMultiplatform::class)
@OptionalExpectation
@Retention(AnnotationRetention.BINARY)
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY,
AnnotationTarget.CONSTRUCTOR,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER
)
expect annotation class OptionalJsName(val name: String)
11 changes: 5 additions & 6 deletions atomicfu/src/commonMain/kotlin/kotlinx/atomicfu/Trace.common.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

package kotlinx.atomicfu

import kotlin.js.JsName
import kotlin.internal.InlineOnly

/**
Expand Down Expand Up @@ -66,30 +65,30 @@ public expect val traceFormatDefault: TraceFormat
/**
* Base class for implementations of `Trace`.
*/
@JsName(TRACE_BASE_CONSTRUCTOR)
@OptionalJsName(TRACE_BASE_CONSTRUCTOR)
public open class TraceBase internal constructor() {
/**
* Accepts the logging [event] and appends it to the trace.
*/
@JsName(TRACE_APPEND_1)
@OptionalJsName(TRACE_APPEND_1)
public open fun append(event: Any) {}

/**
* Accepts the logging events [event1], [event2] and appends them to the trace.
*/
@JsName(TRACE_APPEND_2)
@OptionalJsName(TRACE_APPEND_2)
public open fun append(event1: Any, event2: Any) {}

/**
* Accepts the logging events [event1], [event2], [event3] and appends them to the trace.
*/
@JsName(TRACE_APPEND_3)
@OptionalJsName(TRACE_APPEND_3)
public open fun append(event1: Any, event2: Any, event3: Any) {}

/**
* Accepts the logging events [event1], [event2], [event3], [event4] and appends them to the trace.
*/
@JsName(TRACE_APPEND_4)
@OptionalJsName(TRACE_APPEND_4)
public open fun append(event1: Any, event2: Any, event3: Any, event4: Any) {}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import kotlin.js.JsName
/**
* Trace string formatter.
*/
@JsName(TRACE_FORMAT_CLASS)
@OptionalJsName(TRACE_FORMAT_CLASS)
public open class TraceFormat {
/**
* Formats trace at the given [index] with the given [event] of Any type.
*/
@JsName(TRACE_FORMAT_FORMAT_FUNCTION)
@OptionalJsName(TRACE_FORMAT_FORMAT_FUNCTION)
public open fun format(index: Int, event: Any): String = "$index: $event"
}

Expand Down
Loading