Skip to content

Commit 14e6a98

Browse files
authored
feat(ecmascript): Atomics.isLockFree (#891)
1 parent bb222d1 commit 14e6a98

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed

nova_vm/src/ecmascript/builtins/structured_data/atomics_object.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
ecmascript::{
1111
abstract_operations::type_conversion::{
1212
number_convert_to_integer_or_infinity, to_big_int, to_index,
13-
to_integer_number_or_infinity, try_to_index, validate_index,
13+
to_integer_number_or_infinity, to_integer_or_infinity, try_to_index, validate_index,
1414
},
1515
builders::ordinary_object_builder::OrdinaryObjectBuilder,
1616
builtins::{
@@ -308,13 +308,63 @@ impl AtomicsObject {
308308
.map(|v| v.into_value())
309309
}
310310

311+
/// ### [25.4.8 Atomics.isLockFree ( size )](https://tc39.es/ecma262/#sec-atomics.islockfree)
312+
///
313+
/// > NOTE: This function is an optimization primitive. The intuition is
314+
/// > that if the atomic step of an atomic primitive (**compareExchange**,
315+
/// > **load**, **store**, **add**, **sub**, **and**, **or**, **xor**, or
316+
/// > **exchange**) on a datum of size `n` bytes will be performed without
317+
/// > the surrounding agent acquiring a lock outside the n bytes comprising
318+
/// > the datum, then **Atomics.isLockFree**(`n`) will return **true**.
319+
/// > High-performance algorithms will use this function to determine
320+
/// > whether to use locks or atomic operations in critical sections. If an
321+
/// > atomic primitive is not lock-free then it is often more efficient for
322+
/// > an algorithm to provide its own locking.
323+
/// >
324+
/// > **Atomics.isLockFree**(4) always returns **true** as that can be
325+
/// > supported on all known relevant hardware. Being able to assume this
326+
/// > will generally simplify programs.
327+
/// >
328+
/// > Regardless of the value returned by this function, all atomic
329+
/// > operations are guaranteed to be atomic. For example, they will never
330+
/// > have a visible operation take place in the middle of the operation
331+
/// > (e.g., "tearing").
311332
fn is_lock_free<'gc>(
312333
agent: &mut Agent,
313334
_this_value: Value,
314-
_arguments: ArgumentsList,
335+
arguments: ArgumentsList,
315336
gc: GcScope<'gc, '_>,
316337
) -> JsResult<'gc, Value<'gc>> {
317-
Err(agent.todo("Atomics.isLockFree", gc.into_nogc()))
338+
let size = arguments.get(0).bind(gc.nogc());
339+
// 1. Let n be ? ToIntegerOrInfinity(size).
340+
let n = to_integer_or_infinity(agent, size.unbind(), gc)?.into_i64();
341+
// 2. Let AR be the Agent Record of the surrounding agent.
342+
// 3. If n = 1, return AR.[[IsLockFree1]].
343+
#[cfg(target_has_atomic = "8")]
344+
if n == 1 {
345+
return Ok(true.into());
346+
}
347+
// 4. If n = 2, return AR.[[IsLockFree2]].
348+
#[cfg(target_has_atomic = "16")]
349+
if n == 2 {
350+
return Ok(true.into());
351+
}
352+
// 5. If n = 4, return true.
353+
#[cfg(target_has_atomic = "32")]
354+
if n == 4 {
355+
return Ok(true.into());
356+
}
357+
#[cfg(not(target_has_atomic = "32"))]
358+
const {
359+
panic!("Atomics requires 32-bit lock-free atomics")
360+
};
361+
// 6. If n = 8, return AR.[[IsLockFree8]].
362+
#[cfg(target_has_atomic = "64")]
363+
if n == 8 {
364+
return Ok(true.into());
365+
}
366+
// 7. Return false.
367+
Ok(false.into())
318368
}
319369

320370
/// ### [25.4.9 Atomics.load ( typedArray, index )](https://tc39.es/ecma262/#sec-atomics.load)

tests/expectations.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,6 @@
238238
"built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/throw-rejected-return.js": "FAIL",
239239
"built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/throw-return-getter.js": "FAIL",
240240
"built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/throw-return.js": "FAIL",
241-
"built-ins/Atomics/isLockFree/bigint/expected-return-value.js": "FAIL",
242-
"built-ins/Atomics/isLockFree/corner-cases.js": "FAIL",
243-
"built-ins/Atomics/isLockFree/expected-return-value.js": "FAIL",
244241
"built-ins/Atomics/notify/bad-range.js": "FAIL",
245242
"built-ins/Atomics/notify/bigint/bad-range.js": "FAIL",
246243
"built-ins/Atomics/notify/bigint/non-bigint64-typedarray-throws.js": "FAIL",

tests/metrics.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"results": {
33
"crash": 107,
4-
"fail": 7892,
5-
"pass": 39359,
4+
"fail": 7889,
5+
"pass": 39362,
66
"skip": 3325,
77
"timeout": 15,
88
"unresolved": 35

0 commit comments

Comments
 (0)