diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt index a0ab3d1db13..e19fc62d910 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt @@ -128,23 +128,7 @@ fun WasmCompiledModuleFragment.generateJs(): String { Char_toString(char) { return String.fromCharCode(char) }, - - JsArray_new(size) { - return new Array(size); - }, - - JsArray_get(array, index) { - return array[index]; - }, - - JsArray_set(array, index, value) { - array[index] = value; - }, - - JsArray_getSize(array) { - return array.length; - }, - + identity(x) { return x; }, diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt index 5488a75789d..22cd4da8aa2 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt @@ -122,7 +122,19 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV return } - val wasmStruct: WasmSymbol = context.referenceGcType(klass.symbol) + val wasmGcType: WasmSymbol = context.referenceGcType(klass.symbol) + + klass.getWasmArrayAnnotation()?.let { wasmArrayInfo -> + require(expression.valueArgumentsCount == 1) { "@WasmArrayOf constructs must have exactly one argument" } + generateExpression(expression.getValueArgument(0)!!) + body.buildRttCanon(context.transformType(klass.defaultType)) + body.buildInstr( + WasmOp.ARRAY_NEW_DEFAULT_WITH_RTT, + WasmImmediate.GcType(wasmGcType) + ) + return + } + val wasmClassId = context.referenceClassId(klass.symbol) val irFields: List = klass.allFields(backendContext.irBuiltIns) @@ -135,7 +147,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV } body.buildGetGlobal(context.referenceClassRTT(klass.symbol)) - body.buildStructNew(wasmStruct) + body.buildStructNew(wasmGcType) generateCall(expression) } @@ -472,12 +484,16 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV 0 -> { } 1 -> { - when (val imm = op.immediates[0]) { - WasmImmediateKind.MEM_ARG -> - immediates = arrayOf(WasmImmediate.MemArg(0u, 0u)) - else -> - error("Immediate $imm is unsupported") - } + immediates = arrayOf( + when (val imm = op.immediates[0]) { + WasmImmediateKind.MEM_ARG -> + WasmImmediate.MemArg(0u, 0u) + WasmImmediateKind.STRUCT_TYPE_IDX -> + WasmImmediate.GcType(context.referenceGcType(function.dispatchReceiverParameter!!.type.classOrNull!!)) + else -> + error("Immediate $imm is unsupported") + } + ) } else -> error("Op $opString is unsupported") 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 55ed3f7f8df..ffa99ad0679 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 @@ -168,6 +168,23 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis if (declaration.isAnnotationClass) return val symbol = declaration.symbol + + // Handle arrays + declaration.getWasmArrayAnnotation()?.let { wasmArrayAnnotation -> + val nameStr = declaration.fqNameWhenAvailable.toString() + val wasmArrayDeclaration = WasmArrayDeclaration( + nameStr, + WasmStructFieldDeclaration( + name = "field", + type = context.transformType(wasmArrayAnnotation.type), + isMutable = true + ) + ) + + context.defineGcType(symbol, wasmArrayDeclaration) + return + } + if (declaration.isInterface) { context.registerInterface(symbol) } else { diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt index 98596092c7d..d20a35ef1bd 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/TypeTransformer.kt @@ -45,11 +45,11 @@ class WasmTypeTransformer( toWasmValueType() } - fun IrType.toStructType(): WasmType = + fun IrType.toWasmGcRefType(): WasmType = WasmRefNullType(WasmHeapType.Type(context.referenceGcType(erasedUpperBound?.symbol ?: builtIns.anyClass))) fun IrType.toBoxedInlineClassType(): WasmType = - toStructType() + toWasmGcRefType() fun IrType.toWasmValueType(): WasmType = when (this) { @@ -88,7 +88,7 @@ class WasmTypeTransformer( } else if (ic != null) { getInlineClassUnderlyingType(ic).toWasmValueType() } else { - this.toStructType() + this.toWasmGcRefType() } } } diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Annotations.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Annotations.kt index f303b6707cf..75243f64760 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Annotations.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Annotations.kt @@ -7,7 +7,11 @@ package org.jetbrains.kotlin.backend.wasm.utils import org.jetbrains.kotlin.ir.backend.js.utils.getSingleConstStringArgument import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.expressions.IrClassReference import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.ir.types.makeNullable +import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.getAnnotation import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.name.FqName @@ -36,5 +40,18 @@ fun IrAnnotationContainer.getWasmImportAnnotation(): WasmImportPair? = ) } + +class WasmArrayInfo(val klass: IrClass, val isNullable: Boolean) { + val type = klass.defaultType.let { if (isNullable) it.makeNullable() else it } +} + +fun IrAnnotationContainer.getWasmArrayAnnotation(): WasmArrayInfo? = + getAnnotation(FqName("kotlin.wasm.internal.WasmArrayOf"))?.let { + WasmArrayInfo( + (it.getValueArgument(0) as IrClassReference).symbol.owner as IrClass, + (it.getValueArgument(1) as IrConst<*>).value as Boolean, + ) + } + fun IrAnnotationContainer.getJsFunAnnotation(): String? = getAnnotation(FqName("kotlin.JsFun"))?.getSingleConstStringArgument() diff --git a/libraries/stdlib/wasm/builtins/kotlin/Array.kt b/libraries/stdlib/wasm/builtins/kotlin/Array.kt index cdc115b427f..98a40a67815 100644 --- a/libraries/stdlib/wasm/builtins/kotlin/Array.kt +++ b/libraries/stdlib/wasm/builtins/kotlin/Array.kt @@ -15,7 +15,7 @@ import kotlin.wasm.internal.* * for more information on arrays. */ public class Array constructor(size: Int) { - private var jsArray: WasmExternRef = JsArray_new(size) + private var storage: WasmAnyArray = WasmAnyArray(size) /** * Creates a new array with the specified [size], where each element is calculated by calling the specified @@ -26,7 +26,7 @@ public class Array constructor(size: Int) { */ @Suppress("TYPE_PARAMETER_AS_REIFIED") public constructor(size: Int, init: (Int) -> T) : this(size) { - JsArray_fill_T(jsArray, size, init) + storage.fill(size, init) } /** @@ -41,7 +41,7 @@ public class Array constructor(size: Int) { */ @Suppress("UNCHECKED_CAST") public operator fun get(index: Int): T = - WasmExternRefToAny(JsArray_get_WasmExternRef(jsArray, index)) as T + storage.get(index) as T /** * Sets the array element at the specified [index] to the specified [value]. This method can @@ -54,14 +54,14 @@ public class Array constructor(size: Int) { * where the behavior is unspecified. */ public operator fun set(index: Int, value: T) { - JsArray_set_WasmExternRef(jsArray, index, value.toWasmExternRef()) + storage.set(index, value) } /** * Returns the number of elements in the array. */ public val size: Int - get() = JsArray_getSize(jsArray) + get() = storage.len() /** * Creates an iterator for iterating over the elements of the array. diff --git a/libraries/stdlib/wasm/builtins/kotlin/Arrays.kt b/libraries/stdlib/wasm/builtins/kotlin/Arrays.kt index 3cc884ec1c9..1bbf8ae056c 100644 --- a/libraries/stdlib/wasm/builtins/kotlin/Arrays.kt +++ b/libraries/stdlib/wasm/builtins/kotlin/Arrays.kt @@ -8,27 +8,21 @@ package kotlin import kotlin.wasm.internal.* public class ByteArray(size: Int) { - private var jsArray: WasmExternRef = JsArray_new(size) - - init { - JsArray_fill_Byte(jsArray, size) { 0 } - } + private var storage = WasmByteArray(size) public constructor(size: Int, init: (Int) -> Byte) : this(size) { - jsArray = JsArray_new(size) - JsArray_fill_Byte(jsArray, size, init) + storage.fill(size, init) } public operator fun get(index: Int): Byte = - JsArray_get_Byte(jsArray, index) + storage.get(index) public operator fun set(index: Int, value: Byte) { - JsArray_set_Byte(jsArray, index, value) + storage.set(index, value) } public val size: Int - get() = JsArray_getSize(jsArray) - + get() = storage.len() public operator fun iterator(): ByteIterator = byteArrayIterator(this) } @@ -41,26 +35,21 @@ internal fun byteArrayIterator(array: ByteArray) = object : ByteIterator() { public class CharArray(size: Int) { - private var jsArray: WasmExternRef = JsArray_new(size) - - init { - JsArray_fill_Char(jsArray, size) { 0.toChar() } - } + private var storage = WasmShortArray(size) public constructor(size: Int, init: (Int) -> Char) : this(size) { - jsArray = JsArray_new(size) - JsArray_fill_Char(jsArray, size, init) + storage.fill(size) { init(it).toShort() } } public operator fun get(index: Int): Char = - JsArray_get_Char(jsArray, index) + storage.get(index).toChar() public operator fun set(index: Int, value: Char) { - JsArray_set_Char(jsArray, index, value) + storage.set(index, value.toShort()) } public val size: Int - get() = JsArray_getSize(jsArray) + get() = storage.len() public operator fun iterator(): CharIterator = charArrayIterator(this) @@ -74,25 +63,21 @@ internal fun charArrayIterator(array: CharArray) = object : CharIterator() { public class ShortArray(size: Int) { - private var jsArray: WasmExternRef = JsArray_new(size) - - init { - JsArray_fill_Short(jsArray, size) { 0 } - } + private var storage = WasmShortArray(size) public constructor(size: Int, init: (Int) -> Short) : this(size) { - JsArray_fill_Short(jsArray, size, init) + storage.fill(size, init) } public operator fun get(index: Int): Short = - JsArray_get_Short(jsArray, index) + storage.get(index) public operator fun set(index: Int, value: Short) { - JsArray_set_Short(jsArray, index, value) + storage.set(index, value) } public val size: Int - get() = JsArray_getSize(jsArray) + get() = storage.len() public operator fun iterator(): ShortIterator = shortArrayIterator(this) @@ -106,25 +91,21 @@ internal fun shortArrayIterator(array: ShortArray) = object : ShortIterator() { public class IntArray(size: Int) { - private var jsArray: WasmExternRef = JsArray_new(size) - - init { - JsArray_fill_Int(jsArray, size) { 0 } - } + private var storage = WasmIntArray(size) public constructor(size: Int, init: (Int) -> Int) : this(size) { - JsArray_fill_Int(jsArray, size, init) + storage.fill(size, init) } public operator fun get(index: Int): Int = - JsArray_get_Int(jsArray, index) + storage.get(index) public operator fun set(index: Int, value: Int) { - JsArray_set_Int(jsArray, index, value) + storage.set(index, value) } public val size: Int - get() = JsArray_getSize(jsArray) + get() = storage.len() public operator fun iterator(): IntIterator = intArrayIterator(this) @@ -138,26 +119,21 @@ internal fun intArrayIterator(array: IntArray) = object : IntIterator() { public class LongArray(size: Int) { - private var jsArray: WasmExternRef = JsArray_new(size) - - init { - JsArray_fill_Long(jsArray, size) { 0L } - } + private var storage = WasmLongArray (size) public constructor(size: Int, init: (Int) -> Long) : this(size) { - JsArray_fill_Long(jsArray, size, init) + storage.fill(size, init) } public operator fun get(index: Int): Long = - JsArray_get_Long(jsArray, index) + storage.get(index) public operator fun set(index: Int, value: Long) { - JsArray_set_Long(jsArray, index, value) + storage.set(index, value) } public val size: Int - get() = JsArray_getSize(jsArray) - + get() = storage.len() public operator fun iterator(): LongIterator = longArrayIterator(this) } @@ -170,26 +146,21 @@ internal fun longArrayIterator(array: LongArray) = object : LongIterator() { public class FloatArray(size: Int) { - private var jsArray: WasmExternRef = JsArray_new(size) - - init { - JsArray_fill_Float(jsArray, size) { 0.0f } - } + private var storage = WasmFloatArray(size) public constructor(size: Int, init: (Int) -> Float) : this(size) { - JsArray_fill_Float(jsArray, size, init) + storage.fill(size, init) } public operator fun get(index: Int): Float = - JsArray_get_Float(jsArray, index) + storage.get(index) public operator fun set(index: Int, value: Float) { - JsArray_set_Float(jsArray, index, value) + storage.set(index, value) } public val size: Int - get() = JsArray_getSize(jsArray) - + get() = storage.len() public operator fun iterator(): FloatIterator = floatArrayIterator(this) } @@ -202,26 +173,21 @@ internal fun floatArrayIterator(array: FloatArray) = object : FloatIterator() { public class DoubleArray(size: Int) { - private var jsArray: WasmExternRef = JsArray_new(size) - - init { - JsArray_fill_Double(jsArray, size) { 0.0 } - } + private var storage = WasmDoubleArray(size) public constructor(size: Int, init: (Int) -> Double) : this(size) { - JsArray_fill_Double(jsArray, size, init) + storage.fill(size, init) } public operator fun get(index: Int): Double = - JsArray_get_Double(jsArray, index) + storage.get(index) public operator fun set(index: Int, value: Double) { - JsArray_set_Double(jsArray, index, value) + storage.set(index, value) } public val size: Int - get() = JsArray_getSize(jsArray) - + get() = storage.len() public operator fun iterator(): DoubleIterator = doubleArrayIterator(this) } @@ -234,26 +200,21 @@ internal fun doubleArrayIterator(array: DoubleArray) = object : DoubleIterator() public class BooleanArray(size: Int) { - private var jsArray: WasmExternRef = JsArray_new(size) - - init { - JsArray_fill_Boolean(jsArray, size) { false } - } + private var storage = WasmBooleanArray(size) public constructor(size: Int, init: (Int) -> Boolean) : this(size) { - JsArray_fill_Boolean(jsArray, size, init) + storage.fill(size, init) } public operator fun get(index: Int): Boolean = - JsArray_get_Boolean(jsArray, index) + storage.get(index) public operator fun set(index: Int, value: Boolean) { - JsArray_set_Boolean(jsArray, index, value) + storage.set(index, value) } public val size: Int - get() = JsArray_getSize(jsArray) - + get() = storage.len() public operator fun iterator(): BooleanIterator = booleanArrayIterator(this) } diff --git a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/JsArray.kt b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/JsArray.kt deleted file mode 100644 index 2d74af9b300..00000000000 --- a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/JsArray.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - - -package kotlin.wasm.internal - -@ExcludedFromCodegen -@WasmForeign -internal class WasmExternRef - -@WasmImport("runtime", "JsArray_new") -internal fun JsArray_new(size: Int): WasmExternRef = - implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_get") -internal fun JsArray_get_Byte(array: WasmExternRef, index: Int): Byte = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_set") -internal fun JsArray_set_Byte(array: WasmExternRef, index: Int, value: Byte): Unit = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_get") -internal fun JsArray_get_Char(array: WasmExternRef, index: Int): Char = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_set") -internal fun JsArray_set_Char(array: WasmExternRef, index: Int, value: Char): Unit = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_get") -internal fun JsArray_get_Short(array: WasmExternRef, index: Int): Short = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_set") -internal fun JsArray_set_Short(array: WasmExternRef, index: Int, value: Short): Unit = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_get") -internal fun JsArray_get_Int(array: WasmExternRef, index: Int): Int = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_set") -internal fun JsArray_set_Int(array: WasmExternRef, index: Int, value: Int): Unit = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_get") -internal fun JsArray_get_Long(array: WasmExternRef, index: Int): Long = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_set") -internal fun JsArray_set_Long(array: WasmExternRef, index: Int, value: Long): Unit = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_get") -internal fun JsArray_get_Float(array: WasmExternRef, index: Int): Float = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_set") -internal fun JsArray_set_Float(array: WasmExternRef, index: Int, value: Float): Unit = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_get") -internal fun JsArray_get_Double(array: WasmExternRef, index: Int): Double = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_set") -internal fun JsArray_set_Double(array: WasmExternRef, index: Int, value: Double): Unit = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_get") -internal fun JsArray_get_Boolean(array: WasmExternRef, index: Int): Boolean = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_set") -internal fun JsArray_set_Boolean(array: WasmExternRef, index: Int, value: Boolean): Unit = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_get") -internal fun JsArray_get_WasmExternRef(array: WasmExternRef, index: Int): WasmExternRef = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_set") -internal fun JsArray_set_WasmExternRef(array: WasmExternRef, index: Int, value: WasmExternRef): Unit = implementedAsIntrinsic - -@WasmImport("runtime", "JsArray_getSize") -internal fun JsArray_getSize(array: WasmExternRef): Int = - implementedAsIntrinsic - -@JsFun("(x) => x") -internal fun Any?.toWasmExternRef(): WasmExternRef = - implementedAsIntrinsic - -@JsFun("(x) => x") -internal fun WasmExternRefToAny(ref: WasmExternRef): Any? = - implementedAsIntrinsic - -internal inline fun JsArray_fill_Byte(array: WasmExternRef, size: Int, init: (Int) -> Byte) { - var i = 0 - while (i < size) { - JsArray_set_Byte(array, i, init(i)) - i++ - } -} - -internal inline fun JsArray_fill_Char(array: WasmExternRef, size: Int, init: (Int) -> Char) { - var i = 0 - while (i < size) { - JsArray_set_Char(array, i, init(i)) - i++ - } -} - -internal inline fun JsArray_fill_Short(array: WasmExternRef, size: Int, init: (Int) -> Short) { - var i = 0 - while (i < size) { - JsArray_set_Short(array, i, init(i)) - i++ - } -} - -internal inline fun JsArray_fill_Int(array: WasmExternRef, size: Int, init: (Int) -> Int) { - var i = 0 - while (i < size) { - JsArray_set_Int(array, i, init(i)) - i++ - } -} - -internal inline fun JsArray_fill_Long(array: WasmExternRef, size: Int, init: (Int) -> Long) { - var i = 0 - while (i < size) { - JsArray_set_Long(array, i, init(i)) - i++ - } -} - -internal inline fun JsArray_fill_Float(array: WasmExternRef, size: Int, init: (Int) -> Float) { - var i = 0 - while (i < size) { - JsArray_set_Float(array, i, init(i)) - i++ - } -} - -internal inline fun JsArray_fill_Double(array: WasmExternRef, size: Int, init: (Int) -> Double) { - var i = 0 - while (i < size) { - JsArray_set_Double(array, i, init(i)) - i++ - } -} - -internal inline fun JsArray_fill_Boolean(array: WasmExternRef, size: Int, init: (Int) -> Boolean) { - var i = 0 - while (i < size) { - JsArray_set_Boolean(array, i, init(i)) - i++ - } -} - -internal inline fun JsArray_fill_T(array: WasmExternRef, size: Int, init: (Int) -> T) { - var i = 0 - while (i < size) { - JsArray_set_WasmExternRef(array, i, init(i).toWasmExternRef()) - i++ - } -} \ No newline at end of file diff --git a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmAnnotations.kt b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmAnnotations.kt index 24f44c8057e..1b03001c9ef 100644 --- a/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmAnnotations.kt +++ b/libraries/stdlib/wasm/internal/kotlin/wasm/internal/WasmAnnotations.kt @@ -6,6 +6,7 @@ package kotlin.wasm.internal import kotlin.annotation.AnnotationTarget.* +import kotlin.reflect.KClass // Exclude declaration or file from lowering and code generation @Target(FILE, CLASS, FUNCTION, CONSTRUCTOR, PROPERTY) @@ -20,6 +21,13 @@ internal annotation class WasmImport(val module: String, val name: String) @Retention(AnnotationRetention.BINARY) internal annotation class WasmForeign +@Target(CLASS) +@Retention(AnnotationRetention.BINARY) +internal annotation class WasmArrayOf( + val type: KClass<*>, + val isNullable: Boolean, +) + @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.BINARY) internal annotation class WasmReinterpret diff --git a/libraries/stdlib/wasm/src/generated/_WasmArrays.kt b/libraries/stdlib/wasm/src/generated/_WasmArrays.kt new file mode 100644 index 00000000000..ec59a1e957f --- /dev/null +++ b/libraries/stdlib/wasm/src/generated/_WasmArrays.kt @@ -0,0 +1,196 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package kotlin.wasm.internal + +// +// NOTE: THIS FILE IS AUTO-GENERATED by the GenerateStandardLib.kt +// See: https://github.com/JetBrains/kotlin/tree/master/libraries/stdlib +// + +@WasmArrayOf(Any::class, isNullable = true) +internal class WasmAnyArray(size: Int) { + @WasmOp(WasmOp.ARRAY_GET) + fun get(index: Int): Any? = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_SET) + fun set(index: Int, value: Any?): Unit = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_LEN) + fun len(): Int = + implementedAsIntrinsic +} + +internal inline fun WasmAnyArray.fill(size: Int, init: (Int) -> Any?) { + var i = 0 + while (i < size) { + set(i, init(i)) + i++ + } +} + +@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) + fun get(index: Int): Byte = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_SET) + fun set(index: Int, value: Byte): Unit = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_LEN) + fun len(): Int = + implementedAsIntrinsic +} + +internal inline fun WasmByteArray.fill(size: Int, init: (Int) -> Byte) { + 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) + fun get(index: Int): Short = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_SET) + fun set(index: Int, value: Short): Unit = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_LEN) + fun len(): Int = + implementedAsIntrinsic +} + +internal inline fun WasmShortArray.fill(size: Int, init: (Int) -> Short) { + var i = 0 + while (i < size) { + set(i, init(i)) + i++ + } +} + +@WasmArrayOf(Int::class, isNullable = false) +internal class WasmIntArray(size: Int) { + @WasmOp(WasmOp.ARRAY_GET) + fun get(index: Int): Int = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_SET) + fun set(index: Int, value: Int): Unit = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_LEN) + fun len(): Int = + implementedAsIntrinsic +} + +internal inline fun WasmIntArray.fill(size: Int, init: (Int) -> Int) { + var i = 0 + while (i < size) { + set(i, init(i)) + i++ + } +} + +@WasmArrayOf(Long::class, isNullable = false) +internal class WasmLongArray(size: Int) { + @WasmOp(WasmOp.ARRAY_GET) + fun get(index: Int): Long = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_SET) + fun set(index: Int, value: Long): Unit = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_LEN) + fun len(): Int = + implementedAsIntrinsic +} + +internal inline fun WasmLongArray.fill(size: Int, init: (Int) -> Long) { + var i = 0 + while (i < size) { + set(i, init(i)) + i++ + } +} + +@WasmArrayOf(Float::class, isNullable = false) +internal class WasmFloatArray(size: Int) { + @WasmOp(WasmOp.ARRAY_GET) + fun get(index: Int): Float = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_SET) + fun set(index: Int, value: Float): Unit = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_LEN) + fun len(): Int = + implementedAsIntrinsic +} + +internal inline fun WasmFloatArray.fill(size: Int, init: (Int) -> Float) { + var i = 0 + while (i < size) { + set(i, init(i)) + i++ + } +} + +@WasmArrayOf(Double::class, isNullable = false) +internal class WasmDoubleArray(size: Int) { + @WasmOp(WasmOp.ARRAY_GET) + fun get(index: Int): Double = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_SET) + fun set(index: Int, value: Double): Unit = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_LEN) + fun len(): Int = + implementedAsIntrinsic +} + +internal inline fun WasmDoubleArray.fill(size: Int, init: (Int) -> Double) { + var i = 0 + while (i < size) { + set(i, init(i)) + i++ + } +} + diff --git a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt index c9c548e922c..9d84e3552b5 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt @@ -72,7 +72,7 @@ fun main(args: Array) { targetDir.resolve("_${source.name.capitalize()}$platformSuffix.kt") } - targetBaseDirs[KotlinTarget.WASM]?.let { generateWasmOps(it) } + targetBaseDirs[KotlinTarget.WASM]?.let { generateWasmBuiltIns(it) } } fun File.resolveExistingDir(subpath: String) = resolve(subpath).also { it.requireExistingDir() } diff --git a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateWasmOps.kt b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateWasmOps.kt index f55c535982c..350f73fa400 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateWasmOps.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateWasmOps.kt @@ -8,16 +8,27 @@ package generators import org.jetbrains.kotlin.wasm.ir.WasmOp import templates.COMMON_AUTOGENERATED_WARNING import templates.COPYRIGHT_NOTICE +import templates.PrimitiveType import java.io.File import java.io.FileWriter + +fun generateWasmBuiltIns(targetDir: File) { + generateWasmOps(targetDir) + generateWasmArrays(targetDir) +} + +fun FileWriter.generateStandardWasmInternalHeader() { + appendLine(COPYRIGHT_NOTICE) + appendLine("package kotlin.wasm.internal") + appendLine() + appendLine(COMMON_AUTOGENERATED_WARNING) + appendLine() +} + fun generateWasmOps(targetDir: File) { FileWriter(targetDir.resolve("_WasmOp.kt")).use { writer -> - writer.appendLine(COPYRIGHT_NOTICE) - writer.appendLine("package kotlin.wasm.internal") - writer.appendLine() - writer.appendLine(COMMON_AUTOGENERATED_WARNING) - writer.appendLine() + writer.generateStandardWasmInternalHeader() writer.appendLine( """ @ExcludedFromCodegen @@ -38,4 +49,46 @@ fun generateWasmOps(targetDir: File) { """.trimIndent() ) } +} + +fun generateWasmArrays(targetDir: File) { + FileWriter(targetDir.resolve("_WasmArrays.kt")).use { writer -> + 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)) + } + } +} + +fun wasmArrayForType(klass: String, isNullable: Boolean): String { + val type = klass + if (isNullable) "?" else "" + val name = "Wasm${klass}Array" + return """ + @WasmArrayOf($klass::class, isNullable = $isNullable) + internal class $name(size: Int) { + @WasmOp(WasmOp.ARRAY_GET) + fun get(index: Int): $type = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_SET) + fun set(index: Int, value: $type): Unit = + implementedAsIntrinsic + + @WasmOp(WasmOp.ARRAY_LEN) + fun len(): Int = + implementedAsIntrinsic + } + + internal inline fun $name.fill(size: Int, init: (Int) -> $type) { + var i = 0 + while (i < size) { + set(i, init(i)) + i++ + } + } + + """.trimIndent() } \ No newline at end of file diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt index fa076105238..83e48b3dc39 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/Declarations.kt @@ -145,6 +145,11 @@ class WasmStructDeclaration( val fields: List ) : WasmTypeDeclaration(name) +class WasmArrayDeclaration( + name: String, + val field: WasmStructFieldDeclaration +) : WasmTypeDeclaration(name) + class WasmStructFieldDeclaration( val name: String, val type: WasmType, diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt index 7aff5c8e626..0ed326c03fb 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt @@ -26,7 +26,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) { gcTypes.forEach { when (it) { is WasmStructDeclaration -> appendStructTypeDeclaration(it) - else -> TODO("Support arrays") + is WasmArrayDeclaration -> appendArrayTypeDeclaration(it) } } } @@ -197,15 +197,24 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule) { } } + private fun appendFiledType(field: WasmStructFieldDeclaration) { + appendType(field.type) + b.writeVarUInt1(field.isMutable) + } + private fun appendStructTypeDeclaration(type: WasmStructDeclaration) { b.writeVarInt7(-0x21) b.writeVarUInt32(type.fields.size) type.fields.forEach { - appendType(it.type) - b.writeVarUInt1(it.isMutable) + appendFiledType(it) } } + private fun appendArrayTypeDeclaration(type: WasmArrayDeclaration) { + b.writeVarInt7(-0x22) + appendFiledType(type.field) + } + val WasmFunctionType.index: Int get() = module.functionTypes.indexOf(this) diff --git a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt index a023490d499..dfcdf07ac43 100644 --- a/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt +++ b/wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt @@ -201,8 +201,9 @@ class WasmIrToText : SExpressionBuilder() { when (it) { is WasmStructDeclaration -> appendStructTypeDeclaration(it) - else -> - TODO("Support arrays") + is WasmArrayDeclaration -> + appendArrayTypeDeclaration(it) + else -> error("Unexpected GC type: $it") } } importsInOrder.forEach { @@ -253,6 +254,16 @@ class WasmIrToText : SExpressionBuilder() { } } + private fun appendArrayTypeDeclaration(type: WasmArrayDeclaration) { + newLineList("type") { + appendModuleFieldReference(type) + sameLineList("array") { + appendStructField(type.field) + } + } + } + + private fun appendImportedFunction(function: WasmFunction.Imported) { newLineList("func") { appendModuleFieldReference(function)