[Wasm] Support packed integer array elements

This commit is contained in:
Svyatoslav Kuzmich
2020-12-12 16:26:21 +03:00
parent 51e8d782b0
commit d37271bf35
4 changed files with 61 additions and 39 deletions
@@ -176,7 +176,7 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis
nameStr, nameStr,
WasmStructFieldDeclaration( WasmStructFieldDeclaration(
name = "field", name = "field",
type = context.transformType(wasmArrayAnnotation.type), type = context.transformFieldType(wasmArrayAnnotation.type),
isMutable = true isMutable = true
) )
) )
@@ -35,17 +35,17 @@ internal fun byteArrayIterator(array: ByteArray) = object : ByteIterator() {
public class CharArray(size: Int) { public class CharArray(size: Int) {
private var storage = WasmShortArray(size) private var storage = WasmCharArray(size)
public constructor(size: Int, init: (Int) -> Char) : this(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 = public operator fun get(index: Int): Char =
storage.get(index).toChar() storage.get(index)
public operator fun set(index: Int, value: Char) { public operator fun set(index: Int, value: Char) {
storage.set(index, value.toShort()) storage.set(index, value)
} }
public val size: Int public val size: Int
@@ -200,17 +200,17 @@ internal fun doubleArrayIterator(array: DoubleArray) = object : DoubleIterator()
public class BooleanArray(size: Int) { public class BooleanArray(size: Int) {
private var storage = WasmBooleanArray(size) private var storage = WasmByteArray(size)
public constructor(size: Int, init: (Int) -> Boolean) : this(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 = public operator fun get(index: Int): Boolean =
storage.get(index) storage.get(index).reinterpretAsInt().reinterpretAsBoolean()
public operator fun set(index: Int, value: Boolean) { public operator fun set(index: Int, value: Boolean) {
storage.set(index, value) storage.set(index, value.toInt().reinterpretAsByte())
} }
public val size: Int public val size: Int
@@ -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) @WasmArrayOf(Byte::class, isNullable = false)
internal class WasmByteArray(size: Int) { internal class WasmByteArray(size: Int) {
@WasmOp(WasmOp.ARRAY_GET) @WasmOp(WasmOp.ARRAY_GET_S)
fun get(index: Int): Byte = fun get(index: Int): Byte =
implementedAsIntrinsic 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) @WasmArrayOf(Short::class, isNullable = false)
internal class WasmShortArray(size: Int) { internal class WasmShortArray(size: Int) {
@WasmOp(WasmOp.ARRAY_GET) @WasmOp(WasmOp.ARRAY_GET_S)
fun get(index: Int): Short = fun get(index: Int): Short =
implementedAsIntrinsic implementedAsIntrinsic
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.wasm.ir.WasmOp
import templates.COMMON_AUTOGENERATED_WARNING import templates.COMMON_AUTOGENERATED_WARNING
import templates.COPYRIGHT_NOTICE import templates.COPYRIGHT_NOTICE
import templates.PrimitiveType import templates.PrimitiveType
import templates.isUnsigned
import java.io.File import java.io.File
import java.io.FileWriter import java.io.FileWriter
@@ -56,20 +57,41 @@ fun generateWasmArrays(targetDir: File) {
writer.generateStandardWasmInternalHeader() writer.generateStandardWasmInternalHeader()
writer.appendLine(wasmArrayForType("Any", true)) writer.appendLine(wasmArrayForType("Any", true))
writer.appendLine(wasmArrayForType("Boolean", false)) PrimitiveType.descendingByDomainCapacity.reversed().forEach { primitive ->
PrimitiveType.numericPrimitives.sortedBy { it.capacity }.forEach { primitive -> val isPacked = primitive in setOf(
writer.appendLine(wasmArrayForType(primitive.name, false)) 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 type = klass + if (isNullable) "?" else ""
val name = "Wasm${klass}Array" val name = "Wasm${klass}Array"
val getSuffix = when {
isPacked && isUnsigned -> "_U"
isPacked && !isUnsigned -> "_S"
else -> ""
}
return """ return """
@WasmArrayOf($klass::class, isNullable = $isNullable) @WasmArrayOf($klass::class, isNullable = $isNullable)
internal class $name(size: Int) { internal class $name(size: Int) {
@WasmOp(WasmOp.ARRAY_GET) @WasmOp(WasmOp.ARRAY_GET${getSuffix})
fun get(index: Int): $type = fun get(index: Int): $type =
implementedAsIntrinsic implementedAsIntrinsic