Resizable ArrayBuffer and growable SharedArrayBuffer
17 |
We extend the `ArrayBuffer` and `SharedArrayBuffer` constructors to take an additional maximum byte length, which would construct dynamically resizable and growable array buffers, respectively.
18 |
19 |
20 |
21 |
Modifications to ArrayBuffer Objects
22 |
23 |
24 |
Modifications to Abstract Operations for ArrayBuffer Objects
25 |
26 |
27 |
28 | DetachArrayBuffer (
29 | _arrayBuffer_: an ArrayBuffer,
30 | optional _key_: anything,
31 | ): either a normal completion containing ~unused~ or a throw completion
32 |
33 |
34 |
35 |
36 | 1. Assert: IsSharedArrayBuffer(_arrayBuffer_) is *false*.
37 | 1. If _key_ is not present, set _key_ to *undefined*.
38 | 1. If _arrayBuffer_.[[ArrayBufferDetachKey]] is not _key_, throw a *TypeError* exception.
39 | 1. Set _arrayBuffer_.[[ArrayBufferData]] to *null*.
40 | 1. Set _arrayBuffer_.[[ArrayBufferByteLength]] to 0.
41 | 1. Return ~unused~.
42 |
43 |
44 |
Detaching an ArrayBuffer instance disassociates the Data Block used as its backing store from the instance and sets the byte length of the buffer to 0. No operations defined by this specification use the DetachArrayBuffer abstract operation. However, an ECMAScript host or implementation may define such operations.
45 |
46 |
47 |
48 |
49 |
50 | AllocateArrayBuffer (
51 | _constructor_: a constructor,
52 | _byteLength_: a non-negative integer,
53 | optional _maxByteLength_: a non-negative integer or ~empty~,
54 | ): either a normal completion containing an ArrayBuffer or a throw completion
55 |
56 |
57 |
description
58 |
It is used to create an ArrayBuffer.
59 |
60 |
61 | 1. Let _slots_ be « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] ».
62 | 1. If _maxByteLength_ is present and not ~empty~, then
63 | 1. If _byteLength_ > _maxByteLength_, throw a *RangeError* exception.
64 | 1. Append [[ArrayBufferMaxByteLength]] to _slots_.
65 | 1. Let _obj_ be ? OrdinaryCreateFromConstructor(_constructor_, *"%ArrayBuffer.prototype%"*, « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] »_slots_).
66 | 1. Let _block_ be ? CreateByteDataBlock(_byteLength_).
67 | 1. Set _obj_.[[ArrayBufferData]] to _block_.
68 | 1. Set _obj_.[[ArrayBufferByteLength]] to _byteLength_.
69 | 1. If _maxByteLength_ is present and not ~empty~, then
70 | 1. If it is not possible to create a Data Block _block_ consisting of _maxByteLength_ bytes, throw a *RangeError* exception.
71 | 1. NOTE: Resizable ArrayBuffers 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.
72 | 1. Set _obj_.[[ArrayBufferMaxByteLength]] to _maxByteLength_.
73 | 1. Return _obj_.
74 |
75 |
76 |
77 |
78 |
79 |
80 | ArrayBufferByteLength (
81 | _arrayBuffer_: an ArrayBuffer or SharedArrayBuffer,
82 | _order_: ~SeqCst~ or ~Unordered~,
83 | ): a non-negative integer
84 |
85 |
86 |
87 |
88 | 1. If IsSharedArrayBuffer(_arrayBuffer_) is *true* and _arrayBuffer_ has an [[ArrayBufferByteLengthData]] internal slot, then
89 | 1. Let _bufferByteLengthBlock_ be _arrayBuffer_.[[ArrayBufferByteLengthData]].
90 | 1. Return ℝ(GetValueFromBuffer(_bufferByteLengthBlock_, 0, ~BigUint64~, *true*, _order_)).
91 | 1. Assert: IsDetachedBuffer(_arrayBuffer_) is *false*.
92 | 1. Return _arrayBuffer_.[[ArrayBufferByteLength]].
93 |
94 |
95 |
96 |
97 |
98 | MakeIdempotentArrayBufferByteLengthGetter (
99 | _order_: ~SeqCst~ or ~Unordered~,
100 | ): an Abstract Closure with one parameter
101 |
102 |
103 |
description
104 |
The returned Abstract Closure helps ensure that there there is a single shared memory read event of the byte length data block in the calling operation.
105 |
106 |
107 | 1. NOTE: The [[ArrayBuffer]] slot is used for editorial clarity only, that a getter should only be used with a single ArrayBuffer.
108 | 1. Let _lengthStorage_ be { [[ArrayBuffer]]: ~empty~, [[ByteLength]]: ~empty~ }.
109 | 1. Let _getter_ be a new Abstract Closure with parameters (_buffer_) that captures _lengthStorage_ and _order_ and performs the following steps when called:
110 | 1. If _lengthStorage_.[[ByteLength]] is ~empty~, then
111 | 1. Assert: _lengthStorage_.[[ArrayBuffer]] is ~empty~.
112 | 1. Set _lengthStorage_.[[ArrayBuffer]] to _buffer_.
113 | 1. Set _lengthStorage_.[[ByteLength]] to ArrayBufferByteLength(_buffer_, _order_).
114 | 1. Assert: SameValue(_lengthStorage_.[[ArrayBuffer]], _buffer_) is *true*.
115 | 1. Return _lengthStorage_.[[ByteLength]].
116 | 1. Return _getter_.
117 |
118 |
119 |
120 |
121 |
122 | IsResizableArrayBuffer (
123 | _arrayBuffer_: an ArrayBuffer or a SharedArrayBuffer,
124 | ): a Boolean
125 |
126 |
127 |
128 |
129 | 1. If _arrayBuffer_ has an [[ArrayBufferMaxByteLength]] internal slot, return *true*.
130 | 1. Return *false*.
131 |
132 |
133 |
134 |
135 |
136 | GetArrayBufferMaxByteLengthOption (
137 | _options_: an ECMAScript language value,
138 | ): a normal completion containing either a non-negative integer or ~empty~
139 |
140 |
141 |
142 |
143 | 1. If Type(_options_) is not Object, return ~empty~.
144 | 1. Let _maxByteLength_ be ? Get(_options_, `"maxByteLength"`).
145 | 1. If _maxByteLength_ is *undefined*, return ~empty~.
146 | 1. Return ? ToIndex(_maxByteLength_).
147 |
148 |
149 |
150 |
151 |
152 | HostResizeArrayBuffer (
153 | _buffer_: an ArrayBuffer,
154 | _newByteLength_: a non-negative integer,
155 | ): either a normal completion containing either ~handled~ or ~unhandled~, or a throw completion
156 |
157 |
158 |
description
159 |
The host-defined abstract operation HostResizeArrayBuffer takes arguments _buffer_ (an ArrayBuffer object) and _newByteLength_. It gives the host an opportunity to perform implementation-defined resizing of _buffer_. If the host chooses not to handle resizing of _buffer_, it may return ~unhandled~ for the default behaviour.
160 |
161 |
162 |
The implementation of HostResizeArrayBuffer must conform to the following requirements:
163 |
164 |
The abstract operation must return either NormalCompletion(~handled~), NormalCompletion(~unhandled~), or an abrupt throw completion.
165 |
The abstract operation does not detach _buffer_.
166 |
If the abstract operation completes normally with ~handled~, _buffer_.[[ArrayBufferByteLength]] is _newByteLength_.
167 |
168 |
169 |
The default implementation of HostResizeArrayBuffer is to return ~unhandled~.
170 |
171 |
172 |
173 |
174 |
175 |
The ArrayBuffer Constructor
176 |
177 |
178 |
ArrayBuffer ( _length_ [ , _options_ ] )
179 |
When the `ArrayBuffer` function is called with argument _length_ and optional argument _options_, the following steps are taken:
180 |
181 | 1. If NewTarget is *undefined*, throw a *TypeError* exception.
182 | 1. Let _byteLength_ be ? ToIndex(_length_).
183 | 1. Let _requestedMaxByteLength_ be ? GetArrayBufferMaxByteLengthOption(_options_).
184 | 1. Return ? AllocateArrayBuffer(NewTarget, _byteLength_, _requestedMaxByteLength_).
185 |
186 |
187 |
188 |
189 |
190 |
Modifications to the Properties of the ArrayBuffer Prototype Object
191 |
192 |
193 |
get ArrayBuffer [ @@species ]
194 |
`ArrayBuffer[@@species]` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
The value of the *"name"* property of this function is *"get [Symbol.species]"*.
199 |
200 |
ArrayBuffer prototype methods normally use their *this* value's constructor to create a derived object. However, a subclass constructor may over-ride that default behaviour for the method by redefining its @@species property.
201 |
202 |
203 |
204 |
205 |
206 |
get ArrayBuffer.prototype.maxByteLength
207 |
`ArrayBuffer.prototype.maxByteLength` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
208 |
209 | 1. Let _O_ be the *this* value.
210 | 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferData]]).
211 | 1. If IsSharedArrayBuffer(_O_) is *true*, throw a *TypeError* exception.
212 | 1. If IsDetachedBuffer(_O_) is *true*, return *+0*𝔽.
213 | 1. If IsResizableArrayBuffer(_O_) is *true*, then
214 | 1. Let _length_ be _O_.[[ArrayBufferMaxByteLength]].
215 | 1. Else,
216 | 1. Let _length_ be _O_.[[ArrayBufferByteLength]].
217 | 1. Return 𝔽(_length_).
218 |
219 |
220 |
221 |
222 |
get ArrayBuffer.prototype.resizable
223 |
`ArrayBuffer.prototype.resizable` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
224 |
225 | 1. Let _O_ be the *this* value.
226 | 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferData]]).
227 | 1. If IsSharedArrayBuffer(_O_) is *true*, throw a *TypeError* exception.
228 | 1. Return IsResizableArrayBuffer(_O_).
229 |
230 |
231 |
232 |
233 |
234 |
ArrayBuffer.prototype.slice ( _start_, _end_ )
235 |
This method performs the following steps when called:
236 |
237 | 1. Let _O_ be the *this* value.
238 | 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferData]]).
239 | 1. If IsSharedArrayBuffer(_O_) is *true*, throw a *TypeError* exception.
240 | 1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception.
241 | 1. Let _len_ be _O_.[[ArrayBufferByteLength]].
242 | 1. Let _relativeStart_ be ? ToIntegerOrInfinity(_start_).
243 | 1. If _relativeStart_ is -∞, let _first_ be 0.
244 | 1. Else if _relativeStart_ < 0, let _first_ be max(_len_ + _relativeStart_, 0).
245 | 1. Else, let _first_ be min(_relativeStart_, _len_).
246 | 1. If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).
247 | 1. If _relativeEnd_ is -∞, let _final_ be 0.
248 | 1. Else if _relativeEnd_ < 0, let _final_ be max(_len_ + _relativeEnd_, 0).
249 | 1. Else, let _final_ be min(_relativeEnd_, _len_).
250 | 1. Let _newLen_ be max(_final_ - _first_, 0).
251 | 1. Let _ctor_ be ? SpeciesConstructor(_O_, %ArrayBuffer%).
252 | 1. Let _new_ be ? Construct(_ctor_, « 𝔽(_newLen_) »).
253 | 1. Perform ? RequireInternalSlot(_new_, [[ArrayBufferData]]).
254 | 1. If IsSharedArrayBuffer(_new_) is *true*, throw a *TypeError* exception.
255 | 1. If IsDetachedBuffer(_new_) is *true*, throw a *TypeError* exception.
256 | 1. If SameValue(_new_, _O_) is *true*, throw a *TypeError* exception.
257 | 1. If _new_.[[ArrayBufferByteLength]] < _newLen_, throw a *TypeError* exception.
258 | 1. NOTE: Side-effects of the above steps may have detached or resized _O_.
259 | 1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception.
260 | 1. Let _fromBuf_ be _O_.[[ArrayBufferData]].
261 | 1. Let _toBuf_ be _new_.[[ArrayBufferData]].
262 | 1. If _first_ < _O_.[[ArrayBufferByteLength]], then
263 | 1. Perform CopyDataBlockBytes(_toBuf_, 0, _fromBuf_, _first_, min(_O_.[[ArrayBufferByteLength]], _newLen_)).
264 | 1. Return _new_.
265 |
266 |
267 |
268 |
269 |
270 |
ArrayBuffer.prototype.resize ( _newLength_ )
271 |
The following steps are taken:
272 |
273 | 1. Let _O_ be the *this* value.
274 | 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferMaxByteLength]]).
275 | 1. If IsSharedArrayBuffer(_O_) is *true*, throw a *TypeError* exception.
276 | 1. If IsDetachedBuffer(_O_) is *true*, throw a *TypeError* exception.
277 | 1. Let _newByteLength_ be ? ToIntegerOrInfinity(_newLength_).
278 | 1. If _newByteLength_ < 0 or _newByteLength_ > _O_.[[ArrayBufferMaxByteLength]], throw a *RangeError* exception.
279 | 1. Let _hostHandled_ be ? HostResizeArrayBuffer(_O_, _newByteLength_).
280 | 1. If _hostHandled_ is ~handled~, return *undefined*.
281 | 1. Let _oldBlock_ be _O_.[[ArrayBufferData]].
282 | 1. Let _newBlock_ be ? CreateByteDataBlock(_newByteLength_).
283 | 1. Let _copyLength_ be min(_newByteLength_, _O_.[[ArrayBufferByteLength]]).
284 | 1. Perform CopyDataBlockBytes(_newBlock_, 0, _oldBlock_, 0, _copyLength_).
285 | 1. 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.
286 | 1. Set _O_.[[ArrayBufferData]] to _newBlock_.
287 | 1. Set _O_.[[ArrayBufferByteLength]] to _newLength_.
288 | 1. Return *undefined*.
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
Modifications to SharedArrayBuffer Objects
297 |
298 |
299 |
Modifications to Abstract Operations for SharedArrayBuffer Objects
300 |
301 |
302 |
303 | AllocateSharedArrayBuffer (
304 | _constructor_: a constructor,
305 | _byteLength_: a non-negative integer,
306 | optional _maxByteLength_: a non-negative integer or ~empty~,
307 | ): either a normal completion containing a SharedArrayBuffer or a throw completion
308 |
309 |
310 |
description
311 |
It is used to create a SharedArrayBuffer.
312 |
313 |
314 | 1. Let _slots_ be « [[ArrayBufferData]] ».
315 | 1. If _maxByteLength_ is present and not ~empty~, then
316 | 1. If _byteLength_ > _maxByteLength_, throw a *RangeError* exception.
317 | 1. Append [[ArrayBufferByteLengthData]] and [[ArrayBufferMaxByteLength]] to _slots_.
318 | 1. Else, append [[ArrayBufferByteLength]] to _slots_.
319 | 1. Let _obj_ be ? OrdinaryCreateFromConstructor(_constructor_, *"%SharedArrayBuffer.prototype%"*, « [[ArrayBufferData]], [[ArrayBufferByteLength]] »_slots_).
320 | 1. If _maxByteLength_ is present, let _allocLength_ be _maxByteLength_.
321 | 1. Else, let _allocLength_ be _byteLength_.
322 | 1. Let _block_ be ? CreateSharedByteDataBlock(_byteLength__allocLength_).
323 | 1. NOTE: Growable SharedArrayBuffers 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.
324 | 1. Set _obj_.[[ArrayBufferData]] to _block_.
325 | 1. If _maxByteLength_ is present and not ~empty~, then
326 | 1. Assert: _byteLength_ ≤ _maxByteLength_.
327 | 1. Let _byteLengthBlock_ be ? CreateSharedByteDataBlock(8).
328 | 1. Perform SetValueInBuffer(_byteLengthBlock_, 0, ~BigUint64~, ℤ(_byteLength_), *true*, ~SeqCst~).
329 | 1. Set _obj_.[[ArrayBufferByteLengthData]] to _byteLengthBlock_.
330 | 1. Set _obj_.[[ArrayBufferMaxByteLength]] to _maxByteLength_.
331 | 1. Else,
332 | 1. Set _obj_.[[ArrayBufferByteLength]] to _byteLength_.
333 | 1. Return _obj_.
334 |
335 |
336 |
337 |
338 |
339 |
340 | HostGrowSharedArrayBuffer (
341 | _buffer_: a SharedArrayBuffer,
342 | _newByteLength_: a non-negative integer
343 | ): either a normal completion containing either ~handled~ or ~unhandled~, or a throw completion
344 |
345 |
346 |
description
347 |
It gives the host an opportunity to perform implementation-defined growing of _buffer_. If the host chooses not to handle resizing of _buffer_, it may return ~unhandled~ for the default behaviour.
348 |
349 |
The implementation of HostGrowSharedArrayBuffer must conform to the following requirements:
350 |
351 |
The abstract operation must return either NormalCompletion(~handled~), NormalCompletion(~unhandled~), or an abrupt throw completion.
352 |
If the abstract operation does not complete normally with ~unhandled~, and _newByteLength_ < the current byte length of the _buffer_ or _newByteLength_ > _buffer_.[[ArrayBufferMaxByteLength]], throw a *RangeError* exception.
353 |
Let _isLittleEndian_ be the value of the [[LittleEndian]] field of the surrounding agent's Agent Record. If the abstract operation completes normally with ~handled~, a WriteSharedMemory or ReadModifyWriteSharedMemory event whose [[Order]] is ~SeqCst~, [[Payload]] is NumericToRawBytes(~BigUint64~, _newByteLength_, _isLittleEndian_), [[Block]] is _buffer_.[[ArrayBufferByteLengthData]], [[ByteIndex]] is 0, and [[ElementSize]] is 8 is added to the surrounding agent's candidate execution such that racing calls to `SharedArrayBuffer.prototype.grow` are not "lost", i.e. silently do nothing.
354 |
355 |
356 |
The default implementation of HostGrowSharedArrayBuffer is to return ~unhandled~.
357 |
358 |
359 |
The second requirement above is intentionally vague about how or when the current byte length of _buffer_ is read. Because the byte length must be updated via an atomic read-modify-write operation on the underlying hardware, architectures that use load-link/store-conditional or load-exclusive/store-exclusive instruction pairs may wish to keep the paired instructions close in the instruction stream. As such, SharedArrayBuffer.prototype.grow itself does not perform bounds checking on _newByteLength_ before calling HostGrowSharedArrayBuffer, nor is there a requirement on when the current byte length is read.
360 |
This is in contrast with HostResizeArrayBuffer, which is guaranteed that the value of _newByteLength_ is ≥ 0 and ≤ _buffer_.[[ArrayBufferMaxByteLength]].
361 |
362 |
363 |
364 |
365 |
366 |
367 |
The SharedArrayBuffer Constructor
368 |
369 |
370 |
SharedArrayBuffer ( _length_ [ , _options_ ] )
371 |
When the `SharedArrayBuffer` function is called with argument _length_ and optional argument _options_, the following steps are taken:
372 |
373 | 1. If NewTarget is *undefined*, throw a *TypeError* exception.
374 | 1. Let _byteLength_ be ? ToIndex(_length_).
375 | 1. Let _requestedMaxByteLength_ be ? GetArrayBufferMaxByteLengthOption(_options_).
376 | 1. Return ? AllocateSharedArrayBuffer(NewTarget, _byteLength_, _requestedMaxByteLength_).
377 |
378 |
379 |
380 |
381 |
382 |
Modifications to the Properties of the SharedArrayBuffer Prototype Object
383 |
384 |
385 |
get SharedArrayBuffer.prototype.byteLength
386 |
`SharedArrayBuffer.prototype.byteLength` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
387 |
388 | 1. Let _O_ be the *this* value.
389 | 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferData]]).
390 | 1. If IsSharedArrayBuffer(_O_) is *false*, throw a *TypeError* exception.
391 | 1. Let _length_ be _O_.[[ArrayBufferByteLength]]ArrayBufferByteLength(_O_, ~SeqCst~).
392 | 1. Return 𝔽(_length_).
393 |
394 |
395 |
396 |
397 |
398 |
get SharedArrayBuffer.prototype.growable
399 |
`SharedArrayBuffer.prototype.growable` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
400 |
401 | 1. Let _O_ be the *this* value.
402 | 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferData]]).
403 | 1. If IsSharedArrayBuffer(_O_) is *false*, throw a *TypeError* exception.
404 | 1. Return IsResizableArrayBuffer(_O_).
405 |
406 |
407 |
408 |
409 |
get SharedArrayBuffer.prototype.maxByteLength
410 |
`SharedArrayBuffer.prototype.maxByteLength` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
411 |
412 | 1. Let _O_ be the *this* value.
413 | 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferData]]).
414 | 1. If IsSharedArrayBuffer(_O_) is *false*, throw a *TypeError* exception.
415 | 1. If IsResizableArrayBuffer(_O_) is *true*, then
416 | 1. Let _length_ be _O_.[[ArrayBufferMaxByteLength]].
417 | 1. Else,
418 | 1. Let _length_ be _O_.[[ArrayBufferByteLength]].
419 | 1. Return 𝔽(_length_).
420 |
421 |
422 |
423 |
424 |
SharedArrayBuffer.prototype.grow ( _newLength_ )
425 |
The following steps are taken:
426 |
427 | 1. Let _O_ be the *this* value.
428 | 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferMaxByteLength]]).
429 | 1. If IsSharedArrayBuffer(_O_) is *false*, throw a *TypeError* exception.
430 | 1. Let _newByteLength_ be ? ToIntegerOrInfinity(_newLength_).
431 | 1. Let _hostHandled_ be ? HostGrowSharedArrayBuffer(_O_, _newByteLength_).
432 | 1. If _hostHandled_ is ~handled~, return *undefined*.
433 | 1. Let _rawCurrentByteLengthBytesRead_ be a List of length 8 whose elements are nondeterministically chosen byte values.
434 | 1. NOTE: In implementations, _rawCurrentByteLengthBytesRead_ is the result of a load-link, of a load-exclusive, or of an operand of a read-modify-write instruction on the underlying hardware. The nondeterminism is a semantic prescription of the memory model to describe observable behaviour of hardware with weak consistency.
435 | 1. Let _byteLengthBlock_ be _O_.[[ArrayBufferByteLengthData]].
436 | 1. Let _isLittleEndian_ be the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
437 | 1. Let _currentByteLength_ be RawBytesToNumeric(~BigUint64~, _rawCurrentByteLengthBytesRead_, _isLittleEndian_).
438 | 1. Let _growFailed_ be *false*.
439 | 1. If _newByteLength_ < _currentByteLength_ or _newByteLength_ > _O_.[[ArrayBufferMaxByteLength]], set _growFailed_ to *true*.
440 | 1. Let _byteLengthDelta_ be _newByteLength_ - _currentByteLength_.
441 | 1. If it is impossible to create a new Shared Data Block value consisting of _byteLengthDelta_ bytes, set _growFailed_ to *true*.
442 | 1. NOTE: No new Shared Data Block is constructed and used here. The observable behaviour of growable SharedArrayBuffers is specified by allocating a max-sized Shared Data Block at construction time, and this step is intended to capture the requirement that implementations that run out of memory must throw a *RangeError*.
443 | 1. NOTE: The above checks help ensure that concurrent calls to SharedArrayBuffer.prototype.grow are totally ordered. For example, consider two racing calls: `sab.grow(10)` and `sab.grow(20)`. One of the two calls is guaranteed to win the race. The call to `sab.grow(10)` will never shrink `sab` even if `sab.grow(20)` happened first.
444 | 1. If _growFailed_ is *false* and _newByteLength_ ≠ _currentByteLength_, then
445 | 1. NOTE: Resizes to the same length explicitly do nothing to avoid gratuitous synchronization.
446 | 1. Let _second_ be a new read-modify-write modification function with parameters (_oldBytes_, _newBytes_) that captures nothing and performs the following steps atomically when called:
447 | 1. Return _newBytes_.
448 | 1. Let _newByteLengthBytes_ be NumericToRawBytes(~BigUint64~, ℤ(_newByteLength_), _isLittleEndian_).
449 | 1. Let _event_ be ReadModifyWriteSharedMemory { [[Order]]: ~SeqCst~, [[NoTear]]: *true*, [[Block]]: _byteLengthBlock_, [[ByteIndex]]: 0, [[ElementSize]]: 8, [[Payload]]: _newByteLengthBytes_, [[ModifyOp]]: _second_ }.
450 | 1. NOTE: The new memory is already zeroed, as a _O_.[[ArrayBufferMaxByteLength]] sized Data Block is already allocated. This is a specification mechanism; an implementation is not required to reserve _O_.[[ArrayBufferMaxByteLength]] bytes of physical memory.
451 | 1. Else,
452 | 1. Let _event_ be ReadSharedMemory { [[Order]]: ~SeqCst~, [[NoTear]]: *true*, [[Block]]: _byteLengthBlock_, [[ByteIndex]]: 0, [[ElementSize]]: 8 }.
453 | 1. Let _execution_ be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
454 | 1. Let _eventList_ be the [[EventList]] field of the element in _execution_.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
455 | 1. Append _event_ to _eventList_.
456 | 1. Append Chosen Value Record { [[Event]]: _event_, [[ChosenValue]]: _rawCurrentByteLengthBytesRead_ } to _execution_.[[ChosenValues]].
457 | 1. If _growFailed_ is *true*, throw a *RangeError* exception.
458 | 1. Return *undefined*.
459 |
460 |
461 |
Spurious failures of the compare-exchange to update the length are prohibited. If the bounds checking for the new length passes and the implementation is not out of memory, a ReadModifyWriteSharedMemory event (i.e. a successful compare-exchange) is always added into the candidate execution.
462 |
Many of the above steps are shared with the algorithm steps of Atomics.compareExchange and should be refactored when merged into the full specification.
This method performs the following steps when called:
470 |
471 | 1. Let _O_ be the *this* value.
472 | 1. Perform ? RequireInternalSlot(_O_, [[ArrayBufferData]]).
473 | 1. If IsSharedArrayBuffer(_O_) is *false*, throw a *TypeError* exception.
474 | 1. Let _len_ be _O_.[[ArrayBufferByteLength]]ArrayBufferByteLength(_O_, ~SeqCst~).
475 | 1. Let _relativeStart_ be ? ToIntegerOrInfinity(_start_).
476 | 1. If _relativeStart_ is -∞, let _first_ be 0.
477 | 1. Else if _relativeStart_ < 0, let _first_ be max(_len_ + _relativeStart_, 0).
478 | 1. Else, let _first_ be min(_relativeStart_, _len_).
479 | 1. If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).
480 | 1. If _relativeEnd_ is -∞, let _final_ be 0.
481 | 1. Else if _relativeEnd_ < 0, let _final_ be max(_len_ + _relativeEnd_, 0).
482 | 1. Else, let _final_ be min(_relativeEnd_, _len_).
483 | 1. Let _newLen_ be max(_final_ - _first_, 0).
484 | 1. Let _ctor_ be ? SpeciesConstructor(_O_, %SharedArrayBuffer%).
485 | 1. Let _new_ be ? Construct(_ctor_, « 𝔽(_newLen_) »).
486 | 1. Perform ? RequireInternalSlot(_new_, [[ArrayBufferData]]).
487 | 1. NOTE: Unlike ArrayBuffers, SharedArrayBuffers cannot shrink, so the length does not need to be reloaded.
488 | 1. If IsSharedArrayBuffer(_new_) is *false*, throw a *TypeError* exception.
489 | 1. If _new_.[[ArrayBufferData]] and _O_.[[ArrayBufferData]] are the same Shared Data Block values, throw a *TypeError* exception.
490 | 1. If _new_.[[ArrayBufferByteLength]] < _newLen_, throw a *TypeError* exception.
491 | 1. Let _fromBuf_ be _O_.[[ArrayBufferData]].
492 | 1. Let _toBuf_ be _new_.[[ArrayBufferData]].
493 | 1. Perform CopyDataBlockBytes(_toBuf_, 0, _fromBuf_, _first_, _newLen_).
494 | 1. Return _new_.
495 |
496 |
497 |
498 |
499 |
500 |
501 |
Modifications to Integer-Indexed Exotic Objects
502 |
503 |
504 |
[[OwnPropertyKeys]] ( ): a normal completion containing a List of property keys
505 |
506 |
for
507 |
an Integer-Indexed exotic object _O_
508 |
509 |
510 | 1. Let _keys_ be a new empty List.
511 | 1. Assert: _O_ is an Integer-Indexed exotic object.
512 | 1. If IsDetachedBuffer(_O_.[[ViewedArrayBuffer]]) is *false*, then
513 | 1. For each integer _i_ starting with 0 such that _i_ < _O_.[[ArrayLength]], in ascending order, do
514 | 1. Add ! ToString(𝔽(_i_)) as the last element of _keys_.
515 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
516 | 1. Let _len_ be IntegerIndexedObjectLength(_O_, _getBufferByteLength_).
517 | 1. If _len_ is not ~out-of-bounds~, then
518 | 1. For each integer _i_ starting with 0 such that _i_ < _len_, in ascending order, do
519 | 1. Add ! ToString(𝔽(_i_)) as the last element of _keys_.
520 | 1. 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
521 | 1. Add _P_ as the last element of _keys_.
522 | 1. For each own property key _P_ of _O_ such that Type(_P_) is Symbol, in ascending chronological order of property creation, do
523 | 1. Add _P_ as the last element of _keys_.
524 | 1. Return _keys_.
525 |
526 |
527 |
528 |
529 |
530 | IsValidIntegerIndex (
531 | _O_: an Integer-Indexed exotic object,
532 | _index_: a Number,
533 | ): a Boolean
534 |
535 |
536 |
537 |
538 | 1. If IsDetachedBuffer(_O_.[[ViewedArrayBuffer]]) is *true*, return *false*.
539 | 1. If IsIntegralNumber(_index_) is *false*, return *false*.
540 | 1. If _index_ is *-0*𝔽, return *false*.
541 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~Unordered~).
542 | 1. NOTE: Bounds checking is not a synchronizing operation when _O_'s backing buffer is a growable SharedArrayBuffer.
543 | 1. Let _length_ be IntegerIndexedObjectLength(_O_, _getBufferByteLength_).
544 | 1. If _length_ is ~out-of-bounds~ or ℝ(_index_) < 0 or ℝ(_index_) ≥ _O_.[[ArrayLength]]_length_, return *false*.
545 | 1. Return *true*.
546 |
547 |
548 |
549 |
550 |
551 |
552 | IntegerIndexedObjectByteLength (
553 | _O_: an Integer-Indexed exotic object,
554 | _getBufferByteLength_: an Abstract Closure,
555 | ): a non-negative integer
556 |
557 |
558 |
559 |
560 | 1. Let _length_ be IntegerIndexedObjectLength(_O_, _getBufferByteLength_).
561 | 1. If _length_ is ~out-of-bounds~ or _length_ = 0, return 0.
562 | 1. If _O_.[[ByteLength]] is not ~auto~, return _O_.[[ByteLength]].
563 | 1. Let _elementSize_ be TypedArrayElementSize(_O_).
564 | 1. Return _length_ × _elementSize_.
565 |
566 |
567 |
568 |
569 |
570 | IntegerIndexedObjectLength (
571 | _O_: an Integer-Indexed exotic object,
572 | _getBufferByteLength_: an Abstract Closure,
573 | ): a non-negative integer or ~out-of-bounds~
574 |
575 |
576 |
577 |
578 | 1. If IsIntegerIndexedObjectOutOfBounds(_O_, _getBufferByteLength_) is *true*, return ~out-of-bounds~.
579 | 1. If _O_.[[ArrayLength]] is not ~auto~, return _O_.[[ArrayLength]].
580 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
581 | 1. Let _bufferByteLength_ be _getBufferByteLength_(_buffer_).
582 | 1. Assert: IsResizableArrayBuffer(_buffer_) is *true*.
583 | 1. Let _byteOffset_ be _O_.[[ByteOffset]].
584 | 1. Let _elementSize_ be TypedArrayElementSize(_O_).
585 | 1. Return floor((_bufferByteLength_ - _byteOffset_) / _elementSize_).
586 |
587 |
588 |
589 |
590 |
591 | IsIntegerIndexedObjectOutOfBounds (
592 | _O_: an Integer-Indexed exotic object,
593 | _getBufferByteLength_: an Abstract Closure,
594 | ): a Boolean
595 |
596 |
597 |
description
598 |
It checks if any of the object's numeric properties reference a value at an index not contained within the underlying data block's bounds.
599 |
600 |
601 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
602 | 1. If IsDetachedBuffer(_O_.[[ViewedArrayBuffer]]) is *true*, return *true*.
603 | 1. Let _bufferByteLength_ be _getBufferByteLength_(_buffer_).
604 | 1. Let _byteOffsetStart_ be _O_.[[ByteOffset]].
605 | 1. If _O_.[[ArrayLength]] is ~auto~, then
606 | 1. Let _byteOffsetEnd_ be _bufferByteLength_.
607 | 1. Else,
608 | 1. Let _elementSize_ be TypedArrayElementSize(_O_).
609 | 1. Let _byteOffsetEnd_ be _byteOffsetStart_ + _O_.[[ArrayLength]] × _elementSize_.
610 | 1. If _byteOffsetStart_ > _bufferByteLength_ or _byteOffsetEnd_ > _bufferByteLength_, return *true*.
611 | 1. NOTE: 0-length TypedArrays are not considered out-of-bounds.
612 | 1. Return *false*.
613 |
614 |
615 |
616 |
617 |
618 | IsArrayBufferViewOutOfBounds(
619 | _O_: an Integer-Indexed exotic object or a DataView,
620 | ): a Boolean
621 |
622 |
623 |
description
624 |
It checks if either any of a TypedArray's numeric properties or a DataView object's methods can reference a value at an index not contained within the underlying data block's bounds. This abstract operation exists as a convenience for upstream specifications.
625 |
626 |
627 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
628 | 1. If IsDetachedBuffer(_buffer_) is *true*, return *true*.
629 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
630 | 1. If IsSharedArrayBuffer(_buffer_) is *true*, then
631 | 1. Assert: If _O_ has a [[DataView]] internal slot, IsViewOutOfBounds(_O_, _getBufferByteLength_) is *false*. Else, IsIntegerIndexedObjectOutOfBounds(_O_, _getBufferByteLength_) is *false*.
632 | 1. NOTE: SharedArrayBuffers can only grow, and views on it cannot go out of bounds after construction. This is special-cased in this operation to avoid shared memory loads of the buffer's byte length, which are not necessary for this check.
633 | 1. Return *false*.
634 | 1. If _O_ has a [[DataView]] internal slot, return IsViewOutOfBounds(_O_, _getBufferByteLength_).
635 | 1. Return IsIntegerIndexedObjectOutOfBounds(_O_, _getBufferByteLength_).
636 |
637 |
638 |
639 |
640 |
641 |
642 |
Modifications to TypedArray Objects
643 |
644 |
645 |
Modifications to Properties of the %TypedArray.prototype% Object
646 |
647 |
648 |
649 | ValidateTypedArray (
650 | _O_: an ECMAScript language value,
651 | ): either a normal completion containing ~unused~ or a throw completion
652 |
653 |
654 |
655 |
656 | 1. Perform ? RequireInternalSlot(_O_, [[TypedArrayName]]).
657 | 1. Assert: _O_ has a [[ViewedArrayBuffer]] internal slot.
658 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
659 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
660 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
661 | 1. If IsIntegerIndexedObjectOutOfBounds(_O_, _getBufferByteLength_) is *true*, throw a *TypeError* exception.
662 | 1. Return _buffer_.
663 |
664 |
665 |
666 |
667 |
get %TypedArray%.prototype.byteLength
668 |
%TypedArray%`.prototype.byteLength` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
669 |
670 | 1. Let _O_ be the *this* value.
671 | 1. Perform ? RequireInternalSlot(_O_, [[TypedArrayName]]).
672 | 1. Assert: _O_ has a [[ViewedArrayBuffer]] internal slot.
673 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
674 | 1. If IsDetachedBuffer(_buffer_) is *true*, return *+0*𝔽.
675 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
676 | 1. Let _size_ be _O_.[[ByteLength]]IntegerIndexedObjectByteLength(_O_, _getBufferByteLength_).
677 | 1. Return 𝔽(_size_).
678 |
679 |
680 |
681 |
682 |
get %TypedArray%.prototype.byteOffset
683 |
%TypedArray%`.prototype.byteOffset` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
684 |
685 | 1. Let _O_ be the *this* value.
686 | 1. Perform ? RequireInternalSlot(_O_, [[TypedArrayName]]).
687 | 1. Assert: _O_ has a [[ViewedArrayBuffer]] internal slot.
688 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
689 | 1. If IsDetachedBuffer(_buffer_) is *true*, return *+0*𝔽.
690 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
691 | 1. If IsIntegerIndexedObjectOutOfBounds(_O_, _getBufferByteLength_) is *true*, return *+0*𝔽.
692 | 1. Let _offset_ be _O_.[[ByteOffset]].
693 | 1. Return 𝔽(_offset_).
694 |
695 |
696 |
697 |
698 |
get %TypedArray%.prototype.length
699 |
%TypedArray%`.prototype.length` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
700 |
701 | 1. Let _O_ be the *this* value.
702 | 1. Perform ? RequireInternalSlot(_O_, [[TypedArrayName]]).
703 | 1. Assert: _O_ has [[ViewedArrayBuffer]] and [[ArrayLength]] internal slots.
704 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
705 | 1. If IsDetachedBuffer(_buffer_) is *true*, return *+0*𝔽.
706 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
707 | 1. Let _length_ be _O_.[[ArrayLength]]IntegerIndexedObjectLength(_O_, _getBufferByteLength_).
708 | 1. If _length_ is ~out-of-bounds~, set _length_ to 0.
709 | 1. Return 𝔽(_length_).
710 |
711 |
This function is not generic. The *this* value must be an object with a [[TypedArrayName]] internal slot.
The interpretation and use of the arguments of %TypedArray%`.prototype.copyWithin` are the same as for `Array.prototype.copyWithin` as defined in .
717 |
This method performs the following steps when called:
718 |
719 | 1. Let _O_ be the *this* value.
720 | 1. Perform ? ValidateTypedArray(_O_).
721 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
722 | 1. Let _len_ be _O_.[[ArrayLength]]IntegerIndexedObjectLength(_O_, _getBufferByteLength_).
723 | 1. Assert: _len_ is not ~out-of-bounds~.
724 | 1. Let _relativeTarget_ be ? ToIntegerOrInfinity(_target_).
725 | 1. If _relativeTarget_ is -∞, let _to_ be 0.
726 | 1. Else if _relativeTarget_ < 0, let _to_ be max(_len_ + _relativeTarget_, 0).
727 | 1. Else, let _to_ be min(_relativeTarget_, _len_).
728 | 1. Let _relativeStart_ be ? ToIntegerOrInfinity(_start_).
729 | 1. If _relativeStart_ is -∞, let _from_ be 0.
730 | 1. Else if _relativeStart_ < 0, let _from_ be max(_len_ + _relativeStart_, 0).
731 | 1. Else, let _from_ be min(_relativeStart_, _len_).
732 | 1. If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).
733 | 1. If _relativeEnd_ is -∞, let _final_ be 0.
734 | 1. Else if _relativeEnd_ < 0, let _final_ be max(_len_ + _relativeEnd_, 0).
735 | 1. Else, let _final_ be min(_relativeEnd_, _len_).
736 | 1. Let _count_ be min(_final_ - _from_, _len_ - _to_).
737 | 1. If _count_ > 0, then
738 | 1. NOTE: The copying must be performed in a manner that preserves the bit-level encoding of the source data.
739 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
740 | 1. Set _getBufferByteLength_ to MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
741 | 1. Set _len_ to IntegerIndexedObjectLength(_O_, _getBufferByteLength_).
742 | 1. If IsDetachedBuffer(_buffer_) is *true*_len_ is ~out-of-bounds~, throw a *TypeError* exception.
743 | 1. Let _typedArrayName_ be the String value of _O_.[[TypedArrayName]].
744 | 1. Let _elementSize_ be the Element Size value specified in for _typedArrayName_.
745 | 1. Let _byteOffset_ be _O_.[[ByteOffset]].
746 | 1. Let _bufferByteLimit_ be _len_ × _elementSize_ + _byteOffset_.
747 | 1. Let _toByteIndex_ be _to_ × _elementSize_ + _byteOffset_.
748 | 1. Let _fromByteIndex_ be _from_ × _elementSize_ + _byteOffset_.
749 | 1. Let _countBytes_ be _count_ × _elementSize_.
750 | 1. If _fromByteIndex_ < _toByteIndex_ and _toByteIndex_ < _fromByteIndex_ + _countBytes_, then
751 | 1. Let _direction_ be -1.
752 | 1. Set _fromByteIndex_ to _fromByteIndex_ + _countBytes_ - 1.
753 | 1. Set _toByteIndex_ to _toByteIndex_ + _countBytes_ - 1.
754 | 1. Else,
755 | 1. Let _direction_ be 1.
756 | 1. Repeat, while _countBytes_ > 0,
757 | 1. If _fromByteIndex_ < _bufferByteLimit_ and _toByteIndex_ < _bufferByteLimit_, then
758 | 1. Let _value_ be GetValueFromBuffer(_buffer_, _fromByteIndex_, ~Uint8~, *true*, ~Unordered~).
759 | 1. Perform SetValueInBuffer(_buffer_, _toByteIndex_, ~Uint8~, _value_, *true*, ~Unordered~).
760 | 1. Set _fromByteIndex_ to _fromByteIndex_ + _direction_.
761 | 1. Set _toByteIndex_ to _toByteIndex_ + _direction_.
762 | 1. Set _countBytes_ to _countBytes_ - 1.
763 | 1. Return _O_.
764 |
765 |
766 |
767 |
768 |
The interpretation and use of the arguments of %TypedArray%`.prototype.fill` are the same as for `Array.prototype.fill` as defined in .
770 |
This method performs the following steps when called:
771 |
772 | 1. Let _O_ be the *this* value.
773 | 1. Perform ? ValidateTypedArray(_O_).
774 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
775 | 1. Let _len_ be _O_.[[ArrayLength]]IntegerIndexedObjectLength(_O_, _getBufferByteLength_).
776 | 1. Assert: _len_ is not ~out-of-bounds~.
777 | 1. If _O_.[[ContentType]] is ~BigInt~, set _value_ to ? ToBigInt(_value_).
778 | 1. Otherwise, set _value_ to ? ToNumber(_value_).
779 | 1. Let _relativeStart_ be ? ToIntegerOrInfinity(_start_).
780 | 1. If _relativeStart_ is -∞, let _k_ be 0.
781 | 1. Else if _relativeStart_ < 0, let _k_ be max(_len_ + _relativeStart_, 0).
782 | 1. Else, let _k_ be min(_relativeStart_, _len_).
783 | 1. If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).
784 | 1. If _relativeEnd_ is -∞, let _final_ be 0.
785 | 1. Else if _relativeEnd_ < 0, let _final_ be max(_len_ + _relativeEnd_, 0).
786 | 1. Else, let _final_ be min(_relativeEnd_, _len_).
787 | 1. If IsDetachedBuffer(_O_.[[ViewedArrayBuffer]]) is *true*, throw a *TypeError* exception.
788 | 1. Set _getBufferByteLength_ to MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
789 | 1. Set _len_ to IntegerIndexedObjectLength(_O_, _getBufferByteLength_).
790 | 1. If _len_ is ~out-of-bounds~, throw a *TypeError* exception.
791 | 1. Set _final_ to min(_final_, _len_).
792 | 1. Repeat, while _k_ < _final_,
793 | 1. Let _Pk_ be ! ToString(𝔽(_k_)).
794 | 1. Perform ! Set(_O_, _Pk_, _value_, *true*).
795 | 1. Set _k_ to _k_ + 1.
796 | 1. Return _O_.
797 |
798 |
799 |
800 |
801 |
%TypedArray%.prototype.slice ( _start_, _end_ )
802 |
The interpretation and use of the arguments of %TypedArray%`.prototype.slice` are the same as for `Array.prototype.slice` as defined in . The following steps are taken:
803 |
This method performs the following steps when called:
804 |
805 | 1. Let _O_ be the *this* value.
806 | 1. Perform ? ValidateTypedArray(_O_).
807 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
808 | 1. Let _len_ be _O_.[[ArrayLength]]IntegerIndexedObjectLength(_O_, _getBufferByteLength_).
809 | 1. Assert: _len_ is not ~out-of-bounds~.
810 | 1. Let _relativeStart_ be ? ToIntegerOrInfinity(_start_).
811 | 1. If _relativeStart_ is -∞, let _k_ be 0.
812 | 1. Else if _relativeStart_ < 0, let _k_ be max(_len_ + _relativeStart_, 0).
813 | 1. Else, let _k_ be min(_relativeStart_, _len_).
814 | 1. If _end_ is *undefined*, let _relativeEnd_ be _len_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).
815 | 1. If _relativeEnd_ is -∞, let _final_ be 0.
816 | 1. Else if _relativeEnd_ < 0, let _final_ be max(_len_ + _relativeEnd_, 0).
817 | 1. Else, let _final_ be min(_relativeEnd_, _len_).
818 | 1. Let _count_ be max(_final_ - _k_, 0).
819 | 1. Let _A_ be ? TypedArraySpeciesCreate(_O_, « 𝔽(_count_) »).
820 | 1. If _count_ > 0, then
821 | 1. If IsDetachedBuffer(_O_.[[ViewedArrayBuffer]]) is *true*, throw a *TypeError* exception.
822 | 1. Set _getBufferByteLength_ to MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
823 | 1. Set _len_ to IntegerIndexedObjectLength(_O_, _getBufferByteLength_).
824 | 1. If _len_ is ~out-of-bounds~, throw a *TypeError* exception.
825 | 1. Set _final_ to min(_final_, _len_).
826 | 1. Let _srcName_ be the String value of _O_.[[TypedArrayName]].
827 | 1. Let _srcType_ be the Element Type value in for _srcName_.
828 | 1. Let _targetName_ be the String value of _A_.[[TypedArrayName]].
829 | 1. Let _targetType_ be the Element Type value in for _targetName_.
830 | 1. If _srcType_ is different from _targetType_, then
831 | 1. Let _n_ be 0.
832 | 1. Repeat, while _k_ < _final_,
833 | 1. Let _Pk_ be ! ToString(𝔽(_k_)).
834 | 1. Let _kValue_ be ! Get(_O_, _Pk_).
835 | 1. Perform ! Set(_A_, ! ToString(𝔽(_n_)), _kValue_, *true*).
836 | 1. Set _k_ to _k_ + 1.
837 | 1. Set _n_ to _n_ + 1.
838 | 1. Else,
839 | 1. Let _srcBuffer_ be _O_.[[ViewedArrayBuffer]].
840 | 1. Let _targetBuffer_ be _A_.[[ViewedArrayBuffer]].
841 | 1. Let _elementSize_ be the Element Size value specified in for Element Type _srcType_.
842 | 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.
843 | 1. Let _srcByteOffset_ be _O_.[[ByteOffset]].
844 | 1. Let _targetByteIndex_ be _A_.[[ByteOffset]].
845 | 1. Let _srcByteIndex_ be (_k_ × _elementSize_) + _srcByteOffset_.
846 | 1. Let _limit_ be _targetByteIndex_ + min(_count_, _len_) × _elementSize_.
847 | 1. Repeat, while _targetByteIndex_ < _limit_,
848 | 1. Let _value_ be GetValueFromBuffer(_srcBuffer_, _srcByteIndex_, ~Uint8~, *true*, ~Unordered~).
849 | 1. Perform SetValueInBuffer(_targetBuffer_, _targetByteIndex_, ~Uint8~, _value_, *true*, ~Unordered~).
850 | 1. Set _srcByteIndex_ to _srcByteIndex_ + 1.
851 | 1. Set _targetByteIndex_ to _targetByteIndex_ + 1.
852 | 1. Return _A_.
853 |
854 |
This function is not generic. The *this* value must be an object with a [[TypedArrayName]] internal slot.
Returns a new _TypedArray_ 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.
860 |
This method performs the following steps when called:
861 |
862 | 1. Let _O_ be the *this* value.
863 | 1. Perform ? RequireInternalSlot(_O_, [[TypedArrayName]]).
864 | 1. Assert: _O_ has a [[ViewedArrayBuffer]] internal slot.
865 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
866 | 1. Let _getSrcBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
867 | 1. Let _srcLength_ be _O_.[[ArrayLength]]IntegerIndexedObjectLength(_O_, _getSrcBufferByteLength_).
868 | 1. If _srcLength_ is ~out-of-bounds~, set _srcLength_ to 0.
869 | 1. Let _relativeBegin_ be ? ToIntegerOrInfinity(_begin_).
870 | 1. If _relativeBegin_ is -∞, let _beginIndex_ be 0.
871 | 1. Else if _relativeBegin_ < 0, let _beginIndex_ be max(_srcLength_ + _relativeBegin_, 0).
872 | 1. Else, let _beginIndex_ be min(_relativeBegin_, _srcLength_).
873 | 1. If _O_.[[ArrayLength]] is ~auto~ and _end_ is *undefined*, then
874 | 1. Let _newLength_ be *undefined*.
875 | 1. Else,
876 | 1. If _end_ is *undefined*, let _relativeEnd_ be _srcLength_; else let _relativeEnd_ be ? ToIntegerOrInfinity(_end_).
877 | 1. If _relativeEnd_ is -∞, let _endIndex_ be 0.
878 | 1. Else if _relativeEnd_ < 0, let _endIndex_ be max(_srcLength_ + _relativeEnd_, 0).
879 | 1. Else, let _endIndex_ be min(_relativeEnd_, _srcLength_).
880 | 1. Let _newLength_ be max(_endIndex_ - _beginIndex_, 0).
881 | 1. Let _constructorName_ be the String value of _O_.[[TypedArrayName]].
882 | 1. Let _elementSize_ be the Element Size value specified in for _constructorName_.
883 | 1. Let _srcByteOffset_ be _O_.[[ByteOffset]].
884 | 1. Let _beginByteOffset_ be _srcByteOffset_ + _beginIndex_ × _elementSize_.
885 | 1. If _newLength_ is *undefined*, then
886 | 1. Let _argumentsList_ be « _buffer_, 𝔽(_beginByteOffset_) ».
887 | 1. Else,
888 | 1. Let _argumentsList_ be « _buffer_, 𝔽(_beginByteOffset_), 𝔽(_newLength_) ».
889 | 1. Return ? TypedArraySpeciesCreate(_O_, _argumentsList_).
890 |
891 |
This function is not generic. The *this* value must be an object with a [[TypedArrayName]] internal slot.
892 |
893 |
894 |
895 |
896 | SetTypedArrayFromTypedArray (
897 | _target_: a TypedArray,
898 | _targetOffset_: a non-negative integer or +∞,
899 | _source_: a TypedArray,
900 | ): either a normal completion containing ~unused~ or a throw completion
901 |
902 |
903 |
description
904 |
It sets multiple values in _target_, starting at index _targetOffset_, reading the values from _source_.
905 |
906 |
907 | 1. Assert: _source_ is an Object that has a [[TypedArrayName]] internal slot.
908 | 1. Let _targetBuffer_ be _target_.[[ViewedArrayBuffer]].
909 | 1. If IsDetachedBuffer(_targetBuffer_) is *true*, throw a *TypeError* exception.
910 | 1. Let _getTargetBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
911 | 1. Let _targetLength_ be _target_.[[ArrayLength]]IntegerIndexedObjectLength(_target_, _getTargetBufferByteLength_).
912 | 1. If _targetLength_ is ~out-of-bounds~, throw a *TypeError* exception.
913 | 1. Let _srcBuffer_ be _source_.[[ViewedArrayBuffer]].
914 | 1. If IsDetachedBuffer(_srcBuffer_) is *true*, throw a *TypeError* exception.
915 | 1. Let _targetType_ be TypedArrayElementType(_target_).
916 | 1. Let _targetElementSize_ be TypedArrayElementSize(_target_).
917 | 1. Let _targetByteOffset_ be _target_.[[ByteOffset]].
918 | 1. Let _srcType_ be TypedArrayElementType(_source_).
919 | 1. Let _srcElementSize_ be TypedArrayElementSize(_source_).
920 | 1. Let _getSrcBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
921 | 1. Let _srcLength_ be _source_.[[ArrayLength]]IntegerIndexedObjectLength(_source_, _getSrcBufferByteLength_).
922 | 1. If _srcLength_ is ~out-of-bounds~, throw a *TypeError* exception.
923 | 1. Let _srcByteOffset_ be _source_.[[ByteOffset]].
924 | 1. If _targetOffset_ is +∞, throw a *RangeError* exception.
925 | 1. If _srcLength_ + _targetOffset_ > _targetLength_, throw a *RangeError* exception.
926 | 1. If _target_.[[ContentType]] ≠ _source_.[[ContentType]], throw a *TypeError* exception.
927 | 1. If both IsSharedArrayBuffer(_srcBuffer_) and IsSharedArrayBuffer(_targetBuffer_) are *true*, then
928 | 1. If _srcBuffer_.[[ArrayBufferData]] and _targetBuffer_.[[ArrayBufferData]] are the same Shared Data Block values, let _same_ be *true*; else let _same_ be *false*.
929 | 1. Else, let _same_ be SameValue(_srcBuffer_, _targetBuffer_).
930 | 1. If _same_ is *true*, then
931 | 1. Let _srcByteLength_ be _source_.[[ByteLength]]IntegerIndexedObjectByteLength(_source_, _getSrcBufferByteLength_).
932 | 1. Set _srcBuffer_ to ? CloneArrayBuffer(_srcBuffer_, _srcByteOffset_, _srcByteLength_).
933 | 1. Let _srcByteIndex_ be 0.
934 | 1. Else, let _srcByteIndex_ be _srcByteOffset_.
935 | 1. Let _targetByteIndex_ be _targetOffset_ × _targetElementSize_ + _targetByteOffset_.
936 | 1. Let _limit_ be _targetByteIndex_ + _targetElementSize_ × _srcLength_.
937 | 1. If _srcType_ is the same as _targetType_, then
938 | 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.
939 | 1. Repeat, while _targetByteIndex_ < _limit_,
940 | 1. Let _value_ be GetValueFromBuffer(_srcBuffer_, _srcByteIndex_, ~Uint8~, *true*, ~Unordered~).
941 | 1. Perform SetValueInBuffer(_targetBuffer_, _targetByteIndex_, ~Uint8~, _value_, *true*, ~Unordered~).
942 | 1. Set _srcByteIndex_ to _srcByteIndex_ + 1.
943 | 1. Set _targetByteIndex_ to _targetByteIndex_ + 1.
944 | 1. Else,
945 | 1. Repeat, while _targetByteIndex_ < _limit_,
946 | 1. Let _value_ be GetValueFromBuffer(_srcBuffer_, _srcByteIndex_, _srcType_, *true*, ~Unordered~).
947 | 1. Perform SetValueInBuffer(_targetBuffer_, _targetByteIndex_, _targetType_, _value_, *true*, ~Unordered~).
948 | 1. Set _srcByteIndex_ to _srcByteIndex_ + _srcElementSize_.
949 | 1. Set _targetByteIndex_ to _targetByteIndex_ + _targetElementSize_.
950 |
951 |
952 |
953 |
954 |
955 |
Modifications to the _TypedArray_ Constructors
956 |
957 |
958 |
959 | InitializeTypedArrayFromTypedArray (
960 | _O_: a TypedArray,
961 | _srcArray_: a TypedArray,
962 | ): either a normal completion containing ~unused~ or a throw completion
963 |
964 |
965 |
966 |
967 | 1. Let _srcData_ be _srcArray_.[[ViewedArrayBuffer]].
968 | 1. If IsDetachedBuffer(_srcData_) is *true*, throw a *TypeError* exception.
969 | 1. Let _elementType_ be TypedArrayElementType(_O_).
970 | 1. Let _elementSize_ be TypedArrayElementSize(_O_).
971 | 1. Let _getSrcBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
972 | 1. Let _elementLength_ be _srcArray_.[[ArrayLength]]IntegerIndexedObjectLength(_srcArray_, _getSrcBufferByteLength_).
973 | 1. If _elementLength_ is ~out-of-bounds~, throw a *TypeError* exception.
974 | 1. Let _srcType_ be TypedArrayElementType(_srcArray_).
975 | 1. Let _srcElementSize_ be TypedArrayElementSize(_srcArray_).
976 | 1. Let _srcByteOffset_ be _srcArray_.[[ByteOffset]].
977 | 1. Let _byteLength_ be _elementSize_ × _elementLength_.
978 | 1. If _elementType_ is the same as _srcType_, then
979 | 1. Let _data_ be ? CloneArrayBuffer(_srcData_, _srcByteOffset_, _byteLength_).
980 | 1. Else,
981 | 1. Let _data_ be ? AllocateArrayBuffer(%ArrayBuffer%, _byteLength_).
982 | 1. If _srcArray_.[[ContentType]] ≠ _O_.[[ContentType]], throw a *TypeError* exception.
983 | 1. Let _srcByteIndex_ be _srcByteOffset_.
984 | 1. Let _targetByteIndex_ be 0.
985 | 1. Let _count_ be _elementLength_.
986 | 1. Repeat, while _count_ > 0,
987 | 1. Let _value_ be GetValueFromBuffer(_srcData_, _srcByteIndex_, _srcType_, *true*, ~Unordered~).
988 | 1. Perform SetValueInBuffer(_data_, _targetByteIndex_, _elementType_, _value_, *true*, ~Unordered~).
989 | 1. Set _srcByteIndex_ to _srcByteIndex_ + _srcElementSize_.
990 | 1. Set _targetByteIndex_ to _targetByteIndex_ + _elementSize_.
991 | 1. Set _count_ to _count_ - 1.
992 | 1. Set _O_.[[ViewedArrayBuffer]] to _data_.
993 | 1. Set _O_.[[ByteLength]] to _byteLength_.
994 | 1. Set _O_.[[ByteOffset]] to 0.
995 | 1. Set _O_.[[ArrayLength]] to _elementLength_.
996 | 1. Return ~unused~.
997 |
998 |
999 |
1000 |
1001 |
1002 | InitializeTypedArrayFromArrayBuffer (
1003 | _O_: a TypedArray,
1004 | _buffer_: an ArrayBuffer or a SharedArrayBuffer,
1005 | _byteOffset_: an ECMAScript language value,
1006 | _length_: an ECMAScript language value,
1007 | ): either a normal completion containing ~unused~ or a throw completion
1008 |
1009 |
1010 |
1011 |
1012 | 1. Let _elementSize_ be TypedArrayElementSize(_O_).
1013 | 1. Let _offset_ be ? ToIndex(_byteOffset_).
1014 | 1. If _offset_ modulo _elementSize_ ≠ 0, throw a *RangeError* exception.
1015 | 1. Let _bufferIsResizable_ be IsResizableArrayBuffer(_buffer_).
1016 | 1. If _length_ is not *undefined*, then
1017 | 1. Let _newLength_ be ? ToIndex(_length_).
1018 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1019 | 1. Let _bufferByteLength_ be _buffer_.[[ArrayBufferByteLength]]ArrayBufferByteLength(_buffer_, ~SeqCst~).
1020 | 1. If _length_ is *undefined* and _bufferIsResizable_ is *true*, then
1021 | 1. If _offset_ > _bufferByteLength_, throw a *RangeError* exception.
1022 | 1. Set _O_.[[ByteLength]] to ~auto~.
1023 | 1. Set _O_.[[ArrayLength]] to ~auto~.
1024 | 1. Else,
1025 | 1. If _length_ is *undefined*, then
1026 | 1. If _bufferByteLength_ modulo _elementSize_ ≠ 0, throw a *RangeError* exception.
1027 | 1. Let _newByteLength_ be _bufferByteLength_ - _offset_.
1028 | 1. If _newByteLength_ < 0, throw a *RangeError* exception.
1029 | 1. Else,
1030 | 1. Let _newByteLength_ be _newLength_ × _elementSize_.
1031 | 1. If _offset_ + _newByteLength_ > _bufferByteLength_, throw a *RangeError* exception.
1032 | 1. Set _O_.[[ViewedArrayBuffer]] to _buffer_.
1033 | 1. Set _O_.[[ByteLength]] to _newByteLength_.
1034 | 1. Set _O_.[[ByteOffset]] to _offset_.
1035 | 1. Set _O_.[[ArrayLength]] to _newByteLength_ / _elementSize_.
1036 | 1. Set _O_.[[ViewedArrayBuffer]] to _buffer_.
1037 | 1. Set _O_.[[ByteOffset]] to _offset_.
1038 | 1. Return ~unused~.
1039 |
1040 |
1041 |
1042 |
1043 |
1044 |
1045 |
Modifications to DataView Objects
1046 |
1047 |
1048 |
Modifications to Abstract Operations For DataView Objects
1049 |
1050 |
1051 |
1052 |
1053 | GetViewByteLength (
1054 | _view_: a DataView,
1055 | _getBufferByteLength_: an Abstract Closure,
1056 | ): a non-negative integer or ~out-of-bounds~
1057 |
1058 |
1059 |
1060 |
1061 | 1. If IsViewOutOfBounds(_view_, _getBufferByteLength_) is *true*, return ~out-of-bounds~.
1062 | 1. If _view_.[[ByteLength]] is not ~auto~, return _view_.[[ByteLength]].
1063 | 1. Let _buffer_ be _view_.[[ViewedArrayBuffer]].
1064 | 1. Let _bufferByteLength_ be _getBufferByteLength_(_buffer_).
1065 | 1. Assert: IsResizableArrayBuffer(_buffer_) is *true*.
1066 | 1. Let _byteOffset_ be _view_.[[ByteOffset]].
1067 | 1. Return _bufferByteLength_ - _byteOffset_.
1068 |
1069 |
1070 |
1071 |
1072 |
1073 | IsViewOutOfBounds (
1074 | _view_: a DataView,
1075 | _getBufferByteLength_: an Abstract Closure,
1076 | ): a Boolean
1077 |
1078 |
1079 |
1080 |
1081 | 1. Let _buffer_ be _view_.[[ViewedArrayBuffer]].
1082 | 1. If IsDetachedBuffer(_buffer_) is *true*, return *true*.
1083 | 1. Let _bufferByteLength_ be _getBufferByteLength_(_buffer_).
1084 | 1. Let _byteOffsetStart_ be _view_.[[ByteOffset]].
1085 | 1. If _view_.[[ByteLength]] is ~auto~, then
1086 | 1. Let _byteOffsetEnd_ be _bufferByteLength_.
1087 | 1. Else,
1088 | 1. Let _byteOffsetEnd_ be _byteOffsetStart_ + _view_.[[ByteLength]].
1089 | 1. If _byteOffsetStart_ > _bufferByteLength_ or _byteOffsetEnd_ > _bufferByteLength_, return *true*.
1090 | 1. NOTE: 0-length DataViews are not considered out-of-bounds.
1091 | 1. Return *false*.
1092 |
1093 |
1094 |
1095 |
1096 |
1097 |
1098 | GetViewValue (
1099 | _view_: an ECMAScript language value,
1100 | _requestIndex_: an ECMAScript language value,
1101 | _isLittleEndian_: an ECMAScript language value,
1102 | _type_: a TypedArray element type,
1103 | ): either a normal completion containing either a Number or a BigInt, or a throw completion
1104 |
1105 |
1106 |
description
1107 |
It is used by functions on DataView instances to retrieve values from the view's buffer.
1108 |
1109 |
1110 | 1. Perform ? RequireInternalSlot(_view_, [[DataView]]).
1111 | 1. Assert: _view_ has a [[ViewedArrayBuffer]] internal slot.
1112 | 1. Let _getIndex_ be ? ToIndex(_requestIndex_).
1113 | 1. Set _isLittleEndian_ to ToBoolean(_isLittleEndian_).
1114 | 1. Let _buffer_ be _view_.[[ViewedArrayBuffer]].
1115 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1116 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~Unordered~).
1117 | 1. NOTE: Bounds checking is not a synchronizing operation when _view_'s backing buffer is a growable SharedArrayBuffer.
1118 | 1. Let _viewOffset_ be _view_.[[ByteOffset]].
1119 | 1. Let _viewSize_ be _view_.[[ByteLength]]GetViewByteLength(_view_, _getBufferByteLength_).
1120 | 1. If _viewSize_ is ~out-of-bounds~, throw a *TypeError* exception.
1121 | 1. Let _elementSize_ be the Element Size value specified in for Element Type _type_.
1122 | 1. If _getIndex_ + _elementSize_ > _viewSize_, throw a *RangeError* exception.
1123 | 1. Let _bufferIndex_ be _getIndex_ + _viewOffset_.
1124 | 1. Return GetValueFromBuffer(_buffer_, _bufferIndex_, _type_, *false*, ~Unordered~, _isLittleEndian_).
1125 |
1126 |
1127 |
1128 |
1129 |
1130 | SetViewValue (
1131 | _view_: an ECMAScript language value,
1132 | _requestIndex_: an ECMAScript language value,
1133 | _isLittleEndian_: an ECMAScript language value,
1134 | _type_: a TypedArray element type,
1135 | _value_: an ECMAScript language value,
1136 | ): either a normal completion containing *undefined* or a throw completion
1137 |
1138 |
1139 |
description
1140 |
It is used by functions on DataView instances to store values into the view's buffer.
1141 |
1142 |
1143 | 1. Perform ? RequireInternalSlot(_view_, [[DataView]]).
1144 | 1. Assert: _view_ has a [[ViewedArrayBuffer]] internal slot.
1145 | 1. Let _getIndex_ be ? ToIndex(_requestIndex_).
1146 | 1. If IsBigIntElementType(_type_) is *true*, let _numberValue_ be ? ToBigInt(_value_).
1147 | 1. Otherwise, let _numberValue_ be ? ToNumber(_value_).
1148 | 1. Set _isLittleEndian_ to ToBoolean(_isLittleEndian_).
1149 | 1. Let _buffer_ be _view_.[[ViewedArrayBuffer]].
1150 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1151 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~Unordered~).
1152 | 1. NOTE: Bounds checking is not a synchronizing operation when _view_'s backing buffer is a growable SharedArrayBuffer.
1153 | 1. Let _viewOffset_ be _view_.[[ByteOffset]].
1154 | 1. Let _viewSize_ be _view_.[[ByteLength]]GetViewByteLength(_view_, _getBufferByteLength_).
1155 | 1. If _viewSize_ is ~out-of-bounds~, throw a *TypeError* exception.
1156 | 1. Let _elementSize_ be the Element Size value specified in for Element Type _type_.
1157 | 1. If _getIndex_ + _elementSize_ > _viewSize_, throw a *RangeError* exception.
1158 | 1. Let _bufferIndex_ be _getIndex_ + _viewOffset_.
1159 | 1. Perform SetValueInBuffer(_buffer_, _bufferIndex_, _type_, _numberValue_, *false*, ~Unordered~, _isLittleEndian_).
1160 |
1161 |
1162 |
1163 |
1164 |
1165 |
When the `DataView` function is called with at least one argument _buffer_, the following steps are taken:
1170 |
1171 | 1. If NewTarget is *undefined*, throw a *TypeError* exception.
1172 | 1. Perform ? RequireInternalSlot(_buffer_, [[ArrayBufferData]]).
1173 | 1. Let _offset_ be ? ToIndex(_byteOffset_).
1174 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1175 | 1. Let _bufferByteLength_ be _buffer_.[[ArrayBufferByteLength]]ArrayBufferByteLength(_buffer_, ~SeqCst~).
1176 | 1. If _offset_ > _bufferByteLength_, throw a *RangeError* exception.
1177 | 1. Let _bufferIsResizable_ be IsResizableArrayBuffer(_buffer_).
1178 | 1. Let _byteLengthChecked_ be ~empty~.
1179 | 1. If _bufferIsResizable_ is *true* and _byteLength_ is *undefined*, then
1180 | 1. Let _viewByteLength_ be ~auto~.
1181 | 1. IfElse if _byteLength_ is *undefined*, then
1182 | 1. Let _viewByteLength_ be _bufferByteLength_ - _offset_.
1183 | 1. Else,
1184 | 1. Set _byteLengthChecked_ to ? ToIndex(_byteLength_).
1185 | 1. Let _viewByteLength_ be ? ToIndex(_byteLength_)_byteLengthChecked_.
1186 | 1. If _offset_ + _viewByteLength_ > _bufferByteLength_, throw a *RangeError* exception.
1187 | 1. Let _O_ be ? OrdinaryCreateFromConstructor(NewTarget, *"%DataView.prototype%"*, « [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]] »).
1188 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1189 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
1190 | 1. Set _bufferByteLength_ be _getBufferByteLength_(_buffer_).
1191 | 1. If _offset_ > _bufferByteLength_, throw a *RangeError* exception.
1192 | 1. If _byteLengthChecked_ is not ~empty~, then
1193 | 1. If _offset_ + _viewByteLength_ > _bufferByteLength_, throw a *RangeError* exception.
1194 | 1. Set _O_.[[ViewedArrayBuffer]] to _buffer_.
1195 | 1. Set _O_.[[ByteLength]] to _viewByteLength_.
1196 | 1. Set _O_.[[ByteOffset]] to _offset_.
1197 | 1. Return _O_.
1198 |
1199 |
1200 |
1201 |
1202 |
1203 |
Modifications to Properties of the DataView Prototype Object
1204 |
1205 |
1206 |
get DataView.prototype.byteLength
1207 |
`DataView.prototype.byteLength` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
1208 |
1209 | 1. Let _O_ be the *this* value.
1210 | 1. Perform ? RequireInternalSlot(_O_, [[DataView]]).
1211 | 1. Assert: _O_ has a [[ViewedArrayBuffer]] internal slot.
1212 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
1213 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1214 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
1215 | 1. If IsViewOutOfBounds(_O_, _getBufferByteLength_) is *true*, throw a *TypeError* exception.
1216 | 1. Let _size_ be _O_.[[ByteLength]]GetViewByteLength(_O_, _getBufferByteLength_).
1217 | 1. Return 𝔽(_size_).
1218 |
1219 |
1220 |
1221 |
1222 |
get DataView.prototype.byteOffset
1223 |
`DataView.prototype.byteOffset` is an accessor property whose set accessor function is *undefined*. Its get accessor function performs the following steps:
1224 |
1225 | 1. Let _O_ be the *this* value.
1226 | 1. Perform ? RequireInternalSlot(_O_, [[DataView]]).
1227 | 1. Assert: _O_ has a [[ViewedArrayBuffer]] internal slot.
1228 | 1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
1229 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1230 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).
1231 | 1. If IsViewOutOfBounds(_O_, _getBufferByteLength_) is *true*, throw a *TypeError* exception.
1232 | 1. Let _offset_ be _O_.[[ByteOffset]].
1233 | 1. Return 𝔽(_offset_).
1234 |
1235 |
1236 |
1237 |
1238 |
1239 |
1240 |
This function performs the following steps when called:
1248 |
1249 | 1. Let _buffer_ be ? ValidateIntegerTypedArray(_typedArray_).
1250 | 1. Let _block_ be _buffer_.[[ArrayBufferData]].
1251 | 1. Let _indexedPosition_ be ? ValidateAtomicAccess(_typedArray_, _index_).
1252 | 1. If _typedArray_.[[ContentType]] is ~BigInt~, then
1253 | 1. Let _expected_ be ? ToBigInt(_expectedValue_).
1254 | 1. Let _replacement_ be ? ToBigInt(_replacementValue_).
1255 | 1. Else,
1256 | 1. Let _expected_ be 𝔽(? ToIntegerOrInfinity(_expectedValue_)).
1257 | 1. Let _replacement_ be 𝔽(? ToIntegerOrInfinity(_replacementValue_)).
1258 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1259 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~Unordered~).
1260 | 1. NOTE: Bounds checking is not a synchronizing operation when _typedArray_'s backing buffer is a growable SharedArrayBuffer.
1261 | 1. Let _length_ be IntegerIndexedObjectLength(_typedArray_, _getBufferByteLength_).
1262 | 1. If ~length~ is ~out-of-bounds~, throw a *TypeError* exception.
1263 | 1. If _indexedPosition_ ≥ _length_, throw a *RangeError* exception.
1264 | 1. NOTE: The above checks isare not redundant with the checks in ValidateIntegerTypedArray and ValidateAtomicAccess because the call to ToBigInt or ToIntegerOrInfinity on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached. These checks are only needed when _typedArray_'s backing buffer is an ArrayBuffer.
1265 | 1. Let _elementType_ be TypedArrayElementType(_typedArray_).
1266 | 1. Let _elementSize_ be TypedArrayElementSize(_typedArray_).
1267 | 1. Let _isLittleEndian_ be the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
1268 | 1. Let _expectedBytes_ be NumericToRawBytes(_elementType_, _expected_, _isLittleEndian_).
1269 | 1. Let _replacementBytes_ be NumericToRawBytes(_elementType_, _replacement_, _isLittleEndian_).
1270 | 1. If IsSharedArrayBuffer(_buffer_) is *true*, then
1271 | 1. Let _execution_ be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
1272 | 1. Let _eventList_ be the [[EventList]] field of the element in _execution_.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
1273 | 1. Let _rawBytesRead_ be a List of length _elementSize_ whose elements are nondeterministically chosen byte values.
1274 | 1. NOTE: In implementations, _rawBytesRead_ is the result of a load-link, of a load-exclusive, or of an operand of a read-modify-write instruction on the underlying hardware. The nondeterminism is a semantic prescription of the memory model to describe observable behaviour of hardware with weak consistency.
1275 | 1. NOTE: The comparison of the expected value and the read value is performed outside of the read-modify-write modification function to avoid needlessly strong synchronization when the expected value is not equal to the read value.
1276 | 1. If ByteListEqual(_rawBytesRead_, _expectedBytes_) is *true*, then
1277 | 1. Let _second_ be a new read-modify-write modification function with parameters (_oldBytes_, _newBytes_) that captures nothing and performs the following steps atomically when called:
1278 | 1. Return _newBytes_.
1279 | 1. Let _event_ be ReadModifyWriteSharedMemory { [[Order]]: ~SeqCst~, [[NoTear]]: *true*, [[Block]]: _block_, [[ByteIndex]]: _indexedPosition_, [[ElementSize]]: _elementSize_, [[Payload]]: _replacementBytes_, [[ModifyOp]]: _second_ }.
1280 | 1. Else,
1281 | 1. Let _event_ be ReadSharedMemory { [[Order]]: ~SeqCst~, [[NoTear]]: *true*, [[Block]]: _block_, [[ByteIndex]]: _indexedPosition_, [[ElementSize]]: _elementSize_ }.
1282 | 1. Append _event_ to _eventList_.
1283 | 1. Append Chosen Value Record { [[Event]]: _event_, [[ChosenValue]]: _rawBytesRead_ } to _execution_.[[ChosenValues]].
1284 | 1. Else,
1285 | 1. Let _rawBytesRead_ be a List of length _elementSize_ whose elements are the sequence of _elementSize_ bytes starting with _block_[_indexedPosition_].
1286 | 1. If ByteListEqual(_rawBytesRead_, _expectedBytes_) is *true*, then
1287 | 1. Store the individual bytes of _replacementBytes_ into _block_, starting at _block_[_indexedPosition_].
1288 | 1. Return RawBytesToNumeric(_elementType_, _rawBytesRead_, _isLittleEndian_).
1289 |
1290 |
1291 |
1292 |
1293 |
Atomics.store ( _typedArray_, _index_, _value_ )
1294 |
This function performs the following steps when called:
1295 |
1296 | 1. Let _buffer_ be ? ValidateIntegerTypedArray(_typedArray_).
1297 | 1. Let _indexedPosition_ be ? ValidateAtomicAccess(_typedArray_, _index_).
1298 | 1. If _typedArray_.[[ContentType]] is ~BigInt~, let _v_ be ? ToBigInt(_value_).
1299 | 1. Otherwise, let _v_ be 𝔽(? ToIntegerOrInfinity(_value_)).
1300 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1301 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~Unordered~).
1302 | 1. NOTE: Bounds checking is not a synchronizing operation when _typedArray_'s backing buffer is a growable SharedArrayBuffer.
1303 | 1. Let _length_ be IntegerIndexedObjectLength(_typedArray_, _getBufferByteLength_).
1304 | 1. If ~length~ is ~out-of-bounds~, throw a *TypeError* exception.
1305 | 1. If _indexedPosition_ ≥ _length_, throw a *RangeError* exception.
1306 | 1. Let _elementType_ be TypedArrayElementType(_typedArray_).
1307 | 1. Perform SetValueInBuffer(_buffer_, _indexedPosition_, _elementType_, _v_, *true*, ~SeqCst~).
1308 | 1. Return _v_.
1309 |
1310 |
1311 |
1312 |
1313 |
1314 |
Modifications to Abstract Operations for Atomics
1315 |
1316 |
1317 |
1318 | AtomicReadModifyWrite (
1319 | _typedArray_: an ECMAScript language value,
1320 | _index_: an ECMAScript language value,
1321 | _value_: an ECMAScript language value,
1322 | _op_: a read-modify-write modification function,
1323 | ): either a normal completion containing either a Number or a BigInt, or a throw completion
1324 |
1325 |
1326 |
description
1327 |
_op_ takes two List of byte values arguments and returns a List of byte values. This operation atomically loads a value, combines it with another value, and stores the result of the combination. It returns the loaded value.
1328 |
1329 |
1330 | 1. Let _buffer_ be ? ValidateIntegerTypedArray(_typedArray_).
1331 | 1. Let _indexedPosition_ be ? ValidateAtomicAccess(_typedArray_, _index_).
1332 | 1. If _typedArray_.[[ContentType]] is ~BigInt~, let _v_ be ? ToBigInt(_value_).
1333 | 1. Otherwise, let _v_ be 𝔽(? ToIntegerOrInfinity(_value_)).
1334 | 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
1335 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~Unordered~).
1336 | 1. NOTE: Bounds checking is not a synchronizing operation when _typedArray_'s backing buffer is a growable SharedArrayBuffer.
1337 | 1. Let _length_ be IntegerIndexedObjectLength(_typedArray_, _getBufferByteLength_).
1338 | 1. If ~length~ is ~out-of-bounds~, throw a *TypeError* exception.
1339 | 1. If _indexedPosition_ ≥ _length_, throw a *RangeError* exception.
1340 | 1. NOTE: The above checks isare not redundant with the checks in ValidateIntegerTypedArray and ValidateAtomicAccess because the call to ToBigInt or ToIntegerOrInfinity on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached. These checks are only needed when _typedArray_'s backing buffer is an ArrayBuffer.
1341 | 1. Let _elementType_ be TypedArrayElementType(_typedArray_).
1342 | 1. Return GetModifySetValueInBuffer(_buffer_, _indexedPosition_, _elementType_, _v_, _op_).
1343 |
1344 |
1345 |
1346 |
1347 |
1348 | ValidateAtomicAccess (
1349 | _typedArray_: a TypedArray,
1350 | _requestIndex_: an ECMAScript language value,
1351 | ): either a normal completion containing an integer or a throw completion
1352 |
1353 |
1354 |
1355 |
1356 | 1. Let _getBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~Unordered~).
1357 | 1. Let _length_ be _typedArray_.[[ArrayLength]]IntegerIndexedObjectLength(_typedArray_, _getBufferByteLength_).
1358 | 1. Assert: _length_ is not ~out-of-bounds~.
1359 | 1. Let _accessIndex_ be ? ToIndex(_requestIndex_).
1360 | 1. Assert: _accessIndex_ ≥ 0.
1361 | 1. If _accessIndex_ ≥ _length_, throw a *RangeError* exception.
1362 | 1. Let _arrayTypeName_ be _typedArray_.[[TypedArrayName]].
1363 | 1. Let _elementSize_ be the Element Size value specified in for _arrayTypeName_.
1364 | 1. Let _offset_ be _typedArray_.[[ByteOffset]].
1365 | 1. Return (_accessIndex_ × _elementSize_) + _offset_.
1366 |
1367 |
1368 |
1369 |
1370 |
1371 |
1372 |
Resizable ArrayBuffer and growable SharedArrayBuffer Guidelines
1373 |
1374 |
The following are guidelines for ECMAScript programmers working with resizable ArrayBuffer and growable SharedArrayBuffer.
1375 |
We recommend that programs be tested in their deployment environments where possible. The amount of available physical memory differ greatly between hardware devices. Similarly, virtual memory subsystems also differ greatly between hardware devices as well as operating systems. An application that runs without out-of-memory errors on a 64-bit desktop web browser could run out of memory on a 32-bit mobile web browser.
1376 |
When choosing a value for the `"maxByteLength"` option for resizable ArrayBuffer and growable SharedArrayBuffer, we recommend that the smallest possible size for the application be chosen. We recommend that `"maxByteLength"` does not exceed 1073741824, or 1GiB.
1377 |
Please note that successfully constructing a ResizableArrayBuffer or a growable SharedArrayBuffer for a particular maximum size does not guarantee that future resizes and grows will succeed.
1378 |
1379 |
1380 |
1381 |
The following are guidelines for ECMAScript implementers implementing resizable ArrayBuffer.
1382 |
Resizable ArrayBuffer can be implemented as copying upon resize, as in-place growth via reserving virtual memory up front, or as a combination of both for different values of the constructor's `"maxByteLength"` option.
1383 |
If a host is multi-tenanted (i.e. it runs many JavaScript applications simultaneously), such as a web browser, and its implementations choose to implement in-place growth by reserving virtual memory, we recommend that both 32-bit and 64-bit implementations throw for values of `"maxByteLength"` ≥ 1GiB to 1.5GiB. This is to reduce the likelihood a single application can exhaust the virtual memory address space and to reduce interoperability risks.
1384 |
If a host does not have virtual memory, such as those running on embedded devices without an MMU, or if a host only implements resizing by copying, it may accept any Number value for the `"maxByteLength"` option. However, we recommend a *RangeError* be thrown if a memory block of the requested size can never be allocated. For example, if the requested size is greater than the maximium amount of usable memory on the device.
1385 |
1386 |
1387 |
1388 |
The following are guidelines for ECMAScript implementers implementing growable SharedArrayBuffer.
1389 |
We recommend growable SharedArrayBuffer be implemented as in-place growth via reserving virtual memory up front.
1390 |
Because grow operations can be concurrent with memory accesses on a growable SharedArrayBuffer, the constraints of the memory model require that even unordered accesses do not "tear" (bits of their values will not be mixed). In practice, this means the underlying data block of a growable SharedArrayBuffer cannot be grown by being copied without stopping the world. We do not recommend stopping the world as an implementation strategy because it introduces a serialization point and is slow.
1391 |
Grown memory must appear zeroed from the moment of its creation, including to any racy concurrent accesses. This can be accomplished via zero-filled-on-demand virtual memory pages, or careful synchronization if manually zeroing memory.
1392 |
In practice it is difficult to implement growable SharedArrayBuffer by copying on hosts that do not have virtual memory, such as those running on embedded devices without an MMU. Memory usage behaviour of growable SharedArrayBuffers on such hosts may significantly differ from that of hosts with virtual memory. Such hosts should clearly communicate memory usage expectations to users.
1393 |
1394 |
1395 |
1396 |
1397 |
Mechanical Changes Omitted for Brevity
1398 |
1399 |
Uses of [[ArrayLength]] on Integer-Indexed exotic objects are replaced with calls to IntegerIndexedObjectLength.
1400 |
Uses of [[ByteLength]] on Integer-Indexed exotic objects are replaced with calls to IntegerIndexedByteLength.
1401 |
Uses of [[ArrayBufferByteLength]] on buffer objects that may be growable SharedArrayBuffers are replaced with calls to ArrayBufferByteLength.