# 25.1.1 Notation

The descriptions below in this section, 25.4, and 29 use the read-modify-write modification function internal data structure.

A read-modify-write modification function is a mathematical function that is notationally represented as an abstract closure that takes two Lists of byte values as arguments and returns a List of byte values. These abstract closures satisfy all of the following properties:

• They perform all their algorithm steps atomically.
• Their individual algorithm steps are not observable.
Note

To aid verifying that a read-modify-write modification function's algorithm steps constitute a pure, mathematical function, the following editorial conventions are recommended:

• They do not access, directly or transitively via invoked abstract operations and abstract closures, any language or specification values except their parameters and captured values.
• They do not return completion values.

# 25.1.2.1 AllocateArrayBuffer ( constructor, byteLength )

The abstract operation AllocateArrayBuffer takes arguments constructor and byteLength (a non-negative integer). It is used to create an ArrayBuffer. It performs the following steps when called:

1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBuffer.prototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] »).
2. Let block be ? CreateByteDataBlock(byteLength).
3. Set obj.[[ArrayBufferData]] to block.
4. Set obj.[[ArrayBufferByteLength]] to byteLength.
5. Return obj.

# 25.1.2.2 IsDetachedBuffer ( arrayBuffer )

The abstract operation IsDetachedBuffer takes argument arrayBuffer (an ArrayBuffer or a SharedArrayBuffer). It performs the following steps when called:

1. If arrayBuffer.[[ArrayBufferData]] is null, return true.
2. Return false.

# 25.1.2.3 DetachArrayBuffer ( arrayBuffer [ , key ] )

The abstract operation DetachArrayBuffer takes argument arrayBuffer (an ArrayBuffer) and optional argument key. It performs the following steps when called:

1. Assert: IsSharedArrayBuffer(arrayBuffer) is false.
2. If key is not present, set key to undefined.
3. If SameValue(arrayBuffer.[[ArrayBufferDetachKey]], key) is false, throw a TypeError exception.
4. Set arrayBuffer.[[ArrayBufferData]] to null.
5. Set arrayBuffer.[[ArrayBufferByteLength]] to 0.
6. Return NormalCompletion(null).
Note

Detaching an ArrayBuffer instance disassociates the Data Block used as its backing store from the instance and sets the byte length of the buffer to 0. No operations defined by this specification use the DetachArrayBuffer abstract operation. However, an ECMAScript host or implementation may define such operations.

# 25.1.2.4 CloneArrayBuffer ( srcBuffer, srcByteOffset, srcLength, cloneConstructor )

The abstract operation CloneArrayBuffer takes arguments srcBuffer (an ArrayBuffer or a SharedArrayBuffer), srcByteOffset (a non-negative integer), srcLength (a non-negative integer), and cloneConstructor (a constructor). It creates a new ArrayBuffer whose data is a copy of srcBuffer's data over the range starting at srcByteOffset and continuing for srcLength bytes. It performs the following steps when called:

1. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, srcLength).
2. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
3. Let srcBlock be srcBuffer.[[ArrayBufferData]].
4. Let targetBlock be targetBuffer.[[ArrayBufferData]].
5. Perform CopyDataBlockBytes(targetBlock, 0, srcBlock, srcByteOffset, srcLength).
6. Return targetBuffer.

# 25.1.2.5 IsUnsignedElementType ( type )

The abstract operation IsUnsignedElementType takes argument type. It verifies if the argument type is an unsigned TypedArray element type. It performs the following steps when called:

1. If type is Uint8, Uint8C, Uint16, Uint32, or BigUint64, return true.
2. Return false.

# 25.1.2.6 IsUnclampedIntegerElementType ( type )

The abstract operation IsUnclampedIntegerElementType takes argument type. It verifies if the argument type is an Integer TypedArray element type not including Uint8C. It performs the following steps when called:

1. If type is Int8, Uint8, Int16, Uint16, Int32, or Uint32, return true.
2. Return false.

# 25.1.2.7 IsBigIntElementType ( type )

The abstract operation IsBigIntElementType takes argument type. It verifies if the argument type is a BigInt TypedArray element type. It performs the following steps when called:

1. If type is BigUint64 or BigInt64, return true.
2. Return false.

# 25.1.2.8 IsNoTearConfiguration ( type, order )

The abstract operation IsNoTearConfiguration takes arguments type and order. It performs the following steps when called:

1. If ! IsUnclampedIntegerElementType(type) is true, return true.
2. If ! IsBigIntElementType(type) is true and order is not Init or Unordered, return true.
3. Return false.

# 25.1.2.9 RawBytesToNumeric ( type, rawBytes, isLittleEndian )

The abstract operation RawBytesToNumeric takes arguments type (a TypedArray element type), rawBytes (a List), and isLittleEndian (a Boolean). It performs the following steps when called:

1. Let elementSize be the Element Size value specified in Table 73 for Element Type type.
2. If isLittleEndian is false, reverse the order of the elements of rawBytes.
3. If type is Float32, then
1. Let value be the byte elements of rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2019 binary32 value.
2. If value is an IEEE 754-2019 binary32 NaN value, return the NaN Number value.
3. Return the Number value that corresponds to value.
4. If type is Float64, then
1. Let value be the byte elements of rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2019 binary64 value.
2. If value is an IEEE 754-2019 binary64 NaN value, return the NaN Number value.
3. Return the Number value that corresponds to value.
5. If ! IsUnsignedElementType(type) is true, then
1. Let intValue be the byte elements of rawBytes concatenated and interpreted as a bit string encoding of an unsigned little-endian binary number.
6. Else,
1. Let intValue be the byte elements of rawBytes concatenated and interpreted as a bit string encoding of a binary little-endian two's complement number of bit length elementSize × 8.
7. If ! IsBigIntElementType(type) is true, return the BigInt value that corresponds to intValue.
8. Otherwise, return the Number value that corresponds to intValue.

# 25.1.2.10 GetValueFromBuffer ( arrayBuffer, byteIndex, type, isTypedArray, order [ , isLittleEndian ] )

The abstract operation GetValueFromBuffer takes arguments arrayBuffer (an ArrayBuffer or SharedArrayBuffer), byteIndex (a non-negative integer), type (a TypedArray element type), isTypedArray (a Boolean), and order (SeqCst or Unordered) and optional argument isLittleEndian (a Boolean). It performs the following steps when called:

1. Assert: IsDetachedBuffer(arrayBuffer) is false.
2. Assert: There are sufficient bytes in arrayBuffer starting at byteIndex to represent a value of type.
3. Let block be arrayBuffer.[[ArrayBufferData]].
4. Let elementSize be the Element Size value specified in Table 73 for Element Type type.
5. If IsSharedArrayBuffer(arrayBuffer) is true, then
1. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
2. Let eventList be the [[EventList]] field of the element in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
3. If isTypedArray is true and IsNoTearConfiguration(type, order) is true, let noTear be true; otherwise let noTear be false.
4. Let rawValue be a List of length elementSize whose elements are nondeterministically chosen byte values.
5. NOTE: In implementations, rawValue is the result of a non-atomic or atomic read instruction on the underlying hardware. The nondeterminism is a semantic prescription of the memory model to describe observable behaviour of hardware with weak consistency.
6. Let readEvent be ReadSharedMemory { [[Order]]: order, [[NoTear]]: noTear, [[Block]]: block, [[ByteIndex]]: byteIndex, [[ElementSize]]: elementSize }.
8. Append Chosen Value Record { [[Event]]: readEvent, [[ChosenValue]]: rawValue } to execution.[[ChosenValues]].
6. Else, let rawValue be a List whose elements are bytes from block at indices byteIndex (inclusive) through byteIndex + elementSize (exclusive).
7. Assert: The number of elements in rawValue is elementSize.
8. If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
9. Return RawBytesToNumeric(type, rawValue, isLittleEndian).

# 25.1.2.11 NumericToRawBytes ( type, value, isLittleEndian )

The abstract operation NumericToRawBytes takes arguments type (a TypedArray element type), value (a BigInt or a Number), and isLittleEndian (a Boolean). It performs the following steps when called:

1. If type is Float32, then
1. Let rawBytes be a List whose elements are the 4 bytes that are the result of converting value to IEEE 754-2019 binary32 format using roundTiesToEven mode. If isLittleEndian is false, the bytes are arranged in big endian order. Otherwise, the bytes are arranged in little endian order. If value is NaN, rawBytes may be set to any implementation chosen IEEE 754-2019 binary32 format Not-a-Number encoding. An implementation must always choose the same encoding for each implementation distinguishable NaN value.
2. Else if type is Float64, then
1. Let rawBytes be a List whose elements are the 8 bytes that are the IEEE 754-2019 binary64 format encoding of value. If isLittleEndian is false, the bytes are arranged in big endian order. Otherwise, the bytes are arranged in little endian order. If value is NaN, rawBytes may be set to any implementation chosen IEEE 754-2019 binary64 format Not-a-Number encoding. An implementation must always choose the same encoding for each implementation distinguishable NaN value.
3. Else,
1. Let n be the Element Size value specified in Table 73 for Element Type type.
2. Let convOp be the abstract operation named in the Conversion Operation column in Table 73 for Element Type type.
3. Let intValue be (convOp(value)).
4. If intValue ≥ 0, then
1. Let rawBytes be a List whose elements are the n-byte binary encoding of intValue. If isLittleEndian is false, the bytes are ordered in big endian order. Otherwise, the bytes are ordered in little endian order.
5. Else,
1. Let rawBytes be a List whose elements are the n-byte binary two's complement encoding of intValue. If isLittleEndian is false, the bytes are ordered in big endian order. Otherwise, the bytes are ordered in little endian order.
4. Return rawBytes.

# 25.1.2.12 SetValueInBuffer ( arrayBuffer, byteIndex, type, value, isTypedArray, order [ , isLittleEndian ] )

The abstract operation SetValueInBuffer takes arguments arrayBuffer (an ArrayBuffer or SharedArrayBuffer), byteIndex (a non-negative integer), type (a TypedArray element type), value (a Number or a BigInt), isTypedArray (a Boolean), and order (SeqCst, Unordered, or Init) and optional argument isLittleEndian (a Boolean). It performs the following steps when called:

1. Assert: IsDetachedBuffer(arrayBuffer) is false.
2. Assert: There are sufficient bytes in arrayBuffer starting at byteIndex to represent a value of type.
3. Assert: Type(value) is BigInt if ! IsBigIntElementType(type) is true; otherwise, Type(value) is Number.
4. Let block be arrayBuffer.[[ArrayBufferData]].
5. Let elementSize be the Element Size value specified in Table 73 for Element Type type.
6. If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
7. Let rawBytes be NumericToRawBytes(type, value, isLittleEndian).
8. If IsSharedArrayBuffer(arrayBuffer) is true, then
1. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
2. Let eventList be the [[EventList]] field of the element in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
3. If isTypedArray is true and IsNoTearConfiguration(type, order) is true, let noTear be true; otherwise let noTear be false.
4. Append WriteSharedMemory { [[Order]]: order, [[NoTear]]: noTear, [[Block]]: block, [[ByteIndex]]: byteIndex, [[ElementSize]]: elementSize, [[Payload]]: rawBytes } to eventList.
9. Else, store the individual bytes of rawBytes into block, starting at block[byteIndex].
10. Return NormalCompletion(undefined).

# 25.1.2.13 GetModifySetValueInBuffer ( arrayBuffer, byteIndex, type, value, op [ , isLittleEndian ] )

The abstract operation GetModifySetValueInBuffer takes arguments arrayBuffer (an ArrayBuffer or a SharedArrayBuffer), byteIndex (a non-negative integer), type (a TypedArray element type), value (a Number or a BigInt), and op (a read-modify-write modification function) and optional argument isLittleEndian (a Boolean). It performs the following steps when called:

1. Assert: IsDetachedBuffer(arrayBuffer) is false.
2. Assert: There are sufficient bytes in arrayBuffer starting at byteIndex to represent a value of type.
3. Assert: Type(value) is BigInt if ! IsBigIntElementType(type) is true; otherwise, Type(value) is Number.
4. Let block be arrayBuffer.[[ArrayBufferData]].
5. Let elementSize be the Element Size value specified in Table 73 for Element Type type.
6. If isLittleEndian is not present, set isLittleEndian to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
7. Let rawBytes be NumericToRawBytes(type, value, isLittleEndian).
8. If IsSharedArrayBuffer(arrayBuffer) is true, then
1. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
2. Let eventList be the [[EventList]] field of the element in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
3. Let rawBytesRead be a List of length elementSize whose elements are nondeterministically chosen byte values.
4. 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.
5. Let rmwEvent be ReadModifyWriteSharedMemory { [[Order]]: SeqCst, [[NoTear]]: true, [[Block]]: block, [[ByteIndex]]: byteIndex, [[ElementSize]]: elementSize, [[Payload]]: rawBytes, [[ModifyOp]]: op }.
6. Append rmwEvent to eventList.
7. Append Chosen Value Record { [[Event]]: rmwEvent, [[ChosenValue]]: rawBytesRead } to execution.[[ChosenValues]].
9. Else,
1. Let rawBytesRead be a List of length elementSize whose elements are the sequence of elementSize bytes starting with block[byteIndex].
2. Let rawBytesModified be op(rawBytesRead, rawBytes).
3. Store the individual bytes of rawBytesModified into block, starting at block[byteIndex].

# 25.1.3 The ArrayBuffer Constructor

The ArrayBuffer constructor:

• is %ArrayBuffer%.
• is the initial value of the "ArrayBuffer" property of the global object.
• creates and initializes a new ArrayBuffer when called as a constructor.
• is not intended to be called as a function and will throw an exception when called in that manner.
• may be used as the value of an `extends` clause of a class definition. Subclass constructors that intend to inherit the specified ArrayBuffer behaviour must include a `super` call to the ArrayBuffer constructor to create and initialize subclass instances with the internal state necessary to support the `ArrayBuffer.prototype` built-in methods.

# 25.1.3.1 ArrayBuffer ( length )

When the `ArrayBuffer` function is called with argument length, the following steps are taken:

1. If NewTarget is undefined, throw a TypeError exception.
2. Let byteLength be ? ToIndex(length).
3. Return ? AllocateArrayBuffer(NewTarget, byteLength).

# 25.1.4 Properties of the ArrayBuffer Constructor

The ArrayBuffer constructor:

• has a [[Prototype]] internal slot whose value is %Function.prototype%.
• has the following properties:

# 25.1.4.1 ArrayBuffer.isView ( arg )

The `isView` function takes one argument arg, and performs the following steps:

1. If Type(arg) is not Object, return false.
2. If arg has a [[ViewedArrayBuffer]] internal slot, return true.
3. Return false.

# 25.1.4.2 ArrayBuffer.prototype

The initial value of `ArrayBuffer.prototype` is the ArrayBuffer prototype object.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

# 25.1.4.3 get ArrayBuffer [ @@species ]

`ArrayBuffer[@@species]` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Return the this value.

The value of the "name" property of this function is "get [Symbol.species]".

Note

ArrayBuffer prototype methods normally use their this value's constructor to create a derived object. However, a subclass constructor may over-ride that default behaviour by redefining its @@species property.

# 25.1.5 Properties of the ArrayBuffer Prototype Object

The ArrayBuffer prototype object:

• is %ArrayBuffer.prototype%.
• has a [[Prototype]] internal slot whose value is %Object.prototype%.
• is an ordinary object.
• does not have an [[ArrayBufferData]] or [[ArrayBufferByteLength]] internal slot.

# 25.1.5.1 get ArrayBuffer.prototype.byteLength

`ArrayBuffer.prototype.byteLength` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let O be the this value.
2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]).
3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception.
4. If IsDetachedBuffer(O) is true, return +0𝔽.
5. Let length be O.[[ArrayBufferByteLength]].
6. Return 𝔽(length).

# 25.1.5.2 ArrayBuffer.prototype.constructor

The initial value of `ArrayBuffer.prototype.constructor` is %ArrayBuffer%.

# 25.1.5.3 ArrayBuffer.prototype.slice ( start, end )

The following steps are taken:

1. Let O be the this value.
2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]).
3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception.
4. If IsDetachedBuffer(O) is true, throw a TypeError exception.
5. Let len be O.[[ArrayBufferByteLength]].
6. Let relativeStart be ? ToIntegerOrInfinity(start).
7. If relativeStart is -∞, let first be 0.
8. Else if relativeStart < 0, let first be max(len + relativeStart, 0).
9. Else, let first be min(relativeStart, len).
10. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
11. If relativeEnd is -∞, let final be 0.
12. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0).
13. Else, let final be min(relativeEnd, len).
14. Let newLen be max(final - first, 0).
15. Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%).
16. Let new be ? Construct(ctor, « 𝔽(newLen) »).
17. Perform ? RequireInternalSlot(new, [[ArrayBufferData]]).
18. If IsSharedArrayBuffer(new) is true, throw a TypeError exception.
19. If IsDetachedBuffer(new) is true, throw a TypeError exception.
20. If SameValue(new, O) is true, throw a TypeError exception.
21. If new.[[ArrayBufferByteLength]] < newLen, throw a TypeError exception.
22. NOTE: Side-effects of the above steps may have detached O.
23. If IsDetachedBuffer(O) is true, throw a TypeError exception.
24. Let fromBuf be O.[[ArrayBufferData]].
25. Let toBuf be new.[[ArrayBufferData]].
26. Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen).
27. Return new.

# 25.1.5.4 ArrayBuffer.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "ArrayBuffer".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

# 25.1.6 Properties of ArrayBuffer Instances

ArrayBuffer instances inherit properties from the ArrayBuffer prototype object. ArrayBuffer instances each have an [[ArrayBufferData]] internal slot, an [[ArrayBufferByteLength]] internal slot, and an [[ArrayBufferDetachKey]] internal slot.

ArrayBuffer instances whose [[ArrayBufferData]] is null are considered to be detached and all operators to access or modify data contained in the ArrayBuffer instance will fail.

ArrayBuffer instances whose [[ArrayBufferDetachKey]] is set to a value other than undefined need to have all DetachArrayBuffer calls passing that same "detach key" as an argument, otherwise a TypeError will result. This internal slot is only ever set by certain embedding environments, not by algorithms in this specification.

# 25.2.1.1 AllocateSharedArrayBuffer ( constructor, byteLength )

The abstract operation AllocateSharedArrayBuffer takes arguments constructor and byteLength (a non-negative integer). It is used to create a SharedArrayBuffer. It performs the following steps when called:

1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%SharedArrayBuffer.prototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]] »).
2. Let block be ? CreateSharedByteDataBlock(byteLength).
3. Set obj.[[ArrayBufferData]] to block.
4. Set obj.[[ArrayBufferByteLength]] to byteLength.
5. Return obj.

# 25.2.1.2 IsSharedArrayBuffer ( obj )

The abstract operation IsSharedArrayBuffer takes argument obj (an ArrayBuffer or a SharedArrayBuffer). It tests whether an object is an ArrayBuffer, a SharedArrayBuffer, or a subtype of either. It performs the following steps when called:

1. Let bufferData be obj.[[ArrayBufferData]].
2. If bufferData is null, return false.
3. If bufferData is a Data Block, return false.
4. Assert: bufferData is a Shared Data Block.
5. Return true.

# 25.2.2 The SharedArrayBuffer Constructor

The SharedArrayBuffer constructor:

• is %SharedArrayBuffer%.
• is the initial value of the "SharedArrayBuffer" property of the global object, if that property is present (see below).
• creates and initializes a new SharedArrayBuffer when called as a constructor.
• is not intended to be called as a function and will throw an exception when called in that manner.
• may be used as the value of an `extends` clause of a class definition. Subclass constructors that intend to inherit the specified SharedArrayBuffer behaviour must include a `super` call to the SharedArrayBuffer constructor to create and initialize subclass instances with the internal state necessary to support the `SharedArrayBuffer.prototype` built-in methods.

Whenever a host does not provide concurrent access to SharedArrayBuffers it may omit the "SharedArrayBuffer" property of the global object.

Note

Unlike an `ArrayBuffer`, a `SharedArrayBuffer` cannot become detached, and its internal [[ArrayBufferData]] slot is never null.

# 25.2.2.1 SharedArrayBuffer ( length )

When the `SharedArrayBuffer` function is called with argument length, the following steps are taken:

1. If NewTarget is undefined, throw a TypeError exception.
2. Let byteLength be ? ToIndex(length).
3. Return ? AllocateSharedArrayBuffer(NewTarget, byteLength).

# 25.2.3 Properties of the SharedArrayBuffer Constructor

The SharedArrayBuffer constructor:

• has a [[Prototype]] internal slot whose value is %Function.prototype%.
• has the following properties:

# 25.2.3.1 SharedArrayBuffer.prototype

The initial value of `SharedArrayBuffer.prototype` is the SharedArrayBuffer prototype object.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

# 25.2.3.2 get SharedArrayBuffer [ @@species ]

`SharedArrayBuffer[@@species]` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Return the this value.

The value of the "name" property of this function is "get [Symbol.species]".

# 25.2.4 Properties of the SharedArrayBuffer Prototype Object

The SharedArrayBuffer prototype object:

• is %SharedArrayBuffer.prototype%.
• has a [[Prototype]] internal slot whose value is %Object.prototype%.
• is an ordinary object.
• does not have an [[ArrayBufferData]] or [[ArrayBufferByteLength]] internal slot.

# 25.2.4.1 get SharedArrayBuffer.prototype.byteLength

`SharedArrayBuffer.prototype.byteLength` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let O be the this value.
2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]).
3. If IsSharedArrayBuffer(O) is false, throw a TypeError exception.
4. Let length be O.[[ArrayBufferByteLength]].
5. Return 𝔽(length).

# 25.2.4.2 SharedArrayBuffer.prototype.constructor

The initial value of `SharedArrayBuffer.prototype.constructor` is %SharedArrayBuffer%.

# 25.2.4.3 SharedArrayBuffer.prototype.slice ( start, end )

The following steps are taken:

1. Let O be the this value.
2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]).
3. If IsSharedArrayBuffer(O) is false, throw a TypeError exception.
4. Let len be O.[[ArrayBufferByteLength]].
5. Let relativeStart be ? ToIntegerOrInfinity(start).
6. If relativeStart is -∞, let first be 0.
7. Else if relativeStart < 0, let first be max(len + relativeStart, 0).
8. Else, let first be min(relativeStart, len).
9. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
10. If relativeEnd is -∞, let final be 0.
11. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0).
12. Else, let final be min(relativeEnd, len).
13. Let newLen be max(final - first, 0).
14. Let ctor be ? SpeciesConstructor(O, %SharedArrayBuffer%).
15. Let new be ? Construct(ctor, « 𝔽(newLen) »).
16. Perform ? RequireInternalSlot(new, [[ArrayBufferData]]).
17. If IsSharedArrayBuffer(new) is false, throw a TypeError exception.
18. If new.[[ArrayBufferData]] and O.[[ArrayBufferData]] are the same Shared Data Block values, throw a TypeError exception.
19. If new.[[ArrayBufferByteLength]] < newLen, throw a TypeError exception.
20. Let fromBuf be O.[[ArrayBufferData]].
21. Let toBuf be new.[[ArrayBufferData]].
22. Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen).
23. Return new.

# 25.2.4.4 SharedArrayBuffer.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "SharedArrayBuffer".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

# 25.2.5 Properties of SharedArrayBuffer Instances

SharedArrayBuffer instances inherit properties from the SharedArrayBuffer prototype object. SharedArrayBuffer instances each have an [[ArrayBufferData]] internal slot and an [[ArrayBufferByteLength]] internal slot.

Note

SharedArrayBuffer instances, unlike ArrayBuffer instances, are never detached.

# 25.3.1.1 GetViewValue ( view, requestIndex, isLittleEndian, type )

The abstract operation GetViewValue takes arguments view, requestIndex, isLittleEndian, and type. It is used by functions on DataView instances to retrieve values from the view's buffer. It performs the following steps when called:

1. Perform ? RequireInternalSlot(view, [[DataView]]).
2. Assert: view has a [[ViewedArrayBuffer]] internal slot.
3. Let getIndex be ? ToIndex(requestIndex).
4. Set isLittleEndian to ! ToBoolean(isLittleEndian).
5. Let buffer be view.[[ViewedArrayBuffer]].
6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
7. Let viewOffset be view.[[ByteOffset]].
8. Let viewSize be view.[[ByteLength]].
9. Let elementSize be the Element Size value specified in Table 73 for Element Type type.
10. If getIndex + elementSize > viewSize, throw a RangeError exception.
11. Let bufferIndex be getIndex + viewOffset.
12. Return GetValueFromBuffer(buffer, bufferIndex, type, false, Unordered, isLittleEndian).

# 25.3.1.2 SetViewValue ( view, requestIndex, isLittleEndian, type, value )

The abstract operation SetViewValue takes arguments view, requestIndex, isLittleEndian, type, and value. It is used by functions on DataView instances to store values into the view's buffer. It performs the following steps when called:

1. Perform ? RequireInternalSlot(view, [[DataView]]).
2. Assert: view has a [[ViewedArrayBuffer]] internal slot.
3. Let getIndex be ? ToIndex(requestIndex).
4. If ! IsBigIntElementType(type) is true, let numberValue be ? ToBigInt(value).
5. Otherwise, let numberValue be ? ToNumber(value).
6. Set isLittleEndian to ! ToBoolean(isLittleEndian).
7. Let buffer be view.[[ViewedArrayBuffer]].
8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
9. Let viewOffset be view.[[ByteOffset]].
10. Let viewSize be view.[[ByteLength]].
11. Let elementSize be the Element Size value specified in Table 73 for Element Type type.
12. If getIndex + elementSize > viewSize, throw a RangeError exception.
13. Let bufferIndex be getIndex + viewOffset.
14. Return SetValueInBuffer(buffer, bufferIndex, type, numberValue, false, Unordered, isLittleEndian).

# 25.3.2 The DataView Constructor

The DataView constructor:

• is %DataView%.
• is the initial value of the "DataView" property of the global object.
• creates and initializes a new DataView when called as a constructor.
• is not intended to be called as a function and will throw an exception when called in that manner.
• may be used as the value of an `extends` clause of a class definition. Subclass constructors that intend to inherit the specified DataView behaviour must include a `super` call to the DataView constructor to create and initialize subclass instances with the internal state necessary to support the `DataView.prototype` built-in methods.

# 25.3.2.1 DataView ( buffer [ , byteOffset [ , byteLength ] ] )

When the `DataView` function is called with at least one argument buffer, the following steps are taken:

1. If NewTarget is undefined, throw a TypeError exception.
2. Perform ? RequireInternalSlot(buffer, [[ArrayBufferData]]).
3. Let offset be ? ToIndex(byteOffset).
4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
5. Let bufferByteLength be buffer.[[ArrayBufferByteLength]].
6. If offset > bufferByteLength, throw a RangeError exception.
7. If byteLength is undefined, then
1. Let viewByteLength be bufferByteLength - offset.
8. Else,
1. Let viewByteLength be ? ToIndex(byteLength).
2. If offset + viewByteLength > bufferByteLength, throw a RangeError exception.
9. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%DataView.prototype%", « [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]] »).
10. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
11. Set O.[[ViewedArrayBuffer]] to buffer.
12. Set O.[[ByteLength]] to viewByteLength.
13. Set O.[[ByteOffset]] to offset.
14. Return O.

# 25.3.3 Properties of the DataView Constructor

The DataView constructor:

• has a [[Prototype]] internal slot whose value is %Function.prototype%.
• has the following properties:

# 25.3.3.1 DataView.prototype

The initial value of `DataView.prototype` is the DataView prototype object.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

# 25.3.4 Properties of the DataView Prototype Object

The DataView prototype object:

• is %DataView.prototype%.
• has a [[Prototype]] internal slot whose value is %Object.prototype%.
• is an ordinary object.
• does not have a [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], or [[ByteOffset]] internal slot.

# 25.3.4.1 get DataView.prototype.buffer

`DataView.prototype.buffer` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let O be the this value.
2. Perform ? RequireInternalSlot(O, [[DataView]]).
3. Assert: O has a [[ViewedArrayBuffer]] internal slot.
4. Let buffer be O.[[ViewedArrayBuffer]].
5. Return buffer.

# 25.3.4.2 get DataView.prototype.byteLength

`DataView.prototype.byteLength` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let O be the this value.
2. Perform ? RequireInternalSlot(O, [[DataView]]).
3. Assert: O has a [[ViewedArrayBuffer]] internal slot.
4. Let buffer be O.[[ViewedArrayBuffer]].
5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
6. Let size be O.[[ByteLength]].
7. Return 𝔽(size).

# 25.3.4.3 get DataView.prototype.byteOffset

`DataView.prototype.byteOffset` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let O be the this value.
2. Perform ? RequireInternalSlot(O, [[DataView]]).
3. Assert: O has a [[ViewedArrayBuffer]] internal slot.
4. Let buffer be O.[[ViewedArrayBuffer]].
5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
6. Let offset be O.[[ByteOffset]].
7. Return 𝔽(offset).

# 25.3.4.4 DataView.prototype.constructor

The initial value of `DataView.prototype.constructor` is %DataView%.

# 25.3.4.5 DataView.prototype.getBigInt64 ( byteOffset [ , littleEndian ] )

When the `getBigInt64` method is called with argument byteOffset and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. Return ? GetViewValue(v, byteOffset, littleEndian, BigInt64).

# 25.3.4.6 DataView.prototype.getBigUint64 ( byteOffset [ , littleEndian ] )

When the `getBigUint64` method is called with argument byteOffset and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. Return ? GetViewValue(v, byteOffset, littleEndian, BigUint64).

# 25.3.4.7 DataView.prototype.getFloat32 ( byteOffset [ , littleEndian ] )

When the `getFloat32` method is called with argument byteOffset and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? GetViewValue(v, byteOffset, littleEndian, Float32).

# 25.3.4.8 DataView.prototype.getFloat64 ( byteOffset [ , littleEndian ] )

When the `getFloat64` method is called with argument byteOffset and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? GetViewValue(v, byteOffset, littleEndian, Float64).

# 25.3.4.9 DataView.prototype.getInt8 ( byteOffset )

When the `getInt8` method is called with argument byteOffset, the following steps are taken:

1. Let v be the this value.
2. Return ? GetViewValue(v, byteOffset, true, Int8).

# 25.3.4.10 DataView.prototype.getInt16 ( byteOffset [ , littleEndian ] )

When the `getInt16` method is called with argument byteOffset and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? GetViewValue(v, byteOffset, littleEndian, Int16).

# 25.3.4.11 DataView.prototype.getInt32 ( byteOffset [ , littleEndian ] )

When the `getInt32` method is called with argument byteOffset and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? GetViewValue(v, byteOffset, littleEndian, Int32).

# 25.3.4.12 DataView.prototype.getUint8 ( byteOffset )

When the `getUint8` method is called with argument byteOffset, the following steps are taken:

1. Let v be the this value.
2. Return ? GetViewValue(v, byteOffset, true, Uint8).

# 25.3.4.13 DataView.prototype.getUint16 ( byteOffset [ , littleEndian ] )

When the `getUint16` method is called with argument byteOffset and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? GetViewValue(v, byteOffset, littleEndian, Uint16).

# 25.3.4.14 DataView.prototype.getUint32 ( byteOffset [ , littleEndian ] )

When the `getUint32` method is called with argument byteOffset and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? GetViewValue(v, byteOffset, littleEndian, Uint32).

# 25.3.4.15 DataView.prototype.setBigInt64 ( byteOffset, value [ , littleEndian ] )

When the `setBigInt64` method is called with arguments byteOffset and value and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. Return ? SetViewValue(v, byteOffset, littleEndian, BigInt64, value).

# 25.3.4.16 DataView.prototype.setBigUint64 ( byteOffset, value [ , littleEndian ] )

When the `setBigUint64` method is called with arguments byteOffset and value and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. Return ? SetViewValue(v, byteOffset, littleEndian, BigUint64, value).

# 25.3.4.17 DataView.prototype.setFloat32 ( byteOffset, value [ , littleEndian ] )

When the `setFloat32` method is called with arguments byteOffset and value and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? SetViewValue(v, byteOffset, littleEndian, Float32, value).

# 25.3.4.18 DataView.prototype.setFloat64 ( byteOffset, value [ , littleEndian ] )

When the `setFloat64` method is called with arguments byteOffset and value and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? SetViewValue(v, byteOffset, littleEndian, Float64, value).

# 25.3.4.19 DataView.prototype.setInt8 ( byteOffset, value )

When the `setInt8` method is called with arguments byteOffset and value, the following steps are taken:

1. Let v be the this value.
2. Return ? SetViewValue(v, byteOffset, true, Int8, value).

# 25.3.4.20 DataView.prototype.setInt16 ( byteOffset, value [ , littleEndian ] )

When the `setInt16` method is called with arguments byteOffset and value and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? SetViewValue(v, byteOffset, littleEndian, Int16, value).

# 25.3.4.21 DataView.prototype.setInt32 ( byteOffset, value [ , littleEndian ] )

When the `setInt32` method is called with arguments byteOffset and value and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? SetViewValue(v, byteOffset, littleEndian, Int32, value).

# 25.3.4.22 DataView.prototype.setUint8 ( byteOffset, value )

When the `setUint8` method is called with arguments byteOffset and value, the following steps are taken:

1. Let v be the this value.
2. Return ? SetViewValue(v, byteOffset, true, Uint8, value).

# 25.3.4.23 DataView.prototype.setUint16 ( byteOffset, value [ , littleEndian ] )

When the `setUint16` method is called with arguments byteOffset and value and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? SetViewValue(v, byteOffset, littleEndian, Uint16, value).

# 25.3.4.24 DataView.prototype.setUint32 ( byteOffset, value [ , littleEndian ] )

When the `setUint32` method is called with arguments byteOffset and value and optional argument littleEndian, the following steps are taken:

1. Let v be the this value.
2. If littleEndian is not present, set littleEndian to false.
3. Return ? SetViewValue(v, byteOffset, littleEndian, Uint32, value).

# 25.3.4.25 DataView.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "DataView".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

# 25.3.5 Properties of DataView Instances

DataView instances are ordinary objects that inherit properties from the DataView prototype object. DataView instances each have [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], and [[ByteOffset]] internal slots.

Note

The value of the [[DataView]] internal slot is not used within this specification. The simple presence of that internal slot is used within the specification to identify objects created using the DataView constructor.

# 25.4 The Atomics Object

The Atomics object:

• is %Atomics%.
• is the initial value of the "Atomics" property of the global 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 the `new` 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-agent programs that communicate through shared memory to execute in a well-understood order even on parallel CPUs. The rules that govern shared-memory communication are provided by the memory model, defined below.

Note

For informative guidelines for programming and implementing shared memory in ECMAScript, please see the notes at the end of the memory model section.

# 25.4.1 WaiterList Objects

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 Shared Data Block and i a byte offset into the memory of block. A WaiterList object also optionally contains a Synchronize event denoting the previous leaving of its critical section.

Initially a WaiterList object has an empty list and no Synchronize event.

The agent cluster has a store of WaiterList objects; the store is indexed by (block, i). WaiterLists are agent-independent: a lookup in the store of WaiterLists by (block, i) will result in the same WaiterList object in any agent in the agent cluster.

Each WaiterList has a critical section that controls exclusive access to that WaiterList during evaluation. Only a single agent may enter a WaiterList's critical section at one time. Entering and leaving a WaiterList's critical section is controlled by the abstract operations EnterCriticalSection and LeaveCriticalSection. Operations on a WaiterList—adding and removing waiting agents, traversing the list of agents, suspending and notifying agents on the list, setting and retrieving the Synchronize event—may only be performed by agents that have entered the WaiterList's critical section.

# 25.4.2.1 ValidateIntegerTypedArray ( typedArray [ , waitable ] )

The abstract operation ValidateIntegerTypedArray takes argument typedArray and optional argument waitable (a Boolean). It performs the following steps when called:

1. If waitable is not present, set waitable to false.
2. Perform ? ValidateTypedArray(typedArray).
3. Let buffer be typedArray.[[ViewedArrayBuffer]].
4. Let typeName be typedArray.[[TypedArrayName]].
5. Let type be the Element Type value in Table 73 for typeName.
6. If waitable is true, then
1. If typeName is not "Int32Array" or "BigInt64Array", throw a TypeError exception.
7. Else,
1. If ! IsUnclampedIntegerElementType(type) is false and ! IsBigIntElementType(type) is false, throw a TypeError exception.
8. Return buffer.

# 25.4.2.2 ValidateAtomicAccess ( typedArray, requestIndex )

The abstract operation ValidateAtomicAccess takes arguments typedArray (a TypedArray) and requestIndex. It performs the following steps when called:

1. Let length be typedArray.[[ArrayLength]].
2. Let accessIndex be ? ToIndex(requestIndex).
3. Assert: accessIndex ≥ 0.
4. If accessIndexlength, throw a RangeError exception.
5. Let arrayTypeName be typedArray.[[TypedArrayName]].
6. Let elementSize be the Element Size value specified in Table 73 for arrayTypeName.
7. Let offset be typedArray.[[ByteOffset]].
8. Return (accessIndex × elementSize) + offset.

# 25.4.2.3 GetWaiterList ( block, i )

The abstract operation GetWaiterList takes arguments block (a Shared Data Block) and i (a non-negative integer that is evenly divisble by 4). It performs the following steps when called:

1. Assert: i and i + 3 are valid byte offsets within the memory of block.
2. Return the WaiterList that is referenced by the pair (block, i).

# 25.4.2.4 EnterCriticalSection ( WL )

The abstract operation EnterCriticalSection takes argument WL (a WaiterList). It performs the following steps when called:

1. Assert: The calling agent is not in the critical section for any WaiterList.
2. Wait until no agent is in the critical section for WL, then enter the critical section for WL (without allowing any other agent to enter).
3. If WL has a Synchronize event, then
1. NOTE: A WL whose critical section has been entered at least once has a Synchronize event set by LeaveCriticalSection.
2. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
3. Let eventsRecord be the Agent Events Record in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
4. Let entererEventList be eventsRecord.[[EventList]].
5. Let enterEvent be a new Synchronize event.
6. Append enterEvent to entererEventList.
7. Let leaveEvent be the Synchronize event in WL.
8. Append (leaveEvent, enterEvent) to eventsRecord.[[AgentSynchronizesWith]].

EnterCriticalSection has contention when an agent attempting to enter the critical section must wait for another agent to leave it. When there is no contention, FIFO order of EnterCriticalSection calls is observable. When there is contention, an implementation may choose an arbitrary order but may not cause an agent to wait indefinitely.

# 25.4.2.5 LeaveCriticalSection ( WL )

The abstract operation LeaveCriticalSection takes argument WL (a WaiterList). It performs the following steps when called:

1. Assert: The calling agent is in the critical section for WL.
2. Let execution be the [[CandidateExecution]] field of the calling surrounding's Agent Record.
3. Let eventsRecord be the Agent Events Record in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
4. Let leaverEventList be eventsRecord.[[EventList]].
5. Let leaveEvent be a new Synchronize event.
6. Append leaveEvent to leaverEventList.
7. Set the Synchronize event in WL to leaveEvent.
8. Leave the critical section for WL.

# 25.4.2.6 AddWaiter ( WL, W )

The abstract operation AddWaiter takes arguments WL (a WaiterList) and W (an agent signifier). It performs the following steps when called:

1. Assert: The calling agent is in the critical section for WL.
2. Assert: W is not on the list of waiters in any WaiterList.
3. Add W to the end of the list of waiters in WL.

# 25.4.2.7 RemoveWaiter ( WL, W )

The abstract operation RemoveWaiter takes arguments WL (a WaiterList) and W (an agent signifier). It performs the following steps when called:

1. Assert: The calling agent is in the critical section for WL.
2. Assert: W is on the list of waiters in WL.
3. Remove W from the list of waiters in WL.

# 25.4.2.8 RemoveWaiters ( WL, c )

The abstract operation RemoveWaiters takes arguments WL (a WaiterList) and c (a non-negative integer or +∞). It performs the following steps when called:

1. Assert: The calling agent is in the critical section for WL.
2. Let L be a new empty List.
3. Let S be a reference to the list of waiters in WL.
4. Repeat, while c > 0 and S is not an empty List,
1. Let W be the first waiter in S.
2. Add W to the end of L.
3. Remove W from S.
4. If c is finite, set c to c - 1.
5. Return L.

# 25.4.2.9 SuspendAgent ( WL, W, timeout )

The abstract operation SuspendAgent takes arguments WL (a WaiterList), W (an agent signifier), and timeout (a non-negative integer). It performs the following steps when called:

1. Assert: The calling agent is in the critical section for WL.
2. Assert: W is equivalent to AgentSignifier().
3. Assert: W is on the list of waiters in WL.
4. Assert: AgentCanSuspend() is true.
5. 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 the critical 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 another agent calling NotifyWaiter(WL, W), and not for any other reasons at all.
6. Perform EnterCriticalSection(WL).
7. If W was notified explicitly by another agent calling NotifyWaiter(WL, W), return true.
8. Return false.

# 25.4.2.10 NotifyWaiter ( WL, W )

The abstract operation NotifyWaiter takes arguments WL (a WaiterList) and W (an agent signifier). It performs the following steps when called:

1. Assert: The calling agent is in the critical section for WL.
2. Notify the agent W.
Note

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.2.11 AtomicReadModifyWrite ( typedArray, index, value, op )

The abstract operation AtomicReadModifyWrite takes arguments typedArray, index, value, and op (a read-modify-write modification function). op takes two List of byte values arguments and returns a List of byte values. This operation atomically loads a value, combines it with another value, and stores the result of the combination. It returns the loaded value. It performs the following steps when called:

1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
2. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
3. Let arrayTypeName be typedArray.[[TypedArrayName]].
4. If typedArray.[[ContentType]] is BigInt, let v be ? ToBigInt(value).
5. Otherwise, let v be 𝔽(? ToIntegerOrInfinity(value)).
6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
7. NOTE: The above check is not redundant with the check in ValidateIntegerTypedArray because the call to ToBigInt or ToIntegerOrInfinity on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached.
8. Let elementType be the Element Type value in Table 73 for arrayTypeName.
9. Return GetModifySetValueInBuffer(buffer, indexedPosition, elementType, v, op).

# 25.4.2.12 ByteListBitwiseOp ( op, xBytes, yBytes )

The abstract operation ByteListBitwiseOp takes arguments op (`&`, `^`, or `|`), xBytes (a List of byte values), and yBytes (a List of byte values). The operation atomically performs a bitwise operation on all byte values of the arguments and returns a List of byte values. It performs the following steps when called:

1. Assert: xBytes and yBytes have the same number of elements.
2. Let result be a new empty List.
3. Let i be 0.
4. For each element xByte of xBytes, do
1. Let yByte be yBytes[i].
2. If op is `&`, let resultByte be the result of applying the bitwise AND operation to xByte and yByte.
3. Else if op is `^`, let resultByte be the result of applying the bitwise exclusive OR (XOR) operation to xByte and yByte.
4. Else, op is `|`. Let resultByte be the result of applying the bitwise inclusive OR operation to xByte and yByte.
5. Set i to i + 1.
6. Append resultByte to the end of result.
5. Return result.

# 25.4.2.13 ByteListEqual ( xBytes, yBytes )

The abstract operation ByteListEqual takes arguments xBytes (a List of byte values) and yBytes (a List of byte values). It performs the following steps when called:

1. If xBytes and yBytes do not have the same number of elements, return false.
2. Let i be 0.
3. For each element xByte of xBytes, do
1. Let yByte be yBytes[i].
2. If xByteyByte, return false.
3. Set i to i + 1.
4. Return true.

# 25.4.3 Atomics.add ( typedArray, index, value )

The following steps are taken:

1. Let type be the Element Type value in Table 73 for typedArray.[[TypedArrayName]].
2. Let isLittleEndian be the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
3. 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:
1. Let x be RawBytesToNumeric(type, xBytes, isLittleEndian).
2. Let y be RawBytesToNumeric(type, yBytes, isLittleEndian).
3. Let T be Type(x).
4. Let sum be T::add(x, y).
5. Let sumBytes be NumericToRawBytes(type, sum, isLittleEndian).
6. Assert: sumBytes, xBytes, and yBytes have the same number of elements.
7. Return sumBytes.

# 25.4.4 Atomics.and ( typedArray, index, value )

The following steps are taken:

1. 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:
1. Return ByteListBitwiseOp(`&`, xBytes, yBytes).
2. Return ? AtomicReadModifyWrite(typedArray, index, value, and).

# 25.4.5 Atomics.compareExchange ( typedArray, index, expectedValue, replacementValue )

The following steps are taken:

1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
2. Let block be buffer.[[ArrayBufferData]].
3. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
4. Let arrayTypeName be typedArray.[[TypedArrayName]].
5. If typedArray.[[ContentType]] is BigInt, then
1. Let expected be ? ToBigInt(expectedValue).
2. Let replacement be ? ToBigInt(replacementValue).
6. Else,
1. Let expected be 𝔽(? ToIntegerOrInfinity(expectedValue)).
2. Let replacement be 𝔽(? ToIntegerOrInfinity(replacementValue)).
7. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
8. NOTE: The above check is not redundant with the check in ValidateIntegerTypedArray because the call to ToBigInt or ToIntegerOrInfinity on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached.
9. Let elementType be the Element Type value in Table 73 for arrayTypeName.
10. Let elementSize be the Element Size value specified in Table 73 for Element Type elementType.
11. Let isLittleEndian be the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
12. Let expectedBytes be NumericToRawBytes(elementType, expected, isLittleEndian).
13. Let replacementBytes be NumericToRawBytes(elementType, replacement, isLittleEndian).
14. If IsSharedArrayBuffer(buffer) is true, then
1. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
2. Let eventList be the [[EventList]] field of the element in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
3. Let rawBytesRead be a List of length elementSize whose elements are nondeterministically chosen byte values.
4. 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.
5. 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.
6. If ByteListEqual(rawBytesRead, expectedBytes) is true, then
1. 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:
1. Return newBytes.
2. Let event be ReadModifyWriteSharedMemory { [[Order]]: SeqCst, [[NoTear]]: true, [[Block]]: block, [[ByteIndex]]: indexedPosition, [[ElementSize]]: elementSize, [[Payload]]: replacementBytes, [[ModifyOp]]: second }.
7. Else,
1. Let event be ReadSharedMemory { [[Order]]: SeqCst, [[NoTear]]: true, [[Block]]: block, [[ByteIndex]]: indexedPosition, [[ElementSize]]: elementSize }.
8. Append event to eventList.
9. Append Chosen Value Record { [[Event]]: event, [[ChosenValue]]: rawBytesRead } to execution.[[ChosenValues]].
15. Else,
1. Let rawBytesRead be a List of length elementSize whose elements are the sequence of elementSize bytes starting with block[indexedPosition].
2. If ByteListEqual(rawBytesRead, expectedBytes) is true, then
1. Store the individual bytes of replacementBytes into block, starting at block[indexedPosition].

# 25.4.6 Atomics.exchange ( typedArray, index, value )

The following steps are taken:

1. 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:
1. Return newBytes.
2. Return ? AtomicReadModifyWrite(typedArray, index, value, second).

# 25.4.7 Atomics.isLockFree ( size )

The following steps are taken:

1. Let n be ? ToIntegerOrInfinity(size).
2. Let AR be the Agent Record of the surrounding agent.
3. If n = 1, return AR.[[IsLockFree1]].
4. If n = 2, return AR.[[IsLockFree2]].
5. If n = 4, return true.
6. If n = 8, return AR.[[IsLockFree8]].
7. Return false.
Note

`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 agent acquiring a lock outside the n bytes comprising the datum, then `Atomics.isLockFree`(n) will return true. High-performance algorithms will use `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 true as that can be supported on all known relevant hardware. Being able to assume this will generally simplify programs.

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.8 Atomics.load ( typedArray, index )

The following steps are taken:

1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
2. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
3. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
4. NOTE: The above check is not redundant with the check in ValidateIntegerTypedArray because the call to ValidateAtomicAccess on the preceding line can have arbitrary side effects, which could cause the buffer to become detached.
5. Let arrayTypeName be typedArray.[[TypedArrayName]].
6. Let elementType be the Element Type value in Table 73 for arrayTypeName.
7. Return GetValueFromBuffer(buffer, indexedPosition, elementType, true, SeqCst).

# 25.4.9 Atomics.or ( typedArray, index, value )

The following steps are taken:

1. 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:
1. Return ByteListBitwiseOp(`|`, xBytes, yBytes).
2. Return ? AtomicReadModifyWrite(typedArray, index, value, or).

# 25.4.10 Atomics.store ( typedArray, index, value )

The following steps are taken:

1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
2. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
3. Let arrayTypeName be typedArray.[[TypedArrayName]].
4. If arrayTypeName is "BigUint64Array" or "BigInt64Array", let v be ? ToBigInt(value).
5. Otherwise, let v be 𝔽(? ToIntegerOrInfinity(value)).
6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
7. NOTE: The above check is not redundant with the check in ValidateIntegerTypedArray because the call to ToBigInt or ToIntegerOrInfinity on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached.
8. Let elementType be the Element Type value in Table 73 for arrayTypeName.
9. Perform SetValueInBuffer(buffer, indexedPosition, elementType, v, true, SeqCst).
10. Return v.

# 25.4.11 Atomics.sub ( typedArray, index, value )

The following steps are taken:

1. Let type be the Element Type value in Table 73 for typedArray.[[TypedArrayName]].
2. Let isLittleEndian be the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
3. 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:
1. Let x be RawBytesToNumeric(type, xBytes, isLittleEndian).
2. Let y be RawBytesToNumeric(type, yBytes, isLittleEndian).
3. Let T be Type(x).
4. Let difference be T::subtract(x, y).
5. Let differenceBytes be NumericToRawBytes(type, difference, isLittleEndian).
6. Assert: differenceBytes, xBytes, and yBytes have the same number of elements.
7. Return differenceBytes.
4. Return ? AtomicReadModifyWrite(typedArray, index, value, subtract).

# 25.4.12 Atomics.wait ( typedArray, index, value, timeout )

`Atomics.wait` puts the calling agent in a wait queue and puts it to sleep until it is notified or the sleep times out. The following steps are taken:

1. Let buffer be ? ValidateIntegerTypedArray(typedArray, true).
2. If IsSharedArrayBuffer(buffer) is false, throw a TypeError exception.
3. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
4. Let arrayTypeName be typedArray.[[TypedArrayName]].
5. If arrayTypeName is "BigInt64Array", let v be ? ToBigInt64(value).
6. Otherwise, let v be ? ToInt32(value).
7. Let q be ? ToNumber(timeout).
8. If q is NaN or +∞𝔽, let t be +∞; else if q is -∞𝔽, let t be 0; else let t be max((q), 0).
9. Let B be AgentCanSuspend().
10. If B is false, throw a TypeError exception.
11. Let block be buffer.[[ArrayBufferData]].
12. Let WL be GetWaiterList(block, indexedPosition).
13. Perform EnterCriticalSection(WL).
14. Let elementType be the Element Type value in Table 73 for arrayTypeName.
15. Let w be ! GetValueFromBuffer(buffer, indexedPosition, elementType, true, SeqCst).
16. If vw, then
1. Perform LeaveCriticalSection(WL).
2. Return the String "not-equal".
17. Let W be AgentSignifier().
19. Let notified be SuspendAgent(WL, W, t).
20. If notified is true, then
1. Assert: W is not on the list of waiters in WL.
21. Else,
1. Perform RemoveWaiter(WL, W).
22. Perform LeaveCriticalSection(WL).
23. If notified is true, return the String "ok".
24. Return the String "timed-out".

# 25.4.13 Atomics.notify ( typedArray, index, count )

`Atomics.notify` notifies some agents that are sleeping in the wait queue. The following steps are taken:

1. Let buffer be ? ValidateIntegerTypedArray(typedArray, true).
2. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
3. If count is undefined, let c be +∞.
4. Else,
1. Let intCount be ? ToIntegerOrInfinity(count).
2. Let c be max(intCount, 0).
5. Let block be buffer.[[ArrayBufferData]].
6. If IsSharedArrayBuffer(buffer) is false, return +0𝔽.
7. Let WL be GetWaiterList(block, indexedPosition).
8. Let n be 0.
9. Perform EnterCriticalSection(WL).
10. Let S be RemoveWaiters(WL, c).
11. Repeat, while S is not an empty List,
1. Let W be the first agent in S.
2. Remove W from the front of S.
3. Perform NotifyWaiter(WL, W).
4. Set n to n + 1.
12. Perform LeaveCriticalSection(WL).
13. Return 𝔽(n).

# 25.4.14 Atomics.xor ( typedArray, index, value )

The following steps are taken:

1. 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:
1. Return ByteListBitwiseOp(`^`, xBytes, yBytes).
2. Return ? AtomicReadModifyWrite(typedArray, index, value, xor).

# 25.4.15 Atomics [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Atomics".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

# 25.5 The JSON Object

The JSON object:

• is %JSON%.
• is the initial value of the "JSON" property of the global object.
• is an ordinary object.
• contains two functions, `parse` and `stringify`, that are used to parse and construct JSON texts.
• 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 the `new` operator.
• does not have a [[Call]] internal method; it cannot be invoked as a function.

The JSON Data Interchange Format is defined in ECMA-404. The JSON interchange format used in this specification is exactly that described by ECMA-404. Conforming implementations of `JSON.parse` and `JSON.stringify` must support the exact interchange format described in the ECMA-404 specification without any deletions or extensions to the format.

# 25.5.1 JSON.parse ( text [ , reviver ] )

The `parse` function parses a JSON text (a JSON-formatted String) and produces an ECMAScript value. The JSON format represents literals, arrays, and objects with a syntax similar to the syntax for ECMAScript literals, Array Initializers, and Object Initializers. After parsing, JSON objects are realized as ECMAScript objects. JSON arrays are realized as ECMAScript Array instances. JSON strings, numbers, booleans, and null are realized as ECMAScript Strings, Numbers, Booleans, and null.

The optional reviver parameter is a function that takes two parameters, key and value. It can filter and transform the results. It is called with each of the key/value pairs produced by the parse, and its return value is used instead of the original value. If it returns what it received, the structure is not modified. If it returns undefined then the property is deleted from the result.

1. Let jsonString be ? ToString(text).
2. Parse ! StringToCodePoints(jsonString) as a JSON text as specified in ECMA-404. Throw a SyntaxError exception if it is not a valid JSON text as defined in that specification.
3. Let scriptString be the string-concatenation of "(", jsonString, and ");".
4. Let script be ParseText(! StringToCodePoints(scriptString), Script).
5. NOTE: The early error rules defined in 13.2.5.1 have special handling for the above invocation of ParseText.
6. Assert: script is a Parse Node.
7. Let completion be the result of evaluating script.
8. NOTE: The PropertyDefinitionEvaluation semantics defined in 13.2.5.5 have special handling for the above evaluation.
9. Let unfiltered be completion.[[Value]].
10. Assert: unfiltered is either a String, Number, Boolean, Null, or an Object that is defined by either an ArrayLiteral or an ObjectLiteral.
11. If IsCallable(reviver) is true, then
1. Let root be ! OrdinaryObjectCreate(%Object.prototype%).
2. Let rootName be the empty String.
3. Perform ! CreateDataPropertyOrThrow(root, rootName, unfiltered).
4. Return ? InternalizeJSONProperty(root, rootName, reviver).
12. Else,
1. Return unfiltered.

The "length" property of the `parse` function is 2𝔽.

Note

Valid JSON text is a subset of the ECMAScript PrimaryExpression syntax. Step 2 verifies that jsonString conforms to that subset, and step 10 asserts that that parsing and evaluation returns a value of an appropriate type.

However, because 13.2.5.5 behaves differently during `JSON.parse`, the same source text can produce different results when evaluated as a PrimaryExpression rather than as JSON. Furthermore, the Early Error for duplicate "__proto__" properties in object literals, which likewise does not apply during `JSON.parse`, means that not all texts accepted by `JSON.parse` are valid as a PrimaryExpression, despite matching the grammar.

# 25.5.1.1 InternalizeJSONProperty ( holder, name, reviver )

The abstract operation InternalizeJSONProperty takes arguments holder (an Object), name (a String), and reviver (a function object).

Note 1

This algorithm intentionally does not throw an exception if either [[Delete]] or CreateDataProperty return false.

It performs the following steps when called:

1. Let val be ? Get(holder, name).
2. If Type(val) is Object, then
1. Let isArray be ? IsArray(val).
2. If isArray is true, then
1. Let I be 0.
2. Let len be ? LengthOfArrayLike(val).
3. Repeat, while I < len,
1. Let prop be ! ToString(𝔽(I)).
2. Let newElement be ? InternalizeJSONProperty(val, prop, reviver).
3. If newElement is undefined, then
1. Perform ? val.[[Delete]](prop).
4. Else,
1. Perform ? CreateDataProperty(val, prop, newElement).
5. Set I to I + 1.
3. Else,
1. Let keys be ? EnumerableOwnPropertyNames(val, key).
2. For each String P of keys, do
1. Let newElement be ? InternalizeJSONProperty(val, P, reviver).
2. If newElement is undefined, then
1. Perform ? val.[[Delete]](P).
3. Else,
1. Perform ? CreateDataProperty(val, P, newElement).
3. Return ? Call(reviver, holder, « name, val »).

It is not permitted for a conforming implementation of `JSON.parse` to extend the JSON grammars. If an implementation wishes to support a modified or extended JSON interchange format it must do so by defining a different parse function.

Note 2

In the case where there are duplicate name Strings within an object, lexically preceding values for the same key shall be overwritten.

# 25.5.2 JSON.stringify ( value [ , replacer [ , space ] ] )

The `stringify` function returns a String in UTF-16 encoded JSON format representing an ECMAScript value, or undefined. It can take three parameters. The value parameter is an ECMAScript value, which is usually an object or array, although it can also be a String, Boolean, Number or null. The optional replacer parameter is either a function that alters the way objects and arrays are stringified, or an array of Strings and Numbers that acts as an inclusion list for selecting the object properties that will be stringified. The optional space parameter is a String or Number that allows the result to have white space injected into it to improve human readability.

These are the steps in stringifying an object:

1. Let stack be a new empty List.
2. Let indent be the empty String.
3. Let PropertyList and ReplacerFunction be undefined.
4. If Type(replacer) is Object, then
1. If IsCallable(replacer) is true, then
1. Set ReplacerFunction to replacer.
2. Else,
1. Let isArray be ? IsArray(replacer).
2. If isArray is true, then
1. Set PropertyList to a new empty List.
2. Let len be ? LengthOfArrayLike(replacer).
3. Let k be 0.
4. Repeat, while k < len,
1. Let prop be ! ToString(𝔽(k)).
2. Let v be ? Get(replacer, prop).
3. Let item be undefined.
4. If Type(v) is String, set item to v.
5. Else if Type(v) is Number, set item to ! ToString(v).
6. Else if Type(v) is Object, then
1. If v has a [[StringData]] or [[NumberData]] internal slot, set item to ? ToString(v).
7. If item is not undefined and item is not currently an element of PropertyList, then
1. Append item to the end of PropertyList.
8. Set k to k + 1.
5. If Type(space) is Object, then
1. If space has a [[NumberData]] internal slot, then
1. Set space to ? ToNumber(space).
2. Else if space has a [[StringData]] internal slot, then
1. Set space to ? ToString(space).
6. If Type(space) is Number, then
1. Let spaceMV be ! ToIntegerOrInfinity(space).
2. Set spaceMV to min(10, spaceMV).
3. If spaceMV < 1, let gap be the empty String; otherwise let gap be the String value containing spaceMV occurrences of the code unit 0x0020 (SPACE).
7. Else if Type(space) is String, then
1. If the length of space is 10 or less, let gap be space; otherwise let gap be the substring of space from 0 to 10.
8. Else,
1. Let gap be the empty String.
9. Let wrapper be ! OrdinaryObjectCreate(%Object.prototype%).
10. Perform ! CreateDataPropertyOrThrow(wrapper, the empty String, value).
11. Let state be the Record { [[ReplacerFunction]]: ReplacerFunction, [[Stack]]: stack, [[Indent]]: indent, [[Gap]]: gap, [[PropertyList]]: PropertyList }.
12. Return ? SerializeJSONProperty(state, the empty String, wrapper).

The "length" property of the `stringify` function is 3𝔽.

Note 1

JSON structures are allowed to be nested to any depth, but they must be acyclic. If value is or contains a cyclic structure, then the stringify function must throw a TypeError exception. This is an example of a value that cannot be stringified:

``````a = [];
a = a;
my_text = JSON.stringify(a); // This must throw a TypeError.``````
Note 2

Symbolic primitive values are rendered as follows:

• The null value is rendered in JSON text as the String "null".
• The undefined value is not rendered.
• The true value is rendered in JSON text as the String "true".
• The false value is rendered in JSON text as the String "false".
Note 3

String values are wrapped in QUOTATION MARK (`"`) code units. The code units `"` and `\` are escaped with `\` prefixes. Control characters code units are replaced with escape sequences `\u`HHHH, or with the shorter forms, `\b` (BACKSPACE), `\f` (FORM FEED), `\n` (LINE FEED), `\r` (CARRIAGE RETURN), `\t` (CHARACTER TABULATION).

Note 4

Finite numbers are stringified as if by calling ToString(number). NaN and Infinity regardless of sign are represented as the String "null".

Note 5

Values that do not have a JSON representation (such as undefined and functions) do not produce a String. Instead they produce the undefined value. In arrays these values are represented as the String "null". In objects an unrepresentable value causes the property to be excluded from stringification.

Note 6

An object is rendered as U+007B (LEFT CURLY BRACKET) followed by zero or more properties, separated with a U+002C (COMMA), closed with a U+007D (RIGHT CURLY BRACKET). A property is a quoted String representing the key or property name, a U+003A (COLON), and then the stringified property value. An array is rendered as an opening U+005B (LEFT SQUARE BRACKET followed by zero or more values, separated with a U+002C (COMMA), closed with a U+005D (RIGHT SQUARE BRACKET).

# 25.5.2.1 SerializeJSONProperty ( state, key, holder )

The abstract operation SerializeJSONProperty takes arguments state, key, and holder. It performs the following steps when called:

1. Let value be ? Get(holder, key).
2. If Type(value) is Object or BigInt, then
1. Let toJSON be ? GetV(value, "toJSON").
2. If IsCallable(toJSON) is true, then
1. Set value to ? Call(toJSON, value, « key »).
3. If state.[[ReplacerFunction]] is not undefined, then
1. Set value to ? Call(state.[[ReplacerFunction]], holder, « key, value »).
4. If Type(value) is Object, then
1. If value has a [[NumberData]] internal slot, then
1. Set value to ? ToNumber(value).
2. Else if value has a [[StringData]] internal slot, then
1. Set value to ? ToString(value).
3. Else if value has a [[BooleanData]] internal slot, then
1. Set value to value.[[BooleanData]].
4. Else if value has a [[BigIntData]] internal slot, then
1. Set value to value.[[BigIntData]].
5. If value is null, return "null".
6. If value is true, return "true".
7. If value is false, return "false".
8. If Type(value) is String, return QuoteJSONString(value).
9. If Type(value) is Number, then
1. If value is finite, return ! ToString(value).
2. Return "null".
10. If Type(value) is BigInt, throw a TypeError exception.
11. If Type(value) is Object and IsCallable(value) is false, then
1. Let isArray be ? IsArray(value).
2. If isArray is true, return ? SerializeJSONArray(state, value).
3. Return ? SerializeJSONObject(state, value).
12. Return undefined.

# 25.5.2.2 QuoteJSONString ( value )

The abstract operation QuoteJSONString takes argument value. It wraps value in 0x0022 (QUOTATION MARK) code units and escapes certain other code units within it. This operation interprets value as a sequence of UTF-16 encoded code points, as described in 6.1.4. It performs the following steps when called:

1. Let product be the String value consisting solely of the code unit 0x0022 (QUOTATION MARK).
2. For each code point C of ! StringToCodePoints(value), do
1. If C is listed in the “Code Point” column of Table 74, then
1. Set product to the string-concatenation of product and the escape sequence for C as specified in the “Escape Sequence” column of the corresponding row.
2. Else if C has a numeric value less than 0x0020 (SPACE), or if C has the same numeric value as a leading surrogate or trailing surrogate, then
1. Let unit be the code unit whose numeric value is that of C.
2. Set product to the string-concatenation of product and UnicodeEscape(unit).
3. Else,
1. Set product to the string-concatenation of product and ! UTF16EncodeCodePoint(C).
3. Set product to the string-concatenation of product and the code unit 0x0022 (QUOTATION MARK).
4. Return product.

# 25.5.2.3 UnicodeEscape ( C )

The abstract operation UnicodeEscape takes argument C (a code unit). It represents C as a Unicode escape sequence. It performs the following steps when called:

1. Let n be the numeric value of C.
2. Assert: n ≤ 0xFFFF.
3. Return the string-concatenation of:
• the code unit 0x005C (REVERSE SOLIDUS)
• "u"
• the String representation of n, formatted as a four-digit lowercase hexadecimal number, padded to the left with zeroes if necessary

# 25.5.2.4 SerializeJSONObject ( state, value )

The abstract operation SerializeJSONObject takes arguments state and value. It serializes an object. It performs the following steps when called:

1. If state.[[Stack]] contains value, throw a TypeError exception because the structure is cyclical.
2. Append value to state.[[Stack]].
3. Let stepback be state.[[Indent]].
4. Set state.[[Indent]] to the string-concatenation of state.[[Indent]] and state.[[Gap]].
5. If state.[[PropertyList]] is not undefined, then
1. Let K be state.[[PropertyList]].
6. Else,
1. Let K be ? EnumerableOwnPropertyNames(value, key).
7. Let partial be a new empty List.
8. For each element P of K, do
1. Let strP be ? SerializeJSONProperty(state, P, value).
2. If strP is not undefined, then
1. Let member be QuoteJSONString(P).
2. Set member to the string-concatenation of member and ":".
3. If state.[[Gap]] is not the empty String, then
1. Set member to the string-concatenation of member and the code unit 0x0020 (SPACE).
4. Set member to the string-concatenation of member and strP.
5. Append member to partial.
9. If partial is empty, then
1. Let final be "{}".
10. Else,
1. If state.[[Gap]] is the empty String, then
1. Let properties be the String value formed by concatenating all the element Strings of partial with each adjacent pair of Strings separated with the code unit 0x002C (COMMA). A comma is not inserted either before the first String or after the last String.
2. Let final be the string-concatenation of "{", properties, and "}".
2. Else,
1. Let separator be the string-concatenation of the code unit 0x002C (COMMA), the code unit 0x000A (LINE FEED), and state.[[Indent]].
2. Let properties be the String value formed by concatenating all the element Strings of partial with each adjacent pair of Strings separated with separator. The separator String is not inserted either before the first String or after the last String.
3. Let final be the string-concatenation of "{", the code unit 0x000A (LINE FEED), state.[[Indent]], properties, the code unit 0x000A (LINE FEED), stepback, and "}".
11. Remove the last element of state.[[Stack]].
12. Set state.[[Indent]] to stepback.
13. Return final.

# 25.5.2.5 SerializeJSONArray ( state, value )

The abstract operation SerializeJSONArray takes arguments state and value. It serializes an array. It performs the following steps when called:

1. If state.[[Stack]] contains value, throw a TypeError exception because the structure is cyclical.
2. Append value to state.[[Stack]].
3. Let stepback be state.[[Indent]].
4. Set state.[[Indent]] to the string-concatenation of state.[[Indent]] and state.[[Gap]].
5. Let partial be a new empty List.
6. Let len be ? LengthOfArrayLike(value).
7. Let index be 0.
8. Repeat, while index < len,
1. Let strP be ? SerializeJSONProperty(state, ! ToString(𝔽(index)), value).
2. If strP is undefined, then
1. Append "null" to partial.
3. Else,
1. Append strP to partial.
4. Set index to index + 1.
9. If partial is empty, then
1. Let final be "[]".
10. Else,
1. If state.[[Gap]] is the empty String, then
1. Let properties be the String value formed by concatenating all the element Strings of partial with each adjacent pair of Strings separated with the code unit 0x002C (COMMA). A comma is not inserted either before the first String or after the last String.
2. Let final be the string-concatenation of "[", properties, and "]".
2. Else,
1. Let separator be the string-concatenation of the code unit 0x002C (COMMA), the code unit 0x000A (LINE FEED), and state.[[Indent]].
2. Let properties be the String value formed by concatenating all the element Strings of partial with each adjacent pair of Strings separated with separator. The separator String is not inserted either before the first String or after the last String.
3. Let final be the string-concatenation of "[", the code unit 0x000A (LINE FEED), state.[[Indent]], properties, the code unit 0x000A (LINE FEED), stepback, and "]".
11. Remove the last element of state.[[Stack]].
12. Set state.[[Indent]] to stepback.
13. Return final.
Note

The representation of arrays includes only the elements between zero and `array.length` - 1 inclusive. Properties whose keys are not array indices are excluded from the stringification. An array is stringified as an opening LEFT SQUARE BRACKET, elements separated by COMMA, and a closing RIGHT SQUARE BRACKET.

# 25.5.3 JSON [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "JSON".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.