[WASM] Support for mjs universal launcher
This commit is contained in:
-7
@@ -249,13 +249,6 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value = "-Xwasm-debug-info", description = "Add debug info to WebAssembly compiled module")
|
||||
var wasmDebug: Boolean by FreezableVar(true)
|
||||
|
||||
@Argument(
|
||||
value = "-Xwasm-launcher",
|
||||
valueDescription = "esm|nodejs|d8",
|
||||
description = "Picks flavor for the wasm launcher. Default is ESM."
|
||||
)
|
||||
var wasmLauncher: String? by NullableStringFreezableVar("esm")
|
||||
|
||||
@Argument(value = "-Xwasm-kclass-fqn", description = "Enable support for FQ names in KClass")
|
||||
var wasmKClassFqn: Boolean by FreezableVar(false)
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.backend.common.CompilationException
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmLoaderKind
|
||||
import org.jetbrains.kotlin.backend.wasm.compileWasm
|
||||
import org.jetbrains.kotlin.backend.wasm.compileToLoweredIr
|
||||
import org.jetbrains.kotlin.backend.wasm.wasmPhases
|
||||
@@ -362,18 +361,9 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
generateWat = true,
|
||||
)
|
||||
|
||||
val launcherKind = when (arguments.wasmLauncher) {
|
||||
"esm" -> WasmLoaderKind.BROWSER
|
||||
"nodejs" -> WasmLoaderKind.NODE
|
||||
"d8" -> WasmLoaderKind.D8
|
||||
"d8NodeCompatible" -> WasmLoaderKind.D8NodeCompatible
|
||||
else -> throw IllegalArgumentException("Unrecognized flavor for the wasm launcher")
|
||||
}
|
||||
|
||||
writeCompilationResult(
|
||||
result = res,
|
||||
dir = outputFile.parentFile,
|
||||
loaderKind = launcherKind,
|
||||
fileNameBase = outputFile.nameWithoutExtension
|
||||
)
|
||||
|
||||
|
||||
@@ -120,66 +120,49 @@ fun WasmCompiledModuleFragment.generateJs(): String {
|
||||
return runtime + jsCode
|
||||
}
|
||||
|
||||
enum class WasmLoaderKind {
|
||||
D8,
|
||||
D8NodeCompatible,
|
||||
NODE,
|
||||
BROWSER,
|
||||
}
|
||||
|
||||
fun generateJsWasmLoader(kind: WasmLoaderKind, wasmFilePath: String, externalJs: String): String {
|
||||
val nodeExitOnD8 =
|
||||
if (kind == WasmLoaderKind.D8NodeCompatible) "if ((typeof process !== 'undefined') && (typeof process.versions.node !== 'undefined')) process.exit(0)\n"
|
||||
else ""
|
||||
|
||||
val instantiation = when (kind) {
|
||||
WasmLoaderKind.D8, WasmLoaderKind.D8NodeCompatible ->
|
||||
"""
|
||||
const wasmModule = new WebAssembly.Module(read('$wasmFilePath', 'binary'));
|
||||
const wasmInstance = new WebAssembly.Instance(wasmModule, { js_code });
|
||||
""".trimIndent()
|
||||
|
||||
WasmLoaderKind.NODE ->
|
||||
"""
|
||||
const fs = require('fs');
|
||||
var path = require('path');
|
||||
const wasmBuffer = fs.readFileSync(path.resolve(__dirname, './$wasmFilePath'));
|
||||
const wasmModule = new WebAssembly.Module(wasmBuffer);
|
||||
const wasmInstance = new WebAssembly.Instance(wasmModule, { js_code });
|
||||
""".trimIndent()
|
||||
|
||||
WasmLoaderKind.BROWSER ->
|
||||
"""
|
||||
const { instance: wasmInstance } = await WebAssembly.instantiateStreaming(fetch("$wasmFilePath"), { js_code });
|
||||
""".trimIndent()
|
||||
fun generateJsWasmLoader(wasmFilePath: String, externalJs: String): String =
|
||||
externalJs + """
|
||||
|
||||
const isNodeJs = (typeof process !== 'undefined') && (process.release.name === 'node');
|
||||
const isD8 = !isNodeJs && (typeof d8 !== 'undefined');
|
||||
const isBrowser = !isNodeJs && !isD8 && (typeof window !== 'undefined');
|
||||
|
||||
if (!isNodeJs && !isD8 && !isBrowser) {
|
||||
throw "Supported JS engine not detected";
|
||||
}
|
||||
|
||||
val init =
|
||||
"""
|
||||
|
||||
const wasmExports = wasmInstance.exports;
|
||||
wasmExports.__init();
|
||||
wasmExports.startUnitTests?.();
|
||||
|
||||
""".trimIndent()
|
||||
|
||||
val export = when (kind) {
|
||||
WasmLoaderKind.D8, WasmLoaderKind.BROWSER ->
|
||||
"export default wasmExports;\n"
|
||||
|
||||
WasmLoaderKind.NODE ->
|
||||
"module.exports = wasmExports;\n"
|
||||
|
||||
WasmLoaderKind.D8NodeCompatible -> ""
|
||||
|
||||
let wasmInstance;
|
||||
let require; // Placed here to give access to it from externals (js_code)
|
||||
if (isNodeJs) {
|
||||
const module = await import('node:module');
|
||||
require = module.createRequire(import.meta.url);
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
||||
const wasmBuffer = fs.readFileSync(path.resolve(__dirname, './$wasmFilePath'));
|
||||
const wasmModule = new WebAssembly.Module(wasmBuffer);
|
||||
wasmInstance = new WebAssembly.Instance(wasmModule, { js_code });
|
||||
}
|
||||
|
||||
return nodeExitOnD8 + externalJs + instantiation + init + export
|
||||
}
|
||||
|
||||
if (isD8) {
|
||||
const wasmBuffer = read('$wasmFilePath', 'binary');
|
||||
const wasmModule = new WebAssembly.Module(wasmBuffer);
|
||||
wasmInstance = new WebAssembly.Instance(wasmModule, { js_code });
|
||||
}
|
||||
|
||||
if (isBrowser) {
|
||||
wasmInstance = (await WebAssembly.instantiateStreaming(fetch('$wasmFilePath'), { js_code })).instance;
|
||||
}
|
||||
|
||||
const wasmExports = wasmInstance.exports;
|
||||
wasmExports.__init();
|
||||
export default wasmExports;
|
||||
""".trimIndent()
|
||||
|
||||
fun writeCompilationResult(
|
||||
result: WasmCompilerResult,
|
||||
dir: File,
|
||||
loaderKind: WasmLoaderKind,
|
||||
fileNameBase: String = "index",
|
||||
) {
|
||||
dir.mkdirs()
|
||||
@@ -187,6 +170,7 @@ fun writeCompilationResult(
|
||||
File(dir, "$fileNameBase.wat").writeText(result.wat)
|
||||
}
|
||||
File(dir, "$fileNameBase.wasm").writeBytes(result.wasm)
|
||||
val jsWithLoader = generateJsWasmLoader(loaderKind, "./$fileNameBase.wasm", result.js)
|
||||
File(dir, "$fileNameBase.js").writeText(jsWithLoader)
|
||||
|
||||
val jsWithLoader = generateJsWasmLoader("./$fileNameBase.wasm", result.js)
|
||||
File(dir, "$fileNameBase.mjs").writeText(jsWithLoader)
|
||||
}
|
||||
|
||||
-1
@@ -45,7 +45,6 @@ where advanced options include:
|
||||
Turn on range checks for the array access functions
|
||||
-Xwasm-enable-asserts Turn on asserts
|
||||
-Xwasm-kclass-fqn Enable support for FQ names in KClass
|
||||
-Xwasm-launcher=esm|nodejs|d8 Picks flavor for the wasm launcher. Default is ESM.
|
||||
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
|
||||
-Xallow-result-return-type Allow compiling code when `kotlin.Result` is used as a return type
|
||||
-Xbuiltins-from-sources Compile builtIns from sources
|
||||
|
||||
Reference in New Issue
Block a user