diff options
author | cjihrig <cjihrig@gmail.com> | 2019-09-04 17:56:51 -0400 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2019-11-30 18:06:39 +0100 |
commit | 09b1228c3a2723c6ecb768b40a507688015a478f (patch) | |
tree | 88acbfc979bc6f73572c86e8ee804bf0fa4ad326 /lib | |
parent | 73c837b1ae91cb8852e75a921fa24c714471d690 (diff) | |
download | android-node-v8-09b1228c3a2723c6ecb768b40a507688015a478f.tar.gz android-node-v8-09b1228c3a2723c6ecb768b40a507688015a478f.tar.bz2 android-node-v8-09b1228c3a2723c6ecb768b40a507688015a478f.zip |
wasi: introduce initial WASI support
Co-authored-by: Gus Caplan <me@gus.host>
Co-authored-by: Daniel Bevenius <daniel.bevenius@gmail.com>
Co-authored-by: Jiawen Geng <technicalcute@gmail.com>
Co-authored-by: Tobias Nießen <tniessen@tnie.de>
Co-authored-by: Chengzhong Wu <legendecas@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/30258
Refs: https://github.com/nodejs/node/pull/27850
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Wyatt Preul <wpreul@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/internal/bootstrap/loaders.js | 3 | ||||
-rw-r--r-- | lib/internal/errors.js | 1 | ||||
-rw-r--r-- | lib/internal/modules/cjs/helpers.js | 5 | ||||
-rw-r--r-- | lib/wasi.js | 105 |
4 files changed, 114 insertions, 0 deletions
diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index cfefc56bd8..044bea3114 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -157,6 +157,9 @@ function NativeModule(id) { this.loaded = false; this.loading = false; this.canBeRequiredByUsers = !id.startsWith('internal/'); + + if (id === 'wasi') + this.canBeRequiredByUsers = !!internalBinding('config').experimentalWasi; } // To be called during pre-execution when --expose-internals is on. diff --git a/lib/internal/errors.js b/lib/internal/errors.js index ee467f31f3..88a38f5e1d 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -1229,6 +1229,7 @@ E('ERR_VM_MODULE_LINKING_ERRORED', E('ERR_VM_MODULE_NOT_MODULE', 'Provided module is not an instance of Module', Error); E('ERR_VM_MODULE_STATUS', 'Module status %s', Error); +E('ERR_WASI_ALREADY_STARTED', 'WASI instance has already started', Error); E('ERR_WORKER_INVALID_EXEC_ARGV', (errors) => `Initiated Worker with invalid execArgv flags: ${errors.join(', ')}`, Error); diff --git a/lib/internal/modules/cjs/helpers.js b/lib/internal/modules/cjs/helpers.js index f7155c4aa1..2d73219a77 100644 --- a/lib/internal/modules/cjs/helpers.js +++ b/lib/internal/modules/cjs/helpers.js @@ -117,6 +117,11 @@ const builtinLibs = [ 'v8', 'vm', 'worker_threads', 'zlib' ]; +if (internalBinding('config').experimentalWasi) { + builtinLibs.push('wasi'); + builtinLibs.sort(); +} + if (typeof internalBinding('inspector').open === 'function') { builtinLibs.push('inspector'); builtinLibs.sort(); diff --git a/lib/wasi.js b/lib/wasi.js new file mode 100644 index 0000000000..65b8473624 --- /dev/null +++ b/lib/wasi.js @@ -0,0 +1,105 @@ +'use strict'; +/* global WebAssembly */ +const { + ArrayIsArray, + ArrayPrototypeForEach, + ArrayPrototypeMap, + FunctionPrototypeBind, + ObjectKeys +} = primordials; +const { + ERR_INVALID_ARG_TYPE, + ERR_WASI_ALREADY_STARTED +} = require('internal/errors').codes; +const { emitExperimentalWarning } = require('internal/util'); +const { WASI: _WASI } = internalBinding('wasi'); +const kSetMemory = Symbol('setMemory'); +const kStarted = Symbol('started'); + +emitExperimentalWarning('WASI'); + + +class WASI { + constructor(options = {}) { + if (options === null || typeof options !== 'object') + throw new ERR_INVALID_ARG_TYPE('options', 'object', options); + + // eslint-disable-next-line prefer-const + let { args, env, preopens } = options; + + if (ArrayIsArray(args)) + args = ArrayPrototypeMap(args, (arg) => { return String(arg); }); + else if (args === undefined) + args = []; + else + throw new ERR_INVALID_ARG_TYPE('options.args', 'Array', args); + + const envPairs = []; + + if (env !== null && typeof env === 'object') { + for (const key in env) { + const value = env[key]; + if (value !== undefined) + envPairs.push(`${key}=${value}`); + } + } else if (env !== undefined) { + throw new ERR_INVALID_ARG_TYPE('options.env', 'Object', env); + } + + const preopenArray = []; + + if (typeof preopens === 'object' && preopens !== null) { + ArrayPrototypeForEach(ObjectKeys(preopens), (key) => { + preopenArray.push(String(key)); + preopenArray.push(String(preopens[key])); + }); + } else if (preopens !== undefined) { + throw new ERR_INVALID_ARG_TYPE('options.preopens', 'Object', preopens); + } + + const wrap = new _WASI(args, envPairs, preopenArray); + + for (const prop in wrap) { + wrap[prop] = FunctionPrototypeBind(wrap[prop], wrap); + } + + this[kSetMemory] = wrap._setMemory; + delete wrap._setMemory; + this.wasiImport = wrap; + this[kStarted] = false; + } + + start(instance) { + if (!(instance instanceof WebAssembly.Instance)) { + throw new ERR_INVALID_ARG_TYPE( + 'instance', 'WebAssembly.Instance', instance); + } + + const exports = instance.exports; + + if (exports === null || typeof exports !== 'object') + throw new ERR_INVALID_ARG_TYPE('instance.exports', 'Object', exports); + + const { memory } = exports; + + 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); + + if (exports._start) + exports._start(); + else if (exports.__wasi_unstable_reactor_start) + exports.__wasi_unstable_reactor_start(); + } +} + + +module.exports = { WASI }; |