wasi: add returnOnExit option · nodejs/node@dd83bd2

@@ -15,6 +15,7 @@ const {

1515

} = require('internal/errors').codes;

1616

const { emitExperimentalWarning } = require('internal/util');

1717

const { WASI: _WASI } = internalBinding('wasi');

18+

const kExitCode = Symbol('exitCode');

1819

const kSetMemory = Symbol('setMemory');

1920

const kStarted = Symbol('started');

2021

@@ -26,7 +27,7 @@ class WASI {

2627

if (options === null || typeof options !== 'object')

2728

throw new ERR_INVALID_ARG_TYPE('options', 'object', options);

282929-

const { env, preopens } = options;

30+

const { env, preopens, returnOnExit = false } = options;

3031

let { args = [] } = options;

31323233

if (ArrayIsArray(args))

@@ -56,16 +57,26 @@ class WASI {

5657

throw 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+5965

const wrap = new _WASI(args, envPairs, preopenArray);

60666167

for (const prop in wrap) {

6268

wrap[prop] = FunctionPrototypeBind(wrap[prop], wrap);

6369

}

647071+

if (returnOnExit) {

72+

wrap.proc_exit = FunctionPrototypeBind(wasiReturnOnProcExit, this);

73+

}

74+6575

this[kSetMemory] = wrap._setMemory;

6676

delete wrap._setMemory;

6777

this.wasiImport = wrap;

6878

this[kStarted] = false;

79+

this[kExitCode] = 0;

6980

}

70817182

start(instance) {

@@ -93,12 +104,30 @@ class WASI {

93104

this[kStarted] = true;

94105

this[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

}

102121103122104123

module.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+

}