// GENERATED, DO NOT EDIT // file: asyncHelpers.js // Copyright (C) 2022 Igalia, S.L. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- description: | A collection of assertion and wrapper functions for testing asynchronous built-ins. defines: [asyncTest] ---*/ function asyncTest(testFunc) { if (!Object.hasOwn(globalThis, "$DONE")) { throw new Test262Error("asyncTest called without async flag"); } if (typeof testFunc !== "function") { $DONE(new Test262Error("asyncTest called with non-function argument")); return; } try { testFunc().then( function () { $DONE(); }, function (error) { $DONE(error); } ); } catch (syncError) { $DONE(syncError); } } assert.throwsAsync = async function (expectedErrorConstructor, func, message) { var innerThenable; if (message === undefined) { message = ""; } else { message += " "; } if (typeof func === "function") { try { innerThenable = func(); if ( innerThenable === null || typeof innerThenable !== "object" || typeof innerThenable.then !== "function" ) { message += "Expected to obtain an inner promise that would reject with a" + expectedErrorConstructor.name + " but result was not a thenable"; throw new Test262Error(message); } } catch (thrown) { message += "Expected a " + expectedErrorConstructor.name + " to be thrown asynchronously but an exception was thrown synchronously while obtaining the inner promise"; throw new Test262Error(message); } } else { message += "assert.throwsAsync called with an argument that is not a function"; throw new Test262Error(message); } try { return innerThenable.then( function () { message += "Expected a " + expectedErrorConstructor.name + " to be thrown asynchronously but no exception was thrown at all"; throw new Test262Error(message); }, function (thrown) { var expectedName, actualName; if (typeof thrown !== "object" || thrown === null) { message += "Thrown value was not an object!"; throw new Test262Error(message); } else if (thrown.constructor !== expectedErrorConstructor) { expectedName = expectedErrorConstructor.name; actualName = thrown.constructor.name; if (expectedName === actualName) { message += "Expected a " + expectedName + " but got a different error constructor with the same name"; } else { message += "Expected a " + expectedName + " but got a " + actualName; } throw new Test262Error(message); } } ); } catch (thrown) { if (typeof thrown !== "object" || thrown === null) { message += "Expected a " + expectedErrorConstructor.name + " to be thrown asynchronously but innerThenable synchronously threw a value that was not an object "; } else { message += "Expected a " + expectedErrorConstructor.name + " to be thrown asynchronously but a " + thrown.constructor.name + " was thrown synchronously"; } throw new Test262Error(message); } }; // file: atomicsHelper.js // Copyright (C) 2017 Mozilla Corporation. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- description: > Collection of functions used to interact with Atomics.* operations across agent boundaries. defines: - $262.agent.getReportAsync - $262.agent.getReport - $262.agent.safeBroadcastAsync - $262.agent.safeBroadcast - $262.agent.setTimeout - $262.agent.tryYield - $262.agent.trySleep ---*/ /** * @return {String} A report sent from an agent. */ { // This is only necessary because the original // $262.agent.getReport API was insufficient. // // All runtimes currently have their own // $262.agent.getReport which is wrong, so we // will pave over it with a corrected version. // // Binding $262.agent is necessary to prevent // breaking SpiderMonkey's $262.agent.getReport let getReport = $262.agent.getReport.bind($262.agent); $262.agent.getReport = function() { var r; while ((r = getReport()) == null) { $262.agent.sleep(1); } return r; }; if (this.setTimeout === undefined) { (function(that) { that.setTimeout = function(callback, delay) { let p = Promise.resolve(); let start = Date.now(); let end = start + delay; function check() { if ((end - Date.now()) > 0) { p.then(check); } else { callback(); } } p.then(check); } })(this); } $262.agent.setTimeout = setTimeout; $262.agent.getReportAsync = function() { return new Promise(function(resolve) { (function loop() { let result = getReport(); if (!result) { setTimeout(loop, 1000); } else { resolve(result); } })(); }); }; } /** * * Share a given Int32Array or BigInt64Array to all running agents. Ensure that the * provided TypedArray is a "shared typed array". * * NOTE: Migrating all tests to this API is necessary to prevent tests from hanging * indefinitely when a SAB is sent to a worker but the code in the worker attempts to * create a non-sharable TypedArray (something that is not Int32Array or BigInt64Array). * When that scenario occurs, an exception is thrown and the agent worker can no * longer communicate with any other threads that control the SAB. If the main * thread happens to be spinning in the $262.agent.waitUntil() while loop, it will never * meet its termination condition and the test will hang indefinitely. * * Because we've defined $262.agent.broadcast(SAB) in * https://github.com/tc39/test262/blob/HEAD/INTERPRETING.md, there are host implementations * that assume compatibility, which must be maintained. * * * $262.agent.safeBroadcast(TA) should not be included in * https://github.com/tc39/test262/blob/HEAD/INTERPRETING.md * * * @param {(Int32Array|BigInt64Array)} typedArray An Int32Array or BigInt64Array with a SharedArrayBuffer */ $262.agent.safeBroadcast = function(typedArray) { let Constructor = Object.getPrototypeOf(typedArray).constructor; let temp = new Constructor( new SharedArrayBuffer(Constructor.BYTES_PER_ELEMENT) ); try { // This will never actually wait, but that's fine because we only // want to ensure that this typedArray CAN be waited on and is shareable. Atomics.wait(temp, 0, Constructor === Int32Array ? 1 : BigInt(1)); } catch (error) { throw new Test262Error(`${Constructor.name} cannot be used as a shared typed array. (${error})`); } $262.agent.broadcast(typedArray.buffer); }; $262.agent.safeBroadcastAsync = async function(ta, index, expected) { await $262.agent.broadcast(ta.buffer); await $262.agent.waitUntil(ta, index, expected); await $262.agent.tryYield(); return await Atomics.load(ta, index); }; /** * With a given Int32Array or BigInt64Array, wait until the expected number of agents have * reported themselves by calling: * * Atomics.add(typedArray, index, 1); * * @param {(Int32Array|BigInt64Array)} typedArray An Int32Array or BigInt64Array with a SharedArrayBuffer * @param {number} index The index of which all agents will report. * @param {number} expected The number of agents that are expected to report as active. */ $262.agent.waitUntil = function(typedArray, index, expected) { var agents = 0; while ((agents = Atomics.load(typedArray, index)) !== expected) { /* nothing */ } assert.sameValue(agents, expected, "Reporting number of 'agents' equals the value of 'expected'"); }; /** * Timeout values used throughout the Atomics tests. All timeouts are specified in milliseconds. * * @property {number} yield Used for `$262.agent.tryYield`. Must not be used in other functions. * @property {number} small Used when agents will always timeout and `Atomics.wake` is not part * of the test semantics. Must be larger than `$262.agent.timeouts.yield`. * @property {number} long Used when some agents may timeout and `Atomics.wake` is called on some * agents. The agents are required to wait and this needs to be observable * by the main thread. * @property {number} huge Used when `Atomics.wake` is called on all waiting agents. The waiting * must not timeout. The agents are required to wait and this needs to be * observable by the main thread. All waiting agents must be woken by the * main thread. * * Usage for `$262.agent.timeouts.small`: * const WAIT_INDEX = 0; * const RUNNING = 1; * const TIMEOUT = $262.agent.timeouts.small; * const i32a = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2)); * * $262.agent.start(` * $262.agent.receiveBroadcast(function(sab) { * const i32a = new Int32Array(sab); * Atomics.add(i32a, ${RUNNING}, 1); * * $262.agent.report(Atomics.wait(i32a, ${WAIT_INDEX}, 0, ${TIMEOUT})); * * $262.agent.leaving(); * }); * `); * $262.agent.safeBroadcast(i32a.buffer); * * // Wait until the agent was started and then try to yield control to increase * // the likelihood the agent has called `Atomics.wait` and is now waiting. * $262.agent.waitUntil(i32a, RUNNING, 1); * $262.agent.tryYield(); * * // The agent is expected to time out. * assert.sameValue($262.agent.getReport(), "timed-out"); * * * Usage for `$262.agent.timeouts.long`: * const WAIT_INDEX = 0; * const RUNNING = 1; * const NUMAGENT = 2; * const TIMEOUT = $262.agent.timeouts.long; * const i32a = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2)); * * for (let i = 0; i < NUMAGENT; i++) { * $262.agent.start(` * $262.agent.receiveBroadcast(function(sab) { * const i32a = new Int32Array(sab); * Atomics.add(i32a, ${RUNNING}, 1); * * $262.agent.report(Atomics.wait(i32a, ${WAIT_INDEX}, 0, ${TIMEOUT})); * * $262.agent.leaving(); * }); * `); * } * $262.agent.safeBroadcast(i32a.buffer); * * // Wait until the agents were started and then try to yield control to increase * // the likelihood the agents have called `Atomics.wait` and are now waiting. * $262.agent.waitUntil(i32a, RUNNING, NUMAGENT); * $262.agent.tryYield(); * * // Wake exactly one agent. * assert.sameValue(Atomics.wake(i32a, WAIT_INDEX, 1), 1); * * // When it doesn't matter how many agents were woken at once, a while loop * // can be used to make the test more resilient against intermittent failures * // in case even though `tryYield` was called, the agents haven't started to * // wait. * // * // // Repeat until exactly one agent was woken. * // var woken = 0; * // while ((woken = Atomics.wake(i32a, WAIT_INDEX, 1)) !== 0) ; * // assert.sameValue(woken, 1); * * // One agent was woken and the other one timed out. * const reports = [$262.agent.getReport(), $262.agent.getReport()]; * assert(reports.includes("ok")); * assert(reports.includes("timed-out")); * * * Usage for `$262.agent.timeouts.huge`: * const WAIT_INDEX = 0; * const RUNNING = 1; * const NUMAGENT = 2; * const TIMEOUT = $262.agent.timeouts.huge; * const i32a = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2)); * * for (let i = 0; i < NUMAGENT; i++) { * $262.agent.start(` * $262.agent.receiveBroadcast(function(sab) { * const i32a = new Int32Array(sab); * Atomics.add(i32a, ${RUNNING}, 1); * * $262.agent.report(Atomics.wait(i32a, ${WAIT_INDEX}, 0, ${TIMEOUT})); * * $262.agent.leaving(); * }); * `); * } * $262.agent.safeBroadcast(i32a.buffer); * * // Wait until the agents were started and then try to yield control to increase * // the likelihood the agents have called `Atomics.wait` and are now waiting. * $262.agent.waitUntil(i32a, RUNNING, NUMAGENT); * $262.agent.tryYield(); * * // Wake all agents. * assert.sameValue(Atomics.wake(i32a, WAIT_INDEX), NUMAGENT); * * // When it doesn't matter how many agents were woken at once, a while loop * // can be used to make the test more resilient against intermittent failures * // in case even though `tryYield` was called, the agents haven't started to * // wait. * // * // // Repeat until all agents were woken. * // for (var wokenCount = 0; wokenCount < NUMAGENT; ) { * // var woken = 0; * // while ((woken = Atomics.wake(i32a, WAIT_INDEX)) !== 0) ; * // // Maybe perform an action on the woken agents here. * // wokenCount += woken; * // } * * // All agents were woken and none timeout. * for (var i = 0; i < NUMAGENT; i++) { * assert($262.agent.getReport(), "ok"); * } */ $262.agent.timeouts = { yield: 100, small: 200, long: 1000, huge: 10000, }; /** * Try to yield control to the agent threads. * * Usage: * const VALUE = 0; * const RUNNING = 1; * const i32a = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2)); * * $262.agent.start(` * $262.agent.receiveBroadcast(function(sab) { * const i32a = new Int32Array(sab); * Atomics.add(i32a, ${RUNNING}, 1); * * Atomics.store(i32a, ${VALUE}, 1); * * $262.agent.leaving(); * }); * `); * $262.agent.safeBroadcast(i32a.buffer); * * // Wait until agent was started and then try to yield control. * $262.agent.waitUntil(i32a, RUNNING, 1); * $262.agent.tryYield(); * * // Note: This result is not guaranteed, but should hold in practice most of the time. * assert.sameValue(Atomics.load(i32a, VALUE), 1); * * The default implementation simply waits for `$262.agent.timeouts.yield` milliseconds. */ $262.agent.tryYield = function() { $262.agent.sleep($262.agent.timeouts.yield); }; /** * Try to sleep the current agent for the given amount of milliseconds. It is acceptable, * but not encouraged, to ignore this sleep request and directly continue execution. * * The default implementation calls `$262.agent.sleep(ms)`. * * @param {number} ms Time to sleep in milliseconds. */ $262.agent.trySleep = function(ms) { $262.agent.sleep(ms); }; // file: detachArrayBuffer.js // Copyright (C) 2016 the V8 project authors. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. /*--- description: | A function used in the process of asserting correctness of TypedArray objects. $262.detachArrayBuffer is defined by a host. defines: [$DETACHBUFFER] ---*/ function $DETACHBUFFER(buffer) { if (!$262 || typeof $262.detachArrayBuffer !== "function") { throw new Test262Error("No method available to detach an ArrayBuffer"); } $262.detachArrayBuffer(buffer); }