@twinkle-lang/twinkle 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/runtime.mjs +60 -12
package/package.json
CHANGED
package/runtime.mjs
CHANGED
|
@@ -208,15 +208,17 @@ function readExternMeta(wasmModule) {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
function
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return;
|
|
211
|
+
function importListFromExternMeta(externMeta) {
|
|
212
|
+
const list = [];
|
|
213
|
+
for (const [module, entries] of Object.entries(externMeta)) {
|
|
214
|
+
for (const name of Object.keys(entries)) {
|
|
215
|
+
list.push({ module, name, kind: "function" });
|
|
216
|
+
}
|
|
218
217
|
}
|
|
218
|
+
return list;
|
|
219
|
+
}
|
|
219
220
|
|
|
221
|
+
function bridgeExternImports(importList, hostImports, b, jspi = false, imports = {}, externMeta = {}) {
|
|
220
222
|
const { found, missing } = resolveExternImports(importList, hostImports, imports);
|
|
221
223
|
|
|
222
224
|
if (missing.length > 0) {
|
|
@@ -292,6 +294,52 @@ function autoBridgeExternImports(wasmModule, hostImports, b, jspi = false, impor
|
|
|
292
294
|
}
|
|
293
295
|
}
|
|
294
296
|
|
|
297
|
+
function autoBridgeExternImports(wasmModule, hostImports, b, jspi = false, imports = {}, externMeta = {}) {
|
|
298
|
+
let importList;
|
|
299
|
+
try {
|
|
300
|
+
importList = WebAssembly.Module.imports(wasmModule);
|
|
301
|
+
} catch {
|
|
302
|
+
// Some browsers (notably Safari on Wasm GC modules) can instantiate a module
|
|
303
|
+
// but reject import introspection. Twinkle modules carry their extern ABI in
|
|
304
|
+
// a custom section, so use that as the browser fallback instead of leaving
|
|
305
|
+
// extern modules absent from the import object.
|
|
306
|
+
importList = importListFromExternMeta(externMeta);
|
|
307
|
+
}
|
|
308
|
+
bridgeExternImports(importList, hostImports, b, jspi, imports, externMeta);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function missingImportFromError(e) {
|
|
312
|
+
const msg = e?.message ?? "";
|
|
313
|
+
const match = msg.match(/import\s+([^\s:]+):([^\s]+)\s+must be an object/)
|
|
314
|
+
?? msg.match(/Import #[0-9]+ module="([^"]+)" function="([^"]+)"/)
|
|
315
|
+
?? msg.match(/Import #[0-9]+ "([^"]+)" "([^"]+)"/);
|
|
316
|
+
if (match) return { module: match[1], name: match[2], kind: "function" };
|
|
317
|
+
const moduleOnly = msg.match(/Import #[0-9]+ "([^"]+)": module is not an object or function/);
|
|
318
|
+
if (moduleOnly) return { module: moduleOnly[1], name: null, kind: "function" };
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function instantiateWithExternRetry(mainModule, hostImports, b, jspi, imports, externMeta) {
|
|
323
|
+
// Last-ditch Safari fallback: if both Module.imports() and customSections()
|
|
324
|
+
// are unavailable for a GC module, instantiate once, read the missing import
|
|
325
|
+
// from the LinkError text, bridge it, and retry. This preserves globalThis
|
|
326
|
+
// fallback for common browser globals such as performance/Math.
|
|
327
|
+
for (let i = 0; i < 64; i++) {
|
|
328
|
+
try {
|
|
329
|
+
return new WebAssembly.Instance(mainModule, hostImports);
|
|
330
|
+
} catch (e) {
|
|
331
|
+
const imp = missingImportFromError(e);
|
|
332
|
+
if (!imp) throw e;
|
|
333
|
+
if (imp.name === null) {
|
|
334
|
+
hostImports[imp.module] = {};
|
|
335
|
+
} else {
|
|
336
|
+
bridgeExternImports([imp], hostImports, b, jspi, imports, externMeta);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
throw new Error("too many missing WebAssembly imports while instantiating");
|
|
341
|
+
}
|
|
342
|
+
|
|
295
343
|
// ---------------------------------------------------------------------------
|
|
296
344
|
// Host imports
|
|
297
345
|
// ---------------------------------------------------------------------------
|
|
@@ -521,7 +569,7 @@ function prepareWasm(wasmBytes, opts, { jspi = false } = {}) {
|
|
|
521
569
|
const externMeta = readExternMeta(mainModule);
|
|
522
570
|
autoBridgeExternImports(mainModule, hostImports, b, jspi, imports, externMeta);
|
|
523
571
|
|
|
524
|
-
return { mainModule, hostImports, b, runtime };
|
|
572
|
+
return { mainModule, hostImports, b, runtime, imports, externMeta, jspi };
|
|
525
573
|
}
|
|
526
574
|
|
|
527
575
|
// ---------------------------------------------------------------------------
|
|
@@ -529,9 +577,9 @@ function prepareWasm(wasmBytes, opts, { jspi = false } = {}) {
|
|
|
529
577
|
// ---------------------------------------------------------------------------
|
|
530
578
|
|
|
531
579
|
export function runWasmBytes(wasmBytes, opts = {}) {
|
|
532
|
-
const { mainModule, hostImports } = prepareWasm(wasmBytes, opts);
|
|
580
|
+
const { mainModule, hostImports, b, imports, externMeta, jspi } = prepareWasm(wasmBytes, opts);
|
|
533
581
|
try {
|
|
534
|
-
const instance =
|
|
582
|
+
const instance = instantiateWithExternRetry(mainModule, hostImports, b, jspi, imports, externMeta);
|
|
535
583
|
// Boot-compiled modules export __twinkle_start instead of using a Wasm
|
|
536
584
|
// start section. Stage0-compiled modules still use the start section and
|
|
537
585
|
// run during instantiation above.
|
|
@@ -552,7 +600,7 @@ export function runWasmBytes(wasmBytes, opts = {}) {
|
|
|
552
600
|
// ---------------------------------------------------------------------------
|
|
553
601
|
|
|
554
602
|
export async function runWasmBytesAsync(wasmBytes, opts = {}) {
|
|
555
|
-
const { mainModule, hostImports, b, runtime } = prepareWasm(wasmBytes, opts, { jspi: hasJspi });
|
|
603
|
+
const { mainModule, hostImports, b, runtime, imports, externMeta, jspi } = prepareWasm(wasmBytes, opts, { jspi: hasJspi });
|
|
556
604
|
|
|
557
605
|
if (hasJspi) {
|
|
558
606
|
// Wrap stdin reads as suspending imports so the event loop stays free while
|
|
@@ -593,7 +641,7 @@ export async function runWasmBytesAsync(wasmBytes, opts = {}) {
|
|
|
593
641
|
}
|
|
594
642
|
|
|
595
643
|
try {
|
|
596
|
-
const instance =
|
|
644
|
+
const instance = instantiateWithExternRetry(mainModule, hostImports, b, jspi, imports, externMeta);
|
|
597
645
|
if (instance.exports.__twinkle_start) {
|
|
598
646
|
if (hasJspi) {
|
|
599
647
|
const start = WebAssembly.promising(instance.exports.__twinkle_start);
|