wasi: add returnOnExit option · nodejs/node@dd83bd2
@@ -15,6 +15,7 @@ const {
1515} = require('internal/errors').codes;
1616const { emitExperimentalWarning } = require('internal/util');
1717const { WASI: _WASI } = internalBinding('wasi');
18+const kExitCode = Symbol('exitCode');
1819const kSetMemory = Symbol('setMemory');
1920const kStarted = Symbol('started');
2021@@ -26,7 +27,7 @@ class WASI {
2627if (options === null || typeof options !== 'object')
2728throw new ERR_INVALID_ARG_TYPE('options', 'object', options);
282929-const { env, preopens } = options;
30+const { env, preopens, returnOnExit = false } = options;
3031let { args = [] } = options;
31323233if (ArrayIsArray(args))
@@ -56,16 +57,26 @@ class WASI {
5657throw new ERR_INVALID_ARG_TYPE('options.preopens', 'Object', preopens);
5758}
585960+if (typeof returnOnExit !== 'boolean') {
61+throw new ERR_INVALID_ARG_TYPE(
62+'options.returnOnExit', 'boolean', returnOnExit);
63+}
64+5965const wrap = new _WASI(args, envPairs, preopenArray);
60666167for (const prop in wrap) {
6268wrap[prop] = FunctionPrototypeBind(wrap[prop], wrap);
6369}
647071+if (returnOnExit) {
72+wrap.proc_exit = FunctionPrototypeBind(wasiReturnOnProcExit, this);
73+}
74+6575this[kSetMemory] = wrap._setMemory;
6676delete wrap._setMemory;
6777this.wasiImport = wrap;
6878this[kStarted] = false;
79+this[kExitCode] = 0;
6980}
70817182start(instance) {
@@ -93,12 +104,30 @@ class WASI {
93104this[kStarted] = true;
94105this[kSetMemory](memory);
9510696-if (exports._start)
97-exports._start();
98-else if (exports.__wasi_unstable_reactor_start)
99-exports.__wasi_unstable_reactor_start();
107+try {
108+if (exports._start)
109+exports._start();
110+else if (exports.__wasi_unstable_reactor_start)
111+exports.__wasi_unstable_reactor_start();
112+} catch (err) {
113+if (err !== kExitCode) {
114+throw err;
115+}
116+}
117+118+return this[kExitCode];
100119}
101120}
102121103122104123module.exports = { WASI };
124+125+126+function wasiReturnOnProcExit(rval) {
127+// If __wasi_proc_exit() does not terminate the process, an assertion is
128+// triggered in the wasm runtime. Node can sidestep the assertion and return
129+// an exit code by recording the exit code, and throwing a JavaScript
130+// exception that WebAssembly cannot catch.
131+this[kExitCode] = rval;
132+throw kExitCode;
133+}