Skip to content

Commit d3f11d8

Browse files
authored
Normative: Account for immutability in ArrayBuffer.prototype.{resize,slice} (#4)
1 parent 7a30150 commit d3f11d8

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@ The [OCapN](https://ocapn.org/) network protocol treats strings and byte-arrays
4040

4141
## Solution
4242

43-
This proposal introduces additional methods and read-only accessor properties to `ArrayBuffer.prototype` that fit naturally into those explained above. Just as a buffer can be resizable or not, or detached or not, this proposal enables buffers to be immutable or not. Just as `transferToFixedSize` moves the contents of a original buffer into a newly created non-resizable buffer, this proposal provides a transfer operation that moves the contents of an original original buffer into a newly created immutable buffer. Altogether, this proposal only adds to `ArrayBuffer.prototype` one method
43+
This proposal introduces additional methods and read-only accessor properties to `ArrayBuffer.prototype` that fit naturally into those explained above. Just as a buffer can be resizable or not, and detached or not, this proposal enables buffers to be immutable or not. Just as `transferToFixedSize` moves the contents of a original buffer into a newly created non-resizable buffer, this proposal provides a transfer operation that moves the contents of an original original buffer into a newly created immutable buffer. Altogether, this proposal only adds to `ArrayBuffer.prototype` one method
4444
- `transferToImmutable() :ArrayBuffer` -- move the contents of the original buffer into a new immutable buffer, detach the original buffer, and return the new buffer.
4545

4646
and one read-only accessor
4747
- `immutable: boolean` -- is this buffer immutable, or can its contents be changed?
4848

49-
An immutable buffer cannot be detached or resized. Its `maxByteLength` is the same as its `byteLength`. A `DataView` or `TypedArray` using an immutable buffer as its backing store can be frozen and immutable. `ArrayBuffer`s, `DataView`s, and `TypedArray`s that are frozen and immutable could be placed in ROM without going beyond JavaScript's official semantics.
49+
An immutable buffer cannot be detached, resized, or further transferred. Its `maxByteLength` is the same as its `byteLength`. A `DataView` or `TypedArray` using an immutable buffer as its backing store can be frozen and immutable. `ArrayBuffer`s, `DataView`s, and `TypedArray`s that are frozen and immutable could be placed in ROM without going beyond JavaScript's official semantics.
50+
51+
The ArrayBuffer `slice` method and TypedArray methods that create new ArrayBuffers (`filter`, `map`, `slice`, `toReversed`, etc.) make no effort to preserve immutability, just like they make no effort to preserve resizability (although use of SpeciesConstructor in those methods means that _lack_ of resizability/immutability in the result cannot be guaranteed for the latter).
5052

5153
## Implementations
5254

spec.emu

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,68 @@ contributors: Mark S. Miller, Richard Gibson
495495
</emu-clause>
496496
</ins>
497497

498+
<emu-clause id="sec-arraybuffer.prototype.resize" number="6">
499+
<h1>ArrayBuffer.prototype.resize ( _newLength_ )</h1>
500+
<p>This method performs the following steps when called:</p>
501+
<emu-alg>
502+
1. Let _O_ be the *this* value.
503+
1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferMaxByteLength]]).
504+
1. If IsSharedArrayBuffer(_O_) is *true*, throw a *TypeError* exception.
505+
1. Let _newByteLength_ be ? ToIndex(_newLength_).
506+
1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception.
507+
1. <ins>If IsImmutableBuffer(_O_) is *true*, throw a *TypeError* exception.</ins>
508+
1. If _newByteLength_ > _O_.[[ArrayBufferMaxByteLength]], throw a *RangeError* exception.
509+
1. Let _hostHandled_ be ? HostResizeArrayBuffer(_O_, _newByteLength_).
510+
1. If _hostHandled_ is ~handled~, return *undefined*.
511+
1. Let _oldBlock_ be _O_.[[ArrayBufferData]].
512+
1. Let _newBlock_ be ? CreateByteDataBlock(_newByteLength_).
513+
1. Let _copyLength_ be min(_newByteLength_, _O_.[[ArrayBufferByteLength]]).
514+
1. Perform CopyDataBlockBytes(_newBlock_, 0, _oldBlock_, 0, _copyLength_).
515+
1. NOTE: Neither creation of the new Data Block nor copying from the old Data Block are observable. Implementations may implement this method as in-place growth or shrinkage.
516+
1. Set _O_.[[ArrayBufferData]] to _newBlock_.
517+
1. Set _O_.[[ArrayBufferByteLength]] to _newByteLength_.
518+
1. Return *undefined*.
519+
</emu-alg>
520+
</emu-clause>
521+
522+
<emu-clause id="sec-arraybuffer.prototype.slice">
523+
<h1>ArrayBuffer.prototype.slice ( _start_, _end_ )</h1>
524+
<p>This method performs the following steps when called:</p>
525+
<emu-alg>
526+
1. Let _O_ be the *this* value.
527+
1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferData]]).
528+
1. If IsSharedArrayBuffer(_O_) is *true*, throw a *TypeError* exception.
529+
1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception.
530+
1. Let _len_ be _O_.[[ArrayBufferByteLength]].
531+
1. Let _relativeStart_ be ? ToIntegerOrInfinity(_start_).
532+
1. If _relativeStart_ = -∞, let _first_ be 0.
533+
1. Else if _relativeStart_ &lt; 0, let _first_ be max(_len_ + _relativeStart_, 0).
534+
1. Else, let _first_ be min(_relativeStart_, _len_).
535+
1. If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).
536+
1. If _relativeEnd_ = -∞, let _final_ be 0.
537+
1. Else if _relativeEnd_ &lt; 0, let _final_ be max(_len_ + _relativeEnd_, 0).
538+
1. Else, let _final_ be min(_relativeEnd_, _len_).
539+
1. Let _newLen_ be max(_final_ - _first_, 0).
540+
1. Let _ctor_ be ? SpeciesConstructor(_O_, %ArrayBuffer%).
541+
1. Let _new_ be ? Construct(_ctor_, « 𝔽(_newLen_) »).
542+
1. Perform ? RequireInternalSlot(_new_, [[ArrayBufferData]]).
543+
1. If IsSharedArrayBuffer(_new_) is *true*, throw a *TypeError* exception.
544+
1. If IsDetachedBuffer(_new_) is *true*, throw a *TypeError* exception.
545+
1. <ins>If IsImmutableBuffer(_new_) is *true*, throw a *TypeError* exception.</ins>
546+
1. If SameValue(_new_, _O_) is *true*, throw a *TypeError* exception.
547+
1. If _new_.[[ArrayBufferByteLength]] &lt; _newLen_, throw a *TypeError* exception.
548+
1. NOTE: Side-effects of the above steps may have detached or resized _O_.
549+
1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception.
550+
1. Let _fromBuf_ be _O_.[[ArrayBufferData]].
551+
1. Let _toBuf_ be _new_.[[ArrayBufferData]].
552+
1. Let _currentLen_ be _O_.[[ArrayBufferByteLength]].
553+
1. If _first_ &lt; _currentLen_, then
554+
1. Let _count_ be min(_newLen_, _currentLen_ - _first_).
555+
1. Perform CopyDataBlockBytes(_toBuf_, 0, _fromBuf_, _first_, _count_).
556+
1. Return _new_.
557+
</emu-alg>
558+
</emu-clause>
559+
498560
<ins class="block">
499561

500562
<emu-clause id="sec-arraybuffer.prototype.transfertoimmutable">

0 commit comments

Comments
 (0)