[Wasm] Use static import for wasm imports

^KT-65777 fixed
This commit is contained in:
Ilya Goncharov
2024-02-19 10:01:10 +00:00
committed by Space Team
parent 68e5fc7344
commit abb5f55087
22 changed files with 370 additions and 168 deletions
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.wasm.ir2wasm.JsModuleAndQualifierReference
import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmCompiledModuleFragment
import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmModuleFragmentGenerator
import org.jetbrains.kotlin.backend.wasm.ir2wasm.toJsStringLiteral
import org.jetbrains.kotlin.backend.wasm.lower.JsInteropFunctionsLowering
import org.jetbrains.kotlin.backend.wasm.lower.markExportedDeclarations
import org.jetbrains.kotlin.backend.wasm.utils.SourceMapGenerator
import org.jetbrains.kotlin.backend.wasm.export.ExportModelGenerator
@@ -34,6 +35,7 @@ import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToBinary
import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToText
import org.jetbrains.kotlin.wasm.ir.source.location.SourceLocation
@@ -176,7 +178,10 @@ fun compileWasm(
"./$baseFileName.wasm",
backendContext.jsModuleAndQualifierReferences
)
jsWrapper = generateEsmExportsWrapper("./$baseFileName.uninstantiated.mjs")
jsWrapper = compiledWasmModule.generateEsmExportsWrapper(
"./$baseFileName.uninstantiated.mjs",
backendContext.jsModuleAndQualifierReferences
)
} else {
jsUninstantiatedWrapper = null
jsWrapper = compiledWasmModule.generateAsyncWasiWrapper("./$baseFileName.wasm")
@@ -215,7 +220,8 @@ const wasmInstance = new WebAssembly.Instance(wasmModule, wasi.getImportObject()
wasi.initialize(wasmInstance);
export default wasmInstance.exports;
const exports = wasmInstance.exports
${generateExports()}
"""
fun WasmCompiledModuleFragment.generateAsyncJsWrapper(
@@ -234,7 +240,7 @@ fun WasmCompiledModuleFragment.generateAsyncJsWrapper(
.sorted()
.joinToString("") {
val moduleSpecifier = it.toJsStringLiteral()
" $moduleSpecifier: imports[$moduleSpecifier] ?? await import($moduleSpecifier),\n"
" $moduleSpecifier: imports[$moduleSpecifier],\n"
}
val referencesToQualifiedAndImportedDeclarations = jsModuleAndQualifierReferences
@@ -246,7 +252,7 @@ fun WasmCompiledModuleFragment.generateAsyncJsWrapper(
append(it.jsVariableName)
append(" = ")
if (module != null) {
append("(imports[${module.toJsStringLiteral()}] ?? await import(${module.toJsStringLiteral()}))")
append("imports[${module.toJsStringLiteral()}]")
if (qualifier != null)
append(".")
}
@@ -352,10 +358,59 @@ For more information, see https://kotl.in/wasm-help
"""
}
fun generateEsmExportsWrapper(asyncWrapperFileName: String): String = /*language=js */ """
fun WasmCompiledModuleFragment.generateEsmExportsWrapper(
asyncWrapperFileName: String,
jsModuleAndQualifierReferences: MutableSet<JsModuleAndQualifierReference>
): String {
val importedModules = jsModuleImports
.map {
val moduleSpecifier = it.toJsStringLiteral().toString()
val importVariableString = JsModuleAndQualifierReference.encode(it)
moduleSpecifier to importVariableString
}
val referencesToImportedDeclarations = jsModuleAndQualifierReferences
.filter { it.module != null }
.map {
val module = it.module!!
val stringLiteral = module.toJsStringLiteral().toString()
stringLiteral to if (it.qualifier != null) {
it.importVariableName
} else {
it.jsVariableName
}
}
val allModules = (importedModules + referencesToImportedDeclarations)
.distinctBy {
it.first
}.sortedBy { it.first }
val importsImportedSection = allModules.joinToString("\n") {
buildString {
append("import * as ")
append(it.second)
append(" from ")
append(it.first)
append(";")
}
}
val imports = allModules.joinToString(",\n") {
" ${it.first}: ${it.second}"
}
/*language=js */
return """
$importsImportedSection
import { instantiate } from ${asyncWrapperFileName.toJsStringLiteral()};
export default (await instantiate()).exports;
const exports = (await instantiate({
$imports
})).exports;
${generateExports()}
"""
}
fun writeCompilationResult(
result: WasmCompilerResult,
@@ -384,3 +439,37 @@ fun writeCompilationResult(
File(dir, "$fileNameBase.d.ts").writeText(result.dts)
}
}
fun WasmCompiledModuleFragment.generateExports(): String {
// TODO: necessary to move export check onto common place
val exportNames = exports
.filterNot { it.name.startsWith(JsInteropFunctionsLowering.CALL_FUNCTION) }
.ifNotEmpty {
joinToString(",\n") {
" ${it.name}"
}
}?.let {
"""
|const {
|$it
|}
""".trimMargin()
}
/*language=js */
return """
export default new Proxy(exports, {
_shownError: false,
get(target, prop) {
if (!this._shownError) {
this._shownError = true;
if (typeof console !== "undefined") {
console.error("Do not use default import. Use corresponding named import instead.")
}
}
return target[prop];
}
});
${exportNames?.let { "export $it = exports;" }}
"""
}
@@ -15,11 +15,20 @@ data class JsModuleAndQualifierReference(
val module: String?,
val qualifier: String?,
) {
val jsVariableName = run {
private val moduleBase64 = module?.let { encode(it) }.orEmpty()
private val qualifierBase64 = qualifier?.let { encode(it) }.orEmpty()
val jsVariableName = "_ref_${moduleBase64}_$qualifierBase64"
val importVariableName = "_import_${moduleBase64}_$qualifierBase64"
companion object {
// Encode variable name as base64 to have a valid unique JS identifier
val encoder = Base64.getEncoder().withoutPadding()
val moduleBase64 = module?.let { encoder.encodeToString(module.encodeToByteArray()) }.orEmpty()
val qualifierBase64 = qualifier?.let { encoder.encodeToString(qualifier.encodeToByteArray()) }.orEmpty()
"_ref_${moduleBase64}_$qualifierBase64"
private val encoder = Base64.getEncoder().withoutPadding()
fun encode(value: String): String {
return encoder.encodeToString(value.encodeToByteArray())
}
}
}
@@ -466,7 +466,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
private fun createKotlinClosureCaller(info: FunctionTypeInfo): IrSimpleFunction {
val result = context.irFactory.buildFun {
name = Name.identifier("__callFunction_${info.signatureString}")
name = Name.identifier("$CALL_FUNCTION${info.signatureString}")
returnType = info.adaptedResultType
origin = KOTLIN_TO_JS_CLOSURE_ORIGIN
}
@@ -522,7 +522,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
append("(f) => (")
appendParameterList(arity)
append(") => wasmExports[")
append("__callFunction_${info.signatureString}".toJsStringLiteral())
append("$CALL_FUNCTION${info.signatureString}".toJsStringLiteral())
append("](f, ")
appendParameterList(arity)
append(")")
@@ -911,6 +911,10 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
}
}
}
companion object {
const val CALL_FUNCTION = "__callFunction_"
}
}
internal fun StringBuilder.appendParameterList(size: Int, name: String = "p", isEnd: Boolean = true) =
+3 -3
View File
@@ -2,7 +2,7 @@
// RUN_THIRD_PARTY_OPTIMIZER
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 12_773
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_528
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_921
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 2_640
// FILE: test.kt
@@ -11,7 +11,7 @@
fun add(a: Int, b: Int) = a + b
// FILE: entry.mjs
import k from "./index.mjs"
import { add } from "./index.mjs"
const r = k.add(2, 3);
const r = add(2, 3);
if (r != 5) throw Error("Wrong result: " + r);
+1 -1
View File
@@ -2,7 +2,7 @@
// RUN_THIRD_PARTY_OPTIMIZER
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 35_154
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_552
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_941
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 8_586
fun box(): String {
+3 -3
View File
@@ -2,7 +2,7 @@
// RUN_THIRD_PARTY_OPTIMIZER
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 14_178
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 5_081
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 5_478
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 4_317
// FILE: test.kt
@@ -16,7 +16,7 @@ fun test() {
}
// FILE: entry.mjs
import k from "./index.mjs"
import { test } from "./index.mjs"
const r = typeof k.test;
const r = typeof test;
if (r != "function") throw Error("Wrong result: " + r);
+1 -1
View File
@@ -2,7 +2,7 @@
// RUN_THIRD_PARTY_OPTIMIZER
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 17_907
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_398
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_787
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 5_841
object Simple
+1 -1
View File
@@ -2,7 +2,7 @@
// RUN_THIRD_PARTY_OPTIMIZER
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 12_856
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_398
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_787
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 3_743
fun box() = "OK"
+1 -1
View File
@@ -3,7 +3,7 @@
// RUN_THIRD_PARTY_OPTIMIZER
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 13_321
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_398
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_787
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 3_900
interface I {
@@ -244,22 +244,22 @@ fun box(): String {
// FILE: entry.mjs
import main from "./index.mjs"
import { box, exportedF, complexHigherOrder } from "./index.mjs"
const boxResult = main.box();
const boxResult = box();
if (boxResult != "OK") {
throw `Wrong box result '${boxResult}'; Expected "OK"`;
}
const exportedFres = main.exportedF()(1, 20, 300)("<", ">");
const exportedFres = exportedF()(1, 20, 300)("<", ">");
if (exportedFres !== "<321>")
throw "exportedF fail " + exportedFres;
(function testComplexHighOrder() {
const x = (ss2s1, ss2s2) => (s1, s2) => ss2s1(s1, s2) + "_" + ss2s2(s1, s2);
const y = main.complexHigherOrder(x);
const y = complexHigherOrder(x);
const res = y((s1, s2) => s1 + "+" + s2, (s1, s2) => s1 + "-" + s2)("abc", "xyz");
if (res !== "abc+xyz_abc-xyz") {
throw "Fail complexHigherOrderTest " + res;
+69 -46
View File
@@ -76,155 +76,178 @@ fun box(): String = "OK"
// FILE: entry.mjs
import main from "./index.mjs"
import {
makeC,
getX,
getString,
isEven,
anyAsEI,
eiAsAny,
provideUByte,
provideUShort,
provideUInt,
provideULong,
provideNullableUByte,
provideNullableUShort,
provideNullableUInt,
provideNullableULong,
consumeUByte,
consumeNullableUByte,
consumeUShort,
consumeNullableUShort,
consumeUInt,
consumeNullableUInt,
consumeULong,
consumeNullableULong,
} from "./index.mjs"
const c = main.makeC(300);
if (main.getX(c) !== 300) {
const c = makeC(300);
if (getX(c) !== 300) {
throw "Fail 1";
}
if (main.getString("2") !== "Test string 2") {
if (getString("2") !== "Test string 2") {
throw "Fail 2";
}
if (main.isEven(31) !== false || main.isEven(10) !== true) {
if (isEven(31) !== false || isEven(10) !== true) {
throw "Fail 3";
}
if (main.anyAsEI(main.eiAsAny({x:10})).x !== 10) {
if (anyAsEI(eiAsAny({x:10})).x !== 10) {
throw "Fail 4";
}
if (main.provideUByte() != 255) {
if (provideUByte() != 255) {
throw "Fail 5";
}
if (main.provideUShort() != 65535) {
if (provideUShort() != 65535) {
throw "Fail 6";
}
if (main.provideUInt() != 4294967295) {
if (provideUInt() != 4294967295) {
throw "Fail 7";
}
if (main.provideULong() != 18446744073709551615n) {
if (provideULong() != 18446744073709551615n) {
throw "Fail 8";
}
if (main.provideNullableUByte(false) != 255) {
if (provideNullableUByte(false) != 255) {
throw "Fail 9";
}
if (main.provideNullableUByte(true) != null) {
if (provideNullableUByte(true) != null) {
throw "Fail 10";
}
if (main.provideNullableUShort(false) != 65535) {
if (provideNullableUShort(false) != 65535) {
throw "Fail 11";
}
if (main.provideNullableUShort(true) != null) {
if (provideNullableUShort(true) != null) {
throw "Fail 12";
}
if (main.provideNullableUInt(false) != 4294967295) {
if (provideNullableUInt(false) != 4294967295) {
throw "Fail 13";
}
if (main.provideNullableUInt(true) != null) {
if (provideNullableUInt(true) != null) {
throw "Fail 14";
}
if (main.provideNullableULong(false) != 18446744073709551615n) {
if (provideNullableULong(false) != 18446744073709551615n) {
throw "Fail 15";
}
if (main.provideNullableULong(true) != null) {
if (provideNullableULong(true) != null) {
throw "Fail 16";
}
if (main.consumeUByte(-1) != "255") {
if (consumeUByte(-1) != "255") {
throw "Fail 17";
}
if (main.consumeNullableUByte(-1) != "255") {
if (consumeNullableUByte(-1) != "255") {
throw "Fail 18";
}
if (main.consumeNullableUByte(null) != null) {
if (consumeNullableUByte(null) != null) {
throw "Fail 19";
}
if (main.consumeUShort(-1) != "65535") {
if (consumeUShort(-1) != "65535") {
throw "Fail 20";
}
if (main.consumeNullableUShort(-1) != "65535") {
if (consumeNullableUShort(-1) != "65535") {
throw "Fail 21";
}
if (main.consumeNullableUShort(null) != null) {
if (consumeNullableUShort(null) != null) {
throw "Fail 22";
}
if (main.consumeUInt(-1) != "4294967295") {
if (consumeUInt(-1) != "4294967295") {
throw "Fail 23";
}
if (main.consumeNullableUInt(-1) != "4294967295") {
if (consumeNullableUInt(-1) != "4294967295") {
throw "Fail 24";
}
if (main.consumeNullableUInt(null) != null) {
if (consumeNullableUInt(null) != null) {
throw "Fail 25";
}
if (main.consumeULong(-1n) != "18446744073709551615") {
if (consumeULong(-1n) != "18446744073709551615") {
throw "Fail 26";
}
if (main.consumeNullableULong(-1n) != "18446744073709551615") {
if (consumeNullableULong(-1n) != "18446744073709551615") {
throw "Fail 27";
}
if (main.consumeNullableULong(null) != null) {
if (consumeNullableULong(null) != null) {
throw "Fail 28";
}
if (main.consumeUByte(255) != "255") {
if (consumeUByte(255) != "255") {
throw "Fail 29";
}
if (main.consumeNullableUByte(255) != "255") {
if (consumeNullableUByte(255) != "255") {
throw "Fail 30";
}
if (main.consumeUShort(65535) != "65535") {
if (consumeUShort(65535) != "65535") {
throw "Fail 31";
}
if (main.consumeNullableUShort(65535) != "65535") {
if (consumeNullableUShort(65535) != "65535") {
throw "Fail 32";
}
if (main.consumeUInt(4294967295) != "4294967295") {
if (consumeUInt(4294967295) != "4294967295") {
throw "Fail 33";
}
if (main.consumeNullableUInt(4294967295) != "4294967295") {
if (consumeNullableUInt(4294967295) != "4294967295") {
throw "Fail 34";
}
if (main.consumeULong(18446744073709551615n) != "18446744073709551615") {
if (consumeULong(18446744073709551615n) != "18446744073709551615") {
throw "Fail 35";
}
if (main.consumeNullableULong(18446744073709551615n) != "18446744073709551615") {
if (consumeNullableULong(18446744073709551615n) != "18446744073709551615") {
throw "Fail 36";
}
if (main.consumeUByte(256) != "0") {
if (consumeUByte(256) != "0") {
throw "Fail 37";
}
if (main.consumeNullableUByte(256) != "0") {
if (consumeNullableUByte(256) != "0") {
throw "Fail 38";
}
if (main.consumeUShort(65536) != "0") {
if (consumeUShort(65536) != "0") {
throw "Fail 39";
}
if (main.consumeNullableUShort(65536) != "0") {
if (consumeNullableUShort(65536) != "0") {
throw "Fail 40";
}
if (main.consumeUInt(4294967296) != "0") {
if (consumeUInt(4294967296) != "0") {
throw "Fail 41";
}
if (main.consumeNullableUInt(4294967296) != "0") {
if (consumeNullableUInt(4294967296) != "0") {
throw "Fail 42";
}
if (main.consumeULong(18446744073709551616n) != "0") {
if (consumeULong(18446744073709551616n) != "0") {
throw "Fail 43";
}
if (main.consumeNullableULong(18446744073709551616n) != "0") {
if (consumeNullableULong(18446744073709551616n) != "0") {
throw "Fail 44";
}
+4 -4
View File
@@ -24,19 +24,19 @@ fun throws() {
// FILE: entry.mjs
import wasmExports from "./index.mjs";
import { add, sumNumbers, throws } from "./index.mjs";
if (wasmExports.add(10, 20) !== 30) {
if (add(10, 20) !== 30) {
throw "Fail add";
}
if (wasmExports.sumNumbers(10) !== 55) {
if (sumNumbers(10) !== 55) {
throw "Fail sumNumbers";
}
var thrown = false;
try {
wasmExports.throws();
throws();
} catch(e) {
thrown = true;
}
@@ -55,6 +55,6 @@ fun getResult(): Result<JsString> = getResultInternal()
// FILE: entry.mjs
import main from "./index.mjs";
import { getResult } from "./index.mjs";
if (JSON.stringify(main.getResult()) != "{}") throw new Error("Unexpected result")
if (JSON.stringify(getResult()) != "{}") throw new Error("Unexpected result")
@@ -31,9 +31,9 @@ fun <A, B> complexConstraint(x: A): B where A: Foo<JsBigInt>, A: Bar, B: Baz = g
// FILE: entry.mjs
import main from "./index.mjs";
import { simple, second, simpleWithConstraint, complexConstraint } from "./index.mjs";
if (main.simple("OK") != "OK") throw new Error("Unexpected result from `simple` function")
if (main.second(1, "OK") != "OK") throw new Error("Unexpected result from `second` function")
if (main.simpleWithConstraint(42) != 42) throw new Error("Unexpected result from `simpleConstraint` function")
if (JSON.stringify(main.complexConstraint({ foo: 1n, bar: "bar" })) != "{\"baz\":true}") throw new Error("Unexpected result from `complexConstraint` function")
if (simple("OK") != "OK") throw new Error("Unexpected result from `simple` function")
if (second(1, "OK") != "OK") throw new Error("Unexpected result from `second` function")
if (simpleWithConstraint(42) != 42) throw new Error("Unexpected result from `simpleConstraint` function")
if (JSON.stringify(complexConstraint({ foo: 1n, bar: "bar" })) != "{\"baz\":true}") throw new Error("Unexpected result from `complexConstraint` function")
@@ -35,17 +35,27 @@ fun consumeAny(x: JsAny): String = x.toString()
// FILE: entry.mjs
import main from "./index.mjs"
import {
produceBoolean,
produceNumber,
produceBigInt,
produceString,
produceAny,
consumeBoolean,
consumeNumber,
consumeBigInt,
consumeAny
} from "./index.mjs"
// PRODUCING
if (!main.produceBoolean()) throw new Error("Unexpected value was returned from the `produceBoolean` function")
if (main.produceNumber() != 2147483647) throw new Error("Unexpected value was returned from the `produceNumber` function")
if (main.produceBigInt() != 9223372036854775807n) throw new Error("Unexpected value was returned from the `produceBigInt` function")
if (main.produceString() != "OK") throw new Error("Unexpected value was returned from the `produceString` function")
if (main.produceAny() != 42) throw new Error("Unexpected value was returned from the `produceAny` function")
if (!produceBoolean()) throw new Error("Unexpected value was returned from the `produceBoolean` function")
if (produceNumber() != 2147483647) throw new Error("Unexpected value was returned from the `produceNumber` function")
if (produceBigInt() != 9223372036854775807n) throw new Error("Unexpected value was returned from the `produceBigInt` function")
if (produceString() != "OK") throw new Error("Unexpected value was returned from the `produceString` function")
if (produceAny() != 42) throw new Error("Unexpected value was returned from the `produceAny` function")
// CONSUMPTION
if (main.consumeBoolean(false) != "false") throw new Error("Unexpected value was returned from the `consumeBoolean` function")
if (main.consumeNumber(-2147483648) != "-2147483648") throw new Error("Unexpected value was returned from the `consumeNumber` function")
if (main.consumeBigInt(-9223372036854775808n) != "-9223372036854775808") throw new Error("Unexpected value was returned from the `consumeBigInt` function")
if (main.consumeAny(24) != 24) throw new Error("Unexpected value was returned from the `consumeAny` function")
if (consumeBoolean(false) != "false") throw new Error("Unexpected value was returned from the `consumeBoolean` function")
if (consumeNumber(-2147483648) != "-2147483648") throw new Error("Unexpected value was returned from the `consumeNumber` function")
if (consumeBigInt(-9223372036854775808n) != "-9223372036854775808") throw new Error("Unexpected value was returned from the `consumeBigInt` function")
if (consumeAny(24) != 24) throw new Error("Unexpected value was returned from the `consumeAny` function")
@@ -35,17 +35,27 @@ fun consumeAny(x: JsAny?): String? = x?.toString()
// FILE: entry.mjs
import main from "./index.mjs"
import {
produceBoolean,
produceNumber,
produceBigInt,
produceString,
produceAny,
consumeBoolean,
consumeNumber,
consumeBigInt,
consumeAny,
} from "./index.mjs"
// PRODUCING
if (!main.produceBoolean()) throw new Error("Unexpected value was returned from the `produceBoolean` function")
if (main.produceNumber() != 2147483647) throw new Error("Unexpected value was returned from the `produceNumber` function")
if (main.produceBigInt() != 9223372036854775807n) throw new Error("Unexpected value was returned from the `produceBigInt` function")
if (main.produceString() != "OK") throw new Error("Unexpected value was returned from the `produceString` function")
if (main.produceAny() != 42) throw new Error("Unexpected value was returned from the `produceAny` function")
if (!produceBoolean()) throw new Error("Unexpected value was returned from the `produceBoolean` function")
if (produceNumber() != 2147483647) throw new Error("Unexpected value was returned from the `produceNumber` function")
if (produceBigInt() != 9223372036854775807n) throw new Error("Unexpected value was returned from the `produceBigInt` function")
if (produceString() != "OK") throw new Error("Unexpected value was returned from the `produceString` function")
if (produceAny() != 42) throw new Error("Unexpected value was returned from the `produceAny` function")
// CONSUMPTION
if (main.consumeBoolean(false) != "false") throw new Error("Unexpected value was returned from the `consumeBoolean` function")
if (main.consumeNumber(-2147483648) != "-2147483648") throw new Error("Unexpected value was returned from the `consumeNumber` function")
if (main.consumeBigInt(-9223372036854775808n) != "-9223372036854775808") throw new Error("Unexpected value was returned from the `consumeBigInt` function")
if (main.consumeAny(24) != 24) throw new Error("Unexpected value was returned from the `consumeAny` function")
if (consumeBoolean(false) != "false") throw new Error("Unexpected value was returned from the `consumeBoolean` function")
if (consumeNumber(-2147483648) != "-2147483648") throw new Error("Unexpected value was returned from the `consumeNumber` function")
if (consumeBigInt(-9223372036854775808n) != "-9223372036854775808") throw new Error("Unexpected value was returned from the `consumeBigInt` function")
if (consumeAny(24) != 24) throw new Error("Unexpected value was returned from the `consumeAny` function")
@@ -53,24 +53,41 @@ fun consumeFunction(fn: ((String) -> Int)?): Int? = fn?.invoke("42")
// FILE: entry.mjs
import main from "./index.mjs"
import {
produceBoolean,
produceByte,
produceShort,
produceInt,
produceLong,
produceChar,
produceString,
produceFunction,
consumeBoolean,
consumeByte,
consumeShort,
consumeInt,
consumeLong,
consumeChar,
consumeString,
consumeFunction,
} from "./index.mjs"
// PRODUCING
if (!main.produceBoolean()) throw new Error("Unexpected value was returned from the `produceBoolean` function")
if (main.produceByte() != 127) throw new Error("Unexpected value was returned from the `produceByte` function")
if (main.produceShort() != 32767) throw new Error("Unexpected value was returned from the `produceShort` function")
if (main.produceInt() != 2147483647) throw new Error("Unexpected value was returned from the `produceInt` function")
if (main.produceLong() != 9223372036854775807n) throw new Error("Unexpected value was returned from the `produceLong` function")
if (String.fromCharCode(main.produceChar()) != "a") throw new Error("Unexpected value was returned from the `produceChar` function")
if (main.produceString() != "OK") throw new Error("Unexpected value was returned from the `produceString` function")
if (main.produceFunction()() != 42) throw new Error("Unexpected value was returned from the `produceFunction` function")
if (!produceBoolean()) throw new Error("Unexpected value was returned from the `produceBoolean` function")
if (produceByte() != 127) throw new Error("Unexpected value was returned from the `produceByte` function")
if (produceShort() != 32767) throw new Error("Unexpected value was returned from the `produceShort` function")
if (produceInt() != 2147483647) throw new Error("Unexpected value was returned from the `produceInt` function")
if (produceLong() != 9223372036854775807n) throw new Error("Unexpected value was returned from the `produceLong` function")
if (String.fromCharCode(produceChar()) != "a") throw new Error("Unexpected value was returned from the `produceChar` function")
if (produceString() != "OK") throw new Error("Unexpected value was returned from the `produceString` function")
if (produceFunction()() != 42) throw new Error("Unexpected value was returned from the `produceFunction` function")
// CONSUMPTION
if (main.consumeBoolean(false) != "false") throw new Error("Unexpected value was returned from the `consumeBoolean` function")
if (main.consumeByte(-128) != "-128") throw new Error("Unexpected value was returned from the `consumeByte` function")
if (main.consumeShort(-32768) != "-32768") throw new Error("Unexpected value was returned from the `consumeShort` function")
if (main.consumeInt(-2147483648) != "-2147483648") throw new Error("Unexpected value was returned from the `consumeInt` function")
if (main.consumeLong(-9223372036854775808n) != "-9223372036854775808") throw new Error("Unexpected value was returned from the `consumeLong` function")
if (main.consumeChar("b".charCodeAt()) != "b") throw new Error("Unexpected value was returned from the `consumeChar` function")
if (main.consumeString("🙂") != "🙂") throw new Error("Unexpected value was returned from the `consumeString` function")
if (main.consumeFunction(parseInt) != 42) throw new Error("Unexpected value was returned from the `consumeFunction` function")
if (consumeBoolean(false) != "false") throw new Error("Unexpected value was returned from the `consumeBoolean` function")
if (consumeByte(-128) != "-128") throw new Error("Unexpected value was returned from the `consumeByte` function")
if (consumeShort(-32768) != "-32768") throw new Error("Unexpected value was returned from the `consumeShort` function")
if (consumeInt(-2147483648) != "-2147483648") throw new Error("Unexpected value was returned from the `consumeInt` function")
if (consumeLong(-9223372036854775808n) != "-9223372036854775808") throw new Error("Unexpected value was returned from the `consumeLong` function")
if (consumeChar("b".charCodeAt()) != "b") throw new Error("Unexpected value was returned from the `consumeChar` function")
if (consumeString("🙂") != "🙂") throw new Error("Unexpected value was returned from the `consumeString` function")
if (consumeFunction(parseInt) != 42) throw new Error("Unexpected value was returned from the `consumeFunction` function")
@@ -35,18 +35,29 @@ fun consumeFunction(fn: (String) -> UInt?): UInt? = fn("42")
// FILE: entry.mjs
import main from "./index.mjs"
import {
produceUByte,
produceUShort,
produceUInt,
produceULong,
produceFunction,
consumeUByte,
consumeUShort,
consumeUInt,
consumeULong,
consumeFunction,
} from "./index.mjs"
// PRODUCING
if (main.produceUByte() != 255) throw new Error("Unexpected value was returned from the `produceUByte` function")
if (main.produceUShort() != 65535) throw new Error("Unexpected value was returned from the `produceUShort` function")
if (main.produceUInt() != 4294967295) throw new Error("Unexpected value was returned from the `produceUInt` function")
if (main.produceULong() != 18446744073709551615n) throw new Error("Unexpected value was returned from the `produceULong` function")
if (main.produceFunction()() != 4294967295) throw new Error("Unexpected value was returned from the `produceFunction` function")
if (produceUByte() != 255) throw new Error("Unexpected value was returned from the `produceUByte` function")
if (produceUShort() != 65535) throw new Error("Unexpected value was returned from the `produceUShort` function")
if (produceUInt() != 4294967295) throw new Error("Unexpected value was returned from the `produceUInt` function")
if (produceULong() != 18446744073709551615n) throw new Error("Unexpected value was returned from the `produceULong` function")
if (produceFunction()() != 4294967295) throw new Error("Unexpected value was returned from the `produceFunction` function")
// CONSUMPTION
if (main.consumeUByte(-128) != "128") throw new Error("Unexpected value was returned from the `consumeUByte` function")
if (main.consumeUShort(-32768) != "32768") throw new Error("Unexpected value was returned from the `consumeUShort` function")
if (main.consumeUInt(-2147483648) != "2147483648") throw new Error("Unexpected value was returned from the `consumeUInt` function")
if (main.consumeULong(-9223372036854775808n) != "9223372036854775808") throw new Error("Unexpected value was returned from the `consumeULong` function")
if (main.consumeFunction(parseInt) != 42) throw new Error("Unexpected value was returned from the `consumeFunction` function")
if (consumeUByte(-128) != "128") throw new Error("Unexpected value was returned from the `consumeUByte` function")
if (consumeUShort(-32768) != "32768") throw new Error("Unexpected value was returned from the `consumeUShort` function")
if (consumeUInt(-2147483648) != "2147483648") throw new Error("Unexpected value was returned from the `consumeUInt` function")
if (consumeULong(-9223372036854775808n) != "9223372036854775808") throw new Error("Unexpected value was returned from the `consumeULong` function")
if (consumeFunction(parseInt) != 42) throw new Error("Unexpected value was returned from the `consumeFunction` function")
@@ -63,27 +63,46 @@ fun consumeFunction(fn: (String) -> Int): Int = fn("42")
// FILE: entry.mjs
import main from "./index.mjs"
import {
produceBoolean,
produceByte,
produceShort,
produceInt,
produceLong,
produceChar,
produceString,
getState,
mutateState,
produceFunction,
consumeBoolean,
consumeByte,
consumeShort,
consumeInt,
consumeLong,
consumeChar,
consumeString,
consumeFunction,
} from "./index.mjs"
// PRODUCING
if (!main.produceBoolean()) throw new Error("Unexpected value was returned from the `produceBoolean` function")
if (main.produceByte() != 127) throw new Error("Unexpected value was returned from the `produceByte` function")
if (main.produceShort() != 32767) throw new Error("Unexpected value was returned from the `produceShort` function")
if (main.produceInt() != 2147483647) throw new Error("Unexpected value was returned from the `produceInt` function")
if (main.produceLong() != 9223372036854775807n) throw new Error("Unexpected value was returned from the `produceLong` function")
if (String.fromCharCode(main.produceChar()) != "a") throw new Error("Unexpected value was returned from the `produceChar` function")
if (main.produceString() != "OK") throw new Error("Unexpected value was returned from the `produceString` function")
if (main.getState() != "INITIAL") throw new Error("Unexpected value was returned from the `getState` function before the mutation")
main.mutateState()
if (main.getState() != "MUTATED") throw new Error("Unexpected value was returned from the `getState` function after the mutation")
if (main.produceFunction()() != 2147483647) throw new Error("Unexpected value was returned from the `produceFunction` function")
if (!produceBoolean()) throw new Error("Unexpected value was returned from the `produceBoolean` function")
if (produceByte() != 127) throw new Error("Unexpected value was returned from the `produceByte` function")
if (produceShort() != 32767) throw new Error("Unexpected value was returned from the `produceShort` function")
if (produceInt() != 2147483647) throw new Error("Unexpected value was returned from the `produceInt` function")
if (produceLong() != 9223372036854775807n) throw new Error("Unexpected value was returned from the `produceLong` function")
if (String.fromCharCode(produceChar()) != "a") throw new Error("Unexpected value was returned from the `produceChar` function")
if (produceString() != "OK") throw new Error("Unexpected value was returned from the `produceString` function")
if (getState() != "INITIAL") throw new Error("Unexpected value was returned from the `getState` function before the mutation")
mutateState()
if (getState() != "MUTATED") throw new Error("Unexpected value was returned from the `getState` function after the mutation")
if (produceFunction()() != 2147483647) throw new Error("Unexpected value was returned from the `produceFunction` function")
// CONSUMPTION
if (main.consumeBoolean(false) != "false") throw new Error("Unexpected value was returned from the `consumeBoolean` function")
if (main.consumeByte(-128) != "-128") throw new Error("Unexpected value was returned from the `consumeByte` function")
if (main.consumeShort(-32768) != "-32768") throw new Error("Unexpected value was returned from the `consumeShort` function")
if (main.consumeInt(-2147483648) != "-2147483648") throw new Error("Unexpected value was returned from the `consumeInt` function")
if (main.consumeLong(-9223372036854775808n) != "-9223372036854775808") throw new Error("Unexpected value was returned from the `consumeLong` function")
if (main.consumeChar("b".charCodeAt()) != "b") throw new Error("Unexpected value was returned from the `consumeChar` function")
if (main.consumeString("🙂") != "🙂") throw new Error("Unexpected value was returned from the `consumeString` function")
if (main.consumeFunction(parseInt) != 42) throw new Error("Unexpected value was returned from the `consumeFunction` function")
if (consumeBoolean(false) != "false") throw new Error("Unexpected value was returned from the `consumeBoolean` function")
if (consumeByte(-128) != "-128") throw new Error("Unexpected value was returned from the `consumeByte` function")
if (consumeShort(-32768) != "-32768") throw new Error("Unexpected value was returned from the `consumeShort` function")
if (consumeInt(-2147483648) != "-2147483648") throw new Error("Unexpected value was returned from the `consumeInt` function")
if (consumeLong(-9223372036854775808n) != "-9223372036854775808") throw new Error("Unexpected value was returned from the `consumeLong` function")
if (consumeChar("b".charCodeAt()) != "b") throw new Error("Unexpected value was returned from the `consumeChar` function")
if (consumeString("🙂") != "🙂") throw new Error("Unexpected value was returned from the `consumeString` function")
if (consumeFunction(parseInt) != 42) throw new Error("Unexpected value was returned from the `consumeFunction` function")
@@ -35,18 +35,29 @@ fun consumeFunction(fn: (String) -> UInt): UInt = fn("42")
// FILE: entry.mjs
import main from "./index.mjs"
import {
produceUByte,
produceUShort,
produceUInt,
produceULong,
produceFunction,
consumeUByte,
consumeUShort,
consumeUInt,
consumeULong,
consumeFunction,
} from "./index.mjs"
// PRODUCING
if (main.produceUByte() != 255) throw new Error("Unexpected value was returned from the `produceUByte` function")
if (main.produceUShort() != 65535) throw new Error("Unexpected value was returned from the `produceUShort` function")
if (main.produceUInt() != 4294967295) throw new Error("Unexpected value was returned from the `produceUInt` function")
if (main.produceULong() != 18446744073709551615n) throw new Error("Unexpected value was returned from the `produceULong` function")
if (main.produceFunction()() != 4294967295) throw new Error("Unexpected value was returned from the `produceFunction` function")
if (produceUByte() != 255) throw new Error("Unexpected value was returned from the `produceUByte` function")
if (produceUShort() != 65535) throw new Error("Unexpected value was returned from the `produceUShort` function")
if (produceUInt() != 4294967295) throw new Error("Unexpected value was returned from the `produceUInt` function")
if (produceULong() != 18446744073709551615n) throw new Error("Unexpected value was returned from the `produceULong` function")
if (produceFunction()() != 4294967295) throw new Error("Unexpected value was returned from the `produceFunction` function")
// CONSUMPTION
if (main.consumeUByte(-128) != "128") throw new Error("Unexpected value was returned from the `consumeUByte` function")
if (main.consumeUShort(-32768) != "32768") throw new Error("Unexpected value was returned from the `consumeUShort` function")
if (main.consumeUInt(-2147483648) != "2147483648") throw new Error("Unexpected value was returned from the `consumeUInt` function")
if (main.consumeULong(-9223372036854775808n) != "9223372036854775808") throw new Error("Unexpected value was returned from the `consumeULong` function")
if (main.consumeFunction(parseInt) != 42) throw new Error("Unexpected value was returned from the `consumeFunction` function")
if (consumeUByte(-128) != "128") throw new Error("Unexpected value was returned from the `consumeUByte` function")
if (consumeUShort(-32768) != "32768") throw new Error("Unexpected value was returned from the `consumeUShort` function")
if (consumeUInt(-2147483648) != "2147483648") throw new Error("Unexpected value was returned from the `consumeUInt` function")
if (consumeULong(-9223372036854775808n) != "9223372036854775808") throw new Error("Unexpected value was returned from the `consumeULong` function")
if (consumeFunction(parseInt) != 42) throw new Error("Unexpected value was returned from the `consumeFunction` function")
@@ -69,8 +69,8 @@ internal fun writeWasmUnitTestRunner(compiledFile: File): File {
val testRunnerFile = compiledFile.parentFile.resolve("runUnitTests.mjs")
testRunnerFile.writeText(
"""
import exports from './${compiledFile.name}';
exports.startUnitTests?.();
import { startUnitTests } from './${compiledFile.name}';
startUnitTests?.();
""".trimIndent()
)
return testRunnerFile
@@ -42,9 +42,8 @@ class WasmBoxRunner(
try {
// Use "dynamic import" to catch exception happened during JS & Wasm modules initialization
let jsModule = await import('./index.mjs');
let wasmExports = jsModule.default;
${if (startUnitTests) "wasmExports.startUnitTests();" else ""}
actualResult = wasmExports.box();
${if (startUnitTests) "jsModule.startUnitTests();" else ""}
actualResult = jsModule.box();
} catch(e) {
console.log('Failed with exception!')
console.log('Message: ' + e.message)