25 结构化数据

25.1 ArrayBuffer 对象

25.1.1 表示法

本节、25.429 中的以下描述使用读-改-写修改函数内部数据结构。

读-改-写修改函数是一个数学函数,表示为一个 Abstract Closure,它接受两个字节值 List 作为实参并返回一个字节值 List。这些 Abstract Closure 满足以下所有属性:

  • 它们以原子方式执行其所有算法步骤。
  • 它们的各个算法步骤不可观察。
Note

为帮助验证读-改-写修改函数的算法步骤构成纯粹的数学函数,推荐采用以下编辑约定:

25.1.2 定长和可调整大小的 ArrayBuffer 对象

定长 ArrayBuffer 是创建后字节长度不能改变的 ArrayBuffer。

可调整大小的 ArrayBuffer 是创建后字节长度可以通过调用 ArrayBuffer.prototype.resize ( newLength ) 改变的 ArrayBuffer。

创建哪种 ArrayBuffer 对象取决于传给 ArrayBuffer ( length [ , options ] ) 的实参。

25.1.3 ArrayBuffer 对象的抽象操作

25.1.3.1 AllocateArrayBuffer ( ctor, byteLength [ , maxByteLength ] )

The abstract operation AllocateArrayBuffer takes arguments ctor (a constructor) and byteLength (a non-negative integer) and optional argument maxByteLength (a non-negative integer or empty) and returns either a normal completion containing an ArrayBuffer or a throw completion. 它用于创建 ArrayBuffer。 It performs the following steps when called:

  1. slots 为 « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] »。
  2. 如果存在 maxByteLengthmaxByteLength 不是 empty,则令 allocatingResizableBuffertrue;否则令 allocatingResizableBufferfalse
  3. 如果 allocatingResizableBuffertrue,则
    1. 如果 byteLength > maxByteLength,则抛出 RangeError 异常。
    2. [[ArrayBufferMaxByteLength]] 追加到 slots
  4. obj 为 ? OrdinaryCreateFromConstructor(ctor, "%ArrayBuffer.prototype%", slots)。
  5. block 为 ? CreateByteDataBlock(byteLength)。
  6. obj.[[ArrayBufferData]] 设置为 block
  7. obj.[[ArrayBufferByteLength]] 设置为 byteLength
  8. 如果 allocatingResizableBuffertrue,则
    1. 如果无法创建由 maxByteLength 个字节组成的 Data Block block,则抛出 RangeError 异常。
    2. 注:可调整大小的 ArrayBuffer 被设计为可用原地增长实现。例如,如果虚拟内存无法预先保留,实现可以抛出异常。
    3. obj.[[ArrayBufferMaxByteLength]] 设置为 maxByteLength
  9. 返回 obj

25.1.3.2 ArrayBufferByteLength ( arrayBuffer, order )

The abstract operation ArrayBufferByteLength takes arguments arrayBuffer (an ArrayBuffer or SharedArrayBuffer) and order (seq-cst or unordered) and returns a non-negative integer. It performs the following steps when called:

  1. 如果 IsGrowableSharedArrayBuffer(arrayBuffer) 是 true,则
    1. bufferByteLengthBlockarrayBuffer.[[ArrayBufferByteLengthData]]
    2. rawLengthGetRawBytesFromSharedBlock(bufferByteLengthBlock, 0, biguint64, true, order)。
    3. agentRecord 为 surrounding agentAgent Record
    4. isLittleEndianagentRecord.[[LittleEndian]]
    5. 返回 (RawBytesToNumeric(biguint64, rawLength, isLittleEndian))。
  2. 断言:IsDetachedBuffer(arrayBuffer) 是 false
  3. 返回 arrayBuffer.[[ArrayBufferByteLength]]

25.1.3.3 ArrayBufferCopyAndDetach ( arrayBuffer, newLength, preserveResizability )

The abstract operation ArrayBufferCopyAndDetach takes arguments arrayBuffer (an ECMAScript language value), newLength (an ECMAScript language value), and preserveResizability (preserve-resizability or fixed-length) and returns either a normal completion containing an ArrayBuffer or a throw completion. It performs the following steps when called:

  1. 执行 ? RequireInternalSlot(arrayBuffer, [[ArrayBufferData]])。
  2. 如果 IsSharedArrayBuffer(arrayBuffer) 是 true,则抛出 TypeError 异常。
  3. 如果 newLengthundefined,则
    1. newByteLengtharrayBuffer.[[ArrayBufferByteLength]]
  4. 否则,
    1. newByteLength 为 ? ToIndex(newLength)。
  5. 如果 IsDetachedBuffer(arrayBuffer) 是 true,则抛出 TypeError 异常。
  6. 如果 preserveResizabilitypreserve-resizabilityIsFixedLengthArrayBuffer(arrayBuffer) 是 false,则
    1. newMaxByteLengtharrayBuffer.[[ArrayBufferMaxByteLength]]
  7. 否则,
    1. newMaxByteLengthempty
  8. 如果 arrayBuffer.[[ArrayBufferDetachKey]] 不是 undefined,则抛出 TypeError 异常。
  9. newBuffer 为 ? AllocateArrayBuffer(%ArrayBuffer%, newByteLength, newMaxByteLength)。
  10. copyLengthmin(newByteLength, arrayBuffer.[[ArrayBufferByteLength]])。
  11. fromBlockarrayBuffer.[[ArrayBufferData]]
  12. toBlocknewBuffer.[[ArrayBufferData]]
  13. 执行 CopyDataBlockBytes(toBlock, 0, fromBlock, 0, copyLength)。
  14. 注:新 Data Block 的创建以及从旧 Data Block 的复制都不可观察。实现可以将此方法实现为零复制移动或 realloc
  15. 执行 ! DetachArrayBuffer(arrayBuffer)。
  16. 返回 newBuffer

25.1.3.4 IsDetachedBuffer ( arrayBuffer )

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

  1. 如果 arrayBuffer.[[ArrayBufferData]]null,则返回 true
  2. 返回 false

25.1.3.5 DetachArrayBuffer ( arrayBuffer [ , key ] )

The abstract operation DetachArrayBuffer takes argument arrayBuffer (an ArrayBuffer) and optional argument key (anything) and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

  1. 断言:IsSharedArrayBuffer(arrayBuffer) 是 false
  2. 如果 key 不存在,则将 key 设置为 undefined
  3. 如果 arrayBuffer.[[ArrayBufferDetachKey]] 不是 key,则抛出 TypeError 异常。
  4. arrayBuffer.[[ArrayBufferData]] 设置为 null
  5. arrayBuffer.[[ArrayBufferByteLength]] 设置为 0。
  6. 返回 unused
Note

分离 ArrayBuffer 实例会解除用作其后备存储的 Data Block 与该实例的关联,并将缓冲区的字节长度设置为 0。

25.1.3.6 CloneArrayBuffer ( sourceBuffer, sourceByteOffset, sourceLength )

The abstract operation CloneArrayBuffer takes arguments sourceBuffer (an ArrayBuffer or a SharedArrayBuffer), sourceByteOffset (a non-negative integer), and sourceLength (a non-negative integer) and returns either a normal completion containing an ArrayBuffer or a throw completion. 它创建一个新的 ArrayBuffer,其数据是 sourceBuffersourceByteOffset 开始并持续 sourceLength 字节范围内数据的副本。 It performs the following steps when called:

  1. 断言:IsDetachedBuffer(sourceBuffer) 是 false
  2. targetBuffer 为 ? AllocateArrayBuffer(%ArrayBuffer%, sourceLength)。
  3. sourceBlocksourceBuffer.[[ArrayBufferData]]
  4. targetBlocktargetBuffer.[[ArrayBufferData]]
  5. 执行 CopyDataBlockBytes(targetBlock, 0, sourceBlock, sourceByteOffset, sourceLength)。
  6. 返回 targetBuffer

25.1.3.7 GetArrayBufferMaxByteLengthOption ( options )

The abstract operation GetArrayBufferMaxByteLengthOption takes argument options (an ECMAScript language value) and returns either a normal completion containing either a non-negative integer or empty, or a throw completion. It performs the following steps when called:

  1. 如果 options 不是 Object,则返回 empty
  2. maxByteLength 为 ? Get(options, "maxByteLength")。
  3. 如果 maxByteLengthundefined,则返回 empty
  4. 返回 ? ToIndex(maxByteLength)。

25.1.3.8 HostResizeArrayBuffer ( buffer, newByteLength )

The host-defined abstract operation HostResizeArrayBuffer takes arguments buffer (an ArrayBuffer) and newByteLength (a non-negative integer) and returns either a normal completion containing either handled or unhandled, or a throw completion. 它给宿主一个机会,对 buffer 执行实现定义的调整大小操作。如果宿主选择不处理 buffer 的调整大小,则可以返回 unhandled 以采用默认行为。

HostResizeArrayBuffer 的实现必须符合以下要求:

HostResizeArrayBuffer 的默认实现是返回 NormalCompletion(unhandled)。

25.1.3.9 IsFixedLengthArrayBuffer ( arrayBuffer )

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

  1. 如果 arrayBuffer 具有 [[ArrayBufferMaxByteLength]] 内部槽,则返回 false
  2. 返回 true

25.1.3.10 IsUnsignedElementType ( type )

The abstract operation IsUnsignedElementType takes argument type (a TypedArray element type) and returns a Boolean. 它验证实参 type 是否为无符号 TypedArray 元素类型。 It performs the following steps when called:

  1. 如果 typeuint8uint8clampeduint16uint32biguint64 之一,则返回 true
  2. 返回 false

25.1.3.11 IsUnclampedIntegerElementType ( type )

The abstract operation IsUnclampedIntegerElementType takes argument type (a TypedArray element type) and returns a Boolean. 它验证实参 type 是否为不包含 uint8clampedInteger TypedArray 元素类型。 It performs the following steps when called:

  1. 如果 typeint8uint8int16uint16int32uint32 之一,则返回 true
  2. 返回 false

25.1.3.12 IsBigIntElementType ( type )

The abstract operation IsBigIntElementType takes argument type (a TypedArray element type) and returns a Boolean. 它验证实参 type 是否为 BigInt TypedArray 元素类型。 It performs the following steps when called:

  1. 如果 typebiguint64bigint64,则返回 true
  2. 返回 false

25.1.3.13 IsNoTearConfiguration ( type, order )

The abstract operation IsNoTearConfiguration takes arguments type (a TypedArray element type) and order (seq-cst, unordered, or init) and returns a Boolean. It performs the following steps when called:

  1. 如果 IsUnclampedIntegerElementType(type) 是 true,则返回 true
  2. 如果 IsBigIntElementType(type) 是 trueorder 既不是 init 也不是 unordered,则返回 true
  3. 返回 false

25.1.3.14 RawBytesToNumeric ( type, rawBytes, isLittleEndian )

The abstract operation RawBytesToNumeric takes arguments type (a TypedArray element type), rawBytes (a List of byte values), and isLittleEndian (a Boolean) and returns a Number or a BigInt. It performs the following steps when called:

  1. elementSizeTable 71 中为 Element Type type 指定的 Element Size 值。
  2. 如果 isLittleEndianfalse,则反转 rawBytes 的元素顺序。
  3. 如果 typefloat16,则
    1. valuerawBytes 的字节元素连接后并解释为 IEEE 754-2019 binary16 值的小端位串编码。
    2. 如果 value 是 NaN,则返回 NaN
    3. 返回与 value 对应的 Number 值
  4. 如果 typefloat32,则
    1. valuerawBytes 的字节元素连接后并解释为 IEEE 754-2019 binary32 值的小端位串编码。
    2. 如果 value 是 NaN,则返回 NaN
    3. 返回与 value 对应的 Number 值
  5. 如果 typefloat64,则
    1. valuerawBytes 的字节元素连接后并解释为 IEEE 754-2019 binary64 值的小端位串编码。
    2. 如果 value 是 NaN,则返回 NaN
    3. 返回与 value 对应的 Number 值
  6. 如果 IsUnsignedElementType(type) 是 true,则
    1. intValuerawBytes 的字节元素连接后并解释为无符号小端二进制数的位串编码。
  7. 否则,
    1. intValuerawBytes 的字节元素连接后并解释为位长为 elementSize × 8 的二进制小端二进制补码数的位串编码。
  8. 如果 IsBigIntElementType(type) 是 true,则返回与 intValue 对应的 BigInt 值。
  9. 返回与 intValue 对应的 Number 值

25.1.3.15 GetRawBytesFromSharedBlock ( block, byteIndex, type, isTypedArray, order )

The abstract operation GetRawBytesFromSharedBlock takes arguments block (a Shared Data Block), byteIndex (a non-negative integer), type (a TypedArray element type), isTypedArray (a Boolean), and order (seq-cst or unordered) and returns a List of byte values. It performs the following steps when called:

  1. elementSizeTable 71 中为 Element Type type 指定的 Element Size 值。
  2. agentRecord 为 surrounding agentAgent Record
  3. executionagentRecord.[[CandidateExecution]]
  4. eventsRecordexecution.[[EventsRecords]][[AgentSignifier]]AgentSignifier() 的 Agent Events Record
  5. 如果 isTypedArraytrueIsNoTearConfiguration(type, order) 是 true,则令 noTeartrue;否则令 noTearfalse
  6. rawValue 为长度为 elementSizeList,其元素为非确定性选择的字节值
  7. 注:在实现中,rawValue 是底层硬件上的非原子或原子读取指令的结果。非确定性是内存模型的一项语义规定,用于描述弱一致性硬件的可观察行为。
  8. readEventReadSharedMemory { [[Order]]: order, [[NoTear]]: noTear, [[Block]]: block, [[ByteIndex]]: byteIndex, [[ElementSize]]: elementSize }。
  9. readEvent 追加到 eventsRecord.[[EventList]]
  10. Chosen Value Record { [[Event]]: readEvent, [[ChosenValue]]: rawValue } 追加到 execution.[[ChosenValues]]
  11. 返回 rawValue

25.1.3.16 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 (seq-cst or unordered) and optional argument isLittleEndian (a Boolean) and returns a Number or a BigInt. It performs the following steps when called:

  1. 断言:IsDetachedBuffer(arrayBuffer) 是 false
  2. 断言:arrayBuffer 中从 byteIndex 开始有足够的字节来表示 type 的值。
  3. blockarrayBuffer.[[ArrayBufferData]]
  4. elementSizeTable 71 中为 Element Type type 指定的 Element Size 值。
  5. 如果 IsSharedArrayBuffer(arrayBuffer) 是 true,则
    1. 断言:blockShared Data Block
    2. rawValueGetRawBytesFromSharedBlock(block, byteIndex, type, isTypedArray, order)。
  6. 否则,
    1. rawValue 为一个 List,其元素是 block 中索引在从 byteIndex包含)到 byteIndex + elementSize(不包含)的区间内的字节。
  7. 断言:rawValue 中元素的数量是 elementSize
  8. 如果 isLittleEndian 不存在,则
    1. agentRecord 为 surrounding agentAgent Record
    2. isLittleEndian 设置为 agentRecord.[[LittleEndian]]
  9. 返回 RawBytesToNumeric(type, rawValue, isLittleEndian)。

25.1.3.17 NumericToRawBytes ( type, value, isLittleEndian )

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

  1. 如果 typefloat16,则
    1. rawBytes 为一个 List,其元素是使用 roundTiesToEven 模式将 value 转换为 IEEE 754-2019 binary16 格式所得的 2 个字节。这些字节按小端顺序排列。如果 valueNaN,则 rawBytes 可以设置为任意实现所选择的 IEEE 754-2019 binary16 格式 NaN 编码。实现必须始终为每个实现可区分的 NaN 值选择相同的编码。
  2. 否则,如果 typefloat32,则
    1. rawBytes 为一个 List,其元素是使用 roundTiesToEven 模式将 value 转换为 IEEE 754-2019 binary32 格式所得的 4 个字节。这些字节按小端顺序排列。如果 valueNaN,则 rawBytes 可以设置为任意实现所选择的 IEEE 754-2019 binary32 格式 NaN 编码。实现必须始终为每个实现可区分的 NaN 值选择相同的编码。
  3. 否则,如果 typefloat64,则
    1. rawBytes 为一个 List,其元素是 valueIEEE 754-2019 binary64 格式编码的 8 个字节。这些字节按小端顺序排列。如果 valueNaN,则 rawBytes 可以设置为任意实现所选择的 IEEE 754-2019 binary64 格式 NaN 编码。实现必须始终为每个实现可区分的 NaN 值选择相同的编码。
  4. 否则,
    1. nTable 71 中为 Element Type type 指定的 Element Size 值。
    2. conversionOperationTable 71 中 Element Type type 的 “Conversion Operation” 列所命名的抽象操作
    3. intValue(! conversionOperation(value))。
    4. 如果 intValue ≥ 0,则
      1. rawBytes 为一个 List,其元素是 intValuen 字节二进制编码。这些字节按小端顺序排列。
    5. 否则,
      1. rawBytes 为一个 List,其元素是 intValuen 字节二进制补码编码。这些字节按小端顺序排列。
  5. 如果 isLittleEndianfalse,则反转 rawBytes 的元素顺序。
  6. 返回 rawBytes

25.1.3.18 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 (seq-cst, unordered, or init) and optional argument isLittleEndian (a Boolean) and returns unused. It performs the following steps when called:

  1. 断言:IsDetachedBuffer(arrayBuffer) 是 false
  2. 断言:arrayBuffer 中从 byteIndex 开始有足够的字节来表示 type 的值。
  3. 断言:如果 IsBigIntElementType(type) 是 true,则 value 是 BigInt;否则,value 是 Number。
  4. blockarrayBuffer.[[ArrayBufferData]]
  5. elementSizeTable 71 中为 Element Type type 指定的 Element Size 值。
  6. agentRecord 为 surrounding agentAgent Record
  7. 如果 isLittleEndian 不存在,则
    1. isLittleEndian 设置为 agentRecord.[[LittleEndian]]
  8. rawBytesNumericToRawBytes(type, value, isLittleEndian)。
  9. 如果 IsSharedArrayBuffer(arrayBuffer) 是 true,则
    1. executionagentRecord.[[CandidateExecution]]
    2. eventsRecordexecution.[[EventsRecords]][[AgentSignifier]]AgentSignifier() 的 Agent Events Record
    3. 如果 isTypedArraytrueIsNoTearConfiguration(type, order) 是 true,则令 noTeartrue;否则令 noTearfalse
    4. WriteSharedMemory { [[Order]]: order, [[NoTear]]: noTear, [[Block]]: block, [[ByteIndex]]: byteIndex, [[ElementSize]]: elementSize, [[Payload]]: rawBytes } 追加到 eventsRecord.[[EventList]]
  10. 否则,
    1. rawBytes 的各个字节存储到 block 中,从 block[byteIndex] 开始。
  11. 返回 unused

25.1.3.19 GetModifySetValueInBuffer ( arrayBuffer, byteIndex, type, value, op )

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 returns a Number or a BigInt. It performs the following steps when called:

  1. 断言:IsDetachedBuffer(arrayBuffer) 是 false
  2. 断言:arrayBuffer 中从 byteIndex 开始有足够的字节来表示 type 的值。
  3. 断言:如果 IsBigIntElementType(type) 是 true,则 value 是 BigInt;否则,value 是 Number。
  4. blockarrayBuffer.[[ArrayBufferData]]
  5. elementSizeTable 71 中为 Element Type type 指定的 Element Size 值。
  6. agentRecord 为 surrounding agentAgent Record
  7. isLittleEndianagentRecord.[[LittleEndian]]
  8. rawBytesNumericToRawBytes(type, value, isLittleEndian)。
  9. 如果 IsSharedArrayBuffer(arrayBuffer) 是 true,则
    1. executionagentRecord.[[CandidateExecution]]
    2. eventsRecordexecution.[[EventsRecords]][[AgentSignifier]]AgentSignifier() 的 Agent Events Record
    3. rawBytesRead 为长度为 elementSizeList,其元素为非确定性选择的字节值
    4. 注:在实现中,rawBytesRead 是底层硬件上的 load-link、load-exclusive,或读-改-写指令的一个操作数的结果。非确定性是内存模型的一项语义规定,用于描述弱一致性硬件的可观察行为。
    5. rmwEventReadModifyWriteSharedMemory { [[Order]]: seq-cst, [[NoTear]]: true, [[Block]]: block, [[ByteIndex]]: byteIndex, [[ElementSize]]: elementSize, [[Payload]]: rawBytes, [[ModifyOp]]: op }。
    6. rmwEvent 追加到 eventsRecord.[[EventList]]
    7. Chosen Value Record { [[Event]]: rmwEvent, [[ChosenValue]]: rawBytesRead } 追加到 execution.[[ChosenValues]]
  10. 否则,
    1. rawBytesRead 为长度为 elementSizeList,其元素是从 block[byteIndex] 开始的 elementSize 个字节序列。
    2. rawBytesModifiedop(rawBytesRead, rawBytes)。
    3. rawBytesModified 的各个字节存储到 block 中,从 block[byteIndex] 开始。
  11. 返回 RawBytesToNumeric(type, rawBytesRead, isLittleEndian)。

25.1.4 ArrayBuffer 构造器

ArrayBuffer 构造器:

  • %ArrayBuffer%
  • 全局对象"ArrayBuffer" 属性的初始值。
  • 在作为构造器调用时创建并初始化一个新的 ArrayBuffer。
  • 不意图作为函数调用,并且以这种方式调用时会抛出异常。
  • 可以用作类定义的 extends 子句的值。打算继承指定 ArrayBuffer 行为的子类构造函数,必须包含一次对 ArrayBuffer 构造函数super 调用,以创建并初始化子类实例,使其具备支持 ArrayBuffer.prototype 的内置方法所必需的内部状态。

25.1.4.1 ArrayBuffer ( length [ , options ] )

此函数在被调用时执行以下步骤:

  1. 如果 NewTarget 是 undefined,则抛出 TypeError 异常。
  2. byteLength 为 ? ToIndex(length)。
  3. requestedMaxByteLength 为 ? GetArrayBufferMaxByteLengthOption(options)。
  4. 返回 ? AllocateArrayBuffer(NewTarget, byteLength, requestedMaxByteLength)。

25.1.5 ArrayBuffer 构造器的属性

ArrayBuffer 构造器:

25.1.5.1 ArrayBuffer.isView ( arg )

此函数在被调用时执行以下步骤:

  1. 如果 arg 不是 Object,则返回 false
  2. 如果 arg 具有 [[ViewedArrayBuffer]] 内部槽,则返回 true
  3. 返回 false

25.1.5.2 ArrayBuffer.prototype

ArrayBuffer.prototype 的初始值是 ArrayBuffer 原型对象

此属性具有特性 { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }。

25.1.5.3 get ArrayBuffer [ %Symbol.species% ]

ArrayBuffer[%Symbol.species%]访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. 返回 this 值。

此函数的 "name" 属性的值是 "get [Symbol.species]"

Note

ArrayBuffer.prototype.slice ( start, end ) 通常使用其 this 值的构造器来创建派生对象。不过,子类构造器可以通过重新定义其 %Symbol.species% 属性,覆盖 ArrayBuffer.prototype.slice ( start, end ) 方法的这种默认行为。

25.1.6 ArrayBuffer 原型对象的属性

ArrayBuffer 原型对象

  • %ArrayBuffer.prototype%
  • 具有一个 [[Prototype]] 内部槽,其值为 %Object.prototype%
  • 普通对象
  • 没有 [[ArrayBufferData]][[ArrayBufferByteLength]] 内部槽。

25.1.6.1 get ArrayBuffer.prototype.byteLength

ArrayBuffer.prototype.byteLength访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 true,则抛出 TypeError 异常。
  4. 如果 IsDetachedBuffer(obj) 是 true,则返回 +0𝔽
  5. lengthobj.[[ArrayBufferByteLength]]
  6. 返回 𝔽(length)。

25.1.6.2 ArrayBuffer.prototype.constructor

ArrayBuffer.prototype.constructor 的初始值是 %ArrayBuffer%

25.1.6.3 get ArrayBuffer.prototype.detached

ArrayBuffer.prototype.detached访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 true,则抛出 TypeError 异常。
  4. 返回 IsDetachedBuffer(obj)。

25.1.6.4 get ArrayBuffer.prototype.maxByteLength

ArrayBuffer.prototype.maxByteLength访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 true,则抛出 TypeError 异常。
  4. 如果 IsDetachedBuffer(obj) 是 true,则返回 +0𝔽
  5. 如果 IsFixedLengthArrayBuffer(obj) 是 true,则
    1. lengthobj.[[ArrayBufferByteLength]]
  6. 否则,
    1. lengthobj.[[ArrayBufferMaxByteLength]]
  7. 返回 𝔽(length)。

25.1.6.5 get ArrayBuffer.prototype.resizable

ArrayBuffer.prototype.resizable访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 true,则抛出 TypeError 异常。
  4. 如果 IsFixedLengthArrayBuffer(obj) 是 false,则返回 true
  5. 返回 false

25.1.6.6 ArrayBuffer.prototype.resize ( newLength )

此方法在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferMaxByteLength]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 true,则抛出 TypeError 异常。
  4. newByteLength 为 ? ToIndex(newLength)。
  5. 如果 IsDetachedBuffer(obj) 是 true,则抛出 TypeError 异常。
  6. 如果 newByteLength > obj.[[ArrayBufferMaxByteLength]],则抛出 RangeError 异常。
  7. hostHandled 为 ? HostResizeArrayBuffer(obj, newByteLength)。
  8. 如果 hostHandledhandled,则返回 undefined
  9. oldBlockobj.[[ArrayBufferData]]
  10. newBlock 为 ? CreateByteDataBlock(newByteLength)。
  11. copyLengthmin(newByteLength, obj.[[ArrayBufferByteLength]])。
  12. 执行 CopyDataBlockBytes(newBlock, 0, oldBlock, 0, copyLength)。
  13. 注:新 Data Block 的创建以及从旧 Data Block 的复制都不可观察。实现可以将此方法实现为原地增长或缩小。
  14. obj.[[ArrayBufferData]] 设置为 newBlock
  15. obj.[[ArrayBufferByteLength]] 设置为 newByteLength
  16. 返回 undefined

25.1.6.7 ArrayBuffer.prototype.slice ( start, end )

此方法在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 true,则抛出 TypeError 异常。
  4. 如果 IsDetachedBuffer(obj) 是 true,则抛出 TypeError 异常。
  5. lengthobj.[[ArrayBufferByteLength]]
  6. relativeStart 为 ? ToIntegerOrInfinity(start)。
  7. 如果 relativeStart = -∞,则令 first 为 0。
  8. 否则,如果 relativeStart < 0,则令 firstmax(length + relativeStart, 0)。
  9. 否则,令 firstmin(relativeStart, length)。
  10. 如果 endundefined,则令 relativeEndlength;否则令 relativeEnd 为 ? ToIntegerOrInfinity(end)。
  11. 如果 relativeEnd = -∞,则令 final 为 0。
  12. 否则,如果 relativeEnd < 0,则令 finalmax(length + relativeEnd, 0)。
  13. 否则,令 finalmin(relativeEnd, length)。
  14. newLengthmax(final - first, 0)。
  15. ctor 为 ? SpeciesConstructor(obj, %ArrayBuffer%)。
  16. new 为 ? Construct(ctor, « 𝔽(newLength) »)。
  17. 执行 ? RequireInternalSlot(new, [[ArrayBufferData]])。
  18. 如果 IsSharedArrayBuffer(new) 是 true,则抛出 TypeError 异常。
  19. 如果 IsDetachedBuffer(new) 是 true,则抛出 TypeError 异常。
  20. 如果 SameValue(new, obj) 是 true,则抛出 TypeError 异常。
  21. 如果 new.[[ArrayBufferByteLength]] < newLength,则抛出 TypeError 异常。
  22. 注:上述步骤的副作用可能已分离或调整 obj 的大小。
  23. 如果 IsDetachedBuffer(obj) 是 true,则抛出 TypeError 异常。
  24. fromBufobj.[[ArrayBufferData]]
  25. toBufnew.[[ArrayBufferData]]
  26. currentLengthobj.[[ArrayBufferByteLength]]
  27. 如果 first < currentLength,则
    1. countmin(newLength, currentLength - first)。
    2. 执行 CopyDataBlockBytes(toBuf, 0, fromBuf, first, count)。
  28. 返回 new

25.1.6.8 ArrayBuffer.prototype.transfer ( [ newLength ] )

此方法在被调用时执行以下步骤:

  1. objthis 值。
  2. 返回 ? ArrayBufferCopyAndDetach(obj, newLength, preserve-resizability)。

25.1.6.9 ArrayBuffer.prototype.transferToFixedLength ( [ newLength ] )

此方法在被调用时执行以下步骤:

  1. objthis 值。
  2. 返回 ? ArrayBufferCopyAndDetach(obj, newLength, fixed-length)。

25.1.6.10 ArrayBuffer.prototype [ %Symbol.toStringTag% ]

%Symbol.toStringTag% 属性的初始值是 String 值 "ArrayBuffer"

此属性具有特性 { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }。

25.1.7 ArrayBuffer 实例的属性

ArrayBuffer 实例继承自 ArrayBuffer 原型对象的属性。每个 ArrayBuffer 实例都有一个 [[ArrayBufferData]] 内部槽、一个 [[ArrayBufferByteLength]] 内部槽和一个 [[ArrayBufferDetachKey]] 内部槽。可调整大小的 ArrayBuffer 实例各自具有一个 [[ArrayBufferMaxByteLength]] 内部槽。

[[ArrayBufferData]]null 的 ArrayBuffer 实例被视为已分离,并且所有访问或修改 ArrayBuffer 实例中所包含数据的操作符都将失败。

[[ArrayBufferDetachKey]] 被设置为除 undefined 之外的值的 ArrayBuffer 实例,需要所有 DetachArrayBuffer 调用都将相同的“detach key”作为实参传入,否则将导致 TypeError。此内部槽只会由某些嵌入环境设置,而不会由本规范中的算法设置。

25.1.8 可调整大小 ArrayBuffer 指南

Note 1

以下是面向使用可调整大小 ArrayBuffer 的 ECMAScript 程序员的指南。

我们建议尽可能在程序的部署环境中进行测试。不同硬件设备之间可用物理内存的数量差异很大。同样,虚拟内存子系统在不同硬件设备以及操作系统之间也差异很大。一个在 64 位桌面 Web 浏览器上运行而没有内存不足错误的应用,在 32 位移动 Web 浏览器上可能会耗尽内存。

在为可调整大小 ArrayBuffer 选择 "maxByteLength" 选项的值时,我们建议选择应用所需的尽可能小的大小。我们建议 "maxByteLength" 不超过 1,073,741,824(230 字节或 1GiB)。

请注意,成功构造具有特定最大大小的可调整大小 ArrayBuffer,并不保证未来调整大小会成功。

Note 2

以下是面向实现可调整大小 ArrayBuffer 的 ECMAScript 实现者的指南。

可调整大小 ArrayBuffer 可以实现为调整大小时复制、通过预先保留虚拟内存进行原地增长,或根据构造器的 "maxByteLength" 选项的不同值采用两者的组合。

如果宿主是多租户的(即它同时运行许多 ECMAScript 应用),例如 Web 浏览器,并且其实现选择通过保留虚拟内存来实现原地增长,我们建议 32 位和 64 位实现都对 "maxByteLength" ≥ 1GiB 到 1.5GiB 的值抛出异常。这是为了降低单个应用耗尽虚拟内存地址空间的可能性,并降低互操作性风险。

如果宿主没有虚拟内存,例如运行在没有 MMU 的嵌入式设备上,或者如果宿主只通过复制实现调整大小,则它可以接受 "maxByteLength" 选项的任何 Number 值。不过,如果请求大小的内存块永远无法分配,我们建议抛出 RangeError。例如,请求大小大于设备上最大可用内存量时。

25.2 SharedArrayBuffer 对象

25.2.1 定长和可增长的 SharedArrayBuffer 对象

定长 SharedArrayBuffer 是创建后字节长度不能改变的 SharedArrayBuffer。

可增长 SharedArrayBuffer 是创建后字节长度可以通过调用 SharedArrayBuffer.prototype.grow ( newLength ) 增加的 SharedArrayBuffer。

创建哪种 SharedArrayBuffer 对象取决于传给 SharedArrayBuffer ( length [ , options ] ) 的实参。

25.2.2 SharedArrayBuffer 对象的抽象操作

25.2.2.1 AllocateSharedArrayBuffer ( ctor, byteLength [ , maxByteLength ] )

The abstract operation AllocateSharedArrayBuffer takes arguments ctor (a constructor) and byteLength (a non-negative integer) and optional argument maxByteLength (a non-negative integer or empty) and returns either a normal completion containing a SharedArrayBuffer or a throw completion. 它用于创建 SharedArrayBuffer。 It performs the following steps when called:

  1. slots 为 « [[ArrayBufferData]] »。
  2. 如果存在 maxByteLengthmaxByteLength 不是 empty,则令 allocatingGrowableBuffertrue;否则令 allocatingGrowableBufferfalse
  3. 如果 allocatingGrowableBuffertrue,则
    1. 如果 byteLength > maxByteLength,则抛出 RangeError 异常。
    2. [[ArrayBufferByteLengthData]][[ArrayBufferMaxByteLength]] 追加到 slots
  4. 否则,
    1. [[ArrayBufferByteLength]] 追加到 slots
  5. obj 为 ? OrdinaryCreateFromConstructor(ctor, "%SharedArrayBuffer.prototype%", slots)。
  6. 如果 allocatingGrowableBuffertrue,则令 allocLengthmaxByteLength;否则令 allocLengthbyteLength
  7. block 为 ? CreateSharedByteDataBlock(allocLength)。
  8. obj.[[ArrayBufferData]] 设置为 block
  9. 如果 allocatingGrowableBuffertrue,则
    1. 断言:byteLengthmaxByteLength
    2. byteLengthBlock 为 ? CreateSharedByteDataBlock(8)。
    3. 执行 SetValueInBuffer(byteLengthBlock, 0, biguint64, (byteLength), true, seq-cst)。
    4. obj.[[ArrayBufferByteLengthData]] 设置为 byteLengthBlock
    5. obj.[[ArrayBufferMaxByteLength]] 设置为 maxByteLength
  10. 否则,
    1. obj.[[ArrayBufferByteLength]] 设置为 byteLength
  11. 返回 obj

25.2.2.2 IsSharedArrayBuffer ( obj )

The abstract operation IsSharedArrayBuffer takes argument obj (an ArrayBuffer or a SharedArrayBuffer) and returns a Boolean. 它测试一个对象是否为 SharedArrayBuffer。 It performs the following steps when called:

  1. 如果 obj.[[ArrayBufferData]]Shared Data Block,则返回 true
  2. 返回 false

25.2.2.3 IsGrowableSharedArrayBuffer ( obj )

The abstract operation IsGrowableSharedArrayBuffer takes argument obj (an ArrayBuffer or a SharedArrayBuffer) and returns a Boolean. 它测试一个对象是否为可增长的 SharedArrayBuffer。 It performs the following steps when called:

  1. 如果 IsSharedArrayBuffer(obj) 是 trueobj 具有 [[ArrayBufferByteLengthData]] 内部槽,则返回 true
  2. 返回 false

25.2.2.4 HostGrowSharedArrayBuffer ( buffer, newByteLength )

The host-defined abstract operation HostGrowSharedArrayBuffer takes arguments buffer (a SharedArrayBuffer) and newByteLength (a non-negative integer) and returns either a normal completion containing either handled or unhandled, or a throw completion. 它给宿主一个机会,对 buffer 执行实现定义的增长操作。如果宿主选择不处理 buffer 的增长,则可以返回 unhandled 以采用默认行为。

HostGrowSharedArrayBuffer 的实现必须符合以下要求:

Note

上面的第二项要求有意对如何或何时读取 buffer 的当前字节长度保持模糊。由于字节长度必须通过底层硬件上的原子读-改-写操作来更新,使用 load-link/store-conditional 或 load-exclusive/store-exclusive 指令对的架构可能希望让成对指令在指令流中保持接近。因此,SharedArrayBuffer.prototype.grow ( newLength ) 本身不会在调用 HostGrowSharedArrayBuffer 之前对 newByteLength 执行边界检查,也不要求何时读取当前字节长度。

这与 HostResizeArrayBuffer 形成对比,后者保证 0 ≤ newByteLengthbuffer.[[ArrayBufferMaxByteLength]]

HostGrowSharedArrayBuffer 的默认实现是返回 NormalCompletion(unhandled)。

25.2.3 SharedArrayBuffer 构造器

SharedArrayBuffer 构造器:

  • %SharedArrayBuffer%
  • 全局对象"SharedArrayBuffer" 属性的初始值,如果该属性存在(见下文)。
  • 在作为构造器调用时创建并初始化一个新的 SharedArrayBuffer。
  • 不意图作为函数调用,并且以这种方式调用时会抛出异常。
  • 可以用作类定义的 extends 子句的值。打算继承指定 SharedArrayBuffer 行为的子类构造函数,必须包含一次对 SharedArrayBuffer 构造函数super 调用,以创建并初始化子类实例,使其具备支持 SharedArrayBuffer.prototype 的内置方法所必需的内部状态。

每当宿主不提供对 SharedArrayBuffer 的并发访问时,它可以省略全局对象"SharedArrayBuffer" 属性。

Note

不同于 ArrayBufferSharedArrayBuffer 不能被分离,其内部 [[ArrayBufferData]] 槽永远不会是 null

25.2.3.1 SharedArrayBuffer ( length [ , options ] )

此函数在被调用时执行以下步骤:

  1. 如果 NewTarget 是 undefined,则抛出 TypeError 异常。
  2. byteLength 为 ? ToIndex(length)。
  3. requestedMaxByteLength 为 ? GetArrayBufferMaxByteLengthOption(options)。
  4. 返回 ? AllocateSharedArrayBuffer(NewTarget, byteLength, requestedMaxByteLength)。

25.2.4 SharedArrayBuffer 构造器的属性

SharedArrayBuffer 构造器:

25.2.4.1 SharedArrayBuffer.prototype

SharedArrayBuffer.prototype 的初始值是 SharedArrayBuffer 原型对象

此属性具有特性 { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }。

25.2.4.2 get SharedArrayBuffer [ %Symbol.species% ]

SharedArrayBuffer[%Symbol.species%]访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. 返回 this 值。

此函数的 "name" 属性的值是 "get [Symbol.species]"

25.2.5 SharedArrayBuffer 原型对象的属性

SharedArrayBuffer 原型对象

  • %SharedArrayBuffer.prototype%
  • 具有一个 [[Prototype]] 内部槽,其值为 %Object.prototype%
  • 普通对象
  • 没有 [[ArrayBufferData]][[ArrayBufferByteLength]] 内部槽。

25.2.5.1 get SharedArrayBuffer.prototype.byteLength

SharedArrayBuffer.prototype.byteLength访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 false,则抛出 TypeError 异常。
  4. lengthArrayBufferByteLength(obj, seq-cst)。
  5. 返回 𝔽(length)。

25.2.5.2 SharedArrayBuffer.prototype.constructor

SharedArrayBuffer.prototype.constructor 的初始值是 %SharedArrayBuffer%

25.2.5.3 SharedArrayBuffer.prototype.grow ( newLength )

此方法在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferMaxByteLength]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 false,则抛出 TypeError 异常。
  4. newByteLength 为 ? ToIndex(newLength)。
  5. hostHandled 为 ? HostGrowSharedArrayBuffer(obj, newByteLength)。
  6. 如果 hostHandledhandled,则返回 undefined
  7. agentRecord 为 surrounding agentAgent Record
  8. isLittleEndianagentRecord.[[LittleEndian]]
  9. byteLengthBlockobj.[[ArrayBufferByteLengthData]]
  10. currentByteLengthRawBytesGetRawBytesFromSharedBlock(byteLengthBlock, 0, biguint64, true, seq-cst)。
  11. newByteLengthRawBytesNumericToRawBytes(biguint64, (newByteLength), isLittleEndian)。
  12. 重复,
    1. 注:这是一个 compare-and-exchange 循环,用于确保同一缓冲区的并行竞态增长被完全排序,不会丢失,也不会悄然什么都不做。如果它能够尝试无争用地增长,则循环退出。
    2. currentByteLength(RawBytesToNumeric(biguint64, currentByteLengthRawBytes, isLittleEndian))。
    3. 如果 newByteLength = currentByteLength,则返回 undefined
    4. 如果 newByteLength < currentByteLengthnewByteLength > obj.[[ArrayBufferMaxByteLength]],则抛出 RangeError 异常。
    5. byteLengthDeltanewByteLength - currentByteLength
    6. 如果无法创建由 byteLengthDelta 个字节组成的新 Shared Data Block 值,则抛出 RangeError 异常。
    7. 注:这里不会构造并使用新的 Shared Data Block可增长 SharedArrayBuffer 的可观察行为通过在构造时分配最大大小的 Shared Data Block 来指定,此步骤捕获了运行内存不足的实现必须抛出 RangeError 的要求。
    8. readByteLengthRawBytesAtomicCompareExchangeInSharedBlock(byteLengthBlock, 0, 8, currentByteLengthRawBytes, newByteLengthRawBytes)。
    9. 如果 ByteListEqual(readByteLengthRawBytes, currentByteLengthRawBytes) 是 true,则返回 undefined
    10. currentByteLengthRawBytes 设置为 readByteLengthRawBytes
Note

禁止 compare-exchange 更新长度时出现伪失败。如果新长度的边界检查通过且实现未内存不足,则总会向 candidate execution 添加一个 ReadModifyWriteSharedMemory 事件(即一次成功的 compare-exchange)。

对 SharedArrayBuffer.prototype.grow 的并行调用是完全排序的。例如,考虑两个竞态调用:sab.grow(10)sab.grow(20)。这两个调用中保证有一个会赢得竞态。即使 sab.grow(20) 先发生,对 sab.grow(10) 的调用也绝不会缩小 sab;在这种情况下,它会改为抛出 RangeError。

25.2.5.4 get SharedArrayBuffer.prototype.growable

SharedArrayBuffer.prototype.growable访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 false,则抛出 TypeError 异常。
  4. 如果 IsFixedLengthArrayBuffer(obj) 是 false,则返回 true
  5. 返回 false

25.2.5.5 get SharedArrayBuffer.prototype.maxByteLength

SharedArrayBuffer.prototype.maxByteLength访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 false,则抛出 TypeError 异常。
  4. 如果 IsFixedLengthArrayBuffer(obj) 是 true,则
    1. lengthobj.[[ArrayBufferByteLength]]
  5. 否则,
    1. lengthobj.[[ArrayBufferMaxByteLength]]
  6. 返回 𝔽(length)。

25.2.5.6 SharedArrayBuffer.prototype.slice ( start, end )

此方法在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 false,则抛出 TypeError 异常。
  4. lengthArrayBufferByteLength(obj, seq-cst)。
  5. relativeStart 为 ? ToIntegerOrInfinity(start)。
  6. 如果 relativeStart = -∞,则令 first 为 0。
  7. 否则,如果 relativeStart < 0,则令 firstmax(length + relativeStart, 0)。
  8. 否则,令 firstmin(relativeStart, length)。
  9. 如果 endundefined,则令 relativeEndlength;否则令 relativeEnd 为 ? ToIntegerOrInfinity(end)。
  10. 如果 relativeEnd = -∞,则令 final 为 0。
  11. 否则,如果 relativeEnd < 0,则令 finalmax(length + relativeEnd, 0)。
  12. 否则,令 finalmin(relativeEnd, length)。
  13. newLengthmax(final - first, 0)。
  14. ctor 为 ? SpeciesConstructor(obj, %SharedArrayBuffer%)。
  15. new 为 ? Construct(ctor, « 𝔽(newLength) »)。
  16. 执行 ? RequireInternalSlot(new, [[ArrayBufferData]])。
  17. 如果 IsSharedArrayBuffer(new) 是 false,则抛出 TypeError 异常。
  18. 如果 new.[[ArrayBufferData]]obj.[[ArrayBufferData]],则抛出 TypeError 异常。
  19. 如果 ArrayBufferByteLength(new, seq-cst) < newLength,则抛出 TypeError 异常。
  20. fromBufobj.[[ArrayBufferData]]
  21. toBufnew.[[ArrayBufferData]]
  22. 执行 CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLength)。
  23. 返回 new

25.2.5.7 SharedArrayBuffer.prototype [ %Symbol.toStringTag% ]

%Symbol.toStringTag% 属性的初始值是 String 值 "SharedArrayBuffer"

此属性具有特性 { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }。

25.2.6 SharedArrayBuffer 实例的属性

SharedArrayBuffer 实例继承自 SharedArrayBuffer 原型对象的属性。每个 SharedArrayBuffer 实例都有一个 [[ArrayBufferData]] 内部槽。不可增长的 SharedArrayBuffer 实例各自具有一个 [[ArrayBufferByteLength]] 内部槽。可增长的 SharedArrayBuffer 实例各自具有一个 [[ArrayBufferByteLengthData]] 内部槽和一个 [[ArrayBufferMaxByteLength]] 内部槽。

Note

SharedArrayBuffer 实例不同于 ArrayBuffer 实例,它们永远不会被分离。

25.2.7 可增长 SharedArrayBuffer 指南

Note 1

以下是面向使用可增长 SharedArrayBuffer 的 ECMAScript 程序员的指南。

我们建议尽可能在程序的部署环境中进行测试。不同硬件设备之间可用物理内存的数量差异很大。同样,虚拟内存子系统在不同硬件设备以及操作系统之间也差异很大。一个在 64 位桌面 Web 浏览器上运行而没有内存不足错误的应用,在 32 位移动 Web 浏览器上可能会耗尽内存。

在为可增长 SharedArrayBuffer 选择 "maxByteLength" 选项的值时,我们建议选择应用所需的尽可能小的大小。我们建议 "maxByteLength" 不超过 1073741824,即 1GiB。

请注意,成功构造具有特定最大大小的可增长 SharedArrayBuffer,并不保证未来增长会成功。

并非所有对可增长 SharedArrayBuffer 长度的加载都是同步性的 seq-cst 加载。用于整数索引属性访问(例如 u8[idx])边界检查的长度加载不是同步性的。通常,在没有显式同步的情况下,一个属性访问在边界内并不意味着同一 agent 中后续属性访问也在边界内。相比之下,通过 SharedArrayBuffer、%TypedArray%.prototype 和 DataView.prototype 上的 lengthbyteLength getter 对长度进行的显式加载是同步性的。由内置方法为检查 TypedArray 是否整体越界而执行的长度加载也是同步性的。

Note 2

以下是面向实现可增长 SharedArrayBuffer 的 ECMAScript 实现者的指南。

我们建议将可增长 SharedArrayBuffer 实现为通过预先保留虚拟内存进行原地增长。

由于增长操作可以与可增长 SharedArrayBuffer 上的内存访问并行发生,内存模型的约束要求即使无序访问也不会“撕裂”(其值的位不会混合)。实践中,这意味着可增长 SharedArrayBuffer 的底层数据块不能通过复制来增长,除非停止整个世界。我们不建议将停止整个世界作为实现策略,因为它会引入一个序列化点并且很慢。

增长后的内存必须从其创建的那一刻起表现为零填充,包括对于并行的任何竞态访问也是如此。这可以通过按需零填充的虚拟内存页实现,或者在手动清零内存时通过谨慎同步来实现。

可增长 SharedArrayBufferTypedArray 视图进行整数索引属性访问,意图可类似于对不可增长 SharedArrayBufferTypedArray 视图的访问一样进行优化,因为整数索引属性加载并不同步底层缓冲区的长度(见上面的程序员指南)。例如,属性访问的边界检查仍然可以被提升到循环之外。

实践中,在没有虚拟内存的宿主(例如运行在没有 MMU 的嵌入式设备)上,很难通过复制实现可增长 SharedArrayBuffer。这类宿主可增长 SharedArrayBuffer 的内存使用行为可能与具有虚拟内存的宿主有显著差异。这类宿主应向用户清楚传达内存使用预期。

25.3 DataView 对象

25.3.1 DataView 对象的抽象操作

25.3.1.1 DataView With Buffer Witness Record

DataView With Buffer Witness Record 是一种 Record 值,用于封装 DataView 以及被查看缓冲区的缓存字节长度。当被查看缓冲区是可增长 SharedArrayBuffer 时,它用于帮助确保字节长度数据块只有单个 ReadSharedMemory 事件。

DataView With Buffer Witness Record 具有 Table 73 中列出的字段。

Table 73: DataView With Buffer Witness Record 字段
字段名 含义
[[Object]] a DataView 加载其缓冲区字节长度的 DataView 对象。
[[CachedBufferByteLength]] a non-negative integer or detached 创建该 Record 时对象的 [[ViewedArrayBuffer]] 的字节长度。

25.3.1.2 MakeDataViewWithBufferWitnessRecord ( obj, order )

The abstract operation MakeDataViewWithBufferWitnessRecord takes arguments obj (a DataView) and order (seq-cst or unordered) and returns a DataView With Buffer Witness Record. It performs the following steps when called:

  1. bufferobj.[[ViewedArrayBuffer]]
  2. 如果 IsDetachedBuffer(buffer) 是 true,则
    1. byteLengthdetached
  3. 否则,
    1. byteLengthArrayBufferByteLength(buffer, order)。
  4. 返回 DataView With Buffer Witness Record { [[Object]]: obj, [[CachedBufferByteLength]]: byteLength }。

25.3.1.3 GetViewByteLength ( viewRecord )

The abstract operation GetViewByteLength takes argument viewRecord (a DataView With Buffer Witness Record) and returns a non-negative integer. It performs the following steps when called:

  1. 断言:IsViewOutOfBounds(viewRecord) 是 false
  2. viewviewRecord.[[Object]]
  3. 如果 view.[[ByteLength]] 不是 auto,则返回 view.[[ByteLength]]
  4. 断言:IsFixedLengthArrayBuffer(view.[[ViewedArrayBuffer]]) 是 false
  5. byteOffsetview.[[ByteOffset]]
  6. byteLengthviewRecord.[[CachedBufferByteLength]]
  7. 断言:byteLength 不是 detached
  8. 返回 byteLength - byteOffset

25.3.1.4 IsViewOutOfBounds ( viewRecord )

The abstract operation IsViewOutOfBounds takes argument viewRecord (a DataView With Buffer Witness Record) and returns a Boolean. It performs the following steps when called:

  1. viewviewRecord.[[Object]]
  2. bufferByteLengthviewRecord.[[CachedBufferByteLength]]
  3. 如果 IsDetachedBuffer(view.[[ViewedArrayBuffer]]) 是 true,则
    1. 断言:bufferByteLengthdetached
    2. 返回 true
  4. 断言:bufferByteLength 是非负整数。
  5. byteOffsetStartview.[[ByteOffset]]
  6. 如果 view.[[ByteLength]]auto,则
    1. byteOffsetEndbufferByteLength
  7. 否则,
    1. byteOffsetEndbyteOffsetStart + view.[[ByteLength]]
  8. 注:[[ByteOffset]]bufferByteLength 的 0 长度 DataView 不被视为越界。
  9. 如果 byteOffsetStart > bufferByteLengthbyteOffsetEnd > bufferByteLength,则返回 true
  10. 返回 false

25.3.1.5 GetViewValue ( view, requestIndex, isLittleEndian, type )

The abstract operation GetViewValue takes arguments view (an ECMAScript language value), requestIndex (an ECMAScript language value), isLittleEndian (an ECMAScript language value), and type (a TypedArray element type) and returns either a normal completion containing either a Number or a BigInt, or a throw completion. 它由 DataView 实例上的函数用于从视图的缓冲区中检索值。 It performs the following steps when called:

  1. 执行 ? RequireInternalSlot(view, [[DataView]])。
  2. 断言:view 具有 [[ViewedArrayBuffer]] 内部槽。
  3. getIndex 为 ? ToIndex(requestIndex)。
  4. isLittleEndian 设置为 ToBoolean(isLittleEndian)。
  5. viewOffsetview.[[ByteOffset]]
  6. viewRecordMakeDataViewWithBufferWitnessRecord(view, unordered)。
  7. 注:当 view 的后备缓冲区是可增长 SharedArrayBuffer 时,边界检查不是同步操作。
  8. 如果 IsViewOutOfBounds(viewRecord) 是 true,则抛出 TypeError 异常。
  9. viewSizeGetViewByteLength(viewRecord)。
  10. elementSizeTable 71 中为 Element Type type 指定的 Element Size 值。
  11. 如果 getIndex + elementSize > viewSize,则抛出 RangeError 异常。
  12. bufferIndexgetIndex + viewOffset
  13. 返回 GetValueFromBuffer(view.[[ViewedArrayBuffer]], bufferIndex, type, false, unordered, isLittleEndian)。

25.3.1.6 SetViewValue ( view, requestIndex, isLittleEndian, type, value )

The abstract operation SetViewValue takes arguments view (an ECMAScript language value), requestIndex (an ECMAScript language value), isLittleEndian (an ECMAScript language value), type (a TypedArray element type), and value (an ECMAScript language value) and returns either a normal completion containing undefined or a throw completion. 它由 DataView 实例上的函数用于将值存储到视图的缓冲区中。 It performs the following steps when called:

  1. 执行 ? RequireInternalSlot(view, [[DataView]])。
  2. 断言:view 具有 [[ViewedArrayBuffer]] 内部槽。
  3. getIndex 为 ? ToIndex(requestIndex)。
  4. 如果 IsBigIntElementType(type) 是 true,则令 number 为 ? ToBigInt(value)。
  5. 否则,令 number 为 ? ToNumber(value)。
  6. isLittleEndian 设置为 ToBoolean(isLittleEndian)。
  7. viewOffsetview.[[ByteOffset]]
  8. viewRecordMakeDataViewWithBufferWitnessRecord(view, unordered)。
  9. 注:当 view 的后备缓冲区是可增长 SharedArrayBuffer 时,边界检查不是同步操作。
  10. 如果 IsViewOutOfBounds(viewRecord) 是 true,则抛出 TypeError 异常。
  11. viewSizeGetViewByteLength(viewRecord)。
  12. elementSizeTable 71 中为 Element Type type 指定的 Element Size 值。
  13. 如果 getIndex + elementSize > viewSize,则抛出 RangeError 异常。
  14. bufferIndexgetIndex + viewOffset
  15. 执行 SetValueInBuffer(view.[[ViewedArrayBuffer]], bufferIndex, type, number, false, unordered, isLittleEndian)。
  16. 返回 undefined

25.3.2 DataView 构造器

DataView 构造器:

  • %DataView%
  • 全局对象"DataView" 属性的初始值。
  • 在作为构造器调用时创建并初始化一个新的 DataView。
  • 不意图作为函数调用,并且以这种方式调用时会抛出异常。
  • 可以用作类定义的 extends 子句的值。打算继承指定 DataView 行为的子类构造函数,必须包含一次对 DataView 构造函数super 调用,以创建并初始化子类实例,使其具备支持 DataView.prototype 的内置方法所必需的内部状态。

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

此函数在被调用时执行以下步骤:

  1. 如果 NewTarget 是 undefined,则抛出 TypeError 异常。
  2. 执行 ? RequireInternalSlot(buffer, [[ArrayBufferData]])。
  3. offset 为 ? ToIndex(byteOffset)。
  4. 如果 IsDetachedBuffer(buffer) 是 true,则抛出 TypeError 异常。
  5. bufferByteLengthArrayBufferByteLength(buffer, seq-cst)。
  6. 如果 offset > bufferByteLength,则抛出 RangeError 异常。
  7. bufferIsFixedLengthIsFixedLengthArrayBuffer(buffer)。
  8. 如果 byteLengthundefined,则
    1. 如果 bufferIsFixedLengthtrue,则
      1. viewByteLengthbufferByteLength - offset
    2. 否则,
      1. viewByteLengthauto
  9. 否则,
    1. viewByteLength 为 ? ToIndex(byteLength)。
    2. 如果 offset + viewByteLength > bufferByteLength,则抛出 RangeError 异常。
  10. obj 为 ? OrdinaryCreateFromConstructor(NewTarget, "%DataView.prototype%", « [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]] »)。
  11. 如果 IsDetachedBuffer(buffer) 是 true,则抛出 TypeError 异常。
  12. bufferByteLength 设置为 ArrayBufferByteLength(buffer, seq-cst)。
  13. 如果 offset > bufferByteLength,则抛出 RangeError 异常。
  14. 如果 byteLength 不是 undefined,则
    1. 如果 offset + viewByteLength > bufferByteLength,则抛出 RangeError 异常。
  15. obj.[[ViewedArrayBuffer]] 设置为 buffer
  16. obj.[[ByteLength]] 设置为 viewByteLength
  17. obj.[[ByteOffset]] 设置为 offset
  18. 返回 obj

25.3.3 DataView 构造器的属性

DataView 构造器:

25.3.3.1 DataView.prototype

DataView.prototype 的初始值是 DataView 原型对象

此属性具有特性 { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }。

25.3.4 DataView 原型对象的属性

DataView 原型对象

  • %DataView.prototype%
  • 具有一个 [[Prototype]] 内部槽,其值为 %Object.prototype%
  • 普通对象
  • 没有 [[DataView]][[ViewedArrayBuffer]][[ByteLength]][[ByteOffset]] 内部槽。

25.3.4.1 get DataView.prototype.buffer

DataView.prototype.buffer访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[DataView]])。
  3. 断言:obj 具有 [[ViewedArrayBuffer]] 内部槽。
  4. bufferobj.[[ViewedArrayBuffer]]
  5. 返回 buffer

25.3.4.2 get DataView.prototype.byteLength

DataView.prototype.byteLength访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[DataView]])。
  3. 断言:obj 具有 [[ViewedArrayBuffer]] 内部槽。
  4. viewRecordMakeDataViewWithBufferWitnessRecord(obj, seq-cst)。
  5. 如果 IsViewOutOfBounds(viewRecord) 是 true,则抛出 TypeError 异常。
  6. sizeGetViewByteLength(viewRecord)。
  7. 返回 𝔽(size)。

25.3.4.3 get DataView.prototype.byteOffset

DataView.prototype.byteOffset访问器属性,其 set 访问器函数是 undefined。其 get 访问器函数在被调用时执行以下步骤:

  1. objthis 值。
  2. 执行 ? RequireInternalSlot(obj, [[DataView]])。
  3. 断言:obj 具有 [[ViewedArrayBuffer]] 内部槽。
  4. viewRecordMakeDataViewWithBufferWitnessRecord(obj, seq-cst)。
  5. 如果 IsViewOutOfBounds(viewRecord) 是 true,则抛出 TypeError 异常。
  6. offsetobj.[[ByteOffset]]
  7. 返回 𝔽(offset)。

25.3.4.4 DataView.prototype.constructor

DataView.prototype.constructor 的初始值是 %DataView%

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 返回 ? GetViewValue(view, byteOffset, littleEndian, bigint64)。

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 返回 ? GetViewValue(view, byteOffset, littleEndian, biguint64)。

25.3.4.7 DataView.prototype.getFloat16 ( byteOffset [ , littleEndian ] )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? GetViewValue(view, byteOffset, littleEndian, float16)。

25.3.4.8 DataView.prototype.getFloat32 ( byteOffset [ , littleEndian ] )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? GetViewValue(view, byteOffset, littleEndian, float32)。

25.3.4.9 DataView.prototype.getFloat64 ( byteOffset [ , littleEndian ] )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? GetViewValue(view, byteOffset, littleEndian, float64)。

25.3.4.10 DataView.prototype.getInt8 ( byteOffset )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 返回 ? GetViewValue(view, byteOffset, true, int8)。

25.3.4.11 DataView.prototype.getInt16 ( byteOffset [ , littleEndian ] )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? GetViewValue(view, byteOffset, littleEndian, int16)。

25.3.4.12 DataView.prototype.getInt32 ( byteOffset [ , littleEndian ] )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? GetViewValue(view, byteOffset, littleEndian, int32)。

25.3.4.13 DataView.prototype.getUint8 ( byteOffset )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 返回 ? GetViewValue(view, byteOffset, true, uint8)。

25.3.4.14 DataView.prototype.getUint16 ( byteOffset [ , littleEndian ] )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? GetViewValue(view, byteOffset, littleEndian, uint16)。

25.3.4.15 DataView.prototype.getUint32 ( byteOffset [ , littleEndian ] )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? GetViewValue(view, byteOffset, littleEndian, uint32)。

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 返回 ? SetViewValue(view, byteOffset, littleEndian, bigint64, value)。

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 返回 ? SetViewValue(view, byteOffset, littleEndian, biguint64, value)。

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? SetViewValue(view, byteOffset, littleEndian, float16, value)。

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? SetViewValue(view, byteOffset, littleEndian, float32, value)。

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? SetViewValue(view, byteOffset, littleEndian, float64, value)。

25.3.4.21 DataView.prototype.setInt8 ( byteOffset, value )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 返回 ? SetViewValue(view, byteOffset, true, int8, value)。

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? SetViewValue(view, byteOffset, littleEndian, int16, value)。

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? SetViewValue(view, byteOffset, littleEndian, int32, value)。

25.3.4.24 DataView.prototype.setUint8 ( byteOffset, value )

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 返回 ? SetViewValue(view, byteOffset, true, uint8, value)。

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? SetViewValue(view, byteOffset, littleEndian, uint16, value)。

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

此方法在被调用时执行以下步骤:

  1. viewthis 值。
  2. 如果 littleEndian 不存在,则将 littleEndian 设置为 false
  3. 返回 ? SetViewValue(view, byteOffset, littleEndian, uint32, value)。

25.3.4.27 DataView.prototype [ %Symbol.toStringTag% ]

%Symbol.toStringTag% 属性的初始值是 String 值 "DataView"

此属性具有特性 { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }。

25.3.5 DataView 实例的属性

DataView 实例是普通对象,继承自 DataView 原型对象的属性。每个 DataView 实例都有 [[DataView]][[ViewedArrayBuffer]][[ByteLength]][[ByteOffset]] 内部槽。

Note

[[DataView]] 内部槽的值在本规范中不被使用。该内部槽的单纯存在用于在规范中识别使用 DataView 构造器创建的对象。

25.4 Atomics 对象

Atomics 对象:

  • %Atomics%
  • 全局对象"Atomics" 属性的初始值。
  • 普通对象
  • 具有一个 [[Prototype]] 内部槽,其值为 %Object.prototype%
  • 没有 [[Construct]] 内部方法;它不能作为构造器与 new 操作符一起使用。
  • 没有 [[Call]] 内部方法;它不能作为函数调用。

Atomics 对象提供在共享内存数组单元上不可分割地(原子地)操作的函数,以及让 agent 等待并派发原始事件的函数。当以有纪律的方式使用时,Atomics 函数允许通过共享内存通信的多 agent 程序,即使在并行 CPU 上也能以良好理解的顺序执行。管理共享内存通信的规则由下文定义的内存模型提供。

Note

有关在 ECMAScript 中编程和实现共享内存的信息性指南,请参阅内存模型章节末尾的注。

25.4.1 Waiter Record

Waiter Record 是一种 Record 值,用于表示对 Atomics.waitAtomics.waitAsync 的某次特定调用。

Waiter Record 具有 Table 74 中列出的字段。

Table 74: Waiter Record 字段
字段名 含义
[[AgentSignifier]] an agent signifier 调用了 Atomics.waitAtomics.waitAsyncagent
[[PromiseCapability]] a PromiseCapability Record or blocking 如果表示对 Atomics.waitAsync 的调用,则为所得的 promise,否则为 blocking
[[TimeoutTime]] a non-negative extended mathematical value 可以触发超时的最早时间;使用时间值计算。
[[Result]] "ok" or "timed-out" 调用的返回值。

25.4.2 WaiterList Record

WaiterList Record 用于解释通过 Atomics.waitAtomics.waitAsyncAtomics.notifyagent 的等待和通知。

WaiterList Record 具有 Table 75 中列出的字段。

Table 75: WaiterList Record 字段
字段名 含义
[[Waiters]] a List of Waiter Records 在与此 WaiterList 关联的位置上等待的 Atomics.waitAtomics.waitAsync 调用。
[[MostRecentLeaveEvent]] a Synchronize event or empty 最近一次离开其临界区的事件,或者如果其临界区从未进入过,则为 empty

WaiterList 中可以有多个具有相同 agent signifierWaiter Record

agent cluster 具有一个 WaiterList Record 存储;该存储由 (block, i) 索引,其中 blockShared Data Blockiblock 内存中的字节偏移量。WaiterList Record 与 agent 无关:在 agent cluster 中的任何 agent 内,用 (block, i) 在 WaiterList Record 存储中查找,都会得到同一个 WaiterList Record。

每个 WaiterList Record 都有一个临界区,用于在求值期间控制对该 WaiterList Record 的独占访问。同一时间只能有一个 agent 进入 WaiterList Record 的临界区。进入和离开 WaiterList Record 的临界区由抽象操作 EnterCriticalSectionLeaveCriticalSection 控制。对 WaiterList Record 的操作——添加和移除等待中的 agent、遍历 agent 列表、挂起和通知列表上的 agent、设置和检索 Synchronize 事件——只能由已进入该 WaiterList Record 临界区的 agent 执行。

25.4.3 Atomics 的抽象操作

25.4.3.1 ValidateIntegerTypedArray ( ta, waitable )

The abstract operation ValidateIntegerTypedArray takes arguments ta (an ECMAScript language value) and waitable (a Boolean) and returns either a normal completion containing a TypedArray With Buffer Witness Record, or a throw completion. It performs the following steps when called:

  1. taRecord 为 ? ValidateTypedArray(ta, unordered)。
  2. 注:当 ta 的后备缓冲区是可增长 SharedArrayBuffer 时,边界检查不是同步操作。
  3. 如果 waitabletrue,则
    1. 如果 ta.[[TypedArrayName]] 既不是 "Int32Array" 也不是 "BigInt64Array",则抛出 TypeError 异常。
  4. 否则,
    1. typeTypedArrayElementType(ta)。
    2. 如果 IsUnclampedIntegerElementType(type) 是 falseIsBigIntElementType(type) 是 false,则抛出 TypeError 异常。
  5. 返回 taRecord

25.4.3.2 ValidateAtomicAccess ( taRecord, requestIndex )

The abstract operation ValidateAtomicAccess takes arguments taRecord (a TypedArray With Buffer Witness Record) and requestIndex (an ECMAScript language value) and returns either a normal completion containing a non-negative integer or a throw completion. It performs the following steps when called:

  1. lengthTypedArrayLength(taRecord)。
  2. accessIndex 为 ? ToIndex(requestIndex)。
  3. 断言:accessIndex ≥ 0。
  4. 如果 accessIndexlength,则抛出 RangeError 异常。
  5. tataRecord.[[Object]]
  6. elementSizeTypedArrayElementSize(ta)。
  7. offsetta.[[ByteOffset]]
  8. 返回 (accessIndex × elementSize) + offset

25.4.3.3 ValidateAtomicAccessOnIntegerTypedArray ( ta, requestIndex )

The abstract operation ValidateAtomicAccessOnIntegerTypedArray takes arguments ta (an ECMAScript language value) and requestIndex (an ECMAScript language value) and returns either a normal completion containing a non-negative integer or a throw completion. It performs the following steps when called:

  1. taRecord 为 ? ValidateIntegerTypedArray(ta, false)。
  2. 返回 ? ValidateAtomicAccess(taRecord, requestIndex)。

25.4.3.4 RevalidateAtomicAccess ( ta, byteIndexInBuffer )

The abstract operation RevalidateAtomicAccess takes arguments ta (a TypedArray) and byteIndexInBuffer (a non-negative integer) and returns either a normal completion containing unused or a throw completion. 此操作在 Atomics 方法中所有实参强制转换执行之后,重新验证原子操作在后备缓冲区中的索引,因为实参强制转换可能具有任意副作用,可能导致缓冲区越界。当 ta 的后备缓冲区是 SharedArrayBuffer 时,此操作不会抛出异常。 It performs the following steps when called:

  1. taRecordMakeTypedArrayWithBufferWitnessRecord(ta, unordered)。
  2. 注:当 ta 的后备缓冲区是可增长 SharedArrayBuffer 时,边界检查不是同步操作。
  3. 如果 IsTypedArrayOutOfBounds(taRecord) 是 true,则抛出 TypeError 异常。
  4. 断言:byteIndexInBufferta.[[ByteOffset]]
  5. 如果 byteIndexInBuffertaRecord.[[CachedBufferByteLength]],则抛出 RangeError 异常。
  6. 返回 unused

25.4.3.5 GetWaiterList ( block, i )

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

  1. 断言:ii + 3 是 block 内存内的有效字节偏移量。
  2. 返回由对 (block, i) 引用的 WaiterList Record

25.4.3.6 EnterCriticalSection ( waiterList )

The abstract operation EnterCriticalSection takes argument waiterList (a WaiterList Record) and returns unused. It performs the following steps when called:

  1. 断言:surrounding agent 不在任何 WaiterList Record临界区中。
  2. 等待直到没有 agent 位于 waiterList临界区中,然后进入 waiterList临界区(不允许任何其他 agent 进入)。
  3. 如果 waiterList.[[MostRecentLeaveEvent]] 不是 empty,则
    1. 注:至少进入过一次临界区waiterList 具有由 LeaveCriticalSection 设置的 Synchronize 事件。
    2. agentRecord 为 surrounding agentAgent Record
    3. executionagentRecord.[[CandidateExecution]]
    4. eventsRecordexecution.[[EventsRecords]][[AgentSignifier]]AgentSignifier() 的 Agent Events Record
    5. enterEvent 为新的 Synchronize 事件。
    6. enterEvent 追加到 eventsRecord.[[EventList]]
    7. 将 (waiterList.[[MostRecentLeaveEvent]], enterEvent) 追加到 eventsRecord.[[AgentSynchronizesWith]]
  4. 返回 unused

当试图进入临界区agent 必须等待另一个 agent 离开时,EnterCriticalSection 存在争用。当没有争用时,EnterCriticalSection 调用的 FIFO 顺序是可观察的。当存在争用时,实现可以选择任意顺序,但不得导致某个 agent 无限期等待。

25.4.3.7 LeaveCriticalSection ( waiterList )

The abstract operation LeaveCriticalSection takes argument waiterList (a WaiterList Record) and returns unused. It performs the following steps when called:

  1. 断言:surrounding agent 位于 waiterList临界区中。
  2. agentRecord 为 surrounding agentAgent Record
  3. executionagentRecord.[[CandidateExecution]]
  4. eventsRecordexecution.[[EventsRecords]][[AgentSignifier]]AgentSignifier() 的 Agent Events Record
  5. leaveEvent 为新的 Synchronize 事件。
  6. leaveEvent 追加到 eventsRecord.[[EventList]]
  7. waiterList.[[MostRecentLeaveEvent]] 设置为 leaveEvent
  8. 离开 waiterList临界区
  9. 返回 unused

25.4.3.8 AddWaiter ( waiterList, waiterRecord )

The abstract operation AddWaiter takes arguments waiterList (a WaiterList Record) and waiterRecord (a Waiter Record) and returns unused. It performs the following steps when called:

  1. 断言:surrounding agent 位于 waiterList临界区中。
  2. 断言:waiterList.[[Waiters]] 中不存在 [[PromiseCapability]] 字段为 waiterRecord.[[PromiseCapability]][[AgentSignifier]] 字段为 waiterRecord.[[AgentSignifier]]Waiter Record
  3. waiterRecord 追加到 waiterList.[[Waiters]]
  4. 返回 unused

25.4.3.9 RemoveWaiter ( waiterList, waiterRecord )

The abstract operation RemoveWaiter takes arguments waiterList (a WaiterList Record) and waiterRecord (a Waiter Record) and returns unused. It performs the following steps when called:

  1. 断言:surrounding agent 位于 waiterList临界区中。
  2. 断言:waiterList.[[Waiters]] 包含 waiterRecord
  3. waiterList.[[Waiters]] 中移除 waiterRecord
  4. 返回 unused

25.4.3.10 RemoveWaiters ( waiterList, count )

The abstract operation RemoveWaiters takes arguments waiterList (a WaiterList Record) and count (a non-negative integer or +∞) and returns a List of Waiter Records. It performs the following steps when called:

  1. 断言:surrounding agent 位于 waiterList临界区中。
  2. lengthwaiterList.[[Waiters]] 中元素的数量。
  3. count 设置为 min(count, length)。
  4. waiters 为一个 List,其元素为 waiterList.[[Waiters]] 的前 count 个元素。
  5. 移除 waiterList.[[Waiters]] 的前 count 个元素。
  6. 返回 waiters

25.4.3.11 SuspendThisAgent ( waiterList, waiterRecord )

The abstract operation SuspendThisAgent takes arguments waiterList (a WaiterList Record) and waiterRecord (a Waiter Record) and returns unused. It performs the following steps when called:

  1. 断言:surrounding agent 位于 waiterList临界区中。
  2. 断言:waiterList.[[Waiters]] 包含 waiterRecord
  3. thisAgentAgentSignifier()。
  4. 断言:waiterRecord.[[AgentSignifier]]thisAgent
  5. 断言:waiterRecord.[[PromiseCapability]]blocking
  6. 断言:AgentCanSuspend() 是 true
  7. 执行 LeaveCriticalSection(waiterList) 并挂起 surrounding agent,直到时间为 waiterRecord.[[TimeoutTime]],以一种组合操作的方式执行,使得在退出临界区之后但在挂起生效之前到达的通知不会丢失。surrounding agent 只能因超时或因另一个 agentwaiterListthisAgent 为实参调用 NotifyWaiter(即通过调用 Atomics.notify)而从挂起中唤醒。
  8. 执行 EnterCriticalSection(waiterList)。
  9. 返回 unused

25.4.3.12 NotifyWaiter ( waiterList, waiterRecord )

The abstract operation NotifyWaiter takes arguments waiterList (a WaiterList Record) and waiterRecord (a Waiter Record) and returns unused. It performs the following steps when called:

  1. 断言:surrounding agent 位于 waiterList临界区中。
  2. 如果 waiterRecord.[[PromiseCapability]]blocking,则
    1. 将 signifier 为 waiterRecord.[[AgentSignifier]]agent 从挂起中唤醒。
    2. 注:这会使 agentSuspendThisAgent 中恢复执行。
  3. 否则,如果 AgentSignifier() 是 waiterRecord.[[AgentSignifier]],则
    1. promiseCapabilitywaiterRecord.[[PromiseCapability]]
    2. 执行 ! Call(promiseCapability.[[Resolve]], undefined, « waiterRecord.[[Result]] »)。
  4. 否则,
    1. 执行 EnqueueResolveInAgentJob(waiterRecord.[[AgentSignifier]], waiterRecord.[[PromiseCapability]], waiterRecord.[[Result]])。
  5. 返回 unused
Note

agent 不得以任何能力访问另一个 agent 的 promise capability,除非是将其传递给宿主

25.4.3.13 EnqueueResolveInAgentJob ( agentSignifier, promiseCapability, resolution )

The abstract operation EnqueueResolveInAgentJob takes arguments agentSignifier (an agent signifier), promiseCapability (a PromiseCapability Record), and resolution ("ok" or "timed-out") and returns unused. It performs the following steps when called:

  1. resolveJob 为一个新的无参数 Job Abstract Closure,它捕获 agentSignifierpromiseCapabilityresolution,并在被调用时执行以下步骤:
    1. 断言:AgentSignifier() 是 agentSignifier
    2. 执行 ! Call(promiseCapability.[[Resolve]], undefined, « resolution »)。
    3. 返回 unused
  2. realmInTargetAgent 为 ! GetFunctionRealm(promiseCapability.[[Resolve]])。
  3. 断言:agentSignifierrealmInTargetAgent.[[AgentSignifier]]
  4. 执行 HostEnqueueGenericJob(resolveJob, realmInTargetAgent)。
  5. 返回 unused

25.4.3.14 DoWait ( mode, ta, index, value, timeout )

The abstract operation DoWait takes arguments mode (sync or async), ta (an ECMAScript language value), index (an ECMAScript language value), value (an ECMAScript language value), and timeout (an ECMAScript language value) and returns either a normal completion containing either an Object, "not-equal", "timed-out", or "ok", or a throw completion. It performs the following steps when called:

  1. taRecord 为 ? ValidateIntegerTypedArray(ta, true)。
  2. buffertaRecord.[[Object]].[[ViewedArrayBuffer]]
  3. 如果 IsSharedArrayBuffer(buffer) 是 false,则抛出 TypeError 异常。
  4. byteIndexInBuffer 为 ? ValidateAtomicAccess(taRecord, index)。
  5. arrayTypeNameta.[[TypedArrayName]]
  6. 如果 arrayTypeName"BigInt64Array",则令 expected 为 ? ToBigInt64(value)。
  7. 否则,令 expected 为 ? ToInt32(value)。
  8. timeoutNumber 为 ? ToNumber(timeout)。
  9. 如果 timeoutNumberNaN+∞𝔽,则令 realTimeout 为 +∞。
  10. 否则,如果 timeoutNumber-∞𝔽,则令 realTimeout 为 0。
  11. 否则,令 realTimeoutmax((timeoutNumber), 0)。
  12. 如果 modesyncAgentCanSuspend() 是 false,则抛出 TypeError 异常。
  13. blockbuffer.[[ArrayBufferData]]
  14. waiterListGetWaiterList(block, byteIndexInBuffer)。
  15. 如果 modesync,则
    1. promiseCapabilityblocking
    2. resultObjundefined
  16. 否则,
    1. promiseCapability 为 ! NewPromiseCapability(%Promise%)。
    2. resultObjOrdinaryObjectCreate(%Object.prototype%)。
  17. 执行 EnterCriticalSection(waiterList)。
  18. elementTypeTypedArrayElementType(ta)。
  19. witnessGetValueFromBuffer(buffer, byteIndexInBuffer, elementType, true, seq-cst)。
  20. 如果 expectedwitness,则
    1. 执行 LeaveCriticalSection(waiterList)。
    2. 如果 modesync,则返回 "not-equal"
    3. 执行 ! CreateDataPropertyOrThrow(resultObj, "async", false)。
    4. 执行 ! CreateDataPropertyOrThrow(resultObj, "value", "not-equal")。
    5. 返回 resultObj
  21. 如果 realTimeout = 0 且 modeasync,则
    1. 注:同步的立即超时没有特殊处理。异步的立即超时具有特殊处理,以便快速失败并避免不必要的 Promise job。
    2. 执行 LeaveCriticalSection(waiterList)。
    3. 执行 ! CreateDataPropertyOrThrow(resultObj, "async", false)。
    4. 执行 ! CreateDataPropertyOrThrow(resultObj, "value", "timed-out")。
    5. 返回 resultObj
  22. thisAgentAgentSignifier()。
  23. now 为标识当前时间的时间值(UTC)。
  24. additionalTimeout实现定义的非负数学值
  25. timeoutTime(now) + realTimeout + additionalTimeout
  26. 注:当 realTimeout 是 +∞ 时,timeoutTime 也是 +∞。
  27. waiterRecord 为新的 Waiter Record { [[AgentSignifier]]: thisAgent, [[PromiseCapability]]: promiseCapability, [[TimeoutTime]]: timeoutTime, [[Result]]: "ok" }。
  28. 执行 AddWaiter(waiterList, waiterRecord)。
  29. 如果 modesync,则
    1. 执行 SuspendThisAgent(waiterList, waiterRecord)。
  30. 否则,如果 timeoutTime有限的,则
    1. 执行 EnqueueAtomicsWaitAsyncTimeoutJob(waiterList, waiterRecord)。
  31. 执行 LeaveCriticalSection(waiterList)。
  32. 如果 modesync,则返回 waiterRecord.[[Result]]
  33. 执行 ! CreateDataPropertyOrThrow(resultObj, "async", true)。
  34. 执行 ! CreateDataPropertyOrThrow(resultObj, "value", promiseCapability.[[Promise]])。
  35. 返回 resultObj
Note

additionalTimeout 允许实现根据需要填充超时,例如为了降低功耗或粗化计时器分辨率以缓解定时攻击。此值在不同 DoWait 调用之间可以不同。

25.4.3.15 EnqueueAtomicsWaitAsyncTimeoutJob ( waiterList, waiterRecord )

The abstract operation EnqueueAtomicsWaitAsyncTimeoutJob takes arguments waiterList (a WaiterList Record) and waiterRecord (a Waiter Record) and returns unused. It performs the following steps when called:

  1. timeoutJob 为一个新的无参数 Job Abstract Closure,它捕获 waiterListwaiterRecord,并在被调用时执行以下步骤:
    1. 执行 EnterCriticalSection(waiterList)。
    2. 如果 waiterList.[[Waiters]] 包含 waiterRecord,则
      1. timeOfJobExecution 为标识当前时间的时间值(UTC)。
      2. 断言:(timeOfJobExecution) ≥ waiterRecord.[[TimeoutTime]](忽略时间值的潜在非单调性)。
      3. waiterRecord.[[Result]] 设置为 "timed-out"
      4. 执行 RemoveWaiter(waiterList, waiterRecord)。
      5. 执行 NotifyWaiter(waiterList, waiterRecord)。
    3. 执行 LeaveCriticalSection(waiterList)。
    4. 返回 unused
  2. now 为标识当前时间的时间值(UTC)。
  3. currentRealm当前 Realm Record
  4. 执行 HostEnqueueTimeoutJob(timeoutJob, currentRealm, 𝔽(waiterRecord.[[TimeoutTime]]) - now)。
  5. 返回 unused

25.4.3.16 AtomicCompareExchangeInSharedBlock ( block, byteIndexInBuffer, elementSize, expectedBytes, replacementBytes )

The abstract operation AtomicCompareExchangeInSharedBlock takes arguments block (a Shared Data Block), byteIndexInBuffer (an integer), elementSize (a non-negative integer), expectedBytes (a List of byte values), and replacementBytes (a List of byte values) and returns a List of byte values. It performs the following steps when called:

  1. agentRecord 为 surrounding agentAgent Record
  2. executionagentRecord.[[CandidateExecution]]
  3. eventsRecordexecution.[[EventsRecords]][[AgentSignifier]]AgentSignifier() 的 Agent Events Record
  4. rawBytesRead 为长度为 elementSizeList,其元素为非确定性选择的字节值
  5. 注:在实现中,rawBytesRead 是底层硬件上的 load-link、load-exclusive,或读-改-写指令的一个操作数的结果。非确定性是内存模型的一项语义规定,用于描述弱一致性硬件的可观察行为。
  6. 注:期望值与读取值的比较在读-改-写修改函数之外执行,以避免在期望值不等于读取值时产生不必要的强同步。
  7. 如果 ByteListEqual(rawBytesRead, expectedBytes) 是 true,则
    1. second 为一个新的读-改-写修改函数,其参数为 (oldBytes, newBytes),不捕获任何内容,并在被调用时以原子方式执行以下步骤:
      1. 返回 newBytes
    2. eventReadModifyWriteSharedMemory { [[Order]]: seq-cst, [[NoTear]]: true, [[Block]]: block, [[ByteIndex]]: byteIndexInBuffer, [[ElementSize]]: elementSize, [[Payload]]: replacementBytes, [[ModifyOp]]: second }。
  8. 否则,
    1. eventReadSharedMemory { [[Order]]: seq-cst, [[NoTear]]: true, [[Block]]: block, [[ByteIndex]]: byteIndexInBuffer, [[ElementSize]]: elementSize }。
  9. event 追加到 eventsRecord.[[EventList]]
  10. Chosen Value Record { [[Event]]: event, [[ChosenValue]]: rawBytesRead } 追加到 execution.[[ChosenValues]]
  11. 返回 rawBytesRead

25.4.3.17 AtomicReadModifyWrite ( ta, index, value, op )

The abstract operation AtomicReadModifyWrite takes arguments ta (an ECMAScript language value), index (an ECMAScript language value), value (an ECMAScript language value), and op (a read-modify-write modification function) and returns either a normal completion containing either a Number or a BigInt, or a throw completion. op 接受两个字节值 List 实参并返回一个字节值 List。此操作以原子方式加载一个值,将其与另一个值组合,并存储该组合。它返回已加载的值。 It performs the following steps when called:

  1. byteIndexInBuffer 为 ? ValidateAtomicAccessOnIntegerTypedArray(ta, index)。
  2. 如果 ta.[[ContentType]]bigint,则令 coerced 为 ? ToBigInt(value)。
  3. 否则,令 coerced𝔽(? ToIntegerOrInfinity(value))。
  4. 执行 ? RevalidateAtomicAccess(ta, byteIndexInBuffer)。
  5. bufferta.[[ViewedArrayBuffer]]
  6. elementTypeTypedArrayElementType(ta)。
  7. 返回 GetModifySetValueInBuffer(buffer, byteIndexInBuffer, elementType, coerced, op)。

25.4.3.18 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) and returns a List of byte values. 该操作以原子方式对实参的所有字节值执行按位操作,并返回一个字节值 List。 It performs the following steps when called:

  1. 断言:xBytesyBytes 具有相同数量的元素。
  2. result 为新的空 List
  3. i 为 0。
  4. xBytes 的每个元素 xByte,执行:
    1. yByteyBytes[i]。
    2. 如果 op&,则
      1. resultByte 为对 xByteyByte 应用按位 AND 操作的结果。
    3. 否则,如果 op^,则
      1. resultByte 为对 xByteyByte 应用按位异或(XOR)操作的结果。
    4. 否则,
      1. 断言:op|
      2. resultByte 为对 xByteyByte 应用按位包含 OR 操作的结果。
    5. i 设置为 i + 1。
    6. resultByte 追加到 result
  5. 返回 result

25.4.3.19 ByteListEqual ( xBytes, yBytes )

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

  1. 如果 xBytesyBytes 没有相同数量的元素,则返回 false
  2. i 为 0。
  3. xBytes 的每个元素 xByte,执行:
    1. yByteyBytes[i]。
    2. 如果 xByteyByte,则返回 false
    3. i 设置为 i + 1。
  4. 返回 true

25.4.4 Atomics.add ( ta, index, value )

此函数在被调用时执行以下步骤:

  1. add 为一个新的读-改-写修改函数,其参数为 (xBytes, yBytes),捕获 ta,并在被调用时以原子方式执行以下步骤:
    1. typeTypedArrayElementType(ta)。
    2. agentRecord 为 surrounding agentAgent Record
    3. isLittleEndianagentRecord.[[LittleEndian]]
    4. xRawBytesToNumeric(type, xBytes, isLittleEndian)。
    5. yRawBytesToNumeric(type, yBytes, isLittleEndian)。
    6. 如果 x 是 Number,则
      1. sumNumber::add(x, y)。
    7. 否则,
      1. 断言:x 是 BigInt。
      2. sumBigInt::add(x, y)。
    8. sumBytesNumericToRawBytes(type, sum, isLittleEndian)。
    9. 断言:sumBytesxBytesyBytes 具有相同数量的元素。
    10. 返回 sumBytes
  2. 返回 ? AtomicReadModifyWrite(ta, index, value, add)。

25.4.5 Atomics.and ( ta, index, value )

此函数在被调用时执行以下步骤:

  1. and 为一个新的读-改-写修改函数,其参数为 (xBytes, yBytes),不捕获任何内容,并在被调用时以原子方式执行以下步骤:
    1. 返回 ByteListBitwiseOp(&, xBytes, yBytes)。
  2. 返回 ? AtomicReadModifyWrite(ta, index, value, and)。

25.4.6 Atomics.compareExchange ( ta, index, expectedValue, replacementValue )

此函数在被调用时执行以下步骤:

  1. byteIndexInBuffer 为 ? ValidateAtomicAccessOnIntegerTypedArray(ta, index)。
  2. bufferta.[[ViewedArrayBuffer]]
  3. blockbuffer.[[ArrayBufferData]]
  4. 如果 ta.[[ContentType]]bigint,则
    1. expected 为 ? ToBigInt(expectedValue)。
    2. replacement 为 ? ToBigInt(replacementValue)。
  5. 否则,
    1. expected𝔽(? ToIntegerOrInfinity(expectedValue))。
    2. replacement𝔽(? ToIntegerOrInfinity(replacementValue))。
  6. 执行 ? RevalidateAtomicAccess(ta, byteIndexInBuffer)。
  7. elementTypeTypedArrayElementType(ta)。
  8. elementSizeTypedArrayElementSize(ta)。
  9. agentRecord 为 surrounding agentAgent Record
  10. isLittleEndianagentRecord.[[LittleEndian]]
  11. expectedBytesNumericToRawBytes(elementType, expected, isLittleEndian)。
  12. replacementBytesNumericToRawBytes(elementType, replacement, isLittleEndian)。
  13. 如果 IsSharedArrayBuffer(buffer) 是 true,则
    1. rawBytesReadAtomicCompareExchangeInSharedBlock(block, byteIndexInBuffer, elementSize, expectedBytes, replacementBytes)。
  14. 否则,
    1. rawBytesRead 为长度为 elementSizeList,其元素是从 block[byteIndexInBuffer] 开始的 elementSize 个字节序列。
    2. 如果 ByteListEqual(rawBytesRead, expectedBytes) 是 true,则
      1. replacementBytes 的各个字节存储到 block 中,从 block[byteIndexInBuffer] 开始。
  15. 返回 RawBytesToNumeric(elementType, rawBytesRead, isLittleEndian)。

25.4.7 Atomics.exchange ( ta, index, value )

此函数在被调用时执行以下步骤:

  1. second 为一个新的读-改-写修改函数,其参数为 (oldBytes, newBytes),不捕获任何内容,并在被调用时以原子方式执行以下步骤:
    1. 返回 newBytes
  2. 返回 ? AtomicReadModifyWrite(ta, index, value, second)。

25.4.8 Atomics.isLockFree ( size )

此函数在被调用时执行以下步骤:

  1. n 为 ? ToIntegerOrInfinity(size)。
  2. agentRecord 为 surrounding agentAgent Record
  3. 如果 n = 1,则返回 agentRecord.[[IsLockFree1]]
  4. 如果 n = 2,则返回 agentRecord.[[IsLockFree2]]
  5. 如果 n = 4,则返回 true
  6. 如果 n = 8,则返回 agentRecord.[[IsLockFree8]]
  7. 返回 false
Note

此函数是一种优化原语。直觉是,如果原子原语(compareExchangeloadstoreaddsubandorxorexchange)在大小为 n 字节的数据上的原子步骤,会在 surrounding agent 不获取 n 个字节构成的数据之外的锁的情况下执行,那么 Atomics.isLockFree(n) 将返回 true。高性能算法会使用此函数来确定是在临界区中使用锁还是使用原子操作。如果某个原子原语不是无锁的,那么算法提供自己的锁通常更高效。

Atomics.isLockFree(4) 总是返回 true,因为这可以在所有已知相关硬件上得到支持。能够假定这一点通常会简化程序。

无论此函数返回的值如何,所有原子操作都保证是原子的。例如,它们绝不会有可见操作发生在该操作中间(例如,“tearing”)。

25.4.9 Atomics.load ( ta, index )

此函数在被调用时执行以下步骤:

  1. byteIndexInBuffer 为 ? ValidateAtomicAccessOnIntegerTypedArray(ta, index)。
  2. 执行 ? RevalidateAtomicAccess(ta, byteIndexInBuffer)。
  3. bufferta.[[ViewedArrayBuffer]]
  4. elementTypeTypedArrayElementType(ta)。
  5. 返回 GetValueFromBuffer(buffer, byteIndexInBuffer, elementType, true, seq-cst)。

25.4.10 Atomics.notify ( ta, index, count )

此函数会通知一些正在等待队列中休眠的代理。

调用时,它执行以下步骤:

  1. taRecord 为 ? ValidateIntegerTypedArray(ta, true)。
  2. byteIndexInBuffer 为 ? ValidateAtomicAccess(taRecord, index)。
  3. 如果 countundefined,则
    1. count 设置为 +∞。
  4. 否则,
    1. intCount 为 ? ToIntegerOrInfinity(count)。
    2. count 设置为 max(intCount, 0)。
  5. bufferta.[[ViewedArrayBuffer]]
  6. blockbuffer.[[ArrayBufferData]]
  7. 如果 IsSharedArrayBuffer(buffer) 为 false,则返回 +0𝔽
  8. waiterListGetWaiterList(block, byteIndexInBuffer)。
  9. 执行 EnterCriticalSection(waiterList)。
  10. waitersRemoveWaiters(waiterList, count)。
  11. waiters 的每个元素 waiterRecord,执行
    1. 执行 NotifyWaiter(waiterList, waiterRecord)。
  12. 执行 LeaveCriticalSection(waiterList)。
  13. waitersCountwaiters 中元素的数量。
  14. 返回 𝔽(waitersCount)。

25.4.11 Atomics.or ( ta, index, value )

此函数在调用时执行以下步骤:

  1. or 为一个新的读-修改-写修改函数,它具有参数 (xBytes, yBytes),不捕获任何内容,并在被调用时原子地执行以下步骤:
    1. 返回 ByteListBitwiseOp(|, xBytes, yBytes)。
  2. 返回 ? AtomicReadModifyWrite(ta, index, value, or)。

25.4.12 Atomics.pause ( )

此函数向 CPU 提供一个提示,表明程序正在等待某个值时进行自旋循环。

调用时,它执行以下步骤:

  1. 如果 ECMAScript 实现的执行环境支持向操作系统或 CPU 发出当前正在执行的代码处于自旋等待循环中的信号,则发送该信号。
  2. 返回 undefined
Note 1

此方法是为实现自旋等待循环的程序设计的,例如互斥锁内部的自旋锁快速路径,用于向 CPU 提供一个提示,表明它正在等待某个值时自旋。除计时外,它没有可观察的行为。

如果底层架构的最佳实践建议在自旋循环中使用 pause 或 yield 指令,则期望实现实现这样的指令。例如,Intel 优化手册建议使用 pause 指令。

鼓励实现对暂停的最长时间设置内部上限,其量级为数十到数百纳秒。

Note 2

由于函数调用的开销,在优化编译器中对此方法的内联调用等待的时间与非内联调用不同,是合理的。

25.4.13 Atomics.store ( ta, index, value )

此函数在调用时执行以下步骤:

  1. byteIndexInBuffer 为 ? ValidateAtomicAccessOnIntegerTypedArray(ta, index)。
  2. 如果 ta.[[ContentType]]bigint,则令 coerced 为 ? ToBigInt(value)。
  3. 否则,令 coerced𝔽(? ToIntegerOrInfinity(value))。
  4. 执行 ? RevalidateAtomicAccess(ta, byteIndexInBuffer)。
  5. bufferta.[[ViewedArrayBuffer]]
  6. elementTypeTypedArrayElementType(ta)。
  7. 执行 SetValueInBuffer(buffer, byteIndexInBuffer, elementType, coerced, true, seq-cst)。
  8. 返回 coerced

25.4.14 Atomics.sub ( ta, index, value )

此函数在调用时执行以下步骤:

  1. subtract 为一个新的读-修改-写修改函数,它具有参数 (xBytes, yBytes),捕获 ta,并在被调用时原子地执行以下步骤:
    1. typeTypedArrayElementType(ta)。
    2. agentRecord 为周围代理的代理记录。
    3. isLittleEndianagentRecord.[[LittleEndian]]
    4. xRawBytesToNumeric(type, xBytes, isLittleEndian)。
    5. yRawBytesToNumeric(type, yBytes, isLittleEndian)。
    6. 如果 x 是一个 Number,则
      1. differenceNumber::subtract(x, y)。
    7. 否则,
      1. 断言:x 是一个 BigInt。
      2. differenceBigInt::subtract(x, y)。
    8. differenceBytesNumericToRawBytes(type, difference, isLittleEndian)。
    9. 断言:differenceBytesxBytesyBytes 具有相同数量的元素。
    10. 返回 differenceBytes
  2. 返回 ? AtomicReadModifyWrite(ta, index, value, subtract)。

25.4.15 Atomics.wait ( ta, index, value, timeout )

此函数将周围代理放入等待队列并将其挂起,直到收到通知或等待超时为止,返回一个用于区分这些情况的字符串。

调用时,它执行以下步骤:

  1. 返回 ? DoWait(sync, ta, index, value, timeout)。

25.4.16 Atomics.waitAsync ( ta, index, value, timeout )

此函数返回一个 Promise,该 Promise 会在调用代理收到通知或达到超时时解析。

调用时,它执行以下步骤:

  1. 返回 ? DoWait(async, ta, index, value, timeout)。

25.4.17 Atomics.xor ( ta, index, value )

此函数在调用时执行以下步骤:

  1. xor 为一个新的读-修改-写修改函数,它具有参数 (xBytes, yBytes),不捕获任何内容,并在被调用时原子地执行以下步骤:
    1. 返回 ByteListBitwiseOp(^, xBytes, yBytes)。
  2. 返回 ? AtomicReadModifyWrite(ta, index, value, xor)。

25.4.18 Atomics [ %Symbol.toStringTag% ]

%Symbol.toStringTag% 属性的初始值是字符串值 "Atomics"

此属性具有属性特性 { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }。

25.5 JSON 对象

JSON 对象:

  • %JSON%
  • 全局对象"JSON" 属性的初始值。
  • 普通对象
  • 包含两个函数 parsestringify,用于解析和构造 JSON 文本。
  • 具有一个 [[Prototype]] 内部槽,其值为 %Object.prototype%
  • 没有 [[Construct]] 内部方法;它不能作为构造器与 new 操作符一起使用。
  • 没有 [[Call]] 内部方法;它不能作为函数调用。

JSON 数据交换格式定义于 ECMA-404。本规范中使用的 JSON 交换格式正是 ECMA-404 所描述的格式。JSON.parseJSON.stringify 的符合实现必须支持 ECMA-404 规范中描述的确切交换格式,不得对该格式进行任何删除或扩展。

25.5.1 JSON.isRawJSON ( obj )

此函数在被调用时执行以下步骤:

  1. 如果 obj 是 Object 且 obj 具有 [[IsRawJSON]] 内部槽,则返回 true
  2. 返回 false

25.5.2 JSON.parse ( text [ , reviver ] )

此函数解析 JSON 文本(JSON 格式的 String)并产生 ECMAScript 语言值。JSON 格式使用类似于 ECMAScript 字面量、Array Initializer 和 Object Initializer 语法的语法来表示字面量、数组和对象。解析后,JSON 对象实现为 ECMAScript 对象。JSON 数组实现为 ECMAScript Array 实例。JSON 字符串、数字、布尔值和 null 实现为 ECMAScript String、Number、Boolean 和 null

可选的 reviver 参数是一个可以过滤和转换结果的函数。对于解析产生的每个值,都会以三个实参(关联的属性键、值,以及一个上下文对象)调用 reviver。如果属性未被修改且其值是原始值,则所提供的上下文对象具有 "source" 属性,其中包含对应 Parse Node 的源文本。如果调用返回 undefined,则删除该属性。否则,使用返回值重新定义该属性。

  1. jsonString 为 ? ToString(text)。
  2. parseResult 为 ? ParseJSON(jsonString)。
  3. unfilteredparseResult.[[Value]]
  4. 如果 IsCallable(reviver) 是 false,则返回 unfiltered
  5. rootOrdinaryObjectCreate(%Object.prototype%)。
  6. rootName 为空 String。
  7. 执行 ! CreateDataPropertyOrThrow(root, rootName, unfiltered)。
  8. snapshotCreateJSONParseRecord(parseResult.[[ParseNode]], rootName, unfiltered)。
  9. 返回 ? InternalizeJSONProperty(root, rootName, reviver, snapshot)。

此函数的 "length" 属性是 2𝔽

25.5.2.1 ParseJSON ( text )

The abstract operation ParseJSON takes argument text (a String) and returns either a normal completion containing a Record with fields [[ParseNode]] (a Parse Node) and [[Value]] (an ECMAScript language value), or a throw completion. It performs the following steps when called:

  1. 如果 StringToCodePoints(text) 不是 ECMA-404 中指定的有效 JSON 文本,则抛出 SyntaxError 异常。
  2. scriptString"("text");"字符串连接
  3. scriptParseText(scriptString, Script)。
  4. 注:13.2.5.1 中定义的早期错误规则对上述 ParseText 调用具有特殊处理。
  5. 断言:scriptParse Node
  6. result 为 ! scriptEvaluation
  7. 注:13.2.5.6 中定义的 PropertyDefinitionEvaluation 语义对上述求值具有特殊处理。
  8. 断言:result 是 String、Number、Boolean、由 ArrayLiteralObjectLiteral 定义的 Object,或 null
  9. 返回 Record { [[ParseNode]]: script, [[Value]]: result }。

符合实现的 JSON.parse 不允许扩展 JSON 语法。如果实现希望支持修改或扩展的 JSON 交换格式,则必须通过定义不同的解析函数来实现。

Note 1

有效 JSON 文本是 ECMAScript PrimaryExpression 语法的子集。步骤 1 验证 jsonString 符合该子集,而步骤 8 断言求值返回适当类型的值。

不过,由于 13.2.5.6 在 ParseJSON 期间具有不同表现,同一源文本作为 PrimaryExpression 求值时可能产生与作为 JSON 求值时不同的结果。此外,对对象字面量中重复 "__proto__" 属性的早期错误,同样不适用于 ParseJSON,这意味着并非所有被 ParseJSON 接受的文本都作为 PrimaryExpression 有效,尽管它们匹配语法。

Note 2

在对象中存在重复 name String 的情况下,同一键的词法上在前的值应被覆盖。

25.5.2.2 JSON Parse Record

JSON Parse Record 是一种 Record 值,用于描述从 JSON 文本解析出的值的初始状态。

JSON Parse Record 具有 Table 76 中列出的字段。

Table 76: JSON Parse Record 字段
字段名 含义
[[ParseNode]] a Parse Node 上下文 Parse Node
[[Key]] a property name [[Value]] 关联的属性名
[[Value]] an ECMAScript language value [[ParseNode]] 求值产生的值。
[[Elements]] a List of JSON Parse Records 如果 [[Value]] 是 Array,则它包含[[Value]] 的元素对应的 JSON Parse Record。否则,它是空 List
[[Entries]] a List of JSON Parse Records 如果 [[Value]] 是非 Array Object,则它包含[[Value]] 的条目对应的 JSON Parse Record。否则,它是空 List

25.5.2.3 CreateJSONParseRecord ( parseNode, key, value )

The abstract operation CreateJSONParseRecord takes arguments parseNode (a Parse Node), key (a property name), and value (an ECMAScript language value) and returns a JSON Parse Record. 它递归地组合从 JSON 文本解析出的 parseNode 和由其求值产生的 value。 It performs the following steps when called:

  1. typedValueNodeShallowestContainedJSONValue(parseNode)。
  2. 断言:typedValueNode 不是 empty
  3. elements 为新的空 List
  4. entries 为新的空 List
  5. 如果 value 是 Object,则
    1. isArray 为 ! IsArray(value)。
    2. 如果 isArraytrue,则
      1. 断言:typedValueNodeArrayLiteral Parse Node
      2. contentNodestypedValueNodeJSONArrayLiteralContentNodes
      3. lengthcontentNodes 中元素的数量。
      4. valueLength 为 ! LengthOfArrayLike(value)。
      5. 断言:valueLengthlength
      6. index 为 0。
      7. 重复,只要 index < length
        1. propertyName 为 ! ToString(𝔽(index))。
        2. elementParseRecordCreateJSONParseRecord(contentNodes[index], propertyName, ! Get(value, propertyName))。
        3. elementParseRecord 追加到 elements
        4. index 设置为 index + 1。
    3. 否则,
      1. 断言:typedValueNodeObjectLiteral Parse Node
      2. propertyNodestypedValueNodePropertyDefinitionNodes
      3. 注:因为 value 是从 JSON 文本产生且尚未被修改,所以它的所有属性键都是 String,并且会被穷尽枚举。
      4. keys 为 ! EnumerableOwnProperties(value, key)。
      5. keys 的每个 String propertyKey,执行:
        1. 注:当 JSON 文本为单个对象指定多个具有相同名称的 name/value 对(例如 {"a":"lost","a":"kept"})时,所得 ECMAScript 对象对应属性的值由具有该名称的最后一对指定。
        2. propertyDefinitionempty
        3. propertyNodes 的每个 Parse Node propertyNode,执行:
          1. propertyNamepropertyNodePropName
          2. 如果 propertyNamepropertyKey,则将 propertyDefinition 设置为 propertyNode
        4. 断言:propertyDefinition PropertyDefinition : PropertyName : AssignmentExpression
        5. propertyValueNodepropertyDefinitionAssignmentExpression
        6. entryParseRecordCreateJSONParseRecord(propertyValueNode, propertyKey, ! Get(value, propertyKey))。
        7. entryParseRecord 追加到 entries
  6. 否则,
    1. 断言:typedValueNode 既不是 ArrayLiteral Parse Node,也不是 ObjectLiteral Parse Node
  7. 返回 JSON Parse Record { [[ParseNode]]: typedValueNode, [[Key]]: key, [[Value]]: value, [[Elements]]: elements, [[Entries]]: entries }。

25.5.2.4 InternalizeJSONProperty ( holder, name, reviver, parseRecord )

The abstract operation InternalizeJSONProperty takes arguments holder (an Object), name (a String), reviver (a function object), and parseRecord (a JSON Parse Record or empty) and returns either a normal completion containing an ECMAScript language value or a throw completion.

Note

此算法有意在 [[Delete]]CreateDataProperty 返回 false 时不抛出异常。

它在被调用时执行以下步骤:

  1. value 为 ? Get(holder, name)。
  2. contextOrdinaryObjectCreate(%Object.prototype%)。
  3. 如果 parseRecordJSON Parse RecordSameValue(parseRecord.[[Value]], value) 是 true,则
    1. 如果 value 不是 Object,则
      1. parseNodeparseRecord.[[ParseNode]]
      2. 断言:parseNode 既不是 ArrayLiteral Parse Node,也不是 ObjectLiteral Parse Node
      3. sourceTextparseNode 匹配的源文本
      4. 执行 ! CreateDataPropertyOrThrow(context, "source", CodePointsToString(sourceText))。
    2. elementRecordsparseRecord.[[Elements]]
    3. entryRecordsparseRecord.[[Entries]]
  4. 否则,
    1. elementRecords 为新的空 List
    2. entryRecords 为新的空 List
  5. 如果 value 是 Object,则
    1. isArray 为 ? IsArray(value)。
    2. 如果 isArraytrue,则
      1. elementRecordsLengthelementRecords 中元素的数量。
      2. length 为 ? LengthOfArrayLike(value)。
      3. index 为 0。
      4. 重复,只要 index < length
        1. propertyKey 为 ! ToString(𝔽(index))。
        2. 如果 index < elementRecordsLength,则令 elementRecordelementRecords[index];否则令 elementRecordempty
        3. newElement 为 ? InternalizeJSONProperty(value, propertyKey, reviver, elementRecord)。
        4. 如果 newElementundefined,则
          1. 执行 ? value.[[Delete]](propertyKey)
        5. 否则,
          1. 执行 ? CreateDataProperty(value, propertyKey, newElement)。
        6. index 设置为 index + 1。
    3. 否则,
      1. keys 为 ? EnumerableOwnProperties(value, key)。
      2. keys 的每个 String propertyKey,执行:
        1. 如果存在 entryRecords 的元素 entry 使得 entry.[[Key]]propertyKey,则令 entryRecordentry;否则令 entryRecordempty
        2. newElement 为 ? InternalizeJSONProperty(value, propertyKey, reviver, entryRecord)。
        3. 如果 newElementundefined,则
          1. 执行 ? value.[[Delete]](propertyKey)
        4. 否则,
          1. 执行 ? CreateDataProperty(value, propertyKey, newElement)。
  6. 返回 ? Call(reviver, holder, « name, value, context »)。

25.5.2.5 Static Semantics: ShallowestContainedJSONValue ( root )

The abstract operation ShallowestContainedJSONValue takes argument root (a Parse Node) and returns a Parse Node or empty. 它对以 root 为根的解析树执行广度优先搜索,并返回第一个属于对应于 JSON 值的非终结符实例的节点,如果不存在这样的节点则返回 empty。 It performs the following steps when called:

  1. activeFunc活动函数对象
  2. 断言:activeFuncJSON.parse 内置函数对象(见 JSON.parse)。
  3. types 为 « NullLiteral, BooleanLiteral, NumericLiteral, StringLiteral, ArrayLiteral, ObjectLiteral, UnaryExpression »。
  4. unaryExprempty
  5. queue 为 « root »。
  6. 重复,只要 queue 不为空,
    1. candidatequeue 的第一个元素。
    2. queue 中移除第一个元素。
    3. queuedChildrenfalse
    4. types 的每个非终结符 type,执行:
      1. 如果 candidatetype 的实例,则
        1. 注:在 JSON 语法中,number token 可以表示负值。在 ECMAScript 中,取负表示为一元操作,其中 UnaryExpression 解析为 - 后跟派生的 UnaryExpression
        2. 如果 typeUnaryExpression,则
          1. 如果 candidate 的父节点不是 UnaryExpression Parse Node,则将 unaryExpr 设置为 candidate
        3. 否则,如果 typeNumericLiteral,则
          1. 断言:candidate 包含unaryExpr 中。
          2. 返回 unaryExpr
        4. 否则,
          1. 返回 candidate
      2. 如果 queuedChildrenfalsecandidate 是非终结符的实例,且 candidate Contains typetrue,则
        1. children 为一个 List,按顺序包含 candidate 的每个子节点。
        2. queue 设置为 queuechildren列表连接
        3. queuedChildren 设置为 true
  7. 返回 empty

25.5.2.6 Static Semantics: JSONArrayLiteralContentNodes

The syntax-directed operation JSONArrayLiteralContentNodes takes no arguments and returns a List of Parse Nodes. It is defined piecewise over the following productions:

ArrayLiteral : [ Elisionopt ] [ ElementList ] [ ElementList , Elisionopt ]
  1. 断言:Elision 不存在。
  2. 如果 ElementList 不存在,则返回新的空 List
  3. 返回 ElementListJSONArrayLiteralContentNodes
ElementList : Elisionopt AssignmentExpression
  1. 断言:Elision 不存在。
  2. 返回 « AssignmentExpression »。
ElementList : ElementList , Elisionopt AssignmentExpression
  1. 断言:Elision 不存在。
  2. elements 为派生的 ElementListJSONArrayLiteralContentNodes
  3. 返回 elements 和 « AssignmentExpression » 的列表连接
ElementList : Elisionopt SpreadElement ElementList , Elisionopt SpreadElement
  1. 注:ECMA-404 中指定的 JSON 文本不包含 SpreadElement
  2. 断言:永远不会到达此步骤。

25.5.3 JSON.rawJSON ( text )

此函数返回一个表示字符串、数字、布尔值或 null 值的原始 JSON 文本的对象。

  1. jsonString 为 ? ToString(text)。
  2. 如果 jsonString 是空 String,则抛出 SyntaxError 异常。
  3. 如果 jsonString 的第一个码元既不是 ASCII 小写字母码元(0x0061 到 0x007A,包含)、ASCII 数字码元(0x0030 到 0x0039,包含)、0x0022(QUOTATION MARK),也不是 0x002D(HYPHEN-MINUS),则抛出 SyntaxError 异常。
  4. 如果 jsonString 的最后一个码元既不是 ASCII 小写字母码元(0x0061 到 0x007A,包含)、ASCII 数字码元(0x0030 到 0x0039,包含),也不是 0x0022(QUOTATION MARK),则抛出 SyntaxError 异常。
  5. parseResult 为 ? ParseJSON(jsonString)。
  6. 断言:parseResult.[[Value]] 是 String、Number、Boolean 或 null
  7. internalSlotsList 为 « [[IsRawJSON]] »。
  8. objOrdinaryObjectCreate(null, internalSlotsList)。
  9. 执行 ! CreateDataPropertyOrThrow(obj, "rawJSON", jsonString)。
  10. 执行 ! SetIntegrityLevel(obj, frozen)。
  11. 返回 obj

25.5.4 JSON.stringify ( value [ , replacer [ , space ] ] )

此函数返回一个以 UTF-16 编码 JSON 格式表示 ECMAScript 语言值的 String,或返回 undefined。它可以接受三个参数。value 参数是 ECMAScript 语言值,通常是对象或数组,尽管它也可以是 String、Boolean、Number 或 null。可选的 replacer 参数要么是一个改变对象和数组字符串化方式的函数,要么是一个由 String 和 Number 组成的数组,用作选择要被字符串化的对象属性的包含列表。可选的 space 参数是 String 或 Number,用于允许向结果中注入空白以提高人的可读性。

它在被调用时执行以下步骤:

  1. stack 为新的空 List
  2. indent 为空 String。
  3. propertyListundefined
  4. replacerFuncundefined
  5. 如果 replacer 是 Object,则
    1. 如果 IsCallable(replacer) 是 true,则
      1. replacerFunc 设置为 replacer
    2. 否则,
      1. isArray 为 ? IsArray(replacer)。
      2. 如果 isArraytrue,则
        1. propertyList 设置为新的空 List
        2. length 为 ? LengthOfArrayLike(replacer)。
        3. k 为 0。
        4. 重复,只要 k < length
          1. propertyKey 为 ! ToString(𝔽(k))。
          2. propertyValue 为 ? Get(replacer, propertyKey)。
          3. itemundefined
          4. 如果 propertyValue 是 String,则
            1. item 设置为 propertyValue
          5. 否则,如果 propertyValue 是 Number,则
            1. item 设置为 ! ToString(propertyValue)。
          6. 否则,如果 propertyValue 是 Object,则
            1. 如果 propertyValue 具有 [[StringData]][[NumberData]] 内部槽,则将 item 设置为 ? ToString(propertyValue)。
          7. 如果 item 不是 undefinedpropertyList包含 item,则
            1. item 追加到 propertyList
          8. k 设置为 k + 1。
  6. 如果 space 是 Object,则
    1. 如果 space 具有 [[NumberData]] 内部槽,则
      1. space 设置为 ? ToNumber(space)。
    2. 否则,如果 space 具有 [[StringData]] 内部槽,则
      1. space 设置为 ? ToString(space)。
  7. 如果 space 是 Number,则
    1. spaceMV 为 ! ToIntegerOrInfinity(space)。
    2. spaceMV 设置为 min(10, spaceMV)。
    3. 如果 spaceMV < 1,则令 gap 为空 String;否则令 gap包含 spaceMV 个码元 0x0020(SPACE)的 String 值。
  8. 否则,如果 space 是 String,则
    1. 如果 space 的长度 ≤ 10,则令 gapspace;否则令 gapspace 从 0 到 10 的子字符串
  9. 否则,
    1. gap 为空 String。
  10. wrapperOrdinaryObjectCreate(%Object.prototype%)。
  11. 执行 ! CreateDataPropertyOrThrow(wrapper, 空 String, value)。
  12. stateJSON Serialization Record { [[ReplacerFunction]]: replacerFunc, [[Stack]]: stack, [[Indent]]: indent, [[Gap]]: gap, [[PropertyList]]: propertyList }。
  13. 返回 ? SerializeJSONProperty(state, 空 String, wrapper)。

此函数的 "length" 属性是 3𝔽

Note 1

JSON 结构允许嵌套到任意深度,但它们必须是无环的。如果 value 是或包含循环结构,则此函数必须抛出 TypeError 异常。以下是一个不能被字符串化的值的示例:

a = [];
a[0] = a;
my_text = JSON.stringify(a); // 这必须抛出 TypeError。
Note 2

符号性原始值按如下方式渲染:

  • null 值在 JSON 文本中渲染为 String 值 "null"
  • undefined 值不会被渲染。
  • true 值在 JSON 文本中渲染为 String 值 "true"
  • false 值在 JSON 文本中渲染为 String 值 "false"
Note 3

String 值用 QUOTATION MARK (") 码元包裹。码元 "\\ 前缀转义。控制字符码元替换为转义序列 \uHHHH,或较短形式 \b(BACKSPACE)、\f(FORM FEED)、\n(LINE FEED)、\r(CARRIAGE RETURN)、\t(CHARACTER TABULATION)。

Note 4

有限数值会像调用 ToString(number) 一样被字符串化。NaNInfinity 不论符号如何,都表示为 String 值 "null"

Note 5

没有 JSON 表示的值(例如 undefined 和函数)不会产生 String。相反,它们产生 undefined 值。在数组中,这些值表示为 String 值 "null"。在对象中,不可表示的值会导致该属性被排除在字符串化之外。

Note 6

对象渲染为 U+007B(LEFT CURLY BRACKET),后跟零个或多个属性,这些属性以 U+002C(COMMA)分隔,并以 U+007D(RIGHT CURLY BRACKET)闭合。属性是表示属性名的带引号 String、U+003A(COLON),然后是字符串化后的属性值。数组渲染为开头的 U+005B(LEFT SQUARE BRACKET),后跟零个或多个值,这些值以 U+002C(COMMA)分隔,并以 U+005D(RIGHT SQUARE BRACKET)闭合。

25.5.4.1 JSON Serialization Record

JSON Serialization Record 是一种 Record 值,用于启用对 JSON 格式的序列化。

JSON Serialization Record 具有 Table 77 中列出的字段。

Table 77: JSON Serialization Record 字段
字段名 含义
[[ReplacerFunction]] a function object or undefined 可以为对象属性提供替换值的函数(来自 JSON.stringify 的 replacer 参数)。
[[PropertyList]] either a List of Strings or undefined 序列化非数组对象时要包含属性名(来自 JSON.stringify 的 replacer 参数)。
[[Gap]] a String 缩进单位(来自 JSON.stringify 的 space 参数)。
[[Stack]] a List of Objects 正在序列化过程中的嵌套对象集合。用于检测循环结构。
[[Indent]] a String 当前缩进。

25.5.4.2 SerializeJSONProperty ( state, key, holder )

The abstract operation SerializeJSONProperty takes arguments state (a JSON Serialization Record), key (a String), and holder (an Object) and returns either a normal completion containing either a String or undefined, or a throw completion. It performs the following steps when called:

  1. value 为 ? Get(holder, key)。
  2. 如果 value 是 Object 或 value 是 BigInt,则
    1. toJSON 为 ? GetV(value, "toJSON")。
    2. 如果 IsCallable(toJSON) 是 true,则
      1. value 设置为 ? Call(toJSON, value, « key »)。
  3. 如果 state.[[ReplacerFunction]] 不是 undefined,则
    1. value 设置为 ? Call(state.[[ReplacerFunction]], holder, « key, value »)。
  4. 如果 value 是 Object,则
    1. 如果 value 具有 [[IsRawJSON]] 内部槽,则
      1. rawJSON 为 ! Get(value, "rawJSON")。
      2. 断言:rawJSON 是 String。
      3. 返回 rawJSON
    2. 如果 value 具有 [[NumberData]] 内部槽,则
      1. value 设置为 ? ToNumber(value)。
    3. 否则,如果 value 具有 [[StringData]] 内部槽,则
      1. value 设置为 ? ToString(value)。
    4. 否则,如果 value 具有 [[BooleanData]] 内部槽,则
      1. value 设置为 value.[[BooleanData]]
    5. 否则,如果 value 具有 [[BigIntData]] 内部槽,则
      1. value 设置为 value.[[BigIntData]]
  5. 如果 valuenull,则返回 "null"
  6. 如果 valuetrue,则返回 "true"
  7. 如果 valuefalse,则返回 "false"
  8. 如果 value 是 String,则返回 QuoteJSONString(value)。
  9. 如果 value 是 Number,则
    1. 如果 value有限的,则返回 ! ToString(value)。
    2. 返回 "null"
  10. 如果 value 是 BigInt,则抛出 TypeError 异常。
  11. 如果 value 是 Object 且 IsCallable(value) 是 false,则
    1. isArray 为 ? IsArray(value)。
    2. 如果 isArraytrue,则
      1. 返回 ? SerializeJSONArray(state, value)。
    3. 返回 ? SerializeJSONObject(state, value)。
  12. 返回 undefined

25.5.4.3 QuoteJSONString ( value )

The abstract operation QuoteJSONString takes argument value (a String) and returns a String. 它用 0x0022(QUOTATION MARK)码元包裹 value,并转义其中的某些其他码元。此操作将 value 解释为 UTF-16 编码码点的序列,如 6.1.4 中所述。 It performs the following steps when called:

  1. product 为仅由码元 0x0022(QUOTATION MARK)组成的 String 值。
  2. StringToCodePoints(value) 的每个码点 codePoint,执行:
    1. 如果 codePoint 列于 Table 78 的 “Code Point” 列中,则
      1. product 设置为 product 与对应行的 “Escape Sequence” 列中为 codePoint 指定的转义序列的字符串连接
    2. 否则,如果 codePoint 的数值小于 0x0020(SPACE),或 codePoint 的数值与 leading surrogate 或 trailing surrogate 的数值相同,则
      1. unit 为数值等于 codePoint 数值的码元。
      2. product 设置为 productUnicodeEscape(unit) 的字符串连接
    3. 否则,
      1. product 设置为 productUTF16EncodeCodePoint(codePoint) 的字符串连接
  3. product 设置为 product 和码元 0x0022(QUOTATION MARK)的字符串连接
  4. 返回 product
Table 78: JSON 单字符转义序列
码点 Unicode 字符名称 转义序列
U+0008 BACKSPACE \b
U+0009 CHARACTER TABULATION \t
U+000A LINE FEED (LF) \n
U+000C FORM FEED (FF) \f
U+000D CARRIAGE RETURN (CR) \r
U+0022 QUOTATION MARK \"
U+005C REVERSE SOLIDUS \\

25.5.4.4 UnicodeEscape ( codeUnit )

The abstract operation UnicodeEscape takes argument codeUnit (a code unit) and returns a String. 它将 codeUnit 表示为 Unicode 转义序列。 It performs the following steps when called:

  1. ncodeUnit 的数值。
  2. 断言:n ≤ 0xFFFF。
  3. hexn 的 String 表示,格式化为小写十六进制数。
  4. 返回码元 0x005C(REVERSE SOLIDUS)、"u"StringPad(hex, 4, "0", start) 的字符串连接

25.5.4.5 SerializeJSONObject ( state, value )

The abstract operation SerializeJSONObject takes arguments state (a JSON Serialization Record) and value (an Object) and returns either a normal completion containing a String or a throw completion. 它序列化一个对象。 It performs the following steps when called:

  1. 如果 state.[[Stack]] 包含 value,则抛出 TypeError 异常,因为该结构是循环的。
  2. value 追加到 state.[[Stack]]
  3. stepBackstate.[[Indent]]
  4. state.[[Indent]] 设置为 state.[[Indent]]state.[[Gap]]字符串连接
  5. 如果 state.[[PropertyList]] 不是 undefined,则
    1. keysstate.[[PropertyList]]
  6. 否则,
    1. keys 为 ? EnumerableOwnProperties(value, key)。
  7. partial 为新的空 List
  8. keys 的每个元素 propertyKey,执行:
    1. stringP 为 ? SerializeJSONProperty(state, propertyKey, value)。
    2. 如果 stringP 不是 undefined,则
      1. memberQuoteJSONString(propertyKey)。
      2. member 设置为 member":"字符串连接
      3. 如果 state.[[Gap]] 不是空 String,则
        1. member 设置为 member 和码元 0x0020(SPACE)的字符串连接
      4. member 设置为 memberstringP字符串连接
      5. member 追加到 partial
  9. 如果 partial 为空,则
    1. final"{}"
  10. 否则,
    1. 如果 state.[[Gap]] 是空 String,则
      1. properties 为通过连接 partial 的所有元素 String 形成的 String 值,相邻每对 String 之间以码元 0x002C(COMMA)分隔。逗号既不插入在第一个 String 之前,也不插入在最后一个 String 之后。
      2. final"{"properties"}"字符串连接
    2. 否则,
      1. separator 为码元 0x002C(COMMA)、码元 0x000A(LINE FEED)和 state.[[Indent]]字符串连接
      2. properties 为通过连接 partial 的所有元素 String 形成的 String 值,相邻每对 String 之间以 separator 分隔。separator String 既不插入在第一个 String 之前,也不插入在最后一个 String 之后。
      3. final"{"、码元 0x000A(LINE FEED)、state.[[Indent]]properties、码元 0x000A(LINE FEED)、stepBack"}"字符串连接
  11. 移除 state.[[Stack]] 的最后一个元素。
  12. state.[[Indent]] 设置为 stepBack
  13. 返回 final

25.5.4.6 SerializeJSONArray ( state, value )

The abstract operation SerializeJSONArray takes arguments state (a JSON Serialization Record) and value (an Object) and returns either a normal completion containing a String or a throw completion. 它序列化一个数组。 It performs the following steps when called:

  1. 如果 state.[[Stack]] 包含 value,则抛出 TypeError 异常,因为该结构是循环的。
  2. value 追加到 state.[[Stack]]
  3. stepBackstate.[[Indent]]
  4. state.[[Indent]] 设置为 state.[[Indent]]state.[[Gap]]字符串连接
  5. partial 为新的空 List
  6. length 为 ? LengthOfArrayLike(value)。
  7. index 为 0。
  8. 重复,只要 index < length
    1. stringP 为 ? SerializeJSONProperty(state, ! ToString(𝔽(index)), value)。
    2. 如果 stringPundefined,则
      1. "null" 追加到 partial
    3. 否则,
      1. stringP 追加到 partial
    4. index 设置为 index + 1。
  9. 如果 partial 为空,则
    1. final"[]"
  10. 否则,
    1. 如果 state.[[Gap]] 是空 String,则
      1. properties 为通过连接 partial 的所有元素 String 形成的 String 值,相邻每对 String 之间以码元 0x002C(COMMA)分隔。逗号既不插入在第一个 String 之前,也不插入在最后一个 String 之后。
      2. final"["properties"]"字符串连接
    2. 否则,
      1. separator 为码元 0x002C(COMMA)、码元 0x000A(LINE FEED)和 state.[[Indent]]字符串连接
      2. properties 为通过连接 partial 的所有元素 String 形成的 String 值,相邻每对 String 之间以 separator 分隔。separator String 既不插入在第一个 String 之前,也不插入在最后一个 String 之后。
      3. final"["、码元 0x000A(LINE FEED)、state.[[Indent]]properties、码元 0x000A(LINE FEED)、stepBack"]"字符串连接
  11. 移除 state.[[Stack]] 的最后一个元素。
  12. state.[[Indent]] 设置为 stepBack
  13. 返回 final
Note

数组的表示仅包含+0𝔽包含)到 array.length(不包含区间内的元素。键不是数组索引的属性会被排除在字符串化之外。数组被字符串化为开头的 LEFT SQUARE BRACKET、以 COMMA 分隔的元素,以及闭合的 RIGHT SQUARE BRACKET。

25.5.5 JSON [ %Symbol.toStringTag% ]

%Symbol.toStringTag% 属性的初始值是 String 值 "JSON"

此属性具有特性 { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }。