Skip to content

Commit f837afb

Browse files
authored
Normative: Introduce ArrayBuffer.prototype.sliceToImmutable (merge #21)
2 parents 04b49a7 + 9e7d6c4 commit f837afb

File tree

1 file changed

+112
-12
lines changed

1 file changed

+112
-12
lines changed

spec.emu

+112-12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,45 @@ shortname: proposal-immutable-arraybuffer
1212
contributors: Mark S. Miller, Richard Gibson
1313
</pre>
1414

15+
<emu-clause id="sec-ecmascript-data-types-and-values" number="6">
16+
<h1>ECMAScript Data Types and Values</h1>
17+
18+
<emu-clause id="sec-data-blocks" number="2.9">
19+
<h1>Data Blocks</h1>
20+
<p>A data block that resides in memory that can be referenced from multiple agents concurrently is designated a <dfn variants="Shared Data Blocks">Shared Data Block</dfn>. A Shared Data Block has an identity (for the purposes of equality testing Shared Data Block values) that is <em>address-free</em>: it is tied not to the virtual addresses the block is mapped to in any process, but to the set of locations in memory that the block represents. Two <del>data blocks</del> <ins>Shared Data Blocks</ins> are equal only if the sets of the locations they contain are equal; otherwise, they are not equal and the intersection of the sets of locations they contain is empty. Finally, Shared Data Blocks can be distinguished from Data Blocks.</p>
21+
</emu-clause>
22+
</emu-clause>
23+
24+
<emu-clause id="sec-operations-on-objects" number="7">
25+
<h1>Operations on Objects</h1>
26+
27+
<ins class="block">
28+
29+
<emu-clause id="sec-resolvebounds" type="abstract operation">
30+
<h1>
31+
ResolveBounds (
32+
_len_: an integer,
33+
_start_: an ECMAScript language value,
34+
_end_: an ECMAScript language value,
35+
): either a normal completion containing a Record with fields [[From]] (a non-negative integer) and [[To]] (a non-negative integer) or a throw completion
36+
</h1>
37+
<dl class="header">
38+
</dl>
39+
<emu-alg>
40+
1. Let _relativeStart_ be ? ToIntegerOrInfinity(_start_).
41+
1. If _relativeStart_ = -∞, let _from_ be 0.
42+
1. Else if _relativeStart_ &lt; 0, let _from_ be max(_len_ + _relativeStart_, 0).
43+
1. Else, let _from_ be min(_relativeStart_, _len_).
44+
1. If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).
45+
1. If _relativeEnd_ = -∞, let _to_ be 0.
46+
1. Else if _relativeEnd_ &lt; 0, let _to_ be max(_len_ + _relativeEnd_, 0).
47+
1. Else, let _to_ be min(_relativeEnd_, _len_).
48+
1. Return the Record { [[From]]: _from_, [[To]]: _to_ }.
49+
</emu-alg>
50+
</emu-clause>
51+
</ins>
52+
</emu-clause>
53+
1554
<emu-clause id="sec-ordinary-and-exotic-objects-behaviours" number="10">
1655
<h1>Ordinary and Exotic Objects Behaviours</h1>
1756

@@ -430,6 +469,36 @@ contributors: Mark S. Miller, Richard Gibson
430469
</emu-alg>
431470
</emu-clause>
432471

472+
<ins class="block">
473+
474+
<emu-clause id="sec-allocateimmutablearraybuffer" type="abstract operation">
475+
<h1>
476+
AllocateImmutableArrayBuffer (
477+
_constructor_: a constructor,
478+
_byteLength_: a non-negative integer,
479+
_fromBlock_: a Data Block,
480+
_fromIndex_: a non-negative integer,
481+
_count_: a non-negative integer,
482+
): either a normal completion containing an ArrayBuffer or a throw completion
483+
</h1>
484+
<dl class="header">
485+
<dt>description</dt>
486+
<dd>It is used to create an immutable ArrayBuffer (i.e., an ArrayBuffer with a an [[ArrayBufferIsImmutable]] slot) with contents from _fromBlock_.</dd>
487+
</dl>
488+
<emu-alg>
489+
1. Assert: _constructor_ is %ArrayBuffer%.
490+
1. Assert: _count_ ≤ _byteLength_.
491+
1. Let _newBuffer_ be ? <emu-meta suppress-effects="user-code">AllocateArrayBuffer(_constructor_, _byteLength_, ~immutable~)</emu-meta>.
492+
1. Let _toBlock_ be _newBuffer_.[[ArrayBufferData]].
493+
1. Perform CopyDataBlockBytes(_toBlock_, 0, _fromBlock_, 0, _count_).
494+
1. Return _newBuffer_.
495+
</emu-alg>
496+
<emu-note>
497+
<p>Because neither the identity of a Data Block nor the set of locations in memory represented by it are observable, implementations may implement this operation without allocating new memory locations when _fromBlock_ is the value of the [[ArrayBufferData]] slot for some other immutable ArrayBuffer (and therefore already immutable) and _count_ = _byteLength_.</p>
498+
</emu-note>
499+
</emu-clause>
500+
</ins>
501+
433502
<emu-clause id="sec-arraybuffercopyanddetach" type="abstract operation" number="3">
434503
<h1>
435504
ArrayBufferCopyAndDetach (
@@ -449,18 +518,19 @@ contributors: Mark S. Miller, Richard Gibson
449518
1. Let _newByteLength_ be ? ToIndex(_newLength_).
450519
1. If IsDetachedBuffer(_arrayBuffer_) is *true*, throw a *TypeError* exception.
451520
1. <ins>If IsImmutableBuffer(_arrayBuffer_) is *true*, throw a *TypeError* exception.</ins>
521+
1. <ins>Let _copyLength_ be min(_newByteLength_, _arrayBuffer_.[[ArrayBufferByteLength]]).</ins>
522+
1. <ins>If _preserveResizability_ is ~immutable~, then</ins>
523+
1. <ins>Return ? AllocateImmutableArrayBuffer(%ArrayBuffer%, _newByteLength_, _arrayBuffer_.[[ArrayBufferData]], 0, _copyLength_).</ins>
452524
1. If _preserveResizability_ is ~preserve-resizability~ and IsFixedLengthArrayBuffer(_arrayBuffer_) is *false*, then
453525
1. Let _newMaxByteLength_ be _arrayBuffer_.[[ArrayBufferMaxByteLength]].
454-
1. <ins>Else if _preserveResizability_ is ~immutable~, then</ins>
455-
1. <ins>Let _newMaxByteLength_ be ~immutable~.</ins>
456526
1. Else,
457527
1. Let _newMaxByteLength_ be ~empty~.
458528
1. If _arrayBuffer_.[[ArrayBufferDetachKey]] is not *undefined*, throw a *TypeError* exception.
459529
1. Let _newBuffer_ be ? <emu-meta suppress-effects="user-code">AllocateArrayBuffer(%ArrayBuffer%, _newByteLength_, _newMaxByteLength_)</emu-meta>.
460-
1. Let _copyLength_ be min(_newByteLength_, _arrayBuffer_.[[ArrayBufferByteLength]]).
530+
1. <del>Let _copyLength_ be min(_newByteLength_, _arrayBuffer_.[[ArrayBufferByteLength]]).</del>
461531
1. Let _fromBlock_ be _arrayBuffer_.[[ArrayBufferData]].
462-
1. Let _toBlock_ be _newBuffer_.[[ArrayBufferData]].
463532
1. <ins>NOTE: This is the only step that can write into the Data Block of an immutable ArrayBuffer.</ins>
533+
1. Let _toBlock_ be _newBuffer_.[[ArrayBufferData]].
464534
1. Perform CopyDataBlockBytes(_toBlock_, 0, _fromBlock_, 0, _copyLength_).
465535
1. NOTE: Neither creation of the new Data Block nor copying from the old Data Block are observable. Implementations may implement this method as a zero-copy move or a `realloc`.
466536
1. Perform ! DetachArrayBuffer(_arrayBuffer_).
@@ -606,14 +676,17 @@ contributors: Mark S. Miller, Richard Gibson
606676
1. If IsSharedArrayBuffer(_O_) is *true*, throw a *TypeError* exception.
607677
1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception.
608678
1. Let _len_ be _O_.[[ArrayBufferByteLength]].
609-
1. Let _relativeStart_ be ? ToIntegerOrInfinity(_start_).
610-
1. If _relativeStart_ = -∞, let _first_ be 0.
611-
1. Else if _relativeStart_ &lt; 0, let _first_ be max(_len_ + _relativeStart_, 0).
612-
1. Else, let _first_ be min(_relativeStart_, _len_).
613-
1. If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).
614-
1. If _relativeEnd_ = -∞, let _final_ be 0.
615-
1. Else if _relativeEnd_ &lt; 0, let _final_ be max(_len_ + _relativeEnd_, 0).
616-
1. Else, let _final_ be min(_relativeEnd_, _len_).
679+
1. <del>Let _relativeStart_ be ? ToIntegerOrInfinity(_start_).</del>
680+
1. <del>If _relativeStart_ = -∞, let _first_ be 0.</del>
681+
1. <del>Else if _relativeStart_ &lt; 0, let _first_ be max(_len_ + _relativeStart_, 0).</del>
682+
1. <del>Else, let _first_ be min(_relativeStart_, _len_).</del>
683+
1. <del>If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).</del>
684+
1. <del>If _relativeEnd_ = -∞, let _final_ be 0.</del>
685+
1. <del>Else if _relativeEnd_ &lt; 0, let _final_ be max(_len_ + _relativeEnd_, 0).</del>
686+
1. <del>Else, let _final_ be min(_relativeEnd_, _len_).</del>
687+
1. <ins>Let _bounds_ be ? ResolveBounds(_len_, _start_, _end_).</ins>
688+
1. <ins>Let _first_ be _bounds_.[[From]].</ins>
689+
1. <ins>Let _final_ be _bounds_.[[To]].</ins>
617690
1. Let _newLen_ be max(_final_ - _first_, 0).
618691
1. Let _ctor_ be ? SpeciesConstructor(_O_, %ArrayBuffer%).
619692
1. Let _new_ be ? Construct(_ctor_, « 𝔽(_newLen_) »).
@@ -635,6 +708,33 @@ contributors: Mark S. Miller, Richard Gibson
635708
</emu-alg>
636709
</emu-clause>
637710

711+
<ins class="block">
712+
713+
<emu-clause id="sec-arraybuffer.prototype.slicetoimmutable">
714+
<h1>ArrayBuffer.prototype.sliceToImmutable ( _start_, _end_ )</h1>
715+
<p>This method performs the following steps when called:</p>
716+
<emu-alg>
717+
1. Let _O_ be the *this* value.
718+
1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferData]]).
719+
1. If IsSharedArrayBuffer(_O_) is *true*, throw a *TypeError* exception.
720+
1. TODO: Confirm inclusion of this redundant check.
721+
1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception.
722+
1. Let _len_ be _O_.[[ArrayBufferByteLength]].
723+
1. Let _bounds_ be ? ResolveBounds(_len_, _start_, _end_).
724+
1. Let _first_ be _bounds_.[[From]].
725+
1. Let _final_ be _bounds_.[[To]].
726+
1. TODO: Confirm this strictness vs. the conventional `max(_final_ - _first_, 0)`.
727+
1. Let _newLen_ be _final_ - _first_.
728+
1. If _newLen_ &lt; 0, throw a *RangeError* exception.
729+
1. Let _copyLen_ be min(_newLen_, _len_).
730+
1. NOTE: Side-effects of the above steps may have detached or resized _O_. This algorithm proceeds only when _O_ is not detached, even if _newLen_ is 0.
731+
1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception.
732+
1. Let _newBuffer_ be ? AllocateImmutableArrayBuffer(%ArrayBuffer%, _newLen_, _O_.[[ArrayBufferData]], _first_, _copyLen_).
733+
1. Return _newBuffer_.
734+
</emu-alg>
735+
</emu-clause>
736+
</ins>
737+
638738
<ins class="block">
639739

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

0 commit comments

Comments
 (0)