shell.js (15524B)
1 // GENERATED, DO NOT EDIT 2 // file: asyncHelpers.js 3 // Copyright (C) 2022 Igalia, S.L. All rights reserved. 4 // This code is governed by the BSD license found in the LICENSE file. 5 /*--- 6 description: | 7 A collection of assertion and wrapper functions for testing asynchronous built-ins. 8 defines: [asyncTest, assert.throwsAsync] 9 ---*/ 10 11 /** 12 * Defines the **sole** asynchronous test of a file. 13 * @see {@link ../docs/rfcs/async-helpers.md} for background. 14 * 15 * @param {Function} testFunc a callback whose returned promise indicates test results 16 * (fulfillment for success, rejection for failure) 17 * @returns {void} 18 */ 19 function asyncTest(testFunc) { 20 if (!Object.prototype.hasOwnProperty.call(globalThis, "$DONE")) { 21 throw new Test262Error("asyncTest called without async flag"); 22 } 23 if (typeof testFunc !== "function") { 24 $DONE(new Test262Error("asyncTest called with non-function argument")); 25 return; 26 } 27 try { 28 testFunc().then( 29 function () { 30 $DONE(); 31 }, 32 function (error) { 33 $DONE(error); 34 } 35 ); 36 } catch (syncError) { 37 $DONE(syncError); 38 } 39 } 40 41 /** 42 * Asserts that a callback asynchronously throws an instance of a particular 43 * error (i.e., returns a promise whose rejection value is an object referencing 44 * the constructor). 45 * 46 * @param {Function} expectedErrorConstructor the expected constructor of the 47 * rejection value 48 * @param {Function} func the callback 49 * @param {string} [message] the prefix to use for failure messages 50 * @returns {Promise<void>} fulfills if the expected error is thrown, 51 * otherwise rejects 52 */ 53 assert.throwsAsync = function (expectedErrorConstructor, func, message) { 54 return new Promise(function (resolve) { 55 var fail = function (detail) { 56 if (message === undefined) { 57 throw new Test262Error(detail); 58 } 59 throw new Test262Error(message + " " + detail); 60 }; 61 if (typeof expectedErrorConstructor !== "function") { 62 fail("assert.throwsAsync called with an argument that is not an error constructor"); 63 } 64 if (typeof func !== "function") { 65 fail("assert.throwsAsync called with an argument that is not a function"); 66 } 67 var expectedName = expectedErrorConstructor.name; 68 var expectation = "Expected a " + expectedName + " to be thrown asynchronously"; 69 var res; 70 try { 71 res = func(); 72 } catch (thrown) { 73 fail(expectation + " but the function threw synchronously"); 74 } 75 if (res === null || typeof res !== "object" || typeof res.then !== "function") { 76 fail(expectation + " but result was not a thenable"); 77 } 78 var onResFulfilled, onResRejected; 79 var resSettlementP = new Promise(function (onFulfilled, onRejected) { 80 onResFulfilled = onFulfilled; 81 onResRejected = onRejected; 82 }); 83 try { 84 res.then(onResFulfilled, onResRejected) 85 } catch (thrown) { 86 fail(expectation + " but .then threw synchronously"); 87 } 88 resolve(resSettlementP.then( 89 function () { 90 fail(expectation + " but no exception was thrown at all"); 91 }, 92 function (thrown) { 93 var actualName; 94 if (thrown === null || typeof thrown !== "object") { 95 fail(expectation + " but thrown value was not an object"); 96 } else if (thrown.constructor !== expectedErrorConstructor) { 97 actualName = thrown.constructor.name; 98 if (expectedName === actualName) { 99 fail(expectation + 100 " but got a different error constructor with the same name"); 101 } 102 fail(expectation + " but got a " + actualName); 103 } 104 } 105 )); 106 }); 107 }; 108 109 // file: atomicsHelper.js 110 // Copyright (C) 2017 Mozilla Corporation. All rights reserved. 111 // This code is governed by the BSD license found in the LICENSE file. 112 /*--- 113 description: > 114 Collection of functions used to interact with Atomics.* operations across agent boundaries. 115 defines: 116 - $262.agent.getReportAsync 117 - $262.agent.getReport 118 - $262.agent.safeBroadcastAsync 119 - $262.agent.safeBroadcast 120 - $262.agent.setTimeout 121 - $262.agent.tryYield 122 - $262.agent.trySleep 123 ---*/ 124 125 /** 126 * @return {String} A report sent from an agent. 127 */ 128 { 129 // This is only necessary because the original 130 // $262.agent.getReport API was insufficient. 131 // 132 // All runtimes currently have their own 133 // $262.agent.getReport which is wrong, so we 134 // will pave over it with a corrected version. 135 // 136 // Binding $262.agent is necessary to prevent 137 // breaking SpiderMonkey's $262.agent.getReport 138 let getReport = $262.agent.getReport.bind($262.agent); 139 140 $262.agent.getReport = function() { 141 var r; 142 while ((r = getReport()) == null) { 143 $262.agent.sleep(1); 144 } 145 return r; 146 }; 147 148 if (this.setTimeout === undefined) { 149 (function(that) { 150 that.setTimeout = function(callback, delay) { 151 let p = Promise.resolve(); 152 let start = Date.now(); 153 let end = start + delay; 154 function check() { 155 if ((end - Date.now()) > 0) { 156 p.then(check); 157 } 158 else { 159 callback(); 160 } 161 } 162 p.then(check); 163 } 164 })(this); 165 } 166 167 $262.agent.setTimeout = setTimeout; 168 169 $262.agent.getReportAsync = function() { 170 return new Promise(function(resolve) { 171 (function loop() { 172 let result = getReport(); 173 if (!result) { 174 setTimeout(loop, 1000); 175 } else { 176 resolve(result); 177 } 178 })(); 179 }); 180 }; 181 } 182 183 /** 184 * 185 * Share a given Int32Array or BigInt64Array to all running agents. Ensure that the 186 * provided TypedArray is a "shared typed array". 187 * 188 * NOTE: Migrating all tests to this API is necessary to prevent tests from hanging 189 * indefinitely when a SAB is sent to a worker but the code in the worker attempts to 190 * create a non-sharable TypedArray (something that is not Int32Array or BigInt64Array). 191 * When that scenario occurs, an exception is thrown and the agent worker can no 192 * longer communicate with any other threads that control the SAB. If the main 193 * thread happens to be spinning in the $262.agent.waitUntil() while loop, it will never 194 * meet its termination condition and the test will hang indefinitely. 195 * 196 * Because we've defined $262.agent.broadcast(SAB) in 197 * https://github.com/tc39/test262/blob/HEAD/INTERPRETING.md, there are host implementations 198 * that assume compatibility, which must be maintained. 199 * 200 * 201 * $262.agent.safeBroadcast(TA) should not be included in 202 * https://github.com/tc39/test262/blob/HEAD/INTERPRETING.md 203 * 204 * 205 * @param {(Int32Array|BigInt64Array)} typedArray An Int32Array or BigInt64Array with a SharedArrayBuffer 206 */ 207 $262.agent.safeBroadcast = function(typedArray) { 208 let Constructor = Object.getPrototypeOf(typedArray).constructor; 209 let temp = new Constructor( 210 new SharedArrayBuffer(Constructor.BYTES_PER_ELEMENT) 211 ); 212 try { 213 // This will never actually wait, but that's fine because we only 214 // want to ensure that this typedArray CAN be waited on and is shareable. 215 Atomics.wait(temp, 0, Constructor === Int32Array ? 1 : BigInt(1)); 216 } catch (error) { 217 throw new Test262Error(`${Constructor.name} cannot be used as a shared typed array. (${error})`); 218 } 219 220 $262.agent.broadcast(typedArray.buffer); 221 }; 222 223 $262.agent.safeBroadcastAsync = async function(ta, index, expected) { 224 await $262.agent.broadcast(ta.buffer); 225 await $262.agent.waitUntil(ta, index, expected); 226 await $262.agent.tryYield(); 227 return await Atomics.load(ta, index); 228 }; 229 230 231 /** 232 * With a given Int32Array or BigInt64Array, wait until the expected number of agents have 233 * reported themselves by calling: 234 * 235 * Atomics.add(typedArray, index, 1); 236 * 237 * @param {(Int32Array|BigInt64Array)} typedArray An Int32Array or BigInt64Array with a SharedArrayBuffer 238 * @param {number} index The index of which all agents will report. 239 * @param {number} expected The number of agents that are expected to report as active. 240 */ 241 $262.agent.waitUntil = function(typedArray, index, expected) { 242 243 var agents = 0; 244 while ((agents = Atomics.load(typedArray, index)) !== expected) { 245 /* nothing */ 246 } 247 assert.sameValue(agents, expected, "Reporting number of 'agents' equals the value of 'expected'"); 248 }; 249 250 /** 251 * Timeout values used throughout the Atomics tests. All timeouts are specified in milliseconds. 252 * 253 * @property {number} yield Used for `$262.agent.tryYield`. Must not be used in other functions. 254 * @property {number} small Used when agents will always timeout and `Atomics.wake` is not part 255 * of the test semantics. Must be larger than `$262.agent.timeouts.yield`. 256 * @property {number} long Used when some agents may timeout and `Atomics.wake` is called on some 257 * agents. The agents are required to wait and this needs to be observable 258 * by the main thread. 259 * @property {number} huge Used when `Atomics.wake` is called on all waiting agents. The waiting 260 * must not timeout. The agents are required to wait and this needs to be 261 * observable by the main thread. All waiting agents must be woken by the 262 * main thread. 263 * 264 * Usage for `$262.agent.timeouts.small`: 265 * const WAIT_INDEX = 0; 266 * const RUNNING = 1; 267 * const TIMEOUT = $262.agent.timeouts.small; 268 * const i32a = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2)); 269 * 270 * $262.agent.start(` 271 * $262.agent.receiveBroadcast(function(sab) { 272 * const i32a = new Int32Array(sab); 273 * Atomics.add(i32a, ${RUNNING}, 1); 274 * 275 * $262.agent.report(Atomics.wait(i32a, ${WAIT_INDEX}, 0, ${TIMEOUT})); 276 * 277 * $262.agent.leaving(); 278 * }); 279 * `); 280 * $262.agent.safeBroadcast(i32a.buffer); 281 * 282 * // Wait until the agent was started and then try to yield control to increase 283 * // the likelihood the agent has called `Atomics.wait` and is now waiting. 284 * $262.agent.waitUntil(i32a, RUNNING, 1); 285 * $262.agent.tryYield(); 286 * 287 * // The agent is expected to time out. 288 * assert.sameValue($262.agent.getReport(), "timed-out"); 289 * 290 * 291 * Usage for `$262.agent.timeouts.long`: 292 * const WAIT_INDEX = 0; 293 * const RUNNING = 1; 294 * const NUMAGENT = 2; 295 * const TIMEOUT = $262.agent.timeouts.long; 296 * const i32a = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2)); 297 * 298 * for (let i = 0; i < NUMAGENT; i++) { 299 * $262.agent.start(` 300 * $262.agent.receiveBroadcast(function(sab) { 301 * const i32a = new Int32Array(sab); 302 * Atomics.add(i32a, ${RUNNING}, 1); 303 * 304 * $262.agent.report(Atomics.wait(i32a, ${WAIT_INDEX}, 0, ${TIMEOUT})); 305 * 306 * $262.agent.leaving(); 307 * }); 308 * `); 309 * } 310 * $262.agent.safeBroadcast(i32a.buffer); 311 * 312 * // Wait until the agents were started and then try to yield control to increase 313 * // the likelihood the agents have called `Atomics.wait` and are now waiting. 314 * $262.agent.waitUntil(i32a, RUNNING, NUMAGENT); 315 * $262.agent.tryYield(); 316 * 317 * // Wake exactly one agent. 318 * assert.sameValue(Atomics.wake(i32a, WAIT_INDEX, 1), 1); 319 * 320 * // When it doesn't matter how many agents were woken at once, a while loop 321 * // can be used to make the test more resilient against intermittent failures 322 * // in case even though `tryYield` was called, the agents haven't started to 323 * // wait. 324 * // 325 * // // Repeat until exactly one agent was woken. 326 * // var woken = 0; 327 * // while ((woken = Atomics.wake(i32a, WAIT_INDEX, 1)) !== 0) ; 328 * // assert.sameValue(woken, 1); 329 * 330 * // One agent was woken and the other one timed out. 331 * const reports = [$262.agent.getReport(), $262.agent.getReport()]; 332 * assert(reports.includes("ok")); 333 * assert(reports.includes("timed-out")); 334 * 335 * 336 * Usage for `$262.agent.timeouts.huge`: 337 * const WAIT_INDEX = 0; 338 * const RUNNING = 1; 339 * const NUMAGENT = 2; 340 * const TIMEOUT = $262.agent.timeouts.huge; 341 * const i32a = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2)); 342 * 343 * for (let i = 0; i < NUMAGENT; i++) { 344 * $262.agent.start(` 345 * $262.agent.receiveBroadcast(function(sab) { 346 * const i32a = new Int32Array(sab); 347 * Atomics.add(i32a, ${RUNNING}, 1); 348 * 349 * $262.agent.report(Atomics.wait(i32a, ${WAIT_INDEX}, 0, ${TIMEOUT})); 350 * 351 * $262.agent.leaving(); 352 * }); 353 * `); 354 * } 355 * $262.agent.safeBroadcast(i32a.buffer); 356 * 357 * // Wait until the agents were started and then try to yield control to increase 358 * // the likelihood the agents have called `Atomics.wait` and are now waiting. 359 * $262.agent.waitUntil(i32a, RUNNING, NUMAGENT); 360 * $262.agent.tryYield(); 361 * 362 * // Wake all agents. 363 * assert.sameValue(Atomics.wake(i32a, WAIT_INDEX), NUMAGENT); 364 * 365 * // When it doesn't matter how many agents were woken at once, a while loop 366 * // can be used to make the test more resilient against intermittent failures 367 * // in case even though `tryYield` was called, the agents haven't started to 368 * // wait. 369 * // 370 * // // Repeat until all agents were woken. 371 * // for (var wokenCount = 0; wokenCount < NUMAGENT; ) { 372 * // var woken = 0; 373 * // while ((woken = Atomics.wake(i32a, WAIT_INDEX)) !== 0) ; 374 * // // Maybe perform an action on the woken agents here. 375 * // wokenCount += woken; 376 * // } 377 * 378 * // All agents were woken and none timeout. 379 * for (var i = 0; i < NUMAGENT; i++) { 380 * assert($262.agent.getReport(), "ok"); 381 * } 382 */ 383 $262.agent.timeouts = { 384 yield: 100, 385 small: 200, 386 long: 1000, 387 huge: 10000, 388 }; 389 390 /** 391 * Try to yield control to the agent threads. 392 * 393 * Usage: 394 * const VALUE = 0; 395 * const RUNNING = 1; 396 * const i32a = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2)); 397 * 398 * $262.agent.start(` 399 * $262.agent.receiveBroadcast(function(sab) { 400 * const i32a = new Int32Array(sab); 401 * Atomics.add(i32a, ${RUNNING}, 1); 402 * 403 * Atomics.store(i32a, ${VALUE}, 1); 404 * 405 * $262.agent.leaving(); 406 * }); 407 * `); 408 * $262.agent.safeBroadcast(i32a.buffer); 409 * 410 * // Wait until agent was started and then try to yield control. 411 * $262.agent.waitUntil(i32a, RUNNING, 1); 412 * $262.agent.tryYield(); 413 * 414 * // Note: This result is not guaranteed, but should hold in practice most of the time. 415 * assert.sameValue(Atomics.load(i32a, VALUE), 1); 416 * 417 * The default implementation simply waits for `$262.agent.timeouts.yield` milliseconds. 418 */ 419 $262.agent.tryYield = function() { 420 $262.agent.sleep($262.agent.timeouts.yield); 421 }; 422 423 /** 424 * Try to sleep the current agent for the given amount of milliseconds. It is acceptable, 425 * but not encouraged, to ignore this sleep request and directly continue execution. 426 * 427 * The default implementation calls `$262.agent.sleep(ms)`. 428 * 429 * @param {number} ms Time to sleep in milliseconds. 430 */ 431 $262.agent.trySleep = function(ms) { 432 $262.agent.sleep(ms); 433 }; 434 435 // file: detachArrayBuffer.js 436 // Copyright (C) 2016 the V8 project authors. All rights reserved. 437 // This code is governed by the BSD license found in the LICENSE file. 438 /*--- 439 description: | 440 A function used in the process of asserting correctness of TypedArray objects. 441 442 $262.detachArrayBuffer is defined by a host. 443 defines: [$DETACHBUFFER] 444 ---*/ 445 446 function $DETACHBUFFER(buffer) { 447 if (!$262 || typeof $262.detachArrayBuffer !== "function") { 448 throw new Test262Error("No method available to detach an ArrayBuffer"); 449 } 450 $262.detachArrayBuffer(buffer); 451 }