• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Flags: --experimental-wasi-unstable-preview1
2'use strict';
3
4const common = require('../common');
5const assert = require('assert');
6const vm = require('vm');
7const { WASI } = require('wasi');
8
9const fixtures = require('../common/fixtures');
10const bufferSource = fixtures.readSync('simple.wasm');
11
12(async () => {
13  {
14    // Verify that a WebAssembly.Instance is passed in.
15    const wasi = new WASI();
16
17    assert.throws(
18      () => { wasi.initialize(); },
19      {
20        code: 'ERR_INVALID_ARG_TYPE',
21        message: /"instance" argument must be of type object/
22      }
23    );
24  }
25
26  {
27    // Verify that the passed instance has an exports objects.
28    const wasi = new WASI({});
29    const wasm = await WebAssembly.compile(bufferSource);
30    const instance = await WebAssembly.instantiate(wasm);
31
32    Object.defineProperty(instance, 'exports', { get() { return null; } });
33    assert.throws(
34      () => { wasi.initialize(instance); },
35      {
36        code: 'ERR_INVALID_ARG_TYPE',
37        message: /"instance\.exports" property must be of type object/
38      }
39    );
40  }
41
42  {
43    // Verify that a _initialize() export was passed.
44    const wasi = new WASI({});
45    const wasm = await WebAssembly.compile(bufferSource);
46    const instance = await WebAssembly.instantiate(wasm);
47
48    Object.defineProperty(instance, 'exports', {
49      get() {
50        return { _initialize: 5, memory: new Uint8Array() };
51      },
52    });
53    assert.throws(
54      () => { wasi.initialize(instance); },
55      {
56        code: 'ERR_INVALID_ARG_TYPE',
57        message: /"instance\.exports\._initialize" property must be of type function/
58      }
59    );
60  }
61
62  {
63    // Verify that a _start export was not passed.
64    const wasi = new WASI({});
65    const wasm = await WebAssembly.compile(bufferSource);
66    const instance = await WebAssembly.instantiate(wasm);
67
68    Object.defineProperty(instance, 'exports', {
69      get() {
70        return {
71          _start() {},
72          _initialize() {},
73          memory: new Uint8Array(),
74        };
75      }
76    });
77    assert.throws(
78      () => { wasi.initialize(instance); },
79      {
80        code: 'ERR_INVALID_ARG_TYPE',
81        message: /"instance\.exports\._start" property must be undefined/
82      }
83    );
84  }
85
86  {
87    // Verify that a memory export was passed.
88    const wasi = new WASI({});
89    const wasm = await WebAssembly.compile(bufferSource);
90    const instance = await WebAssembly.instantiate(wasm);
91
92    Object.defineProperty(instance, 'exports', {
93      get() { return { _initialize() {} }; }
94    });
95    assert.throws(
96      () => { wasi.initialize(instance); },
97      {
98        code: 'ERR_INVALID_ARG_TYPE',
99        message: /"instance\.exports\.memory" property must be of type object/
100      }
101    );
102  }
103
104  {
105    // Verify that a non-ArrayBuffer memory.buffer is rejected.
106    const wasi = new WASI({});
107    const wasm = await WebAssembly.compile(bufferSource);
108    const instance = await WebAssembly.instantiate(wasm);
109
110    Object.defineProperty(instance, 'exports', {
111      get() {
112        return {
113          _initialize() {},
114          memory: {},
115        };
116      }
117    });
118    // The error message is a little white lie because any object
119    // with a .buffer property of type ArrayBuffer is accepted,
120    // but 99% of the time a WebAssembly.Memory object is used.
121    assert.throws(
122      () => { wasi.initialize(instance); },
123      {
124        code: 'ERR_INVALID_ARG_TYPE',
125        message: /"instance\.exports\.memory\.buffer" property must be an WebAssembly\.Memory/
126      }
127    );
128  }
129
130  {
131    // Verify that an argument that duck-types as a WebAssembly.Instance
132    // is accepted.
133    const wasi = new WASI({});
134    const wasm = await WebAssembly.compile(bufferSource);
135    const instance = await WebAssembly.instantiate(wasm);
136
137    Object.defineProperty(instance, 'exports', {
138      get() {
139        return {
140          _initialize() {},
141          memory: { buffer: new ArrayBuffer(0) },
142        };
143      }
144    });
145    wasi.initialize(instance);
146  }
147
148  {
149    // Verify that a WebAssembly.Instance from another VM context is accepted.
150    const wasi = new WASI({});
151    const instance = await vm.runInNewContext(`
152      (async () => {
153        const wasm = await WebAssembly.compile(bufferSource);
154        const instance = await WebAssembly.instantiate(wasm);
155
156        Object.defineProperty(instance, 'exports', {
157          get() {
158            return {
159              _initialize() {},
160              memory: new WebAssembly.Memory({ initial: 1 })
161            };
162          }
163        });
164
165        return instance;
166      })()
167    `, { bufferSource });
168
169    wasi.initialize(instance);
170  }
171
172  {
173    // Verify that initialize() can only be called once.
174    const wasi = new WASI({});
175    const wasm = await WebAssembly.compile(bufferSource);
176    const instance = await WebAssembly.instantiate(wasm);
177
178    Object.defineProperty(instance, 'exports', {
179      get() {
180        return {
181          _initialize() {},
182          memory: new WebAssembly.Memory({ initial: 1 })
183        };
184      }
185    });
186    wasi.initialize(instance);
187    assert.throws(
188      () => { wasi.initialize(instance); },
189      {
190        code: 'ERR_WASI_ALREADY_STARTED',
191        message: /^WASI instance has already started$/
192      }
193    );
194  }
195})().then(common.mustCall());
196