forked from nodejs/node
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathwasi.js
123 lines (99 loc) · 3.12 KB
/
wasi.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
'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 { 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);
try {
if (exports._start)
exports._start();
else if (exports.__wasi_unstable_reactor_start)
exports.__wasi_unstable_reactor_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;
}