summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorcjihrig <cjihrig@gmail.com>2019-09-04 17:56:51 -0400
committerAnna Henningsen <anna@addaleax.net>2019-11-30 18:06:39 +0100
commit09b1228c3a2723c6ecb768b40a507688015a478f (patch)
tree88acbfc979bc6f73572c86e8ee804bf0fa4ad326 /lib
parent73c837b1ae91cb8852e75a921fa24c714471d690 (diff)
downloadandroid-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.js3
-rw-r--r--lib/internal/errors.js1
-rw-r--r--lib/internal/modules/cjs/helpers.js5
-rw-r--r--lib/wasi.js105
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 };