[WASM] Add array copy intrinsic

This commit is contained in:
Igor Yakovlev
2022-06-29 18:51:31 +02:00
committed by teamcity
parent 8306b1bd71
commit 0ea7e8b70a
17 changed files with 218 additions and 203 deletions
@@ -157,6 +157,7 @@ class WasmSymbols(
val refIsNull = getInternalFunction("wasm_ref_is_null") val refIsNull = getInternalFunction("wasm_ref_is_null")
val refTest = getInternalFunction("wasm_ref_test") val refTest = getInternalFunction("wasm_ref_test")
val refCast = getInternalFunction("wasm_ref_cast") val refCast = getInternalFunction("wasm_ref_cast")
val wasmArrayCopy = getInternalFunction("wasm_array_copy")
val intToLong = getInternalFunction("wasm_i64_extend_i32_s") val intToLong = getInternalFunction("wasm_i64_extend_i32_s")
@@ -48,7 +48,8 @@ internal class WasmUsefulDeclarationProcessor(
context.wasmSymbols.wasmInterfaceId, context.wasmSymbols.wasmInterfaceId,
context.wasmSymbols.refCast, context.wasmSymbols.refCast,
context.wasmSymbols.refTest, context.wasmSymbols.refTest,
context.wasmSymbols.boxIntrinsic -> { context.wasmSymbols.boxIntrinsic,
context.wasmSymbols.wasmArrayCopy -> {
call.getTypeArgument(0)?.enqueueRuntimeClassOrAny(from, "intrinsic ${call.symbol.owner.name}") call.getTypeArgument(0)?.enqueueRuntimeClassOrAny(from, "intrinsic ${call.symbol.owner.name}")
true true
} }
@@ -475,6 +475,13 @@ class BodyGenerator(
body.buildConstI32Symbol(WasmSymbol(context.scratchMemSizeInBytes)) body.buildConstI32Symbol(WasmSymbol(context.scratchMemSizeInBytes))
} }
wasmSymbols.wasmArrayCopy -> {
val immediate = WasmImmediate.GcType(
context.referenceGcType(call.getTypeArgument(0)!!.getRuntimeClass(irBuiltIns).symbol)
)
body.buildInstr(WasmOp.ARRAY_COPY, immediate, immediate)
}
else -> { else -> {
return false return false
} }
+6 -3
View File
@@ -104,7 +104,11 @@ fun wasmArrayForType(
@WasmOp(WasmOp.ARRAY_LEN) @WasmOp(WasmOp.ARRAY_LEN)
fun len(): Int = fun len(): Int =
implementedAsIntrinsic implementedAsIntrinsic
}
internal inline fun $name.copyTo(destination: $name, sourceIndex: Int, destinationIndex: Int, length: Int) {
wasm_array_copy<$name>(destination, destinationIndex, this, sourceIndex, length)
} }
internal inline fun $name.fill(size: Int, init: (Int) -> $type) { internal inline fun $name.fill(size: Int, init: (Int) -> $type) {
@@ -113,8 +117,7 @@ fun wasmArrayForType(
set(i, init(i)) set(i, init(i))
i++ i++
} }
} }
""".trimIndent() """.trimIndent()
} }
@@ -15,7 +15,7 @@ import kotlin.wasm.internal.*
* for more information on arrays. * for more information on arrays.
*/ */
public class Array<T> constructor(size: Int) { public class Array<T> constructor(size: Int) {
private var storage: WasmAnyArray = WasmAnyArray(size) internal val storage: WasmAnyArray = WasmAnyArray(size)
/** /**
* Creates a new array with the specified [size], where each element is calculated by calling the specified * Creates a new array with the specified [size], where each element is calculated by calling the specified
@@ -8,7 +8,7 @@ package kotlin
import kotlin.wasm.internal.* import kotlin.wasm.internal.*
public class ByteArray(size: Int) { public class ByteArray(size: Int) {
private var storage = WasmByteArray(size) internal val storage = WasmByteArray(size)
public constructor(size: Int, init: (Int) -> Byte) : this(size) { public constructor(size: Int, init: (Int) -> Byte) : this(size) {
storage.fill(size, init) storage.fill(size, init)
@@ -38,7 +38,7 @@ internal fun byteArrayIterator(array: ByteArray) = object : ByteIterator() {
public class CharArray(size: Int) { public class CharArray(size: Int) {
private var storage = WasmCharArray(size) internal val 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) } storage.fill(size) { init(it) }
@@ -69,7 +69,7 @@ internal fun charArrayIterator(array: CharArray) = object : CharIterator() {
public class ShortArray(size: Int) { public class ShortArray(size: Int) {
private var storage = WasmShortArray(size) internal val storage = WasmShortArray(size)
public constructor(size: Int, init: (Int) -> Short) : this(size) { public constructor(size: Int, init: (Int) -> Short) : this(size) {
storage.fill(size, init) storage.fill(size, init)
@@ -100,7 +100,7 @@ internal fun shortArrayIterator(array: ShortArray) = object : ShortIterator() {
public class IntArray(size: Int) { public class IntArray(size: Int) {
private var storage = WasmIntArray(size) internal val storage = WasmIntArray(size)
public constructor(size: Int, init: (Int) -> Int) : this(size) { public constructor(size: Int, init: (Int) -> Int) : this(size) {
storage.fill(size, init) storage.fill(size, init)
@@ -131,7 +131,7 @@ internal fun intArrayIterator(array: IntArray) = object : IntIterator() {
public class LongArray(size: Int) { public class LongArray(size: Int) {
private var storage = WasmLongArray (size) internal val storage = WasmLongArray (size)
public constructor(size: Int, init: (Int) -> Long) : this(size) { public constructor(size: Int, init: (Int) -> Long) : this(size) {
storage.fill(size, init) storage.fill(size, init)
@@ -161,7 +161,7 @@ internal fun longArrayIterator(array: LongArray) = object : LongIterator() {
public class FloatArray(size: Int) { public class FloatArray(size: Int) {
private var storage = WasmFloatArray(size) internal val storage = WasmFloatArray(size)
public constructor(size: Int, init: (Int) -> Float) : this(size) { public constructor(size: Int, init: (Int) -> Float) : this(size) {
storage.fill(size, init) storage.fill(size, init)
@@ -191,7 +191,7 @@ internal fun floatArrayIterator(array: FloatArray) = object : FloatIterator() {
public class DoubleArray(size: Int) { public class DoubleArray(size: Int) {
private var storage = WasmDoubleArray(size) internal val storage = WasmDoubleArray(size)
public constructor(size: Int, init: (Int) -> Double) : this(size) { public constructor(size: Int, init: (Int) -> Double) : this(size) {
storage.fill(size, init) storage.fill(size, init)
@@ -221,7 +221,7 @@ internal fun doubleArrayIterator(array: DoubleArray) = object : DoubleIterator()
public class BooleanArray(size: Int) { public class BooleanArray(size: Int) {
private var storage = WasmByteArray(size) internal val 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(it).toInt().reinterpretAsByte() } storage.fill(size) { init(it).toInt().reinterpretAsByte() }
+29 -20
View File
@@ -22,12 +22,15 @@ public class String private constructor(internal val chars: WasmCharArray) : Com
* Returns a string obtained by concatenating this string with the string representation of the given [other] object. * Returns a string obtained by concatenating this string with the string representation of the given [other] object.
*/ */
public operator fun plus(other: Any?): String { public operator fun plus(other: Any?): String {
val thisChars = chars
val otherChars = if (other is String) other.chars else other.toString().chars val otherChars = if (other is String) other.chars else other.toString().chars
val newCharsLen = chars.len() + otherChars.len() val thisLen = thisChars.len()
val newChars = WasmCharArray(newCharsLen) val otherLen = otherChars.len()
newChars.fill(newCharsLen) { i -> if (otherLen == 0) return String(thisChars)
if (i < chars.len()) chars.get(i) else otherChars.get(i - chars.len())
} val newChars = WasmCharArray(thisLen + otherLen)
thisChars.copyTo(newChars, 0, 0, thisLen)
otherChars.copyTo(newChars, 0, thisLen, otherLen)
return String(newChars) return String(newChars)
} }
@@ -47,42 +50,48 @@ public class String private constructor(internal val chars: WasmCharArray) : Com
public override fun subSequence(startIndex: Int, endIndex: Int): CharSequence { public override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
val actualStartIndex = startIndex.coerceAtLeast(0) val actualStartIndex = startIndex.coerceAtLeast(0)
val actualEndIndex = endIndex.coerceAtMost(chars.len()) val thisChars = chars
val actualEndIndex = endIndex.coerceAtMost(thisChars.len())
val newCharsLen = actualEndIndex - actualStartIndex val newCharsLen = actualEndIndex - actualStartIndex
val newChars = WasmCharArray(newCharsLen) val newChars = WasmCharArray(newCharsLen)
newChars.fill(newCharsLen) { i -> thisChars.copyTo(newChars, actualStartIndex, 0, newCharsLen)
chars.get(actualStartIndex + i)
}
return String(newChars) return String(newChars)
} }
public override fun compareTo(other: String): Int { public override fun compareTo(other: String): Int {
val len = min(this.length, other.length) val thisChars = this.chars
val otherChars = other.chars
val thisLength = thisChars.len()
val otherLength = otherChars.len()
val len = min(thisLength, otherLength)
for (i in 0 until len) { for (i in 0 until len) {
val l = this[i] val l = thisChars.get(i)
val r = other[i] val r = otherChars.get(i)
if (l != r) if (l != r)
return l - r return l - r
} }
return this.length - other.length return thisLength - otherLength
} }
public override fun equals(other: Any?): Boolean { public override fun equals(other: Any?): Boolean =
if (other is String) other != null &&
return this.compareTo(other) == 0 other is String &&
return false (this.length == other.length) &&
} this.compareTo(other) == 0
public override fun toString(): String = this public override fun toString(): String = this
public override fun hashCode(): Int { public override fun hashCode(): Int {
if (_hashCode != 0 || this.isEmpty()) val thisLength = length
if (_hashCode != 0 || thisLength == null)
return _hashCode return _hashCode
var hash = 0 var hash = 0
var i = 0 var i = 0
while (i < chars.len()) { while (i < thisLength) {
hash = 31 * hash + chars.get(i).toInt() hash = 31 * hash + chars.get(i).toInt()
i++ i++
} }
@@ -24,6 +24,9 @@ internal fun <To> wasm_ref_cast(a: Any?): To =
internal fun <To> wasm_ref_test(a: Any?): Boolean = internal fun <To> wasm_ref_test(a: Any?): Boolean =
implementedAsIntrinsic implementedAsIntrinsic
internal fun <T> wasm_array_copy(destination: T, destinationIndex: Int, source: T, sourceIndex: Int, length: Int): Unit =
implementedAsIntrinsic
@WasmOp(WasmOp.I32_EQ) @WasmOp(WasmOp.I32_EQ)
public external fun wasm_i32_eq(a: Int, b: Int): Boolean public external fun wasm_i32_eq(a: Int, b: Int): Boolean
@@ -1017,18 +1017,8 @@ public actual fun CharArray?.contentToString(): String {
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun <T> Array<out T>.copyInto(destination: Array<T>, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): Array<T> { public actual fun <T> Array<out T>.copyInto(destination: Array<T>, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): Array<T> {
AbstractList.checkRangeIndexes(startIndex, endIndex, this.size) @Suppress("UNCHECKED_CAST")
val rangeSize = endIndex - startIndex arrayCopy(this as Array<Any?>, startIndex, destination as Array<Any?>, destinationOffset, endIndex - startIndex)
AbstractList.checkRangeIndexes(destinationOffset, destinationOffset + rangeSize, destination.size)
if (this !== destination || destinationOffset <= startIndex) {
for (index in 0 until rangeSize) {
destination[destinationOffset + index] = this[startIndex + index]
}
} else {
for (index in rangeSize - 1 downTo 0) {
destination[destinationOffset + index] = this[startIndex + index]
}
}
return destination return destination
} }
@@ -1051,18 +1041,7 @@ public actual fun <T> Array<out T>.copyInto(destination: Array<T>, destinationOf
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun ByteArray.copyInto(destination: ByteArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): ByteArray { public actual fun ByteArray.copyInto(destination: ByteArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): ByteArray {
AbstractList.checkRangeIndexes(startIndex, endIndex, this.size) arrayCopy(this, startIndex, destination, destinationOffset, endIndex - startIndex)
val rangeSize = endIndex - startIndex
AbstractList.checkRangeIndexes(destinationOffset, destinationOffset + rangeSize, destination.size)
if (this !== destination || destinationOffset <= startIndex) {
for (index in 0 until rangeSize) {
destination[destinationOffset + index] = this[startIndex + index]
}
} else {
for (index in rangeSize - 1 downTo 0) {
destination[destinationOffset + index] = this[startIndex + index]
}
}
return destination return destination
} }
@@ -1085,18 +1064,7 @@ public actual fun ByteArray.copyInto(destination: ByteArray, destinationOffset:
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun ShortArray.copyInto(destination: ShortArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): ShortArray { public actual fun ShortArray.copyInto(destination: ShortArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): ShortArray {
AbstractList.checkRangeIndexes(startIndex, endIndex, this.size) arrayCopy(this, startIndex, destination, destinationOffset, endIndex - startIndex)
val rangeSize = endIndex - startIndex
AbstractList.checkRangeIndexes(destinationOffset, destinationOffset + rangeSize, destination.size)
if (this !== destination || destinationOffset <= startIndex) {
for (index in 0 until rangeSize) {
destination[destinationOffset + index] = this[startIndex + index]
}
} else {
for (index in rangeSize - 1 downTo 0) {
destination[destinationOffset + index] = this[startIndex + index]
}
}
return destination return destination
} }
@@ -1119,18 +1087,7 @@ public actual fun ShortArray.copyInto(destination: ShortArray, destinationOffset
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun IntArray.copyInto(destination: IntArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): IntArray { public actual fun IntArray.copyInto(destination: IntArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): IntArray {
AbstractList.checkRangeIndexes(startIndex, endIndex, this.size) arrayCopy(this, startIndex, destination, destinationOffset, endIndex - startIndex)
val rangeSize = endIndex - startIndex
AbstractList.checkRangeIndexes(destinationOffset, destinationOffset + rangeSize, destination.size)
if (this !== destination || destinationOffset <= startIndex) {
for (index in 0 until rangeSize) {
destination[destinationOffset + index] = this[startIndex + index]
}
} else {
for (index in rangeSize - 1 downTo 0) {
destination[destinationOffset + index] = this[startIndex + index]
}
}
return destination return destination
} }
@@ -1153,18 +1110,7 @@ public actual fun IntArray.copyInto(destination: IntArray, destinationOffset: In
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun LongArray.copyInto(destination: LongArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): LongArray { public actual fun LongArray.copyInto(destination: LongArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): LongArray {
AbstractList.checkRangeIndexes(startIndex, endIndex, this.size) arrayCopy(this, startIndex, destination, destinationOffset, endIndex - startIndex)
val rangeSize = endIndex - startIndex
AbstractList.checkRangeIndexes(destinationOffset, destinationOffset + rangeSize, destination.size)
if (this !== destination || destinationOffset <= startIndex) {
for (index in 0 until rangeSize) {
destination[destinationOffset + index] = this[startIndex + index]
}
} else {
for (index in rangeSize - 1 downTo 0) {
destination[destinationOffset + index] = this[startIndex + index]
}
}
return destination return destination
} }
@@ -1187,18 +1133,7 @@ public actual fun LongArray.copyInto(destination: LongArray, destinationOffset:
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun FloatArray.copyInto(destination: FloatArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): FloatArray { public actual fun FloatArray.copyInto(destination: FloatArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): FloatArray {
AbstractList.checkRangeIndexes(startIndex, endIndex, this.size) arrayCopy(this, startIndex, destination, destinationOffset, endIndex - startIndex)
val rangeSize = endIndex - startIndex
AbstractList.checkRangeIndexes(destinationOffset, destinationOffset + rangeSize, destination.size)
if (this !== destination || destinationOffset <= startIndex) {
for (index in 0 until rangeSize) {
destination[destinationOffset + index] = this[startIndex + index]
}
} else {
for (index in rangeSize - 1 downTo 0) {
destination[destinationOffset + index] = this[startIndex + index]
}
}
return destination return destination
} }
@@ -1221,18 +1156,7 @@ public actual fun FloatArray.copyInto(destination: FloatArray, destinationOffset
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun DoubleArray.copyInto(destination: DoubleArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): DoubleArray { public actual fun DoubleArray.copyInto(destination: DoubleArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): DoubleArray {
AbstractList.checkRangeIndexes(startIndex, endIndex, this.size) arrayCopy(this, startIndex, destination, destinationOffset, endIndex - startIndex)
val rangeSize = endIndex - startIndex
AbstractList.checkRangeIndexes(destinationOffset, destinationOffset + rangeSize, destination.size)
if (this !== destination || destinationOffset <= startIndex) {
for (index in 0 until rangeSize) {
destination[destinationOffset + index] = this[startIndex + index]
}
} else {
for (index in rangeSize - 1 downTo 0) {
destination[destinationOffset + index] = this[startIndex + index]
}
}
return destination return destination
} }
@@ -1255,18 +1179,7 @@ public actual fun DoubleArray.copyInto(destination: DoubleArray, destinationOffs
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun BooleanArray.copyInto(destination: BooleanArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): BooleanArray { public actual fun BooleanArray.copyInto(destination: BooleanArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): BooleanArray {
AbstractList.checkRangeIndexes(startIndex, endIndex, this.size) arrayCopy(this, startIndex, destination, destinationOffset, endIndex - startIndex)
val rangeSize = endIndex - startIndex
AbstractList.checkRangeIndexes(destinationOffset, destinationOffset + rangeSize, destination.size)
if (this !== destination || destinationOffset <= startIndex) {
for (index in 0 until rangeSize) {
destination[destinationOffset + index] = this[startIndex + index]
}
} else {
for (index in rangeSize - 1 downTo 0) {
destination[destinationOffset + index] = this[startIndex + index]
}
}
return destination return destination
} }
@@ -1289,18 +1202,7 @@ public actual fun BooleanArray.copyInto(destination: BooleanArray, destinationOf
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun CharArray.copyInto(destination: CharArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): CharArray { public actual fun CharArray.copyInto(destination: CharArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): CharArray {
AbstractList.checkRangeIndexes(startIndex, endIndex, this.size) arrayCopy(this, startIndex, destination, destinationOffset, endIndex - startIndex)
val rangeSize = endIndex - startIndex
AbstractList.checkRangeIndexes(destinationOffset, destinationOffset + rangeSize, destination.size)
if (this !== destination || destinationOffset <= startIndex) {
for (index in 0 until rangeSize) {
destination[destinationOffset + index] = this[startIndex + index]
}
} else {
for (index in rangeSize - 1 downTo 0) {
destination[destinationOffset + index] = this[startIndex + index]
}
}
return destination return destination
} }
@@ -32,7 +32,11 @@ internal class WasmAnyArray(size: Int) {
@WasmOp(WasmOp.ARRAY_LEN) @WasmOp(WasmOp.ARRAY_LEN)
fun len(): Int = fun len(): Int =
implementedAsIntrinsic implementedAsIntrinsic
}
internal inline fun WasmAnyArray.copyTo(destination: WasmAnyArray, sourceIndex: Int, destinationIndex: Int, length: Int) {
wasm_array_copy<WasmAnyArray>(destination, destinationIndex, this, sourceIndex, length)
} }
internal inline fun WasmAnyArray.fill(size: Int, init: (Int) -> Any?) { internal inline fun WasmAnyArray.fill(size: Int, init: (Int) -> Any?) {
@@ -41,8 +45,7 @@ internal inline fun WasmAnyArray.fill(size: Int, init: (Int) -> Any?) {
set(i, init(i)) set(i, init(i))
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_S) @WasmOp(WasmOp.ARRAY_GET_S)
@@ -55,7 +58,11 @@ internal class WasmByteArray(size: Int) {
@WasmOp(WasmOp.ARRAY_LEN) @WasmOp(WasmOp.ARRAY_LEN)
fun len(): Int = fun len(): Int =
implementedAsIntrinsic implementedAsIntrinsic
}
internal inline fun WasmByteArray.copyTo(destination: WasmByteArray, sourceIndex: Int, destinationIndex: Int, length: Int) {
wasm_array_copy<WasmByteArray>(destination, destinationIndex, this, sourceIndex, length)
} }
internal inline fun WasmByteArray.fill(size: Int, init: (Int) -> Byte) { internal inline fun WasmByteArray.fill(size: Int, init: (Int) -> Byte) {
@@ -64,8 +71,7 @@ internal inline fun WasmByteArray.fill(size: Int, init: (Int) -> Byte) {
set(i, init(i)) set(i, init(i))
i++ i++
} }
} }
@WasmArrayOf(Char::class, isNullable = false) @WasmArrayOf(Char::class, isNullable = false)
internal class WasmCharArray(size: Int) { internal class WasmCharArray(size: Int) {
@WasmOp(WasmOp.ARRAY_GET_U) @WasmOp(WasmOp.ARRAY_GET_U)
@@ -78,7 +84,11 @@ internal class WasmCharArray(size: Int) {
@WasmOp(WasmOp.ARRAY_LEN) @WasmOp(WasmOp.ARRAY_LEN)
fun len(): Int = fun len(): Int =
implementedAsIntrinsic implementedAsIntrinsic
}
internal inline fun WasmCharArray.copyTo(destination: WasmCharArray, sourceIndex: Int, destinationIndex: Int, length: Int) {
wasm_array_copy<WasmCharArray>(destination, destinationIndex, this, sourceIndex, length)
} }
internal inline fun WasmCharArray.fill(size: Int, init: (Int) -> Char) { internal inline fun WasmCharArray.fill(size: Int, init: (Int) -> Char) {
@@ -87,8 +97,7 @@ internal inline fun WasmCharArray.fill(size: Int, init: (Int) -> Char) {
set(i, init(i)) set(i, init(i))
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_S) @WasmOp(WasmOp.ARRAY_GET_S)
@@ -101,7 +110,11 @@ internal class WasmShortArray(size: Int) {
@WasmOp(WasmOp.ARRAY_LEN) @WasmOp(WasmOp.ARRAY_LEN)
fun len(): Int = fun len(): Int =
implementedAsIntrinsic implementedAsIntrinsic
}
internal inline fun WasmShortArray.copyTo(destination: WasmShortArray, sourceIndex: Int, destinationIndex: Int, length: Int) {
wasm_array_copy<WasmShortArray>(destination, destinationIndex, this, sourceIndex, length)
} }
internal inline fun WasmShortArray.fill(size: Int, init: (Int) -> Short) { internal inline fun WasmShortArray.fill(size: Int, init: (Int) -> Short) {
@@ -110,8 +123,7 @@ internal inline fun WasmShortArray.fill(size: Int, init: (Int) -> Short) {
set(i, init(i)) set(i, init(i))
i++ i++
} }
} }
@WasmArrayOf(Int::class, isNullable = false) @WasmArrayOf(Int::class, isNullable = false)
internal class WasmIntArray(size: Int) { internal class WasmIntArray(size: Int) {
@WasmOp(WasmOp.ARRAY_GET) @WasmOp(WasmOp.ARRAY_GET)
@@ -124,7 +136,11 @@ internal class WasmIntArray(size: Int) {
@WasmOp(WasmOp.ARRAY_LEN) @WasmOp(WasmOp.ARRAY_LEN)
fun len(): Int = fun len(): Int =
implementedAsIntrinsic implementedAsIntrinsic
}
internal inline fun WasmIntArray.copyTo(destination: WasmIntArray, sourceIndex: Int, destinationIndex: Int, length: Int) {
wasm_array_copy<WasmIntArray>(destination, destinationIndex, this, sourceIndex, length)
} }
internal inline fun WasmIntArray.fill(size: Int, init: (Int) -> Int) { internal inline fun WasmIntArray.fill(size: Int, init: (Int) -> Int) {
@@ -133,8 +149,7 @@ internal inline fun WasmIntArray.fill(size: Int, init: (Int) -> Int) {
set(i, init(i)) set(i, init(i))
i++ i++
} }
} }
@WasmArrayOf(Long::class, isNullable = false) @WasmArrayOf(Long::class, isNullable = false)
internal class WasmLongArray(size: Int) { internal class WasmLongArray(size: Int) {
@WasmOp(WasmOp.ARRAY_GET) @WasmOp(WasmOp.ARRAY_GET)
@@ -147,7 +162,11 @@ internal class WasmLongArray(size: Int) {
@WasmOp(WasmOp.ARRAY_LEN) @WasmOp(WasmOp.ARRAY_LEN)
fun len(): Int = fun len(): Int =
implementedAsIntrinsic implementedAsIntrinsic
}
internal inline fun WasmLongArray.copyTo(destination: WasmLongArray, sourceIndex: Int, destinationIndex: Int, length: Int) {
wasm_array_copy<WasmLongArray>(destination, destinationIndex, this, sourceIndex, length)
} }
internal inline fun WasmLongArray.fill(size: Int, init: (Int) -> Long) { internal inline fun WasmLongArray.fill(size: Int, init: (Int) -> Long) {
@@ -156,8 +175,7 @@ internal inline fun WasmLongArray.fill(size: Int, init: (Int) -> Long) {
set(i, init(i)) set(i, init(i))
i++ i++
} }
} }
@WasmArrayOf(Float::class, isNullable = false) @WasmArrayOf(Float::class, isNullable = false)
internal class WasmFloatArray(size: Int) { internal class WasmFloatArray(size: Int) {
@WasmOp(WasmOp.ARRAY_GET) @WasmOp(WasmOp.ARRAY_GET)
@@ -170,7 +188,11 @@ internal class WasmFloatArray(size: Int) {
@WasmOp(WasmOp.ARRAY_LEN) @WasmOp(WasmOp.ARRAY_LEN)
fun len(): Int = fun len(): Int =
implementedAsIntrinsic implementedAsIntrinsic
}
internal inline fun WasmFloatArray.copyTo(destination: WasmFloatArray, sourceIndex: Int, destinationIndex: Int, length: Int) {
wasm_array_copy<WasmFloatArray>(destination, destinationIndex, this, sourceIndex, length)
} }
internal inline fun WasmFloatArray.fill(size: Int, init: (Int) -> Float) { internal inline fun WasmFloatArray.fill(size: Int, init: (Int) -> Float) {
@@ -179,8 +201,7 @@ internal inline fun WasmFloatArray.fill(size: Int, init: (Int) -> Float) {
set(i, init(i)) set(i, init(i))
i++ i++
} }
} }
@WasmArrayOf(Double::class, isNullable = false) @WasmArrayOf(Double::class, isNullable = false)
internal class WasmDoubleArray(size: Int) { internal class WasmDoubleArray(size: Int) {
@WasmOp(WasmOp.ARRAY_GET) @WasmOp(WasmOp.ARRAY_GET)
@@ -193,7 +214,11 @@ internal class WasmDoubleArray(size: Int) {
@WasmOp(WasmOp.ARRAY_LEN) @WasmOp(WasmOp.ARRAY_LEN)
fun len(): Int = fun len(): Int =
implementedAsIntrinsic implementedAsIntrinsic
}
internal inline fun WasmDoubleArray.copyTo(destination: WasmDoubleArray, sourceIndex: Int, destinationIndex: Int, length: Int) {
wasm_array_copy<WasmDoubleArray>(destination, destinationIndex, this, sourceIndex, length)
} }
internal inline fun WasmDoubleArray.fill(size: Int, init: (Int) -> Double) { internal inline fun WasmDoubleArray.fill(size: Int, init: (Int) -> Double) {
@@ -202,5 +227,4 @@ internal inline fun WasmDoubleArray.fill(size: Int, init: (Int) -> Double) {
set(i, init(i)) set(i, init(i))
i++ i++
} }
} }
@@ -252,6 +252,7 @@ internal annotation class WasmOp(val name: String) {
const val ARRAY_GET_U = "ARRAY_GET_U" const val ARRAY_GET_U = "ARRAY_GET_U"
const val ARRAY_SET = "ARRAY_SET" const val ARRAY_SET = "ARRAY_SET"
const val ARRAY_LEN = "ARRAY_LEN" const val ARRAY_LEN = "ARRAY_LEN"
const val ARRAY_COPY = "ARRAY_COPY"
const val I31_NEW = "I31_NEW" const val I31_NEW = "I31_NEW"
const val I31_GET_S = "I31_GET_S" const val I31_GET_S = "I31_GET_S"
const val I31_GET_U = "I31_GET_U" const val I31_GET_U = "I31_GET_U"
@@ -5,6 +5,84 @@
package kotlin.collections package kotlin.collections
import kotlin.wasm.internal.copyTo
private inline fun rangeCheck(index: Int, count: Int, arraySize: Int) {
if (index < 0 || count < 0 || index + count > arraySize) throw IndexOutOfBoundsException()
}
internal inline fun arrayCopy(array: ByteArray, fromIndex: Int, destination: ByteArray, toIndex: Int, count: Int) {
val srcStorage = array.storage
rangeCheck(fromIndex, count, srcStorage.len())
val dstStorage = destination.storage
rangeCheck(toIndex, count, dstStorage.len())
srcStorage.copyTo(dstStorage, fromIndex, toIndex, count)
}
internal inline fun arrayCopy(array: ShortArray, fromIndex: Int, destination: ShortArray, toIndex: Int, count: Int) {
val srcStorage = array.storage
rangeCheck(fromIndex, count, srcStorage.len())
val dstStorage = destination.storage
rangeCheck(toIndex, count, dstStorage.len())
srcStorage.copyTo(dstStorage, fromIndex, toIndex, count)
}
internal inline fun arrayCopy(array: CharArray, fromIndex: Int, destination: CharArray, toIndex: Int, count: Int) {
val srcStorage = array.storage
rangeCheck(fromIndex, count, srcStorage.len())
val dstStorage = destination.storage
rangeCheck(toIndex, count, dstStorage.len())
srcStorage.copyTo(dstStorage, fromIndex, toIndex, count)
}
internal inline fun arrayCopy(array: IntArray, fromIndex: Int, destination: IntArray, toIndex: Int, count: Int) {
val srcStorage = array.storage
rangeCheck(fromIndex, count, srcStorage.len())
val dstStorage = destination.storage
rangeCheck(toIndex, count, dstStorage.len())
srcStorage.copyTo(dstStorage, fromIndex, toIndex, count)
}
internal inline fun arrayCopy(array: LongArray, fromIndex: Int, destination: LongArray, toIndex: Int, count: Int) {
val srcStorage = array.storage
rangeCheck(fromIndex, count, srcStorage.len())
val dstStorage = destination.storage
rangeCheck(toIndex, count, dstStorage.len())
srcStorage.copyTo(dstStorage, fromIndex, toIndex, count)
}
internal inline fun arrayCopy(array: FloatArray, fromIndex: Int, destination: FloatArray, toIndex: Int, count: Int) {
val srcStorage = array.storage
rangeCheck(fromIndex, count, srcStorage.len())
val dstStorage = destination.storage
rangeCheck(toIndex, count, dstStorage.len())
srcStorage.copyTo(dstStorage, fromIndex, toIndex, count)
}
internal inline fun arrayCopy(array: DoubleArray, fromIndex: Int, destination: DoubleArray, toIndex: Int, count: Int) {
val srcStorage = array.storage
rangeCheck(fromIndex, count, srcStorage.len())
val dstStorage = destination.storage
rangeCheck(toIndex, count, dstStorage.len())
srcStorage.copyTo(dstStorage, fromIndex, toIndex, count)
}
internal inline fun arrayCopy(array: BooleanArray, fromIndex: Int, destination: BooleanArray, toIndex: Int, count: Int) {
val srcStorage = array.storage
rangeCheck(fromIndex, count, srcStorage.len())
val dstStorage = destination.storage
rangeCheck(toIndex, count, dstStorage.len())
srcStorage.copyTo(dstStorage, fromIndex, toIndex, count)
}
internal inline fun arrayCopy(array: Array<Any?>, fromIndex: Int, destination: Array<Any?>, toIndex: Int, count: Int) {
val srcStorage = array.storage
rangeCheck(fromIndex, count, srcStorage.len())
val dstStorage = destination.storage
rangeCheck(toIndex, count, dstStorage.len())
srcStorage.copyTo(dstStorage, fromIndex, toIndex, count)
}
/** /**
* Returns a *typed* array containing all of the elements of this collection. * Returns a *typed* array containing all of the elements of this collection.
* *
@@ -7,18 +7,14 @@ package kotlin.text
import kotlin.wasm.internal.* import kotlin.wasm.internal.*
internal fun insertString(array: CharArray, distIndex: Int, value: String, sourceIndex: Int, count: Int): Int { internal fun insertString(array: CharArray, destinationIndex: Int, value: String, sourceIndex: Int, count: Int): Int {
var arrayIdx = distIndex value.chars.copyTo(array.storage, sourceIndex, destinationIndex, count)
var stringIdx = sourceIndex
repeat(count) {
array[arrayIdx++] = value[stringIdx++]
}
return count return count
} }
internal fun unsafeStringFromCharArray(array: CharArray, start: Int, size: Int): String { internal fun unsafeStringFromCharArray(array: CharArray, start: Int, size: Int): String {
val copy = WasmCharArray(size) val copy = WasmCharArray(size)
copy.fill(size) { array[it + start] } array.storage.copyTo(copy, start, 0, size)
return String.unsafeFromCharArray(copy) return String.unsafeFromCharArray(copy)
} }
@@ -74,7 +74,7 @@ public actual fun String(chars: CharArray, offset: Int, length: Int): String {
throw IndexOutOfBoundsException() throw IndexOutOfBoundsException()
val copy = WasmCharArray(length) val copy = WasmCharArray(length)
copy.fill(length) { chars[it + offset] } chars.storage.copyTo(copy, offset, 0, length)
return String.unsafeFromCharArray(copy) return String.unsafeFromCharArray(copy)
} }
@@ -84,8 +84,10 @@ public actual fun String(chars: CharArray, offset: Int, length: Int): String {
@SinceKotlin("1.4") @SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class) @WasExperimental(ExperimentalStdlibApi::class)
public actual fun CharArray.concatToString(): String { public actual fun CharArray.concatToString(): String {
val copy = WasmCharArray(this.size) val thisStorage = this.storage
copy.fill(this.size) { this[it] } val thisLength = thisStorage.len()
val copy = WasmCharArray(thisLength)
this.storage.copyTo(copy, 0, 0, thisLength)
return String.unsafeFromCharArray(copy) return String.unsafeFromCharArray(copy)
} }
@@ -106,7 +108,7 @@ public actual fun CharArray.concatToString(startIndex: Int = 0, endIndex: Int =
val length = endIndex - startIndex val length = endIndex - startIndex
val copy = WasmCharArray(length) val copy = WasmCharArray(length)
copy.fill(length) { this[it + startIndex] } this.storage.copyTo(copy, startIndex, 0, length)
return String.unsafeFromCharArray(copy) return String.unsafeFromCharArray(copy)
} }
@@ -116,7 +118,11 @@ public actual fun CharArray.concatToString(startIndex: Int = 0, endIndex: Int =
@SinceKotlin("1.4") @SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class) @WasExperimental(ExperimentalStdlibApi::class)
public actual fun String.toCharArray(): CharArray { public actual fun String.toCharArray(): CharArray {
return CharArray(length) { get(it) } val thisChars = this.chars
val thisLength = thisChars.len()
val newArray = CharArray(thisLength)
thisChars.copyTo(newArray.storage, 0, 0, thisLength)
return newArray
} }
/** /**
@@ -133,7 +139,10 @@ public actual fun String.toCharArray(): CharArray {
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun String.toCharArray(startIndex: Int = 0, endIndex: Int = this.length): CharArray { public actual fun String.toCharArray(startIndex: Int = 0, endIndex: Int = this.length): CharArray {
AbstractList.checkBoundsIndexes(startIndex, endIndex, length) AbstractList.checkBoundsIndexes(startIndex, endIndex, length)
return CharArray(endIndex - startIndex) { get(startIndex + it) } val newLength = endIndex - startIndex
val newArray = CharArray(newLength)
this.chars.copyTo(newArray.storage, startIndex, 0, newLength)
return newArray
} }
/** /**
@@ -350,9 +350,9 @@ private val decompositionValueIndex = shortArrayOf(
) )
internal fun getDecompositionByIndex(index: Int): IntArray { internal fun getDecompositionByIndex(index: Int): IntArray {
val valueIndex = decompositionValueIndex[index] val startIndex = decompositionValueIndex[index].toInt()
val size = decompositionValueIndex[index + 1] - valueIndex val endIndex = decompositionValueIndex[index + 1].toInt()
return IntArray(size) { shift -> val result = IntArray(endIndex - startIndex)
decompositionValues[valueIndex + shift] decompositionValues.copyInto(result, startIndex = startIndex, endIndex = endIndex)
} return result
} }
@@ -919,26 +919,6 @@ object ArrayOps : TemplateGroupBase() {
""" """
} }
} }
on(Backend.Wasm) {
body {
"""
AbstractList.checkRangeIndexes(startIndex, endIndex, this.size)
val rangeSize = endIndex - startIndex
AbstractList.checkRangeIndexes(destinationOffset, destinationOffset + rangeSize, destination.size)
if (this !== destination || destinationOffset <= startIndex) {
for (index in 0 until rangeSize) {
destination[destinationOffset + index] = this[startIndex + index]
}
} else {
for (index in rangeSize - 1 downTo 0) {
destination[destinationOffset + index] = this[startIndex + index]
}
}
return destination
"""
}
}
} }
} }
} }
@@ -354,6 +354,7 @@ enum class WasmOp(
ARRAY_GET_U("array.get_u", 0xFB_15, listOf(STRUCT_TYPE_IDX)), ARRAY_GET_U("array.get_u", 0xFB_15, listOf(STRUCT_TYPE_IDX)),
ARRAY_SET("array.set", 0xFB_16, listOf(STRUCT_TYPE_IDX)), ARRAY_SET("array.set", 0xFB_16, listOf(STRUCT_TYPE_IDX)),
ARRAY_LEN("array.len", 0xFB_17, listOf(STRUCT_TYPE_IDX)), ARRAY_LEN("array.len", 0xFB_17, listOf(STRUCT_TYPE_IDX)),
ARRAY_COPY("array.copy", 0xFB_18, listOf(STRUCT_TYPE_IDX, STRUCT_TYPE_IDX)),
I31_NEW("i31.new", 0xFB_20), I31_NEW("i31.new", 0xFB_20),
I31_GET_S("i31.get_s", 0xFB_21), I31_GET_S("i31.get_s", 0xFB_21),