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 ( constructor, byteLength [ , maxByteLength ] )

The abstract operation AllocateArrayBuffer takes arguments constructor (一个构造器,) and byteLength (一个非负整数,) and optional argument maxByteLength (一个非负整数empty,) and returns 要么是一个包含 ArrayBuffer 的正常完成,要么是一个抛出完成. 它用于创建一个 ArrayBuffer。 It performs the following steps when called:

  1. slots 为 « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] »。
  2. 如果 maxByteLength 存在且 maxByteLength 不是 empty,令 allocatingResizableBuffertrue;否则令 allocatingResizableBufferfalse
  3. 如果 allocatingResizableBuffertrue,则
    1. 如果 byteLength > maxByteLength,抛出 RangeError 异常。
    2. [[ArrayBufferMaxByteLength]] 追加到 slots
  4. obj 为 ? OrdinaryCreateFromConstructor(constructor, "%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 (一个 ArrayBuffer 或 SharedArrayBuffer,) and order (seq-cstunordered,) and returns 一个非负整数. It performs the following steps when called:

  1. 如果 IsGrowableSharedArrayBuffer(arrayBuffer) 是 true,则
    1. bufferByteLengthBlockarrayBuffer.[[ArrayBufferByteLengthData]]
    2. rawLengthGetRawBytesFromSharedBlock(bufferByteLengthBlock, 0, biguint64, true, order)。
    3. agentRecord 为周围 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 (一个 ECMAScript 语言值,), newLength (一个 ECMAScript 语言值,), and preserveResizability (preserve-resizabilityfixed-length,) and returns 要么是一个包含 ArrayBuffer 的正常完成,要么是一个抛出完成. 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 (一个 ArrayBuffer 或 SharedArrayBuffer,) and returns 一个 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 (一个 ArrayBuffer,) and optional argument key (任意值,) and returns 要么是一个包含 unused正常完成,要么是一个抛出完成. 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 与该实例解除关联,并将该 buffer 的字节长度设置为 0。

25.1.3.6 CloneArrayBuffer ( srcBuffer, srcByteOffset, srcLength )

The abstract operation CloneArrayBuffer takes arguments srcBuffer (一个 ArrayBuffer 或 SharedArrayBuffer,), srcByteOffset (一个非负整数,), and srcLength (一个非负整数,) and returns 要么是一个包含 ArrayBuffer 的正常完成,要么是一个抛出完成. 它创建一个新的 ArrayBuffer,其数据是 srcBuffer 的数据在从 srcByteOffset 开始并持续 srcLength 个字节的范围内的副本。 It performs the following steps when called:

  1. 断言:IsDetachedBuffer(srcBuffer) 是 false
  2. targetBuffer 为 ? AllocateArrayBuffer(%ArrayBuffer%, srcLength)。
  3. srcBlocksrcBuffer.[[ArrayBufferData]]
  4. targetBlocktargetBuffer.[[ArrayBufferData]]
  5. 执行 CopyDataBlockBytes(targetBlock, 0, srcBlock, srcByteOffset, srcLength)。
  6. 返回 targetBuffer

25.1.3.7 GetArrayBufferMaxByteLengthOption ( options )

The abstract operation GetArrayBufferMaxByteLengthOption takes argument options (一个 ECMAScript 语言值,) and returns 要么是一个包含非负整数empty正常完成,要么是一个抛出完成. 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 (一个 ArrayBuffer,) and newByteLength (一个非负整数,) and returns 要么是一个包含 handledunhandled正常完成,要么是一个抛出完成. 它给予宿主执行 buffer实现定义调整大小的机会。如果宿主选择不处理 buffer 的调整大小,则可返回 unhandled 以采用默认行为。

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

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

25.1.3.9 IsFixedLengthArrayBuffer ( arrayBuffer )

The abstract operation IsFixedLengthArrayBuffer takes argument arrayBuffer (一个 ArrayBuffer 或 SharedArrayBuffer,) and returns 一个 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 (一个 TypedArray 元素类型,) and returns 一个 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 (一个 TypedArray 元素类型,) and returns 一个 Boolean. 它验证参数 type 是否为一个 Integer TypedArray 元素类型,且不包括 uint8clamped。 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 (一个 TypedArray 元素类型,) and returns 一个 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 (一个 TypedArray 元素类型,) and order (seq-cstunorderedinit,) and returns 一个 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 (一个 TypedArray 元素类型,), rawBytes (一个由字节值组成的 List,), and isLittleEndian (一个 Boolean,) and returns 一个 Number 或一个 BigInt. It performs the following steps when called:

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

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

The abstract operation GetRawBytesFromSharedBlock takes arguments block (一个 Shared Data Block,), byteIndex (一个非负整数,), type (一个 TypedArray 元素类型,), isTypedArray (一个 Boolean,), and order (seq-cstunordered,) and returns 一个由字节值组成的 List. It performs the following steps when called:

  1. elementSizeTable 70 中为 Element Type type 指定的 Element Size 值。
  2. agentRecord 为周围 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. readEvent 为 ReadSharedMemory { [[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 (一个 ArrayBuffer 或 SharedArrayBuffer,), byteIndex (一个非负整数,), type (一个 TypedArray 元素类型,), isTypedArray (一个 Boolean,), and order (seq-cstunordered,) and optional argument isLittleEndian (一个 Boolean,) and returns 一个 Number 或一个 BigInt. It performs the following steps when called:

  1. 断言:IsDetachedBuffer(arrayBuffer) 是 false
  2. 断言:arrayBuffer 中从 byteIndex 开始有足够的字节来表示一个 type 的值。
  3. blockarrayBuffer.[[ArrayBufferData]]
  4. elementSizeTable 70 中为 Element Type type 指定的 Element Size 值。
  5. 如果 IsSharedArrayBuffer(arrayBuffer) 是 true,则
    1. 断言:block 是一个 Shared Data Block
    2. rawValueGetRawBytesFromSharedBlock(block, byteIndex, type, isTypedArray, order)。
  6. 否则,
    1. rawValue 为一个 List,其元素是 block 中索引位于从 byteIndex(包含)到 byteIndex + elementSize(不包含)区间内的字节。
  7. 断言:rawValue 中元素的数量为 elementSize
  8. 如果 isLittleEndian 不存在,则
    1. agentRecord 为周围 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 (一个 TypedArray 元素类型,), value (一个 Number 或一个 BigInt,), and isLittleEndian (一个 Boolean,) and returns 一个由字节值组成的 List. It performs the following steps when called:

  1. 如果 typefloat16,则
    1. rawBytes 为一个 List,其元素为使用 roundTiesToEven 模式将 value 转换为 IEEE 754-2019 binary16 格式所得的 2 个字节。这些字节按小端顺序排列。如果 valueNaNrawBytes 可被设置为任意由实现选择的 IEEE 754-2019 binary16 格式 NaN 编码。实现必须始终为每个实现可区分的 NaN 值选择相同的编码。
  2. 否则如果 typefloat32,则
    1. rawBytes 为一个 List,其元素为使用 roundTiesToEven 模式将 value 转换为 IEEE 754-2019 binary32 格式所得的 4 个字节。这些字节按小端顺序排列。如果 valueNaNrawBytes 可被设置为任意由实现选择的 IEEE 754-2019 binary32 格式 NaN 编码。实现必须始终为每个实现可区分的 NaN 值选择相同的编码。
  3. 否则如果 typefloat64,则
    1. rawBytes 为一个 List,其元素为 valueIEEE 754-2019 binary64 格式编码的 8 个字节。这些字节按小端顺序排列。如果 valueNaNrawBytes 可被设置为任意由实现选择的 IEEE 754-2019 binary64 格式 NaN 编码。实现必须始终为每个实现可区分的 NaN 值选择相同的编码。
  4. 否则,
    1. nTable 70 中为 Element Type type 指定的 Element Size 值。
    2. conversionOperationTable 70 中 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 (一个 ArrayBuffer 或 SharedArrayBuffer,), byteIndex (一个非负整数,), type (一个 TypedArray 元素类型,), value (一个 Number 或一个 BigInt,), isTypedArray (一个 Boolean,), and order (seq-cstunorderedinit,) and optional argument isLittleEndian (一个 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 70 中为 Element Type type 指定的 Element Size 值。
  6. agentRecord 为周围 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 (一个 ArrayBuffer 或一个 SharedArrayBuffer,), byteIndex (一个非负整数,), type (一个 TypedArray 元素类型,), value (一个 Number 或一个 BigInt,), and op (一个读-改-写修改函数,) and returns 一个 Number 或一个 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 70 中为 Element Type type 指定的 Element Size 值。
  6. agentRecord 为周围 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. rmwEvent 为 ReadModifyWriteSharedMemory { [[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. lenobj.[[ArrayBufferByteLength]]
  6. relativeStart 为 ? ToIntegerOrInfinity(start)。
  7. 如果 relativeStart = -∞,令 first 为 0。
  8. 否则如果 relativeStart < 0,令 firstmax(len + relativeStart, 0)。
  9. 否则,令 firstmin(relativeStart, len)。
  10. 如果 endundefined,令 relativeEndlen;否则令 relativeEnd 为 ? ToIntegerOrInfinity(end)。
  11. 如果 relativeEnd = -∞,令 final 为 0。
  12. 否则如果 relativeEnd < 0,令 finalmax(len + relativeEnd, 0)。
  13. 否则,令 finalmin(relativeEnd, len)。
  14. newLenmax(final - first, 0)。
  15. ctor 为 ? SpeciesConstructor(obj, %ArrayBuffer%)。
  16. new 为 ? Construct(ctor, « 𝔽(newLen) »)。
  17. 执行 ? RequireInternalSlot(new, [[ArrayBufferData]])。
  18. 如果 IsSharedArrayBuffer(new) 是 true,抛出 TypeError 异常。
  19. 如果 IsDetachedBuffer(new) 是 true,抛出 TypeError 异常。
  20. 如果 SameValue(new, obj) 是 true,抛出 TypeError 异常。
  21. 如果 new.[[ArrayBufferByteLength]] < newLen,抛出 TypeError 异常。
  22. 注:上述步骤的副作用可能已分离或调整了 obj 的大小。
  23. 如果 IsDetachedBuffer(obj) 是 true,抛出 TypeError 异常。
  24. fromBufobj.[[ArrayBufferData]]
  25. toBufnew.[[ArrayBufferData]]
  26. currentLenobj.[[ArrayBufferByteLength]]
  27. 如果 first < currentLen,则
    1. countmin(newLen, currentLen - 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,并不能保证未来的 resize 会成功。

Note 2

以下是供实现可调整大小 ArrayBuffer 的 ECMAScript 实现者使用的指南。

可调整大小 ArrayBuffer 可以实现为在 resize 时复制、通过预先保留虚拟内存进行就地增长,或针对构造器"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 ( constructor, byteLength [ , maxByteLength ] )

The abstract operation AllocateSharedArrayBuffer takes arguments constructor (一个构造器,) and byteLength (一个非负整数,) and optional argument maxByteLength (一个非负整数empty,) and returns 要么是一个包含 SharedArrayBuffer 的正常完成,要么是一个抛出完成. 它用于创建一个 SharedArrayBuffer。 It performs the following steps when called:

  1. slots 为 « [[ArrayBufferData]] »。
  2. 如果 maxByteLength 存在且 maxByteLength 不是 empty,令 allocatingGrowableBuffertrue;否则令 allocatingGrowableBufferfalse
  3. 如果 allocatingGrowableBuffertrue,则
    1. 如果 byteLength > maxByteLength,抛出 RangeError 异常。
    2. [[ArrayBufferByteLengthData]][[ArrayBufferMaxByteLength]] 追加到 slots
  4. 否则,
    1. [[ArrayBufferByteLength]] 追加到 slots
  5. obj 为 ? OrdinaryCreateFromConstructor(constructor, "%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 (一个 ArrayBuffer 或一个 SharedArrayBuffer,) and returns 一个 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 (一个 ArrayBuffer 或一个 SharedArrayBuffer,) and returns 一个 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 (一个 SharedArrayBuffer,) and newByteLength (一个非负整数,) and returns 要么是一个包含 handledunhandled正常完成,要么是一个抛出完成. 它给予宿主执行 buffer实现定义增长的机会。如果宿主选择不处理 buffer 的增长,则可返回 unhandled 以采用默认行为。

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

  • 如果该抽象操作没有以 unhandled 正常完成,且 newByteLength < buffer 的当前字节长度或 newByteLength > buffer.[[ArrayBufferMaxByteLength]],则抛出 RangeError 异常。
  • agentRecord 为周围 agentAgent Record。令 isLittleEndianagentRecord.[[LittleEndian]]。如果该抽象操作handled 正常完成,则向周围 agent候选执行添加一个 WriteSharedMemory 或 ReadModifyWriteSharedMemory 事件,其 [[Order]]seq-cst[[Payload]]NumericToRawBytes(biguint64, newByteLength, isLittleEndian),[[Block]]buffer.[[ArrayBufferByteLengthData]][[ByteIndex]] 为 0,且 [[ElementSize]] 为 8,使得对 SharedArrayBuffer.prototype.grow ( newLength ) 的竞争调用不会“丢失”,即不会静默地什么也不做。
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

ArrayBuffer 不同,SharedArrayBuffer 不能变为已分离,并且其内部 [[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 为周围 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 循环,用于确保同一 buffer 的并行竞争增长是全序的、不会丢失,也不会静默地什么也不做。如果它能够尝试无竞争地增长,则循环退出。
    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 在更新长度时发生虚假失败。如果新长度的边界检查通过,且实现没有内存不足,则总是会向候选执行中添加一个 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. lenArrayBufferByteLength(obj, seq-cst)。
  5. relativeStart 为 ? ToIntegerOrInfinity(start)。
  6. 如果 relativeStart = -∞,令 first 为 0。
  7. 否则如果 relativeStart < 0,令 firstmax(len + relativeStart, 0)。
  8. 否则,令 firstmin(relativeStart, len)。
  9. 如果 endundefined,令 relativeEndlen;否则令 relativeEnd 为 ? ToIntegerOrInfinity(end)。
  10. 如果 relativeEnd = -∞,令 final 为 0。
  11. 否则如果 relativeEnd < 0,令 finalmax(len + relativeEnd, 0)。
  12. 否则,令 finalmin(relativeEnd, len)。
  13. newLenmax(final - first, 0)。
  14. ctor 为 ? SpeciesConstructor(obj, %SharedArrayBuffer%)。
  15. new 为 ? Construct(ctor, « 𝔽(newLen) »)。
  16. 执行 ? RequireInternalSlot(new, [[ArrayBufferData]])。
  17. 如果 IsSharedArrayBuffer(new) 是 false,抛出 TypeError 异常。
  18. 如果 new.[[ArrayBufferData]]obj.[[ArrayBufferData]],抛出 TypeError 异常。
  19. 如果 ArrayBufferByteLength(new, seq-cst) < newLen,抛出 TypeError 异常。
  20. fromBufobj.[[ArrayBufferData]]
  21. toBufnew.[[ArrayBufferData]]
  22. 执行 CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen)。
  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,并不能保证未来的 grow 会成功。

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

Note 2

以下是供实现可增长 SharedArrayBuffer 的 ECMAScript 实现者使用的指南。

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

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

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

可增长 SharedArrayBufferTypedArray 视图上的整数索引属性访问意图能够像不可增长 SharedArrayBufferTypedArray 视图上的访问一样被优化,因为整数索引属性加载不会在底层 buffer 的长度上同步(见上文程序员指南)。例如,属性访问的边界检查仍可被提升到循环之外。

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

25.3 DataView 对象

25.3.1 DataView 对象的抽象操作

25.3.1.1 DataView With Buffer Witness Records

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

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

Table 72: DataView With Buffer Witness Record 字段
字段名 含义
[[Object]] 一个 DataView 加载其 buffer 字节长度的 DataView 对象。
[[CachedBufferByteLength]] 一个非负整数detached 创建该 Record 时对象的 [[ViewedArrayBuffer]] 的字节长度。

25.3.1.2 MakeDataViewWithBufferWitnessRecord ( obj, order )

The abstract operation MakeDataViewWithBufferWitnessRecord takes arguments obj (一个 DataView,) and order (seq-cstunordered,) and returns 一个 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 (一个 DataView With Buffer Witness Record,) and returns 一个非负整数. 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 (一个 DataView With Buffer Witness Record,) and returns 一个 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 (一个 ECMAScript 语言值,), requestIndex (一个 ECMAScript 语言值,), isLittleEndian (一个 ECMAScript 语言值,), and type (一个 TypedArray 元素类型,) and returns 要么是一个包含 Number 或 BigInt 的正常完成,要么是一个抛出完成. 它由 DataView 实例上的函数用于从该 view 的 buffer 中检索值。 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 的后备 buffer 是可增长 SharedArrayBuffer 时,边界检查不是同步操作。
  8. 如果 IsViewOutOfBounds(viewRecord) 是 true,抛出 TypeError 异常。
  9. viewSizeGetViewByteLength(viewRecord)。
  10. elementSizeTable 70 中为 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 (一个 ECMAScript 语言值,), requestIndex (一个 ECMAScript 语言值,), isLittleEndian (一个 ECMAScript 语言值,), type (一个 TypedArray 元素类型,), and value (一个 ECMAScript 语言值,) and returns 要么是一个包含 undefined正常完成,要么是一个抛出完成. 它由 DataView 实例上的函数用于将值存储进该 view 的 buffer。 It performs the following steps when called:

  1. 执行 ? RequireInternalSlot(view, [[DataView]])。
  2. 断言:view[[ViewedArrayBuffer]] 内部槽。
  3. getIndex 为 ? ToIndex(requestIndex)。
  4. 如果 IsBigIntElementType(type) 是 true,令 numberValue 为 ? ToBigInt(value)。
  5. 否则,令 numberValue 为 ? ToNumber(value)。
  6. isLittleEndian 设置为 ToBoolean(isLittleEndian)。
  7. viewOffsetview.[[ByteOffset]]
  8. viewRecordMakeDataViewWithBufferWitnessRecord(view, unordered)。
  9. 注:当 view 的后备 buffer 是可增长 SharedArrayBuffer 时,边界检查不是同步操作。
  10. 如果 IsViewOutOfBounds(viewRecord) 是 true,抛出 TypeError 异常。
  11. viewSizeGetViewByteLength(viewRecord)。
  12. elementSizeTable 70 中为 Element Type type 指定的 Element Size 值。
  13. 如果 getIndex + elementSize > viewSize,抛出 RangeError 异常。
  14. bufferIndexgetIndex + viewOffset
  15. 执行 SetValueInBuffer(view.[[ViewedArrayBuffer]], bufferIndex, type, numberValue, 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 对象提供一些函数,这些函数以不可分割(原子)的方式操作共享内存数组单元,也提供一些使 agents 能够等待并派发原始事件的函数。当以有纪律的方式使用时,Atomics 函数允许通过共享内存通信的多 agent 程序即使在并行 CPU 上也能以可充分理解的顺序执行。支配共享内存通信的规则由下面定义的内存模型提供。

Note

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

25.4.1 Waiter Record

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

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

Table 73: Waiter Record 字段
字段名 含义
[[AgentSignifier]] 一个 agent signifier 调用 Atomics.waitAtomics.waitAsyncagent
[[PromiseCapability]] 一个 PromiseCapability Recordblocking 如果表示对 Atomics.waitAsync 的调用,则为产生的 promise;否则为 blocking
[[TimeoutTime]] 一个非负扩展数学值 timeout 可以被触发的最早时间;使用时间值计算。
[[Result]] "ok""timed-out" 该调用的返回值。

25.4.2 WaiterList Records

WaiterList Record 用于解释 agents 通过 Atomics.waitAtomics.waitAsyncAtomics.notify 进行等待和通知。

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

Table 74: WaiterList Record 字段
字段名 含义
[[Waiters]] 一个由 Waiter Records 组成的 List 正在等待与此 WaiterList 相关联位置的 Atomics.waitAtomics.waitAsync 调用。
[[MostRecentLeaveEvent]] 一个 Synchronize 事件empty 最近一次离开其临界区的事件;如果其临界区从未被进入过,则为 empty

一个 WaiterList 中可以有多个具有相同 agent signifier 的 Waiter Records

agent cluster 有一个 WaiterList Records 存储;该存储按 (block, i) 索引,其中 block 是一个 Shared Data Block,而 i 是进入 block 内存的一个字节偏移。WaiterList Records 与 agent 无关:在 agent cluster 中的任意 agent 内,通过 (block, i) 查询 WaiterList Records 存储都会得到同一个 WaiterList Record。

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

25.4.3 Atomics 的抽象操作

25.4.3.1 ValidateIntegerTypedArray ( typedArray, waitable )

The abstract operation ValidateIntegerTypedArray takes arguments typedArray (一个 ECMAScript 语言值,) and waitable (一个 Boolean,) and returns 要么是一个包含 TypedArray With Buffer Witness Record正常完成,要么是一个抛出完成. It performs the following steps when called:

  1. taRecord 为 ? ValidateTypedArray(typedArray, unordered)。
  2. 注:当 typedArray 的后备 buffer 是可增长 SharedArrayBuffer 时,边界检查不是同步操作。
  3. 如果 waitabletrue,则
    1. 如果 typedArray.[[TypedArrayName]] 既不是 "Int32Array" 也不是 "BigInt64Array",抛出 TypeError 异常。
  4. 否则,
    1. typeTypedArrayElementType(typedArray)。
    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. typedArraytaRecord.[[Object]]
  6. elementSizeTypedArrayElementSize(typedArray)。
  7. offsettypedArray.[[ByteOffset]]
  8. 返回 (accessIndex × elementSize) + offset

25.4.3.3 ValidateAtomicAccessOnIntegerTypedArray ( typedArray, requestIndex )

The abstract operation ValidateAtomicAccessOnIntegerTypedArray takes arguments typedArray (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(typedArray, false)。
  2. 返回 ? ValidateAtomicAccess(taRecord, requestIndex)。

25.4.3.4 RevalidateAtomicAccess ( typedArray, byteIndexInBuffer )

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

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

25.4.3.5 GetWaiterList ( block, i )

The abstract operation GetWaiterList takes arguments block (一个 Shared Data Block,) and i (一个可被 4 整除的非负整数,) and returns 一个 WaiterList Record. It performs the following steps when called:

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

25.4.3.6 EnterCriticalSection ( waiterList )

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

  1. 断言:周围 agent 不在任何 WaiterList Record临界区中。
  2. 等待直到没有 agent 处于 waiterList临界区中,然后进入 waiterList临界区(不允许任何其他 agent 进入)。
  3. 如果 waiterList.[[MostRecentLeaveEvent]] 不是 empty,则
    1. 注:临界区已至少进入过一次的 waiterList 具有由 LeaveCriticalSection 设置的 Synchronize 事件
    2. agentRecord 为周围 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 (一个 WaiterList Record,) and returns unused. It performs the following steps when called:

  1. 断言:周围 agent 处于 waiterList临界区中。
  2. agentRecord 为周围 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 (一个 WaiterList Record,) and waiterRecord (一个 Waiter Record,) and returns unused. It performs the following steps when called:

  1. 断言:周围 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 (一个 WaiterList Record,) and waiterRecord (一个 Waiter Record,) and returns unused. It performs the following steps when called:

  1. 断言:周围 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 (一个 WaiterList Record,) and count (一个非负整数或 +∞,) and returns 一个由 Waiter Records 组成的 List. It performs the following steps when called:

  1. 断言:周围 agent 处于 waiterList临界区中。
  2. lenwaiterList.[[Waiters]] 中元素的数量。
  3. count 设置为 min(count, len)。
  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 (一个 WaiterList Record,) and waiterRecord (一个 Waiter Record,) and returns unused. It performs the following steps when called:

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

25.4.3.12 NotifyWaiter ( waiterList, waiterRecord )

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

  1. 断言:周围 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 (一个 agent signifier,), promiseCapability (一个 PromiseCapability Record,), and resolution ("ok""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, typedArray, index, value, timeout )

The abstract operation DoWait takes arguments mode (syncasync,), typedArray (一个 ECMAScript 语言值,), index (一个 ECMAScript 语言值,), value (一个 ECMAScript 语言值,), and timeout (一个 ECMAScript 语言值,) and returns 要么是一个包含 Object、"not-equal""timed-out""ok"正常完成,要么是一个抛出完成. It performs the following steps when called:

  1. taRecord 为 ? ValidateIntegerTypedArray(typedArray, true)。
  2. buffertaRecord.[[Object]].[[ViewedArrayBuffer]]
  3. 如果 IsSharedArrayBuffer(buffer) 是 false,抛出 TypeError 异常。
  4. byteIndexInBuffer 为 ? ValidateAtomicAccess(taRecord, index)。
  5. arrayTypeNametypedArray.[[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. resultObjectundefined
  16. 否则,
    1. promiseCapability 为 ! NewPromiseCapability(%Promise%)。
    2. resultObjectOrdinaryObjectCreate(%Object.prototype%)。
  17. 执行 EnterCriticalSection(waiterList)。
  18. elementTypeTypedArrayElementType(typedArray)。
  19. witnessGetValueFromBuffer(buffer, byteIndexInBuffer, elementType, true, seq-cst)。
  20. 如果 expectedwitness,则
    1. 执行 LeaveCriticalSection(waiterList)。
    2. 如果 modesync,返回 "not-equal"
    3. 执行 ! CreateDataPropertyOrThrow(resultObject, "async", false)。
    4. 执行 ! CreateDataPropertyOrThrow(resultObject, "value", "not-equal")。
    5. 返回 resultObject
  21. 如果 realTimeout = 0 且 modeasync,则
    1. 注:同步的立即 timeout 没有特殊处理。异步的立即 timeout 有特殊处理,以便快速失败并避免不必要的 Promise jobs。
    2. 执行 LeaveCriticalSection(waiterList)。
    3. 执行 ! CreateDataPropertyOrThrow(resultObject, "async", false)。
    4. 执行 ! CreateDataPropertyOrThrow(resultObject, "value", "timed-out")。
    5. 返回 resultObject
  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(resultObject, "async", true)。
  34. 执行 ! CreateDataPropertyOrThrow(resultObject, "value", promiseCapability.[[Promise]])。
  35. 返回 resultObject
Note

additionalTimeout 允许实现按需填充 timeout,例如用于降低功耗或粗化计时器分辨率以缓解定时攻击。该值在 DoWait 的不同调用之间可以不同。

25.4.3.15 EnqueueAtomicsWaitAsyncTimeoutJob ( waiterList, waiterRecord )

The abstract operation EnqueueAtomicsWaitAsyncTimeoutJob takes arguments waiterList (一个 WaiterList Record,) and waiterRecord (一个 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 (一个 Shared Data Block,), byteIndexInBuffer (一个整数,), elementSize (一个非负整数,), expectedBytes (一个由字节值组成的 List,), and replacementBytes (一个由字节值组成的 List,) and returns 一个由字节值组成的 List. It performs the following steps when called:

  1. agentRecord 为周围 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. event 为 ReadModifyWriteSharedMemory { [[Order]]: seq-cst, [[NoTear]]: true, [[Block]]: block, [[ByteIndex]]: byteIndexInBuffer, [[ElementSize]]: elementSize, [[Payload]]: replacementBytes, [[ModifyOp]]: second }。
  8. 否则,
    1. event 为 ReadSharedMemory { [[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 ( typedArray, index, value, op )

The abstract operation AtomicReadModifyWrite takes arguments typedArray (一个 ECMAScript 语言值,), index (一个 ECMAScript 语言值,), value (一个 ECMAScript 语言值,), and op (一个读-改-写修改函数,) and returns 要么是一个包含 Number 或 BigInt 的正常完成,要么是一个抛出完成. op 接受两个由字节值组成的 List 参数,并返回一个由字节值组成的 List。此操作以原子方式加载一个值,将它与另一个值组合,并存储该组合。它返回被加载的值。 It performs the following steps when called:

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

25.4.3.18 ByteListBitwiseOp ( op, xBytes, yBytes )

The abstract operation ByteListBitwiseOp takes arguments op (&^|,), xBytes (一个由字节值组成的 List,), and yBytes (一个由字节值组成的 List,) and returns 一个由字节值组成的 List. 该操作以原子方式对参数的所有字节值执行按位操作,并返回一个由字节值组成的 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 应用按位 exclusive OR(XOR)操作的结果。
    4. 否则,
      1. 断言:op|
      2. resultByte 为对 xByteyByte 应用按位 inclusive OR 操作的结果。
    5. i 设置为 i + 1。
    6. resultByte 追加到 result
  5. 返回 result

25.4.3.19 ByteListEqual ( xBytes, yBytes )

The abstract operation ByteListEqual takes arguments xBytes (一个由字节值组成的 List,) and yBytes (一个由字节值组成的 List,) and returns 一个 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 ( typedArray, index, value )

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

  1. add 为一个新的读-改-写修改函数,带参数 (xBytes, yBytes),捕获 typedArray,并在被调用时以原子方式执行以下步骤:
    1. typeTypedArrayElementType(typedArray)。
    2. agentRecord 为周围 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(typedArray, index, value, add)。

25.4.5 Atomics.and ( typedArray, index, value )

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

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

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

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

  1. byteIndexInBuffer 为 ? ValidateAtomicAccessOnIntegerTypedArray(typedArray, index)。
  2. buffertypedArray.[[ViewedArrayBuffer]]
  3. blockbuffer.[[ArrayBufferData]]
  4. 如果 typedArray.[[ContentType]]bigint,则
    1. expected 为 ? ToBigInt(expectedValue)。
    2. replacement 为 ? ToBigInt(replacementValue)。
  5. 否则,
    1. expected𝔽(? ToIntegerOrInfinity(expectedValue))。
    2. replacement𝔽(? ToIntegerOrInfinity(replacementValue))。
  6. 执行 ? RevalidateAtomicAccess(typedArray, byteIndexInBuffer)。
  7. elementTypeTypedArrayElementType(typedArray)。
  8. elementSizeTypedArrayElementSize(typedArray)。
  9. agentRecord 为周围 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 ( typedArray, index, value )

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

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

25.4.8 Atomics.isLockFree ( size )

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

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

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

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

无论此函数返回的值是什么,所有原子操作都保证是原子的。例如,它们永远不会在操作中间发生可见操作(例如“撕裂”)。

25.4.9 Atomics.load ( typedArray, index )

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

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

25.4.10 Atomics.or ( typedArray, index, value )

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

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

25.4.11 Atomics.store ( typedArray, index, value )

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

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

25.4.12 Atomics.sub ( typedArray, index, value )

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

  1. subtract 为一个新的读-改-写修改函数,带参数 (xBytes, yBytes),捕获 typedArray,并在被调用时以原子方式执行以下步骤:
    1. typeTypedArrayElementType(typedArray)。
    2. agentRecord 为周围 agentAgent Record
    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(typedArray, index, value, subtract)。

25.4.13 Atomics.wait ( typedArray, index, value, timeout )

此函数将周围 agent 放入等待队列并将其挂起,直到收到通知或等待超时为止,并返回一个 String 来区分这些情况。

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

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

25.4.14 Atomics.waitAsync ( typedArray, index, value, timeout )

此函数返回一个 Promise,该 Promise 会在调用 agent 收到通知或到达 timeout 时被解决。

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

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

25.4.15 Atomics.notify ( typedArray, index, count )

此函数通知一些正在等待队列中休眠的 agents

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

  1. taRecord 为 ? ValidateIntegerTypedArray(typedArray, true)。
  2. byteIndexInBuffer 为 ? ValidateAtomicAccess(taRecord, index)。
  3. 如果 countundefined,则
    1. count 设置为 +∞。
  4. 否则,
    1. intCount 为 ? ToIntegerOrInfinity(count)。
    2. count 设置为 max(intCount, 0)。
  5. buffertypedArray.[[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. nwaiters 中元素的数量。
  14. 返回 𝔽(n)。

25.4.16 Atomics.xor ( typedArray, index, value )

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

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

25.4.17 Atomics [ %Symbol.toStringTag% ]

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

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

25.5 JSON 对象

JSON 对象:

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

JSON Data Interchange Format 在 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 Initializers 和 Object Initializers 语法的语法来表示字面量、数组和对象。解析之后,JSON 对象被实现为 ECMAScript 对象。JSON 数组被实现为 ECMAScript Array 实例。JSON 字符串、数字、布尔值和 null 被实现为 ECMAScript Strings、Numbers、Booleans 和 null

可选的 reviver 参数是一个可以过滤和转换结果的函数。对于 parse 产生的每个值,都会以三个参数(关联的属性键、该值和一个 context 对象)调用 reviver。如果属性未被修改且其值为 primitive,则所提供的 context 对象具有一个 "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 (一个 String,) and returns 要么是一个包含字段 [[ParseNode]](一个 Parse Node)和 [[Value]](一个 ECMAScript 语言值)的 Record正常完成,要么是一个抛出完成. 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. 断言:script 是一个 Parse 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 交换格式,它必须通过定义另一个 parse 函数来做到这一点。

Note 1

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

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

Note 2

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

25.5.2.2 JSON Parse Record

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

JSON Parse Records 具有 Table 75 中列出的字段。

Table 75: JSON Parse Record 字段
字段名 含义
[[ParseNode]] 一个 Parse Node context Parse Node。
[[Key]] 一个属性名 [[Value]] 相关联的属性名
[[Value]] 一个 ECMAScript 语言值 [[ParseNode]] 的求值产生的值。
[[Elements]] 一个由 JSON Parse Records 组成的 List 如果 [[Value]] 是一个 Array,则它包含与 [[Value]] 的元素相对应的 JSON Parse Records。否则,它是一个空 List
[[Entries]] 一个由 JSON Parse Records 组成的 List 如果 [[Value]] 是一个非 Array Object,则它包含与 [[Value]] 的 entries 相对应的 JSON Parse Records。否则,它是一个空 List

25.5.2.3 CreateJSONParseRecord ( parseNode, key, val )

The abstract operation CreateJSONParseRecord takes arguments parseNode (一个 Parse Node,), key (一个属性名,), and val (一个 ECMAScript 语言值,) and returns 一个 JSON Parse Record. 它递归地组合从 JSON 文本解析出的 parseNode 以及其求值产生的 val。 It performs the following steps when called:

  1. typedValNodeShallowestContainedJSONValue(parseNode)。
  2. 断言:typedValNode 不是 empty
  3. elements 为一个新的空 List
  4. entries 为一个新的空 List
  5. 如果 val 是一个 Object,则
    1. isArray 为 ! IsArray(val)。
    2. 如果 isArraytrue,则
      1. 断言:typedValNode 是一个 ArrayLiteral Parse Node。
      2. contentNodestypedValNodeJSONArrayLiteralContentNodes
      3. lencontentNodes 中元素的数量。
      4. valLen 为 ! LengthOfArrayLike(val)。
      5. 断言:valLenlen
      6. index 为 0。
      7. 重复,当 index < len 时,
        1. propName 为 ! ToString(𝔽(index))。
        2. elementParseRecordCreateJSONParseRecord(contentNodes[index], propName, ! Get(val, propName))。
        3. elementParseRecord 追加到 elements
        4. index 设置为 index + 1。
    3. 否则,
      1. 断言:typedValNode 是一个 ObjectLiteral Parse Node。
      2. propertyNodestypedValNodePropertyDefinitionNodes
      3. 注:因为 val 是从 JSON 文本产生且尚未被修改,所以它的所有属性键都是 Strings,并将被穷尽枚举。
      4. keys 为 ! EnumerableOwnProperties(val, key)。
      5. 对于 keys 的每个 String propertyKey,执行
        1. 注:在 JSON 文本为单个对象指定多个具有相同 name 的 name/value pairs(例如 {"a":"lost","a":"kept"})的情况下,结果 ECMAScript 对象对应属性的值由具有该 name 的最后一个 pair 指定。
        2. propertyDefinitionempty
        3. 对于 propertyNodes 的每个 Parse Node propertyNode,执行
          1. propNamepropertyNodePropName
          2. 如果 propNamepropertyKey,将 propertyDefinition 设置为 propertyNode
        4. 断言:propertyDefinition PropertyDefinition : PropertyName : AssignmentExpression
        5. propertyValueNodepropertyDefinitionAssignmentExpression
        6. entryParseRecordCreateJSONParseRecord(propertyValueNode, propertyKey, ! Get(val, propertyKey))。
        7. entryParseRecord 追加到 entries
  6. 否则,
    1. 断言:typedValNode 既不是 ArrayLiteral Parse Node,也不是 ObjectLiteral Parse Node。
  7. 返回 JSON Parse Record { [[ParseNode]]: typedValNode, [[Key]]: key, [[Value]]: val, [[Elements]]: elements, [[Entries]]: entries }。

25.5.2.4 InternalizeJSONProperty ( holder, name, reviver, parseRecord )

The abstract operation InternalizeJSONProperty takes arguments holder (一个 Object,), name (一个 String,), reviver (一个函数对象,), and parseRecord (一个 JSON Parse Recordempty,) and returns 要么是一个包含 ECMAScript 语言值正常完成,要么是一个抛出完成.

Note

如果 [[Delete]]CreateDataProperty 返回 false,此算法有意不抛出异常。

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

  1. val 为 ? Get(holder, name)。
  2. contextOrdinaryObjectCreate(%Object.prototype%)。
  3. 如果 parseRecord 是一个 JSON Parse RecordSameValue(parseRecord.[[Value]], val) 是 true,则
    1. 如果 val 不是 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. 如果 val 是一个 Object,则
    1. isArray 为 ? IsArray(val)。
    2. 如果 isArraytrue,则
      1. elementRecordsLenelementRecords 中元素的数量。
      2. len 为 ? LengthOfArrayLike(val)。
      3. index 为 0。
      4. 重复,当 index < len 时,
        1. propertyKey 为 ! ToString(𝔽(index))。
        2. 如果 index < elementRecordsLen,令 elementRecordelementRecords[index];否则令 elementRecordempty
        3. newElement 为 ? InternalizeJSONProperty(val, propertyKey, reviver, elementRecord)。
        4. 如果 newElementundefined,则
          1. 执行 ? val.[[Delete]](propertyKey)
        5. 否则,
          1. 执行 ? CreateDataProperty(val, propertyKey, newElement)。
        6. index 设置为 index + 1。
    3. 否则,
      1. keys 为 ? EnumerableOwnProperties(val, key)。
      2. 对于 keys 的每个 String propertyKey,执行
        1. 如果存在 entryRecords 的某个元素 entry 使得 entry.[[Key]]propertyKey,令 entryRecordentry;否则令 entryRecordempty
        2. newElement 为 ? InternalizeJSONProperty(val, propertyKey, reviver, entryRecord)。
        3. 如果 newElementundefined,则
          1. 执行 ? val.[[Delete]](propertyKey)
        4. 否则,
          1. 执行 ? CreateDataProperty(val, propertyKey, newElement)。
  6. 返回 ? Call(reviver, holder, « name, val, context »)。

25.5.2.5 Static Semantics: ShallowestContainedJSONValue ( root )

The abstract operation ShallowestContainedJSONValue takes argument root (一个 Parse Node,) and returns 一个 Parse Node 或 empty. 它对以 root 为根的 parse tree 执行广度优先搜索,并返回第一个属于对应 JSON value 的 nonterminal 实例的节点;如果没有这样的节点,则返回 empty。 It performs the following steps when called:

  1. activeFunc活动函数对象
  2. 断言:activeFunc 是一个 JSON.parse 内置函数对象(见 JSON.parse)。
  3. types 为 « NullLiteral, BooleanLiteral, NumericLiteral, StringLiteral, ArrayLiteral, ObjectLiteral, UnaryExpression »。
  4. unaryExpressionempty
  5. queue 为 « root »。
  6. 重复,当 queue 不是空时,
    1. candidatequeue 的第一个元素。
    2. queue 中移除第一个元素。
    3. queuedChildrenfalse
    4. 对于 types 的每个 nonterminal type,执行
      1. 如果 candidatetype 的一个实例,则
        1. 注:在 JSON 语法中,number token 可以表示一个负值。在 ECMAScript 中,取负表示为一元操作,其中 UnaryExpression 解析为 - 后跟一个派生的 UnaryExpression
        2. 如果 typeUnaryExpression,则
          1. 如果 candidate 的 parent 不是 UnaryExpression Parse Node,将 unaryExpression 设置为 candidate
        3. 否则如果 typeNumericLiteral,则
          1. 断言:candidate 包含于 unaryExpression 中。
          2. 返回 unaryExpression
        4. 否则,
          1. 返回 candidate
      2. 如果 queuedChildrenfalsecandidate 是一个 nonterminal 的实例,且 candidate Contains typetrue,则
        1. children 为一个包含 candidate 的每个子节点且按顺序排列的 List
        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 一个由 Parse Nodes 组成的 List. 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 的第一个 code unit 既不是 ASCII 小写字母 code unit(0x0061 到 0x007A,包含两端)、ASCII 数字 code unit(0x0030 到 0x0039,包含两端)、0x0022 (QUOTATION MARK),也不是 0x002D (HYPHEN-MINUS),抛出 SyntaxError 异常。
  4. 如果 jsonString 的最后一个 code unit 既不是 ASCII 小写字母 code unit(0x0061 到 0x007A,包含两端)、ASCII 数字 code unit(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 格式的 String,用于表示一个 ECMAScript 语言值;或者返回 undefined。它可以接受三个参数。value 参数是一个 ECMAScript 语言值,通常是对象或数组,不过也可以是 String、Boolean、Number 或 null。可选的 replacer 参数要么是一个改变对象和数组被字符串化方式的函数,要么是一个由 Strings 和 Numbers 组成的数组,该数组作为 inclusion list 来选择将被字符串化的对象属性。可选的 space 参数是一个 String 或 Number,它允许向结果中注入 white space,以提高人类可读性。

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

  1. stack 为一个新的空 List
  2. indent 为空 String。
  3. propertyListundefined
  4. replacerFunctionundefined
  5. 如果 replacer 是 Object,则
    1. 如果 IsCallable(replacer) 是 true,则
      1. replacerFunction 设置为 replacer
    2. 否则,
      1. isArray 为 ? IsArray(replacer)。
      2. 如果 isArraytrue,则
        1. propertyList 设置为一个新的空 List
        2. len 为 ? LengthOfArrayLike(replacer)。
        3. k 为 0。
        4. 重复,当 k < len 时,
          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 次 code unit 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]]: replacerFunction, [[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); // This must throw a TypeError.
Note 2

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

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

String 值被包裹在 QUOTATION MARK (") code units 中。code units "\ 会以 \ 前缀转义。控制字符 code units 会被替换为 escape sequences \uHHHH,或替换为较短形式 \b (BACKSPACE)、\f (FORM FEED)、\n (LINE FEED)、\r (CARRIAGE RETURN)、\t (CHARACTER TABULATION)。

Note 4

有限 numbers 会像调用 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 Records 具有 Table 76 中列出的字段。

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

25.5.4.2 SerializeJSONProperty ( state, key, holder )

The abstract operation SerializeJSONProperty takes arguments state (一个 JSON Serialization Record,), key (一个 String,), and holder (一个 Object,) and returns 要么是一个包含 String 或 undefined正常完成,要么是一个抛出完成. 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 (一个 String,) and returns 一个 String. 它用 0x0022 (QUOTATION MARK) code units 包裹 value,并转义其中的某些其他 code units。此操作按 6.1.4 中描述的方式,将 value 解释为一个 UTF-16 编码 code points 序列。 It performs the following steps when called:

  1. product 为仅由 code unit 0x0022 (QUOTATION MARK) 组成的 String 值。
  2. 对于 StringToCodePoints(value) 的每个 code point cp,执行
    1. 如果 cp 列于 Table 77 的 “Code Point” 列中,则
      1. product 设置为 product 与对应行 “Escape Sequence” 列中指定的 cp 的 escape sequence 的字符串拼接。
    2. 否则如果 cp 的数值小于 0x0020 (SPACE),或 cp 具有与 leading surrogate 或 trailing surrogate 相同的数值,则
      1. unit 为其数值等于 cp 数值的 code unit。
      2. product 设置为 productUnicodeEscape(unit) 的字符串拼接。
    3. 否则,
      1. product 设置为 productUTF16EncodeCodePoint(cp) 的字符串拼接。
  3. product 设置为 product 与 code unit 0x0022 (QUOTATION MARK) 的字符串拼接。
  4. 返回 product
Table 77: JSON 单字符转义序列
Code Point 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 ( constructor )

The abstract operation UnicodeEscape takes argument constructor (一个 code unit,) and returns 一个 String. 它将 constructor 表示为一个 Unicode escape sequence。 It performs the following steps when called:

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

25.5.4.5 SerializeJSONObject ( state, value )

The abstract operation SerializeJSONObject takes arguments state (一个 JSON Serialization Record,) and value (一个 Object,) and returns 要么是一个包含 String 的正常完成,要么是一个抛出完成. 它序列化一个对象。 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. strP 为 ? SerializeJSONProperty(state, propertyKey, value)。
    2. 如果 strP 不是 undefined,则
      1. memberQuoteJSONString(propertyKey)。
      2. member 设置为 member":" 的字符串拼接。
      3. 如果 state.[[Gap]] 不是空 String,则
        1. member 设置为 member 和 code unit 0x0020 (SPACE) 的字符串拼接。
      4. member 设置为 memberstrP 的字符串拼接。
      5. member 追加到 partial
  9. 如果 partial 为空,则
    1. final"{}"
  10. 否则,
    1. 如果 state.[[Gap]] 是空 String,则
      1. properties 为通过拼接 partial 中所有元素 Strings 形成的 String 值,相邻每对 Strings 之间以 code unit 0x002C (COMMA) 分隔。逗号既不会插入在第一个 String 之前,也不会插入在最后一个 String 之后。
      2. final"{"properties"}" 的字符串拼接。
    2. 否则,
      1. separator 为 code unit 0x002C (COMMA)、code unit 0x000A (LINE FEED) 和 state.[[Indent]] 的字符串拼接。
      2. properties 为通过拼接 partial 中所有元素 Strings 形成的 String 值,相邻每对 Strings 之间以 separator 分隔。separator String 既不会插入在第一个 String 之前,也不会插入在最后一个 String 之后。
      3. final"{"、code unit 0x000A (LINE FEED)、state.[[Indent]]properties、code unit 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. len 为 ? LengthOfArrayLike(value)。
  7. index 为 0。
  8. 重复,当 index < len 时,
    1. strP 为 ? SerializeJSONProperty(state, ! ToString(𝔽(index)), value)。
    2. 如果 strPundefined,则
      1. "null" 追加到 partial
    3. 否则,
      1. strP 追加到 partial
    4. index 设置为 index + 1。
  9. 如果 partial 为空,则
    1. final"[]"
  10. 否则,
    1. 如果 state.[[Gap]] 是空 String,则
      1. properties 为通过拼接 partial 中所有元素 Strings 形成的 String 值,相邻每对 Strings 之间以 code unit 0x002C (COMMA) 分隔。逗号既不会插入在第一个 String 之前,也不会插入在最后一个 String 之后。
      2. final"["properties"]" 的字符串拼接。
    2. 否则,
      1. separator 为 code unit 0x002C (COMMA)、code unit 0x000A (LINE FEED) 和 state.[[Indent]] 的字符串拼接。
      2. properties 为通过拼接 partial 中所有元素 Strings 形成的 String 值,相邻每对 Strings 之间以 separator 分隔。separator String 既不会插入在第一个 String 之前,也不会插入在最后一个 String 之后。
      3. final"["、code unit 0x000A (LINE FEED)、state.[[Indent]]properties、code unit 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 }。