import-export.js (32264B)
1 const { Module, Instance, Memory, Table, LinkError, RuntimeError } = WebAssembly; 2 3 const mem1Page = new Memory({initial:1}); 4 const mem1PageMax1 = new Memory({initial:1, maximum: 1}); 5 const mem2Page = new Memory({initial:2}); 6 const mem2PageMax2 = new Memory({initial:2, maximum: 2}); 7 const mem2PageMax3 = new Memory({initial:2, maximum: 3}); 8 const mem2PageMax4 = new Memory({initial:2, maximum: 4}); 9 const mem3Page = new Memory({initial:3}); 10 const mem3PageMax3 = new Memory({initial:3, maximum: 3}); 11 const mem4Page = new Memory({initial:4}); 12 const mem4PageMax4 = new Memory({initial:4, maximum: 4}); 13 const tab1Elem = new Table({initial:1, element:"anyfunc"}); 14 const tab2Elem = new Table({initial:2, element:"anyfunc"}); 15 const tab3Elem = new Table({initial:3, element:"anyfunc"}); 16 const tab4Elem = new Table({initial:4, element:"anyfunc"}); 17 18 function assertSegmentFitError(f) { 19 assertErrorMessage(f, RuntimeError, /out of bounds/); 20 } 21 22 const m1 = new Module(wasmTextToBinary('(module (import "foo" "bar" (func)) (import "baz" "quux" (func)))')); 23 assertErrorMessage(() => new Instance(m1), TypeError, /second argument must be an object/); 24 assertErrorMessage(() => new Instance(m1, {foo:null}), TypeError, /import object field 'foo' is not an Object/); 25 assertErrorMessage(() => new Instance(m1, {foo:{bar:{}}}), LinkError, /import object field 'bar' is not a Function/); 26 assertErrorMessage(() => new Instance(m1, {foo:{bar:()=>{}}, baz:null}), TypeError, /import object field 'baz' is not an Object/); 27 assertErrorMessage(() => new Instance(m1, {foo:{bar:()=>{}}, baz:{}}), LinkError, /import object field 'quux' is not a Function/); 28 assertEq(new Instance(m1, {foo:{bar:()=>{}}, baz:{quux:()=>{}}}) instanceof Instance, true); 29 30 const m2 = new Module(wasmTextToBinary('(module (import "x" "y" (memory 2 3)))')); 31 assertErrorMessage(() => new Instance(m2), TypeError, /second argument must be an object/); 32 assertErrorMessage(() => new Instance(m2, {x:null}), TypeError, /import object field 'x' is not an Object/); 33 assertErrorMessage(() => new Instance(m2, {x:{y:{}}}), LinkError, /import object field 'y' is not a Memory/); 34 assertErrorMessage(() => new Instance(m2, {x:{y:mem1Page}}), LinkError, /imported Memory with incompatible size/); 35 assertErrorMessage(() => new Instance(m2, {x:{y:mem1PageMax1}}), LinkError, /imported Memory with incompatible size/); 36 assertErrorMessage(() => new Instance(m2, {x:{y:mem4Page}}), LinkError, /imported Memory with incompatible size/); 37 assertErrorMessage(() => new Instance(m2, {x:{y:mem4PageMax4}}), LinkError, /imported Memory with incompatible size/); 38 assertErrorMessage(() => new Instance(m2, {x:{y:mem2Page}}), LinkError, /imported Memory with incompatible maximum size/); 39 assertEq(new Instance(m2, {x:{y:mem2PageMax2}}) instanceof Instance, true); 40 assertErrorMessage(() => new Instance(m2, {x:{y:mem3Page}}), LinkError, /imported Memory with incompatible maximum size/); 41 assertEq(new Instance(m2, {x:{y:mem3PageMax3}}) instanceof Instance, true); 42 assertEq(new Instance(m2, {x:{y:mem2PageMax3}}) instanceof Instance, true); 43 assertErrorMessage(() => new Instance(m2, {x:{y:mem2PageMax4}}), LinkError, /imported Memory with incompatible maximum size/); 44 45 const m3 = new Module(wasmTextToBinary('(module (import "foo" "bar" (memory 1 1)) (import "baz" "quux" (func)))')); 46 assertErrorMessage(() => new Instance(m3), TypeError, /second argument must be an object/); 47 assertErrorMessage(() => new Instance(m3, {foo:null}), TypeError, /import object field 'foo' is not an Object/); 48 assertErrorMessage(() => new Instance(m3, {foo:{bar:{}}}), LinkError, /import object field 'bar' is not a Memory/); 49 assertErrorMessage(() => new Instance(m3, {foo:{bar:mem1Page}, baz:null}), TypeError, /import object field 'baz' is not an Object/); 50 assertErrorMessage(() => new Instance(m3, {foo:{bar:mem1Page}, baz:{quux:mem1Page}}), LinkError, /import object field 'quux' is not a Function/); 51 assertErrorMessage(() => new Instance(m3, {foo:{bar:mem1Page}, baz:{quux:()=>{}}}), LinkError, /imported Memory with incompatible maximum size/); 52 assertEq(new Instance(m3, {foo:{bar:mem1PageMax1}, baz:{quux:()=>{}}}) instanceof Instance, true); 53 54 const m4 = new Module(wasmTextToBinary('(module (import "baz" "quux" (func)) (import "foo" "bar" (memory 1 1)))')); 55 assertErrorMessage(() => new Instance(m4), TypeError, /second argument must be an object/); 56 assertErrorMessage(() => new Instance(m4, {baz:null}), TypeError, /import object field 'baz' is not an Object/); 57 assertErrorMessage(() => new Instance(m4, {baz:{quux:{}}}), LinkError, /import object field 'quux' is not a Function/); 58 assertErrorMessage(() => new Instance(m4, {baz:{quux:()=>{}}, foo:null}), TypeError, /import object field 'foo' is not an Object/); 59 assertErrorMessage(() => new Instance(m4, {baz:{quux:()=>{}}, foo:{bar:()=>{}}}), LinkError, /import object field 'bar' is not a Memory/); 60 assertErrorMessage(() => new Instance(m4, {baz:{quux:()=>{}}, foo:{bar:mem1Page}}), LinkError, /imported Memory with incompatible maximum size/); 61 assertEq(new Instance(m3, {baz:{quux:()=>{}}, foo:{bar:mem1PageMax1}}) instanceof Instance, true); 62 63 const m5 = new Module(wasmTextToBinary('(module (import "a" "b" (memory 2)))')); 64 assertErrorMessage(() => new Instance(m5, {a:{b:mem1Page}}), LinkError, /imported Memory with incompatible size/); 65 assertEq(new Instance(m5, {a:{b:mem2Page}}) instanceof Instance, true); 66 assertEq(new Instance(m5, {a:{b:mem3Page}}) instanceof Instance, true); 67 assertEq(new Instance(m5, {a:{b:mem4Page}}) instanceof Instance, true); 68 69 const m6 = new Module(wasmTextToBinary('(module (import "a" "b" (table 2 funcref)))')); 70 assertErrorMessage(() => new Instance(m6, {a:{b:tab1Elem}}), LinkError, /imported Table with incompatible size/); 71 assertEq(new Instance(m6, {a:{b:tab2Elem}}) instanceof Instance, true); 72 assertEq(new Instance(m6, {a:{b:tab3Elem}}) instanceof Instance, true); 73 assertEq(new Instance(m6, {a:{b:tab4Elem}}) instanceof Instance, true); 74 75 const m7 = new Module(wasmTextToBinary('(module (import "a" "b" (table 2 3 funcref)))')); 76 assertErrorMessage(() => new Instance(m7, {a:{b:tab1Elem}}), LinkError, /imported Table with incompatible size/); 77 assertErrorMessage(() => new Instance(m7, {a:{b:tab2Elem}}), LinkError, /imported Table with incompatible maximum size/); 78 assertErrorMessage(() => new Instance(m7, {a:{b:tab3Elem}}), LinkError, /imported Table with incompatible maximum size/); 79 assertErrorMessage(() => new Instance(m7, {a:{b:tab4Elem}}), LinkError, /imported Table with incompatible size/); 80 81 wasmFailValidateText('(module (memory 2 1))', /maximum length 1 is less than initial length 2/); 82 wasmFailValidateText('(module (import "a" "b" (memory 2 1)))', /maximum length 1 is less than initial length 2/); 83 wasmFailValidateText('(module (table 2 1 funcref))', /maximum length 1 is less than initial length 2/); 84 wasmFailValidateText('(module (import "a" "b" (table 2 1 funcref)))', /maximum length 1 is less than initial length 2/); 85 86 // Import wasm-wasm type mismatch 87 88 var e = wasmEvalText('(module (func $i2v (param i32)) (export "i2v" (func $i2v)) (func $f2v (param f32)) (export "f2v" (func $f2v)))').exports; 89 var i2vm = new Module(wasmTextToBinary('(module (import "a" "b" (func (param i32))))')); 90 var f2vm = new Module(wasmTextToBinary('(module (import "a" "b" (func (param f32))))')); 91 assertEq(new Instance(i2vm, {a:{b:e.i2v}}) instanceof Instance, true); 92 assertErrorMessage(() => new Instance(i2vm, {a:{b:e.f2v}}), LinkError, /imported function 'a.b' signature mismatch/); 93 assertErrorMessage(() => new Instance(f2vm, {a:{b:e.i2v}}), LinkError, /imported function 'a.b' signature mismatch/); 94 assertEq(new Instance(f2vm, {a:{b:e.f2v}}) instanceof Instance, true); 95 var l2vm = new Module(wasmTextToBinary('(module (import "x" "y" (memory 1)) (import "c" "d" (func (param i64))))')); 96 assertErrorMessage(() => new Instance(l2vm, {x:{y:mem1Page}, c:{d:e.i2v}}), LinkError, /imported function 'c.d' signature mismatch/); 97 98 // Import order: 99 100 var arr = []; 101 var importObj = { 102 get foo() { arr.push("foo") }, 103 get baz() { arr.push("bad") }, 104 }; 105 assertErrorMessage(() => new Instance(m1, importObj), TypeError, /import object field 'foo' is not an Object/); 106 assertEq(arr.join(), "foo"); 107 108 var arr = []; 109 var importObj = { 110 get foo() { 111 arr.push("foo"); 112 return { get bar() { arr.push("bar"); return null } } 113 }, 114 get baz() { arr.push("bad") }, 115 }; 116 assertErrorMessage(() => new Instance(m1, importObj), LinkError, /import object field 'bar' is not a Function/); 117 assertEq(arr.join(), "foo,bar"); 118 119 var arr = []; 120 var importObj = { 121 get foo() { 122 arr.push("foo"); 123 return { get bar() { arr.push("bar"); return () => arr.push("bad") } } 124 }, 125 get baz() { 126 arr.push("baz"); 127 return { get quux() { arr.push("quux"); return () => arr.push("bad") } } 128 } 129 }; 130 assertEq(new Instance(m1, importObj) instanceof Instance, true); 131 assertEq(arr.join(), "foo,bar,baz,quux"); 132 133 var arr = []; 134 var importObj = { 135 get foo() { 136 arr.push("foo"); 137 return { get bar() { arr.push("bar"); return new WebAssembly.Memory({initial:1, maximum:1}) } } 138 }, 139 get baz() { 140 arr.push("baz"); 141 return { get quux() { arr.push("quux"); return () => arr.push("bad") } } 142 } 143 }; 144 assertEq(new Instance(m3, importObj) instanceof Instance, true); 145 assertEq(arr.join(), "foo,bar,baz,quux"); 146 arr = []; 147 assertEq(new Instance(m4, importObj) instanceof Instance, true); 148 assertEq(arr.join(), "baz,quux,foo,bar"); 149 150 // Export key order: 151 152 var code = wasmTextToBinary('(module)'); 153 var e = new Instance(new Module(code)).exports; 154 assertEq(Object.keys(e).length, 0); 155 156 var code = wasmTextToBinary('(module (func) (export "foo" (func 0)))'); 157 var e = new Instance(new Module(code)).exports; 158 assertEq(Object.keys(e).join(), "foo"); 159 assertEq(e.foo(), undefined); 160 161 var code = wasmTextToBinary('(module (func) (export "foo" (func 0)) (export "bar" (func 0)))'); 162 var e = new Instance(new Module(code)).exports; 163 assertEq(Object.keys(e).join(), "foo,bar"); 164 assertEq(e.foo(), undefined); 165 assertEq(e.bar(), undefined); 166 assertEq(e.foo, e.bar); 167 168 var code = wasmTextToBinary('(module (memory 1 1) (export "memory" (memory 0)))'); 169 var e = new Instance(new Module(code)).exports; 170 assertEq(Object.keys(e).join(), "memory"); 171 172 var code = wasmTextToBinary('(module (memory 1 1) (export "foo" (memory 0)) (export "bar" (memory 0)))'); 173 var e = new Instance(new Module(code)).exports; 174 assertEq(Object.keys(e).join(), "foo,bar"); 175 assertEq(e.foo, e.bar); 176 assertEq(e.foo instanceof Memory, true); 177 assertEq(e.foo.buffer.byteLength, 64*1024); 178 179 var code = wasmTextToBinary('(module (memory 1 1) (func) (export "foo" (func 0)) (export "bar" (memory 0)))'); 180 var e = new Instance(new Module(code)).exports; 181 assertEq(Object.keys(e).join(), "foo,bar"); 182 assertEq(e.foo(), undefined); 183 assertEq(e.bar instanceof Memory, true); 184 assertEq(e.bar instanceof Memory, true); 185 assertEq(e.bar.buffer.byteLength, 64*1024); 186 187 var code = wasmTextToBinary('(module (memory 1 1) (func) (export "bar" (memory 0)) (export "foo" (func 0)))'); 188 var e = new Instance(new Module(code)).exports; 189 assertEq(Object.keys(e).join(), "bar,foo"); 190 assertEq(e.foo(), undefined); 191 assertEq(e.bar.buffer.byteLength, 64*1024); 192 193 var code = wasmTextToBinary('(module (memory 1 1) (export "" (memory 0)))'); 194 var e = new Instance(new Module(code)).exports; 195 assertEq(Object.keys(e).length, 1); 196 assertEq(String(Object.keys(e)), ""); 197 assertEq(e[""] instanceof Memory, true); 198 199 var code = wasmTextToBinary('(module (table 0 funcref) (export "tbl" (table 0)))'); 200 var e = new Instance(new Module(code)).exports; 201 assertEq(Object.keys(e).join(), "tbl"); 202 assertEq(e.tbl instanceof Table, true); 203 assertEq(e.tbl.length, 0); 204 205 var code = wasmTextToBinary('(module (table 2 funcref) (export "t1" (table 0)) (export "t2" (table 0)))'); 206 var e = new Instance(new Module(code)).exports; 207 assertEq(Object.keys(e).join(), "t1,t2"); 208 assertEq(e.t1 instanceof Table, true); 209 assertEq(e.t2 instanceof Table, true); 210 assertEq(e.t1, e.t2); 211 assertEq(e.t1.length, 2); 212 213 var code = wasmTextToBinary('(module (table 2 funcref) (memory 1 1) (func) (export "t" (table 0)) (export "m" (memory 0)) (export "f" (func 0)))'); 214 var e = new Instance(new Module(code)).exports; 215 assertEq(Object.keys(e).join(), "t,m,f"); 216 assertEq(e.f(), undefined); 217 assertEq(e.t instanceof Table, true); 218 assertEq(e.m instanceof Memory, true); 219 assertEq(e.t.length, 2); 220 221 var code = wasmTextToBinary('(module (table 1 funcref) (memory 1 1) (func) (export "m" (memory 0)) (export "f" (func 0)) (export "t" (table 0)))'); 222 var e = new Instance(new Module(code)).exports; 223 assertEq(Object.keys(e).join(), "m,f,t"); 224 assertEq(e.f(), undefined); 225 assertEq(e.t instanceof Table, true); 226 assertEq(e.m instanceof Memory, true); 227 +assertEq(e.t.length, 1); 228 229 var code = wasmTextToBinary('(module (table 0 funcref) (export "" (table 0)))'); 230 var e = new Instance(new Module(code)).exports; 231 assertEq(Object.keys(e).length, 1); 232 assertEq(String(Object.keys(e)), ""); 233 assertEq(e[""] instanceof Table, true); 234 +assertEq(e[""].length, 0); 235 236 // Table export function identity 237 238 var text = `(module 239 (func $f (result i32) (i32.const 1)) 240 (func $g (result i32) (i32.const 2)) 241 (func $h (result i32) (i32.const 3)) 242 (table 4 funcref) 243 (elem (i32.const 0) $f) 244 (elem (i32.const 2) $g) 245 (export "f1" (func $f)) 246 (export "tbl1" (table 0)) 247 (export "f2" (func $f)) 248 (export "tbl2" (table 0)) 249 (export "f3" (func $h)) 250 (func (export "run") (result i32) (call_indirect (type 0) (i32.const 2))) 251 )`; 252 wasmFullPass(text, 2); 253 var e = new Instance(new Module(wasmTextToBinary(text))).exports; 254 assertEq(String(Object.keys(e)), "f1,tbl1,f2,tbl2,f3,run"); 255 assertEq(e.f1, e.f2); 256 assertEq(e.f1(), 1); 257 assertEq(e.f3(), 3); 258 assertEq(e.tbl1, e.tbl2); 259 assertEq(e.tbl1.get(0), e.f1); 260 assertEq(e.tbl1.get(0), e.tbl1.get(0)); 261 assertEq(e.tbl1.get(0)(), 1); 262 assertEq(e.tbl1.get(1), null); 263 assertEq(e.tbl1.get(2), e.tbl1.get(2)); 264 assertEq(e.tbl1.get(2)(), 2); 265 assertEq(e.tbl1.get(3), null); 266 assertErrorMessage(() => e.tbl1.get(4), RangeError, /bad Table get address/); 267 assertEq(e.tbl1.get(1), null); 268 e.tbl1.set(1, e.f3); 269 assertEq(e.tbl1.get(1), e.f3); 270 e.tbl1.set(1, null); 271 assertEq(e.tbl1.get(1), null); 272 e.tbl1.set(3, e.f1); 273 assertEq(e.tbl1.get(0), e.tbl1.get(3)); 274 275 // JS re-exports 276 277 var args; 278 var m = new Module(wasmTextToBinary(`(module 279 (export "a" (func $a)) (import "" "a" (func $a (param f32))) 280 (export "b" (func $b)) (import "" "b" (func $b (param i32) (result i32))) 281 (export "c" (func $c)) (import "" "c" (func $c (result i32))) 282 (export "d" (func $d)) (import "" "d" (func $d)) 283 )`)); 284 var js = function() { args = arguments; return 42 } 285 var e = new Instance(m, {"":{a:js, b:js, c:js, d:js}}).exports; 286 assertEq(e.a.length, 1); 287 assertEq(e.a(), undefined); 288 assertEq(args.length, 1); 289 assertEq(args[0], NaN); 290 assertEq(e.a(99.5), undefined); 291 assertEq(args.length, 1); 292 assertEq(args[0], 99.5); 293 assertEq(e.b.length, 1); 294 assertEq(e.b(), 42); 295 assertEq(args.length, 1); 296 assertEq(args[0], 0); 297 assertEq(e.b(99.5), 42); 298 assertEq(args.length, 1); 299 assertEq(args[0], 99); 300 assertEq(e.c.length, 0); 301 assertEq(e.c(), 42); 302 assertEq(args.length, 0); 303 assertEq(e.c(99), 42); 304 assertEq(args.length, 0); 305 assertEq(e.d.length, 0); 306 assertEq(e.d(), undefined); 307 assertEq(args.length, 0); 308 assertEq(e.d(99), undefined); 309 assertEq(args.length, 0); 310 311 // Re-exports and Identity: 312 313 var code = wasmTextToBinary('(module (import "a" "b" (memory 1 1)) (export "foo" (memory 0)) (export "bar" (memory 0)))'); 314 var mem = new Memory({initial:1, maximum:1}); 315 var e = new Instance(new Module(code), {a:{b:mem}}).exports; 316 assertEq(mem, e.foo); 317 assertEq(mem, e.bar); 318 319 var code = wasmTextToBinary('(module (import "a" "b" (table 1 1 funcref)) (export "foo" (table 0)) (export "bar" (table 0)))'); 320 var tbl = new Table({initial:1, maximum:1, element:"anyfunc"}); 321 var e = new Instance(new Module(code), {a:{b:tbl}}).exports; 322 assertEq(tbl, e.foo); 323 assertEq(tbl, e.bar); 324 325 var code = wasmTextToBinary('(module (import "a" "b" (table 2 2 funcref)) (func $foo) (elem (i32.const 0) $foo) (export "foo" (func $foo)))'); 326 var tbl = new Table({initial:2, maximum:2, element:"anyfunc"}); 327 var e1 = new Instance(new Module(code), {a:{b:tbl}}).exports; 328 assertEq(e1.foo, tbl.get(0)); 329 tbl.set(1, e1.foo); 330 assertEq(e1.foo, tbl.get(1)); 331 var e2 = new Instance(new Module(code), {a:{b:tbl}}).exports; 332 assertEq(e2.foo, tbl.get(0)); 333 assertEq(e1.foo, tbl.get(1)); 334 assertEq(tbl.get(0) === e1.foo, false); 335 assertEq(e1.foo === e2.foo, false); 336 337 var m = new Module(wasmTextToBinary(`(module 338 (import "" "foo" (func $foo (result i32))) 339 (import "" "bar" (func $bar (result i32))) 340 (table 3 funcref) 341 (func $baz (result i32) (i32.const 13)) 342 (elem (i32.const 0) $foo $bar $baz) 343 (export "foo" (func $foo)) 344 (export "bar" (func $bar)) 345 (export "baz" (func $baz)) 346 (export "tbl" (table 0)) 347 )`)); 348 var jsFun = () => 83; 349 var wasmFun = new Instance(new Module(wasmTextToBinary('(module (func (result i32) (i32.const 42)) (export "foo" (func 0)))'))).exports.foo; 350 var e1 = new Instance(m, {"":{foo:jsFun, bar:wasmFun}}).exports; 351 assertEq(jsFun === e1.foo, false); 352 assertEq(wasmFun, e1.bar); 353 assertEq(e1.foo, e1.tbl.get(0)); 354 assertEq(e1.bar, e1.tbl.get(1)); 355 assertEq(e1.baz, e1.tbl.get(2)); 356 assertEq(e1.tbl.get(0)(), 83); 357 assertEq(e1.tbl.get(1)(), 42); 358 assertEq(e1.tbl.get(2)(), 13); 359 var e2 = new Instance(m, {"":{foo:jsFun, bar:jsFun}}).exports; 360 assertEq(jsFun === e2.foo, false); 361 assertEq(jsFun === e2.bar, false); 362 assertEq(e2.foo === e1.foo, false); 363 assertEq(e2.bar === e1.bar, false); 364 assertEq(e2.baz === e1.baz, false); 365 assertEq(e2.tbl === e1.tbl, false); 366 assertEq(e2.foo, e2.tbl.get(0)); 367 assertEq(e2.bar, e2.tbl.get(1)); 368 assertEq(e2.baz, e2.tbl.get(2)); 369 var e3 = new Instance(m, {"":{foo:wasmFun, bar:wasmFun}}).exports; 370 assertEq(wasmFun, e3.foo); 371 assertEq(wasmFun, e3.bar); 372 assertEq(e3.baz === e3.foo, false); 373 assertEq(e3.baz === e1.baz, false); 374 assertEq(e3.tbl === e1.tbl, false); 375 assertEq(e3.foo, e3.tbl.get(0)); 376 assertEq(e3.bar, e3.tbl.get(1)); 377 assertEq(e3.baz, e3.tbl.get(2)); 378 var e4 = new Instance(m, {"":{foo:e1.foo, bar:e1.foo}}).exports; 379 assertEq(e4.foo, e1.foo); 380 assertEq(e4.bar, e1.foo); 381 assertEq(e4.baz === e4.foo, false); 382 assertEq(e4.baz === e1.baz, false); 383 assertEq(e4.tbl === e1.tbl, false); 384 assertEq(e4.foo, e4.tbl.get(0)); 385 assertEq(e4.foo, e4.tbl.get(1)); 386 assertEq(e4.baz, e4.tbl.get(2)); 387 388 // i64 is fully allowed for imported wasm functions 389 390 var code1 = wasmTextToBinary('(module (func $exp (param i64) (result i64) (i64.add (local.get 0) (i64.const 10))) (export "exp" (func $exp)))'); 391 var e1 = new Instance(new Module(code1)).exports; 392 var code2 = wasmTextToBinary('(module (import "a" "b" (func $i (param i64) (result i64))) (func $f (result i32) (i32.wrap_i64 (call $i (i64.const 42)))) (export "f" (func $f)))'); 393 var e2 = new Instance(new Module(code2), {a:{b:e1.exp}}).exports; 394 assertEq(e2.f(), 52); 395 396 // Non-existent export errors 397 398 wasmFailValidateText('(module (export "a" (func 0)))', /exported function index out of bounds/); 399 wasmFailValidateText('(module (export "a" (global 0)))', /exported global index out of bounds/); 400 wasmFailValidateText('(module (export "a" (memory 0)))', /exported memory index out of bounds/); 401 wasmFailValidateText('(module (export "a" (table 0)))', /exported table index out of bounds/); 402 403 // Data segments on imports 404 405 var m = new Module(wasmTextToBinary(` 406 (module 407 (import "a" "b" (memory 1 1)) 408 (data (i32.const 0) "\\0a\\0b") 409 (data (i32.const 100) "\\0c\\0d") 410 (func $get (param $p i32) (result i32) 411 (i32.load8_u (local.get $p))) 412 (export "get" (func $get))) 413 `)); 414 var mem = new Memory({initial:1, maximum:1}); 415 var {get} = new Instance(m, {a:{b:mem}}).exports; 416 assertEq(get(0), 0xa); 417 assertEq(get(1), 0xb); 418 assertEq(get(2), 0x0); 419 assertEq(get(100), 0xc); 420 assertEq(get(101), 0xd); 421 assertEq(get(102), 0x0); 422 var i8 = new Uint8Array(mem.buffer); 423 assertEq(i8[0], 0xa); 424 assertEq(i8[1], 0xb); 425 assertEq(i8[2], 0x0); 426 assertEq(i8[100], 0xc); 427 assertEq(i8[101], 0xd); 428 assertEq(i8[102], 0x0); 429 430 // Data segments with imported offsets 431 432 var m = new Module(wasmTextToBinary(` 433 (module 434 (import "glob" "a" (global i32)) 435 (memory 1) 436 (data (global.get 0) "\\0a\\0b")) 437 `)); 438 assertEq(new Instance(m, {glob:{a:0}}) instanceof Instance, true); 439 assertEq(new Instance(m, {glob:{a:(64*1024 - 2)}}) instanceof Instance, true); 440 assertSegmentFitError(() => new Instance(m, {glob:{a:(64*1024 - 1)}})); 441 assertSegmentFitError(() => new Instance(m, {glob:{a:64*1024}})); 442 443 var m = new Module(wasmTextToBinary(` 444 (module 445 (memory 1) 446 (data (i32.const 0x10001) "\\0a\\0b")) 447 `)); 448 assertSegmentFitError(() => new Instance(m)); 449 450 var m = new Module(wasmTextToBinary(` 451 (module 452 (memory 0) 453 (data (i32.const 0x10001) "")) 454 `)); 455 assertSegmentFitError(() => new Instance(m)); 456 457 // Errors during segment initialization do not have observable effects 458 // and are checked against the actual memory/table length, not the declared 459 // initial length. 460 461 var m = new Module(wasmTextToBinary(` 462 (module 463 (import "a" "mem" (memory 1)) 464 (import "a" "tbl" (table 1 funcref)) 465 (import "a" "memOff" (global $memOff i32)) 466 (import "a" "tblOff" (global $tblOff i32)) 467 (func $f) 468 (func $g) 469 (data (i32.const 0) "\\01") 470 (elem (i32.const 0) $f) 471 (data (global.get $memOff) "\\02") 472 (elem (global.get $tblOff) $g) 473 (export "f" (func $f)) 474 (export "g" (func $g))) 475 `)); 476 477 // Active segments are applied in order (this is observable if they overlap). 478 // 479 // Without bulk memory, all range checking for tables and memory happens before 480 // any writes happen, and any OOB will force no writing to happen at all. 481 // 482 // With bulk memory, active segments are applied first for tables and then for 483 // memories. Bounds checking happens for each byte or table element written. 484 // The first OOB aborts the initialization process, leaving written data in 485 // place. Notably, any OOB in table initialization will prevent any memory 486 // initialization from happening at all. 487 488 var npages = 2; 489 var mem = new Memory({initial:npages}); 490 var mem8 = new Uint8Array(mem.buffer); 491 var tbl = new Table({initial:2, element:"anyfunc"}); 492 493 assertSegmentFitError(() => new Instance(m, {a:{mem, tbl, memOff:1, tblOff:2}})); 494 // The first active element segment is applied, but the second active 495 // element segment is completely OOB. 496 assertEq(typeof tbl.get(0), "function"); 497 assertEq(tbl.get(1), null); 498 499 assertEq(mem8[0], 0); 500 assertEq(mem8[1], 0); 501 502 tbl.set(0, null); 503 tbl.set(1, null); 504 505 assertSegmentFitError(() => new Instance(m, {a:{mem, tbl, memOff:npages*64*1024, tblOff:1}})); 506 // The first and second active element segments are applied fully. The 507 // first active data segment applies, but the second one is completely OOB. 508 assertEq(typeof tbl.get(0), "function"); 509 assertEq(typeof tbl.get(1), "function"); 510 assertEq(mem8[0], 1); 511 512 tbl.set(0, null); 513 tbl.set(1, null); 514 mem8[0] = 0; 515 516 // Both element and data segments apply successfully without OOB 517 518 var i = new Instance(m, {a:{mem, tbl, memOff:npages*64*1024-1, tblOff:1}}); 519 assertEq(mem8[0], 1); 520 assertEq(mem8[npages*64*1024-1], 2); 521 assertEq(tbl.get(0), i.exports.f); 522 assertEq(tbl.get(1), i.exports.g); 523 524 // Element segment doesn't apply and prevents subsequent elem segment and 525 // data segment from being applied. 526 527 var m = new Module(wasmTextToBinary( 528 `(module 529 (import "" "mem" (memory 1)) 530 (import "" "tbl" (table 3 funcref)) 531 (elem (i32.const 1) $f $g $h) ;; fails after $f and $g 532 (elem (i32.const 0) $f) ;; is not applied 533 (data (i32.const 0) "\\01") ;; is not applied 534 (func $f) 535 (func $g) 536 (func $h))`)); 537 var mem = new Memory({initial:1}); 538 var tbl = new Table({initial:3, element:"anyfunc"}); 539 assertSegmentFitError(() => new Instance(m, {"":{mem, tbl}})); 540 assertEq(tbl.get(0), null); 541 assertEq(tbl.get(1), null); 542 assertEq(tbl.get(2), null); 543 var v = new Uint8Array(mem.buffer); 544 assertEq(v[0], 0); 545 546 // Data segment doesn't apply and prevents subsequent data segment from 547 // being applied. 548 549 var m = new Module(wasmTextToBinary( 550 `(module 551 (import "" "mem" (memory 1)) 552 (data (i32.const 65534) "\\01\\02\\03") ;; fails after 1 and 2 553 (data (i32.const 0) "\\04") ;; is not applied 554 )`)); 555 var mem = new Memory({initial:1}); 556 assertSegmentFitError(() => new Instance(m, {"":{mem}})); 557 var v = new Uint8Array(mem.buffer); 558 assertEq(v[65534], 0); 559 assertEq(v[65535], 0); 560 assertEq(v[0], 0); 561 562 // Elem segments on imported tables 563 564 var m = new Module(wasmTextToBinary(` 565 (module 566 (import "a" "b" (table 10 funcref)) 567 (elem (i32.const 0) $one $two) 568 (elem (i32.const 3) $three $four) 569 (func $one (result i32) (i32.const 1)) 570 (func $two (result i32) (i32.const 2)) 571 (func $three (result i32) (i32.const 3)) 572 (func $four (result i32) (i32.const 4))) 573 `)); 574 var tbl = new Table({initial:10, element:"anyfunc"}); 575 new Instance(m, {a:{b:tbl}}); 576 assertEq(tbl.get(0)(), 1); 577 assertEq(tbl.get(1)(), 2); 578 assertEq(tbl.get(2), null); 579 assertEq(tbl.get(3)(), 3); 580 assertEq(tbl.get(4)(), 4); 581 for (var i = 5; i < 10; i++) 582 assertEq(tbl.get(i), null); 583 584 var m = new Module(wasmTextToBinary(` 585 (module 586 (func $their1 (import "" "func") (result i32)) 587 (func $their2 (import "" "func")) 588 (table (import "" "table") 4 funcref) 589 (func $my (result i32) i32.const 13) 590 (elem (i32.const 1) $my) 591 (elem (i32.const 2) $their1) 592 (elem (i32.const 3) $their2) 593 ) 594 `)); 595 var tbl = new Table({initial:4, element:"anyfunc"}); 596 var f = () => 42; 597 new Instance(m, { "": { table: tbl, func: f} }); 598 assertEq(tbl.get(0), null); 599 assertEq(tbl.get(1)(), 13); 600 assertEq(tbl.get(2)(), 42); 601 assertEq(tbl.get(3)(), undefined); 602 603 // Cross-instance calls 604 605 var i1 = new Instance(new Module(wasmTextToBinary(`(module (func) (func (param i32) (result i32) (i32.add (local.get 0) (i32.const 1))) (func) (export "f" (func 1)))`))); 606 var i2 = new Instance(new Module(wasmTextToBinary(`(module (import "a" "b" (func $imp (param i32) (result i32))) (func $g (result i32) (call $imp (i32.const 13))) (export "g" (func $g)))`)), {a:{b:i1.exports.f}}); 607 assertEq(i2.exports.g(), 14); 608 609 var i1 = new Instance(new Module(wasmTextToBinary(`(module 610 (memory 1 1) 611 (data (i32.const 0) "\\42") 612 (func $f (result i32) (i32.load (i32.const 0))) 613 (export "f" (func $f)) 614 )`))); 615 var i2 = new Instance(new Module(wasmTextToBinary(`(module 616 (import "a" "b" (func $imp (result i32))) 617 (memory 1 1) 618 (data (i32.const 0) "\\13") 619 (table 2 2 funcref) 620 (elem (i32.const 0) $imp $def) 621 (func $def (result i32) (i32.load (i32.const 0))) 622 (type $v2i (func (result i32))) 623 (func $call (param i32) (result i32) (call_indirect (type $v2i) (local.get 0))) 624 (export "call" (func $call)) 625 )`)), {a:{b:i1.exports.f}}); 626 assertEq(i2.exports.call(0), 0x42); 627 assertEq(i2.exports.call(1), 0x13); 628 629 var m = new Module(wasmTextToBinary(`(module 630 (import "a" "val" (global $val i32)) 631 (import "a" "next" (func $next (result i32))) 632 (memory 1) 633 (func $start (i32.store (i32.const 0) (global.get $val))) 634 (start $start) 635 (func $call (result i32) 636 (i32.add 637 (global.get $val) 638 (i32.add 639 (i32.load (i32.const 0)) 640 (call $next)))) 641 (export "call" (func $call)) 642 )`)); 643 var e = {call:() => 1000}; 644 for (var i = 0; i < 10; i++) 645 e = new Instance(m, {a:{val:i, next:e.call}}).exports; 646 assertEq(e.call(), 1090); 647 648 (function testImportJitExit() { 649 let options = getJitCompilerOptions(); 650 if (!options['baseline.enable']) 651 return; 652 653 let baselineTrigger = options['baseline.warmup.trigger']; 654 655 let valueToConvert = 0; 656 function ffi(n) { if (n == 1337) { return valueToConvert }; return 42; } 657 658 function sum(a, b, c) { 659 if (a === 1337) 660 return valueToConvert; 661 return (a|0) + (b|0) + (c|0) | 0; 662 } 663 664 // Baseline compile ffis. 665 for (let i = baselineTrigger + 1; i --> 0;) { 666 ffi(i); 667 sum((i%2)?i:undefined, 668 (i%3)?i:undefined, 669 (i%4)?i:undefined); 670 } 671 672 let imports = { 673 a: { 674 ffi, 675 sum 676 } 677 }; 678 679 i = wasmEvalText(`(module 680 (import "a" "ffi" (func $ffi (param i32) (result i32))) 681 682 (import "a" "sum" (func $missingOneArg (param i32) (param i32) (result i32))) 683 (import "a" "sum" (func $missingTwoArgs (param i32) (result i32))) 684 (import "a" "sum" (func $missingThreeArgs (result i32))) 685 686 (func (export "foo") (param i32) (result i32) 687 local.get 0 688 call $ffi 689 ) 690 691 (func (export "missThree") (result i32) 692 call $missingThreeArgs 693 ) 694 695 (func (export "missTwo") (param i32) (result i32) 696 local.get 0 697 call $missingTwoArgs 698 ) 699 700 (func (export "missOne") (param i32) (param i32) (result i32) 701 local.get 0 702 local.get 1 703 call $missingOneArg 704 ) 705 )`, imports).exports; 706 707 // Enable the jit exit for each JS callee. 708 assertEq(i.foo(0), 42); 709 710 assertEq(i.missThree(), 0); 711 assertEq(i.missTwo(42), 42); 712 assertEq(i.missOne(13, 37), 50); 713 714 // Test the jit exit under normal conditions. 715 assertEq(i.foo(0), 42); 716 assertEq(i.foo(1337), 0); 717 718 // Test the arguments rectifier. 719 assertEq(i.missThree(), 0); 720 assertEq(i.missTwo(-1), -1); 721 assertEq(i.missOne(23, 10), 33); 722 723 // Test OOL coercion. 724 valueToConvert = 2**31; 725 assertEq(i.foo(1337), -(2**31)); 726 727 // Test OOL error path. 728 valueToConvert = { valueOf() { throw new Error('make ffi great again'); } } 729 assertErrorMessage(() => i.foo(1337), Error, "make ffi great again"); 730 731 valueToConvert = { toString() { throw new Error('a FFI to believe in'); } } 732 assertErrorMessage(() => i.foo(1337), Error, "a FFI to believe in"); 733 734 // Test the error path in the arguments rectifier. 735 assertErrorMessage(() => i.missTwo(1337), Error, "a FFI to believe in"); 736 })(); 737 738 (function testCrossRealmImport() { 739 var g = newGlobal({sameCompartmentAs: this}); 740 g.evaluate("function f1() { assertCorrectRealm(); return 123; }"); 741 g.mem = new Memory({initial:8}); 742 743 // The memory.size builtin asserts cx->realm matches instance->realm so 744 // we call it here. 745 var i1 = new Instance(new Module(wasmTextToBinary(` 746 (module 747 (import "a" "f1" (func $imp1 (result i32))) 748 (import "a" "f2" (func $imp2 (result i32))) 749 (import "a" "m" (memory 1)) 750 (func $test (result i32) 751 (i32.add 752 (i32.add 753 (i32.add (memory.size) (call $imp1)) 754 (memory.size)) 755 (call $imp2))) 756 (export "impstub" (func $imp1)) 757 (export "test" (func $test))) 758 `)), {a:{m:g.mem, f1:g.f1, f2:g.Math.abs}}); 759 760 for (var i = 0; i < 20; i++) { 761 assertEq(i1.exports.impstub(), 123); 762 assertEq(i1.exports.test(), 139); 763 } 764 765 // Inter-module/inter-realm wasm => wasm calls. 766 var src = ` 767 (module 768 (import "a" "othertest" (func $imp (result i32))) 769 (import "a" "m" (memory 1)) 770 (func (result i32) (i32.add (call $imp) (memory.size))) 771 (export "test" (func 1))) 772 `; 773 g.i1 = i1; 774 g.evaluate("i2 = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`" + src + "`)), {a:{m:mem,othertest:i1.exports.test}})"); 775 for (var i = 0; i < 20; i++) 776 assertEq(g.i2.exports.test(), 147); 777 })(); 778 779 // The name presented in toString and as the fn.name property is the index of the 780 // function within the module. See bug 1714505 for analysis. 781 782 var ins = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(` 783 (module 784 (func (export "myfunc") (result i32) 785 (i32.const 1337)) 786 (func $hi (result i32) 787 (i32.const 3)) 788 (func $abracadabra (export "bletch") (result i32) 789 (i32.const -1)))`))) 790 assertEq(String(ins.exports.myfunc), "function 0() {\n [native code]\n}") 791 assertEq(ins.exports.myfunc.name, "0"); 792 assertEq(String(ins.exports.bletch), "function 2() {\n [native code]\n}") 793 assertEq(ins.exports.bletch.name, "2")