bigint.js (10882B)
1 // Used to ensure tests will trigger Wasm Jit stub code. 2 var threshold = 2 * getJitCompilerOptions()["ion.warmup.trigger"] + 10; 3 function testWithJit(f) { 4 for (var i = 0; i < threshold; i++) { 5 f(); 6 } 7 } 8 9 function testRet() { 10 var f = wasmEvalText(`(module 11 (func (export "f") (result i64) (i64.const 66)) 12 )`).exports.f; 13 14 testWithJit(() => { 15 assertEq(typeof f(), "bigint", "should return a bigint"); 16 assertEq(f(), 66n, "should return the correct value"); 17 }); 18 } 19 20 function testId() { 21 var exports = wasmEvalText(`(module 22 (func (export "f") (param i64 i64) (result i64) 23 (local.get 0) 24 ) 25 (func (export "f2") (param i64 i64) (result i64) 26 (local.get 1) 27 ) 28 )`).exports; 29 var f = exports.f; 30 var f2 = exports.f2; 31 32 testWithJit(() => { 33 assertEq(f(0n, 1n), 0n); 34 assertEq(f(-0n, 1n), -0n); 35 assertEq(f(123n, 1n), 123n); 36 assertEq(f(-123n, 1n), -123n); 37 assertEq(f(2n ** 63n, 1n), -(2n ** 63n)); 38 assertEq(f(2n ** 64n + 123n, 1n), 123n); 39 assertEq(f("5", 1n), 5n); 40 assertEq(f(true, 1n), 1n); 41 assertEq(f(false, 1n), 0n); 42 assertEq(f({ toString() { return "5"; }, }, 1n), 5n); 43 assertEq(f({ valueOf() { return 5n; }, }, 1n), 5n); 44 45 assertEq(f2(1n, 0n), 0n); 46 assertEq(f2(1n, -0n), -0n); 47 assertEq(f2(1n, 123n), 123n); 48 assertEq(f2(1n, -123n), -123n); 49 assertEq(f2(1n, 2n ** 63n), -(2n ** 63n)); 50 assertEq(f2(1n, 2n ** 64n + 123n), 123n); 51 assertEq(f2(1n, "5"), 5n); 52 assertEq(f2(1n, true), 1n); 53 assertEq(f2(1n, false), 0n); 54 assertEq(f2(1n, { toString() { return "5"; }, }), 5n); 55 assertEq(f2(1n, { valueOf() { return 5n; }, }), 5n); 56 }); 57 } 58 59 function testNonBigIntArgs() { 60 var f = wasmEvalText(`(module 61 (func (export "f") (param i64) (result i64) 62 (local.get 0) 63 ) 64 )`).exports.f; 65 66 assertErrorMessage(() => f(5), TypeError, "can't convert 5 to BigInt"); 67 assertErrorMessage(() => f({ valueOf() { return 5; }, }), 68 TypeError, 69 "can't convert 5 to BigInt"); 70 assertErrorMessage(() => f(5.3), TypeError, "can't convert 5.3 to BigInt"); 71 assertErrorMessage(() => f(), TypeError, "can't convert undefined to BigInt"); 72 assertErrorMessage( 73 () => f(undefined), 74 TypeError, 75 "can't convert undefined to BigInt" 76 ); 77 assertErrorMessage(() => f(null), TypeError, "can't convert null to BigInt"); 78 assertErrorMessage( 79 () => f(Symbol("foo")), 80 TypeError, 81 'can\'t convert Symbol("foo") to BigInt' 82 ); 83 assertErrorMessage(() => f({}), SyntaxError, "invalid BigInt syntax"); 84 assertErrorMessage(() => f({ valueof() { return "foo"; }, }), 85 SyntaxError, 86 "invalid BigInt syntax"); 87 assertErrorMessage(() => f("x"), SyntaxError, "invalid BigInt syntax"); 88 } 89 90 function testIdPlus() { 91 var f = wasmEvalText(`(module 92 (func (export "f") (param i64) (result i64) 93 (i64.const 8) 94 (local.get 0) 95 (i64.add) 96 ) 97 )`).exports.f; 98 99 testWithJit(() => { 100 assertEq(f(0n), 0n + 8n); 101 assertEq(f(147n), 147n + 8n); 102 }); 103 } 104 105 // Test functions with many parameters to stress ABI cases. We want to test 106 // spilled arguments both under and over the Ion call inlining limit. 107 function testManyArgs() { 108 var f1 = wasmEvalText(`(module 109 (func (export "f") 110 (param i64 i64 i64 i64 i64 i64 i64 i64) 111 (result i64) 112 (local.get 0) 113 (local.get 1) 114 (local.get 2) 115 (local.get 3) 116 (local.get 4) 117 (local.get 5) 118 (local.get 6) 119 (local.get 7) 120 (i64.add) 121 (i64.add) 122 (i64.add) 123 (i64.add) 124 (i64.add) 125 (i64.add) 126 (i64.add) 127 ) 128 )`).exports.f; 129 130 var f2 = wasmEvalText(`(module 131 (func (export "f") 132 (param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64) 133 (result i64) 134 (local.get 0) 135 (local.get 1) 136 (local.get 2) 137 (local.get 3) 138 (local.get 4) 139 (local.get 5) 140 (local.get 6) 141 (local.get 7) 142 (local.get 8) 143 (local.get 9) 144 (local.get 10) 145 (local.get 11) 146 (local.get 12) 147 (local.get 13) 148 (i64.add) 149 (i64.add) 150 (i64.add) 151 (i64.add) 152 (i64.add) 153 (i64.add) 154 (i64.add) 155 (i64.add) 156 (i64.add) 157 (i64.add) 158 (i64.add) 159 (i64.add) 160 (i64.add) 161 ) 162 )`).exports.f; 163 164 testWithJit(() => { 165 assertEq(f1(1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n), 8n); 166 assertEq(f2(1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n), 14n); 167 }); 168 } 169 170 // Test import and re-export. 171 function testImportExport() { 172 var f1 = wasmEvalText( 173 `(module 174 (import "i64" "func" (func (param i64))) 175 (export "f" (func 0)) 176 )`, 177 { 178 i64: { 179 func(b) { 180 assertEq(b, 42n); 181 }, 182 }, 183 } 184 ).exports.f; 185 186 var f2 = wasmEvalText( 187 `(module 188 (import "i64" "func" (func (param i64) (result i64))) 189 (export "f" (func 0)) 190 )`, 191 { 192 i64: { 193 func(n) { 194 return n + 1n; 195 }, 196 }, 197 } 198 ).exports.f; 199 200 var f3 = wasmEvalText( 201 `(module 202 (import "" "i64" (func $i64 (param i64) (result i64))) 203 (func (export "f") (param i64) (result i64) 204 (local.get 0) 205 (call $i64)) 206 )`, 207 { 208 "": { 209 i64: n => { 210 return n + 1n; 211 }, 212 }, 213 } 214 ).exports.f; 215 216 var f4 = wasmEvalText( 217 `(module 218 (import "i64" "func" (func (result i64))) 219 (export "f" (func 0)) 220 )`, 221 { i64: { func() {} } } 222 ).exports.f; 223 224 testWithJit(() => { 225 assertEq(f1(42n), undefined); 226 assertEq(f2(42n), 43n); 227 assertEq(f3(42n), 43n); 228 assertErrorMessage(() => f4(42), TypeError, "can't convert undefined to BigInt"); 229 }); 230 } 231 232 // Test that a mixture of I64 and other argument types works. 233 function testMixedArgs() { 234 var f = wasmEvalText(`(module 235 (func (export "f") 236 (param i64 f32 f64 i32 i64) 237 (result i64) 238 (local.get 1) 239 (i64.trunc_f32_s) 240 (local.get 2) 241 (i64.trunc_f64_s) 242 (i64.add) 243 (local.get 3) 244 (i64.extend_i32_u) 245 (i64.add) 246 (local.get 0) 247 (i64.add) 248 (local.get 4) 249 (i64.add) 250 ) 251 )`).exports.f; 252 253 testWithJit(() => { 254 assertEq(f(1n, 1.3, 1.7, 1, 1n), 5n); 255 }); 256 } 257 258 function testGlobalImport() { 259 var exports = wasmEvalText( 260 `(module 261 (import "g" "a" (global $a i64)) 262 (import "g" "b" (global $b i64)) 263 (import "g" "c" (global $c i64)) 264 265 (export "a" (global $a)) 266 (export "b" (global $b)) 267 (export "c" (global $c)) 268 )`, 269 { g: { a: 1n, b: 2n ** 63n, c: -100n } } 270 ).exports; 271 272 testWithJit(() => { 273 assertEq(exports.a.value, 1n); 274 assertEq(exports.b.value, -(2n ** 63n)); 275 assertEq(exports.c.value, -100n); 276 }); 277 } 278 279 function testMutableGlobalImport() { 280 var exports = wasmEvalText( 281 `(module 282 (import "g" "a" (global $a (mut i64))) 283 (import "g" "b" (global $b (mut i64))) 284 285 (export "a" (global $a)) 286 (export "b" (global $b)) 287 )`, 288 { 289 g: { 290 a: new WebAssembly.Global({ value: "i64", mutable: true }, 1n), 291 b: new WebAssembly.Global({ value: "i64", mutable: true }, "2"), 292 }, 293 } 294 ).exports; 295 296 testWithJit(() => { 297 assertEq(exports.a.value, 1n); 298 assertEq(exports.b.value, 2n); 299 }); 300 } 301 302 function testMutableGlobalImportLiteral() { 303 assertErrorMessage( 304 () => 305 wasmEvalText( 306 `(module 307 (import "g" "a" (global $a (mut i64))) 308 )`, 309 { g: { a: 1n } } 310 ), 311 WebAssembly.LinkError, 312 "imported global mutability mismatch" 313 ); 314 } 315 316 function testGlobalBadImportLiteral() { 317 assertErrorMessage( 318 () => 319 wasmEvalText( 320 `(module 321 (import "g" "a" (global $a i64)) 322 (export "a" (global $a)) 323 )`, 324 { g: { a: 1 } } 325 ), 326 WebAssembly.LinkError, 327 "import object field 'a' is not a BigInt" 328 ); 329 330 assertErrorMessage( 331 () => 332 wasmEvalText( 333 `(module 334 (import "g" "a" (global $a i64)) 335 (export "a" (global $a)) 336 )`, 337 { g: { a: "foo" } } 338 ), 339 WebAssembly.LinkError, 340 "import object field 'a' is not a BigInt" 341 ); 342 } 343 344 // This exercises error code paths that were added due to BigInt/I64 345 // conversion, though the test does not directly deal with I64 types. 346 function testGlobalBadImportNumber() { 347 assertErrorMessage( 348 () => 349 wasmEvalText( 350 `(module 351 (import "g" "a" (global $a i32)) 352 (export "a" (global $a)) 353 )`, 354 { g: { a: 1n } } 355 ), 356 WebAssembly.LinkError, 357 "import object field 'a' is not a Number" 358 ); 359 360 assertErrorMessage( 361 () => 362 wasmEvalText( 363 `(module 364 (import "g" "a" (global $a i32)) 365 (export "a" (global $a)) 366 )`, 367 { g: { a: "foo" } } 368 ), 369 WebAssembly.LinkError, 370 "import object field 'a' is not a Number" 371 ); 372 } 373 374 function testI64Global() { 375 var global = new WebAssembly.Global({ value: "i64", mutable: true }); 376 377 assertEq(global.value, 0n); // initial value 378 379 global.value = 123n; 380 assertEq(global.value, 123n); 381 382 global.value = 2n ** 63n; 383 assertEq(global.value, -(2n ** 63n)); 384 385 global.value = "123"; 386 assertEq(global.value, 123n); 387 } 388 389 function testI64GlobalValueOf() { 390 var argument = { value: "i64" }; 391 392 // as literal 393 var global = new WebAssembly.Global(argument, { 394 valueOf() { 395 return 123n; 396 }, 397 }); 398 assertEq(global.value, 123n); 399 400 // as string 401 var global2 = new WebAssembly.Global(argument, { 402 valueOf() { 403 return "123"; 404 }, 405 }); 406 assertEq(global.value, 123n); 407 } 408 409 function testGlobalI64ValueWrongType() { 410 var argument = { value: "i64" }; 411 assertErrorMessage( 412 () => new WebAssembly.Global(argument, 666), 413 TypeError, 414 "can't convert 666 to BigInt" 415 ); 416 assertErrorMessage( 417 () => new WebAssembly.Global(argument, "foo"), 418 SyntaxError, 419 "invalid BigInt syntax" 420 ); 421 assertErrorMessage( 422 () => 423 new WebAssembly.Global(argument, { 424 valueOf() { 425 return 5; 426 }, 427 }), 428 TypeError, 429 "can't convert 5 to BigInt" 430 ); 431 } 432 433 function testGlobalI64SetWrongType() { 434 var global = new WebAssembly.Global({ value: "i64", mutable: true }); 435 assertErrorMessage(() => (global.value = 1), TypeError, "can't convert 1 to BigInt"); 436 assertErrorMessage( 437 () => (global.value = "foo"), 438 SyntaxError, 439 "invalid BigInt syntax" 440 ); 441 assertErrorMessage( 442 () => 443 (global.value = { 444 valueOf() { 445 return 5; 446 }, 447 }), 448 TypeError, 449 "can't convert 5 to BigInt" 450 ); 451 } 452 453 testRet(); 454 testId(); 455 testIdPlus(); 456 testNonBigIntArgs(); 457 testManyArgs(); 458 testImportExport(); 459 testMixedArgs(); 460 testGlobalImport(); 461 testMutableGlobalImport(); 462 testMutableGlobalImportLiteral(); 463 testGlobalBadImportLiteral(); 464 testGlobalBadImportNumber(); 465 testI64Global(); 466 testI64GlobalValueOf(); 467 testGlobalI64ValueWrongType(); 468 testGlobalI64SetWrongType();