[WASM] Optimize varargs without spreads
This commit is contained in:
+2
-2
@@ -77,7 +77,7 @@ abstract class AbstractValueUsageTransformer(
|
||||
protected open fun IrExpression.useAsResult(enclosing: IrExpression): IrExpression =
|
||||
this.useAs(enclosing.type)
|
||||
|
||||
protected open fun IrExpression.useAsVarargElement(expression: IrVararg): IrExpression = this
|
||||
protected open fun useAsVarargElement(element: IrExpression, expression: IrVararg): IrExpression = element
|
||||
|
||||
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
||||
TODO()
|
||||
@@ -233,7 +233,7 @@ abstract class AbstractValueUsageTransformer(
|
||||
is IrSpreadElement ->
|
||||
element.expression = element.expression.useAs(expression.type)
|
||||
is IrExpression -> {
|
||||
expression.putElement(i, element.useAsVarargElement(expression))
|
||||
expression.putElement(i, useAsVarargElement(element, expression))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -108,16 +108,14 @@ abstract class AbstractValueUsageLowering(val context: JsCommonBackendContext) :
|
||||
return this.useAsArgument(expression.target.valueParameters[parameter.index])
|
||||
}
|
||||
|
||||
|
||||
override fun IrExpression.useAsVarargElement(expression: IrVararg): IrExpression {
|
||||
return this.useAs(
|
||||
override fun useAsVarargElement(element: IrExpression, expression: IrVararg): IrExpression =
|
||||
element.useAs(
|
||||
// Do not box primitive inline classes
|
||||
if (icUtils.isTypeInlined(type) && !icUtils.isTypeInlined(expression.type) && !expression.type.isPrimitiveArray())
|
||||
if (icUtils.isTypeInlined(element.type) && !icUtils.isTypeInlined(expression.type) && !expression.type.isPrimitiveArray())
|
||||
irBuiltIns.anyNType
|
||||
else
|
||||
expression.varargElementType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class AutoboxingTransformer(context: JsCommonBackendContext) : AbstractValueUsageLowering(context) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
|
||||
+8
@@ -37,6 +37,14 @@ internal class WasmUsefulDeclarationProcessor(
|
||||
super.visitVariable(declaration, data)
|
||||
}
|
||||
|
||||
override fun visitVararg(expression: IrVararg, data: IrDeclaration) {
|
||||
expression.type.getClass()!!
|
||||
.constructors
|
||||
.firstOrNull { it.hasWasmPrimitiveConstructorAnnotation() }
|
||||
?.enqueue(data, "implicit vararg constructor")
|
||||
super.visitVararg(expression, data)
|
||||
}
|
||||
|
||||
private fun tryToProcessIntrinsicCall(from: IrDeclaration, call: IrCall): Boolean = when (call.symbol) {
|
||||
context.wasmSymbols.unboxIntrinsic -> {
|
||||
val fromType = call.getTypeArgument(0)
|
||||
|
||||
+68
-11
@@ -73,6 +73,59 @@ class BodyGenerator(
|
||||
error("Unexpected element of type ${element::class}")
|
||||
}
|
||||
|
||||
private fun tryGenerateConstVarargArray(irVararg: IrVararg, wasmArrayType: WasmImmediate.GcType): Boolean {
|
||||
if (irVararg.elements.isEmpty()) return false
|
||||
|
||||
val kind = (irVararg.elements[0] as? IrConst<*>)?.kind ?: return false
|
||||
if (kind == IrConstKind.String || kind == IrConstKind.Null) return false
|
||||
if (irVararg.elements.any { it !is IrConst<*> || it.kind != kind }) return false
|
||||
|
||||
val elementConstValues = irVararg.elements.map { (it as IrConst<*>).value!! }
|
||||
|
||||
val resource = when (irVararg.varargElementType) {
|
||||
irBuiltIns.byteType -> elementConstValues.map { (it as Byte).toLong() } to WasmI8
|
||||
irBuiltIns.booleanType -> elementConstValues.map { if (it as Boolean) 1L else 0L } to WasmI8
|
||||
irBuiltIns.intType -> elementConstValues.map { (it as Int).toLong() } to WasmI32
|
||||
irBuiltIns.shortType -> elementConstValues.map { (it as Short).toLong() } to WasmI16
|
||||
irBuiltIns.longType -> elementConstValues.map { it as Long } to WasmI64
|
||||
else -> return false
|
||||
}
|
||||
|
||||
val constantArrayId = context.referenceConstantArray(resource)
|
||||
|
||||
body.buildConstI32(0)
|
||||
body.buildConstI32(irVararg.elements.size)
|
||||
body.buildInstr(WasmOp.ARRAY_NEW_DATA, wasmArrayType, WasmImmediate.DataIdx(constantArrayId))
|
||||
return true
|
||||
}
|
||||
|
||||
private fun tryGenerateVarargArray(irVararg: IrVararg, wasmArrayType: WasmImmediate.GcType) {
|
||||
irVararg.elements.forEach {
|
||||
check(it is IrExpression)
|
||||
generateExpression(it)
|
||||
}
|
||||
|
||||
val length = WasmImmediate.ConstI32(irVararg.elements.size)
|
||||
body.buildInstr(WasmOp.ARRAY_NEW_FIXED, wasmArrayType, length)
|
||||
}
|
||||
|
||||
override fun visitVararg(expression: IrVararg) {
|
||||
val arrayClass = expression.type.getClass()!!
|
||||
|
||||
val wasmArrayType = arrayClass.constructors
|
||||
.mapNotNull { it.valueParameters.singleOrNull()?.type }
|
||||
.firstOrNull { it.getClass()?.getWasmArrayAnnotation() != null }
|
||||
?.getRuntimeClass(irBuiltIns)?.symbol
|
||||
?.let(context::referenceGcType)
|
||||
?.let(WasmImmediate::GcType)
|
||||
|
||||
check(wasmArrayType != null)
|
||||
|
||||
generateAnyParameters(arrayClass.symbol)
|
||||
if (!tryGenerateConstVarargArray(expression, wasmArrayType)) tryGenerateVarargArray(expression, wasmArrayType)
|
||||
body.buildStructNew(context.referenceGcType(expression.type.getRuntimeClass(irBuiltIns).symbol))
|
||||
}
|
||||
|
||||
override fun visitThrow(expression: IrThrow) {
|
||||
generateExpression(expression.value)
|
||||
body.buildThrow(context.tagIdx)
|
||||
@@ -256,14 +309,18 @@ class BodyGenerator(
|
||||
generateCall(expression)
|
||||
}
|
||||
|
||||
private fun generateBox(expression: IrExpression, type: IrType) {
|
||||
val klassSymbol = type.getRuntimeClass(irBuiltIns).symbol
|
||||
generateAnyParameters(klassSymbol)
|
||||
generateExpression(expression)
|
||||
body.buildStructNew(context.referenceGcType(klassSymbol))
|
||||
}
|
||||
|
||||
private fun generateCall(call: IrFunctionAccessExpression) {
|
||||
// Box intrinsic has an additional klass ID argument.
|
||||
// Processing it separately
|
||||
if (call.symbol == wasmSymbols.boxIntrinsic) {
|
||||
val klassSymbol = call.getTypeArgument(0)!!.getRuntimeClass(irBuiltIns).symbol
|
||||
generateAnyParameters(klassSymbol)
|
||||
generateExpression(call.getValueArgument(0)!!)
|
||||
body.buildStructNew(context.referenceGcType(klassSymbol))
|
||||
generateBox(call.getValueArgument(0)!!, call.getTypeArgument(0)!!)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -491,17 +548,17 @@ class BodyGenerator(
|
||||
body.buildInstr(WasmOp.ARRAY_COPY, immediate, immediate)
|
||||
}
|
||||
|
||||
wasmSymbols.wasmArrayNewData0 -> {
|
||||
val immediate = WasmImmediate.GcType(
|
||||
context.referenceGcType(call.getTypeArgument(0)!!.getRuntimeClass(irBuiltIns).symbol)
|
||||
)
|
||||
body.buildInstr(WasmOp.ARRAY_NEW_DATA, immediate, WasmImmediate.DataIdx(0))
|
||||
}
|
||||
|
||||
wasmSymbols.stringGetPoolSize -> {
|
||||
body.buildConstI32Symbol(context.stringPoolSize)
|
||||
}
|
||||
|
||||
wasmSymbols.wasmArrayNewData0 -> {
|
||||
val arrayGcType = WasmImmediate.GcType(
|
||||
context.referenceGcType(call.getTypeArgument(0)!!.getRuntimeClass(irBuiltIns).symbol)
|
||||
)
|
||||
body.buildInstr(WasmOp.ARRAY_NEW_DATA, arrayGcType, WasmImmediate.DataIdx(0))
|
||||
}
|
||||
|
||||
else -> {
|
||||
return false
|
||||
}
|
||||
|
||||
+27
@@ -10,7 +10,10 @@ import org.jetbrains.kotlin.wasm.ir.WasmSymbol
|
||||
// Representation of constant data in Wasm memory
|
||||
|
||||
internal const val CHAR_SIZE_BYTES = 2
|
||||
internal const val BYTE_SIZE_BYTES = 1
|
||||
internal const val SHORT_SIZE_BYTES = 2
|
||||
internal const val INT_SIZE_BYTES = 4
|
||||
internal const val LONG_SIZE_BYTES = 8
|
||||
|
||||
sealed class ConstantDataElement {
|
||||
abstract val sizeInBytes: Int
|
||||
@@ -45,6 +48,23 @@ class ConstantDataIntField(val name: String, val value: WasmSymbol<Int>) : Const
|
||||
override val sizeInBytes: Int = INT_SIZE_BYTES
|
||||
}
|
||||
|
||||
class ConstantDataIntegerArray(val name: String, val value: List<Long>, private val integerSize: Int) : ConstantDataElement() {
|
||||
override fun toBytes(): ByteArray {
|
||||
val array = ByteArray(value.size * integerSize)
|
||||
repeat(value.size) { i ->
|
||||
value[i].toLittleEndianBytesTo(array, i * integerSize, integerSize)
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
override fun dump(indent: String, startAddress: Int): String {
|
||||
if (value.isEmpty()) return ""
|
||||
return "${addressToString(startAddress)}: $indent i${integerSize * 8}[] : ${toBytes().contentToString()} ;; $name\n"
|
||||
}
|
||||
|
||||
override val sizeInBytes: Int = value.size * integerSize
|
||||
}
|
||||
|
||||
class ConstantDataIntArray(val name: String, val value: List<WasmSymbol<Int>>) : ConstantDataElement() {
|
||||
override fun toBytes(): ByteArray {
|
||||
return value.fold(byteArrayOf()) { acc, el -> acc + el.owner.toLittleEndianBytes() }
|
||||
@@ -95,6 +115,13 @@ class ConstantDataStruct(val name: String, val elements: List<ConstantDataElemen
|
||||
override val sizeInBytes: Int = elements.map { it.sizeInBytes }.sum()
|
||||
}
|
||||
|
||||
fun Long.toLittleEndianBytesTo(to: ByteArray, offset: Int, size: Int) {
|
||||
for (i in 0 until size) {
|
||||
to[offset + i] = (this ushr (i * 8)).toByte()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun Int.toLittleEndianBytes(): ByteArray {
|
||||
return ByteArray(4) {
|
||||
(this ushr (it * 8)).toByte()
|
||||
|
||||
+2
@@ -38,6 +38,8 @@ interface WasmBaseCodegenContext {
|
||||
|
||||
fun referenceStringLiteralAddressAndId(string: String): Pair<WasmSymbol<Int>, WasmSymbol<Int>>
|
||||
|
||||
fun referenceConstantArray(resource: Pair<List<Long>, WasmType>): WasmSymbol<Int>
|
||||
|
||||
fun transformType(irType: IrType): WasmType
|
||||
fun transformFieldType(irType: IrType): WasmType
|
||||
|
||||
|
||||
+15
@@ -40,6 +40,8 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
ReferencableElements<String, Int>()
|
||||
val stringLiteralPoolId =
|
||||
ReferencableElements<String, Int>()
|
||||
val constantArrayDataSegmentId =
|
||||
ReferencableElements<Pair<List<Long>, WasmType>, Int>()
|
||||
|
||||
private val tagFuncType = WasmFunctionType(
|
||||
listOf(
|
||||
@@ -148,6 +150,18 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
|
||||
val data = mutableListOf<WasmData>()
|
||||
data.add(WasmData(WasmDataMode.Passive, stringDataSectionBytes.toByteArray()))
|
||||
constantArrayDataSegmentId.unbound.forEach { (constantArraySegment, symbol) ->
|
||||
symbol.bind(data.size)
|
||||
val integerSize = when (constantArraySegment.second) {
|
||||
WasmI8 -> BYTE_SIZE_BYTES
|
||||
WasmI16 -> SHORT_SIZE_BYTES
|
||||
WasmI32 -> INT_SIZE_BYTES
|
||||
WasmI64 -> LONG_SIZE_BYTES
|
||||
else -> TODO("type ${constantArraySegment.second} is not implemented")
|
||||
}
|
||||
val constData = ConstantDataIntegerArray("constant_array", constantArraySegment.first, integerSize)
|
||||
data.add(WasmData(WasmDataMode.Passive, constData.toBytes()))
|
||||
}
|
||||
typeInfo.buildData(data, address = { klassIds.getValue(it) })
|
||||
|
||||
val masterInitFunctionType = WasmFunctionType(emptyList(), emptyList())
|
||||
@@ -203,6 +217,7 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
||||
startFunction = null, // Module is initialized via export call
|
||||
elements = emptyList(),
|
||||
data = data,
|
||||
dataCount = true,
|
||||
tags = listOf(tag)
|
||||
)
|
||||
module.calculateIds()
|
||||
|
||||
+3
@@ -67,6 +67,9 @@ class WasmModuleCodegenContextImpl(
|
||||
return address to id
|
||||
}
|
||||
|
||||
override fun referenceConstantArray(resource: Pair<List<Long>, WasmType>): WasmSymbol<Int> =
|
||||
wasmFragment.constantArrayDataSegmentId.reference(resource)
|
||||
|
||||
override fun generateTypeInfo(irClass: IrClassSymbol, typeInfo: ConstantDataElement) {
|
||||
wasmFragment.typeInfo.define(irClass, typeInfo)
|
||||
}
|
||||
|
||||
+7
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.wasm.ir2wasm.isExternalType
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.AbstractValueUsageLowering
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
|
||||
/**
|
||||
@@ -26,4 +27,10 @@ class ExplicitlyCastExternalTypesLowering(wasmContext: WasmBackendContext) : Abs
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
override fun useAsVarargElement(element: IrExpression, expression: IrVararg): IrExpression =
|
||||
if (isExternalType(element.type))
|
||||
element.useAs(irBuiltIns.anyNType)
|
||||
else
|
||||
super.useAsVarargElement(element, expression)
|
||||
}
|
||||
|
||||
+28
-10
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irComposite
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
@@ -20,7 +21,6 @@ import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
internal class WasmVarargExpressionLowering(
|
||||
private val context: WasmBackendContext
|
||||
@@ -44,11 +44,11 @@ internal class WasmVarargExpressionLowering(
|
||||
get() = arrayClass.symbol in context.wasmSymbols.unsignedTypesToUnsignedArrays.values
|
||||
|
||||
val primaryConstructor: IrConstructor
|
||||
get() {
|
||||
get() =
|
||||
if (isUnsigned)
|
||||
return arrayClass.constructors.find { it.valueParameters.singleOrNull()?.type == context.irBuiltIns.intType }!!
|
||||
return arrayClass.primaryConstructor!!
|
||||
}
|
||||
arrayClass.constructors.find { it.valueParameters.singleOrNull()?.type == context.irBuiltIns.intType }!!
|
||||
else arrayClass.primaryConstructor!!
|
||||
|
||||
val constructors
|
||||
get() = arrayClass.constructors
|
||||
|
||||
@@ -74,7 +74,6 @@ internal class WasmVarargExpressionLowering(
|
||||
|
||||
return func?.owner ?: throw IllegalArgumentException("copyInto is not found for ${arrayType.render()}")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun IrBlockBuilder.irCreateArray(size: IrExpression, arrDescr: ArrayDescr) =
|
||||
@@ -164,16 +163,37 @@ internal class WasmVarargExpressionLowering(
|
||||
this@irSize.irSize()
|
||||
}
|
||||
|
||||
private fun tryVisitWithNoSpread(irVararg: IrVararg, builder: DeclarationIrBuilder): IrExpression {
|
||||
val irVarargType = irVararg.type
|
||||
if (!irVarargType.isUnsignedArray()) return irVararg
|
||||
|
||||
val unsignedConstructor = irVarargType.getClass()!!.primaryConstructor!!
|
||||
val constructorParameterType = unsignedConstructor.valueParameters[0].type
|
||||
val signedElementType = constructorParameterType.getArrayElementType(context.irBuiltIns)
|
||||
|
||||
irVararg.type = constructorParameterType
|
||||
irVararg.varargElementType = signedElementType
|
||||
return builder.irCall(unsignedConstructor.symbol, irVarargType).also {
|
||||
it.putValueArgument(0, irVararg)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitVararg(expression: IrVararg): IrExpression {
|
||||
// Optimization in case if we have a single spread element
|
||||
if (expression.elements.size == 1 && expression.elements.first() is IrSpreadElement) {
|
||||
val spreadExpr = (expression.elements.first() as IrSpreadElement).expression
|
||||
val singleSpreadElement = expression.elements.singleOrNull() as? IrSpreadElement
|
||||
if (singleSpreadElement != null) {
|
||||
val spreadExpr = singleSpreadElement.expression
|
||||
if (isImmediatelyCreatedArray(spreadExpr))
|
||||
return spreadExpr.transform(this, null)
|
||||
}
|
||||
|
||||
// Lower nested varargs
|
||||
val irVararg = super.visitVararg(expression) as IrVararg
|
||||
val builder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol)
|
||||
|
||||
if (irVararg.elements.none { it is IrSpreadElement }) {
|
||||
return tryVisitWithNoSpread(irVararg, builder)
|
||||
}
|
||||
|
||||
// Create temporary variable for each element and emit them all at once to preserve
|
||||
// argument evaluation order as per kotlin language spec.
|
||||
@@ -202,9 +222,7 @@ internal class WasmVarargExpressionLowering(
|
||||
yield(VarargSegmentBuilder.Plain(currentElements.toList(), context))
|
||||
}.toList()
|
||||
|
||||
val builder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol)
|
||||
val destArrayDescr = ArrayDescr(irVararg.type, context)
|
||||
|
||||
return builder.irComposite(irVararg) {
|
||||
// Emit all of the variables first so that all vararg expressions
|
||||
// are evaluated only once and in order of their appearance.
|
||||
|
||||
@@ -17,6 +17,10 @@ import kotlin.wasm.internal.*
|
||||
public class Array<T> constructor(size: Int) {
|
||||
internal val storage: WasmAnyArray = WasmAnyArray(size)
|
||||
|
||||
@Suppress("TYPE_PARAMETER_AS_REIFIED")
|
||||
@WasmPrimitiveConstructor
|
||||
internal constructor(storage: WasmAnyArray) : this(check(false) as Int)
|
||||
|
||||
/**
|
||||
* Creates a new array with the specified [size], where each element is calculated by calling the specified
|
||||
* [init] function.
|
||||
|
||||
@@ -10,6 +10,10 @@ import kotlin.wasm.internal.*
|
||||
public class ByteArray(size: Int) {
|
||||
internal val storage = WasmByteArray(size)
|
||||
|
||||
@Suppress("TYPE_PARAMETER_AS_REIFIED")
|
||||
@WasmPrimitiveConstructor
|
||||
internal constructor(storage: WasmByteArray) : this(check(false) as Int)
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Byte) : this(size) {
|
||||
storage.fill(size, init)
|
||||
}
|
||||
@@ -40,6 +44,10 @@ internal fun byteArrayIterator(array: ByteArray) = object : ByteIterator() {
|
||||
public class CharArray(size: Int) {
|
||||
internal val storage = WasmCharArray(size)
|
||||
|
||||
@Suppress("TYPE_PARAMETER_AS_REIFIED")
|
||||
@WasmPrimitiveConstructor
|
||||
internal constructor(storage: WasmCharArray) : this(check(false) as Int)
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Char) : this(size) {
|
||||
storage.fill(size) { init(it) }
|
||||
}
|
||||
@@ -71,6 +79,10 @@ internal fun charArrayIterator(array: CharArray) = object : CharIterator() {
|
||||
public class ShortArray(size: Int) {
|
||||
internal val storage = WasmShortArray(size)
|
||||
|
||||
@Suppress("TYPE_PARAMETER_AS_REIFIED")
|
||||
@WasmPrimitiveConstructor
|
||||
internal constructor(storage: WasmShortArray) : this(check(false) as Int)
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Short) : this(size) {
|
||||
storage.fill(size, init)
|
||||
}
|
||||
@@ -102,6 +114,10 @@ internal fun shortArrayIterator(array: ShortArray) = object : ShortIterator() {
|
||||
public class IntArray(size: Int) {
|
||||
internal val storage = WasmIntArray(size)
|
||||
|
||||
@Suppress("TYPE_PARAMETER_AS_REIFIED")
|
||||
@WasmPrimitiveConstructor
|
||||
internal constructor(storage: WasmIntArray) : this(check(false) as Int)
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Int) : this(size) {
|
||||
storage.fill(size, init)
|
||||
}
|
||||
@@ -133,6 +149,10 @@ internal fun intArrayIterator(array: IntArray) = object : IntIterator() {
|
||||
public class LongArray(size: Int) {
|
||||
internal val storage = WasmLongArray (size)
|
||||
|
||||
@Suppress("TYPE_PARAMETER_AS_REIFIED")
|
||||
@WasmPrimitiveConstructor
|
||||
internal constructor(storage: WasmLongArray) : this(check(false) as Int)
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Long) : this(size) {
|
||||
storage.fill(size, init)
|
||||
}
|
||||
@@ -163,6 +183,10 @@ internal fun longArrayIterator(array: LongArray) = object : LongIterator() {
|
||||
public class FloatArray(size: Int) {
|
||||
internal val storage = WasmFloatArray(size)
|
||||
|
||||
@Suppress("TYPE_PARAMETER_AS_REIFIED")
|
||||
@WasmPrimitiveConstructor
|
||||
internal constructor(storage: WasmFloatArray) : this(check(false) as Int)
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Float) : this(size) {
|
||||
storage.fill(size, init)
|
||||
}
|
||||
@@ -193,6 +217,10 @@ internal fun floatArrayIterator(array: FloatArray) = object : FloatIterator() {
|
||||
public class DoubleArray(size: Int) {
|
||||
internal val storage = WasmDoubleArray(size)
|
||||
|
||||
@Suppress("TYPE_PARAMETER_AS_REIFIED")
|
||||
@WasmPrimitiveConstructor
|
||||
internal constructor(storage: WasmDoubleArray) : this(check(false) as Int)
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Double) : this(size) {
|
||||
storage.fill(size, init)
|
||||
}
|
||||
@@ -223,6 +251,10 @@ internal fun doubleArrayIterator(array: DoubleArray) = object : DoubleIterator()
|
||||
public class BooleanArray(size: Int) {
|
||||
internal val storage = WasmByteArray(size)
|
||||
|
||||
@Suppress("TYPE_PARAMETER_AS_REIFIED")
|
||||
@WasmPrimitiveConstructor
|
||||
internal constructor(storage: WasmByteArray) : this(check(false) as Int)
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Boolean) : this(size) {
|
||||
storage.fill(size) { init(it).toInt().reinterpretAsByte() }
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ internal fun <To> wasm_ref_test(a: Any?): Boolean =
|
||||
internal fun <T> wasm_array_copy(destination: T, destinationIndex: Int, source: T, sourceIndex: Int, length: Int): Unit =
|
||||
implementedAsIntrinsic
|
||||
|
||||
internal fun <T> array_new_data0(address: Int, length: Int): WasmCharArray =
|
||||
internal fun <T> array_new_data0(address: Int, length: Int): T =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@WasmOp(WasmOp.I32_EQ)
|
||||
|
||||
@@ -253,6 +253,8 @@ internal annotation class WasmOp(val name: String) {
|
||||
const val ARRAY_SET = "ARRAY_SET"
|
||||
const val ARRAY_LEN = "ARRAY_LEN"
|
||||
const val ARRAY_COPY = "ARRAY_COPY"
|
||||
const val ARRAY_NEW_DATA = "ARRAY_NEW_DATA"
|
||||
const val ARRAY_NEW_FIXED = "ARRAY_NEW_FIXED"
|
||||
const val I31_NEW = "I31_NEW"
|
||||
const val I31_GET_S = "I31_GET_S"
|
||||
const val I31_GET_U = "I31_GET_U"
|
||||
|
||||
@@ -29,7 +29,7 @@ class WasmModule(
|
||||
val startFunction: WasmFunction? = null,
|
||||
|
||||
val data: List<WasmData> = emptyList(),
|
||||
val dataCount: Boolean = false,
|
||||
val dataCount: Boolean = true,
|
||||
)
|
||||
|
||||
sealed class WasmNamedModuleField {
|
||||
|
||||
@@ -73,7 +73,10 @@ sealed class WasmImmediate {
|
||||
constructor(value: WasmMemory) : this(WasmSymbol(value))
|
||||
}
|
||||
|
||||
class DataIdx(val value: Int) : WasmImmediate()
|
||||
class DataIdx(val value: WasmSymbol<Int>) : WasmImmediate() {
|
||||
constructor(value: Int) : this(WasmSymbol(value))
|
||||
}
|
||||
|
||||
class TableIdx(val value: WasmSymbolReadOnly<Int>) : WasmImmediate() {
|
||||
constructor(value: Int) : this(WasmSymbol(value))
|
||||
}
|
||||
@@ -356,6 +359,7 @@ enum class WasmOp(
|
||||
ARRAY_LEN("array.len", 0xFB_17, listOf(STRUCT_TYPE_IDX)),
|
||||
ARRAY_COPY("array.copy", 0xFB_18, listOf(STRUCT_TYPE_IDX, STRUCT_TYPE_IDX)),
|
||||
ARRAY_NEW_DATA("array.new_data", 0xFB_1D, listOf(STRUCT_TYPE_IDX, DATA_IDX)),
|
||||
ARRAY_NEW_FIXED("array.new_fixed", 0xFB_1A, listOf(STRUCT_TYPE_IDX, CONST_I32)),
|
||||
|
||||
I31_NEW("i31.new", 0xFB_20),
|
||||
I31_GET_S("i31.get_s", 0xFB_21),
|
||||
|
||||
@@ -32,7 +32,7 @@ class WasmBinaryToIR(val b: MyByteReader) {
|
||||
var startFunction: WasmFunction? = null
|
||||
val elements: MutableList<WasmElement> = mutableListOf()
|
||||
val data: MutableList<WasmData> = mutableListOf()
|
||||
var dataCount: Boolean = false
|
||||
var dataCount: Boolean = true
|
||||
val tags: MutableList<WasmTag> = mutableListOf()
|
||||
|
||||
private fun <T> byIdx(l1: List<T>, l2: List<T>, index: Int): T {
|
||||
|
||||
@@ -114,10 +114,6 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule, val mod
|
||||
data.forEach { appendData(it) }
|
||||
}
|
||||
|
||||
appendSection(12u) {
|
||||
b.writeVarUInt32(data.size)
|
||||
}
|
||||
|
||||
//text section (should be placed after data)
|
||||
if (emitNameSection) {
|
||||
appendTextSection(definedFunctions)
|
||||
@@ -217,7 +213,7 @@ class WasmIrToBinary(outputStream: OutputStream, val module: WasmModule, val mod
|
||||
is WasmImmediate.GlobalIdx -> appendModuleFieldReference(x.value.owner)
|
||||
is WasmImmediate.TypeIdx -> appendModuleFieldReference(x.value.owner)
|
||||
is WasmImmediate.MemoryIdx -> appendModuleFieldReference(x.value.owner)
|
||||
is WasmImmediate.DataIdx -> b.writeVarUInt32(x.value)
|
||||
is WasmImmediate.DataIdx -> b.writeVarUInt32(x.value.owner)
|
||||
is WasmImmediate.TableIdx -> b.writeVarUInt32(x.value.owner)
|
||||
is WasmImmediate.LabelIdx -> b.writeVarUInt32(x.value)
|
||||
is WasmImmediate.TagIdx -> b.writeVarUInt32(x.value)
|
||||
|
||||
Reference in New Issue
Block a user