generated from tc39/template-for-proposals
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathspec.emu
More file actions
288 lines (272 loc) · 17.6 KB
/
spec.emu
File metadata and controls
288 lines (272 loc) · 17.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
<!doctype html>
<meta charset="utf8">
<link rel="stylesheet" href="./spec.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/github.min.css">
<script src="./spec.js"></script>
<pre class="metadata">
title: TypedArray, ArrayBuffer, and SharedArrayBuffer Concatenation
stage: 1
contributors: James M Snell
</pre>
<emu-clause id="sec-typedarray-objects">
<h1>TypedArray Objects</h1>
<emu-clause id="sec-%typedarray%-intrinsic-object">
<h1>The %TypedArray% Intrinsic Object</h1>
<emu-clause id="sec-abstract-operations-for-typedarray-objects">
<h1>Abstract Operations for TypedArray Objects</h1>
<emu-clause id="sec-validateintegralnumber" type="abstract operation">
<h1>
ValidateIntegralNumber (
_value_: an ECMAScript language value,
_default_: an integer,
): either a normal completion containing an integer or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It validates that _value_ is either *undefined* or an integral Number, returning the corresponding mathematical integer. If _value_ is *undefined*, the _default_ is returned.</dd>
</dl>
<emu-alg>
1. If _value_ is *undefined*, return _default_.
1. If _value_ is not a Number, throw a *TypeError* exception.
1. If _value_ is *NaN*, throw a *RangeError* exception.
1. If truncate(ℝ(_value_)) is not ℝ(_value_), throw a *RangeError* exception.
1. Return ℝ(_value_).
</emu-alg>
</emu-clause>
</emu-clause>
<emu-clause id="sec-properties-of-the-%typedarray%-intrinsic-object">
<h1>Properties of the %TypedArray% Intrinsic Object</h1>
<emu-clause id="sec-%typedarray%.concat">
<h1>%TypedArray%.concat ( _items_ [ , _length_ ] )</h1>
<p>This method concatenates the elements of multiple TypedArrays of the same type into a new TypedArray. It performs the following steps when called:</p>
<emu-alg>
1. Let _constructor_ be the *this* value.
1. If IsConstructor(_constructor_) is *false*, throw a *TypeError* exception.
1. If _constructor_ does not have a [[TypedArrayName]] internal slot, throw a *TypeError* exception.
1. Let _arrayList_ be ? IteratorToList(? GetIteratorFromMethod(_items_, ? GetMethod(_items_, %Symbol.iterator%))).
1. Let _newLength_ be ~empty~.
1. If _length_ is present and _length_ is not *undefined*, then
1. Set _newLength_ to ? ValidateIntegralNumber(_length_, 0).
1. If _newLength_ < 0, throw a *RangeError* exception.
1. If _newLength_ > 2<sup>53</sup> - 1, throw a *RangeError* exception.
1. Let _totalLength_ be 0.
1. Let _constructorName_ be _constructor_.[[TypedArrayName]].
1. For each element _item_ of _arrayList_, do
1. Let _taRecord_ be ? ValidateTypedArray(_item_, ~seq-cst~).
1. If _item_.[[TypedArrayName]] is not _constructorName_, throw a *TypeError* exception.
1. Let _itemLength_ be TypedArrayLength(_taRecord_).
1. Set _totalLength_ to _totalLength_ + _itemLength_.
1. If _totalLength_ > 2<sup>53</sup> - 1, throw a *RangeError* exception.
1. If _newLength_ is ~empty~, then
1. Set _newLength_ to _totalLength_.
1. Let _defaultProto_ be the String value of the Prototype column of the row in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for _constructorName_.
1. Let _result_ be ? AllocateTypedArray(_constructorName_, _constructor_, _defaultProto_).
1. Perform ? AllocateTypedArrayBuffer(_result_, _newLength_).
1. Let _elementSize_ be TypedArrayElementSize(_result_).
1. [id="step-ta-copy-start"] Let _writeOffset_ be 0.
1. For each element _item_ of _arrayList_, do
1. Let _remaining_ be _newLength_ - _writeOffset_.
1. If _remaining_ > 0, then
1. Let _taRecord_ be MakeTypedArrayWithBufferWitnessRecord(_item_, ~seq-cst~).
1. Let _itemLength_ be TypedArrayLength(_taRecord_).
1. Let _count_ be the result of clamping _itemLength_ between 0 and _remaining_.
1. Let _srcByteOffset_ be _item_.[[ByteOffset]].
1. Let _srcByteLength_ be _count_ × _elementSize_.
1. Perform CopyDataBlockBytes(_result_.[[ViewedArrayBuffer]].[[ArrayBufferData]], _writeOffset_ × _elementSize_, _item_.[[ViewedArrayBuffer]].[[ArrayBufferData]], _srcByteOffset_, _srcByteLength_).
1. [id="step-ta-copy-done"] Set _writeOffset_ to _writeOffset_ + _count_.
1. Return _result_.
</emu-alg>
<emu-note type="editor">
<p>The algorithm from <emu-xref href="#step-ta-copy-start"></emu-xref> through <emu-xref href="#step-ta-copy-done"></emu-xref> is specified with explicit allocation and byte-copying steps for clarity. Because all items share the same element type and the copy operates on the underlying data blocks, the result of the concatenation is not observable to user code during construction. Implementations may therefore use any technique — such as bulk memory copy, deferred allocation, or platform-specific optimizations — provided the observable result is equivalent.</p>
</emu-note>
</emu-clause>
</emu-clause>
</emu-clause>
</emu-clause>
<emu-clause id="sec-abstract-operations-for-buffer-concatenation">
<h1>Abstract Operations for Buffer Concatenation</h1>
<emu-clause id="sec-getconcatenationsources" type="abstract operation">
<h1>
GetConcatenationSources (
_arrayList_: a List of ECMAScript language values,
): either a normal completion containing a Record with fields [[Sources]] (a List of Records) and [[TotalByteLength]] (a non-negative integer), or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It validates each element of _arrayList_ as an ArrayBuffer, SharedArrayBuffer, TypedArray, or DataView, and returns a Record containing a List of source Records (each with [[Buffer]], [[ByteOffset]], and [[ByteLength]] fields) and the total byte length of all sources.</dd>
</dl>
<emu-alg>
1. Let _totalByteLength_ be 0.
1. Let _sources_ be a new empty List.
1. For each element _item_ of _arrayList_, do
1. If _item_ has a [[TypedArrayName]] internal slot, then
1. Let _taRecord_ be ? ValidateTypedArray(_item_, ~seq-cst~).
1. Let _byteLen_ be TypedArrayByteLength(_taRecord_).
1. Append the Record { [[Buffer]]: _item_.[[ViewedArrayBuffer]], [[ByteOffset]]: _item_.[[ByteOffset]], [[ByteLength]]: _byteLen_ } to _sources_.
1. Set _totalByteLength_ to _totalByteLength_ + _byteLen_.
1. If _totalByteLength_ > 2<sup>53</sup> - 1, throw a *RangeError* exception.
1. Else if _item_ has a [[DataView]] internal slot, then
1. Let _dvRecord_ be MakeDataViewWithBufferWitnessRecord(_item_, ~seq-cst~).
1. If IsViewOutOfBounds(_dvRecord_) is *true*, throw a *TypeError* exception.
1. Let _byteLen_ be GetViewByteLength(_dvRecord_).
1. Append the Record { [[Buffer]]: _item_.[[ViewedArrayBuffer]], [[ByteOffset]]: _item_.[[ByteOffset]], [[ByteLength]]: _byteLen_ } to _sources_.
1. Set _totalByteLength_ to _totalByteLength_ + _byteLen_.
1. If _totalByteLength_ > 2<sup>53</sup> - 1, throw a *RangeError* exception.
1. Else if _item_ has an [[ArrayBufferData]] internal slot, then
1. If IsDetachedBuffer(_item_) is *true*, throw a *TypeError* exception.
1. Let _byteLen_ be ArrayBufferByteLength(_item_, ~seq-cst~).
1. Append the Record { [[Buffer]]: _item_, [[ByteOffset]]: 0, [[ByteLength]]: _byteLen_ } to _sources_.
1. Set _totalByteLength_ to _totalByteLength_ + _byteLen_.
1. If _totalByteLength_ > 2<sup>53</sup> - 1, throw a *RangeError* exception.
1. Else,
1. Throw a *TypeError* exception.
1. Return the Record { [[Sources]]: _sources_, [[TotalByteLength]]: _totalByteLength_ }.
</emu-alg>
<emu-note>
<p>For TypedArray and DataView inputs, only the viewed portion of the underlying buffer is included. The byte lengths are snapshotted with ~seq-cst~ ordering at the time each item is validated.</p>
</emu-note>
</emu-clause>
<emu-clause id="sec-copysourcestobuffer" type="abstract operation">
<h1>
CopySourcesToBuffer (
_result_: an ArrayBuffer or SharedArrayBuffer,
_sources_: a List of Records with fields [[Buffer]], [[ByteOffset]], and [[ByteLength]],
): ~unused~
</h1>
<dl class="header">
<dt>description</dt>
<dd>It copies byte data from _sources_ into _result_ in order, stopping when _result_ is full.</dd>
</dl>
<emu-alg>
1. [id="step-copy-start"] Let _writeOffset_ be 0.
1. For each element _source_ of _sources_, do
1. Let _remaining_ be _result_.[[ArrayBufferByteLength]] - _writeOffset_.
1. If _remaining_ > 0, then
1. Let _sourceBuffer_ be _source_.[[Buffer]].
1. Let _sourceByteOffset_ be _source_.[[ByteOffset]].
1. Let _sourceByteLength_ be _source_.[[ByteLength]].
1. Let _count_ be the result of clamping _sourceByteLength_ between 0 and _remaining_.
1. Perform CopyDataBlockBytes(_result_.[[ArrayBufferData]], _writeOffset_, _sourceBuffer_.[[ArrayBufferData]], _sourceByteOffset_, _count_).
1. [id="step-copy-done"] Set _writeOffset_ to _writeOffset_ + _count_.
1. Return ~unused~.
</emu-alg>
<emu-note type="editor">
<p>The algorithm from <emu-xref href="#step-copy-start"></emu-xref> through <emu-xref href="#step-copy-done"></emu-xref> is specified with explicit byte-copying steps for clarity. Because the copy operates on the underlying data blocks, the result of the concatenation is not observable to user code during construction. Implementations may therefore use any technique — such as bulk memory copy, deferred allocation, or platform-specific optimizations — provided the observable result is equivalent.</p>
</emu-note>
</emu-clause>
</emu-clause>
<emu-clause id="sec-arraybuffer-objects">
<h1>ArrayBuffer Objects</h1>
<emu-clause id="sec-makearraybufferimmutable" type="abstract operation">
<h1>
MakeArrayBufferImmutable (
_arrayBuffer_: an ArrayBuffer,
): ~unused~
</h1>
<dl class="header">
<dt>description</dt>
<dd>It transitions _arrayBuffer_ to an immutable state whose contents cannot be changed, resized, or detached.</dd>
</dl>
<emu-alg>
1. Assert: IsDetachedBuffer(_arrayBuffer_) is *false*.
1. NOTE: The concrete steps for this abstract operation will be provided by the Immutable ArrayBuffer proposal.
1. Return ~unused~.
</emu-alg>
<emu-note type="editor">
<p>This is a placeholder abstract operation. The actual mechanism for transitioning an ArrayBuffer to an immutable state will be defined by the <a href="https://github.com/tc39/proposal-immutable-arraybuffer">Immutable ArrayBuffer proposal</a> (currently at stage 2.7).</p>
</emu-note>
</emu-clause>
<emu-clause id="sec-properties-of-the-arraybuffer-constructor">
<h1>Properties of the ArrayBuffer Constructor</h1>
<emu-clause id="sec-arraybuffer.concat">
<h1>ArrayBuffer.concat ( _items_ [ , _options_ ] )</h1>
<p>This method concatenates the byte contents of multiple ArrayBuffers, SharedArrayBuffers, TypedArrays, or DataViews into a new ArrayBuffer. It performs the following steps when called:</p>
<emu-alg>
1. Let _arrayList_ be ? IteratorToList(? GetIteratorFromMethod(_items_, ? GetMethod(_items_, %Symbol.iterator%))).
1. If _options_ is *undefined*, then
1. Let _optionsObj_ be OrdinaryObjectCreate(*null*).
1. Else if _options_ is an Object, then
1. Let _optionsObj_ be _options_.
1. Else,
1. Throw a *TypeError* exception.
1. Let _lengthOption_ be ? Get(_optionsObj_, *"length"*).
1. Let _newByteLength_ be ~empty~.
1. If _lengthOption_ is not *undefined*, then
1. Set _newByteLength_ to ? ValidateIntegralNumber(_lengthOption_, 0).
1. If _newByteLength_ < 0, throw a *RangeError* exception.
1. If _newByteLength_ > 2<sup>53</sup> - 1, throw a *RangeError* exception.
1. Let _resizable_ be ToBoolean(? Get(_optionsObj_, *"resizable"*)).
1. Let _immutable_ be ToBoolean(? Get(_optionsObj_, *"immutable"*)).
1. If _resizable_ is *true* and _immutable_ is *true*, throw a *TypeError* exception.
1. Let _concatenation_ be ? GetConcatenationSources(_arrayList_).
1. Let _sources_ be _concatenation_.[[Sources]].
1. Let _totalByteLength_ be _concatenation_.[[TotalByteLength]].
1. If _newByteLength_ is ~empty~, then
1. Set _newByteLength_ to _totalByteLength_.
1. If _resizable_ is *true*, then
1. Let _maxByteLength_ be _newByteLength_.
1. Let _byteLength_ be the result of clamping _totalByteLength_ between 0 and _maxByteLength_.
1. Let _result_ be ? AllocateArrayBuffer(%ArrayBuffer%, _byteLength_, _maxByteLength_).
1. Else,
1. Let _result_ be ? AllocateArrayBuffer(%ArrayBuffer%, _newByteLength_).
1. Perform CopySourcesToBuffer(_result_, _sources_).
1. If _immutable_ is *true*, then
1. Perform MakeArrayBufferImmutable(_result_).
1. Return _result_.
</emu-alg>
<emu-note type="editor">
<p>The _immutable_ option depends on the <a href="https://github.com/tc39/proposal-immutable-arraybuffer">Immutable ArrayBuffer proposal</a> (currently at stage 2.7). MakeArrayBufferImmutable is a placeholder for the abstract operation that will be defined by that proposal.</p>
</emu-note>
<emu-note>
<p>The result is always a (non-shared) ArrayBuffer regardless of the input types.</p>
<p>If the optional _options_ object is provided, the *"length"* property controls the byte length of the result. If *"length"* is less than the total byte length of the inputs, the result is truncated. If *"length"* is greater, the result is zero-filled beyond the copied bytes.</p>
<p>If the *"resizable"* option is *true*, the result is a resizable ArrayBuffer where *"length"* specifies the maximum byte length. The actual byte length is the lesser of the total input bytes and *"length"*.</p>
<p>If the *"immutable"* option is *true*, the result is an immutable ArrayBuffer whose contents cannot be changed, resized, or detached. The *"resizable"* and *"immutable"* options are mutually exclusive.</p>
</emu-note>
</emu-clause>
</emu-clause>
</emu-clause>
<emu-clause id="sec-sharedarraybuffer-objects">
<h1>SharedArrayBuffer Objects</h1>
<emu-clause id="sec-properties-of-the-sharedarraybuffer-constructor">
<h1>Properties of the SharedArrayBuffer Constructor</h1>
<emu-clause id="sec-sharedarraybuffer.concat">
<h1>SharedArrayBuffer.concat ( _items_ [ , _options_ ] )</h1>
<p>This method concatenates the byte contents of multiple ArrayBuffers, SharedArrayBuffers, TypedArrays, or DataViews into a new SharedArrayBuffer. It performs the following steps when called:</p>
<emu-alg>
1. Let _arrayList_ be ? IteratorToList(? GetIteratorFromMethod(_items_, ? GetMethod(_items_, %Symbol.iterator%))).
1. If _options_ is *undefined*, then
1. Let _optionsObj_ be OrdinaryObjectCreate(*null*).
1. Else if _options_ is an Object, then
1. Let _optionsObj_ be _options_.
1. Else,
1. Throw a *TypeError* exception.
1. Let _lengthOption_ be ? Get(_optionsObj_, *"length"*).
1. Let _newByteLength_ be ~empty~.
1. If _lengthOption_ is not *undefined*, then
1. Set _newByteLength_ to ? ValidateIntegralNumber(_lengthOption_, 0).
1. If _newByteLength_ < 0, throw a *RangeError* exception.
1. If _newByteLength_ > 2<sup>53</sup> - 1, throw a *RangeError* exception.
1. Let _growable_ be ToBoolean(? Get(_optionsObj_, *"growable"*)).
1. Let _concatenation_ be ? GetConcatenationSources(_arrayList_).
1. Let _sources_ be _concatenation_.[[Sources]].
1. Let _totalByteLength_ be _concatenation_.[[TotalByteLength]].
1. If _newByteLength_ is ~empty~, then
1. Set _newByteLength_ to _totalByteLength_.
1. If _growable_ is *true*, then
1. Let _maxByteLength_ be _newByteLength_.
1. Let _byteLength_ be the result of clamping _totalByteLength_ between 0 and _maxByteLength_.
1. Let _result_ be ? AllocateSharedArrayBuffer(%SharedArrayBuffer%, _byteLength_, _maxByteLength_).
1. Else,
1. Let _result_ be ? AllocateSharedArrayBuffer(%SharedArrayBuffer%, _newByteLength_).
1. Perform CopySourcesToBuffer(_result_, _sources_).
1. Return _result_.
</emu-alg>
<emu-note>
<p>The result is always a SharedArrayBuffer regardless of the input types.</p>
<p>If the optional _options_ object is provided, the *"length"* property controls the byte length of the result. If *"length"* is less than the total byte length of the inputs, the result is truncated. If *"length"* is greater, the result is zero-filled beyond the copied bytes.</p>
<p>If the *"growable"* option is *true*, the result is a growable SharedArrayBuffer where *"length"* specifies the maximum byte length. The actual byte length is the lesser of the total input bytes and *"length"*.</p>
</emu-note>
</emu-clause>
</emu-clause>
</emu-clause>