Stage 1 Draft / March 12, 2020

TypedArray Stride Parameter

1 Modifications to Integer-Indexed Exotic Objects definitions

1.1 Integer-Indexed Exotic Objects

An Integer-Indexed exotic object is an exotic object that performs special handling of integer index property keys.

Integer-Indexed exotic objects have the same internal slots as ordinary objects and additionally [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], [[Stride]], [[ContentType]], and [[TypedArrayName]] internal slots.

An object is an Integer-Indexed exotic object if its [[GetOwnProperty]], [[HasProperty]], [[DefineOwnProperty]], [[Get]], [[Set]], and [[OwnPropertyKeys]] internal methods use the definitions in this section, and its other essential internal methods use the definitions found in 9.1. These methods are installed by IntegerIndexedObjectCreate.

1.2 ToByteIndex ( O, index )

Editor's Note

This is a new abstract operation.

The abstract operation ToByteIndex takes two arguments, an Integer-Indexed Exotic Object O and an integer index, and transforms the index to the byte index on the underlying ArrayBuffer.

  1. Assert: O is an Integer-Indexed exotic object.
  2. Assert: ! IsValidIntegerIndex(O, index) is true.
  3. Let stride be O.[[Stride]].
  4. Let offset be O.[[ByteOffset]].
  5. Let arrayTypeName be the String value of O.[[TypedArrayName]].
  6. Let elementSize be the Element Size value specified in Table 63 for arrayTypeName.
  7. Return (index × elementSize × stride) + offset.

1.3 IntegerIndexedObjectCreate ( prototype )

The abstract operation IntegerIndexedObjectCreate is used to specify the creation of new Integer-Indexed exotic objects. IntegerIndexedObjectCreate performs the following steps:

  1. Let internalSlotsList be « [[Prototype]], [[Extensible]], [[ViewedArrayBuffer]], [[TypedArrayName]], [[ContentType]], [[ByteLength]], [[ByteOffset]], [[Stride]], [[ArrayLength]] ».
  2. Let A be ! MakeBasicObject(internalSlotsList).
  3. Set A.[[GetOwnProperty]] as specified in 9.4.5.1.
  4. Set A.[[HasProperty]] as specified in 9.4.5.2.
  5. Set A.[[DefineOwnProperty]] as specified in 9.4.5.3.
  6. Set A.[[Get]] as specified in 9.4.5.4.
  7. Set A.[[Set]] as specified in 9.4.5.5.
  8. Set A.[[OwnPropertyKeys]] as specified in 9.4.5.6.
  9. Set A.[[Prototype]] to prototype.
  10. Return A.

1.4 IntegerIndexedElementGet ( O, index )

The abstract operation IntegerIndexedElementGet with arguments O and index performs the following steps:

  1. Assert: O is an Integer-Indexed exotic object.
  2. Assert: Type(index) is Number.
  3. Let buffer be O.[[ViewedArrayBuffer]].
  4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
  5. If ! IsValidIntegerIndex(O, index) is false, return undefined.
  6. Let indexedPosition be ToByteIndex(O, index).
  7. Let offset be O.[[ByteOffset]].
  8. Let arrayTypeName be the String value of O.[[TypedArrayName]].
  9. Let elementSize be the Element Size value specified in Table 63 for arrayTypeName.
  10. Let indexedPosition be (index × elementSize) + offset.
  11. Let elementType be the Element Type value in Table 63 for arrayTypeName.
  12. Return GetValueFromBuffer(buffer, indexedPosition, elementType, true, Unordered).

1.5 IntegerIndexedElementSet ( O, index, value )

The abstract operation IntegerIndexedElementSet with arguments O, index, and value performs the following steps:

  1. Assert: O is an Integer-Indexed exotic object.
  2. Assert: Type(index) is Number.
  3. If O.[[ContentType]] is BigInt, let numValue be ? ToBigInt(value).
  4. Otherwise, let numValue be ? ToNumber(value).
  5. Let buffer be O.[[ViewedArrayBuffer]].
  6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
  7. If ! IsValidIntegerIndex(O, index) is false, return false.
  8. Let indexedPosition be ToByteIndex(O, index).
  9. Let offset be O.[[ByteOffset]].
  10. Let arrayTypeName be the String value of O.[[TypedArrayName]].
  11. Let elementSize be the Element Size value specified in Table 63 for arrayTypeName.
  12. Let indexedPosition be (index × elementSize) + offset.
  13. Let elementType be the Element Type value in Table 63 for arrayTypeName.
  14. Perform SetValueInBuffer(buffer, indexedPosition, elementType, numValue, true, Unordered).
  15. Return true.

2 Modifications to TypedArray Objects

2.1 Modifications to Abstract Operations For ArrayBuffer Objects

2.1.1 CloneArrayBuffer ( srcBuffer, srcByteOffset, srcElementSize, srcStride, srcLength, cloneConstructor )

Editor's Note

The cloned ArrayBuffer returned by this abstract operation does not preserve stride.

The abstract operation CloneArrayBuffer takes four parameters, an ArrayBuffer srcBuffer, an integer offset srcByteOffset, an integer srcElementSize, an integer stride srcStride, an integer length srcLength, and a constructor function cloneConstructor. It creates a new ArrayBuffer whose data is a copy of srcBuffer's data over the range starting at srcByteOffset and continuing for srcLength × srcByteStride bytes. This operation performs the following steps:

  1. Assert: Type(srcBuffer) is Object and it has an [[ArrayBufferData]] internal slot.
  2. Assert: IsConstructor(cloneConstructor) is true.
  3. Let targetBuffer be ? AllocateArrayBuffer(cloneConstructor, srcLength).
  4. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
  5. Let srcBlock be srcBuffer.[[ArrayBufferData]].
  6. Let targetBlock be targetBuffer.[[ArrayBufferData]].
  7. Perform CopyDataBlockBytes(targetBlock, 0, srcBlock, srcByteOffset, srcElementSize, srcStride, srcLength).
  8. Return targetBuffer.

2.1.2 CopyDataBlockBytes ( toBlock, toIndex, fromBlock, fromIndex, fromElementSize, fromStride, count )

When the abstract operation CopyDataBlockBytes is called, the following steps are taken:

  1. Assert: fromBlock and toBlock are distinct Data Block or Shared Data Block values.
  2. Assert: fromIndex, fromStride, toIndex, and count are integer values ≥ 0.
  3. Let fromSize be the number of bytes in fromBlock.
  4. Assert: fromIndex + count × fromStridefromSize.
  5. Let toSize be the number of bytes in toBlock.
  6. Assert: toIndex + counttoSize.
  7. Repeat, while count > 0
    1. Let countBytes be fromElementSize.
    2. Repeat, while countBytes > 0
      1. If fromBlock is a Shared Data Block, then
        1. Let execution be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
        2. Let eventList be the [[EventList]] field of the element in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
        3. Let bytes be a List of length 1 that contains a nondeterministically chosen byte value.
        4. NOTE: In implementations, bytes is the result of a non-atomic read instruction on the underlying hardware. The nondeterminism is a semantic prescription of the memory model to describe observable behaviour of hardware with weak consistency.
        5. Let readEvent be ReadSharedMemory { [[Order]]: Unordered, [[NoTear]]: true, [[Block]]: fromBlock, [[ByteIndex]]: fromIndex, [[ElementSize]]: 1 }.
        6. Append readEvent to eventList.
        7. Append Chosen Value Record { [[Event]]: readEvent, [[ChosenValue]]: bytes } to execution.[[ChosenValues]].
        8. If toBlock is a Shared Data Block, then
          1. Append WriteSharedMemory { [[Order]]: Unordered, [[NoTear]]: true, [[Block]]: toBlock, [[ByteIndex]]: toIndex, [[ElementSize]]: 1, [[Payload]]: bytes } to eventList.
        9. Else,
          1. Set toBlock[toIndex] to bytes[0].
      2. Else,
        1. Assert: toBlock is not a Shared Data Block.
        2. Set toBlock[toIndex] to fromBlock[fromIndex].
      3. Set toIndex to toIndex + 1.
      4. Set fromIndex to fromIndex + 1.
      5. Set countBytes to countBytes - 1.
      6. Set count to count - 1.
      7. NOTE: count already accounts for stride.
    3. Set fromIndex to fromIndex + fromElementSize × (fromStride - 1).
    4. Set countBytes to fromElementSize
  8. Return NormalCompletion(empty).

2.2 Modifications to Properties of the %TypedArray% Intrinsic Object

2.2.1 %TypedArray%.prototype.copyWithin ( target, start [ , end ] )

The interpretation and use of the arguments of %TypedArray%.prototype.copyWithin are the same as for Array.prototype.copyWithin as defined in 22.1.3.3.

The following steps are taken:

  1. Let O be the this value.
  2. Perform ? ValidateTypedArray(O).
  3. Let len be O.[[ArrayLength]].
  4. Let relativeTarget be ? ToInteger(target).
  5. If relativeTarget < 0, let to be max((len + relativeTarget), 0); else let to be min(relativeTarget, len).
  6. Let relativeStart be ? ToInteger(start).
  7. If relativeStart < 0, let from be max((len + relativeStart), 0); else let from be min(relativeStart, len).
  8. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToInteger(end).
  9. If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let final be min(relativeEnd, len).
  10. Let count be min(final - from, len - to).
  11. If count > 0, then
    1. NOTE: The copying must be performed in a manner that preserves the bit-level encoding of the source data.
    2. Let buffer be O.[[ViewedArrayBuffer]].
    3. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
    4. Let typedArrayName be the String value of O.[[TypedArrayName]].
    5. Let elementSize be the Element Size value specified in Table 63 for typedArrayName.
    6. Let stride be O.[[Stride]].
    7. Let byteOffset be O.[[ByteOffset]].
    8. Let toByteIndex be to × elementSize × stride + byteOffset.
    9. Let fromByteIndex be from × elementSize × stride + byteOffset.
    10. Let countBytes be count × elementSize.
    11. If fromByteIndex < toByteIndex and toByteIndex < fromByteIndex + countBytes, then
      1. Let direction be -1.
      2. Set fromByteIndex to fromByteIndex + countBytes - 1.
      3. Set toByteIndex to toByteIndex + countBytes - 1.
    12. Else,
      1. Let direction be 1.
    13. Repeat, while countBytescount > 0
      1. Let countBytes be elementSize.
      2. Repeat, while countBytes > 0
        1. Let value be GetValueFromBuffer(buffer, fromByteIndex, Uint8, true, Unordered).
        2. Perform SetValueInBuffer(buffer, toByteIndex, Uint8, value, true, Unordered).
        3. Set fromByteIndex to fromByteIndex + direction.
        4. Set toByteIndex to toByteIndex + direction.
        5. Set countBytes to countBytes - 1.
      3. Set fromByteIndex to fromByteIndex + direction × elementSize × (stride - 1).
      4. Set toByteIndex to toByteIndex + direction × elementSize × (stride - 1).
      5. Set count to count - 1.
  12. Return O.

2.2.2 %TypedArray%.prototype.set ( array [ , offset ] )

Sets multiple values in this TypedArray, reading the values from the object array. The optional offset value indicates the first element index in this TypedArray where values are written. If omitted, it is assumed to be 0.

  1. Assert: array is any ECMAScript language value other than an Object with a [[TypedArrayName]] internal slot. If it is such an Object, the definition in 2.2.3 applies.
  2. Let target be the this value.
  3. Perform ? RequireInternalSlot(target, [[TypedArrayName]]).
  4. Assert: target has a [[ViewedArrayBuffer]] internal slot.
  5. Let targetOffset be ? ToInteger(offset).
  6. If targetOffset < 0, throw a RangeError exception.
  7. Let targetBuffer be target.[[ViewedArrayBuffer]].
  8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
  9. Let targetLength be target.[[ArrayLength]].
  10. Let targetName be the String value of target.[[TypedArrayName]].
  11. Let targetElementSize be the Element Size value specified in Table 63 for targetName.
  12. Let targetType be the Element Type value in Table 63 for targetName.
  13. Let targetStride be target.[[Stride]].
  14. Let targetByteOffset be target.[[ByteOffset]].
  15. Let src be ? ToObject(array).
  16. Let srcLength be ? LengthOfArrayLike(src).
  17. If srcLength + targetOffset > targetLength, throw a RangeError exception.
  18. Let targetByteIndex be targetOffset × targetElementSize × targetStride + targetByteOffset.
  19. Let k be 0.
  20. Let limit be targetByteIndex + targetElementSize × targetStride × srcLength.
  21. Repeat, while targetByteIndex < limit
    1. Let Pk be ! ToString(k).
    2. Let value be ? Get(src, Pk).
    3. If target.[[ContentType]] is BigInt, set value to ? ToBigInt(value).
    4. Otherwise, set value to ? ToNumber(value).
    5. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
    6. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, value, true, Unordered).
    7. Set k to k + 1.
    8. Set targetByteIndex to targetByteIndex + targetElementSize × targetStride.
  22. Return undefined.

2.2.3 %TypedArray%.prototype.set ( typedArray [ , offset ] )

Sets multiple values in this TypedArray, reading the values from the typedArray argument object. The optional offset value indicates the first element index in this TypedArray where values are written. If omitted, it is assumed to be 0.

  1. Assert: typedArray has a [[TypedArrayName]] internal slot. If it does not, the definition in 22.2.3.23.1 applies.
  2. Let target be the this value.
  3. Perform ? RequireInternalSlot(target, [[TypedArrayName]]).
  4. Assert: target has a [[ViewedArrayBuffer]] internal slot.
  5. Let targetOffset be ? ToInteger(offset).
  6. If targetOffset < 0, throw a RangeError exception.
  7. Let targetBuffer be target.[[ViewedArrayBuffer]].
  8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
  9. Let targetLength be target.[[ArrayLength]].
  10. Let srcBuffer be typedArray.[[ViewedArrayBuffer]].
  11. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
  12. Let targetName be the String value of target.[[TypedArrayName]].
  13. Let targetType be the Element Type value in Table 63 for targetName.
  14. Let targetElementSize be the Element Size value specified in Table 63 for targetName.
  15. Let targetByteOffset be target.[[ByteOffset]].
  16. Let targetByteOffset be target.[[Stride]].
  17. Let srcName be the String value of typedArray.[[TypedArrayName]].
  18. Let srcType be the Element Type value in Table 63 for srcName.
  19. Let srcElementSize be the Element Size value specified in Table 63 for srcName.
  20. Let srcLength be typedArray.[[ArrayLength]].
  21. Let srcByteOffset be typedArray.[[ByteOffset]].
  22. Let srcStride be typedArray.[[Stride]].
  23. If srcLength + targetOffset > targetLength, throw a RangeError exception.
  24. If target.[[ContentType]] is not equal to typedArray.[[ContentType]], throw a TypeError exception.
  25. If both IsSharedArrayBuffer(srcBuffer) and IsSharedArrayBuffer(targetBuffer) are true, then
    1. If srcBuffer.[[ArrayBufferData]] and targetBuffer.[[ArrayBufferData]] are the same Shared Data Block values, let same be true; else let same be false.
  26. Else, let same be SameValue(srcBuffer, targetBuffer).
  27. If same is true, then
    1. Let srcByteLength be typedArray.[[ByteLength]].
    2. Set srcBuffer to ? CloneArrayBuffer(srcBuffer, srcByteOffset, srcElementSize, srcStride, srcByteLength, %ArrayBuffer%).
    3. NOTE: %ArrayBuffer% is used to clone srcBuffer because is it known to not have any observable side-effects.
    4. Let srcByteIndex be 0.
    5. Set srcStride to 1.
    6. NOTE: CloneArrayBuffer does not preserve stride.
  28. Else, let srcByteIndex be srcByteOffset.
  29. Let targetByteIndex be targetOffset × targetElementSize × targetStride + targetByteOffset.
  30. Let limit be targetByteIndex + targetElementSize × targetStride × srcLength.
  31. If srcType is the same as targetType, then
    1. NOTE: If srcType and targetType are the same, the transfer must be performed in a manner that preserves the bit-level encoding of the source data.
    2. Repeat, while targetByteIndex < limit
      1. Let countBytes be elementSize.
      2. Repeat, while countBytes > 0
        1. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, true, Uint8, Unordered).
        2. Perform SetValueInBuffer(targetBuffer, targetByteIndex, Uint8, value, true, Unordered).
        3. Set srcByteIndex to srcByteIndex + 1.
        4. Set targetByteIndex to targetByteIndex + 1.
        5. Set countBytes to countBytes - 1.
      3. Set srcByteIndex to srcByteIndex + elementSize × (srcStride - 1).
      4. Set targetByteIndex to targetByteIndex + elementSize × (targetStride - 1).
  32. Else,
    1. Repeat, while targetByteIndex < limit
      1. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, srcType, true, Unordered).
      2. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, value, true, Unordered).
      3. Set srcByteIndex to srcByteIndex + srcElementSize × srcStride.
      4. Set targetByteIndex to targetByteIndex + targetElementSize × targetStride.
  33. Return undefined.

2.2.4 %TypedArray%.prototype.slice ( start, end )

Editor's Note

This method clones the underlying buffer and does not preserve stride.

The interpretation and use of the arguments of %TypedArray%.prototype.slice are the same as for Array.prototype.slice as defined in 22.1.3.25. The following steps are taken:

  1. Let O be the this value.
  2. Perform ? ValidateTypedArray(O).
  3. Let len be O.[[ArrayLength]].
  4. Let relativeStart be ? ToInteger(start).
  5. If relativeStart < 0, let k be max((len + relativeStart), 0); else let k be min(relativeStart, len).
  6. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToInteger(end).
  7. If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let final be min(relativeEnd, len).
  8. Let count be max(final - k, 0).
  9. Let A be ? TypedArraySpeciesCreate(O, « count »).
  10. Let srcName be the String value of O.[[TypedArrayName]].
  11. Let srcType be the Element Type value in Table 63 for srcName.
  12. Let targetName be the String value of A.[[TypedArrayName]].
  13. Let targetType be the Element Type value in Table 63 for targetName.
  14. If srcType is different from targetType, then
    1. Let n be 0.
    2. Repeat, while k < final
      1. Let Pk be ! ToString(k).
      2. Let kValue be ? Get(O, Pk).
      3. Perform ! Set(A, ! ToString(n), kValue, true).
      4. Set k to k + 1.
      5. Set n to n + 1.
  15. Else if count > 0, then
    1. Let srcBuffer be O.[[ViewedArrayBuffer]].
    2. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
    3. Let targetBuffer be A.[[ViewedArrayBuffer]].
    4. Let elementSize be the Element Size value specified in Table 63 for Element Type srcType.
    5. NOTE: If srcType and targetType are the same, the transfer must be performed in a manner that preserves the bit-level encoding of the source data.
    6. Let stride be O.[[Stride]].
    7. Let srcByteOffet be O.[[ByteOffset]].
    8. Let targetByteIndex be A.[[ByteOffset]].
    9. Let srcByteIndex be (k × elementSize) + srcByteOffet.
    10. Repeat, while count > 0
      1. Let countBytes be elementSize.
      2. Repeat, while countBytes > 0
        1. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, Uint8, true, Unordered).
        2. Perform SetValueInBuffer(targetBuffer, targetByteIndex, Uint8, value, true, Unordered).
        3. Set srcByteIndex to srcByteIndex + 1.
        4. Set targetByteIndex to targetByteIndex + 1.
        5. Set countBytes to countBytes - 1.
      3. Set srcByteIndex to srcByteIndex + elementSize × (stride - 1).
      4. Set targetByteIndex to targetByteIndex + elementSize × (stride - 1).
      5. Set count to count - 1.
  16. Return A.

This function is not generic. The this value must be an object with a [[TypedArrayName]] internal slot.

2.2.5 %TypedArray%.prototype.subarray ( begin, end )

Editor's Note

This method does not clone the underlying buffer and preserves stride.

Returns a new TypedArray object whose element type is the same as this TypedArray and whose ArrayBuffer is the same as the ArrayBuffer of this TypedArray, referencing the elements at begin, inclusive, up to end, exclusive. If either begin or end is negative, it refers to an index from the end of the array, as opposed to from the beginning.

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
  3. Assert: O has a [[ViewedArrayBuffer]] internal slot.
  4. Let buffer be O.[[ViewedArrayBuffer]].
  5. Let srcLength be O.[[ArrayLength]].
  6. Let relativeBegin be ? ToInteger(begin).
  7. If relativeBegin < 0, let beginIndex be max((srcLength + relativeBegin), 0); else let beginIndex be min(relativeBegin, srcLength).
  8. If end is undefined, let relativeEnd be srcLength; else let relativeEnd be ? ToInteger(end).
  9. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), 0); else let endIndex be min(relativeEnd, srcLength).
  10. Let newLength be max(endIndex - beginIndex, 0).
  11. Let constructorName be the String value of O.[[TypedArrayName]].
  12. Let elementSize be the Element Size value specified in Table 63 for constructorName.
  13. Let srcStride be O.[[Stride]].
  14. Let srcByteOffset be O.[[ByteOffset]].
  15. Let beginByteOffset be srcByteOffset + beginIndex × elementSize × stride.
  16. Let argumentsList be « buffer, beginByteOffset, newLength, stride ».
  17. Return ? TypedArraySpeciesCreate(O, argumentsList).

This function is not generic. The this value must be an object with a [[TypedArrayName]] internal slot.

2.3 Modifications to the TypedArray Constructors

2.3.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto [ , length ] )

The abstract operation AllocateTypedArray with arguments constructorName, newTarget, defaultProto and optional argument length is used to validate and create an instance of a TypedArray constructor. constructorName is required to be the name of a TypedArray constructor in Table 63. If the length argument is passed, an ArrayBuffer of that length is also allocated and associated with the new TypedArray instance. AllocateTypedArray provides common semantics that is used by all of the TypedArray overloads. AllocateTypedArray performs the following steps:

  1. Let proto be ? GetPrototypeFromConstructor(newTarget, defaultProto).
  2. Let obj be ! IntegerIndexedObjectCreate(proto).
  3. Assert: obj.[[ViewedArrayBuffer]] is undefined.
  4. Set obj.[[TypedArrayName]] to constructorName.
  5. If constructorName is "BigInt64Array" or "BigUint64Array", set obj.[[ContentType]] to BigInt.
  6. Otherwise, set obj.[[ContentType]] to Number.
  7. If length is not present, then
    1. Set obj.[[ByteLength]] to 0.
    2. Set obj.[[ByteOffset]] to 0.
    3. Set obj.[[ArrayLength]] to 0.
    4. Set obj.[[Stride]] to 1.
  8. Else,
    1. Perform ? AllocateTypedArrayBuffer(obj, length).
  9. Return obj.

2.3.2 Runtime Semantics: AllocateTypedArrayBuffer ( O, length )

The abstract operation AllocateTypedArrayBuffer with arguments O and length allocates and associates an ArrayBuffer with the TypedArray instance O. It performs the following steps:

  1. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
  2. Assert: O.[[ViewedArrayBuffer]] is undefined.
  3. Assert: ! IsNonNegativeInteger(length) is true.
  4. Let constructorName be the String value of O.[[TypedArrayName]].
  5. Let elementSize be the Element Size value specified in Table 63 for constructorName.
  6. Let byteLength be elementSize × length.
  7. Let data be ? AllocateArrayBuffer(%ArrayBuffer%, byteLength).
  8. Set O.[[ViewedArrayBuffer]] to data.
  9. Set O.[[ByteLength]] to byteLength.
  10. Set O.[[ByteOffset]] to 0.
  11. Set O.[[ArrayLength]] to length.
  12. Set O.[[Stride]] to 1.
  13. Return O.

2.3.3 TypedArray ( typedArray )

Editor's Note

When copying a source TypedArray using this constructor, the stride is not preserved.

This description applies only if the TypedArray function is called with at least one argument and the Type of the first argument is Object and that object has a [[TypedArrayName]] internal slot.

TypedArray called with argument typedArray performs the following steps:

  1. Assert: Type(typedArray) is Object and typedArray has a [[TypedArrayName]] internal slot.
  2. If NewTarget is undefined, throw a TypeError exception.
  3. Let constructorName be the String value of the Constructor Name value specified in Table 63 for this TypedArray constructor.
  4. Let O be ? AllocateTypedArray(constructorName, NewTarget, "%TypedArray.prototype%").
  5. Let srcArray be typedArray.
  6. Let srcData be srcArray.[[ViewedArrayBuffer]].
  7. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
  8. Let elementType be the Element Type value in Table 63 for constructorName.
  9. Let elementLength be srcArray.[[ArrayLength]].
  10. Let srcName be the String value of srcArray.[[TypedArrayName]].
  11. Let srcType be the Element Type value in Table 63 for srcName.
  12. Let srcElementSize be the Element Size value specified in Table 63 for srcName.
  13. Let srcByteOffset be srcArray.[[ByteOffset]].
  14. Let srcStride be srcArray.[[Stride]].
  15. Let elementSize be the Element Size value specified in Table 63 for constructorName.
  16. Let byteLength be elementSize × elementLength.
  17. If IsSharedArrayBuffer(srcData) is false, then
    1. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%).
  18. Else,
    1. Let bufferConstructor be %ArrayBuffer%.
  19. If elementType is the same as srcType, then
    1. Let data be ? CloneArrayBuffer(srcData, srcByteOffset, srcElementSize, srcStride, srcStride, byteLength, bufferConstructor).
  20. Else,
    1. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength).
    2. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
    3. If srcArray.[[ContentType]] is not equal to O.[[ContentType]], throw a TypeError exception.
    4. Let srcByteIndex be srcByteOffset.
    5. Let targetByteIndex be 0.
    6. Let count be elementLength.
    7. Repeat, while count > 0
      1. Let value be GetValueFromBuffer(srcData, srcByteIndex, srcType, true, Unordered).
      2. Perform SetValueInBuffer(data, targetByteIndex, elementType, value, true, Unordered).
      3. Set srcByteIndex to srcByteIndex + srcElementSize × srcStride.
      4. Set targetByteIndex to targetByteIndex + elementSize.
      5. Set count to count - 1.
  21. Set O.[[ViewedArrayBuffer]] to data.
  22. Set O.[[ByteLength]] to byteLength.
  23. Set O.[[ByteOffset]] to 0.
  24. Set O.[[ArrayLength]] to elementLength.
  25. Set O.[[Stride]] to 1.
  26. Return O.

2.3.4 TypedArray ( buffer [ , byteOffset [ , length ] [ , stride ] ] )

This description applies only if the TypedArray function is called with at least one argument and the Type of the first argument is Object and that object has an [[ArrayBufferData]] internal slot.

TypedArray called with at least one argument buffer performs the following steps:

  1. Assert: Type(buffer) is Object and buffer has an [[ArrayBufferData]] internal slot.
  2. If NewTarget is undefined, throw a TypeError exception.
  3. Let constructorName be the String value of the Constructor Name value specified in Table 63 for this TypedArray constructor.
  4. Let O be ? AllocateTypedArray(constructorName, NewTarget, "%TypedArray.prototype%").
  5. Let elementSize be the Element Size value specified in Table 63 for constructorName.
  6. If stride is undefined, then
    1. Let newStride be 1.
  7. Else,
    1. Let newStride be ? ToInteger(length).
  8. If newStride ≤ 0, throw a RangeError exception.
  9. Let offset be ? ToIndex(byteOffset).
  10. If offset modulo (elementSize × newStride) ≠ 0, throw a RangeError exception.
  11. If length is not undefined, then
    1. Let newLength be ? ToIndex(length).
  12. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
  13. Let bufferByteLength be buffer.[[ArrayBufferByteLength]].
  14. If length is undefined, then
    1. If bufferByteLength modulo (elementSize × newStride) ≠ 0, throw a RangeError exception.
    2. Let newByteLength be (bufferByteLength - offset) / newStride.
    3. If newByteLength < 0, throw a RangeError exception.
  15. Else,
    1. Let newByteLength be newLength × elementSize × newStride.
    2. If offset + newByteLength > bufferByteLength, throw a RangeError exception.
  16. Set O.[[ViewedArrayBuffer]] to buffer.
  17. Set O.[[ByteLength]] to newByteLength.
  18. Set O.[[ByteOffset]] to offset.
  19. Set O.[[Stride]] to newStride.
  20. Set O.[[ArrayLength]] to newByteLength / elementSize.
  21. Return O.

2.4 Properties of TypedArray Instances

TypedArray instances are Integer-Indexed exotic objects. Each TypedArray instance inherits properties from the corresponding TypedArray prototype object. Each TypedArray instance has the following internal slots: [[TypedArrayName]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]], [[Stride]], and [[ArrayLength]].

3 Modifications to the Atomics Object

3.1 Modifications to Abstract Operations for Atomics

3.1.1 AtomicReadModifyWrite ( typedArray, index, value, op )

The abstract operation AtomicReadModifyWrite takes four arguments, typedArray, index, value, and a pure combining operation op. The pure combining operation op takes two List of byte values arguments and returns a List of byte values. The operation atomically loads a value, combines it with another value, and stores the result of the combination. It returns the loaded value. It performs the following steps:

  1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray).
  2. Let i be ? ValidateAtomicAccess(typedArray, index).
  3. Let arrayTypeName be typedArray.[[TypedArrayName]].
  4. If typedArray.[[ContentType]] is BigInt, let v be ? ToBigInt(value).
  5. Otherwise, let v be ? ToInteger(value).
  6. Let elementSize be the Element Size value specified in Table 63 for arrayTypeName.
  7. Let elementType be the Element Type value in Table 63 for arrayTypeName.
  8. Let offset be typedArray.[[ByteOffset]].
  9. Let stride be typedArray.[[Stride]].
  10. Let indexedPosition be (i × elementSize × stride) + offset.
  11. Return GetModifySetValueInBuffer(buffer, indexedPosition, elementType, v, op).

3.1.2 AtomicLoad ( typedArray, index )

The abstract operation AtomicLoad takes two arguments, typedArray, index. The operation atomically loads a value and returns the loaded value. It performs the following steps:

  1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray).
  2. Let i be ? ValidateAtomicAccess(typedArray, index).
  3. Let arrayTypeName be typedArray.[[TypedArrayName]].
  4. Let elementSize be the Element Size value specified in Table 63 for arrayTypeName.
  5. Let elementType be the Element Type value in Table 63 for arrayTypeName.
  6. Let offset be typedArray.[[ByteOffset]].
  7. Let stride be typedArray.[[Stride]].
  8. Let indexedPosition be (i × elementSize × stride) + offset.
  9. Return GetValueFromBuffer(buffer, indexedPosition, elementType, true, SeqCst).

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

The following steps are taken:

  1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray).
  2. Let i be ? ValidateAtomicAccess(typedArray, index).
  3. Let arrayTypeName be typedArray.[[TypedArrayName]].
  4. If typedArray.[[ContentType]] is BigInt, then
    1. Let expected be ? ToBigInt(expectedValue).
    2. Let replacement be ? ToBigInt(replacementValue).
  5. Else,
    1. Let expected be ? ToInteger(expectedValue).
    2. Let replacement be ? ToInteger(replacementValue).
  6. Let elementType be the Element Type value in Table 63 for arrayTypeName.
  7. Let isLittleEndian be the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
  8. Let expectedBytes be NumericToRawBytes(elementType, expected, isLittleEndian).
  9. Let elementSize be the Element Size value specified in Table 63 for arrayTypeName.
  10. Let offset be typedArray.[[ByteOffset]].
  11. Let stride be typedArray.[[Stride]].
  12. Let indexedPosition be (i × elementSize × stride) + offset.
  13. Let compareExchange denote a semantic function of two List of byte values arguments that returns the second argument if the first argument is element-wise equal to expectedBytes.
  14. Return GetModifySetValueInBuffer(buffer, indexedPosition, elementType, replacement, compareExchange).

3.3 Atomics.store ( typedArray, index, value )

The following steps are taken:

  1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray).
  2. Let i be ? ValidateAtomicAccess(typedArray, index).
  3. Let arrayTypeName be typedArray.[[TypedArrayName]].
  4. If arrayTypeName is "BigUint64Array" or "BigInt64Array", let v be ? ToBigInt(value).
  5. Otherwise, let v be ? ToInteger(value).
  6. Let elementSize be the Element Size value specified in Table 63 for arrayTypeName.
  7. Let elementType be the Element Type value in Table 63 for arrayTypeName.
  8. Let offset be typedArray.[[ByteOffset]].
  9. Let stride be typedArray.[[Stride]].
  10. Let indexedPosition be (i × elementSize × stride) + offset.
  11. Perform SetValueInBuffer(buffer, indexedPosition, elementType, v, true, SeqCst).
  12. Return v.

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

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

  1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray, true).
  2. Let i be ? ValidateAtomicAccess(typedArray, index).
  3. Let arrayTypeName be typedArray.[[TypedArrayName]].
  4. If arrayTypeName is "BigInt64Array", let v be ? ToBigInt64(value).
  5. Otherwise, let v be ? ToInt32(value).
  6. Let q be ? ToNumber(timeout).
  7. If q is NaN, let t be +∞; else let t be max(q, 0).
  8. Let B be AgentCanSuspend().
  9. If B is false, throw a TypeError exception.
  10. Let block be buffer.[[ArrayBufferData]].
  11. Let offset be typedArray.[[ByteOffset]].
  12. Let stride be typedArray.[[Stride]].
  13. Let elementSize be the Element Size value specified in Table 63 for arrayTypeName.
  14. Let indexedPosition be (i × elementSize × stride) + offset.
  15. Let WL be GetWaiterList(block, indexedPosition).
  16. Perform EnterCriticalSection(WL).
  17. Let w be ! AtomicLoad(typedArray, i).
  18. If v is not equal to w, then
    1. Perform LeaveCriticalSection(WL).
    2. Return the String "not-equal".
  19. Let W be AgentSignifier().
  20. Perform AddWaiter(WL, W).
  21. Let notified be Suspend(WL, W, t).
  22. If notified is true, then
    1. Assert: W is not on the list of waiters in WL.
  23. Else,
    1. Perform RemoveWaiter(WL, W).
  24. Perform LeaveCriticalSection(WL).
  25. If notified is true, return the String "ok".
  26. Return the String "timed-out".

3.5 Atomics.notify ( typedArray, index, count )

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

  1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray, true).
  2. Let i be ? ValidateAtomicAccess(typedArray, index).
  3. If count is undefined, let c be +∞.
  4. Else,
    1. Let intCount be ? ToInteger(count).
    2. Let c be max(intCount, 0).
  5. Let block be buffer.[[ArrayBufferData]].
  6. Let offset be typedArray.[[ByteOffset]].
  7. Let stride be typedArray.[[Stride]].
  8. Let arrayTypeName be typedArray.[[TypedArrayName]].
  9. Let elementSize be the Element Size value specified in Table 63 for arrayTypeName.
  10. Let indexedPosition be (i × elementSize × stride) + offset.
  11. Let WL be GetWaiterList(block, indexedPosition).
  12. Let n be 0.
  13. Perform EnterCriticalSection(WL).
  14. Let S be RemoveWaiters(WL, c).
  15. Repeat, while S is not an empty List,
    1. Let W be the first agent in S.
    2. Remove W from the front of S.
    3. Perform NotifyWaiter(WL, W).
    4. Set n to n + 1.
  16. Perform LeaveCriticalSection(WL).
  17. Return n.

A Copyright & Software License

Copyright Notice

© 2020 Shu-yu Guo, Surma

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.