summaryrefslogtreecommitdiff
path: root/lib/wasi.js
blob: ff8685cbb06452f02ff88fb08dbeff2ea073996b (plain)
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
'use strict';
/* global WebAssembly */
const {
  ArrayIsArray,
  ArrayPrototypeForEach,
  ArrayPrototypeMap,
  FunctionPrototypeBind,
  ObjectKeys,
  Symbol,
} = 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 };