25.4 The Atomics Object
The Atomics object:
- is %Atomics%.
- is the initial value of the
"Atomics" property of theglobal object . - is an
ordinary object . - has a [[Prototype]] internal slot whose value is
%Object.prototype% . - does not have a [[Construct]] internal method; it cannot be used as a
constructor with thenew
operator. - does not have a [[Call]] internal method; it cannot be invoked as a function.
The Atomics object provides functions that operate indivisibly (atomically) on shared memory array cells as well as functions that let agents wait for and dispatch primitive events. When used with discipline, the Atomics functions allow multi-
For informative guidelines for programming and implementing shared memory in ECMAScript, please see the notes at the end of the
25.4.1 Abstract Operations for Atomics
25.4.1.1 ValidateIntegerTypedArray ( typedArray [ , waitable ] )
The abstract operation ValidateIntegerTypedArray takes argument typedArray and optional argument waitable (a Boolean). It performs the following steps when called:
- If waitable is not present, set waitable to
false . - Let buffer be ?
ValidateTypedArray (typedArray). - Let typeName be typedArray.[[TypedArrayName]].
- Let type be the Element Type value in
Table 60 for typeName. - If waitable is
true , then- If typeName is not
"Int32Array" or"BigInt64Array" , throw aTypeError exception.
- If typeName is not
- Else,
- If !
IsUnclampedIntegerElementType (type) isfalse and !IsBigIntElementType (type) isfalse , throw aTypeError exception.
- If !
- Return buffer.
25.4.1.2 ValidateAtomicAccess ( typedArray, requestIndex )
The abstract operation ValidateAtomicAccess takes arguments typedArray and requestIndex. It performs the following steps when called:
Assert : typedArray is an Object that has a [[ViewedArrayBuffer]] internal slot.- Let length be typedArray.[[ArrayLength]].
- Let accessIndex be ?
ToIndex (requestIndex). Assert : accessIndex ≥ 0.- If accessIndex ≥ length, throw a
RangeError exception. - Let arrayTypeName be typedArray.[[TypedArrayName]].
- Let elementSize be the Element Size value specified in
Table 60 for arrayTypeName. - Let offset be typedArray.[[ByteOffset]].
- Return (accessIndex × elementSize) + offset.
25.4.1.3 GetWaiterList ( block, i )
A WaiterList is a semantic object that contains an ordered list of those agents that are waiting on a location (block, i) in shared memory; block is a
Initially a WaiterList object has an empty list and no
The
Each WaiterList has a critical section that controls exclusive access to that WaiterList during evaluation. Only a single
The abstract operation GetWaiterList takes arguments block (a
Assert : block is aShared Data Block .Assert : i and i + 3 are valid byte offsets within the memory of block.Assert : i is divisible by 4.- Return the
WaiterList that is referenced by the pair (block, i).
25.4.1.4 EnterCriticalSection ( WL )
The abstract operation EnterCriticalSection takes argument WL (a
Assert : The callingagent is not in thecritical section for anyWaiterList .- Wait until no
agent is in thecritical section for WL, then enter thecritical section for WL (without allowing any otheragent to enter). - If WL has a
Synchronize event , then- NOTE: A WL whose
critical section has been entered at least once has aSynchronize event set byLeaveCriticalSection . - Let execution be the [[CandidateExecution]] field of the
surrounding agent 'sAgent Record . - Let eventsRecord be the
Agent Events Record in execution.[[EventsRecords]] whose [[AgentSignifier]] isAgentSignifier (). - Let entererEventList be eventsRecord.[[EventList]].
- Let enterEvent be a new
Synchronize event . - Append enterEvent to entererEventList.
- Let leaveEvent be the
Synchronize event in WL. - Append (leaveEvent, enterEvent) to eventsRecord.[[AgentSynchronizesWith]].
- NOTE: A WL whose
EnterCriticalSection has contention when an
25.4.1.5 LeaveCriticalSection ( WL )
The abstract operation LeaveCriticalSection takes argument WL (a
Assert : The callingagent is in thecritical section for WL.- Let execution be the [[CandidateExecution]] field of the calling surrounding's
Agent Record . - Let eventsRecord be the
Agent Events Record in execution.[[EventsRecords]] whose [[AgentSignifier]] isAgentSignifier (). - Let leaverEventList be eventsRecord.[[EventList]].
- Let leaveEvent be a new
Synchronize event . - Append leaveEvent to leaverEventList.
- Set the
Synchronize event in WL to leaveEvent. - Leave the
critical section for WL.
25.4.1.6 AddWaiter ( WL, W )
The abstract operation AddWaiter takes arguments WL (a
Assert : The callingagent is in thecritical section for WL.Assert : W is not on the list of waiters in anyWaiterList .- Add W to the end of the list of waiters in WL.
25.4.1.7 RemoveWaiter ( WL, W )
The abstract operation RemoveWaiter takes arguments WL (a
Assert : The callingagent is in thecritical section for WL.Assert : W is on the list of waiters in WL.- Remove W from the list of waiters in WL.
25.4.1.8 RemoveWaiters ( WL, c )
The abstract operation RemoveWaiters takes arguments WL (a
Assert : The callingagent is in thecritical section for WL.- Let L be a new empty
List . - Let S be a reference to the list of waiters in WL.
- Repeat, while c > 0 and S is not an empty
List ,- Let W be the first waiter in S.
- Add W to the end of L.
- Remove W from S.
- If c is finite, set c to c - 1.
- Return L.
25.4.1.9 SuspendAgent ( WL, W, timeout )
The abstract operation SuspendAgent takes arguments WL (a
Assert : The callingagent is in thecritical section for WL.Assert : W is equivalent toAgentSignifier ().Assert : W is on the list of waiters in WL.Assert :AgentCanSuspend () istrue .- Perform
LeaveCriticalSection (WL) and suspend W for up to timeout milliseconds, performing the combined operation in such a way that a notification that arrives after thecritical section is exited but before the suspension takes effect is not lost. W can notify either because the timeout expired or because it was notified explicitly by anotheragent callingNotifyWaiter (WL, W), and not for any other reasons at all. - Perform
EnterCriticalSection (WL). - If W was notified explicitly by another
agent callingNotifyWaiter (WL, W), returntrue . - Return
false .
25.4.1.10 NotifyWaiter ( WL, W )
The abstract operation NotifyWaiter takes arguments WL (a
Assert : The callingagent is in thecritical section for WL.- Notify the
agent W.
The embedding may delay notifying W, e.g. for resource management reasons, but W must eventually be notified in order to guarantee forward progress.
25.4.1.11 AtomicReadModifyWrite ( typedArray, index, value, op )
The abstract operation AtomicReadModifyWrite takes arguments typedArray, index, value, and op (a
- Let buffer be ?
ValidateIntegerTypedArray (typedArray). - Let indexedPosition be ?
ValidateAtomicAccess (typedArray, index). - Let arrayTypeName be typedArray.[[TypedArrayName]].
- If typedArray.[[ContentType]] is
BigInt , let v be ?ToBigInt (value). - Otherwise, let v be
𝔽 (?ToIntegerOrInfinity (value)). - If
IsDetachedBuffer (buffer) istrue , throw aTypeError exception. - NOTE: The above check is not redundant with the check in
ValidateIntegerTypedArray because the call toToBigInt orToIntegerOrInfinity on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached. - Let elementType be the Element Type value in
Table 60 for arrayTypeName. - Return
GetModifySetValueInBuffer (buffer, indexedPosition, elementType, v, op).
25.4.1.12 ByteListBitwiseOp ( op, xBytes, yBytes )
The abstract operation ByteListBitwiseOp takes arguments op (a sequence of Unicode code points), xBytes (a
Assert : op is&
,^
, or|
.Assert : xBytes and yBytes have the same number of elements.- Let result be a new empty
List . - Let i be 0.
- For each element xByte of xBytes, do
- Let yByte be yBytes[i].
- If op is
&
, let resultByte be the result of applying the bitwise AND operation to xByte and yByte. - Else if op is
^
, let resultByte be the result of applying the bitwise exclusive OR (XOR) operation to xByte and yByte. - Else, op is
|
. Let resultByte be the result of applying the bitwise inclusive OR operation to xByte and yByte. - Set i to i + 1.
- Append resultByte to the end of result.
- Return result.
25.4.1.13 ByteListEqual ( xBytes, yBytes )
The abstract operation ByteListEqual takes arguments xBytes (a
- If xBytes and yBytes do not have the same number of elements, return
false . - Let i be 0.
- For each element xByte of xBytes, do
- Let yByte be yBytes[i].
- If xByte ≠ yByte, return
false . - Set i to i + 1.
- Return
true .
25.4.2 Atomics.add ( typedArray, index, value )
The following steps are taken:
- Let type be the Element Type value in
Table 60 for typedArray.[[TypedArrayName]]. - Let isLittleEndian be the value of the [[LittleEndian]] field of the
surrounding agent 'sAgent Record . - Let add be a new
read-modify-write modification function with parameters (xBytes, yBytes) that captures type and isLittleEndian and performs the following steps atomically when called:- Let x be
RawBytesToNumeric (type, xBytes, isLittleEndian). - Let y be
RawBytesToNumeric (type, yBytes, isLittleEndian). - Let T be
Type (x). - Let sum be T::add(x, y).
- Let sumBytes be
NumericToRawBytes (type, sum, isLittleEndian). Assert : sumBytes, xBytes, and yBytes have the same number of elements.- Return sumBytes.
- Let x be
- Return ?
AtomicReadModifyWrite (typedArray, index, value, add).
25.4.3 Atomics.and ( typedArray, index, value )
The following steps are taken:
- Let and be a new
read-modify-write modification function with parameters (xBytes, yBytes) that captures nothing and performs the following steps atomically when called:- Return
ByteListBitwiseOp (&
, xBytes, yBytes).
- Return
- Return ?
AtomicReadModifyWrite (typedArray, index, value, and).
25.4.4 Atomics.compareExchange ( typedArray, index, expectedValue, replacementValue )
The following steps are taken:
- Let buffer be ?
ValidateIntegerTypedArray (typedArray). - Let block be buffer.[[ArrayBufferData]].
- Let indexedPosition be ?
ValidateAtomicAccess (typedArray, index). - Let arrayTypeName be typedArray.[[TypedArrayName]].
- If typedArray.[[ContentType]] is
BigInt , then - Else,
- Let expected be
𝔽 (?ToIntegerOrInfinity (expectedValue)). - Let replacement be
𝔽 (?ToIntegerOrInfinity (replacementValue)).
- Let expected be
- If
IsDetachedBuffer (buffer) istrue , throw aTypeError exception. - NOTE: The above check is not redundant with the check in
ValidateIntegerTypedArray because the call toToBigInt orToIntegerOrInfinity on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached. - Let elementType be the Element Type value in
Table 60 for arrayTypeName. - Let elementSize be the Element Size value specified in
Table 60 for Element Type elementType. - Let isLittleEndian be the value of the [[LittleEndian]] field of the
surrounding agent 'sAgent Record . - Let expectedBytes be
NumericToRawBytes (elementType, expected, isLittleEndian). - Let replacementBytes be
NumericToRawBytes (elementType, replacement, isLittleEndian). - If
IsSharedArrayBuffer (buffer) istrue , then- Let execution be the [[CandidateExecution]] field of the
surrounding agent 'sAgent Record . - Let eventList be the [[EventList]] field of the element in execution.[[EventsRecords]] whose [[AgentSignifier]] is
AgentSignifier (). - Let rawBytesRead be a
List of length elementSize whose elements are nondeterministically chosen byte values. - NOTE: In implementations, rawBytesRead is the result of a load-link, of a load-exclusive, or of an operand of a read-modify-write instruction on the underlying hardware. The nondeterminism is a semantic prescription of the
memory model to describe observable behaviour of hardware with weak consistency. - NOTE: The comparison of the expected value and the read value is performed outside of the
read-modify-write modification function to avoid needlessly strong synchronization when the expected value is not equal to the read value. - If
ByteListEqual (rawBytesRead, expectedBytes) istrue , then- Let second be a new
read-modify-write modification function with parameters (oldBytes, newBytes) that captures nothing and performs the following steps atomically when called:- Return newBytes.
- Let event be
ReadModifyWriteSharedMemory { [[Order]]:SeqCst , [[NoTear]]:true , [[Block]]: block, [[ByteIndex]]: indexedPosition, [[ElementSize]]: elementSize, [[Payload]]: replacementBytes, [[ModifyOp]]: second }.
- Let second be a new
- Else,
- Let event be
ReadSharedMemory { [[Order]]:SeqCst , [[NoTear]]:true , [[Block]]: block, [[ByteIndex]]: indexedPosition, [[ElementSize]]: elementSize }.
- Let event be
- Append event to eventList.
- Append
Chosen Value Record { [[Event]]: event, [[ChosenValue]]: rawBytesRead } to execution.[[ChosenValues]].
- Let execution be the [[CandidateExecution]] field of the
- Else,
- Let rawBytesRead be a
List of length elementSize whose elements are the sequence of elementSize bytes starting with block[indexedPosition]. - If
ByteListEqual (rawBytesRead, expectedBytes) istrue , then- Store the individual bytes of replacementBytes into block, starting at block[indexedPosition].
- Let rawBytesRead be a
- Return
RawBytesToNumeric (elementType, rawBytesRead, isLittleEndian).
25.4.5 Atomics.exchange ( typedArray, index, value )
The following steps are taken:
- Let second be a new
read-modify-write modification function with parameters (oldBytes, newBytes) that captures nothing and performs the following steps atomically when called:- Return newBytes.
- Return ?
AtomicReadModifyWrite (typedArray, index, value, second).
25.4.6 Atomics.isLockFree ( size )
The following steps are taken:
- Let n be ?
ToIntegerOrInfinity (size). - Let AR be the
Agent Record of thesurrounding agent . - If n = 1, return AR.[[IsLockFree1]].
- If n = 2, return AR.[[IsLockFree2]].
- If n = 4, return
true . - If n = 8, return AR.[[IsLockFree8]].
- Return
false .
Atomics.isLockFree
() is an optimization primitive. The intuition is that if the atomic step of an atomic primitive (compareExchange
, load
, store
, add
, sub
, and
, or
, xor
, or exchange
) on a datum of size n bytes will be performed without the calling Atomics.isLockFree
(n) will return Atomics.isLockFree
to determine whether to use locks or atomic operations in critical sections. If an atomic primitive is not lock-free then it is often more efficient for an algorithm to provide its own locking.
Atomics.isLockFree
(4) always returns
Regardless of the value of Atomics.isLockFree
, all atomic operations are guaranteed to be atomic. For example, they will never have a visible operation take place in the middle of the operation (e.g., "tearing").
25.4.7 Atomics.load ( typedArray, index )
The following steps are taken:
- Let buffer be ?
ValidateIntegerTypedArray (typedArray). - Let indexedPosition be ?
ValidateAtomicAccess (typedArray, index). - If
IsDetachedBuffer (buffer) istrue , throw aTypeError exception. - NOTE: The above check is not redundant with the check in
ValidateIntegerTypedArray because the call toValidateAtomicAccess on the preceding line can have arbitrary side effects, which could cause the buffer to become detached. - Let arrayTypeName be typedArray.[[TypedArrayName]].
- Let elementType be the Element Type value in
Table 60 for arrayTypeName. - Return
GetValueFromBuffer (buffer, indexedPosition, elementType,true ,SeqCst ).
25.4.8 Atomics.or ( typedArray, index, value )
The following steps are taken:
- Let or be a new
read-modify-write modification function with parameters (xBytes, yBytes) that captures nothing and performs the following steps atomically when called:- Return
ByteListBitwiseOp (|
, xBytes, yBytes).
- Return
- Return ?
AtomicReadModifyWrite (typedArray, index, value, or).
25.4.9 Atomics.store ( typedArray, index, value )
The following steps are taken:
- Let buffer be ?
ValidateIntegerTypedArray (typedArray). - Let indexedPosition be ?
ValidateAtomicAccess (typedArray, index). - Let arrayTypeName be typedArray.[[TypedArrayName]].
- If arrayTypeName is
"BigUint64Array" or"BigInt64Array" , let v be ?ToBigInt (value). - Otherwise, let v be
𝔽 (?ToIntegerOrInfinity (value)). - If
IsDetachedBuffer (buffer) istrue , throw aTypeError exception. - NOTE: The above check is not redundant with the check in
ValidateIntegerTypedArray because the call toToBigInt orToIntegerOrInfinity on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached. - Let elementType be the Element Type value in
Table 60 for arrayTypeName. - Perform
SetValueInBuffer (buffer, indexedPosition, elementType, v,true ,SeqCst ). - Return v.
25.4.10 Atomics.sub ( typedArray, index, value )
The following steps are taken:
- Let type be the Element Type value in
Table 60 for typedArray.[[TypedArrayName]]. - Let isLittleEndian be the value of the [[LittleEndian]] field of the
surrounding agent 'sAgent Record . - Let subtract be a new
read-modify-write modification function with parameters (xBytes, yBytes) that captures type and isLittleEndian and performs the following steps atomically when called:- Let x be
RawBytesToNumeric (type, xBytes, isLittleEndian). - Let y be
RawBytesToNumeric (type, yBytes, isLittleEndian). - Let T be
Type (x). - Let difference be T::subtract(x, y).
- Let differenceBytes be
NumericToRawBytes (type, difference, isLittleEndian). Assert : differenceBytes, xBytes, and yBytes have the same number of elements.- Return differenceBytes.
- Let x be
- Return ?
AtomicReadModifyWrite (typedArray, index, value, subtract).
25.4.11 Atomics.wait ( typedArray, index, value, timeout )
Atomics.wait
puts the calling
- Let buffer be ?
ValidateIntegerTypedArray (typedArray,true ). - If
IsSharedArrayBuffer (buffer) isfalse , throw aTypeError exception. - Let indexedPosition be ?
ValidateAtomicAccess (typedArray, index). - Let arrayTypeName be typedArray.[[TypedArrayName]].
- If arrayTypeName is
"BigInt64Array" , let v be ?ToBigInt64 (value). - Otherwise, let v be ?
ToInt32 (value). - Let q be ?
ToNumber (timeout). - If q is
NaN or+∞ 𝔽, let t be +∞; else if q is-∞ 𝔽, let t be 0; else let t bemax (ℝ (q), 0). - Let B be
AgentCanSuspend (). - If B is
false , throw aTypeError exception. - Let block be buffer.[[ArrayBufferData]].
- Let WL be
GetWaiterList (block, indexedPosition). - Perform
EnterCriticalSection (WL). - Let elementType be the Element Type value in
Table 60 for arrayTypeName. - Let w be !
GetValueFromBuffer (buffer, indexedPosition, elementType,true ,SeqCst ). - If v ≠ w, then
- Perform
LeaveCriticalSection (WL). - Return the String
"not-equal" .
- Perform
- Let W be
AgentSignifier (). - Perform
AddWaiter (WL, W). - Let notified be
SuspendAgent (WL, W, t). - If notified is
true , thenAssert : W is not on the list of waiters in WL.
- Else,
- Perform
RemoveWaiter (WL, W).
- Perform
- Perform
LeaveCriticalSection (WL). - If notified is
true , return the String"ok" . - Return the String
"timed-out" .
25.4.12 Atomics.notify ( typedArray, index, count )
Atomics.notify
notifies some agents that are sleeping in the wait queue. The following steps are taken:
- Let buffer be ?
ValidateIntegerTypedArray (typedArray,true ). - Let indexedPosition be ?
ValidateAtomicAccess (typedArray, index). - If count is
undefined , let c be +∞. - Else,
- Let intCount be ?
ToIntegerOrInfinity (count). - Let c be
max (intCount, 0).
- Let intCount be ?
- Let block be buffer.[[ArrayBufferData]].
- Let arrayTypeName be typedArray.[[TypedArrayName]].
- If
IsSharedArrayBuffer (buffer) isfalse , return+0 𝔽. - Let WL be
GetWaiterList (block, indexedPosition). - Let n be 0.
- Perform
EnterCriticalSection (WL). - Let S be
RemoveWaiters (WL, c). - Repeat, while S is not an empty
List ,- Let W be the first
agent in S. - Remove W from the front of S.
- Perform
NotifyWaiter (WL, W). - Set n to n + 1.
- Let W be the first
- Perform
LeaveCriticalSection (WL). - Return
𝔽 (n).
25.4.13 Atomics.xor ( typedArray, index, value )
The following steps are taken:
- Let xor be a new
read-modify-write modification function with parameters (xBytes, yBytes) that captures nothing and performs the following steps atomically when called:- Return
ByteListBitwiseOp (^
, xBytes, yBytes).
- Return
- Return ?
AtomicReadModifyWrite (typedArray, index, value, xor).
25.4.14 Atomics [ @@toStringTag ]
The initial value of the
This property has the attributes { [[Writable]]: