Stage 2 Draft / February 24, 2021

ResizableArrayBuffer and GrowableSharedArrayBuffer

We provide two new constructors, ResizableArrayBuffer and GrowableSharedArrayBuffer, which allow dynamically resizable array buffers. In addition, a transfer method is added to the existing ArrayBuffer prototype.

1 Modifications to Abstract Operations for ArrayBuffer Objects

1.1 AllocateArrayBuffer ( constructor, byteLength[ , requestedMaxByteLength ] )

The abstract operation AllocateArrayBuffer takes arguments constructor and, byteLength, and requestedMaxByteLength. It is used to create an ArrayBuffer object. It performs the following steps when called:

  1. Let slots be « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] ».
  2. If requestedMaxByteLength is present, append [[ArrayBufferMaxByteLength]] to slots.
  3. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBuffer.prototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] »_slots).
  4. Let block be ? CreateByteDataBlock(byteLength).
  5. Set obj.[[ArrayBufferData]] to block.
  6. Set obj.[[ArrayBufferByteLength]] to byteLength.
  7. If requestedMaxByteLength is present, then
    1. Let maxByteLength be an implementation-defined value that is either = requestedMaxByteLength or both ≥ requestedMaxByteLength and a power of 2.
    2. NOTE: Implementations may choose to round up the requested maximum byte length, for example, to be on a page boundary.
    3. If it is not possible to create a Data Block block consisting of maxByteLength bytes, throw a RangeError exception.
    4. NOTE: ResizableArrayBuffers are designed to be implementable with in-place growth. Implementations reserve the right to throw if, for example, virtual memory cannot be reserved up front.
    5. Set obj.[[ArrayBufferMaxByteLength]] to maxByteLength.
  8. Return obj.

1.2 ArrayBufferByteLength ( arrayBuffer )

The abstract operation ArrayBufferByteLength takes argument arrayBuffer. It performs the following steps when called:

  1. Assert: Type(arrayBuffer) is Object and it has an [[ArrayBufferData]] internal slot.
  2. If IsSharedArrayBuffer(arrayBuffer) is true and arrayBuffer has an [[ArrayBufferByteLengthData]] internal slot, then
    1. Let bufferByteLengthBlock be O.[[ArrayBufferByteLengthData]].
    2. Return (GetValueFromBuffer(bufferByteLengthBlock, 0, Uint64, true, SeqCst)).
  3. Assert: IsDetachedBuffer(arrayBuffer) is false.
  4. Return arrayBuffer.[[ArrayBufferByteLength]].

1.3 IsResizableArrayBuffer ( arrayBuffer )

The abstract operation IsResizableArrayBuffer takes argument arrayBuffer. It performs the following steps when called:

  1. Assert: Type(arrayBuffer) is Object and it has an [[ArrayBufferData]] internal slot.
  2. If buffer has an [[ArrayBufferMaxByteLength]] internal slot, return true.
  3. Return false.

2 ResizableArrayBuffer Objects

2.1 The ResizableArrayBuffer Constructor

The ResizableArrayBuffer constructor:

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

2.1.1 ResizableArrayBuffer ( initialLength, maxLength )

When the ResizableArrayBuffer function is called with arguments initialLength and maxLength, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let byteLength be ? ToIndex(initialLength).
  3. Let maxByteLength be ? ToIndex(maxLength).
  4. If byteLength > maxByteLength, throw a RangeError exception.
  5. Return ? AllocateArrayBuffer(NewTarget, byteLength, maxByteLength).

2.2 Properties of the ResizableArrayBuffer Constructor

The ResizableArrayBuffer constructor:

2.3 ResizableArrayBuffer.prototype

The initial value of ResizableArrayBuffer.prototype is the ResizableArrayBuffer prototype object.

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

2.4 Properties of the ResizableArrayBuffer Prototype Object

The ResizableArrayBuffer prototype object:

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

2.4.1 get ResizableArrayBuffer.prototype.byteLength

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

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]).
  3. If IsDetachedBuffer(O) is true, return +0𝔽.
  4. Let length be ArrayBufferByteLength(O).
  5. Return 𝔽(length).

2.4.2 ResizableArrayBuffer.prototype.constructor

The initial value of ResizableArrayBuffer.prototype.constructor is %ResizableArrayBuffer%.

2.4.3 get ResizableArrayBuffer.prototype.maxByteLength

ResizableArrayBuffer.prototype.maxByteLength is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]).
  3. If IsDetachedBuffer(O) is true, return +0𝔽.
  4. Let length be O.[[ArrayBufferMaxByteLength]].
  5. Return 𝔽(length).

2.4.4 ResizableArrayBuffer.prototype.resize ( newLength )

The following steps are taken:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]).
  3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception.
  4. If IsDetachedBuffer(O) is true, throw a TypeError exception.
  5. Let newByteLength to ? ToIntegerOrInfinity(newLength).
  6. Let oldBlock be O.[[ArrayBufferData]].
  7. If newByteLength < 0 or newByteLength > O.[[ArrayBufferMaxByteLength]], throw a RangeError exception.
  8. Let newBlock be ? CreateByteDataBlock(newByteLength).
  9. Let copyLength be min(newByteLength, O.[[ArrayBufferByteLength]]).
  10. Perform CopyDataBlockBytes(newBlock, 0, oldBlock, 0, copyLength).
  11. NOTE: Neither creation of the new Data Block nor copying from the old Data Block are observable. Implementations reserve the right to implement this method as in-place growth or shrinkage.
  12. Set O.[[ArrayBufferByteLength]] to newLength.
  13. Return undefined.

2.4.5 ResizableArrayBuffer.prototype.slice ( start, end )

The following steps are taken:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]).
  3. If IsDetachedBuffer(O) is true, throw a TypeError exception.
  4. Let len be O.[[ArrayBufferByteLength]].
  5. Let relativeStart be ? ToIntegerOrInfinity(start).
  6. If relativeStart is -∞, let first be 0.
  7. Else if relativeStart < 0, let first be max(len + relativeStart, 0).
  8. Else, let first be min(relativeStart, len).
  9. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
  10. If relativeEnd is -∞, let final be 0.
  11. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0).
  12. Else, let final be min(relativeEnd, len).
  13. Let newLen be max(final - first, 0).
  14. Let new be ? Construct(%ArrayBuffer%, « 𝔽(newLen) »).
  15. NOTE: This method returns a fixed ArrayBuffer.
  16. Let fromBlock be O.[[ArrayBufferData]].
  17. Let toBlock be new.[[ArrayBufferData]].
  18. Perform CopyDataBlockBytes(toBlock, 0, fromBlock, first, newLen).
  19. Return new.

2.4.6 ResizableArrayBuffer.prototype.transfer ( [ newLength ] )

The following steps are taken:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]).
  3. If IsDetachedBuffer(O) is true, throw a TypeError exception.
  4. If newLength is not present, let newByteLength be O.[[ArrayBufferByteLength]].
  5. Else, let newByteLength be ? ToIntegerOrInfinity(newLength).
  6. Let new be ? Construct(%ArrayBuffer%, « 𝔽(newByteLength) »).
  7. NOTE: This method returns a fixed ArrayBuffer.
  8. Let copyLength be min(newByteLength, O.[[ArrayBufferByteLength]]).
  9. Let fromBlock be O.[[ArrayBufferData]].
  10. Let toBlock be new.[[ArrayBufferData]].
  11. Perform CopyDataBlockBytes(toBlock, 0, fromBlock, 0, copyLength).
  12. NOTE: Neither creation of the new Data Block nor copying from the old Data Block are observable. Implementations reserve the right to implement this method as a zero-copy move or a realloc.
  13. Perform ! DetachArrayBuffer(O).
  14. Return new.

2.4.7 ResizableArrayBuffer.prototype [ @@toStringTag ]

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

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

3 Modifications to Abstract Operations for SharedArrayBuffer Objects

3.1 AllocateSharedArrayBuffer ( constructor, byteLength[ , requestedMaxByteLength ] )

The abstract operation AllocateSharedArrayBuffer takes arguments constructor and, byteLength, and requestedMaxByteLength. It is used to create a SharedArrayBuffer object. It performs the following steps when called:

  1. Let slots be « [[ArrayBufferData]] ».
  2. If requestedMaxByteLength is present, then:
  3. Append [[ArrayBufferByteLengthData]] and [[ArrayBufferMaxByteLength]] to slots.
    1. Let maxByteLength be an implementation-defined value that is either = requestedMaxByteLength or both ≥ requestedMaxByteLength and a power of 2.
    2. NOTE: Implementations may choose to round up the requested maximum byte length, for example, to be on a page boundary.
  4. Else, append [[ArrayBufferByteLength]] to slots.
  5. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%SharedArrayBuffer.prototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]] »slots).
  6. Assert: byteLengthmaxByteLength.
  7. If maxByteLength is present, then let allocLength be byteLength.
  8. Else, let allocLength be maxByteLength
  9. Let block be ? CreateSharedByteDataBlock(byteLengthallocLength).
  10. NOTE: GrowableSharedArrayBuffers must be implemented as in-place growable. Creation of a maxByteLength sized Data Block is a specification mechanism. It may be implemented as committing a byteLength sized buffer while reserving maxByteLength in virtual memory.
  11. Set obj.[[ArrayBufferData]] to block.
  12. If maxByteLength is present, then
    1. Let byteLengthBlock be ? CreateSharedByteDataBlock(4).
    2. Perform SetValueInBuffer(byteLengthBlock, 0, Uint64, 𝔽(byteLength), true, SeqCst).
    3. Set obj.[[ArrayBufferByteLengthData]] to byteLengthBlock.
    4. Set obj.[[ArrayBufferMaxByteLength]] to maxByteLength.
  13. Else,
    1. Set obj.[[ArrayBufferByteLength]] to byteLength.
  14. Return obj.

4 GrowableSharedArrayBuffer Objects

4.1 The GrowableSharedArrayBuffer Constructor

The GrowableSharedArrayBuffer constructor:

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

4.1.1 GrowableSharedArrayBuffer ( initialLength, maxLength )

When the GrowableSharedArrayBuffer function is called with arguments initialLength and maxLength, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let byteLength be ? ToIndex(initialLength).
  3. Let maxByteLength be ? ToIndex(maxLength).
  4. If byteLength > maxByteLength, throw a RangeError exception.
  5. Return ? AllocateSharedArrayBuffer(NewTarget, byteLength, maxByteLength).

4.2 Properties of the GrowableSharedArrayBuffer Constructor

The GrowableSharedArrayBuffer constructor:

4.3 GrowableSharedArrayBuffer.prototype

The initial value of GrowableSharedArrayBuffer.prototype is the GrowableSharedArrayBuffer prototype object.

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

4.4 Properties of the GrowableSharedArrayBuffer Prototype Object

The GrowableSharedArrayBuffer prototype object:

  • is %GrowableSharedArrayBuffer.prototype%.
  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • is an ordinary object.
  • does not have an [[ArrayBufferData]], [[ArrayBufferByteLengthData]], or [[ArrayBufferMaxByteLength]] internal slot.

4.4.1 get GrowableSharedArrayBuffer.prototype.byteLength

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

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

4.4.2 GrowableSharedArrayBuffer.prototype.constructor

The initial value of GrowableSharedArrayBuffer.prototype.constructor is %GrowableSharedArrayBuffer%.

4.4.3 get GrowableSharedArrayBuffer.prototype.maxByteLength

GrowableSharedArrayBuffer.prototype.maxByteLength is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

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

4.4.4 GrowableSharedArrayBuffer.prototype.grow ( newLength )

The following steps are taken:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]).
  3. If IsSharedArrayBuffer(O) is false, throw a TypeError exception.
  4. Let newByteLength to ? ToIntegerOrInfinity(newLength).
  5. If newByteLengthArrayBufferByteLength(O), then
    1. Note: Resizes to the same length explicitly do nothing to avoid gratuitous synchronization.
    2. If newByteLength < ArrayBufferByteLength(O) or newByteLength > O.[[ArrayBufferMaxByteLength]], throw a RangeError exception.
    3. Let byteLengthBlock be O.[[ArrayBufferByteLengthData]].
    4. Perform SetValueInBuffer(byteLengthBlock, 0, Uint64, 𝔽(newByteLength), true, SeqCst).
    5. TODO: Verify memory model event for the resize.
  6. Return undefined.

4.4.5 GrowableSharedArrayBuffer.prototype.slice ( start, end )

The following steps are taken:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[ArrayBufferMaxByteLength]]).
  3. If IsSharedArrayBuffer(O) is false, throw a TypeError exception.
  4. Let len be ArrayBufferByteLength(O).
  5. Let relativeStart be ? ToIntegerOrInfinity(start).
  6. If relativeStart is -∞, let first be 0.
  7. Else if relativeStart < 0, let first be max(len + relativeStart, 0).
  8. Else, let first be min(relativeStart, len).
  9. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
  10. If relativeEnd is -∞, let final be 0.
  11. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0).
  12. Else, let final be min(relativeEnd, len).
  13. Let newLen be max(final - first, 0).
  14. Let new be ? Construct(%SharedArrayBuffer%, « 𝔽(newLen) »).
  15. NOTE: This method returns a fixed SharedArrayBuffer.
  16. Let fromBlock be O.[[ArrayBufferData]].
  17. Let toBlock be new.[[ArrayBufferData]].
  18. Perform CopyDataBlockBytes(toBlock, 0, fromBlock, first, newLen).
  19. Return new.

4.4.6 GrowableSharedArrayBuffer.prototype [ @@toStringTag ]

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

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

5 Modifications to Properties of the ArrayBuffer Prototype Object

5.1 get ArrayBuffer.prototype.byteLength

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

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

5.2 ArrayBuffer.prototype.slice ( start, end )

The following steps are taken:

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

5.3 ArrayBuffer.prototype.transfer ( [ newLength ] )

The following steps are taken:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]).
  3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception.
  4. If IsDetachedBuffer(O) is true, throw a TypeError exception.
  5. If newLength is not present, let newByteLength be O.[[ArrayBufferByteLength]].
  6. Else, let newByteLength be ? ToIntegerOrInfinity(newLength).
  7. Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%).
  8. Let new be ? Construct(ctor, « 𝔽(newLen) »).
  9. Perform ? RequireInternalSlot(new, [[ArrayBufferData]]).
  10. If IsSharedArrayBuffer(new) is true, throw a TypeError exception.
  11. If IsResizableArrayBuffer(new) is true, throw a TypeError exception.
  12. If IsDetachedBuffer(new) is true, throw a TypeError exception.
  13. If SameValue(new, O) is true, throw a TypeError exception.
  14. Let copyLength be min(newByteLength, O.[[ArrayBufferByteLength]]).
  15. Let fromBlock be O.[[ArrayBufferData]].
  16. Let toBlock be new.[[ArrayBufferData]].
  17. Perform CopyDataBlockBytes(toBlock, 0, fromBlock, 0, copyLength).
  18. NOTE: Neither creation of the new Data Block nor copying from the old Data Block are observable. Implementations reserve the right to implement this method as a zero-copy move or a realloc.
  19. Perform ! DetachArrayBuffer(O).
  20. Return new.

6 Modifications to Properties of the SharedArrayBuffer Prototype Object

6.1 get SharedArrayBuffer.prototype.byteLength

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

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

6.2 SharedArrayBuffer.prototype.slice ( start, end )

The following steps are taken:

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

7 Modifications to Integer-Indexed Exotic Objects

7.1 [[OwnPropertyKeys]] ( )

When the [[OwnPropertyKeys]] internal method of an Integer-Indexed exotic object O is called, the following steps are taken:

  1. Let keys be a new empty List.
  2. Assert: O is an Integer-Indexed exotic object.
  3. Let len be O.[[ArrayLength]].
  4. Let len be IntegerIndexedObjectLength(O).
  5. For each integer i starting with 0 such that i < len, in ascending order, do
    1. Add ! ToString(i) as the last element of keys.
  6. For each own property key P of O such that Type(P) is String and P is not an integer index, in ascending chronological order of property creation, do
    1. Add P as the last element of keys.
  7. For each own property key P of O such that Type(P) is Symbol, in ascending chronological order of property creation, do
    1. Add P as the last element of keys.
  8. Return keys.

7.2 IsValidIntegerIndex ( O, index )

The abstract operation IsValidIntegerIndex takes arguments O and index. It performs the following steps when called:

  1. Assert: O is an Integer-Indexed exotic object.
  2. Assert: Type(index) is Number.
  3. If ! IsInteger(index) is false, return false.
  4. If index is -0𝔽, return false.
  5. If CheckIntegerIndexedObjectOutOfBounds(O) is true, return false.
  6. If (index) < 0 or (index) ≥ O.[[ArrayLength]]IntegerIndexedObjectLength(O), return false.
  7. Return true.

7.3 IntegerIndexedObjectByteLength ( O )

The abstract operation IntegerIndexedObjectByteLength takes arguments O. It performs the following steps when called:

  1. Assert: O is an Integer-Indexed exotic object.
  2. If CheckIntegerIndexedObjectOutOfBounds(O) is true, return 0.
  3. If O.[[ByteLength]] is not auto, return O.[[ByteLength]].
  4. Let elementSize be the Element Size value specified in Table 63 for O.[[TypedArrayName]].
  5. Return IntegerIndexedObjectLength(O) × elementSize.

7.4 IntegerIndexedObjectLength ( O )

The abstract operation IntegerIndexedObjectLength takes arguments O. It performs the following steps when called:

  1. Assert: O is an Integer-Indexed exotic object.
  2. If CheckIntegerIndexedObjectOutOfBounds(O) is true, return 0.
  3. If O.[[ArrayLength]] is not auto, return O.[[ArrayLength]].
  4. Let buffer be O.[[ViewedArrayBuffer]].
  5. Assert: IsResizableArrayBuffer(buffer) is true.
  6. Let bufferByteLength be ArrayBufferByteLength(buffer).
  7. Let byteOffset be O.[[ByteOffset]].
  8. Let elementSize be the Element Size value specified in Table 63 for O.[[TypedArrayName]].
  9. Let length be floor((bufferByteLength - byteOffset) / elementSize).
  10. Return length.

7.5 CheckIntegerIndexedObjectOutOfBounds ( O )

The abstract operation CheckIntegerIndexedObjectOutOfBounds takes arguments O. It checks if any part of the underlying viewed buffer is out of bounds. It performs the following steps when called:

  1. Assert: O is an Integer-Indexed exotic object.
  2. Let buffer be O.[[ViewedArrayBuffer]].
  3. Let bufferByteLength be ArrayBufferByteLength(buffer).
  4. Let byteOffsetStart be O.[[ByteOffset]].
  5. If O.[[ArrayLength]] is auto, then
    1. Let byteOffsetEnd be bufferByteLength.
  6. Else,
    1. Let elementSize be the Element Size value specified in Table 63 for O.[[TypedArrayName]].
    2. Let byteOffsetEnd be O.[[ArrayLength]] × elementSize.
  7. If byteOffsetStartbufferByteLength or byteOffsetEndbufferByteLength, then return true.
  8. Return false.

8 Modifications to TypedArray Objects

8.1 Modifications to Properties of the %TypedArray.prototype% Object

8.1.1 Runtime Semantics: ValidateTypedArray ( O )

The abstract operation ValidateTypedArray takes argument O. It performs the following steps when called:

  1. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
  2. Assert: O has a [[ViewedArrayBuffer]] internal slot.
  3. Let buffer be O.[[ViewedArrayBuffer]].
  4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
  5. If CheckIntegerIndexedObjectOutOfBounds(O) is true, throw a TypeError exception.
  6. Return buffer.

8.1.2 get %TypedArray%.prototype.byteLength

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

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

8.1.3 get %TypedArray%.prototype.byteOffset

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

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
  3. Assert: O has a [[ViewedArrayBuffer]] internal slot.
  4. Let buffer be O.[[ViewedArrayBuffer]].
  5. If IsDetachedBuffer(buffer) is true, return +0𝔽.
  6. If CheckIntegerIndexedObjectOutOfBounds(O) is true, return +0𝔽.
  7. Let offset be O.[[ByteOffset]].
  8. Return 𝔽(offset).

8.1.4 get %TypedArray%.prototype.length

%TypedArray%.prototype.length is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
  3. Assert: O has [[ViewedArrayBuffer]] and [[ArrayLength]] internal slots.
  4. Let buffer be O.[[ViewedArrayBuffer]].
  5. If IsDetachedBuffer(buffer) is true, return +0𝔽.
  6. Let length be O.[[ArrayLength]]IntegerIndexedObjectLength(O).
  7. Return 𝔽(length).

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

8.1.5 SetTypedArrayFromTypedArray ( target, targetOffset, source )

The abstract operation SetTypedArrayFromTypedArray takes arguments target (a TypedArray object), targetOffset (a non-negative integer or +∞), and source (a TypedArray object). It sets multiple values in target, starting at index targetOffset, reading the values from source. It performs the following steps when called:

  1. Assert: source is an Object that has a [[TypedArrayName]] internal slot.
  2. Let targetBuffer be target.[[ViewedArrayBuffer]].
  3. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
  4. Let targetLength be target.[[ArrayLength]]IntegerIndexedObjectLength(target).
  5. Let srcBuffer be source.[[ViewedArrayBuffer]].
  6. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
  7. If CheckIntegerIndexedObjectOutOfBounds(target) is true, throw a TypeError exception.
  8. Let targetName be the String value of target.[[TypedArrayName]].
  9. Let targetType be the Element Type value in Table 63 for targetName.
  10. Let targetElementSize be the Element Size value specified in Table 63 for targetName.
  11. Let targetByteOffset be target.[[ByteOffset]].
  12. Let srcName be the String value of source.[[TypedArrayName]].
  13. Let srcType be the Element Type value in Table 63 for srcName.
  14. Let srcElementSize be the Element Size value specified in Table 63 for srcName.
  15. Let srcLength be source.[[ArrayLength]].
  16. Let srcByteOffset be source.[[ByteOffset]].
  17. If targetOffset is +∞, throw a RangeError exception.
  18. If srcLength + targetOffset > targetLength, throw a RangeError exception.
  19. If target.[[ContentType]] ≠ source.[[ContentType]], throw a TypeError exception.
  20. 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.
  21. Else, let same be SameValue(srcBuffer, targetBuffer).
  22. If same is true, then
    1. Let srcByteLength be source.[[ByteLength]]IntegerIndexedObjectByteLength(source).
    2. Set srcBuffer to ? CloneArrayBuffer(srcBuffer, srcByteOffset, 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.
  23. Else, let srcByteIndex be srcByteOffset.
  24. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset.
  25. Let limit be targetByteIndex + targetElementSize × srcLength.
  26. 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 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.
  27. 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.
      4. Set targetByteIndex to targetByteIndex + targetElementSize.

8.2 Modifications to the TypedArray Constructors

8.2.1 InitializeTypedArrayFromTypedArray ( O, srcArray )

The abstract operation InitializeTypedArrayFromTypedArray takes arguments O (a TypedArray object) and srcArray (a TypedArray object). It performs the following steps when called:

  1. Assert: O is an Object that has a [[TypedArrayName]] internal slot.
  2. Assert: srcArray is an Object that has a [[TypedArrayName]] internal slot.
  3. Let srcData be srcArray.[[ViewedArrayBuffer]].
  4. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
  5. Let constructorName be the String value of O.[[TypedArrayName]].
  6. Let elementType be the Element Type value in Table 63 for constructorName.
  7. Let elementLength be srcArray.[[ArrayLength]]IntegerIndexedObjectLength(srcArray).
  8. Let srcName be the String value of srcArray.[[TypedArrayName]].
  9. Let srcType be the Element Type value in Table 63 for srcName.
  10. Let srcElementSize be the Element Size value specified in Table 63 for srcName.
  11. Let srcByteOffset be srcArray.[[ByteOffset]].
  12. Let elementSize be the Element Size value specified in Table 63 for constructorName.
  13. Let byteLength be elementSize × elementLength.
  14. If IsSharedArrayBuffer(srcData) is false, then
    1. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%).
  15. Else,
    1. Let bufferConstructor be %ArrayBuffer%.
  16. If elementType is the same as srcType, then
    1. Let data be ? CloneArrayBuffer(srcData, srcByteOffset, byteLength, bufferConstructor).
  17. Else,
    1. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength).
    2. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
    3. If CheckIntegerIndexedObjectOutOfBounds(srcArray) is true, throw a TypeError exception.
    4. If srcArray.[[ContentType]] ≠ O.[[ContentType]], throw a TypeError exception.
    5. Let srcByteIndex be srcByteOffset.
    6. Let targetByteIndex be 0.
    7. Let count be elementLength.
    8. 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.
      4. Set targetByteIndex to targetByteIndex + elementSize.
      5. Set count to count - 1.
  18. Set O.[[ViewedArrayBuffer]] to data.
  19. Set O.[[ByteLength]] to byteLength.
  20. Set O.[[ByteOffset]] to 0.
  21. Set O.[[ArrayLength]] to elementLength.

8.2.2 InitializeTypedArrayFromArrayBuffer ( O, buffer, byteOffset, length )

The abstract operation InitializeTypedArrayFromArrayBuffer takes arguments O (a TypedArray object), buffer (an ArrayBuffer object), byteOffset (an ECMAScript language value), and length (an ECMAScript language value). It performs the following steps when called:

  1. Assert: O is an Object that has a [[TypedArrayName]] internal slot.
  2. Assert: buffer is an Object that has an [[ArrayBufferData]] internal slot.
  3. Let constructorName be the String value of O.[[TypedArrayName]].
  4. Let elementSize be the Element Size value specified in Table 63 for constructorName.
  5. Let offset be ? ToIndex(byteOffset).
  6. If offset modulo elementSize ≠ 0, throw a RangeError exception
  7. Let bufferIsResizable be IsResizableArrayBuffer(buffer)..
  8. If length is not undefined, then
    1. Let newLength be ? ToIndex(length).
  9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
  10. Let bufferByteLength be buffer.[[ArrayBufferByteLength]]ArrayBufferByteLength(buffer)..
  11. If length is undefined and bufferIsResizable is true, then
    1. If offset > bufferByteLength, throw a RangeError exception.
    2. Set O.[[ByteLength]] to auto.
    3. Set O.[[ArrayLength]] to auto.
  12. Else,
    1. If length is undefined, then
      1. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError exception.
      2. Let newByteLength be bufferByteLength - offset.
      3. If newByteLength < 0, throw a RangeError exception.
    2. Else,
      1. Let newByteLength be newLength × elementSize.
      2. If offset + newByteLength > bufferByteLength, throw a RangeError exception.
    3. Set O.[[ViewedArrayBuffer]] to buffer.
    4. Set O.[[ByteLength]] to newByteLength.
    5. Set O.[[ByteOffset]] to offset.
    6. Set O.[[ArrayLength]] to newByteLength / elementSize.
  13. Set O.[[ViewedArrayBuffer]] to buffer.
  14. Set O.[[ByteOffset]] to offset.

9 Modifications to DataView Objects

9.1 Modifications to Abstract Operations For DataView Objects

9.1.1 GetViewByteLength ( view )

The abstract operation GetViewByteLength takes argument view. It performs the following steps when called:

  1. Perform ? RequireInternalSlot(view, [[DataView]]).
  2. If view.[[ByteLength]] is not auto, then return view.[[ByteLength]].
  3. Let buffer be view.[[ViewedArrayBuffer]].
  4. Return ArrayBufferByteLength(buffer).

9.1.2 CheckViewOutOfBounds ( view )

The abstract operation CheckViewOutOfBounds takes argument view. It performs the following steps when called:

  1. Perform ? RequireInternalSlot(view, [[DataView]]).
  2. Let byteLength be GetViewByteLength(view).
  3. Let buffer be view.[[ViewedArrayBuffer]].
  4. Let bufferByteLength be ArrayBufferByteLength(buffer).
  5. If view.[[ByteOffset]] + byteLength > bufferByteLength, then return true.
  6. Return false.

9.1.3 GetViewValue ( view, requestIndex, isLittleEndian, type )

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

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

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

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

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

9.2 Modifications to the DataView Constructor

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

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

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

9.3 Modifications to Properties of the DataView Prototype Object

9.3.1 get DataView.prototype.byteLength

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

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

9.3.2 get DataView.prototype.byteOffset

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

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

10 Mechanical Changes Omitted for Brevity