mirror of
https://github.com/nodejs/node.git
synced 2024-11-29 23:16:30 +01:00
6ca6db105d
_start() and _initialize() shouldn't be called from the same function, as they have different behavior. Furthermore, Node should throw if both are provided. This commit updates the implementation, docs, and tests accordingly. PR-URL: https://github.com/nodejs/node/pull/33073 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Gus Caplan <me@gus.host>
131 lines
3.3 KiB
JavaScript
131 lines
3.3 KiB
JavaScript
'use strict';
|
|
/* global WebAssembly */
|
|
const {
|
|
ArrayPrototypeMap,
|
|
ArrayPrototypePush,
|
|
FunctionPrototypeBind,
|
|
ObjectEntries,
|
|
Symbol,
|
|
} = primordials;
|
|
|
|
const {
|
|
ERR_INVALID_ARG_TYPE,
|
|
ERR_WASI_ALREADY_STARTED
|
|
} = require('internal/errors').codes;
|
|
const { emitExperimentalWarning } = require('internal/util');
|
|
const {
|
|
validateArray,
|
|
validateBoolean,
|
|
validateObject,
|
|
} = require('internal/validators');
|
|
const { WASI: _WASI } = internalBinding('wasi');
|
|
const kExitCode = Symbol('exitCode');
|
|
const kSetMemory = Symbol('setMemory');
|
|
const kStarted = Symbol('started');
|
|
|
|
emitExperimentalWarning('WASI');
|
|
|
|
|
|
class WASI {
|
|
constructor(options = {}) {
|
|
validateObject(options, 'options');
|
|
|
|
if (options.args !== undefined)
|
|
validateArray(options.args, 'options.args');
|
|
const args = ArrayPrototypeMap(options.args || [], String);
|
|
|
|
const env = [];
|
|
if (options.env !== undefined) {
|
|
validateObject(options.env, 'options.env');
|
|
for (const [key, value] of ObjectEntries(options.env)) {
|
|
if (value !== undefined)
|
|
ArrayPrototypePush(env, `${key}=${value}`);
|
|
}
|
|
}
|
|
|
|
const preopens = [];
|
|
if (options.preopens !== undefined) {
|
|
validateObject(options.preopens, 'options.preopens');
|
|
for (const [key, value] of ObjectEntries(options.preopens)) {
|
|
ArrayPrototypePush(preopens, String(key), String(value));
|
|
}
|
|
}
|
|
|
|
const wrap = new _WASI(args, env, preopens);
|
|
|
|
for (const prop in wrap) {
|
|
wrap[prop] = FunctionPrototypeBind(wrap[prop], wrap);
|
|
}
|
|
|
|
if (options.returnOnExit !== undefined) {
|
|
validateBoolean(options.returnOnExit, 'options.returnOnExit');
|
|
if (options.returnOnExit)
|
|
wrap.proc_exit = FunctionPrototypeBind(wasiReturnOnProcExit, this);
|
|
}
|
|
|
|
this[kSetMemory] = wrap._setMemory;
|
|
delete wrap._setMemory;
|
|
this.wasiImport = wrap;
|
|
this[kStarted] = false;
|
|
this[kExitCode] = 0;
|
|
}
|
|
|
|
start(instance) {
|
|
if (!(instance instanceof WebAssembly.Instance)) {
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
'instance', 'WebAssembly.Instance', instance);
|
|
}
|
|
|
|
const exports = instance.exports;
|
|
|
|
validateObject(exports, 'instance.exports');
|
|
|
|
const { _initialize, _start, memory } = exports;
|
|
|
|
if (typeof _start !== 'function') {
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
'instance.exports._start', 'function', _start);
|
|
}
|
|
|
|
if (_initialize !== undefined) {
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
'instance.exports._initialize', 'undefined', _initialize);
|
|
}
|
|
|
|
if (!(memory instanceof WebAssembly.Memory)) {
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
'instance.exports.memory', 'WebAssembly.Memory', memory);
|
|
}
|
|
|
|
if (this[kStarted]) {
|
|
throw new ERR_WASI_ALREADY_STARTED();
|
|
}
|
|
|
|
this[kStarted] = true;
|
|
this[kSetMemory](memory);
|
|
|
|
try {
|
|
exports._start();
|
|
} catch (err) {
|
|
if (err !== kExitCode) {
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
return this[kExitCode];
|
|
}
|
|
}
|
|
|
|
|
|
module.exports = { WASI };
|
|
|
|
|
|
function wasiReturnOnProcExit(rval) {
|
|
// If __wasi_proc_exit() does not terminate the process, an assertion is
|
|
// triggered in the wasm runtime. Node can sidestep the assertion and return
|
|
// an exit code by recording the exit code, and throwing a JavaScript
|
|
// exception that WebAssembly cannot catch.
|
|
this[kExitCode] = rval;
|
|
throw kExitCode;
|
|
}
|