Skip to content

Commit 82ac89b

Browse files
sygh2oche
authored andcommitted
Normative: Allow Atomics methods to work on ArrayBuffers (tc39#1908)
Allow Atomics methods to work on ArrayBuffers in a fully deterministic fashion. Atomics.wait still throws when used on ArrayBuffers, while Atomics.notify always returns 0.
1 parent 0e6f6e7 commit 82ac89b

File tree

1 file changed

+36
-24
lines changed

1 file changed

+36
-24
lines changed

spec.html

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37437,7 +37437,7 @@ <h1>GetValueFromBuffer ( _arrayBuffer_, _byteIndex_, _type_, _isTypedArray_, _or
3743737437
1. Let _readEvent_ be ReadSharedMemory { [[Order]]: _order_, [[NoTear]]: _noTear_, [[Block]]: _block_, [[ByteIndex]]: _byteIndex_, [[ElementSize]]: _elementSize_ }.
3743837438
1. Append _readEvent_ to _eventList_.
3743937439
1. Append Chosen Value Record { [[Event]]: _readEvent_, [[ChosenValue]]: _rawValue_ } to _execution_.[[ChosenValues]].
37440-
1. Else, let _rawValue_ be a List of _elementSize_ containing, in order, the _elementSize_ sequence of bytes starting with _block_[_byteIndex_].
37440+
1. Else, let _rawValue_ be a List of size _elementSize_ containing the sequence of _elementSize_ bytes starting with _block_[_byteIndex_].
3744137441
1. If _isLittleEndian_ is not present, set _isLittleEndian_ to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
3744237442
1. Return RawBytesToNumeric(_type_, _rawValue_, _isLittleEndian_).
3744337443
</emu-alg>
@@ -37487,23 +37487,28 @@ <h1>SetValueInBuffer ( _arrayBuffer_, _byteIndex_, _type_, _value_, _isTypedArra
3748737487

3748837488
<emu-clause id="sec-getmodifysetvalueinbuffer" aoid="GetModifySetValueInBuffer">
3748937489
<h1>GetModifySetValueInBuffer ( _arrayBuffer_, _byteIndex_, _type_, _value_, _op_ [ , _isLittleEndian_ ] )</h1>
37490-
<p>The abstract operation GetModifySetValueInBuffer takes arguments _arrayBuffer_ (a SharedArrayBuffer object), _byteIndex_ (a non-negative integer), _type_ (a TypedArray element type), _value_ (a Number or a BigInt), and _op_ (a read-modify-write modification function) and optional argument _isLittleEndian_ (a Boolean). It performs the following steps when called:</p>
37490+
<p>The abstract operation GetModifySetValueInBuffer takes arguments _arrayBuffer_ (an ArrayBuffer object or a SharedArrayBuffer object), _byteIndex_ (a non-negative integer), _type_ (a TypedArray element type), _value_ (a Number or a BigInt), and _op_ (a read-modify-write modification function) and optional argument _isLittleEndian_ (a Boolean). It performs the following steps when called:</p>
3749137491
<emu-alg>
37492-
1. Assert: IsSharedArrayBuffer(_arrayBuffer_) is *true*.
37492+
1. Assert: IsDetachedBuffer(_arrayBuffer_) is *false*.
3749337493
1. Assert: There are sufficient bytes in _arrayBuffer_ starting at _byteIndex_ to represent a value of _type_.
3749437494
1. Assert: ! IsNonNegativeInteger(_byteIndex_) is *true*.
3749537495
1. Assert: Type(_value_) is BigInt if ! IsBigIntElementType(_type_) is *true*; otherwise, Type(_value_) is Number.
3749637496
1. Let _block_ be _arrayBuffer_.[[ArrayBufferData]].
3749737497
1. Let _elementSize_ be the Element Size value specified in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for Element Type _type_.
3749837498
1. If _isLittleEndian_ is not present, set _isLittleEndian_ to the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
3749937499
1. Let _rawBytes_ be NumericToRawBytes(_type_, _value_, _isLittleEndian_).
37500-
1. Let _execution_ be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
37501-
1. Let _eventList_ be the [[EventList]] field of the element in _execution_.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
37502-
1. Let _rawBytesRead_ be a List of length _elementSize_ of nondeterministically chosen byte values.
37503-
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.
37504-
1. Let _rmwEvent_ be ReadModifyWriteSharedMemory { [[Order]]: ~SeqCst~, [[NoTear]]: *true*, [[Block]]: _block_, [[ByteIndex]]: _byteIndex_, [[ElementSize]]: _elementSize_, [[Payload]]: _rawBytes_, [[ModifyOp]]: _op_ }.
37505-
1. Append _rmwEvent_ to _eventList_.
37506-
1. Append Chosen Value Record { [[Event]]: _rmwEvent_, [[ChosenValue]]: _rawBytesRead_ } to _execution_.[[ChosenValues]].
37500+
1. If IsSharedArrayBuffer(_arrayBuffer_) is *true*, then
37501+
1. Let _execution_ be the [[CandidateExecution]] field of the surrounding agent's Agent Record.
37502+
1. Let _eventList_ be the [[EventList]] field of the element in _execution_.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
37503+
1. Let _rawBytesRead_ be a List of length _elementSize_ of nondeterministically chosen byte values.
37504+
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.
37505+
1. Let _rmwEvent_ be ReadModifyWriteSharedMemory { [[Order]]: ~SeqCst~, [[NoTear]]: *true*, [[Block]]: _block_, [[ByteIndex]]: _byteIndex_, [[ElementSize]]: _elementSize_, [[Payload]]: _rawBytes_, [[ModifyOp]]: _op_ }.
37506+
1. Append _rmwEvent_ to _eventList_.
37507+
1. Append Chosen Value Record { [[Event]]: _rmwEvent_, [[ChosenValue]]: _rawBytesRead_ } to _execution_.[[ChosenValues]].
37508+
1. Else,
37509+
1. Let _rawBytesRead_ be a List of size _elementSize_ containing the sequence of _elementSize_ bytes starting with _block_[_byteIndex_].
37510+
1. Let _rawBytesModified_ be _op_(_rawBytesRead_, _rawBytes_).
37511+
1. Store the individual bytes of _rawBytesModified_ into _block_, in order, starting at _block_[_byteIndex_].
3750737512
1. Return RawBytesToNumeric(_type_, _rawBytesRead_, _isLittleEndian_).
3750837513
</emu-alg>
3750937514
</emu-clause>
@@ -38176,21 +38181,18 @@ <h1>The Atomics Object</h1>
3817638181
<emu-clause id="sec-abstract-operations-for-atomics">
3817738182
<h1>Abstract Operations for Atomics</h1>
3817838183

38179-
<emu-clause id="sec-validatesharedintegertypedarray" aoid="ValidateSharedIntegerTypedArray">
38180-
<h1>ValidateSharedIntegerTypedArray ( _typedArray_ [ , _waitable_ ] )</h1>
38181-
<p>The abstract operation ValidateSharedIntegerTypedArray takes argument _typedArray_ and optional argument _waitable_ (a Boolean). It performs the following steps when called:</p>
38184+
<emu-clause id="sec-validateintegertypedarray" aoid="ValidateIntegerTypedArray" oldid="sec-validatesharedintegertypedarray">
38185+
<h1>ValidateIntegerTypedArray ( _typedArray_ [ , _waitable_ ] )</h1>
38186+
<p>The abstract operation ValidateIntegerTypedArray takes argument _typedArray_ and optional argument _waitable_ (a Boolean). It performs the following steps when called:</p>
3818238187
<emu-alg>
3818338188
1. If _waitable_ is not present, set _waitable_ to *false*.
38184-
1. Perform ? RequireInternalSlot(_typedArray_, [[TypedArrayName]]).
38189+
1. Let _buffer_ be ? ValidateTypedArray(_typedArray_).
3818538190
1. Let _typeName_ be _typedArray_.[[TypedArrayName]].
3818638191
1. Let _type_ be the Element Type value in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for _typeName_.
3818738192
1. If _waitable_ is *true*, then
3818838193
1. If _typeName_ is not *"Int32Array"* or *"BigInt64Array"*, throw a *TypeError* exception.
3818938194
1. Else,
3819038195
1. If ! IsUnclampedIntegerElementType(_type_) is *false* and ! IsBigIntElementType(_type_) is *false*, throw a *TypeError* exception.
38191-
1. Assert: _typedArray_ has a [[ViewedArrayBuffer]] internal slot.
38192-
1. Let _buffer_ be _typedArray_.[[ViewedArrayBuffer]].
38193-
1. If IsSharedArrayBuffer(_buffer_) is *false*, throw a *TypeError* exception.
3819438196
1. Return _buffer_.
3819538197
</emu-alg>
3819638198
</emu-clause>
@@ -38200,8 +38202,8 @@ <h1>ValidateAtomicAccess ( _typedArray_, _requestIndex_ )</h1>
3820038202
<p>The abstract operation ValidateAtomicAccess takes arguments _typedArray_ and _requestIndex_. It performs the following steps when called:</p>
3820138203
<emu-alg>
3820238204
1. Assert: _typedArray_ is an Object that has a [[ViewedArrayBuffer]] internal slot.
38203-
1. Let _accessIndex_ be ? ToIndex(_requestIndex_).
3820438205
1. Let _length_ be _typedArray_.[[ArrayLength]].
38206+
1. Let _accessIndex_ be ? ToIndex(_requestIndex_).
3820538207
1. Assert: _accessIndex_ &ge; 0.
3820638208
1. If _accessIndex_ &ge; _length_, throw a *RangeError* exception.
3820738209
1. Return _accessIndex_.
@@ -38324,11 +38326,13 @@ <h1>NotifyWaiter ( _WL_, _W_ )</h1>
3832438326
<h1>AtomicReadModifyWrite ( _typedArray_, _index_, _value_, _op_ )</h1>
3832538327
<p>The abstract operation AtomicReadModifyWrite takes arguments _typedArray_, _index_, _value_, and _op_ (a read-modify-write modification function). _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. It performs the following steps when called:</p>
3832638328
<emu-alg>
38327-
1. Let _buffer_ be ? ValidateSharedIntegerTypedArray(_typedArray_).
38329+
1. Let _buffer_ be ? ValidateIntegerTypedArray(_typedArray_).
3832838330
1. Let _i_ be ? ValidateAtomicAccess(_typedArray_, _index_).
3832938331
1. Let _arrayTypeName_ be _typedArray_.[[TypedArrayName]].
3833038332
1. If _typedArray_.[[ContentType]] is ~BigInt~, let _v_ be ? ToBigInt(_value_).
3833138333
1. Otherwise, let _v_ be ? ToInteger(_value_).
38334+
1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
38335+
1. NOTE: The above check is not redundant with the check in ValidateIntegerTypedArray because the call to ToBigInt or ToInteger on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached.
3833238336
1. Let _elementSize_ be the Element Size value specified in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for _arrayTypeName_.
3833338337
1. Let _elementType_ be the Element Type value in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for _arrayTypeName_.
3833438338
1. Let _offset_ be _typedArray_.[[ByteOffset]].
@@ -38341,8 +38345,10 @@ <h1>AtomicReadModifyWrite ( _typedArray_, _index_, _value_, _op_ )</h1>
3834138345
<h1>AtomicLoad ( _typedArray_, _index_ )</h1>
3834238346
<p>The abstract operation AtomicLoad takes arguments _typedArray_ and _index_. It atomically loads a value and returns the loaded value. It performs the following steps when called:</p>
3834338347
<emu-alg>
38344-
1. Let _buffer_ be ? ValidateSharedIntegerTypedArray(_typedArray_).
38348+
1. Let _buffer_ be ? ValidateIntegerTypedArray(_typedArray_).
3834538349
1. Let _i_ be ? ValidateAtomicAccess(_typedArray_, _index_).
38350+
1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
38351+
1. NOTE: The above check is not redundant with the check in ValidateIntegerTypedArray because the call to ValidateAtomicAccess on the preceding line can have arbitrary side effects, which could cause the buffer to become detached.
3834638352
1. Let _arrayTypeName_ be _typedArray_.[[TypedArrayName]].
3834738353
1. Let _elementSize_ be the Element Size value specified in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for _arrayTypeName_.
3834838354
1. Let _elementType_ be the Element Type value in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for _arrayTypeName_.
@@ -38418,7 +38424,7 @@ <h1>Atomics.and ( _typedArray_, _index_, _value_ )</h1>
3841838424
<h1>Atomics.compareExchange ( _typedArray_, _index_, _expectedValue_, _replacementValue_ )</h1>
3841938425
<p>The following steps are taken:</p>
3842038426
<emu-alg>
38421-
1. Let _buffer_ be ? ValidateSharedIntegerTypedArray(_typedArray_).
38427+
1. Let _buffer_ be ? ValidateIntegerTypedArray(_typedArray_).
3842238428
1. Let _i_ be ? ValidateAtomicAccess(_typedArray_, _index_).
3842338429
1. Let _arrayTypeName_ be _typedArray_.[[TypedArrayName]].
3842438430
1. If _typedArray_.[[ContentType]] is ~BigInt~, then
@@ -38427,6 +38433,8 @@ <h1>Atomics.compareExchange ( _typedArray_, _index_, _expectedValue_, _replaceme
3842738433
1. Else,
3842838434
1. Let _expected_ be ? ToInteger(_expectedValue_).
3842938435
1. Let _replacement_ be ? ToInteger(_replacementValue_).
38436+
1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
38437+
1. NOTE: The above check is not redundant with the check in ValidateIntegerTypedArray because the call to ToBigInt or ToInteger on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached.
3843038438
1. Let _elementType_ be the Element Type value in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for _arrayTypeName_.
3843138439
1. Let _isLittleEndian_ be the value of the [[LittleEndian]] field of the surrounding agent's Agent Record.
3843238440
1. Let _expectedBytes_ be NumericToRawBytes(_elementType_, _expected_, _isLittleEndian_).
@@ -38490,11 +38498,13 @@ <h1>Atomics.or ( _typedArray_, _index_, _value_ )</h1>
3849038498
<h1>Atomics.store ( _typedArray_, _index_, _value_ )</h1>
3849138499
<p>The following steps are taken:</p>
3849238500
<emu-alg>
38493-
1. Let _buffer_ be ? ValidateSharedIntegerTypedArray(_typedArray_).
38501+
1. Let _buffer_ be ? ValidateIntegerTypedArray(_typedArray_).
3849438502
1. Let _i_ be ? ValidateAtomicAccess(_typedArray_, _index_).
3849538503
1. Let _arrayTypeName_ be _typedArray_.[[TypedArrayName]].
3849638504
1. If _arrayTypeName_ is *"BigUint64Array"* or *"BigInt64Array"*, let _v_ be ? ToBigInt(_value_).
3849738505
1. Otherwise, let _v_ be ? ToInteger(_value_).
38506+
1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception.
38507+
1. NOTE: The above check is not redundant with the check in ValidateIntegerTypedArray because the call to ToBigInt or ToInteger on the preceding lines can have arbitrary side effects, which could cause the buffer to become detached.
3849838508
1. Let _elementSize_ be the Element Size value specified in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for _arrayTypeName_.
3849938509
1. Let _elementType_ be the Element Type value in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for _arrayTypeName_.
3850038510
1. Let _offset_ be _typedArray_.[[ByteOffset]].
@@ -38526,7 +38536,8 @@ <h1>Atomics.sub ( _typedArray_, _index_, _value_ )</h1>
3852638536
<h1>Atomics.wait ( _typedArray_, _index_, _value_, _timeout_ )</h1>
3852738537
<p>`Atomics.wait` puts the calling agent in a wait queue and puts it to sleep until it is notified or the sleep times out. The following steps are taken:</p>
3852838538
<emu-alg>
38529-
1. Let _buffer_ be ? ValidateSharedIntegerTypedArray(_typedArray_, *true*).
38539+
1. Let _buffer_ be ? ValidateIntegerTypedArray(_typedArray_, *true*).
38540+
1. If IsSharedArrayBuffer(_buffer_) is *false*, throw a *TypeError* exception.
3853038541
1. Let _i_ be ? ValidateAtomicAccess(_typedArray_, _index_).
3853138542
1. Let _arrayTypeName_ be _typedArray_.[[TypedArrayName]].
3853238543
1. If _arrayTypeName_ is *"BigInt64Array"*, let _v_ be ? ToBigInt64(_value_).
@@ -38562,7 +38573,7 @@ <h1>Atomics.wait ( _typedArray_, _index_, _value_, _timeout_ )</h1>
3856238573
<h1>Atomics.notify ( _typedArray_, _index_, _count_ )</h1>
3856338574
<p>`Atomics.notify` notifies some agents that are sleeping in the wait queue. The following steps are taken:</p>
3856438575
<emu-alg>
38565-
1. Let _buffer_ be ? ValidateSharedIntegerTypedArray(_typedArray_, *true*).
38576+
1. Let _buffer_ be ? ValidateIntegerTypedArray(_typedArray_, *true*).
3856638577
1. Let _i_ be ? ValidateAtomicAccess(_typedArray_, _index_).
3856738578
1. If _count_ is *undefined*, let _c_ be *+&infin;*.
3856838579
1. Else,
@@ -38573,6 +38584,7 @@ <h1>Atomics.notify ( _typedArray_, _index_, _count_ )</h1>
3857338584
1. Let _arrayTypeName_ be _typedArray_.[[TypedArrayName]].
3857438585
1. Let _elementSize_ be the Element Size value specified in <emu-xref href="#table-the-typedarray-constructors"></emu-xref> for _arrayTypeName_.
3857538586
1. Let _indexedPosition_ be (_i_ &times; _elementSize_) + _offset_.
38587+
1. If IsSharedArrayBuffer(_buffer_) is *false*, return 0.
3857638588
1. Let _WL_ be GetWaiterList(_block_, _indexedPosition_).
3857738589
1. Let _n_ be 0.
3857838590
1. Perform EnterCriticalSection(_WL_).

0 commit comments

Comments
 (0)