页面模式偏好

25 结构化数据

25.1 ArrayBuffer 对象

25.1.1 记号

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

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

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

为了帮助验证读-修改-写修改函数的算法步骤构成纯数学函数,建议遵循以下编辑约定:

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

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

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

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

25.1.3 ArrayBuffer 对象的抽象操作

25.1.3.1 AllocateArrayBuffer ( ctor, byteLength [ , maxByteLength ] )

抽象操作 AllocateArrayBuffer,接收参数 ctor (构造函数) 和 byteLength (非负整数)和可选参数 maxByteLength ((非负整数 或 empty));返回值:(正常完成 (值:ArrayBuffer) 或 抛出完成)。 它用于创建 ArrayBuffer。 调用时执行以下步骤:

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

25.1.3.2 ArrayBufferByteLength ( arrayBuffer, order )

抽象操作 ArrayBufferByteLength,接收参数 arrayBuffer ((ArrayBuffer 或 SharedArrayBuffer)) 和 order ((seq-cst 或 unordered));返回值:非负整数。 调用时执行以下步骤:

  1. 如果 IsGrowableSharedArrayBuffer(arrayBuffer) 是 true,则
    1. 令 bufferByteLengthBlock 为 arrayBuffer.[[ArrayBufferByteLengthData]]。
    2. 令 rawLength 为 GetRawBytesFromSharedBlock(bufferByteLengthBlock, 0, biguint64, true, order)。
    3. 令 agentRecord 为周围代理的 Agent Record。
    4. 令 isLittleEndian 为 agentRecord.[[LittleEndian]]。
    5. 返回 ℝ(RawBytesToNumeric(biguint64, rawLength, isLittleEndian))。
  2. 断言:IsDetachedBuffer(arrayBuffer) 是 false。
  3. 返回 arrayBuffer.[[ArrayBufferByteLength]]。

25.1.3.3 ArrayBufferCopyAndDetach ( arrayBuffer, newLength, preserveResizability )

抽象操作 ArrayBufferCopyAndDetach,接收参数 arrayBuffer (ECMAScript 语言值)、newLength (ECMAScript 语言值) 和 preserveResizability ((preserve-resizability 或 fixed-length));返回值:(正常完成 (值:ArrayBuffer) 或 抛出完成)。 调用时执行以下步骤:

  1. 执行 ? RequireInternalSlot(arrayBuffer, [[ArrayBufferData]])。
  2. 如果 IsSharedArrayBuffer(arrayBuffer) 是 true,则抛出 TypeError 异常。
  3. 如果 newLength 是 undefined,则
    1. 令 newByteLength 为 arrayBuffer.[[ArrayBufferByteLength]]。
  4. 否则,
    1. 令 newByteLength 为 ? ToIndex(newLength)。
  5. 如果 IsDetachedBuffer(arrayBuffer) 是 true,则抛出 TypeError 异常。
  6. 如果 preserveResizability 是 preserve-resizability 且 IsFixedLengthArrayBuffer(arrayBuffer) 是 false,则
    1. 令 newMaxByteLength 为 arrayBuffer.[[ArrayBufferMaxByteLength]]。
  7. 否则,
    1. 令 newMaxByteLength 为 empty。
  8. 如果 arrayBuffer.[[ArrayBufferDetachKey]] 不是 undefined,则抛出 TypeError 异常。
  9. 令 newBuffer 为 ? AllocateArrayBuffer(%ArrayBuffer%, newByteLength, newMaxByteLength)。
  10. 令 copyLength 为 min(newByteLength, arrayBuffer.[[ArrayBufferByteLength]])。
  11. 令 fromBlock 为 arrayBuffer.[[ArrayBufferData]]。
  12. 令 toBlock 为 newBuffer.[[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 )

抽象操作 IsDetachedBuffer,接收参数 arrayBuffer ((ArrayBuffer 或 SharedArrayBuffer));返回值:Boolean。 调用时执行以下步骤:

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

25.1.3.5 DetachArrayBuffer ( arrayBuffer [ , key ] )

抽象操作 DetachArrayBuffer,接收参数 arrayBuffer (ArrayBuffer)和可选参数 key (任意值);返回值:(正常完成 (值:unused) 或 抛出完成)。 调用时执行以下步骤:

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

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

25.1.3.6 CloneArrayBuffer ( sourceBuffer, sourceByteOffset, sourceLength )

抽象操作 CloneArrayBuffer,接收参数 sourceBuffer ((ArrayBuffer 或 SharedArrayBuffer))、sourceByteOffset (非负整数) 和 sourceLength (非负整数);返回值:(正常完成 (值:ArrayBuffer) 或 抛出完成)。 它创建一个新的 ArrayBuffer,其数据是 sourceBuffer 数据中从 sourceByteOffset 开始并持续 sourceLength 个字节范围的副本。 调用时执行以下步骤:

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

25.1.3.7 GetArrayBufferMaxByteLengthOption ( options )

抽象操作 GetArrayBufferMaxByteLengthOption,接收参数 options (ECMAScript 语言值);返回值:(正常完成 (值:(非负整数 或 empty)) 或 抛出完成)。 调用时执行以下步骤:

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

25.1.3.8 HostResizeArrayBuffer ( buffer, newByteLength )

宿主定义的抽象操作 HostResizeArrayBuffer,接收参数 buffer (ArrayBuffer) 和 newByteLength (非负整数);返回值:(正常完成 (值:(handled 或 unhandled)) 或 抛出完成)。 它为宿主提供执行由实现定义的 buffer 大小调整的机会。如果宿主选择不处理 buffer 的大小调整,则可以返回 unhandled 以使用默认行为。

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

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

25.1.3.9 IsFixedLengthArrayBuffer ( arrayBuffer )

抽象操作 IsFixedLengthArrayBuffer,接收参数 arrayBuffer ((ArrayBuffer 或 SharedArrayBuffer));返回值:Boolean。 调用时执行以下步骤:

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

25.1.3.10 IsUnsignedElementType ( type )

抽象操作 IsUnsignedElementType,接收参数 type (TypedArray 元素类型);返回值:Boolean。 它验证参数 type 是否为无符号 TypedArray 元素类型。 调用时执行以下步骤:

  1. 如果 type 是 uint8、uint8clamped、uint16、uint32 或 biguint64 之一,则返回 true。
  2. 返回 false。

25.1.3.11 IsUnclampedIntegerElementType ( type )

抽象操作 IsUnclampedIntegerElementType,接收参数 type (TypedArray 元素类型);返回值:Boolean。 它验证参数 type 是否为不包括 uint8clamped 的整数 TypedArray 元素类型。 调用时执行以下步骤:

  1. 如果 type 是 int8、uint8、int16、uint16、int32 或 uint32 之一,则返回 true。
  2. 返回 false。

25.1.3.12 IsBigIntElementType ( type )

抽象操作 IsBigIntElementType,接收参数 type (TypedArray 元素类型);返回值:Boolean。 它验证参数 type 是否为 BigInt TypedArray 元素类型。 调用时执行以下步骤:

  1. 如果 type 是 biguint64 或 bigint64,则返回 true。
  2. 返回 false。

25.1.3.13 IsNoTearConfiguration ( type, order )

抽象操作 IsNoTearConfiguration,接收参数 type (TypedArray 元素类型) 和 order ((seq-cst、unordered 或 init));返回值:Boolean。 调用时执行以下步骤:

  1. 如果 IsUnclampedIntegerElementType(type) 是 true,则返回 true。
  2. 如果 IsBigIntElementType(type) 是 true 且 order 是 seq-cst,则返回 true。
  3. 返回 false。

25.1.3.14 RawBytesToNumeric ( type, rawBytes, isLittleEndian )

抽象操作 RawBytesToNumeric,接收参数 type (TypedArray 元素类型)、rawBytes (列表 (元素:字节值)) 和 isLittleEndian (Boolean);返回值:(Number 或 BigInt)。 调用时执行以下步骤:

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

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

抽象操作 GetRawBytesFromSharedBlock,接收参数 block (共享数据块)、byteIndex (非负整数)、type (TypedArray 元素类型)、isTypedArray (Boolean) 和 order ((seq-cst 或 unordered));返回值:列表 (元素:字节值)。 调用时执行以下步骤:

  1. 令 elementSize 为 表 71 中为 Element Type type 指定的 Element Size 值。
  2. 令 agentRecord 为周围代理的 Agent Record。
  3. 令 execution 为 agentRecord.[[CandidateExecution]]。
  4. 令 eventsRecord 为 execution.[[EventsRecords]] 中 [[AgentSignifier]] 为 AgentSignifier() 的 Agent Events Record。
  5. 如果 isTypedArray 是 true 且 IsNoTearConfiguration(type, order) 是 true,则令 noTear 为 true;否则令 noTear 为 false。
  6. 令 rawValue 为长度为 elementSize 的 List,其元素是非确定性选择的字节值。
  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 ] )

抽象操作 GetValueFromBuffer,接收参数 arrayBuffer ((ArrayBuffer 或 SharedArrayBuffer))、byteIndex (非负整数)、type (TypedArray 元素类型)、isTypedArray (Boolean) 和 order ((seq-cst 或 unordered))和可选参数 isLittleEndian (Boolean);返回值:(Number 或 BigInt)。 调用时执行以下步骤:

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

25.1.3.17 NumericToRawBytes ( type, value, isLittleEndian )

抽象操作 NumericToRawBytes,接收参数 type (TypedArray 元素类型)、value ((Number 或 BigInt)) 和 isLittleEndian (Boolean);返回值:列表 (元素:字节值)。 调用时执行以下步骤:

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

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

抽象操作 SetValueInBuffer,接收参数 arrayBuffer ((ArrayBuffer 或 SharedArrayBuffer))、byteIndex (非负整数)、type (TypedArray 元素类型)、value ((Number 或 BigInt))、isTypedArray (Boolean) 和 order ((seq-cst、unordered 或 init))和可选参数 isLittleEndian (Boolean);返回值:unused。 调用时执行以下步骤:

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

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

抽象操作 GetModifySetValueInBuffer,接收参数 arrayBuffer ((ArrayBuffer 或 SharedArrayBuffer))、byteIndex (非负整数)、type (TypedArray 元素类型)、value ((Number 或 BigInt)) 和 op (a read-modify-write modification function);返回值:(Number 或 BigInt)。 调用时执行以下步骤:

  1. 断言:IsDetachedBuffer(arrayBuffer) 是 false。
  2. 断言:arrayBuffer 中从 byteIndex 开始有足够的字节来表示 type 的值。
  3. 断言:如果 IsBigIntElementType(type) 是 true,则 value 是 BigInt;否则,value 是 Number。
  4. 令 block 为 arrayBuffer.[[ArrayBufferData]]。
  5. 令 elementSize 为 表 71 中为 Element Type type 指定的 Element Size 值。
  6. 令 agentRecord 为周围代理的 Agent Record。
  7. 令 isLittleEndian 为 agentRecord.[[LittleEndian]]。
  8. 令 rawBytes 为 NumericToRawBytes(type, value, isLittleEndian)。
  9. 如果 IsSharedArrayBuffer(arrayBuffer) 是 true,则
    1. 令 execution 为 agentRecord.[[CandidateExecution]]。
    2. 令 eventsRecord 为 execution.[[EventsRecords]] 中 [[AgentSignifier]] 为 AgentSignifier() 的 Agent Events Record。
    3. 令 rawBytesRead 为长度为 elementSize 的 List,其元素是非确定性选择的字节值。
    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 为长度为 elementSize 的 List,其元素是从 block[byteIndex] 开始的 elementSize 个字节序列。
    2. 令 rawBytesModified 为 op(rawBytesRead, rawBytes)。
    3. 从 block[byteIndex] 开始,将 rawBytesModified 的各个字节存储到 block 中。
  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 value。

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

注

ArrayBuffer.prototype.slice ( start, end ) 通常使用其 this value 的构造函数创建派生对象。不过,子类构造函数可以通过重新定义其 %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. 令 obj 为 this value。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 true,则抛出 TypeError 异常。
  4. 如果 IsDetachedBuffer(obj) 是 true,则返回 +0𝔽。
  5. 令 length 为 obj.[[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. 令 obj 为 this value。
  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. 令 obj 为 this value。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 true,则抛出 TypeError 异常。
  4. 如果 IsDetachedBuffer(obj) 是 true,则返回 +0𝔽。
  5. 如果 IsFixedLengthArrayBuffer(obj) 是 true,则
    1. 令 length 为 obj.[[ArrayBufferByteLength]]。
  6. 否则,
    1. 令 length 为 obj.[[ArrayBufferMaxByteLength]]。
  7. 返回 𝔽(length)。

25.1.6.5 get ArrayBuffer.prototype.resizable

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

  1. 令 obj 为 this value。
  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. 令 obj 为 this value。
  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. 如果 hostHandled 是 handled,则返回 undefined。
  9. 令 oldBlock 为 obj.[[ArrayBufferData]]。
  10. 令 newBlock 为 ? CreateByteDataBlock(newByteLength)。
  11. 令 copyLength 为 min(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. 令 obj 为 this value。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 true,则抛出 TypeError 异常。
  4. 如果 IsDetachedBuffer(obj) 是 true,则抛出 TypeError 异常。
  5. 令 length 为 obj.[[ArrayBufferByteLength]]。
  6. 令 first 为 ? ToClampedIndex(start, length)。
  7. 如果 end 是 undefined,则令 final 为 length;否则令 final 为 ? ToClampedIndex(end, length)。
  8. 令 newLength 为 max(final - first, 0)。
  9. 令 ctor 为 ? SpeciesConstructor(obj, %ArrayBuffer%)。
  10. 令 new 为 ? Construct(ctor, « 𝔽(newLength) »)。
  11. 执行 ? RequireInternalSlot(new, [[ArrayBufferData]])。
  12. 如果 IsSharedArrayBuffer(new) 是 true,则抛出 TypeError 异常。
  13. 如果 IsDetachedBuffer(new) 是 true,则抛出 TypeError 异常。
  14. 如果 SameValue(new, obj) 是 true,则抛出 TypeError 异常。
  15. 如果 new.[[ArrayBufferByteLength]] < newLength,则抛出 TypeError 异常。
  16. 注:上述步骤的副作用可能已经分离或调整了 obj 的大小。
  17. 如果 IsDetachedBuffer(obj) 是 true,则抛出 TypeError 异常。
  18. 令 fromBlock 为 obj.[[ArrayBufferData]]。
  19. 令 toBlock 为 new.[[ArrayBufferData]]。
  20. 令 currentLength 为 obj.[[ArrayBufferByteLength]]。
  21. 令 maxCount 为 currentLength - first。
  22. 如果 maxCount > 0,则
    1. 令 count 为 min(newLength, maxCount)。
    2. 执行 CopyDataBlockBytes(toBlock, 0, fromBlock, first, count)。
  23. 返回 new。

25.1.6.8 ArrayBuffer.prototype.transfer ( [ newLength ] )

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

  1. 令 obj 为 this value。
  2. 返回 ? ArrayBufferCopyAndDetach(obj, newLength, preserve-resizability)。

25.1.6.9 ArrayBuffer.prototype.transferToFixedLength ( [ newLength ] )

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

  1. 令 obj 为 this value。
  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 调用都将同一个“分离键”作为参数传递,否则会产生 TypeError。此内部槽仅由某些嵌入环境设置,而不会由本规范中的算法设置。

25.1.8 可调整大小 ArrayBuffer 指南

注 1

以下是供使用可调整大小 ArrayBuffer 的 ECMAScript 程序员参考的指南。

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

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

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

注 2

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

可调整大小 ArrayBuffer 可以通过调整大小时进行复制、通过预先保留虚拟内存实现原地增长,或者针对构造函数 "maxByteLength" 选项的不同值结合使用这两种方式来实现。

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

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

25.2 SharedArrayBuffer 对象

25.2.1 固定长度和可增长的 SharedArrayBuffer 对象

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

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

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

25.2.2 SharedArrayBuffer 对象的抽象操作

25.2.2.1 AllocateSharedArrayBuffer ( ctor, byteLength [ , maxByteLength ] )

抽象操作 AllocateSharedArrayBuffer,接收参数 ctor (构造函数) 和 byteLength (非负整数)和可选参数 maxByteLength ((非负整数 或 empty));返回值:(正常完成 (值:SharedArrayBuffer) 或 抛出完成)。 它用于创建 SharedArrayBuffer。 调用时执行以下步骤:

  1. 令 slots 为 « [[ArrayBufferData]] »。
  2. 如果存在 maxByteLength 且 maxByteLength 不是 empty,则令 allocatingGrowableBuffer 为 true;否则令 allocatingGrowableBuffer 为 false。
  3. 如果 allocatingGrowableBuffer 是 true,则
    1. 如果 byteLength > maxByteLength,则抛出 RangeError 异常。
    2. 将 [[ArrayBufferByteLengthData]] 和 [[ArrayBufferMaxByteLength]] 追加到 slots。
  4. 否则,
    1. 将 [[ArrayBufferByteLength]] 追加到 slots。
  5. 令 obj 为 ? OrdinaryCreateFromConstructor(ctor, "%SharedArrayBuffer.prototype%", slots)。
  6. 如果 allocatingGrowableBuffer 是 true,则令 allocationLength 为 maxByteLength;否则令 allocationLength 为 byteLength。
  7. 令 block 为 ? CreateSharedByteDataBlock(allocationLength)。
  8. 将 obj.[[ArrayBufferData]] 设置为 block。
  9. 如果 allocatingGrowableBuffer 是 true,则
    1. 断言:byteLength ≤ maxByteLength。
    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 )

抽象操作 IsSharedArrayBuffer,接收参数 obj ((ArrayBuffer 或 SharedArrayBuffer));返回值:Boolean。 它测试对象是否为 SharedArrayBuffer。 调用时执行以下步骤:

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

25.2.2.3 IsGrowableSharedArrayBuffer ( obj )

抽象操作 IsGrowableSharedArrayBuffer,接收参数 obj ((ArrayBuffer 或 SharedArrayBuffer));返回值:Boolean。 它测试对象是否为可增长的 SharedArrayBuffer。 调用时执行以下步骤:

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

25.2.2.4 HostGrowSharedArrayBuffer ( buffer, newByteLength )

宿主定义的抽象操作 HostGrowSharedArrayBuffer,接收参数 buffer (SharedArrayBuffer) 和 newByteLength (非负整数);返回值:(正常完成 (值:(handled 或 unhandled)) 或 抛出完成)。 它为宿主提供执行由实现定义的 buffer 增长的机会。如果宿主选择不处理 buffer 的增长,则可以返回 unhandled 以使用默认行为。

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

注

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

这与 HostResizeArrayBuffer 不同,后者保证 0 ≤ newByteLength ≤ buffer.[[ArrayBufferMaxByteLength]]。

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

25.2.3 SharedArrayBuffer 构造函数

SharedArrayBuffer 构造函数:

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

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

注

与 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 value。

此函数的 "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. 令 obj 为 this value。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 false,则抛出 TypeError 异常。
  4. 令 length 为 ArrayBufferByteLength(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. 令 obj 为 this value。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferMaxByteLength]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 false,则抛出 TypeError 异常。
  4. 令 newByteLength 为 ? ToIndex(newLength)。
  5. 令 hostHandled 为 ? HostGrowSharedArrayBuffer(obj, newByteLength)。
  6. 如果 hostHandled 是 handled,则返回 undefined。
  7. 令 agentRecord 为周围代理的 Agent Record。
  8. 令 isLittleEndian 为 agentRecord.[[LittleEndian]]。
  9. 令 byteLengthBlock 为 obj.[[ArrayBufferByteLengthData]]。
  10. 令 currentByteLengthRawBytes 为 GetRawBytesFromSharedBlock(byteLengthBlock, 0, biguint64, true, seq-cst)。
  11. 令 newByteLengthRawBytes 为 NumericToRawBytes(biguint64, ℤ(newByteLength), isLittleEndian)。
  12. 重复执行,
    1. 注:这是一个比较并交换循环,用于确保对同一缓冲区的并行、竞争增长操作具有全序、不会丢失,也不会悄无声息地不执行任何操作。如果它能够在没有竞争的情况下尝试增长,则循环退出。
    2. 令 currentByteLength 为 ℝ(RawBytesToNumeric(biguint64, currentByteLengthRawBytes, isLittleEndian))。
    3. 如果 newByteLength = currentByteLength,则返回 undefined。
    4. 如果 newByteLength < currentByteLength 或 newByteLength > obj.[[ArrayBufferMaxByteLength]],则抛出 RangeError 异常。
    5. 令 byteLengthDelta 为 newByteLength - currentByteLength。
    6. 如果无法创建由 byteLengthDelta 个字节组成的新 Shared Data Block 值,则抛出 RangeError 异常。
    7. 注:这里不会构造和使用新的 Shared Data Block。可增长 SharedArrayBuffer 的可观察行为通过在构造时分配最大大小的 Shared Data Block 来规定,而此步骤体现了实现耗尽内存时必须抛出 RangeError 的要求。
    8. 令 readByteLengthRawBytes 为 AtomicCompareExchangeInSharedBlock(byteLengthBlock, 0, 8, currentByteLengthRawBytes, newByteLengthRawBytes)。
    9. 如果 ByteListEqual(readByteLengthRawBytes, currentByteLengthRawBytes) 是 true,则返回 undefined。
    10. 将 currentByteLengthRawBytes 设置为 readByteLengthRawBytes。
注

禁止比较交换更新长度时出现虚假失败。如果新长度的边界检查通过且实现未耗尽内存,则始终会向候选执行中添加一个 ReadModifyWriteSharedMemory 事件(即成功的比较交换)。

对 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. 令 obj 为 this value。
  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. 令 obj 为 this value。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 false,则抛出 TypeError 异常。
  4. 如果 IsFixedLengthArrayBuffer(obj) 是 true,则
    1. 令 length 为 obj.[[ArrayBufferByteLength]]。
  5. 否则,
    1. 令 length 为 obj.[[ArrayBufferMaxByteLength]]。
  6. 返回 𝔽(length)。

25.2.5.6 SharedArrayBuffer.prototype.slice ( start, end )

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

  1. 令 obj 为 this value。
  2. 执行 ? RequireInternalSlot(obj, [[ArrayBufferData]])。
  3. 如果 IsSharedArrayBuffer(obj) 是 false,则抛出 TypeError 异常。
  4. 令 length 为 ArrayBufferByteLength(obj, seq-cst)。
  5. 令 first 为 ? ToClampedIndex(start, length)。
  6. 如果 end 是 undefined,则令 final 为 length;否则令 final 为 ? ToClampedIndex(end, length)。
  7. 令 newLength 为 max(final - first, 0)。
  8. 令 ctor 为 ? SpeciesConstructor(obj, %SharedArrayBuffer%)。
  9. 令 new 为 ? Construct(ctor, « 𝔽(newLength) »)。
  10. 执行 ? RequireInternalSlot(new, [[ArrayBufferData]])。
  11. 如果 IsSharedArrayBuffer(new) 是 false,则抛出 TypeError 异常。
  12. 如果 new.[[ArrayBufferData]] 是 obj.[[ArrayBufferData]],则抛出 TypeError 异常。
  13. 如果 ArrayBufferByteLength(new, seq-cst) < newLength,则抛出 TypeError 异常。
  14. 令 fromBlock 为 obj.[[ArrayBufferData]]。
  15. 令 toBlock 为 new.[[ArrayBufferData]]。
  16. 执行 CopyDataBlockBytes(toBlock, 0, fromBlock, first, newLength)。
  17. 返回 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]] 内部槽。

注

与 ArrayBuffer 实例不同,SharedArrayBuffer 实例永远不会被分离。

25.2.7 可增长 SharedArrayBuffer 指南

注 1

以下是供使用可增长 SharedArrayBuffer 的 ECMAScript 程序员参考的指南。

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

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

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

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

注 2

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

建议通过预先保留虚拟内存实现原地增长的方式实现可增长 SharedArrayBuffer。

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

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

可增长 SharedArrayBuffer 的 TypedArray 视图上的整数索引属性访问,应当能够像不可增长 SharedArrayBuffer 的 TypedArray 视图上的访问一样进行优化,因为整数索引属性加载不会在底层缓冲区的长度上进行同步(参见上面的程序员指南)。例如,属性访问的边界检查仍然可以提升到循环之外。

在没有虚拟内存的宿主上,例如运行在没有 MMU 的嵌入式设备上的宿主,实际上很难通过复制实现可增长 SharedArrayBuffer。此类宿主上可增长 SharedArrayBuffer 的内存使用行为可能与具有虚拟内存的宿主有显著差异。此类宿主应向用户明确说明内存使用预期。

25.3 DataView 对象

25.3.1 DataView 对象的抽象操作

25.3.1.1 DataView With Buffer Witness Record

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

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

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

25.3.1.2 MakeDataViewWithBufferWitnessRecord ( obj, order )

抽象操作 MakeDataViewWithBufferWitnessRecord,接收参数 obj (DataView) 和 order ((seq-cst 或 unordered));返回值:DataView With Buffer Witness 记录。 调用时执行以下步骤:

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

25.3.1.3 GetViewByteLength ( viewRecord )

抽象操作 GetViewByteLength,接收参数 viewRecord (DataView With Buffer Witness 记录);返回值:非负整数。 调用时执行以下步骤:

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

25.3.1.4 IsViewOutOfBounds ( viewRecord )

抽象操作 IsViewOutOfBounds,接收参数 viewRecord (DataView With Buffer Witness 记录);返回值:Boolean。 调用时执行以下步骤:

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

25.3.1.5 GetViewValue ( view, requestIndex, isLittleEndian, type )

抽象操作 GetViewValue,接收参数 view (ECMAScript 语言值)、requestIndex (ECMAScript 语言值)、isLittleEndian (ECMAScript 语言值) 和 type (TypedArray 元素类型);返回值:(正常完成 (值:(Number 或 BigInt)) 或 抛出完成)。 它由 DataView 实例上的函数使用,以从视图的缓冲区中检索值。 调用时执行以下步骤:

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

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

抽象操作 SetViewValue,接收参数 view (ECMAScript 语言值)、requestIndex (ECMAScript 语言值)、isLittleEndian (ECMAScript 语言值)、type (TypedArray 元素类型) 和 value (ECMAScript 语言值);返回值:(正常完成 (值:unused) 或 抛出完成)。 它由 DataView 实例上的函数使用,以将值存储到视图的缓冲区中。 调用时执行以下步骤:

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

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. 令 bufferByteLength 为 ArrayBufferByteLength(buffer, seq-cst)。
  6. 如果 offset > bufferByteLength,则抛出 RangeError 异常。
  7. 令 bufferIsFixedLength 为 IsFixedLengthArrayBuffer(buffer)。
  8. 如果 byteLength 是 undefined,则
    1. 如果 bufferIsFixedLength 是 true,则
      1. 令 viewByteLength 为 bufferByteLength - offset。
    2. 否则,
      1. 令 viewByteLength 为 auto。
  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. 令 obj 为 this value。
  2. 执行 ? RequireInternalSlot(obj, [[DataView]])。
  3. 断言:obj 具有 [[ViewedArrayBuffer]] 内部槽。
  4. 令 buffer 为 obj.[[ViewedArrayBuffer]]。
  5. 返回 buffer。

25.3.4.2 get DataView.prototype.byteLength

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

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

25.3.4.3 get DataView.prototype.byteOffset

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

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

25.3.4.4 DataView.prototype.constructor

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

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

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

  1. 令 view 为 this value。
  2. 返回 ? GetViewValue(view, byteOffset, littleEndian, bigint64)。

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

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

  1. 令 view 为 this value。
  2. 返回 ? GetViewValue(view, byteOffset, littleEndian, biguint64)。

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

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

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

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

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

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

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

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

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

25.3.4.10 DataView.prototype.getInt8 ( byteOffset )

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

  1. 令 view 为 this value。
  2. 返回 ? GetViewValue(view, byteOffset, true, int8)。

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

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

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

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

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

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

25.3.4.13 DataView.prototype.getUint8 ( byteOffset )

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

  1. 令 view 为 this value。
  2. 返回 ? GetViewValue(view, byteOffset, true, uint8)。

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

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

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

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

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

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

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

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

  1. 令 view 为 this value。
  2. 执行 ? SetViewValue(view, byteOffset, littleEndian, bigint64, value)。
  3. 返回 undefined。

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

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

  1. 令 view 为 this value。
  2. 执行 ? SetViewValue(view, byteOffset, littleEndian, biguint64, value)。
  3. 返回 undefined。

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

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

  1. 令 view 为 this value。
  2. 如果不存在 littleEndian,则将 littleEndian 设置为 false。
  3. 执行 ? SetViewValue(view, byteOffset, littleEndian, float16, value)。
  4. 返回 undefined。

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

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

  1. 令 view 为 this value。
  2. 如果不存在 littleEndian,则将 littleEndian 设置为 false。
  3. 执行 ? SetViewValue(view, byteOffset, littleEndian, float32, value)。
  4. 返回 undefined。

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

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

  1. 令 view 为 this value。
  2. 如果不存在 littleEndian,则将 littleEndian 设置为 false。
  3. 执行 ? SetViewValue(view, byteOffset, littleEndian, float64, value)。
  4. 返回 undefined。

25.3.4.21 DataView.prototype.setInt8 ( byteOffset, value )

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

  1. 令 view 为 this value。
  2. 执行 ? SetViewValue(view, byteOffset, true, int8, value)。
  3. 返回 undefined。

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

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

  1. 令 view 为 this value。
  2. 如果不存在 littleEndian,则将 littleEndian 设置为 false。
  3. 执行 ? SetViewValue(view, byteOffset, littleEndian, int16, value)。
  4. 返回 undefined。

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

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

  1. 令 view 为 this value。
  2. 如果不存在 littleEndian,则将 littleEndian 设置为 false。
  3. 执行 ? SetViewValue(view, byteOffset, littleEndian, int32, value)。
  4. 返回 undefined。

25.3.4.24 DataView.prototype.setUint8 ( byteOffset, value )

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

  1. 令 view 为 this value。
  2. 执行 ? SetViewValue(view, byteOffset, true, uint8, value)。
  3. 返回 undefined。

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

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

  1. 令 view 为 this value。
  2. 如果不存在 littleEndian,则将 littleEndian 设置为 false。
  3. 执行 ? SetViewValue(view, byteOffset, littleEndian, uint16, value)。
  4. 返回 undefined。

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

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

  1. 令 view 为 this value。
  2. 如果不存在 littleEndian,则将 littleEndian 设置为 false。
  3. 执行 ? SetViewValue(view, byteOffset, littleEndian, uint32, value)。
  4. 返回 undefined。

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]] 内部槽。

注

本规范中不使用 [[DataView]] 内部槽的值。在规范中,仅通过该内部槽的存在来识别使用 DataView 构造函数创建的对象。

25.4 Atomics 对象

Atomics 对象:

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

Atomics 对象提供以不可分割方式(原子方式)操作共享内存数组单元的函数,以及允许代理等待和分派原始事件的函数。如果正确使用,Atomics 函数允许通过共享内存通信的多代理程序,即使在并行 CPU 上也能以明确可理解的顺序执行。控制共享内存通信的规则由下文定义的内存模型提供。

注

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

25.4.1 Waiter Record

Waiter Record 是用于表示对 Atomics.wait 或 Atomics.waitAsync 的某次特定调用的 Record。

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

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

25.4.2 WaiterList Record

WaiterList Record 用于说明通过 Atomics.wait、Atomics.waitAsync 和 Atomics.notify 等待和通知代理。

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

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

一个 WaiterList 中可以有多个具有相同代理标识符的 Waiter Record。

代理集群具有一个 WaiterList Record 存储;该存储由 (block, i) 索引,其中 block 是 Shared Data Block,i 是 block 内存中的字节偏移量。WaiterList Record 与代理无关:在代理集群中的任何代理中,通过 (block, i) 在 WaiterList Record 存储中查找都会得到同一个 WaiterList Record。

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

25.4.3 Atomics 的抽象操作

25.4.3.1 ValidateIntegerTypedArray ( ta, waitable )

抽象操作 ValidateIntegerTypedArray,接收参数 ta (ECMAScript 语言值) 和 waitable (Boolean);返回值:(正常完成 (值:TypedArray With Buffer Witness 记录) 或 抛出完成)。 它用于约束可与 %Atomics% 函数一起使用的 TypedArray,尤其是能够保证与共享内存进行原子交互的 TypedArray。 调用时执行以下步骤:

  1. 注:当 ta 的后备缓冲区是可增长 SharedArrayBuffer 时,边界检查不是同步操作。
  2. 令 taRecord 为 ? ValidateTypedArray(ta, unordered)。
  3. 令 elementType 为 TypedArrayElementType(ta)。
  4. 如果 IsNoTearConfiguration(elementType, seq-cst) 是 false,则抛出 TypeError 异常。
  5. 如果 waitable 是 true 且 elementType 既不是 int32 也不是 bigint64,则抛出 TypeError 异常。
  6. 返回 taRecord。

25.4.3.2 ValidateAtomicAccess ( taRecord, requestIndex )

抽象操作 ValidateAtomicAccess,接收参数 taRecord (TypedArray With Buffer Witness 记录) 和 requestIndex (ECMAScript 语言值);返回值:(正常完成 (值:非负整数) 或 抛出完成)。 调用时执行以下步骤:

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

25.4.3.3 ValidateAtomicAccessOnIntegerTypedArray ( ta, requestIndex )

抽象操作 ValidateAtomicAccessOnIntegerTypedArray,接收参数 ta (ECMAScript 语言值) 和 requestIndex (ECMAScript 语言值);返回值:(正常完成 (值:非负整数) 或 抛出完成)。 调用时执行以下步骤:

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

25.4.3.4 RevalidateAtomicAccess ( ta, byteIndexInBuffer )

抽象操作 RevalidateAtomicAccess,接收参数 ta (TypedArray) 和 byteIndexInBuffer (非负整数);返回值:(正常完成 (值:unused) 或 抛出完成)。 此操作在 Atomics 方法中完成所有参数强制转换之后,重新验证原子操作在后备缓冲区中的索引,因为参数强制转换可能具有任意副作用,从而可能导致缓冲区越界。当 ta 的后备缓冲区是 SharedArrayBuffer 时,此操作不会抛出异常。 调用时执行以下步骤:

  1. 注意:当 ta 的后备缓冲区是可增长的 SharedArrayBuffer 时,边界检查不是同步操作。
  2. 令 taRecord 为 ? ValidateTypedArrayBounds(ta, unordered)。
  3. 断言:byteIndexInBuffer ≥ ta.[[ByteOffset]]。
  4. 令 elementSize 为 TypedArrayElementSize(ta)。
  5. 令 elementLastByteIndex 为 byteIndexInBuffer + elementSize - 1。
  6. 如果 elementLastByteIndex ≥ taRecord.[[CachedBufferByteLength]],则抛出 RangeError 异常。
  7. 返回 unused。

25.4.3.5 GetWaiterList ( block, i )

抽象操作 GetWaiterList,接收参数 block (共享数据块) 和 i (a non-negative integer that is evenly divisible by 4);返回值:WaiterList 记录。 调用时执行以下步骤:

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

25.4.3.6 EnterCriticalSection ( waiterList )

抽象操作 EnterCriticalSection,接收参数 waiterList (WaiterList 记录);返回值:unused。 调用时执行以下步骤:

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

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

25.4.3.7 LeaveCriticalSection ( waiterList )

抽象操作 LeaveCriticalSection,接收参数 waiterList (WaiterList 记录);返回值:unused。 调用时执行以下步骤:

  1. 断言:周围代理位于 waiterList 的临界区中。
  2. 令 agentRecord 为周围代理的 Agent Record。
  3. 令 execution 为 agentRecord.[[CandidateExecution]]。
  4. 令 eventsRecord 为 execution.[[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 )

抽象操作 AddWaiter,接收参数 waiterList (WaiterList 记录) 和 waiterRecord (Waiter 记录);返回值:unused。 调用时执行以下步骤:

  1. 断言:周围代理位于 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 )

抽象操作 RemoveWaiter,接收参数 waiterList (WaiterList 记录) 和 waiterRecord (Waiter 记录);返回值:unused。 调用时执行以下步骤:

  1. 断言:周围代理位于 waiterList 的临界区中。
  2. 断言:waiterList.[[Waiters]] 包含 waiterRecord。
  3. 从 waiterList.[[Waiters]] 中移除 waiterRecord。
  4. 返回 unused。

25.4.3.10 RemoveWaiters ( waiterList, count )

抽象操作 RemoveWaiters,接收参数 waiterList (WaiterList 记录) 和 count ((非负整数 或 +∞));返回值:列表 (元素:Waiter 记录)。 调用时执行以下步骤:

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

25.4.3.11 SuspendThisAgent ( waiterList, waiterRecord )

抽象操作 SuspendThisAgent,接收参数 waiterList (WaiterList 记录) 和 waiterRecord (Waiter 记录);返回值:unused。 调用时执行以下步骤:

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

25.4.3.12 NotifyWaiter ( waiterList, waiterRecord )

抽象操作 NotifyWaiter,接收参数 waiterList (WaiterList 记录) 和 waiterRecord (Waiter 记录);返回值:unused。 调用时执行以下步骤:

  1. 断言:周围代理位于 waiterList 的临界区中。
  2. 如果 waiterRecord.[[PromiseCapability]] 是 blocking,则
    1. 将标识符为 waiterRecord.[[AgentSignifier]] 的代理从挂起中唤醒。
    2. 注:这会使该代理在 SuspendThisAgent 中恢复执行。
  3. 否则如果 AgentSignifier() 是 waiterRecord.[[AgentSignifier]],则
    1. 令 promiseCapability 为 waiterRecord.[[PromiseCapability]]。
    2. 执行 ! Call(promiseCapability.[[Resolve]], undefined, « waiterRecord.[[Result]] »)。
  4. 否则,
    1. 执行 EnqueueResolveInAgentJob(waiterRecord.[[AgentSignifier]], waiterRecord.[[PromiseCapability]], waiterRecord.[[Result]])。
  5. 返回 unused。
注

除将另一个代理的 promise capability 传递给宿主之外,代理不得以任何方式访问另一个代理的 promise capability。

25.4.3.13 EnqueueResolveInAgentJob ( agentSignifier, promiseCapability, resolution )

抽象操作 EnqueueResolveInAgentJob,接收参数 agentSignifier (an agent signifier)、promiseCapability (PromiseCapability 记录) 和 resolution (("ok" 或 "timed-out"));返回值:unused。 调用时执行以下步骤:

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

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

抽象操作 DoWait,接收参数 mode ((sync 或 async))、ta (ECMAScript 语言值)、index (ECMAScript 语言值)、value (ECMAScript 语言值) 和 timeout (ECMAScript 语言值);返回值:(正常完成 (值:(Object、"not-equal"、"timed-out" 或 "ok")) 或 抛出完成)。 调用时执行以下步骤:

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

additionalTimeout 允许实现根据需要延长超时,例如为了降低功耗或降低计时器分辨率以缓解时序攻击。DoWait 的每次调用中,此值都可能不同。

25.4.3.15 EnqueueAtomicsWaitAsyncTimeoutJob ( waiterList, waiterRecord )

抽象操作 EnqueueAtomicsWaitAsyncTimeoutJob,接收参数 waiterList (WaiterList 记录) 和 waiterRecord (Waiter 记录);返回值:unused。 调用时执行以下步骤:

  1. 令 timeoutJob 为不带参数的新 Job Abstract Closure,它捕获 waiterList 和 waiterRecord,并在被调用时执行以下步骤:
    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 )

抽象操作 AtomicCompareExchangeInSharedBlock,接收参数 block (共享数据块)、byteIndexInBuffer (整数)、elementSize (非负整数)、expectedBytes (列表 (元素:字节值)) 和 replacementBytes (列表 (元素:字节值));返回值:列表 (元素:字节值)。 调用时执行以下步骤:

  1. 令 agentRecord 为周围代理的 Agent Record。
  2. 令 execution 为 agentRecord.[[CandidateExecution]]。
  3. 令 eventsRecord 为 execution.[[EventsRecords]] 中 [[AgentSignifier]] 为 AgentSignifier() 的 Agent Events Record。
  4. 令 rawBytesRead 为长度为 elementSize 的 List,其元素是非确定性选择的字节值。
  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 ( ta, index, value, op )

抽象操作 AtomicReadModifyWrite,接收参数 ta (ECMAScript 语言值)、index (ECMAScript 语言值)、value (ECMAScript 语言值) 和 op (a read-modify-write modification function);返回值:(正常完成 (值:(Number 或 BigInt)) 或 抛出完成)。 op 接受两个字节值 List 参数并返回一个字节值 List。此操作以原子方式加载一个值,将其与另一个值组合,并存储组合结果。它返回加载的值。 调用时执行以下步骤:

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

25.4.3.18 ByteListBitwiseOp ( op, xBytes, yBytes )

抽象操作 ByteListBitwiseOp,接收参数 op ((&、^ 或 |))、xBytes (列表 (元素:字节值)) 和 yBytes (列表 (元素:字节值));返回值:列表 (元素:字节值)。 此操作以原子方式对参数的所有字节值执行按位操作,并返回一个字节值 List。 调用时执行以下步骤:

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

25.4.3.19 ByteListEqual ( xBytes, yBytes )

抽象操作 ByteListEqual,接收参数 xBytes (列表 (元素:字节值)) 和 yBytes (列表 (元素:字节值));返回值:Boolean。 调用时执行以下步骤:

  1. 如果 xBytes 和 yBytes 不具有相同的元素数量,则返回 false。
  2. 令 i 为 0。
  3. 对 xBytes 的每个元素 xByte,执行
    1. 令 yByte 为 yBytes[i]。
    2. 如果 xByte ≠ yByte,则返回 false。
    3. 将 i 设置为 i + 1。
  4. 返回 true。

25.4.4 Atomics.add ( ta, index, value )

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

  1. 令 add 为参数为 (xBytes, yBytes) 的新读-修改-写修改函数,它捕获 ta,并在被调用时以原子方式执行以下步骤:
    1. 令 type 为 TypedArrayElementType(ta)。
    2. 令 agentRecord 为周围代理的 Agent Record。
    3. 令 isLittleEndian 为 agentRecord.[[LittleEndian]]。
    4. 令 x 为 RawBytesToNumeric(type, xBytes, isLittleEndian)。
    5. 令 y 为 RawBytesToNumeric(type, yBytes, isLittleEndian)。
    6. 如果 x 是 Number,则
      1. 令 sum 为 Number::add(x, y)。
    7. 否则,
      1. 断言:x 是 BigInt。
      2. 令 sum 为 BigInt::add(x, y)。
    8. 令 sumBytes 为 NumericToRawBytes(type, sum, isLittleEndian)。
    9. 断言:sumBytes、xBytes 和 yBytes 具有相同的元素数量。
    10. 返回 sumBytes。
  2. 返回 ? AtomicReadModifyWrite(ta, index, value, add)。

25.4.5 Atomics.and ( ta, index, value )

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

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

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

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

  1. 令 byteIndexInBuffer 为 ? ValidateAtomicAccessOnIntegerTypedArray(ta, index)。
  2. 令 buffer 为 ta.[[ViewedArrayBuffer]]。
  3. 令 block 为 buffer.[[ArrayBufferData]]。
  4. 如果 ta.[[ContentType]] 是 bigint,则
    1. 令 expected 为 ? ToBigInt(expectedValue)。
    2. 令 replacement 为 ? ToBigInt(replacementValue)。
  5. 否则,
    1. 令 expected 为 𝔽(? ToIntegerOrInfinity(expectedValue))。
    2. 令 replacement 为 𝔽(? ToIntegerOrInfinity(replacementValue))。
  6. 执行 ? RevalidateAtomicAccess(ta, byteIndexInBuffer)。
  7. 令 elementType 为 TypedArrayElementType(ta)。
  8. 令 elementSize 为 TypedArrayElementSize(ta)。
  9. 令 agentRecord 为周围代理的 Agent Record。
  10. 令 isLittleEndian 为 agentRecord.[[LittleEndian]]。
  11. 令 expectedBytes 为 NumericToRawBytes(elementType, expected, isLittleEndian)。
  12. 令 replacementBytes 为 NumericToRawBytes(elementType, replacement, isLittleEndian)。
  13. 如果 IsSharedArrayBuffer(buffer) 是 true,则
    1. 令 rawBytesRead 为 AtomicCompareExchangeInSharedBlock(block, byteIndexInBuffer, elementSize, expectedBytes, replacementBytes)。
  14. 否则,
    1. 令 rawBytesRead 为长度为 elementSize 的 List,其元素是从 block[byteIndexInBuffer] 开始的 elementSize 个字节序列。
    2. 如果 ByteListEqual(rawBytesRead, expectedBytes) 是 true,则
      1. 从 block[byteIndexInBuffer] 开始,将 replacementBytes 的各个字节存储到 block 中。
  15. 返回 RawBytesToNumeric(elementType, rawBytesRead, isLittleEndian)。

25.4.7 Atomics.exchange ( ta, index, value )

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

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

25.4.8 Atomics.isLockFree ( size )

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

  1. 令 n 为 ? ToIntegerOrInfinity(size)。
  2. 令 agentRecord 为周围代理的 Agent Record。
  3. 如果 n = 1,则返回 agentRecord.[[IsLockFree1]]。
  4. 如果 n = 2,则返回 agentRecord.[[IsLockFree2]]。
  5. 如果 n = 4,则返回 true。
  6. 如果 n = 8,则返回 agentRecord.[[IsLockFree8]]。
  7. 返回 false。
注

此函数是一种优化原语。直观来说,如果在大小为 n 字节的数据上执行某个原子原语(compareExchange、load、store、add、sub、and、or、xor 或 exchange)的原子步骤时,周围代理无需获取组成该数据的 n 字节之外的锁,则 Atomics.isLockFree(n) 将返回 true。高性能算法会使用此函数来确定在临界区中是使用锁还是原子操作。如果某个原子原语不是无锁的,那么算法自行提供锁通常效率更高。

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

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

25.4.9 Atomics.load ( ta, index )

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

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

25.4.10 Atomics.notify ( ta, index, count )

此函数通知等待队列中处于睡眠状态的一些代理。

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

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

25.4.11 Atomics.or ( ta, index, value )

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

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

25.4.12 Atomics.pause ( )

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

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

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

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

如果底层架构的最佳实践建议在自旋循环中使用暂停或让出指令,则预期实现采用此类指令。例如,Intel Optimization Manual 建议使用 pause 指令。

鼓励实现在内部将最大暂停时间设定一个上限,大约为几十到几百纳秒。

注 2

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

25.4.13 Atomics.store ( ta, index, value )

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

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

25.4.14 Atomics.sub ( ta, index, value )

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

  1. 令 subtract 为参数为 (xBytes, yBytes) 的新读-修改-写修改函数,它捕获 ta,并在被调用时以原子方式执行以下步骤:
    1. 令 type 为 TypedArrayElementType(ta)。
    2. 令 agentRecord 为周围代理的 Agent Record。
    3. 令 isLittleEndian 为 agentRecord.[[LittleEndian]]。
    4. 令 x 为 RawBytesToNumeric(type, xBytes, isLittleEndian)。
    5. 令 y 为 RawBytesToNumeric(type, yBytes, isLittleEndian)。
    6. 如果 x 是 Number,则
      1. 令 difference 为 Number::subtract(x, y)。
    7. 否则,
      1. 断言:x 是 BigInt。
      2. 令 difference 为 BigInt::subtract(x, y)。
    8. 令 differenceBytes 为 NumericToRawBytes(type, difference, isLittleEndian)。
    9. 断言:differenceBytes、xBytes 和 yBytes 具有相同的元素数量。
    10. 返回 differenceBytes。
  2. 返回 ? AtomicReadModifyWrite(ta, index, value, subtract)。

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

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

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

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

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

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

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

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

25.4.17 Atomics.xor ( ta, index, value )

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

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

25.4.18 Atomics [ %Symbol.toStringTag% ]

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

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

25.5 JSON 对象

JSON 对象:

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

JSON 数据交换格式定义于 ECMA-404。本规范使用的 JSON 交换格式与 ECMA-404 所述完全相同。符合规范的 JSON.parse 和 JSON.stringify 实现必须支持 ECMA-404 中描述的精确交换格式,不得对该格式进行任何删减或扩展。

25.5.1 JSON.isRawJSON ( obj )

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

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

25.5.2 JSON.parse ( text [ , reviver ] )

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

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

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

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

25.5.2.1 ParseJSON ( text )

抽象操作 ParseJSON,接收参数 text (String);返回值:(正常完成 (值:记录 (字段:[[ParseNode]] (解析节点), [[Value]] (ECMAScript 语言值))) 或 抛出完成)。 调用时执行以下步骤:

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

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

注 1

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

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

注 2

如果对象中存在重复的名称 String,则词法上靠前的同键值应被覆盖。

25.5.2.2 JSON Parse Record

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

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

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

25.5.2.3 CreateJSONParseRecord ( parseNode, key, value )

抽象操作 CreateJSONParseRecord,接收参数 parseNode (解析节点)、key (属性名) 和 value (ECMAScript 语言值);返回值:JSON Parse 记录。 它以递归方式将从 JSON 文本解析出的 parseNode 与其求值产生的 value 组合起来。 调用时执行以下步骤:

  1. 令 typedValueNode 为 ShallowestContainedJSONValue(parseNode)。
  2. 断言:typedValueNode 不是 empty。
  3. 令 elements 为新的空 List。
  4. 令 entries 为新的空 List。
  5. 如果 value 是 Object,则
    1. 令 isArray 为 ! IsArray(value)。
    2. 如果 isArray 是 true,则
      1. 断言:typedValueNode 是 ArrayLiteral Parse Node。
      2. 令 contentNodes 为 the JSONArrayLiteralContentNodes of typedValueNode。
      3. 令 length 为 contentNodes 中的元素数量。
      4. 令 valueLength 为 ! LengthOfArrayLike(value)。
      5. 断言:valueLength 是 length。
      6. 令 index 为 0。
      7. 当 index < length 时,重复执行,
        1. 令 propertyName 为 ! ToString(𝔽(index))。
        2. 令 elementParseRecord 为 CreateJSONParseRecord(contentNodes[index], propertyName, ! Get(value, propertyName))。
        3. 将 elementParseRecord 追加到 elements。
        4. 将 index 设置为 index + 1。
    3. 否则,
      1. 断言:typedValueNode 是 ObjectLiteral Parse Node。
      2. 令 propertyNodes 为 the PropertyDefinitionNodes of typedValueNode。
      3. 注:由于 value 由 JSON 文本产生且尚未被修改,因此其所有属性键都是 String,并且会被完整枚举。
      4. 令 keys 为 ! EnumerableOwnProperties(value, key)。
      5. 对 keys 的每个 String propertyKey,执行
        1. 注:如果 JSON 文本为单个对象指定了多个具有相同名称的名称/值对(例如 {"a":"lost","a":"kept"}),则结果 ECMAScript 对象对应属性的值由具有该名称的最后一对指定。
        2. 令 propertyDefinition 为 empty。
        3. 对 propertyNodes 的每个 Parse Node propertyNode,执行
          1. 令 propertyName 为 the PropName of propertyNode。
          2. 如果 propertyName 是 propertyKey,则将 propertyDefinition 设置为 propertyNode。
        4. 断言:propertyDefinition 是 PropertyDefinition : PropertyName : AssignmentExpression 。
        5. 令 propertyValueNode 为 the AssignmentExpression of propertyDefinition。
        6. 令 entryParseRecord 为 CreateJSONParseRecord(propertyValueNode, propertyKey, ! Get(value, propertyKey))。
        7. 将 entryParseRecord 追加到 entries。
  6. 否则,
    1. 断言:typedValueNode 既不是 ArrayLiteral Parse Node,也不是 ObjectLiteral Parse Node。
  7. 返回 JSON Parse Record { [[ParseNode]]: typedValueNode, [[Key]]: key, [[Value]]: value, [[Elements]]: elements, [[Entries]]: entries }。

25.5.2.4 InternalizeJSONProperty ( holder, name, reviver, parseRecord )

抽象操作 InternalizeJSONProperty,接收参数 holder (Object)、name (String)、reviver (函数对象) 和 parseRecord ((JSON Parse 记录 或 empty));返回值:(正常完成 (值:ECMAScript 语言值) 或 抛出完成)。

注

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

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

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

25.5.2.5 Static Semantics: ShallowestContainedJSONValue ( root )

抽象操作 ShallowestContainedJSONValue,接收参数 root (解析节点);返回值:(解析节点 或 empty)。 它对以 root 为根的解析树执行广度优先搜索,并返回第一个属于与 JSON 值对应的非终结符实例的节点;如果不存在此类节点,则返回 empty。 调用时执行以下步骤:

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

25.5.2.6 Static Semantics: JSONArrayLiteralContentNodes

语法制导操作 JSONArrayLiteralContentNodes,接收无参数;返回值:列表 (元素:解析节点)。 它按以下产生式分别定义:

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

25.5.3 JSON.rawJSON ( text )

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

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

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

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

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

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

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

注 1

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

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

符号原始值按如下方式呈现:

  • null 值在 JSON 文本中呈现为 String 值 "null"。
  • undefined 值不会被呈现。
  • true 值在 JSON 文本中呈现为 String 值 "true"。
  • false 值在 JSON 文本中呈现为 String 值 "false"。
注 3

String 值由 QUOTATION MARK (") 码元包围。码元 " 和 \ 使用 \ 前缀进行转义。控制字符码元被替换为转义序列 \uHHHH,或者替换为更短的形式 \b (BACKSPACE)、\f (FORM FEED)、\n (LINE FEED)、\r (CARRIAGE RETURN)、\t (CHARACTER TABULATION)。

注 4

每个有限 Number 都如同通过调用 ToString(number) 一样被字符串化。NaN、+∞𝔽 和 -∞𝔽 表示为 String 值 "null"。

注 5

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

注 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 是用于实现序列化为 JSON 格式的 Record。

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

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

25.5.4.2 SerializeJSONProperty ( state, key, holder )

抽象操作 SerializeJSONProperty,接收参数 state (JSON Serialization 记录)、key (String) 和 holder (Object);返回值:(正常完成 (值:(String 或 undefined)) 或 抛出完成)。 调用时执行以下步骤:

  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. 如果 value 是 null,返回 "null"。
  6. 如果 value 是 true,返回 "true"。
  7. 如果 value 是 false,返回 "false"。
  8. 如果 value 是 String,返回 QuoteJSONString(value)。
  9. 如果 value 是 Number,那么
    1. 如果 value 是有限 Number,返回 ! ToString(value)。
    2. 返回 "null"。
  10. 如果 value 是 BigInt,抛出 TypeError 异常。
  11. 如果 value 是 Object 且 IsCallable(value) 是 false,那么
    1. 令 isArray 为 ? IsArray(value)。
    2. 如果 isArray 是 true,那么
      1. 返回 ? SerializeJSONArray(state, value)。
    3. 返回 ? SerializeJSONObject(state, value)。
  12. 返回 undefined。

25.5.4.3 QuoteJSONString ( value )

抽象操作 QuoteJSONString,接收参数 value (String);返回值:String。 它使用 0x0022 (QUOTATION MARK) 码元包围 value,并转义其中的某些其他码元。此操作将 value 解释为 UTF-16 编码的码点序列,如 6.1.4 所述。 调用时执行以下步骤:

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

25.5.4.4 UnicodeEscape ( codeUnit )

抽象操作 UnicodeEscape,接收参数 codeUnit (码元);返回值:String。 它将 codeUnit 表示为 Unicode 转义序列。 调用时执行以下步骤:

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

25.5.4.5 SerializeJSONObject ( state, value )

抽象操作 SerializeJSONObject,接收参数 state (JSON Serialization 记录) 和 value (Object);返回值:(正常完成 (值:String) 或 抛出完成)。 它序列化一个对象。 调用时执行以下步骤:

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

25.5.4.6 SerializeJSONArray ( state, value )

抽象操作 SerializeJSONArray,接收参数 state (JSON Serialization 记录) 和 value (Object);返回值:(正常完成 (值:String) 或 抛出完成)。 它序列化一个数组。 调用时执行以下步骤:

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

数组的表示仅包括从 +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 }。