summaryrefslogtreecommitdiffstats
path: root/js/src/tests/test262/built-ins/Atomics/waitAsync/shell.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/tests/test262/built-ins/Atomics/waitAsync/shell.js
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/built-ins/Atomics/waitAsync/shell.js')
-rw-r--r--js/src/tests/test262/built-ins/Atomics/waitAsync/shell.js457
1 files changed, 457 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/Atomics/waitAsync/shell.js b/js/src/tests/test262/built-ins/Atomics/waitAsync/shell.js
new file mode 100644
index 0000000000..409797a047
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/waitAsync/shell.js
@@ -0,0 +1,457 @@
+// 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);
+}