diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/tests/test262/built-ins/Atomics/wait/shell.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.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/wait/shell.js')
-rw-r--r-- | js/src/tests/test262/built-ins/Atomics/wait/shell.js | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/Atomics/wait/shell.js b/js/src/tests/test262/built-ins/Atomics/wait/shell.js new file mode 100644 index 0000000000..c55dbb8399 --- /dev/null +++ b/js/src/tests/test262/built-ins/Atomics/wait/shell.js @@ -0,0 +1,344 @@ +// GENERATED, DO NOT EDIT +// 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); +} |