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