[Wasm] Migrate usages of @JsFun to js("code")

This commit is contained in:
Svyatoslav Kuzmich
2023-01-14 15:19:25 +01:00
committed by Space Team
parent 7a04999e4a
commit 7175b9f31c
18 changed files with 303 additions and 297 deletions
@@ -242,8 +242,9 @@ fun box(): String {
} }
// TODO: Rewrite test to use module system // TODO: Rewrite test to use module system
@JsFun("() => { globalThis.main = wasmExports; }") fun hackNonModuleExport() {
external fun hackNonModuleExport() js("globalThis.main = wasmExports;")
}
fun main() { fun main() {
hackNonModuleExport() hackNonModuleExport()
+3 -3
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR, JS
// WASM_FAILS_IN: SM // WASM_FAILS_IN: SM
// MODULE: main // MODULE: main
// FILE: externals.kt // FILE: externals.kt
@@ -29,8 +28,9 @@ fun box(): String = "OK"
// TODO: Rewrite test to use module system // TODO: Rewrite test to use module system
@JsFun("() => { globalThis.main = wasmExports; }") fun hackNonModuleExport() {
external fun hackNonModuleExport() js("globalThis.main = wasmExports;")
}
fun main() { fun main() {
hackNonModuleExport() hackNonModuleExport()
@@ -11,17 +11,13 @@ inline fun checkNPE(body: () -> Unit) {
check(throwed) check(throwed)
} }
@JsFun("() => 'abc'") fun notNullString(): String = js("'abc'")
external fun notNullString(): String
@JsFun("() => null") fun notNull2String(): String = js("null")
external fun notNull2String(): String
@JsFun("() => 'abc'") fun nullString(): String? = js("'abc'")
external fun nullString(): String?
@JsFun("() => null") fun null2String(): String? = js("null")
external fun null2String(): String?
fun testString() { fun testString() {
check(notNullString() == "abc") check(notNullString() == "abc")
@@ -32,17 +28,13 @@ fun testString() {
external interface ExternRef external interface ExternRef
@JsFun("() => 'abc'") fun notNullExternRef(): ExternRef = js("'abc'")
external fun notNullExternRef(): ExternRef
@JsFun("() => null") fun notNull2ExternRef(): ExternRef = js("null")
external fun notNull2ExternRef(): ExternRef
@JsFun("() => 'abc'") fun nullExternRef(): ExternRef? = js("'abc'")
external fun nullExternRef(): ExternRef?
@JsFun("() => null") fun null2ExternRef(): ExternRef? = js("null")
external fun null2ExternRef(): ExternRef?
fun testExterRef() { fun testExterRef() {
@@ -54,17 +46,13 @@ fun testExterRef() {
class DataRef class DataRef
@JsFun("(x) => x") fun notNullDataRef(x: DataRef): DataRef = js("x")
external fun notNullDataRef(x: DataRef): DataRef
@JsFun("(x) => null") fun notNull2DataRef(x: DataRef): DataRef = js("null")
external fun notNull2DataRef(x: DataRef): DataRef
@JsFun("(x) => x") fun nullDataRef(x: DataRef): DataRef? = js("x")
external fun nullDataRef(x: DataRef): DataRef?
@JsFun("(x) => null") fun null2DataRef(x: DataRef): DataRef? = js("null")
external fun null2DataRef(x: DataRef): DataRef?
fun testDataRef() { fun testDataRef() {
val dataRef = DataRef() val dataRef = DataRef()
@@ -74,17 +62,13 @@ fun testDataRef() {
check (null2DataRef(dataRef) == null) check (null2DataRef(dataRef) == null)
} }
@JsFun("() => 123") fun notNullInt(): Int = js("123")
external fun notNullInt(): Int
@JsFun("() => null") fun notNull2Int(): Int = js("null")
external fun notNull2Int(): Int
@JsFun("() => 123") fun nullInt(): Int? = js("123")
external fun nullInt(): Int?
@JsFun("() => null") fun null2Int(): Int? = js("null")
external fun null2Int(): Int?
fun testInt() { fun testInt() {
check(notNullInt() == 123) check(notNullInt() == 123)
@@ -93,17 +77,13 @@ fun testInt() {
check(null2Int() == null) check(null2Int() == null)
} }
@JsFun("() => true") fun notNullBoolean(): Boolean = js("true")
external fun notNullBoolean(): Boolean
@JsFun("() => null") fun notNull2Boolean(): Boolean = js("null")
external fun notNull2Boolean(): Boolean
@JsFun("() => true") fun nullBoolean(): Boolean? = js("true")
external fun nullBoolean(): Boolean?
@JsFun("() => null") fun null2Boolean(): Boolean? = js("null")
external fun null2Boolean(): Boolean?
fun testBoolean() { fun testBoolean() {
check(notNullBoolean() == true) check(notNullBoolean() == true)
@@ -112,17 +92,13 @@ fun testBoolean() {
check(null2Boolean() == null) check(null2Boolean() == null)
} }
@JsFun("() => 123") fun notNullShort(): Short = js("123")
external fun notNullShort(): Short
@JsFun("() => null") fun notNull2Short(): Short = js("null")
external fun notNull2Short(): Short
@JsFun("() => 123") fun nullShort(): Short? = js("123")
external fun nullShort(): Short?
@JsFun("() => null") fun null2Short(): Short? = js("null")
external fun null2Short(): Short?
fun testShort() { fun testShort() {
check(notNullShort() == 123.toShort()) check(notNullShort() == 123.toShort())
@@ -131,17 +107,13 @@ fun testShort() {
check(null2Short() == null) check(null2Short() == null)
} }
@JsFun("() => 123.5") fun notNullFloat(): Float = js("123.5")
external fun notNullFloat(): Float
@JsFun("() => null") fun notNull2Float(): Float = js("null")
external fun notNull2Float(): Float
@JsFun("() => 123.5") fun nullFloat(): Float? = js("123.5")
external fun nullFloat(): Float?
@JsFun("() => null") fun null2Float(): Float? = js("null")
external fun null2Float(): Float?
fun testFloat() { fun testFloat() {
check(notNullFloat() == 123.5f) check(notNullFloat() == 123.5f)
@@ -151,17 +123,13 @@ fun testFloat() {
} }
@JsFun("() => 123.5") fun notNullNumber(): Number = js("123.5")
external fun notNullNumber(): Number
@JsFun("() => null") fun notNull2Number(): Number = js("null")
external fun notNull2Number(): Number
@JsFun("() => 123.5") fun nullNumber(): Number? = js("123.5")
external fun nullNumber(): Number?
@JsFun("() => null") fun null2Number(): Number? = js("null")
external fun null2Number(): Number?
fun testNumber() { fun testNumber() {
check(notNullNumber() == 123.5) check(notNullNumber() == 123.5)
@@ -1,14 +1,16 @@
// IGNORE_BACKEND: JS_IR, JS
// WASM_FAILS_IN: SM // WASM_FAILS_IN: SM
@JsFun("(x) => { if (x !== 'abc') throw 'error' }") fun notNullString(x: String) {
external fun notNullString(x: String) js("if (x !== 'abc') throw 'error'")
}
@JsFun("(x) => { if (x !== 'abc') throw 'error' }") fun nullString(x: String?) {
external fun nullString(x: String?) js("if (x !== 'abc') throw 'error'")
}
@JsFun("(x) => { if (x !== null) throw 'error' }") fun null2String(x: String?) {
external fun null2String(x: String?) js("if (x !== null) throw 'error'")
}
fun testString() { fun testString() {
notNullString("abc") notNullString("abc")
@@ -18,17 +20,20 @@ fun testString() {
external interface ExternRef external interface ExternRef
@JsFun("(x) => { if (x !== 'abc') throw 'error' }") fun notNullExternRef(x: ExternRef) {
external fun notNullExternRef(x: ExternRef) js("if (x !== 'abc') throw 'error'")
}
@JsFun("(x) => { if (x !== 'abc') throw 'error' }") fun nullExternRef(x: ExternRef?) {
external fun nullExternRef(x: ExternRef?) js("if (x !== 'abc') throw 'error'")
}
@JsFun("(x) => { if (x !== null) throw 'error' }") fun null2ExternRef(x: ExternRef?) {
external fun null2ExternRef(x: ExternRef?) js("if (x !== null) throw 'error'")
}
@JsFun("() => 'abc'") fun getExternRef(): ExternRef =
external fun getExternRef(): ExternRef js("'abc'")
fun testExterRef() { fun testExterRef() {
val externRef = getExternRef() val externRef = getExternRef()
@@ -39,14 +44,17 @@ fun testExterRef() {
class DataRef class DataRef
@JsFun("(x, y) => { if (x === null) throw 'error' }") fun notNullDataRef(x: DataRef) {
external fun notNullDataRef(x: DataRef) js("if (x === null) throw 'error'")
}
@JsFun("(x, y) => { if (x === null) throw 'error' }") fun nullDataRef(x: DataRef?) {
external fun nullDataRef(x: DataRef?) js("if (x === null) throw 'error'")
}
@JsFun("(x, y) => { if (x !== null) throw 'error' }") fun null2DataRef(x: DataRef?) {
external fun null2DataRef(x: DataRef?) js("if (x !== null) throw 'error'")
}
fun testDataRef() { fun testDataRef() {
val dataRef = DataRef() val dataRef = DataRef()
@@ -55,14 +63,17 @@ fun testDataRef() {
null2DataRef(null) null2DataRef(null)
} }
@JsFun("(x) => { if (x !== 123) throw 'error' }") fun notNullInt(x: Int) {
external fun notNullInt(x: Int) js("if (x !== 123) throw 'error'")
}
@JsFun("(x) => { if (x !== 123) throw 'error' }") fun nullInt(x: Int?) {
external fun nullInt(x: Int?) js("if (x !== 123) throw 'error'")
}
@JsFun("(x) => { if (x !== null) throw 'error' }") fun null2Int(x: Int?) {
external fun null2Int(x: Int?) js("if (x !== null) throw 'error'")
}
fun testInt() { fun testInt() {
notNullInt(123) notNullInt(123)
@@ -70,14 +81,17 @@ fun testInt() {
null2Int(null) null2Int(null)
} }
@JsFun("(x) => { if (x !== true) throw 'error' }") fun notNullBoolean(x: Boolean) {
external fun notNullBoolean(x: Boolean) js("if (x !== true) throw 'error'")
}
@JsFun("(x) => { if (x !== true) throw 'error' }") fun nullBoolean(x: Boolean?) {
external fun nullBoolean(x: Boolean?) js("if (x !== true) throw 'error'")
}
@JsFun("(x) => { if (x !== null) throw 'error' }") fun null2Boolean(x: Boolean?) {
external fun null2Boolean(x: Boolean?) js("if (x !== null) throw 'error'")
}
fun testBoolean() { fun testBoolean() {
notNullBoolean(true) notNullBoolean(true)
@@ -85,14 +99,17 @@ fun testBoolean() {
null2Boolean(null) null2Boolean(null)
} }
@JsFun("(x) => { x == 123 }") fun notNullShort(x: Short) {
external fun notNullShort(x: Short) js("x == 123")
}
@JsFun("(x) => { if (x !== 123) throw 'error' }") fun nullShort(x: Short?) {
external fun nullShort(x: Short?) js("if (x !== 123) throw 'error'")
}
@JsFun("(x) => { if (x !== null) throw 'error' }") fun null2Short(x: Short?) {
external fun null2Short(x: Short?) js("if (x !== null) throw 'error'")
}
fun testShort() { fun testShort() {
notNullShort(123.toShort()) notNullShort(123.toShort())
@@ -100,14 +117,17 @@ fun testShort() {
null2Short(null) null2Short(null)
} }
@JsFun("(x) => { if (x !== 123.5) throw 'error' }") fun notNullFloat(x: Float) {
external fun notNullFloat(x: Float) js("if (x !== 123.5) throw 'error'")
}
@JsFun("(x) => { if (x !== 123.5) throw 'error' }") fun nullFloat(x: Float?) {
external fun nullFloat(x: Float?) js("if (x !== 123.5) throw 'error'")
}
@JsFun("(x) => { if (x !== null) throw 'error' }") fun null2Float(x: Float?) {
external fun null2Float(x: Float?) js("if (x !== null) throw 'error'")
}
fun testFloat() { fun testFloat() {
notNullFloat(123.5f) notNullFloat(123.5f)
@@ -115,23 +135,29 @@ fun testFloat() {
null2Float(null) null2Float(null)
} }
@JsFun("(x) => { if (x !== 123.5) throw 'error' }") fun notNullNumber(x: Number) {
external fun notNullNumber(x: Number) js("if (x !== 123.5) throw 'error'")
}
@JsFun("(x) => { if (x !== 123.5) throw 'error' }") fun nullNumber(x: Number?) {
external fun nullNumber(x: Number?) js("if (x !== 123.5) throw 'error'")
}
@JsFun("(x) => { if (x !== null) throw 'error' }") fun null2Number(x: Number?) {
external fun null2Number(x: Number?) js("if (x !== null) throw 'error'")
}
@JsFun("(x) => { if (x !== 123) throw 'error' }") fun byte2Number(x: Number) {
external fun byte2Number(x: Number) js("if (x !== 123) throw 'error'")
}
@JsFun("(x) => { if (x !== 123) throw 'error' }") fun notNullByte2Number(x: Number?) {
external fun notNullByte2Number(x: Number?) js("if (x !== 123) throw 'error'")
}
@JsFun("(x) => { if (x !== null) throw 'error' }") fun nullByte2Number(x: Number?) {
external fun nullByte2Number(x: Number?) js("if (x !== null) throw 'error'")
}
fun testNumber() { fun testNumber() {
notNullNumber(123.5) notNullNumber(123.5)
@@ -19,23 +19,23 @@ fun assertFalse(x: Boolean) {
external interface EI external interface EI
@JsFun("() => null") fun getNull(): EI? =
external fun getNull(): EI? js("null")
@JsFun("() => undefined") fun getUndefined(): EI? =
external fun getUndefined(): EI? js("undefined")
@JsFun("(ref) => ref === null") fun isJsNull(ref: EI?): Boolean =
external fun isJsNull(ref: EI?): Boolean js("ref === null")
@JsFun("(ref) => ref === undefined") fun isJsUndefined(ref: EI?): Boolean =
external fun isJsUndefined(ref: EI?): Boolean js("ref === undefined")
@JsFun("() => null") fun getJsNullAsNonNullable(): EI =
external fun getJsNullAsNonNullable(): EI js("null")
@JsFun("() => undefined") fun getJsUndefinedAsNonNullable(): EI =
external fun getJsUndefinedAsNonNullable(): EI js("undefined")
inline fun checkNPE(body: () -> Unit) { inline fun checkNPE(body: () -> Unit) {
var throwed = false var throwed = false
@@ -9,23 +9,25 @@ import kotlin.test.FrameworkAdapter
import kotlin.js.Promise import kotlin.js.Promise
// Need to wrap into additional lambdas so that js launcher will work without Mocha or any other testing framework // Need to wrap into additional lambdas so that js launcher will work without Mocha or any other testing framework
@JsFun("(name, fn) => describe(name, fn)") private fun describe(name: String, fn: () -> Unit): Unit =
private external fun describe(name: String, fn: () -> Unit) js("describe(name, fn)")
@JsFun("(name, fn) => xdescribe(name, fn)") private fun xdescribe(name: String, fn: () -> Unit): Unit =
private external fun xdescribe(name: String, fn: () -> Unit) js("xdescribe(name, fn)")
@JsFun("(name, fn) => it(name, fn)") private fun it(name: String, fn: () -> Any?): Unit =
private external fun it(name: String, fn: () -> Any?) js("it(name, fn)")
@JsFun("(name, fn) => xit(name, fn)") private fun xit(name: String, fn: () -> Any?): Unit =
private external fun xit(name: String, fn: () -> Any?) js("xit(name, fn)")
@JsFun("(e) => { throw e }") private fun jsThrow(jsException: Dynamic) {
private external fun jsThrow(jsException: Dynamic) js("throw e")
}
@JsFun("(message, stack) => { const e = new Error(); e.message = message; e.stack = stack; return e; }") private fun throwableToJsError(message: String, stack: String): Dynamic {
private external fun throwableToJsError(message: String, stack: String): Dynamic js("var e = new Error(); e.message = message; e.stack = stack; return e;")
}
private fun Throwable.toJsError(): Dynamic = private fun Throwable.toJsError(): Dynamic =
throwableToJsError(message ?: "", stackTraceToString()) throwableToJsError(message ?: "", stackTraceToString())
@@ -39,8 +39,8 @@ internal fun test(name: String, ignored: Boolean, testFn: () -> Any?) {
internal var currentAdapter: FrameworkAdapter? = null internal var currentAdapter: FrameworkAdapter? = null
@JsFun("() => typeof describe === 'function' && typeof it === 'function'") private fun isJasmine(): Boolean =
private external fun isJasmine(): Boolean js("typeof describe === 'function' && typeof it === 'function'")
internal fun adapter(): FrameworkAdapter { internal fun adapter(): FrameworkAdapter {
val result = currentAdapter ?: if (isJasmine()) JasmineLikeAdapter() else TeamcityAdapter() val result = currentAdapter ?: if (isJasmine()) JasmineLikeAdapter() else TeamcityAdapter()
@@ -40,5 +40,5 @@ public open class Throwable(open val message: String?, open val cause: kotlin.Th
} }
} }
@JsFun("() => new Error().stack") private fun captureStackTrace(): ExternalInterfaceType =
private external fun captureStackTrace(): ExternalInterfaceType js("new Error().stack")
@@ -5,16 +5,16 @@
package kotlin.wasm.internal package kotlin.wasm.internal
@JsFun( @Suppress("UNUSED_PARAMETER") // TODO: Remove after bootstrap update
"""(message, wasmTypeName, stack) => { private fun throwJsError(message: String?, wasmTypeName: String?, stack: String): Nothing {
const error = new Error(); js("""
error.message = message; const error = new Error();
error.name = wasmTypeName; error.message = message;
error.stack = stack; error.name = wasmTypeName;
throw error; error.stack = stack;
}""" throw error;
) """)
private external fun throwJsError(message: String?, wasmTypeName: String?, stack: String): Nothing }
internal fun throwAsJsException(t: Throwable): Nothing { internal fun throwAsJsException(t: Throwable): Nothing {
throwJsError(t.message, t::class.simpleName, t.stackTraceToString()) throwJsError(t.message, t::class.simpleName, t.stackTraceToString())
@@ -3,6 +3,8 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("UNUSED_PARAMETER") // TODO: Remove after bootstrap update
package kotlin.wasm.internal package kotlin.wasm.internal
import kotlin.wasm.internal.reftypes.anyref import kotlin.wasm.internal.reftypes.anyref
@@ -31,6 +33,7 @@ internal class JsExternalBox @WasmPrimitiveConstructor constructor(val ref: Exte
} }
} }
@Suppress("DEPRECATION")
//language=js //language=js
@JsFun(""" @JsFun("""
(() => { (() => {
@@ -85,41 +88,41 @@ return (obj) => {
) )
private external fun externrefHashCode(ref: ExternalInterfaceType): Int private external fun externrefHashCode(ref: ExternalInterfaceType): Int
@JsFun("ref => String(ref)") private fun externrefToString(ref: ExternalInterfaceType): String =
private external fun externrefToString(ref: ExternalInterfaceType): String js("String(ref)")
@JsFun("ref => Number(ref)") private fun externrefToInt(ref: ExternalInterfaceType): Int =
private external fun externrefToInt(ref: ExternalInterfaceType): Int js("Number(ref)")
@JsFun("ref => Number(ref)") private fun externrefToLong(ref: ExternalInterfaceType): Long =
private external fun externrefToLong(ref: ExternalInterfaceType): Long js("Number(ref)")
@JsFun("ref => Boolean(ref)") private fun externrefToBoolean(ref: ExternalInterfaceType): Boolean =
private external fun externrefToBoolean(ref: ExternalInterfaceType): Boolean js("Boolean(ref)")
@JsFun("ref => Number(ref)") private fun externrefToFloat(ref: ExternalInterfaceType): Float =
private external fun externrefToFloat(ref: ExternalInterfaceType): Float js("Number(ref)")
@JsFun("ref => Number(ref)") private fun externrefToDouble(ref: ExternalInterfaceType): Double =
private external fun externrefToDouble(ref: ExternalInterfaceType): Double js("Number(ref)")
@JsFun("x => x") private fun intToExternref(x: Int): ExternalInterfaceType =
private external fun intToExternref(x: Int): ExternalInterfaceType js("x")
@JsFun("x => x") private fun longToExternref(x: Long): ExternalInterfaceType =
private external fun longToExternref(x: Long): ExternalInterfaceType js("x")
@JsFun("x => x") private fun booleanToExternref(x: Boolean): ExternalInterfaceType =
private external fun booleanToExternref(x: Boolean): ExternalInterfaceType js("x")
@JsFun("x => x") private fun floatToExternref(x: Float): ExternalInterfaceType =
private external fun floatToExternref(x: Float): ExternalInterfaceType js("x")
@JsFun("x => x") private fun doubleToExternref(x: Double): ExternalInterfaceType =
private external fun doubleToExternref(x: Double): ExternalInterfaceType js("x")
@JsFun("(lhs, rhs) => lhs === rhs") private fun externrefEquals(lhs: ExternalInterfaceType, rhs: ExternalInterfaceType): Boolean =
private external fun externrefEquals(lhs: ExternalInterfaceType, rhs: ExternalInterfaceType): Boolean js("lhs === rhs")
private external fun tryGetOrSetExternrefBox(ref: ExternalInterfaceType, ifNotCached: JsExternalBox): JsExternalBox? private external fun tryGetOrSetExternrefBox(ref: ExternalInterfaceType, ifNotCached: JsExternalBox): JsExternalBox?
@@ -136,8 +139,8 @@ private fun ExternalInterfaceType.externAsWasmAnyref(): anyref =
private fun Any.asWasmExternRef(): ExternalInterfaceType = private fun Any.asWasmExternRef(): ExternalInterfaceType =
implementedAsIntrinsic implementedAsIntrinsic
@JsFun("(ref) => ref == null") internal fun isNullish(ref: ExternalInterfaceType?): Boolean =
internal external fun isNullish(ref: ExternalInterfaceType?): Boolean js("ref == null")
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
@ExcludedFromCodegen @ExcludedFromCodegen
@@ -179,18 +182,18 @@ internal fun anyToExternRef(x: Any): ExternalInterfaceType {
x.asWasmExternRef() x.asWasmExternRef()
} }
@JsFun("x => x.length") internal fun stringLength(x: ExternalInterfaceType): Int =
internal external fun stringLength(x: ExternalInterfaceType): Int js("x.length")
// kotlin string to js string export // kotlin string to js string export
// TODO Uint16Array may work with byte endian different with Wasm (i.e. little endian) // TODO Uint16Array may work with byte endian different with Wasm (i.e. little endian)
@JsFun("""(address, length, prefix) => { internal fun importStringFromWasm(address: Int, length: Int, prefix: ExternalInterfaceType?): ExternalInterfaceType {
js("""
const mem16 = new Uint16Array(wasmExports.memory.buffer, address, length); const mem16 = new Uint16Array(wasmExports.memory.buffer, address, length);
const str = String.fromCharCode.apply(null, mem16); const str = String.fromCharCode.apply(null, mem16);
return (prefix == null) ? str : prefix + str; return (prefix == null) ? str : prefix + str;
""")
} }
""")
internal external fun importStringFromWasm(address: Int, length: Int, prefix: ExternalInterfaceType?): ExternalInterfaceType
internal fun kotlinToJsStringAdapter(x: String?): ExternalInterfaceType? { internal fun kotlinToJsStringAdapter(x: String?): ExternalInterfaceType? {
// Using nullable String to represent default value // Using nullable String to represent default value
@@ -224,21 +227,18 @@ internal fun jsCheckIsNullOrUndefinedAdapter(x: ExternalInterfaceType?): Externa
// js string to kotlin string import // js string to kotlin string import
// TODO Uint16Array may work with byte endian different with Wasm (i.e. little endian) // TODO Uint16Array may work with byte endian different with Wasm (i.e. little endian)
//language=js internal fun jsExportStringToWasm(src: ExternalInterfaceType, srcOffset: Int, srcLength: Int, dstAddr: Int) {
@JsFun( js("""
""" (src, srcOffset, srcLength, dstAddr) => { const mem16 = new Uint16Array(wasmExports.memory.buffer, dstAddr, srcLength);
const mem16 = new Uint16Array(wasmExports.memory.buffer, dstAddr, srcLength); let arrayIndex = 0;
let arrayIndex = 0; let srcIndex = srcOffset;
let srcIndex = srcOffset; while (arrayIndex < srcLength) {
while (arrayIndex < srcLength) { mem16.set([src.charCodeAt(srcIndex)], arrayIndex);
mem16.set([src.charCodeAt(srcIndex)], arrayIndex); srcIndex++;
srcIndex++; arrayIndex++;
arrayIndex++; }
} """)
} }
"""
)
internal external fun jsExportStringToWasm(src: ExternalInterfaceType, srcOffset: Int, srcLength: Int, dstAddr: Int)
private const val STRING_INTEROP_MEM_BUFFER_SIZE = 65_536 // 1 page 4KiB private const val STRING_INTEROP_MEM_BUFFER_SIZE = 65_536 // 1 page 4KiB
@@ -269,14 +269,14 @@ internal fun jsToKotlinStringAdapter(x: ExternalInterfaceType): String {
} }
@JsFun("() => ''") private fun getJsEmptyString(): ExternalInterfaceType =
private external fun getJsEmptyString(): ExternalInterfaceType js("''")
@JsFun("() => true") private fun getJsTrue(): ExternalInterfaceType =
private external fun getJsTrue(): ExternalInterfaceType js("true")
@JsFun("() => false") private fun getJsFalse(): ExternalInterfaceType =
private external fun getJsFalse(): ExternalInterfaceType js("false")
private val jsEmptyString by lazy(::getJsEmptyString) private val jsEmptyString by lazy(::getJsEmptyString)
private val jsTrue by lazy(::getJsTrue) private val jsTrue by lazy(::getJsTrue)
@@ -335,8 +335,9 @@ internal fun kotlinShortToExternRefAdapter(x: Short): ExternalInterfaceType =
internal fun kotlinCharToExternRefAdapter(x: Char): ExternalInterfaceType = internal fun kotlinCharToExternRefAdapter(x: Char): ExternalInterfaceType =
intToExternref(x.toInt()) intToExternref(x.toInt())
@JsFun("() => []") internal fun newJsArray(): ExternalInterfaceType =
internal external fun newJsArray(): ExternalInterfaceType js("[]")
@JsFun("(array, element) => { array.push(element); }") internal fun jsArrayPush(array: ExternalInterfaceType, element: ExternalInterfaceType) {
internal external fun jsArrayPush(array: ExternalInterfaceType, element: ExternalInterfaceType) js("array.push(element);")
}
+51 -49
View File
@@ -3,87 +3,89 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("UNUSED_PARAMETER") // TODO: Remove after bootstrap update
package kotlin.js package kotlin.js
@PublishedApi @PublishedApi
@JsFun("(obj, index, value) => obj[index] = value") internal fun dynamicSetBoolean(obj: Dynamic, index: String, value: Boolean): Unit =
internal external fun dynamicSetBoolean(obj: Dynamic, index: String, value: Boolean) js("obj[index] = value")
@PublishedApi @PublishedApi
@JsFun("(obj, index, value) => obj[index] = value") internal fun dynamicSetByte(obj: Dynamic, index: String, value: Byte): Unit =
internal external fun dynamicSetByte(obj: Dynamic, index: String, value: Byte) js("obj[index] = value")
@PublishedApi @PublishedApi
@JsFun("(obj, index, value) => obj[index] = value") internal fun dynamicSetShort(obj: Dynamic, index: String, value: Short): Unit =
internal external fun dynamicSetShort(obj: Dynamic, index: String, value: Short) js("obj[index] = value")
@PublishedApi @PublishedApi
@JsFun("(obj, index, value) => obj[index] = value") internal fun dynamicSetChar(obj: Dynamic, index: String, value: Char): Unit =
internal external fun dynamicSetChar(obj: Dynamic, index: String, value: Char) js("obj[index] = value")
@PublishedApi @PublishedApi
@JsFun("(obj, index, value) => obj[index] = value") internal fun dynamicSetInt(obj: Dynamic, index: String, value: Int): Unit =
internal external fun dynamicSetInt(obj: Dynamic, index: String, value: Int) js("obj[index] = value")
@PublishedApi @PublishedApi
@JsFun("(obj, index, value) => obj[index] = value") internal fun dynamicSetLong(obj: Dynamic, index: String, value: Long): Unit =
internal external fun dynamicSetLong(obj: Dynamic, index: String, value: Long) js("obj[index] = value")
@PublishedApi @PublishedApi
@JsFun("(obj, index, value) => obj[index] = value") internal fun dynamicSetFloat(obj: Dynamic, index: String, value: Float): Unit =
internal external fun dynamicSetFloat(obj: Dynamic, index: String, value: Float) js("obj[index] = value")
@PublishedApi @PublishedApi
@JsFun("(obj, index, value) => obj[index] = value") internal fun dynamicSetDouble(obj: Dynamic, index: String, value: Double): Unit =
internal external fun dynamicSetDouble(obj: Dynamic, index: String, value: Double) js("obj[index] = value")
@PublishedApi @PublishedApi
@JsFun("(obj, index, value) => obj[index] = value") internal fun dynamicSetString(obj: Dynamic, index: String, value: String?): Unit =
internal external fun dynamicSetString(obj: Dynamic, index: String, value: String?) js("obj[index] = value")
@PublishedApi @PublishedApi
@JsFun("(obj, index, value) => obj[index] = value") internal fun dynamicSetAny(obj: Dynamic, index: String, value: Any?): Unit =
internal external fun dynamicSetAny(obj: Dynamic, index: String, value: Any?) js("obj[index] = value")
@PublishedApi @PublishedApi
@JsFun("(obj, index) => obj[index]") internal fun dynamicGetBoolean(obj: Dynamic, index: String): Boolean =
internal external fun dynamicGetBoolean(obj: Dynamic, index: String): Boolean js("obj[index]")
@PublishedApi @PublishedApi
@JsFun("(obj, index) => obj[index]") internal fun dynamicGetByte(obj: Dynamic, index: String): Byte =
internal external fun dynamicGetByte(obj: Dynamic, index: String): Byte js("obj[index]")
@PublishedApi @PublishedApi
@JsFun("(obj, index) => obj[index]") internal fun dynamicGetShort(obj: Dynamic, index: String): Short =
internal external fun dynamicGetShort(obj: Dynamic, index: String): Short js("obj[index]")
@PublishedApi @PublishedApi
@JsFun("(obj, index) => obj[index]") internal fun dynamicGetChar(obj: Dynamic, index: String): Char =
internal external fun dynamicGetChar(obj: Dynamic, index: String): Char js("obj[index]")
@PublishedApi @PublishedApi
@JsFun("(obj, index) => obj[index]") internal fun dynamicGetInt(obj: Dynamic, index: String): Int =
internal external fun dynamicGetInt(obj: Dynamic, index: String): Int js("obj[index]")
@PublishedApi @PublishedApi
@JsFun("(obj, index) => obj[index]") internal fun dynamicGetLong(obj: Dynamic, index: String): Long =
internal external fun dynamicGetLong(obj: Dynamic, index: String): Long js("obj[index]")
@PublishedApi @PublishedApi
@JsFun("(obj, index) => obj[index]") internal fun dynamicGetFloat(obj: Dynamic, index: String): Float =
internal external fun dynamicGetFloat(obj: Dynamic, index: String): Float js("obj[index]")
@PublishedApi @PublishedApi
@JsFun("(obj, index) => obj[index]") internal fun dynamicGetDouble(obj: Dynamic, index: String): Double =
internal external fun dynamicGetDouble(obj: Dynamic, index: String): Double js("obj[index]")
@PublishedApi @PublishedApi
@JsFun("(obj, index) => obj[index]") internal fun dynamicGetString(obj: Dynamic, index: String): String? =
internal external fun dynamicGetString(obj: Dynamic, index: String): String? js("obj[index]")
@PublishedApi @PublishedApi
@JsFun("(obj, index) => obj[index]") internal fun dynamicGetAny(obj: Dynamic, index: String): Any? =
internal external fun dynamicGetAny(obj: Dynamic, index: String): Any? js("obj[index]")
@PublishedApi @PublishedApi
internal fun Dynamic.getBoolean(index: String): Boolean = dynamicGetBoolean(this, index) internal fun Dynamic.getBoolean(index: String): Boolean = dynamicGetBoolean(this, index)
@@ -184,14 +186,12 @@ operator fun Dynamic.set(index: Int, value: Any?) {
this[index.toString()] = value this[index.toString()] = value
} }
@JsFun("(x) => x") private fun <T> unsafeCastJs(x: String): Dynamic = js("x")
private external fun <T> unsafeCastJs(x: String): Dynamic
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T> String.unsafeCast(): T = unsafeCastJs<T>(this) as T fun <T> String.unsafeCast(): T = unsafeCastJs<T>(this) as T
@JsFun("(x) => x") private fun <T> unsafeCastJs(x: Boolean): Dynamic = js("x")
private external fun <T> unsafeCastJs(x: Boolean): Dynamic
/** /**
* Reinterprets boolean value as a value of the specified type [T] without any actual type checking. * Reinterprets boolean value as a value of the specified type [T] without any actual type checking.
@@ -210,10 +210,12 @@ fun <T> Nothing?.unsafeCast(): Dynamic? = null
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T> Dynamic.unsafeCast(): T = this as T fun <T> Dynamic.unsafeCast(): T = this as T
@JsFun("e => { throw e; }") private fun jsThrow(e: Dynamic) {
private external fun jsThrow(e: Dynamic) js("throw e;")
}
@JsFun("""(f) => { private fun jsCatch(f: () -> Unit): Dynamic? {
js("""
let result = null; let result = null;
try { try {
f(); f();
@@ -221,8 +223,8 @@ private external fun jsThrow(e: Dynamic)
result = e; result = e;
} }
return result; return result;
}""") """)
private external fun jsCatch(f: () -> Unit): Dynamic? }
/** /**
* For a Dynamic value caught in JS, returns the corresponding [Throwable] * For a Dynamic value caught in JS, returns the corresponding [Throwable]
+8 -6
View File
@@ -3,18 +3,20 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("UNUSED_PARAMETER") // TODO: Remove after bootstrap update
package kotlin.io package kotlin.io
import kotlin.wasm.internal.* import kotlin.wasm.internal.*
@JsFun("(error) => console.error(error)") internal fun printError(error: String?): Unit =
internal external fun printError(error: String?): Unit js("console.error(error)")
@JsFun("(message) => console.log(message)") private fun printlnImpl(message: String?): Unit =
private external fun printlnImpl(message: String?): Unit js("console.log(message)")
@JsFun("(message) => typeof write !== 'undefined' ? write(message) : console.log(message)") private fun printImpl(message: String?): Unit =
private external fun printImpl(message: String?): Unit js("typeof write !== 'undefined' ? write(message) : console.log(message)")
/** Prints the line separator to the standard output stream. */ /** Prints the line separator to the standard output stream. */
public actual fun println() { public actual fun println() {
@@ -5,8 +5,8 @@
package kotlin.random package kotlin.random
@JsFun("() => ((Math.random() * Math.pow(2, 32)) | 0)") private fun initialSeed(): Int =
private external fun initialSeed(): Int js("((Math.random() * Math.pow(2, 32)) | 0)")
internal actual fun defaultPlatformRandom(): Random = internal actual fun defaultPlatformRandom(): Random =
Random(initialSeed()) Random(initialSeed())
@@ -3,17 +3,19 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("UNUSED_PARAMETER") // TODO: Remove after bootstrap update
package kotlin.time package kotlin.time
import kotlin.math.* import kotlin.math.*
internal actual inline val durationAssertionsEnabled: Boolean get() = true internal actual inline val durationAssertionsEnabled: Boolean get() = true
@JsFun("(value, decimals) => value.toFixed(decimals)") private fun toFixed(value: Double, decimals: Int): String =
private external fun toFixed(value: Double, decimals: Int): String js("value.toFixed(decimals)")
@JsFun("(value, decimals) => value.toPrecision(decimals)") private fun toPrecision(value: Double, decimals: Int): String =
private external fun toPrecision(value: Double, decimals: Int): String js("value.toPrecision(decimals)")
internal actual fun formatToExactDecimals(value: Double, decimals: Int): String { internal actual fun formatToExactDecimals(value: Double, decimals: Int): String {
val rounded = if (decimals == 0) { val rounded = if (decimals == 0) {
@@ -34,5 +36,5 @@ internal actual fun formatToExactDecimals(value: Double, decimals: Int): String
} }
} }
@JsFun("(value, decimals) => value.toLocaleString(\"en-us\", ({\"maximumFractionDigits\": decimals}))") internal actual fun formatUpToDecimals(value: Double, decimals: Int): String =
external internal actual fun formatUpToDecimals(value: Double, decimals: Int): String js("(value, decimals) => value.toLocaleString(\"en-us\", ({\"maximumFractionDigits\": decimals}))")
@@ -3,20 +3,22 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("UNUSED_PARAMETER") // TODO: Remove after bootstrap advance
package kotlin.time package kotlin.time
import kotlin.wasm.internal.ExternalInterfaceType import kotlin.wasm.internal.ExternalInterfaceType
import kotlin.time.TimeSource.Monotonic.ValueTimeMark import kotlin.time.TimeSource.Monotonic.ValueTimeMark
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
@JsFun("() => typeof globalThis !== 'undefined' && typeof globalThis.performance !== 'undefined' ? globalThis.performance : null") private fun tryGetPerformance(): ExternalInterfaceType? =
private external fun tryGetPerformance(): ExternalInterfaceType? js("typeof globalThis !== 'undefined' && typeof globalThis.performance !== 'undefined' ? globalThis.performance : null")
@JsFun("(performance) => performance.now()") private fun getPerformanceNow(performance: ExternalInterfaceType): Double =
private external fun getPerformanceNow(performance: ExternalInterfaceType): Double js("performance.now()")
@JsFun("() => Date.now()") private fun dateNow(): Double =
private external fun dateNow(): Double js("Date.now()")
@SinceKotlin("1.3") @SinceKotlin("1.3")
@ExperimentalTime @ExperimentalTime
@@ -9,5 +9,5 @@ package kotlin.js
internal val undefined: Nothing? = null internal val undefined: Nothing? = null
@PublishedApi @PublishedApi
@JsFun("() => ({})") internal fun newJsObject(): Dynamic =
internal external fun newJsObject(): Dynamic js("({})")
+4 -4
View File
@@ -3,11 +3,11 @@ package test.js
import kotlin.js.* import kotlin.js.*
import kotlin.test.* import kotlin.test.*
@JsFun("async () => 'foo'") internal fun jsAsyncFoo(): Promise<Dynamic?> =
internal external fun jsAsyncFoo(): Promise<Dynamic?> js("(async () => 'foo')()")
@JsFun("() => 'foo'") internal fun jsFoo(): Dynamic =
internal external fun jsFoo(): Dynamic js("'foo'")
var state: Dynamic? = null var state: Dynamic? = null
@@ -3,8 +3,8 @@ package test.wasm.unsafe
import kotlin.wasm.unsafe.* import kotlin.wasm.unsafe.*
import kotlin.test.* import kotlin.test.*
@JsFun("(a, b) => a + b") private fun jsConcatStrings(a: String, b: String): String =
private external fun jsConcatStrings(a: String, b: String): String js("a + b")
@OptIn(UnsafeWasmMemoryApi::class) @OptIn(UnsafeWasmMemoryApi::class)
class MemoryAllocationTest { class MemoryAllocationTest {