Skip to content

Commit 7ae7a23

Browse files
authored
Add support of WASM target to mainline (#2410)
* Implement wasm target * Slightly fix test data to suite wasm fp parser Wasm fp parser has a different algorithm, so fix the tests to have similar results for all platforms * Update okio version to 3.5.0 * Kotlin 1.9.30+ support
1 parent f4c3a70 commit 7ae7a23

File tree

33 files changed

+378
-24
lines changed

33 files changed

+378
-24
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@file:JvmName("KotlinVersion")
2+
3+
fun isKotlinVersionAtLeast(kotlinVersion: String, atLeastMajor: Int, atLeastMinor: Int, atLeastPatch: Int): Boolean {
4+
val (major, minor) = kotlinVersion
5+
.split('.')
6+
.take(2)
7+
.map { it.toInt() }
8+
val patch = kotlinVersion.substringAfterLast('.').substringBefore('-').toInt()
9+
return when {
10+
major > atLeastMajor -> true
11+
major < atLeastMajor -> false
12+
else -> (minor == atLeastMinor && patch >= atLeastPatch) || minor > atLeastMinor
13+
}
14+
}

core/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,7 @@ tasks.withType(Jar).named(kotlin.jvm().artifactsTaskName) {
6666
}
6767

6868
Java9Modularity.configureJava9ModuleInfo(project)
69+
70+
tasks.withType(org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink.class).configureEach {
71+
kotlinOptions.freeCompilerArgs += "-Xwasm-enable-array-range-checks"
72+
}

core/commonTest/src/kotlinx/serialization/BasicTypesSerializationTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import kotlinx.serialization.descriptors.*
1010
import kotlinx.serialization.encoding.*
1111
import kotlinx.serialization.encoding.CompositeDecoder.Companion.UNKNOWN_NAME
1212
import kotlinx.serialization.modules.*
13+
import kotlinx.serialization.test.*
1314
import kotlin.test.*
1415
import kotlin.time.Duration
1516

core/commonTest/src/kotlinx/serialization/SerializersLookupInterfaceTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class SerializersLookupInterfaceTest {
3434
@Test
3535
fun testInterfaceLookup() {
3636
// Native does not have KClass.isInterface
37-
if (isNative()) return
37+
if (isNative() || isWasm()) return
3838

3939
val serializer1 = serializer<I>()
4040
assertTrue(serializer1 is PolymorphicSerializer)

core/commonTest/src/kotlinx/serialization/SerializersLookupNamedCompanionTest.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,25 @@ class SerializersLookupNamedCompanionTest {
6464
fun test() {
6565
assertSame<KSerializer<*>>(Plain.serializer(), serializer(typeOf<Plain>()))
6666

67-
shouldFail<SerializationException>(beforeKotlin = "1.9.20", onJs = false, onNative = false) {
67+
shouldFail<SerializationException>(beforeKotlin = "1.9.20", onJs = false, onNative = false, onWasm = false) {
6868
assertSame<KSerializer<*>>(PlainSerializer, serializer(typeOf<PlainWithCustom>()))
6969
}
7070

71-
shouldFail<SerializationException>(beforeKotlin = "1.9.20", onJs = false, onNative = false) {
71+
shouldFail<SerializationException>(beforeKotlin = "1.9.20", onJs = false, onNative = false, onWasm = false) {
7272
assertEquals(
7373
Parametrized.serializer(Int.serializer()).descriptor.toString(),
7474
serializer(typeOf<Parametrized<Int>>()).descriptor.toString()
7575
)
7676
}
7777

78-
shouldFail<SerializationException>(beforeKotlin = "1.9.20", onJs = false, onNative = false) {
78+
shouldFail<SerializationException>(beforeKotlin = "1.9.20", onJs = false, onNative = false, onWasm = false) {
7979
assertEquals(
8080
ParametrizedWithCustom.serializer(Int.serializer()).descriptor.toString(),
8181
serializer(typeOf<ParametrizedWithCustom<Int>>()).descriptor.toString()
8282
)
8383
}
8484

85-
shouldFail<SerializationException>(beforeKotlin = "1.9.20", onJs = false, onNative = false) {
85+
shouldFail<SerializationException>(beforeKotlin = "1.9.20", onJs = false, onNative = false, onWasm = false) {
8686
assertEquals(
8787
SealedInterface.serializer().descriptor.toString(),
8888
serializer(typeOf<SealedInterface>()).descriptor.toString()
@@ -91,7 +91,7 @@ class SerializersLookupNamedCompanionTest {
9191

9292
// should fail because annotation @NamedCompanion will be placed again by the compilation plugin
9393
// and they both will be placed into @Container annotation - thus they will be invisible to the runtime
94-
shouldFail<SerializationException>(sinceKotlin = "1.9.20", onJs = false, onNative = false) {
94+
shouldFail<SerializationException>(sinceKotlin = "1.9.20", onJs = false, onNative = false, onWasm = false) {
9595
serializer(typeOf<SealedInterfaceWithExplicitAnnotation>())
9696
}
9797
}

core/commonTest/src/kotlinx/serialization/UmbrellaTypes.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,4 @@ val umbrellaInstance = TypesUmbrella(
8686
arrayOf(null, -1, -2),
8787
arrayOf(IntData(1), IntData(2))
8888
)
89-
)
89+
)

core/commonTest/src/kotlinx/serialization/test/CompilerVersions.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@ internal inline fun <reified T : Throwable> shouldFail(
2929
onJvm: Boolean = true,
3030
onJs: Boolean = true,
3131
onNative: Boolean = true,
32+
onWasm: Boolean = true,
3233
test: () -> Unit
3334
) {
3435
val args = mapOf(
3536
"since" to sinceKotlin,
3637
"before" to beforeKotlin,
3738
"onJvm" to onJvm,
3839
"onJs" to onJs,
39-
"onNative" to onNative
40+
"onNative" to onNative,
41+
"onWasm" to onWasm
4042
)
4143

4244
val sinceVersion = sinceKotlin?.toKotlinVersion()
@@ -45,7 +47,7 @@ internal inline fun <reified T : Throwable> shouldFail(
4547
val version = (sinceVersion != null && currentKotlinVersion >= sinceVersion)
4648
|| (beforeVersion != null && currentKotlinVersion < beforeVersion)
4749

48-
val platform = (isJvm() && onJvm) || (isJs() && onJs) || (isNative() && onNative)
50+
val platform = (isJvm() && onJvm) || (isJs() && onJs) || (isNative() && onNative) || (isWasm() && onWasm)
4951

5052
var error: Throwable? = null
5153
try {
@@ -164,6 +166,16 @@ internal class CompilerVersionTest {
164166
shouldFail<IllegalArgumentException>(sinceKotlin = "0.0.0", beforeKotlin = "255.255.255", onJs = false) {
165167
// no-op
166168
}
169+
} else if (isWasm()) {
170+
shouldFail<IllegalArgumentException>(beforeKotlin = "255.255.255", onWasm = false) {
171+
// no-op
172+
}
173+
shouldFail<IllegalArgumentException>(sinceKotlin = "0.0.0", onWasm = false) {
174+
// no-op
175+
}
176+
shouldFail<IllegalArgumentException>(sinceKotlin = "0.0.0", beforeKotlin = "255.255.255", onWasm = false) {
177+
// no-op
178+
}
167179
} else if (isNative()) {
168180
shouldFail<IllegalArgumentException>(beforeKotlin = "255.255.255", onNative = false) {
169181
// no-op

core/commonTest/src/kotlinx/serialization/test/CurrentPlatform.common.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
package kotlinx.serialization.test
66

77
enum class Platform {
8-
JVM, JS, NATIVE
8+
JVM, JS, NATIVE, WASM
99
}
1010

1111
public expect val currentPlatform: Platform
1212

1313
public fun isJs(): Boolean = currentPlatform == Platform.JS
1414
public fun isJvm(): Boolean = currentPlatform == Platform.JVM
1515
public fun isNative(): Boolean = currentPlatform == Platform.NATIVE
16+
public fun isWasm(): Boolean = currentPlatform == Platform.WASM
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization
6+
7+
import kotlin.reflect.*
8+
9+
@OptIn(ExperimentalAssociatedObjects::class)
10+
@AssociatedObjectKey
11+
@Retention(AnnotationRetention.BINARY)
12+
@PublishedApi
13+
internal annotation class SerializableWith(public val serializer: KClass<out KSerializer<*>>)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization.internal
6+
7+
import kotlinx.serialization.*
8+
import kotlin.reflect.*
9+
10+
@Suppress("NOTHING_TO_INLINE")
11+
internal actual inline fun <T> Array<T>.getChecked(index: Int): T {
12+
return get(index)
13+
}
14+
15+
@Suppress("NOTHING_TO_INLINE")
16+
internal actual inline fun BooleanArray.getChecked(index: Int): Boolean {
17+
return get(index)
18+
}
19+
20+
internal actual fun KClass<*>.platformSpecificSerializerNotRegistered(): Nothing {
21+
throw SerializationException(
22+
"${notRegisteredMessage()}\n" +
23+
"On Kotlin/Wasm explicitly declared serializer should be used for interfaces and enums without @Serializable annotation"
24+
)
25+
}
26+
27+
@Suppress(
28+
"UNCHECKED_CAST",
29+
"DEPRECATION_ERROR"
30+
)
31+
@OptIn(ExperimentalAssociatedObjects::class)
32+
internal actual fun <T : Any> KClass<T>.constructSerializerForGivenTypeArgs(vararg args: KSerializer<Any?>): KSerializer<T>? =
33+
when (val assocObject = findAssociatedObject<SerializableWith>()) {
34+
is KSerializer<*> -> assocObject as KSerializer<T>
35+
is SerializerFactory -> assocObject.serializer(*args) as KSerializer<T>
36+
else -> null
37+
}
38+
39+
@Suppress("DEPRECATION_ERROR")
40+
internal actual fun <T : Any> KClass<T>.compiledSerializerImpl(): KSerializer<T>? =
41+
this.constructSerializerForGivenTypeArgs()
42+
43+
44+
internal actual fun <T> createCache(factory: (KClass<*>) -> KSerializer<T>?): SerializerCache<T> {
45+
return object: SerializerCache<T> {
46+
override fun get(key: KClass<Any>): KSerializer<T>? {
47+
return factory(key)
48+
}
49+
}
50+
}
51+
52+
internal actual fun <T> createParametrizedCache(factory: (KClass<Any>, List<KType>) -> KSerializer<T>?): ParametrizedSerializerCache<T> {
53+
return object: ParametrizedSerializerCache<T> {
54+
override fun get(key: KClass<Any>, types: List<KType>): Result<KSerializer<T>?> {
55+
return kotlin.runCatching { factory(key, types) }
56+
}
57+
}
58+
}
59+
60+
internal actual fun <T : Any, E : T?> ArrayList<E>.toNativeArrayImpl(eClass: KClass<T>): Array<E> = toTypedArray()
61+
62+
internal actual fun isReferenceArray(rootClass: KClass<Any>): Boolean = rootClass == Array::class

0 commit comments

Comments
 (0)