diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt index 081bb9e3e02..e673b667423 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt @@ -176,7 +176,7 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis nameStr, WasmStructFieldDeclaration( name = "field", - type = context.transformType(wasmArrayAnnotation.type), + type = context.transformFieldType(wasmArrayAnnotation.type), isMutable = true ) ) diff --git a/libraries/stdlib/wasm/builtins/kotlin/Arrays.kt b/libraries/stdlib/wasm/builtins/kotlin/Arrays.kt index 1bbf8ae056c..6126576f0ff 100644 --- a/libraries/stdlib/wasm/builtins/kotlin/Arrays.kt +++ b/libraries/stdlib/wasm/builtins/kotlin/Arrays.kt @@ -35,17 +35,17 @@ internal fun byteArrayIterator(array: ByteArray) = object : ByteIterator() { public class CharArray(size: Int) { - private var storage = WasmShortArray(size) + private var storage = WasmCharArray(size) public constructor(size: Int, init: (Int) -> Char) : this(size) { - storage.fill(size) { init(it).toShort() } + storage.fill(size) { init(it) } } public operator fun get(index: Int): Char = - storage.get(index).toChar() + storage.get(index) public operator fun set(index: Int, value: Char) { - storage.set(index, value.toShort()) + storage.set(index, value) } public val size: Int @@ -200,17 +200,17 @@ internal fun doubleArrayIterator(array: DoubleArray) = object : DoubleIterator() public class BooleanArray(size: Int) { - private var storage = WasmBooleanArray(size) + private var storage = WasmByteArray(size) public constructor(size: Int, init: (Int) -> Boolean) : this(size) { - storage.fill(size, init) + storage.fill(size) { init(it).toInt().reinterpretAsByte() } } public operator fun get(index: Int): Boolean = - storage.get(index) + storage.get(index).reinterpretAsInt().reinterpretAsBoolean() public operator fun set(index: Int, value: Boolean) { - storage.set(index, value) + storage.set(index, value.toInt().reinterpretAsByte()) } public val size: Int diff --git a/libraries/stdlib/wasm/src/generated/_WasmArrays.kt b/libraries/stdlib/wasm/src/generated/_WasmArrays.kt index ec59a1e957f..b50a47da571 100644 --- a/libraries/stdlib/wasm/src/generated/_WasmArrays.kt +++ b/libraries/stdlib/wasm/src/generated/_WasmArrays.kt @@ -33,32 +33,9 @@ internal inline fun WasmAnyArray.fill(size: Int, init: (Int) -> Any?) { } } -@WasmArrayOf(Boolean::class, isNullable = false) -internal class WasmBooleanArray(size: Int) { - @WasmOp(WasmOp.ARRAY_GET) - fun get(index: Int): Boolean = - implementedAsIntrinsic - - @WasmOp(WasmOp.ARRAY_SET) - fun set(index: Int, value: Boolean): Unit = - implementedAsIntrinsic - - @WasmOp(WasmOp.ARRAY_LEN) - fun len(): Int = - implementedAsIntrinsic -} - -internal inline fun WasmBooleanArray.fill(size: Int, init: (Int) -> Boolean) { - var i = 0 - while (i < size) { - set(i, init(i)) - i++ - } -} - @WasmArrayOf(Byte::class, isNullable = false) internal class WasmByteArray(size: Int) { - @WasmOp(WasmOp.ARRAY_GET) + @WasmOp(WasmOp.ARRAY_GET_S) fun get(index: Int): Byte = implementedAsIntrinsic @@ -79,9 +56,32 @@ internal inline fun WasmByteArray.fill(size: Int, init: (Int) -> Byte) { } } +@WasmArrayOf(Char::class, isNullable = false) +internal class WasmCharArray(size: Int) { + @WasmOp(WasmOp.ARRAY_GET_U) + fun get(index: Int): Char = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_SET) + fun set(index: Int, value: Char): Unit = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_LEN) + fun len(): Int = + implementedAsIntrinsic +} + +internal inline fun WasmCharArray.fill(size: Int, init: (Int) -> Char) { + var i = 0 + while (i < size) { + set(i, init(i)) + i++ + } +} + @WasmArrayOf(Short::class, isNullable = false) internal class WasmShortArray(size: Int) { - @WasmOp(WasmOp.ARRAY_GET) + @WasmOp(WasmOp.ARRAY_GET_S) fun get(index: Int): Short = implementedAsIntrinsic diff --git a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateWasmOps.kt b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateWasmOps.kt index 350f73fa400..604436b6721 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateWasmOps.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateWasmOps.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.wasm.ir.WasmOp import templates.COMMON_AUTOGENERATED_WARNING import templates.COPYRIGHT_NOTICE import templates.PrimitiveType +import templates.isUnsigned import java.io.File import java.io.FileWriter @@ -56,20 +57,41 @@ fun generateWasmArrays(targetDir: File) { writer.generateStandardWasmInternalHeader() writer.appendLine(wasmArrayForType("Any", true)) - writer.appendLine(wasmArrayForType("Boolean", false)) - PrimitiveType.numericPrimitives.sortedBy { it.capacity }.forEach { primitive -> - writer.appendLine(wasmArrayForType(primitive.name, false)) + PrimitiveType.descendingByDomainCapacity.reversed().forEach { primitive -> + val isPacked = primitive in setOf( + PrimitiveType.Byte, + PrimitiveType.Short, + PrimitiveType.Char, + ) + val isUnsigned = primitive.isUnsigned() || primitive == PrimitiveType.Char + + writer.appendLine( + wasmArrayForType( + primitive.name, + false, isPacked, isUnsigned + ) + ) } } } -fun wasmArrayForType(klass: String, isNullable: Boolean): String { +fun wasmArrayForType( + klass: String, + isNullable: Boolean, + isPacked: Boolean = false, + isUnsigned: Boolean = false, +): String { val type = klass + if (isNullable) "?" else "" val name = "Wasm${klass}Array" + val getSuffix = when { + isPacked && isUnsigned -> "_U" + isPacked && !isUnsigned -> "_S" + else -> "" + } return """ @WasmArrayOf($klass::class, isNullable = $isNullable) internal class $name(size: Int) { - @WasmOp(WasmOp.ARRAY_GET) + @WasmOp(WasmOp.ARRAY_GET${getSuffix}) fun get(index: Int): $type = implementedAsIntrinsic