js-api.js (12134B)
1 // Tests for wasm exception proposal JS API features. 2 3 load(libdir + "eqArrayHelper.js"); 4 5 // WebAssembly.Tag tests. 6 assertErrorMessage( 7 () => WebAssembly.Tag(), 8 TypeError, 9 /calling a builtin Tag constructor without new is forbidden/ 10 ); 11 12 assertErrorMessage( 13 () => new WebAssembly.Tag(), 14 TypeError, 15 /At least 1 argument required/ 16 ); 17 18 assertErrorMessage( 19 () => new WebAssembly.Tag(3), 20 TypeError, 21 /first argument must be a tag descriptor/ 22 ); 23 24 assertErrorMessage( 25 () => new WebAssembly.Tag({ parameters: ["foobar"] }), 26 TypeError, 27 /bad value type/ 28 ); 29 30 new WebAssembly.Tag({ parameters: [] }); 31 new WebAssembly.Tag({ parameters: ["i32"] }); 32 new WebAssembly.Tag({ parameters: ["i32", "externref"] }); 33 34 wasmEvalText(`(module (import "m" "e" (tag)))`, { 35 m: { e: new WebAssembly.Tag({ parameters: [] }) }, 36 }); 37 38 wasmEvalText(`(module (import "m" "e" (tag (param i32))))`, { 39 m: { e: new WebAssembly.Tag({ parameters: ["i32"] }) }, 40 }); 41 42 wasmEvalText(`(module (import "m" "e" (tag (param i32 i64))))`, { 43 m: { e: new WebAssembly.Tag({ parameters: ["i32", "i64"] }) }, 44 }); 45 46 assertErrorMessage( 47 () => 48 wasmEvalText(`(module (import "m" "e" (tag (param i32))))`, { 49 m: { e: new WebAssembly.Tag({ parameters: [] }) }, 50 }), 51 WebAssembly.LinkError, 52 /imported tag 'm.e' signature mismatch/ 53 ); 54 55 assertErrorMessage( 56 () => 57 wasmEvalText(`(module (import "m" "e" (tag (param))))`, { 58 m: { e: new WebAssembly.Tag({ parameters: ["i32"] }) }, 59 }), 60 WebAssembly.LinkError, 61 /imported tag 'm.e' signature mismatch/ 62 ); 63 64 // Test WebAssembly.Tag methods. 65 // TODO: add runtime detection for js-types 66 // { 67 // let params = [ 68 // [], 69 // ["i32"], 70 // ["i32", "i64"], 71 // ["f32", "externref"], 72 // ["i32", "i64", "f32", "f64"], 73 // ]; 74 75 // for (const arg of params) { 76 // const tag = new WebAssembly.Tag({ parameters: arg }); 77 // assertEqArray(tag.type().parameters, arg); 78 // } 79 // } 80 81 // WebAssembly.Exception tests. 82 assertErrorMessage( 83 () => WebAssembly.Exception(), 84 TypeError, 85 /calling a builtin Exception constructor without new is forbidden/ 86 ); 87 88 assertErrorMessage( 89 () => new WebAssembly.Exception(), 90 TypeError, 91 /At least 2 arguments required/ 92 ); 93 94 assertErrorMessage( 95 () => new WebAssembly.Exception(3, []), 96 TypeError, 97 /first argument must be a WebAssembly.Tag/ 98 ); 99 100 const { tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9 } = wasmEvalText( 101 `(module 102 (tag (export "tag1") (param)) 103 (tag (export "tag2") (param i32)) 104 (tag (export "tag3") (param i32 f32)) 105 (tag (export "tag4") (param i32 externref i32)) 106 (tag (export "tag5") (param i32 externref i32 externref)) 107 (tag (export "tag6") (param funcref)) 108 (tag (export "tag7") (param i64)) 109 (tag (export "tag8") (param i32 f64)) 110 (tag (export "tag9") (param externref funcref)))` 111 ).exports; 112 113 new WebAssembly.Exception(tag1, []); 114 new WebAssembly.Exception(tag2, [3]); 115 new WebAssembly.Exception(tag3, [3, 5.5]); 116 new WebAssembly.Exception(tag4, [3, "foo", 4]); 117 new WebAssembly.Exception(tag5, [3, "foo", 4, "bar"]); 118 119 assertErrorMessage( 120 () => new WebAssembly.Exception(tag2, []), 121 TypeError, 122 /expected 1 values but got 0/ 123 ); 124 125 assertErrorMessage( 126 () => new WebAssembly.Exception(tag2, [3n]), 127 TypeError, 128 /can't convert BigInt to number/ 129 ); 130 131 assertErrorMessage( 132 () => new WebAssembly.Exception(tag6, [undefined]), 133 TypeError, 134 /can only pass WebAssembly exported functions to funcref/ 135 ); 136 137 assertErrorMessage( 138 () => new WebAssembly.Exception(tag7, [undefined]), 139 TypeError, 140 /can't convert undefined to BigInt/ 141 ); 142 143 assertErrorMessage( 144 () => new WebAssembly.Exception(tag7, {}), 145 TypeError, 146 /\({}\) is not iterable/ 147 ); 148 149 assertErrorMessage( 150 () => new WebAssembly.Exception(tag7, 1), 151 TypeError, 152 /second argument must be an object/ 153 ); 154 155 // Exnref cannot cross the JS/wasm boundary as a function parameter. 156 var inst = wasmEvalText(` 157 (module 158 (func (export "f") (result nullexnref) 159 unreachable 160 ) 161 )`); 162 assertErrorMessage(() => inst.exports.f(), TypeError, /cannot pass value to or from JS/); 163 164 inst = wasmEvalText(` 165 (module 166 (func (export "f") (result exnref) 167 unreachable 168 ) 169 )`); 170 assertErrorMessage(() => inst.exports.f(), TypeError, /cannot pass value to or from JS/); 171 172 inst = wasmEvalText(` 173 (module 174 (func (export "f") (result (ref exn)) 175 unreachable 176 ) 177 )`); 178 assertErrorMessage(() => inst.exports.f(), TypeError, /cannot pass value to or from JS/); 179 180 inst = wasmEvalText(` 181 (module 182 (func (export "f") (result (ref noexn)) 183 unreachable 184 ) 185 )`); 186 assertErrorMessage(() => inst.exports.f(), TypeError, /cannot pass value to or from JS/); 187 188 // Test Exception methods. 189 { 190 const exn1 = new WebAssembly.Exception(tag1, []); 191 assertEq(exn1.is(tag1), true); 192 assertEq(exn1.is(tag2), false); 193 assertErrorMessage( 194 () => exn1.is(), 195 TypeError, 196 /At least 1 argument required/ 197 ); 198 assertErrorMessage( 199 () => exn1.is(5), 200 TypeError, 201 /first argument must be a WebAssembly.Tag/ 202 ); 203 204 const exn2 = new WebAssembly.Exception(tag2, [3]); 205 assertEq(exn2.getArg(tag2, 0), 3); 206 207 assertEq(new WebAssembly.Exception(tag2, [undefined]).getArg(tag2, 0), 0); 208 209 const exn4 = new WebAssembly.Exception(tag4, [3, "foo", 4]); 210 assertEq(exn4.getArg(tag4, 0), 3); 211 assertEq(exn4.getArg(tag4, 1), "foo"); 212 assertEq(exn4.getArg(tag4, 2), 4); 213 214 const exn5 = new WebAssembly.Exception(tag5, [3, "foo", 4, "bar"]); 215 assertEq(exn5.getArg(tag5, 3), "bar"); 216 217 const { funcref } = wasmEvalText( 218 `(module (func (export "funcref")))` 219 ).exports; 220 const exn9 = new WebAssembly.Exception(tag9, ["foo", funcref]); 221 assertEq(exn9.getArg(tag9, 0), "foo"); 222 assertEq(exn9.getArg(tag9, 1), funcref); 223 224 assertErrorMessage( 225 () => exn2.getArg(), 226 TypeError, 227 /At least 2 arguments required/ 228 ); 229 assertErrorMessage( 230 () => exn2.getArg(5, 0), 231 TypeError, 232 /first argument must be a WebAssembly.Tag/ 233 ); 234 assertErrorMessage( 235 () => exn2.getArg(tag2, "foo"), 236 TypeError, 237 /bad Exception getArg index/ 238 ); 239 assertErrorMessage( 240 () => exn2.getArg(tag2, 10), 241 RangeError, 242 /bad Exception getArg index/ 243 ); 244 } 245 246 // Test throwing a JS constructed exception to Wasm. 247 assertEq( 248 wasmEvalText( 249 `(module 250 (import "m" "exn" (tag $exn (param i32))) 251 (import "m" "f" (func $f)) 252 (func (export "f") (result i32) 253 try (result i32) 254 call $f 255 (i32.const 0) 256 catch $exn 257 end))`, 258 { 259 m: { 260 exn: tag2, 261 f: () => { 262 throw new WebAssembly.Exception(tag2, [42]); 263 }, 264 }, 265 } 266 ).exports.f(), 267 42 268 ); 269 270 assertEqArray( 271 wasmEvalText( 272 `(module 273 (import "m" "exn" (tag $exn (param i32 f32))) 274 (import "m" "f" (func $f)) 275 (func (export "f") (result i32 f32) 276 try (result i32 f32) 277 call $f 278 (i32.const 0) 279 (f32.const 0) 280 catch $exn 281 end))`, 282 { 283 m: { 284 exn: tag3, 285 f: () => { 286 throw new WebAssembly.Exception(tag3, [42, 5.5]); 287 }, 288 }, 289 } 290 ).exports.f(), 291 [42, 5.5] 292 ); 293 294 assertEqArray( 295 wasmEvalText( 296 `(module 297 (import "m" "exn" (tag $exn (param i32 f64))) 298 (import "m" "f" (func $f)) 299 (func (export "f") (result i32 f64) 300 try (result i32 f64) 301 call $f 302 (i32.const 0) 303 (f64.const 0) 304 catch $exn 305 end))`, 306 { 307 m: { 308 exn: tag8, 309 f: () => { 310 throw new WebAssembly.Exception(tag8, [9999, 9999]); 311 }, 312 }, 313 } 314 ).exports.f(), 315 [9999, 9999] 316 ); 317 318 assertEqArray( 319 wasmEvalText( 320 `(module 321 (import "m" "exn" (tag $exn (param i32 externref i32))) 322 (import "m" "f" (func $f)) 323 (func (export "f") (result i32 externref i32) 324 try (result i32 externref i32) 325 call $f 326 (i32.const 0) 327 (ref.null extern) 328 (i32.const 0) 329 catch $exn 330 end))`, 331 { 332 m: { 333 exn: tag4, 334 f: () => { 335 throw new WebAssembly.Exception(tag4, [42, "foo", 42]); 336 }, 337 }, 338 } 339 ).exports.f(), 340 [42, "foo", 42] 341 ); 342 343 assertEqArray( 344 wasmEvalText( 345 `(module 346 (import "m" "exn" (tag $exn (param i32 externref i32 externref))) 347 (import "m" "f" (func $f)) 348 (func (export "f") (result i32 externref i32 externref) 349 try (result i32 externref i32 externref) 350 call $f 351 (i32.const 0) 352 (ref.null extern) 353 (i32.const 0) 354 (ref.null extern) 355 catch $exn 356 end))`, 357 { 358 m: { 359 exn: tag5, 360 f: () => { 361 throw new WebAssembly.Exception(tag5, [42, "foo", 42, "bar"]); 362 }, 363 }, 364 } 365 ).exports.f(), 366 [42, "foo", 42, "bar"] 367 ); 368 369 { 370 const { funcref } = wasmEvalText( 371 `(module (func (export "funcref")))` 372 ).exports; 373 assertEqArray( 374 wasmEvalText( 375 `(module 376 (import "m" "exn" (tag $exn (param externref funcref))) 377 (import "m" "f" (func $f)) 378 (func (export "f") (result externref funcref) 379 try (result externref funcref) 380 call $f 381 (ref.null extern) 382 (ref.null func) 383 catch $exn 384 end))`, 385 { 386 m: { 387 exn: tag9, 388 f: () => { 389 throw new WebAssembly.Exception(tag9, ["foo", funcref]); 390 }, 391 }, 392 } 393 ).exports.f(), 394 ["foo", funcref] 395 ); 396 } 397 398 assertEq( 399 wasmEvalText( 400 `(module 401 (import "m" "exn" (tag $exn)) 402 (import "m" "f" (func $f)) 403 (func (export "f") (result i32) 404 try (result i32) 405 call $f 406 (i32.const 0) 407 catch $exn 408 (i32.const 0) 409 catch_all 410 (i32.const 1) 411 end))`, 412 { 413 m: { 414 exn: tag1, 415 f: () => { 416 throw new WebAssembly.Exception(tag2, [42]); 417 }, 418 }, 419 } 420 ).exports.f(), 421 1 422 ); 423 424 { 425 const exn = new WebAssembly.Tag({ parameters: ["i32"] }); 426 assertEq( 427 wasmEvalText( 428 `(module 429 (import "m" "exn" (tag $exn (param i32))) 430 (import "m" "f" (func $f)) 431 (func (export "f") (result i32) 432 try (result i32) 433 call $f 434 (i32.const 0) 435 catch $exn 436 end))`, 437 { 438 m: { 439 exn, 440 f: () => { 441 throw new WebAssembly.Exception(exn, [42]); 442 }, 443 }, 444 } 445 ).exports.f(), 446 42 447 ); 448 } 449 450 { 451 const exn1 = new WebAssembly.Tag({ parameters: ["i32"] }); 452 const exn2 = new WebAssembly.Tag({ parameters: ["i32"] }); 453 assertEq( 454 wasmEvalText( 455 `(module 456 (import "m" "exn" (tag $exn (param i32))) 457 (import "m" "f" (func $f)) 458 (func (export "f") (result i32) 459 try (result i32) 460 call $f 461 (i32.const 0) 462 catch $exn 463 catch_all 464 (i32.const 1) 465 end))`, 466 { 467 m: { 468 exn: exn1, 469 f: () => { 470 throw new WebAssembly.Exception(exn2, [42]); 471 }, 472 }, 473 } 474 ).exports.f(), 475 1 476 ); 477 } 478 479 // Test `getArg` on a Wasm-thrown exception. 480 assertEq( 481 (() => { 482 try { 483 wasmEvalText( 484 `(module 485 (import "m" "exn" (tag $exn (param i32 f64))) 486 (func (export "f") 487 (i32.const 9999) 488 (f64.const 9999) 489 throw $exn))`, 490 { m: { exn: tag8 } } 491 ).exports.f(); 492 } catch (exn) { 493 return exn.getArg(tag8, 1); 494 } 495 })(), 496 9999 497 ); 498 499 assertEqArray( 500 (() => { 501 try { 502 wasmEvalText( 503 `(module 504 (import "m" "exn" (tag $exn (param i32 externref i32 externref))) 505 (func (export "f") (param externref externref) 506 (i32.const 1) 507 (local.get 0) 508 (i32.const 2) 509 (local.get 1) 510 throw $exn))`, 511 { m: { exn: tag5 } } 512 ).exports.f("foo", "bar"); 513 } catch (exn) { 514 return [ 515 exn.getArg(tag5, 0), 516 exn.getArg(tag5, 1), 517 exn.getArg(tag5, 2), 518 exn.getArg(tag5, 3), 519 ]; 520 } 521 })(), 522 [1, "foo", 2, "bar"] 523 );