Skip to content

Commit d6e71e5

Browse files
authored
Add and improve operations on BufferSources
* Introduce algorithms for creating ArrayBuffers and ArrayBufferViews from byte sequences. * Introduce algorithms for writing into ArrayBuffers and ArrayBufferViews, replacing "get a reference to the bytes held by the buffer source". * Introduce "transfer" for an ArrayBuffer. * Introduce "byte length", "underlying buffer", and "detached" for introspecting a BufferSource. * Improve the specification for "get a copy of the bytes held by a buffer source" and "detach".
1 parent 9d43a5d commit d6e71e5

File tree

1 file changed

+176
-71
lines changed

1 file changed

+176
-71
lines changed

index.bs

Lines changed: 176 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
8686
text: Set; url: sec-set-objects
8787
text: SharedArrayBuffer; url: sec-sharedarraybuffer-objects
8888
text: %AsyncIteratorPrototype%; url: sec-asynciteratorprototype
89+
text: %ArrayBuffer%; url: sec-arraybuffer-constructor
8990
text: %Array.prototype%; url: sec-properties-of-the-array-prototype-object
9091
text: %Error.prototype%; url: sec-properties-of-the-error-prototype-object
9192
text: %Function.prototype%; url: sec-properties-of-the-function-prototype-object
@@ -116,6 +117,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
116117
type: argument
117118
text: NewTarget; url: sec-built-in-function-objects
118119
type: abstract-op
120+
text: AllocateArrayBuffer; url: sec-allocatearraybuffer
119121
text: ArrayCreate; url: sec-arraycreate
120122
text: Call; url: sec-call
121123
text: CanonicalNumericIndexString; url: sec-canonicalnumericindexstring
@@ -140,6 +142,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
140142
text: GetFunctionRealm; url: sec-getfunctionrealm
141143
text: GetIterator; url: sec-getiterator
142144
text: GetMethod; url: sec-getmethod
145+
text: GetValueFromBuffer; url: sec-getvaluefrombuffer
143146
text: IfAbruptRejectPromise; url: sec-ifabruptrejectpromise
144147
text: IsArray; url: sec-isarray
145148
text: IsAccessorDescriptor; url: sec-isaccessordescriptor
@@ -155,9 +158,10 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
155158
text: NewModuleEnvironment; url: sec-newmoduleenvironment
156159
text: NewPromiseCapability; url: sec-newpromisecapability
157160
text: NormalCompletion; url: sec-normalcompletion
158-
text: OrdinaryObjectCreate; url: sec-ordinaryobjectcreate
161+
text: OrdinaryCreateFromConstructor; sec: sec-ordinarycreatefromconstructor
159162
text: OrdinaryDefineOwnProperty; url: sec-ordinarydefineownproperty
160163
text: OrdinaryGetOwnProperty; url: sec-ordinarygetownproperty
164+
text: OrdinaryObjectCreate; url: sec-ordinaryobjectcreate
161165
text: OrdinaryPreventExtensions; url: sec-ordinarypreventextensions
162166
text: OrdinarySetWithOwnDescriptor; url: sec-ordinarysetwithowndescriptor
163167
text: PerformPromiseThen; url: sec-performpromisethen
@@ -167,6 +171,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
167171
text: SetFunctionName; url: sec-setfunctionname
168172
text: SetImmutablePrototype; url: sec-set-immutable-prototype
169173
text: SetIntegrityLevel; url: sec-setintegritylevel
174+
text: SetValueInBuffer; url: sec-setvalueinbuffer
170175
text: ToBigInt; url: #sec-tobigint
171176
text: ToBoolean; url: sec-toboolean
172177
text: ToInt32; url: sec-toint32
@@ -237,6 +242,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
237242
text: realm; url: realm
238243
text: ResolvedBinding Record; url: resolvedbinding-record
239244
text: running execution context; url: running-execution-context
245+
text: element size; url: table-the-typedarray-constructors
240246
</pre>
241247

242248
<style>
@@ -6774,51 +6780,9 @@ There is no way to represent a constant value of any of these types in IDL.
67746780
The [=type name=] of all
67756781
of these types is the name of the type itself.
67766782

6777-
At the specification prose level, IDL [=buffer source types=]
6778-
are simply references to objects. To inspect or manipulate the bytes inside the buffer,
6779-
specification prose must first either
6780-
<dfn id="dfn-get-buffer-source-reference" export lt="get a reference to the buffer source">get a reference to the bytes held by the buffer source</dfn>
6781-
or <dfn id="dfn-get-buffer-source-copy" export lt="get a copy of the buffer source">get a copy of the bytes held by the buffer source</dfn>.
6782-
With a reference to the buffer source’s bytes, specification prose can get or set individual
6783-
byte values using that reference.
6784-
6785-
<div class="advisement">
6786-
6787-
Extreme care must be taken when writing specification text that gets a reference
6788-
to the bytes held by a buffer source, as the underlying data can easily be changed
6789-
by the script author or other APIs at unpredictable times. If you are using a buffer source type
6790-
as an operation argument to obtain a chunk of binary data that will not be modified,
6791-
it is strongly recommended to get a copy of the buffer source’s bytes at the beginning
6792-
of the prose defining the operation.
6793-
6794-
Requiring prose to explicitly get a reference to or copy of the bytes is intended to
6795-
help specification reviewers look for problematic uses of these buffer source types.
6796-
6797-
</div>
6798-
6799-
<div class="note">
6800-
6801-
When designing APIs that take a buffer, it is recommended to use the
6802-
{{BufferSource}} typedef rather than {{ArrayBuffer}}
6803-
or any of the view types.
6804-
6805-
When designing APIs that create and return a buffer, it is recommended
6806-
to use the {{ArrayBuffer}} type rather than
6807-
{{Uint8Array}}.
6808-
6809-
</div>
6810-
6811-
Attempting to [=get a reference to the buffer source|get a reference to=] or
6812-
[=get a copy of the buffer source|get a copy of the bytes held by a buffer source=]
6813-
when the {{ArrayBuffer}} has been [=ArrayBuffer/detached=]
6814-
will fail in a language binding-specific manner.
6815-
6816-
Note: See [[#es-buffer-source-types]] below for
6817-
how interacting with buffer source types works in the ECMAScript language binding.
6818-
6819-
<p class="issue">
6820-
We should include an example of specification text that uses these types and terms.
6821-
</p>
6783+
At the specification prose level, IDL [=buffer source types=] are simply references to objects. To
6784+
inspect or manipulate the bytes inside the buffer, specification prose needs to use the algorithms
6785+
in [[#es-buffer-source-types]].
68226786

68236787
<pre class="grammar" id="prod-BufferRelatedType">
68246788
BufferRelatedType :
@@ -8994,37 +8958,178 @@ an IDL value of any [=buffer source type=]
89948958
to an ECMAScript value is the Object value that represents
89958959
a reference to the same object that the IDL value represents.
89968960

8997-
<div algorithm="get a reference to a buffer source">
8998-
8999-
When [=get a reference to the buffer source|getting a reference to=]
9000-
or [=get a copy of the buffer source|getting a copy of the bytes held by a buffer source=]
9001-
that is an ECMAScript {{ECMAScript/ArrayBuffer}}, {{ECMAScript/DataView}}
9002-
or typed array object, these steps must be followed:
9003-
9004-
1. Let |O| be the ECMAScript object that is the buffer source.
9005-
1. Initialize |arrayBuffer| to |O|.
9006-
1. Initialize |offset| to 0.
9007-
1. Initialize |length| to 0.
9008-
1. If |O| has a \[[ViewedArrayBuffer]] [=internal slot=], then:
9009-
1. Set |arrayBuffer| to the value of |O|’s \[[ViewedArrayBuffer]] [=internal slot=].
9010-
1. Set |offset| to the value of |O|’s \[[ByteOffset]] [=internal slot=].
9011-
1. Set |length| to the value of |O|’s \[[ByteLength]] [=internal slot=].
9012-
1. Otherwise, set |length| to the value of |O|’s \[[ArrayBufferByteLength]] [=internal slot=].
9013-
1. If <a abstract-op>IsDetachedBuffer</a>(|arrayBuffer|) is <emu-val>true</emu-val>, then
9014-
return the empty byte sequence.
9015-
1. Let |data| be the value of |O|’s \[[ArrayBufferData]] [=internal slot=].
9016-
1. Return a reference to or copy of (as required) the |length| bytes in |data|
9017-
starting at byte offset |offset|.
8961+
<hr>
8962+
8963+
<div algorithm>
8964+
To <dfn export for="ArrayBuffer">create</dfn> an {{ArrayBuffer}} from a [=byte sequence=]
8965+
|bytes| in a [=Realm=] |realm|:
8966+
8967+
1. Let |esArrayBuffer| be [=?=]
8968+
[$AllocateArrayBuffer$](|realm|.\[[Intrinsics]].[[{{%ArrayBuffer%}}]], |bytes|'s
8969+
[=byte sequence/length=]).
8970+
1. Let |arrayBuffer| be the result of [=converted to an IDL value|converting=] |esArrayBuffer|
8971+
to an IDL value of type {{ArrayBuffer}}.
8972+
1. [=ArrayBuffer/Write=] |bytes| into |arrayBuffer|.
8973+
1. Return |arrayBuffer|.
8974+
</div>
8975+
8976+
<div algorithm>
8977+
To <dfn export for="ArrayBufferView">create</dfn> one of the {{ArrayBufferView}} types from a
8978+
[=byte sequence=] |bytes| in a [=Realm=] |realm|:
8979+
8980+
1. Assert: if the type is not {{DataView}}, then |bytes|'s [=byte sequence/length=] [=modulo=]
8981+
the [=element size=] of that type is 0.
8982+
1. Let |arrayBuffer| be the result of [=ArrayBuffer/creating=] an {{ArrayBuffer}} from |bytes|
8983+
in |realm|.
8984+
1. Let |esArrayBuffer| be the result of [=converted to an ECMAScript value|converting=]
8985+
|arrayBuffer| to an ECMAScript value.
8986+
1. Let |constructor| be the appropriate constructor from |realm|.\[[Intrinsics]] for the type
8987+
of {{ArrayBufferView}} being created.
8988+
1. Let |esView| be [=!=] [$Construct$](|constructor|, « |esArrayBuffer| »).
8989+
1. Return the result of [=converted to an IDL value|converting=] |esView| into the given type.
8990+
</div>
8991+
8992+
<div algorithm>
8993+
To <dfn id="dfn-get-buffer-source-copy" export lt="get a copy of the buffer source|get a copy of the bytes held by the buffer source">get a copy of the bytes held by the buffer source</dfn>
8994+
given a {{BufferSource}} |bufferSource|:
8995+
8996+
1. Let |esBufferSource| be be the result of [=converted to an ECMAScript value|converting=]
8997+
|bufferSource| to an ECMAScript value.
8998+
1. Let |esArrayBuffer| be |esBufferSource|.
8999+
1. Let |offset| be 0.
9000+
1. Let |length| be 0.
9001+
1. If |esBufferSource| has a \[[ViewedArrayBuffer]] [=internal slot=], then:
9002+
1. Set |esArrayBuffer| to |esBufferSource|.\[[ViewedArrayBuffer]].
9003+
1. Set |offset| to |esBufferSource|.\[[ByteOffset]].
9004+
1. Set |length| to |esBufferSource|.\[[ByteLength]].
9005+
1. Otherwise:
9006+
1. Assert: |esBufferSource| is an {{ECMAScript/ArrayBuffer}} or
9007+
{{ECMAScript/SharedArrayBuffer}} object.
9008+
1. Set |length| to |esBufferSource|.\[[ArrayBufferByteLength]].
9009+
1. If [=!=] [$IsDetachedBuffer$](|esArrayBuffer|) is true, then return the empty
9010+
[=byte sequence=].
9011+
1. Let |bytes| be a new [=byte sequence=] of [=byte sequence/length=] equal to |length|.
9012+
1. For |i| in [=the range=] |offset| to |offset| + |length| &minus; 1, inclusive, set
9013+
|bytes|[|i| &minus; |offset|] to [=!=] [$GetValueFromBuffer$](|esArrayBuffer|, |i|, Uint8,
9014+
true, Unordered).
9015+
1. Return |bytes|.
90189016
</div>
90199017

90209018
<div algorithm>
9019+
The <dfn export for="BufferSource">byte length</dfn> of a {{BufferSource}} |bufferSource| is
9020+
the value returned by the following steps:
90219021

9022-
To <dfn id="dfn-detach" for="ArrayBuffer" export>detach</dfn> an {{ArrayBuffer}}, these steps must be followed:
9022+
1. Let |esBufferSource| be be the result of [=converted to an ECMAScript value|converting=]
9023+
|bufferSource| to an ECMAScript value.
9024+
1. If |esBufferSource| has a \[[ViewedArrayBuffer]] internal slot, then return
9025+
|esBufferSource|.\[[ByteLength]].
9026+
1. Return |esBufferSource|.\[[ArrayBufferByteLength]].
9027+
</div>
9028+
9029+
<div algorithm>
9030+
The <dfn export for="BufferSource">underlying buffer</dfn> of a {{BufferSource}} |bufferSource|
9031+
is the value returned by the following steps:
9032+
9033+
1. If |bufferSource| is an {{ArrayBuffer}}, return |bufferSource|.
9034+
1. Let |esBufferSource| be be the result of [=converted to an ECMAScript value|converting=]
9035+
|bufferSource| to an ECMAScript value.
9036+
1. Return the result of [=converted to an IDL value|converting=]
9037+
|esBufferSource|.\[[ViewedArrayBuffer]] to an IDL value of type {{ArrayBuffer}}.
9038+
</div>
9039+
9040+
<div algorithm="ArrayBuffer/write">
9041+
To <dfn export for="ArrayBuffer">write</dfn> a [=byte sequence=] |bytes| into an {{ArrayBuffer}}
9042+
|arrayBuffer|, optionally given a <dfn export for="ArrayBuffer/write">|startingOffset|</dfn>
9043+
(default 0):
9044+
9045+
1. Let |esArrayBuffer| be be the result of [=converted to an ECMAScript value|converting=]
9046+
|arrayBuffer| to an ECMAScript value.
9047+
1. Assert: |bytes|'s [=byte sequence/length=] ≤ |esArrayBuffer|.\[[ArrayBufferByteLength]]
9048+
&minus; |startingOffset|.
9049+
1. For |i| in [=the range=] |startingOffset| to |startingOffset| + |bytes|'s [=byte
9050+
sequence/length=] &minus; 1, inclusive, perform [=!=] [$SetValueInBuffer$](|esArrayBuffer|,
9051+
|i|, Uint8, |bytes|[|i| - |startingOffset|], true, Unordered).
9052+
</div>
9053+
9054+
<div algorithm="ArrayBufferView/write">
9055+
To <dfn export for="ArrayBufferView">write</dfn> a [=byte sequence=] |bytes| into an
9056+
{{ArrayBufferView}} |view|, optionally given a
9057+
<dfn export for="ArrayBufferView/write">|startingOffset|</dfn> (default 0):
9058+
9059+
1. Let |esView| be be the result of [=converted to an ECMAScript value|converting=] |view| to
9060+
an ECMAScript value.
9061+
1. Assert: |bytes|'s [=byte sequence/length=] ≤ |esView|.\[[ByteLength]] &minus;
9062+
|startingOffset|.
9063+
1. Assert: if |view| is not a {{DataView}}, then |bytes|'s [=byte sequence/length=] [=modulo=]
9064+
the [=element size=] of |view|'s type is 0.
9065+
1. Let |arrayBuffer| be the result of [=converted to an IDL value|converting=]
9066+
|esView|.\[[ViewedArrayBuffer]] to an IDL value of type {{ArrayBuffer}}.
9067+
1. [=ArrayBuffer/Write=] |bytes| into |arrayBuffer| with
9068+
<i>[=ArrayBuffer/write/startingOffset=]</i> set to |esView|.\[[ByteOffset]] +
9069+
|startingOffset|.
9070+
</div>
9071+
9072+
<div class="advisement">
9073+
Extreme care must be taken when writing specification text that
9074+
[=ArrayBuffer/writes=] into an {{ArrayBuffer}} or {{ArrayBufferView}}, as the underlying data
9075+
can easily be changed by the script author or other APIs at unpredictable times. This is
9076+
especially true if the [{{AllowShared}}] [=extended attribute=] is involved.
90239077

9024-
1. Let |O| be the ECMAScript object that is the {{ArrayBuffer}}.
9025-
1. Perform [=!=] <a abstract-op>DetachArrayBuffer</a>(|O|).
9078+
For the non-shared cases, a more recommended pattern is to [=ArrayBuffer/transfer=] the
9079+
{{ArrayBuffer}} first if possible, to ensure the writes cannot overlap with other modifications,
9080+
and then give the new {{ArrayBuffer}} instance to author code as necessary. Alternately, you can
9081+
[=get a copy of the bytes held by the buffer source=], modify those bytes, and then use them to
9082+
[=ArrayBuffer/create=] a new {{ArrayBuffer}} or {{ArrayBufferView}} to give back to author code.
90269083
</div>
90279084

9085+
<div algorithm>
9086+
To <dfn id="dfn-detach" for="ArrayBuffer" export>detach</dfn> an {{ArrayBuffer}} |arrayBuffer|:
9087+
9088+
1. Let |esArrayBuffer| be be the result of [=converted to an ECMAScript value|converting=]
9089+
|arrayBuffer| to an ECMAScript value.
9090+
1. Assert: [=!=] [$IsSharedArrayBuffer$](|esArrayBuffer|) is false.
9091+
1. Perform [=?=] [$DetachArrayBuffer$](|esArrayBuffer|).
9092+
9093+
<p class="note">This will throw an exception if |esArrayBuffer| has an \[[ArrayBufferDetachKey]]
9094+
that is not undefined, such as is the case with the value of {{Memory|WebAssembly.Memory}}'s
9095+
{{Memory/buffer}} attribute. [[WASM-JS-API-1]]
9096+
9097+
<p class="note">Detaching a buffer that is already [=BufferSource/detached=] is a no-op.
9098+
</div>
9099+
9100+
<div algorithm>
9101+
A {{BufferSource}} |bufferSource| is <dfn for="BufferSource" export>detached</dfn> if the
9102+
following steps return true:
9103+
9104+
1. Let |esArrayBuffer| be be the result of [=converted to an ECMAScript value|converting=]
9105+
|bufferSource| to an ECMAScript value.
9106+
1. If |esArrayBuffer| has a \[[ViewedArrayBuffer]] internal slot, then set |esArrayBuffer| to
9107+
|esArrayBuffer|.\[[ViewedArrayBuffer]].
9108+
1. Return [=!=] [$IsDetachedBuffer$](|esArrayBuffer|).
9109+
</div>
9110+
9111+
<div algorithm>
9112+
To <dfn for="ArrayBuffer" export>transfer</dfn> an {{ArrayBuffer}} |arrayBuffer|, optionally
9113+
given a [=Realm=] |targetRealm|:
9114+
9115+
1. Let |esArrayBuffer| be be the result of [=converted to an ECMAScript value|converting=]
9116+
|arrayBuffer| to an ECMAScript value.
9117+
1. Assert: [=!=] [$IsSharedArrayBuffer$](|esArrayBuffer|) is false.
9118+
1. Assert: [=!=] [$IsDetachedBuffer$](|esArrayBuffer|) is false.
9119+
1. Let |arrayBufferData| be |esArrayBuffer|.\[[ArrayBufferData]].
9120+
1. Let |arrayBufferByteLength| be |esArrayBuffer|.\[[ArrayBufferByteLength]].
9121+
1. Perform [=?=] [$DetachArrayBuffer$](|esArrayBuffer|).
9122+
1. If |targetRealm| is not given, let |targetRealm| be the [=current Realm=].
9123+
1. Let |esTransferred| be [=!=]
9124+
[$AllocateArrayBuffer$](|targetRealm|.\[[Intrinsics]].[[{{%ArrayBuffer%}}]], 0).
9125+
1. Set |esTransferred|.\[[ArrayBufferData]] to |arrayBufferData|.
9126+
1. Set |esTransferred|.\[[ArrayBufferByteLength]] to |arrayBufferByteLength|.
9127+
1. Return the result of [=converted to an IDL value|converting=] |esTransferred| to an IDL
9128+
value of type {{ArrayBuffer}}.
9129+
9130+
<p class="note">This will throw an exception under the same circumstances as
9131+
[=ArrayBuffer/detaching=].
9132+
</div>
90289133

90299134
<h4 id="es-frozen-array">Frozen arrays — FrozenArray&lt;|T|&gt;</h4>
90309135

@@ -14285,7 +14390,7 @@ A {{DOMException}} is represented by a
1428514390

1428614391
<div algorithm="to create a simple exception or DOMException">
1428714392

14288-
To [=create=] a [=simple exception=] or {{DOMException}} |E|, with a string giving the
14393+
To create a [=simple exception=] or {{DOMException}} |E|, with a string giving the
1428914394
[=error name=] |N| for the {{DOMException}} case and optionally a string giving a user
1429014395
agent-defined message |M|:
1429114396

0 commit comments

Comments
 (0)