Skip to content

Commit 6a1b87a

Browse files
refactor: wasm init handling
Signed-off-by: Victor Adossi <vadossi@cosmonic.com>
1 parent 1da22e3 commit 6a1b87a

File tree

1 file changed

+129
-70
lines changed

1 file changed

+129
-70
lines changed

src/componentize.js

Lines changed: 129 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -328,76 +328,8 @@ export async function componentize(
328328

329329
await tmpdirRemovePromise;
330330

331-
async function initWasm(bin) {
332-
const eep = (name) => () => {
333-
throw new Error(
334-
`Internal error: unexpected call to "${name}" during Wasm verification`,
335-
);
336-
};
337-
338-
let stderr = '';
339-
const wasmModule = await WebAssembly.compile(bin);
340-
341-
const mockImports = {
342-
// "wasi-logging2": {
343-
// log: eep("log"),
344-
// },
345-
wasi_snapshot_preview1: {
346-
fd_write: function (fd, iovs, iovs_len, nwritten) {
347-
if (fd !== 2) return 0;
348-
const mem = new DataView(exports.memory.buffer);
349-
let written = 0;
350-
for (let i = 0; i < iovs_len; i++) {
351-
const bufPtr = mem.getUint32(iovs + i * 8, true);
352-
const bufLen = mem.getUint32(iovs + 4 + i * 8, true);
353-
stderr += new TextDecoder().decode(
354-
new Uint8Array(exports.memory.buffer, bufPtr, bufLen),
355-
);
356-
written += bufLen;
357-
}
358-
mem.setUint32(nwritten, written, true);
359-
return 1;
360-
},
361-
},
362-
};
363-
364-
for (const { module, name } of WebAssembly.Module.imports(wasmModule)) {
365-
mockImports[module] = mockImports[module] || {};
366-
if (!mockImports[module][name]) mockImports[module][name] = eep(name);
367-
}
368-
369-
const { exports } = await WebAssembly.instantiate(wasmModule, mockImports);
370-
return {
371-
exports,
372-
getStderr() {
373-
return stderr;
374-
},
375-
};
376-
}
377-
378-
const status = check_init();
379-
let err = null;
380-
switch (status) {
381-
case CHECK_INIT_RETURN_OK:
382-
break;
383-
case CHECK_INIT_RETURN_FN_LIST:
384-
err = `Unable to extract expected exports list`;
385-
break;
386-
case CHECK_INIT_RETURN_TYPE_PARSE:
387-
err = `Unable to parse the core ABI export types`;
388-
break;
389-
default:
390-
err = `Unknown error during initialization: ${status}`;
391-
}
392-
393-
if (err) {
394-
let msg = err;
395-
const stderr = getStderr();
396-
if (stderr) {
397-
msg += `\n${stripLinesPrefixes(stderr, [new RegExp(`${initializerPath}[:\\d]* ?`)], tmpDir)}`;
398-
}
399-
throw new Error(msg);
400-
}
331+
/// Process output of check init, throwing if necessary
332+
handleCheckInitOutput(check_init(), initializerPath, workDir, getStderr);
401333

402334
// after wizening, stub out the wasi imports depending on what features are enabled
403335
const finalBin = stubWasi(
@@ -498,3 +430,130 @@ function isNumeric(n) {
498430
}
499431
}
500432

433+
/**
434+
* Initialize a WebAssembly binary, given the
435+
*
436+
* @param {Buffer} bin - WebAssembly binary bytes
437+
* @throws If a binary is invalid
438+
*/
439+
async function initWasm(bin) {
440+
const eep = (name) => () => {
441+
throw new Error(
442+
`Internal error: unexpected call to "${name}" during Wasm verification`,
443+
);
444+
};
445+
446+
let stderr = '';
447+
const wasmModule = await WebAssembly.compile(bin);
448+
449+
const mockImports = {
450+
// "wasi-logging2": {
451+
// log: eep("log"),
452+
// },
453+
wasi_snapshot_preview1: {
454+
fd_write: function (fd, iovs, iovs_len, nwritten) {
455+
if (fd !== 2) return 0;
456+
const mem = new DataView(exports.memory.buffer);
457+
let written = 0;
458+
for (let i = 0; i < iovs_len; i++) {
459+
const bufPtr = mem.getUint32(iovs + i * 8, true);
460+
const bufLen = mem.getUint32(iovs + 4 + i * 8, true);
461+
stderr += new TextDecoder().decode(
462+
new Uint8Array(exports.memory.buffer, bufPtr, bufLen),
463+
);
464+
written += bufLen;
465+
}
466+
mem.setUint32(nwritten, written, true);
467+
return 1;
468+
},
469+
},
470+
};
471+
472+
for (const { module, name } of WebAssembly.Module.imports(wasmModule)) {
473+
mockImports[module] = mockImports[module] || {};
474+
if (!mockImports[module][name]) mockImports[module][name] = eep(name);
475+
}
476+
477+
const { exports } = await WebAssembly.instantiate(wasmModule, mockImports);
478+
return {
479+
exports,
480+
getStderr() {
481+
return stderr;
482+
},
483+
};
484+
}
485+
486+
/**
487+
* Handle the output of `check_init()`
488+
*
489+
* @param {number} status - output of check_init
490+
* @param {string} initializerPath
491+
* @param {string} workDir
492+
* @param {() => string} getStderr - A function that resolves to the stderr output of check init
493+
*/
494+
async function handleCheckInitOutput(
495+
status,
496+
initializerPath,
497+
workDir,
498+
getStderr,
499+
) {
500+
let err = null;
501+
switch (status) {
502+
case CHECK_INIT_RETURN_OK:
503+
break;
504+
case CHECK_INIT_RETURN_FN_LIST:
505+
err = `Unable to extract expected exports list`;
506+
break;
507+
case CHECK_INIT_RETURN_TYPE_PARSE:
508+
err = `Unable to parse the core ABI export types`;
509+
break;
510+
default:
511+
err = `Unknown error during initialization: ${status}`;
512+
}
513+
514+
if (err) {
515+
let msg = err;
516+
const stderr = getStderr();
517+
if (stderr) {
518+
msg += `\n${stripLinesPrefixes(stderr, [new RegExp(`${initializerPath}[:\\d]* ?`)], workDir)}`;
519+
}
520+
throw new Error(msg);
521+
}
522+
523+
// after wizening, stub out the wasi imports depending on what features are enabled
524+
const finalBin = stubWasi(
525+
bin,
526+
features,
527+
witWorld,
528+
maybeWindowsPath(witPath),
529+
worldName,
530+
);
531+
532+
if (debugBindings) {
533+
await writeFile('binary.wasm', finalBin);
534+
}
535+
536+
const component = await metadataAdd(
537+
await componentNew(
538+
finalBin,
539+
Object.entries({
540+
wasi_snapshot_preview1: await readFile(preview2Adapter),
541+
}),
542+
false,
543+
),
544+
Object.entries({
545+
language: [['JavaScript', '']],
546+
'processed-by': [['ComponentizeJS', version]],
547+
}),
548+
);
549+
550+
// convert CABI import conventions to ESM import conventions
551+
imports = imports.map(([specifier, impt]) =>
552+
specifier === '$root' ? [impt, 'default'] : [specifier, impt],
553+
);
554+
555+
return {
556+
component,
557+
imports,
558+
};
559+
}

0 commit comments

Comments
 (0)