From c11ed1c18203f2172ee790780139774dcb2645b7 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Fri, 9 Apr 2021 23:39:08 +0200 Subject: [PATCH 01/44] Throw when trying to enqueue/close after the BYOB request has been detached --- index.bs | 8 ++++++++ .../lib/ReadableByteStreamController-impl.js | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/index.bs b/index.bs index 6ce66e637..e9b1bdb23 100644 --- a/index.bs +++ b/index.bs @@ -1805,6 +1805,10 @@ has the following [=struct/items=]: exception. 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=].[=ReadableStream/[[state]]=] is not "`readable`", throw a {{TypeError}} exception. + 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], + 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. + 1. If [$IsDetachedBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is true, + throw a {{TypeError}} exception. 1. Perform ? [$ReadableByteStreamControllerClose$]([=this=]). @@ -1819,6 +1823,10 @@ for="ReadableByteStreamController">enqueue(|chunk|) method steps are: exception. 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=].[=ReadableStream/[[state]]=] is not "`readable`", throw a {{TypeError}} exception. + 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], + 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. + 1. If [$IsDetachedBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is true, + throw a {{TypeError}} exception. 1. Return ! [$ReadableByteStreamControllerEnqueue$]([=this=], |chunk|). diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index a560dd136..3c6e53594 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -3,6 +3,7 @@ const assert = require('assert'); const { CancelSteps, PullSteps } = require('./abstract-ops/internal-methods.js'); const { ResetQueue } = require('./abstract-ops/queue-with-sizes.js'); +const { IsDetachedBuffer } = require('./abstract-ops/ecmascript.js'); const aos = require('./abstract-ops/readable-streams.js'); const ReadableStreamBYOBRequest = require('../generated/ReadableStreamBYOBRequest.js'); @@ -38,6 +39,13 @@ exports.implementation = class ReadableByteStreamControllerImpl { throw new TypeError(`The stream (in ${state} state) is not in the readable state and cannot be closed`); } + if (this._pendingPullIntos.length > 0) { + const firstDescriptor = this._pendingPullIntos[0]; + if (IsDetachedBuffer(firstDescriptor.buffer) === true) { + throw new TypeError('The BYOB request\'s buffer has been detached'); + } + } + aos.ReadableByteStreamControllerClose(this); } @@ -58,6 +66,13 @@ exports.implementation = class ReadableByteStreamControllerImpl { throw new TypeError(`The stream (in ${state} state) is not in the readable state and cannot be enqueued to`); } + if (this._pendingPullIntos.length > 0) { + const firstDescriptor = this._pendingPullIntos[0]; + if (IsDetachedBuffer(firstDescriptor.buffer) === true) { + throw new TypeError('The BYOB request\'s buffer has been detached'); + } + } + aos.ReadableByteStreamControllerEnqueue(this, chunk); } From be2cc147ff80c49784cbb84aab091454645a2f32 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 10 Apr 2021 00:14:19 +0200 Subject: [PATCH 02/44] Fix some links --- index.bs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index e9b1bdb23..4af4da443 100644 --- a/index.bs +++ b/index.bs @@ -1587,7 +1587,7 @@ counterparts for BYOB controllers, as discussed in [[#rs-abstract-ops-used-by-co id="rs-default-controller-private-pull">\[[PullSteps]](|readRequest|) implements the [$ReadableStreamController/[[PullSteps]]$] contract. It performs the following steps: - 1. Let |stream| be [=this=].[=ReadableStreamGenericReader/[[stream]]=]. + 1. Let |stream| be [=this=].[=ReadableStreamDefaultController/[[stream]]=]. 1. If [=this=].[=ReadableStreamDefaultController/[[queue]]=] is not [=list/is empty|empty=], 1. Let |chunk| be ! [$DequeueValue$]([=this=]). 1. If [=this=].[=ReadableStreamDefaultController/[[closeRequested]]=] is true and @@ -1803,7 +1803,7 @@ has the following [=struct/items=]: 1. If [=this=].[=ReadableByteStreamController/[[closeRequested]]=] is true, throw a {{TypeError}} exception. - 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=].[=ReadableStream/[[state]]=] is not + 1. If [=this=].[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=] is not "`readable`", throw a {{TypeError}} exception. 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. @@ -1821,7 +1821,7 @@ for="ReadableByteStreamController">enqueue(|chunk|) method steps are: exception. 1. If [=this=].[=ReadableByteStreamController/[[closeRequested]]=] is true, throw a {{TypeError}} exception. - 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=].[=ReadableStream/[[state]]=] is not + 1. If [=this=].[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=] is not "`readable`", throw a {{TypeError}} exception. 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. From 858bebcf9f49b2aaac769ac4b0733a2f027b731b Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 10 Apr 2021 01:16:52 +0200 Subject: [PATCH 03/44] Ensure new view's buffer has same capacity as BYOB request's initial buffer --- index.bs | 16 +++++++++++----- .../lib/ReadableByteStreamController-impl.js | 1 + .../lib/abstract-ops/readable-streams.js | 6 +++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/index.bs b/index.bs index 4af4da443..3102cf6e6 100644 --- a/index.bs +++ b/index.bs @@ -1721,6 +1721,8 @@ has the following [=struct/items=]: : buffer :: An {{ArrayBuffer}} +: buffer byte length +:: A positive integer representing the initial byte length of [=pull-into descriptor/buffer=] : byte offset :: A nonnegative integer byte offset into the [=pull-into descriptor/buffer=] where the [=underlying byte source=] will start writing @@ -1887,8 +1889,9 @@ counterparts for default controllers, as discussed in [[#rs-abstract-ops-used-by 1. Perform |readRequest|'s [=read request/error steps=], given |buffer|.\[[Value]]. 1. Return. 1. Let |pullIntoDescriptor| be a new [=pull-into descriptor=] with [=pull-into descriptor/buffer=] - |buffer|.\[[Value]], [=pull-into descriptor/byte offset=] 0, [=pull-into descriptor/byte - length=] |autoAllocateChunkSize|, [=pull-into descriptor/bytes filled=] 0, [=pull-into + |buffer|.\[[Value]], [=pull-into descriptor/buffer byte length=] |autoAllocateChunkSize|, + [=pull-into descriptor/byte offset=] 0, [=pull-into descriptor/byte length=] + |autoAllocateChunkSize|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/element size=] 1, [=pull-into descriptor/view constructor=] {{%Uint8Array%}}, and [=pull-into descriptor/reader type=] "`default`". 1. [=list/Append=] |pullIntoDescriptor| to @@ -3095,9 +3098,10 @@ The following abstract operations support the implementation of the 1. Let |byteLength| be |view|.\[[ByteLength]]. 1. Let |buffer| be ! [$TransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]). 1. Let |pullIntoDescriptor| be a new [=pull-into descriptor=] with [=pull-into descriptor/buffer=] - |buffer|, [=pull-into descriptor/byte offset=] |byteOffset|, [=pull-into descriptor/byte - length=] |byteLength|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/element - size=] |elementSize|, [=pull-into descriptor/view constructor=] |ctor|, and [=pull-into + |buffer|, [=pull-into descriptor/buffer byte length=] |buffer|.\[[ArrayBufferByteLength]], + [=pull-into descriptor/byte offset=] |byteOffset|, [=pull-into descriptor/byte length=] + |byteLength|, [=pull-into descriptor/bytes filled=] 0, [=pull-into descriptor/element size=] + |elementSize|, [=pull-into descriptor/view constructor=] |ctor|, and [=pull-into descriptor/reader type=] "`byob`". 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not empty, 1. [=list/Append=] |pullIntoDescriptor| to @@ -3214,6 +3218,8 @@ The following abstract operations support the implementation of the 1. Let |firstDescriptor| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. 1. If |firstDescriptor|'s [=pull-into descriptor/byte offset=] + |firstDescriptor|' [=pull-into descriptor/bytes filled=] is not |view|.\[[ByteOffset]], throw a {{RangeError}} exception. + 1. If |firstDescriptor|'s [=pull-into descriptor/buffer byte length=] is not + |view|.\[[ViewedArrayBuffer]].\[[ByteLength]], throw a {{RangeError}} exception. 1. If |firstDescriptor|'s [=pull-into descriptor/byte length=] is not |view|.\[[ByteLength]], throw a {{RangeError}} exception. 1. Set |firstDescriptor|'s [=pull-into descriptor/buffer=] to |view|.\[[ViewedArrayBuffer]]. diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index 3c6e53594..867d62365 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -123,6 +123,7 @@ exports.implementation = class ReadableByteStreamControllerImpl { const pullIntoDescriptor = { buffer, + bufferByteLength: autoAllocateChunkSize, byteOffset: 0, byteLength: autoAllocateChunkSize, bytesFilled: 0, diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index b072d3fdd..6977c61f5 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1163,6 +1163,7 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) const buffer = TransferArrayBuffer(view.buffer); const pullIntoDescriptor = { buffer, + bufferByteLength: buffer.byteLength, byteOffset: view.byteOffset, byteLength: view.byteLength, bytesFilled: 0, @@ -1289,9 +1290,12 @@ function ReadableByteStreamControllerRespondWithNewView(controller, view) { if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) { throw new RangeError('The region specified by view does not match byobRequest'); } - if (firstDescriptor.byteLength !== view.byteLength) { + if (firstDescriptor.bufferByteLength !== view.buffer.byteLength) { throw new RangeError('The buffer of view has different capacity than byobRequest'); } + if (firstDescriptor.byteLength !== view.byteLength) { + throw new RangeError('The region specified by view has different length than byobRequest'); + } firstDescriptor.buffer = view.buffer; From 933db510de5e3c3042c8340ed27a03154f9ee000 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 20 Mar 2021 01:39:59 +0100 Subject: [PATCH 04/44] Allow passing a smaller view to BYOBRequest.respondWithNewView --- index.bs | 2 +- reference-implementation/lib/abstract-ops/readable-streams.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index 3102cf6e6..e7d097751 100644 --- a/index.bs +++ b/index.bs @@ -3220,7 +3220,7 @@ The following abstract operations support the implementation of the descriptor/bytes filled=] is not |view|.\[[ByteOffset]], throw a {{RangeError}} exception. 1. If |firstDescriptor|'s [=pull-into descriptor/buffer byte length=] is not |view|.\[[ViewedArrayBuffer]].\[[ByteLength]], throw a {{RangeError}} exception. - 1. If |firstDescriptor|'s [=pull-into descriptor/byte length=] is not |view|.\[[ByteLength]], throw + 1. If |firstDescriptor|'s [=pull-into descriptor/byte length=] < |view|.\[[ByteLength]], throw a {{RangeError}} exception. 1. Set |firstDescriptor|'s [=pull-into descriptor/buffer=] to |view|.\[[ViewedArrayBuffer]]. 1. Perform ? [$ReadableByteStreamControllerRespondInternal$](|controller|, |view|.\[[ByteLength]]). diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 6977c61f5..1263f90f7 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1293,8 +1293,8 @@ function ReadableByteStreamControllerRespondWithNewView(controller, view) { if (firstDescriptor.bufferByteLength !== view.buffer.byteLength) { throw new RangeError('The buffer of view has different capacity than byobRequest'); } - if (firstDescriptor.byteLength !== view.byteLength) { - throw new RangeError('The region specified by view has different length than byobRequest'); + if (firstDescriptor.byteLength < view.byteLength) { + throw new RangeError('The region specified by view is larger than byobRequest'); } firstDescriptor.buffer = view.buffer; From b27f364a06287899840e9acdd89ba349447b67fa Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 10 Apr 2021 00:56:13 +0200 Subject: [PATCH 05/44] Allow passing an empty view to respondWithNewView() in closed state --- index.bs | 2 +- reference-implementation/lib/ReadableStreamBYOBRequest-impl.js | 3 --- reference-implementation/lib/abstract-ops/readable-streams.js | 3 +++ 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index e7d097751..31540c40f 100644 --- a/index.bs +++ b/index.bs @@ -1992,7 +1992,6 @@ following table: The respondWithNewView(|view|) method steps are: - 1. If |view|.\[[ByteLength]] is 0, throw a {{TypeError}} exception. 1. If |view|.\[[ViewedArrayBuffer]].\[[ArrayBufferByteLength]] is 0, throw a {{TypeError}} exception. 1. If [=this=].[=ReadableStreamBYOBRequest/[[controller]]=] is undefined, throw a {{TypeError}} @@ -3203,6 +3202,7 @@ The following abstract operations support the implementation of the |firstDescriptor|). 1. Otherwise, 1. Assert: |state| is "`readable`". + 1. If |bytesWritten| is 0, throw a {{TypeError}} exception. 1. Perform ? [$ReadableByteStreamControllerRespondInReadableState$](|controller|, |bytesWritten|, |firstDescriptor|). 1. Perform ! [$ReadableByteStreamControllerCallPullIfNeeded$](|controller|). diff --git a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js index 2e737fd9b..cde009ff8 100644 --- a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js @@ -25,9 +25,6 @@ exports.implementation = class ReadableStreamBYOBRequestImpl { } respondWithNewView(view) { - if (view.byteLength === 0) { - throw new TypeError('chunk must have non-zero byteLength'); - } if (view.buffer.byteLength === 0) { throw new TypeError('chunk\'s buffer must have non-zero byteLength'); } diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 1263f90f7..9344ab512 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1275,6 +1275,9 @@ function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) { ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor); } else { assert(state === 'readable'); + if (bytesWritten === 0) { + throw new TypeError('bytesWritten must be greater than 0 when calling respond() on a readable stream'); + } ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor); } From 01b6e787fe2170f2d8630832463e76b0ff42dcb4 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 10 Apr 2021 01:45:12 +0200 Subject: [PATCH 06/44] Restrict pull-into descriptor's byte length to be non-zero --- index.bs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 31540c40f..2fa8f5278 100644 --- a/index.bs +++ b/index.bs @@ -1727,8 +1727,7 @@ has the following [=struct/items=]: :: A nonnegative integer byte offset into the [=pull-into descriptor/buffer=] where the [=underlying byte source=] will start writing : byte length -:: A nonnegative integer number of bytes which can be written into the [=pull-into - descriptor/buffer=] +:: A positive integer number of bytes which can be written into the [=pull-into descriptor/buffer=] : bytes filled :: A nonnegative integer number of bytes that have been written into the [=pull-into descriptor/buffer=] so far From ec2af1983fafb893d8003a78c1db481784f1b4ea Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 17 Apr 2021 01:16:54 +0200 Subject: [PATCH 07/44] Fix check to match ReadableByteStreamControllerRespondInReadableState --- index.bs | 4 ++-- reference-implementation/lib/abstract-ops/readable-streams.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index 2fa8f5278..53ccd3443 100644 --- a/index.bs +++ b/index.bs @@ -3219,8 +3219,8 @@ The following abstract operations support the implementation of the descriptor/bytes filled=] is not |view|.\[[ByteOffset]], throw a {{RangeError}} exception. 1. If |firstDescriptor|'s [=pull-into descriptor/buffer byte length=] is not |view|.\[[ViewedArrayBuffer]].\[[ByteLength]], throw a {{RangeError}} exception. - 1. If |firstDescriptor|'s [=pull-into descriptor/byte length=] < |view|.\[[ByteLength]], throw - a {{RangeError}} exception. + 1. If |firstDescriptor|'s [=pull-into descriptor/bytes filled=] + |view|.\[[ByteLength]] > + |firstDescriptor|'s [=pull-into descriptor/byte length=], throw a {{RangeError}} exception. 1. Set |firstDescriptor|'s [=pull-into descriptor/buffer=] to |view|.\[[ViewedArrayBuffer]]. 1. Perform ? [$ReadableByteStreamControllerRespondInternal$](|controller|, |view|.\[[ByteLength]]). diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 9344ab512..f15b1168a 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1296,7 +1296,7 @@ function ReadableByteStreamControllerRespondWithNewView(controller, view) { if (firstDescriptor.bufferByteLength !== view.buffer.byteLength) { throw new RangeError('The buffer of view has different capacity than byobRequest'); } - if (firstDescriptor.byteLength < view.byteLength) { + if (firstDescriptor.bytesFilled + view.byteLength > firstDescriptor.byteLength) { throw new RangeError('The region specified by view is larger than byobRequest'); } From 7fdb8a594fdca5ba61b39d1fd41c7bfe5b148e33 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 17 Apr 2021 01:17:44 +0200 Subject: [PATCH 08/44] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 1bdb43faa..212c09dbb 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 1bdb43faa7434d36645ab5c64e754b5caefbc9d2 +Subproject commit 212c09dbbc284fbb58b962df9cd238a7f5c7d60f From c475de891e2220c4ecaa93cc64d47333615f80de Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 17 Apr 2021 21:04:32 +0200 Subject: [PATCH 09/44] Remove redundant check --- index.bs | 2 -- .../lib/ReadableStreamBYOBRequest-impl.js | 4 ---- 2 files changed, 6 deletions(-) diff --git a/index.bs b/index.bs index 53ccd3443..3930b8ca7 100644 --- a/index.bs +++ b/index.bs @@ -1991,8 +1991,6 @@ following table: The respondWithNewView(|view|) method steps are: - 1. If |view|.\[[ViewedArrayBuffer]].\[[ArrayBufferByteLength]] is 0, throw a {{TypeError}} - exception. 1. If [=this=].[=ReadableStreamBYOBRequest/[[controller]]=] is undefined, throw a {{TypeError}} exception. 1. Return ? diff --git a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js index cde009ff8..03eee865a 100644 --- a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js @@ -25,10 +25,6 @@ exports.implementation = class ReadableStreamBYOBRequestImpl { } respondWithNewView(view) { - if (view.buffer.byteLength === 0) { - throw new TypeError('chunk\'s buffer must have non-zero byteLength'); - } - if (this._controller === undefined) { throw new TypeError('This BYOB request has been invalidated'); } From 98415ae81c9b0c6e7e207fd3bab963a3c5dc0a78 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 21:43:41 +0200 Subject: [PATCH 10/44] Fix missing ! before calls --- index.bs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index 3930b8ca7..05760d923 100644 --- a/index.bs +++ b/index.bs @@ -1808,7 +1808,7 @@ has the following [=struct/items=]: "`readable`", throw a {{TypeError}} exception. 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. If [$IsDetachedBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is true, + 1. If ! [$IsDetachedBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is true, throw a {{TypeError}} exception. 1. Perform ? [$ReadableByteStreamControllerClose$]([=this=]). @@ -1826,7 +1826,7 @@ for="ReadableByteStreamController">enqueue(|chunk|) method steps are: "`readable`", throw a {{TypeError}} exception. 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. If [$IsDetachedBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is true, + 1. If ! [$IsDetachedBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is true, throw a {{TypeError}} exception. 1. Return ! [$ReadableByteStreamControllerEnqueue$]([=this=], |chunk|). @@ -1977,7 +1977,7 @@ following table: 1. If [=this=].[=ReadableStreamBYOBRequest/[[controller]]=] is undefined, throw a {{TypeError}} exception. - 1. If [$IsDetachedBuffer$]([=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ArrayBuffer]]) is + 1. If ! [$IsDetachedBuffer$]([=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ArrayBuffer]]) is true, throw a {{TypeError}} exception. 1. Assert: [=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ByteLength]] > 0. 1. Assert: [=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ViewedArrayBuffer]].\[[ByteLength]] From 22c5aa8ce4e978eddbbd9b35318211f5b2b9bf05 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 22:08:59 +0200 Subject: [PATCH 11/44] Add CanTransferArrayBuffer helper --- index.bs | 22 +++++++++++++------ .../lib/ReadableByteStreamController-impl.js | 6 ++--- .../lib/ReadableStreamBYOBRequest-impl.js | 4 ++-- .../lib/abstract-ops/ecmascript.js | 7 +++++- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/index.bs b/index.bs index 05760d923..8a492ee81 100644 --- a/index.bs +++ b/index.bs @@ -1808,7 +1808,7 @@ has the following [=struct/items=]: "`readable`", throw a {{TypeError}} exception. 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. If ! [$IsDetachedBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is true, + 1. If ! [$CanTransferArrayBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is false, throw a {{TypeError}} exception. 1. Perform ? [$ReadableByteStreamControllerClose$]([=this=]). @@ -1826,7 +1826,7 @@ for="ReadableByteStreamController">enqueue(|chunk|) method steps are: "`readable`", throw a {{TypeError}} exception. 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. If ! [$IsDetachedBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is true, + 1. If ! [$CanTransferArrayBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is false, throw a {{TypeError}} exception. 1. Return ! [$ReadableByteStreamControllerEnqueue$]([=this=], |chunk|). @@ -1977,8 +1977,8 @@ following table: 1. If [=this=].[=ReadableStreamBYOBRequest/[[controller]]=] is undefined, throw a {{TypeError}} exception. - 1. If ! [$IsDetachedBuffer$]([=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ArrayBuffer]]) is - true, throw a {{TypeError}} exception. + 1. If ! [$CanTransferArrayBuffer$]([=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ArrayBuffer]]) + is false, throw a {{TypeError}} exception. 1. Assert: [=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ByteLength]] > 0. 1. Assert: [=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ViewedArrayBuffer]].\[[ByteLength]] > 0. @@ -6079,6 +6079,16 @@ abstract operations are used to implement these "cross-realm transforms". The following abstract operations are a grab-bag of utilities. +
+ CanTransferArrayBuffer(|O|) performs the following steps: + + 1. Assert: [$Type$](|O|) is Object. + 1. Assert: |O| has an \[[ArrayBufferData]] internal slot. + 1. If ! [$IsDetachedBuffer$](|O|) is true, return false. + 1. Return true. +
+
IsNonNegativeNumber(|v|) performs the following steps: @@ -6093,9 +6103,7 @@ The following abstract operations are a grab-bag of utilities. TransferArrayBuffer(|O|) performs the following steps: - 1. Assert: [$Type$](|O|) is Object. - 1. Assert: |O| has an \[[ArrayBufferData]] internal slot. - 1. Assert: ! [$IsDetachedBuffer$](|O|) is false. + 1. Assert: ! [$CanTransferArrayBuffer$](|O|) is true. 1. Let |arrayBufferData| be |O|.\[[ArrayBufferData]]. 1. Let |arrayBufferByteLength| be |O|.\[[ArrayBufferByteLength]]. 1. Perform ! [$DetachArrayBuffer$](|O|). diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index 867d62365..a07de551b 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -3,7 +3,7 @@ const assert = require('assert'); const { CancelSteps, PullSteps } = require('./abstract-ops/internal-methods.js'); const { ResetQueue } = require('./abstract-ops/queue-with-sizes.js'); -const { IsDetachedBuffer } = require('./abstract-ops/ecmascript.js'); +const { CanTransferArrayBuffer } = require('./abstract-ops/ecmascript.js'); const aos = require('./abstract-ops/readable-streams.js'); const ReadableStreamBYOBRequest = require('../generated/ReadableStreamBYOBRequest.js'); @@ -41,7 +41,7 @@ exports.implementation = class ReadableByteStreamControllerImpl { if (this._pendingPullIntos.length > 0) { const firstDescriptor = this._pendingPullIntos[0]; - if (IsDetachedBuffer(firstDescriptor.buffer) === true) { + if (CanTransferArrayBuffer(firstDescriptor.buffer) === false) { throw new TypeError('The BYOB request\'s buffer has been detached'); } } @@ -68,7 +68,7 @@ exports.implementation = class ReadableByteStreamControllerImpl { if (this._pendingPullIntos.length > 0) { const firstDescriptor = this._pendingPullIntos[0]; - if (IsDetachedBuffer(firstDescriptor.buffer) === true) { + if (CanTransferArrayBuffer(firstDescriptor.buffer) === false) { throw new TypeError('The BYOB request\'s buffer has been detached'); } } diff --git a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js index 03eee865a..e7215c73f 100644 --- a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js @@ -1,7 +1,7 @@ 'use strict'; const assert = require('assert'); -const { IsDetachedBuffer } = require('./abstract-ops/ecmascript.js'); +const { CanTransferArrayBuffer } = require('./abstract-ops/ecmascript.js'); const aos = require('./abstract-ops/readable-streams.js'); exports.implementation = class ReadableStreamBYOBRequestImpl { @@ -14,7 +14,7 @@ exports.implementation = class ReadableStreamBYOBRequestImpl { throw new TypeError('This BYOB request has been invalidated'); } - if (IsDetachedBuffer(this._view.buffer) === true) { + if (CanTransferArrayBuffer(this._view.buffer) === false) { throw new TypeError('The BYOB request\'s buffer has been detached and so cannot be used as a response'); } diff --git a/reference-implementation/lib/abstract-ops/ecmascript.js b/reference-implementation/lib/abstract-ops/ecmascript.js index 636e352da..37fbb7a92 100644 --- a/reference-implementation/lib/abstract-ops/ecmascript.js +++ b/reference-implementation/lib/abstract-ops/ecmascript.js @@ -15,7 +15,7 @@ exports.CopyDataBlockBytes = (dest, destOffset, src, srcOffset, n) => { // Not implemented correctly exports.TransferArrayBuffer = O => { - assert(!exports.IsDetachedBuffer(O)); + assert(exports.CanTransferArrayBuffer(O)); const transferredIshVersion = O.slice(); // This is specifically to fool tests that test "is transferred" by taking a non-zero-length @@ -30,6 +30,11 @@ exports.TransferArrayBuffer = O => { return transferredIshVersion; }; +// Not implemented correctly +exports.CanTransferArrayBuffer = O => { + return !exports.IsDetachedBuffer(O); +}; + // Not implemented correctly exports.IsDetachedBuffer = O => { return isFakeDetached in O; From 882fc7c8861b23264a0d78afd9cc7460665ae5ed Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 22:09:28 +0200 Subject: [PATCH 12/44] Check [[ArrayBufferDetachKey]] in CanTransferArrayBuffer --- index.bs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.bs b/index.bs index 8a492ee81..a5cb1649c 100644 --- a/index.bs +++ b/index.bs @@ -55,6 +55,7 @@ urlPrefix: https://tc39.es/ecma262/; spec: ECMASCRIPT text: IsDetachedBuffer; url: #sec-isdetachedbuffer text: IsInteger; url: #sec-isinteger text: OrdinaryObjectCreate; url: #sec-ordinaryobjectcreate + text: SameValue; url: #sec-samevalue text: SetFunctionLength; url: #sec-setfunctionlength text: SetFunctionName; url: #sec-setfunctionname text: Type; url: #sec-ecmascript-data-types-and-values @@ -6086,6 +6087,7 @@ The following abstract operations are a grab-bag of utilities. 1. Assert: [$Type$](|O|) is Object. 1. Assert: |O| has an \[[ArrayBufferData]] internal slot. 1. If ! [$IsDetachedBuffer$](|O|) is true, return false. + 1. If [$SameValue$](|O|.\[[ArrayBufferDetachKey]], undefined) is false, return false. 1. Return true.
From afd3e810436a6d858fdf5f30b4b092e71503f10a Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 22:15:35 +0200 Subject: [PATCH 13/44] Remove detached check from ReadableByteStreamController.close() This should be allowed: controller.close(); controller.byobRequest.respondWithNewView(transferredView); --- index.bs | 4 ---- .../lib/ReadableByteStreamController-impl.js | 7 ------- 2 files changed, 11 deletions(-) diff --git a/index.bs b/index.bs index a5cb1649c..1f978f2bf 100644 --- a/index.bs +++ b/index.bs @@ -1807,10 +1807,6 @@ has the following [=struct/items=]: exception. 1. If [=this=].[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=] is not "`readable`", throw a {{TypeError}} exception. - 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], - 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. If ! [$CanTransferArrayBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is false, - throw a {{TypeError}} exception. 1. Perform ? [$ReadableByteStreamControllerClose$]([=this=]). diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index a07de551b..5f10f00a1 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -39,13 +39,6 @@ exports.implementation = class ReadableByteStreamControllerImpl { throw new TypeError(`The stream (in ${state} state) is not in the readable state and cannot be closed`); } - if (this._pendingPullIntos.length > 0) { - const firstDescriptor = this._pendingPullIntos[0]; - if (CanTransferArrayBuffer(firstDescriptor.buffer) === false) { - throw new TypeError('The BYOB request\'s buffer has been detached'); - } - } - aos.ReadableByteStreamControllerClose(this); } From 3d13462fe4abef7180353a137b5f91064d654766 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 22:31:48 +0200 Subject: [PATCH 14/44] Move detached pull-into buffer check to ReadableByteStreamControllerEnqueue --- index.bs | 15 ++++++++++----- .../lib/ReadableByteStreamController-impl.js | 8 -------- .../lib/abstract-ops/readable-streams.js | 15 ++++++++++++++- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/index.bs b/index.bs index 1f978f2bf..abc8665a6 100644 --- a/index.bs +++ b/index.bs @@ -1821,11 +1821,7 @@ for="ReadableByteStreamController">enqueue(|chunk|) method steps are: exception. 1. If [=this=].[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=] is not "`readable`", throw a {{TypeError}} exception. - 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], - 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. If ! [$CanTransferArrayBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is false, - throw a {{TypeError}} exception. - 1. Return ! [$ReadableByteStreamControllerEnqueue$]([=this=], |chunk|). + 1. Return ? [$ReadableByteStreamControllerEnqueue$]([=this=], |chunk|).
@@ -2913,6 +2909,15 @@ The following abstract operations support the implementation of the |byteOffset|, |byteLength| »). 1. Perform ! [$ReadableStreamFulfillReadRequest$](|stream|, |transferredView|, false). 1. Otherwise, if ! [$ReadableStreamHasBYOBReader$](|stream|) is true, + 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not + [=list/is empty|empty=], + 1. Let |firstPendingPullInto| be + |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. + 1. If ! [$CanTransferArrayBuffer$](|firstPendingPullInto|'s [=pull-into descriptor/buffer=]) + is false, + 1. Let |e| be a new {{TypeError}} exception. + 1. Perform ! [$ReadableByteStreamControllerError$](|controller|, |e|). + 1. Throw |e|. 1. Perform ! [$ReadableByteStreamControllerEnqueueChunkToQueue$](|controller|, |transferredBuffer|, |byteOffset|, |byteLength|). 1. Perform ! [$ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue$](|controller|). diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index 5f10f00a1..799ea3799 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -3,7 +3,6 @@ const assert = require('assert'); const { CancelSteps, PullSteps } = require('./abstract-ops/internal-methods.js'); const { ResetQueue } = require('./abstract-ops/queue-with-sizes.js'); -const { CanTransferArrayBuffer } = require('./abstract-ops/ecmascript.js'); const aos = require('./abstract-ops/readable-streams.js'); const ReadableStreamBYOBRequest = require('../generated/ReadableStreamBYOBRequest.js'); @@ -59,13 +58,6 @@ exports.implementation = class ReadableByteStreamControllerImpl { throw new TypeError(`The stream (in ${state} state) is not in the readable state and cannot be enqueued to`); } - if (this._pendingPullIntos.length > 0) { - const firstDescriptor = this._pendingPullIntos[0]; - if (CanTransferArrayBuffer(firstDescriptor.buffer) === false) { - throw new TypeError('The BYOB request\'s buffer has been detached'); - } - } - aos.ReadableByteStreamControllerEnqueue(this, chunk); } diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index f15b1168a..929676c0f 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -4,7 +4,8 @@ const assert = require('assert'); const { promiseResolvedWith, promiseRejectedWith, newPromise, resolvePromise, rejectPromise, uponPromise, setPromiseIsHandledToTrue, waitForAllPromise, transformPromiseWith, uponFulfillment, uponRejection } = require('../helpers/webidl.js'); -const { CopyDataBlockBytes, CreateArrayFromList, TransferArrayBuffer } = require('./ecmascript.js'); +const { CanTransferArrayBuffer, CopyDataBlockBytes, CreateArrayFromList, TransferArrayBuffer } = + require('./ecmascript.js'); const { IsNonNegativeNumber } = require('./miscellaneous.js'); const { EnqueueValueWithSize, ResetQueue } = require('./queue-with-sizes.js'); const { AcquireWritableStreamDefaultWriter, IsWritableStreamLocked, WritableStreamAbort, @@ -1009,6 +1010,18 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) { ReadableStreamFulfillReadRequest(stream, transferredView, false); } } else if (ReadableStreamHasBYOBReader(stream) === true) { + if (controller._pendingPullIntos.length > 0) { + const firstPendingPullInto = controller._pendingPullIntos[0]; + if (CanTransferArrayBuffer(firstPendingPullInto.buffer) === false) { + const e = new TypeError( + 'The BYOB request\'s buffer has been detached and so cannot be filled with an enqueued chunk' + ); + ReadableByteStreamControllerError(controller, e); + + throw e; + } + } + // TODO: Ideally in this branch detaching should happen only if the buffer is not consumed fully. ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller); From 2e55eda8706e09a9fe67d5dfb42c5ad93872f581 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 22:35:19 +0200 Subject: [PATCH 15/44] Assert that pull-into descriptor is transferable in ReadableByteStreamControllerRespondInternal --- index.bs | 1 + reference-implementation/lib/abstract-ops/readable-streams.js | 1 + 2 files changed, 2 insertions(+) diff --git a/index.bs b/index.bs index abc8665a6..5f4f1cef8 100644 --- a/index.bs +++ b/index.bs @@ -3193,6 +3193,7 @@ The following abstract operations support the implementation of the |bytesWritten|) performs the following steps: 1. Let |firstDescriptor| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. + 1. Assert: ! [$CanTransferArrayBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is true. 1. Let |state| be |controller|.[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=]. 1. If |state| is "`closed`", diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 929676c0f..6d51ce555 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1277,6 +1277,7 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) { const firstDescriptor = controller._pendingPullIntos[0]; + assert(CanTransferArrayBuffer(firstDescriptor.buffer) === true); const state = controller._stream._state; From ec48c0def76a2839507f08ad71152af94835d62a Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 22:45:52 +0200 Subject: [PATCH 16/44] Check that respondWithNewView() is called with a transferable buffer --- index.bs | 3 +++ .../lib/ReadableStreamBYOBRequest-impl.js | 4 ++++ reference-implementation/lib/abstract-ops/readable-streams.js | 1 + 3 files changed, 8 insertions(+) diff --git a/index.bs b/index.bs index 5f4f1cef8..907b9021d 100644 --- a/index.bs +++ b/index.bs @@ -1986,6 +1986,8 @@ following table: 1. If [=this=].[=ReadableStreamBYOBRequest/[[controller]]=] is undefined, throw a {{TypeError}} exception. + 1. If ! [$CanTransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]) is false, + throw a {{TypeError}} exception. 1. Return ? [$ReadableByteStreamControllerRespondWithNewView$]([=this=].[=ReadableStreamBYOBRequest/[[controller]]=], |view|). @@ -3215,6 +3217,7 @@ The following abstract operations support the implementation of the 1. Assert: |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=]. + 1. Assert: ! [$CanTransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]) is true. 1. Let |firstDescriptor| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. 1. If |firstDescriptor|'s [=pull-into descriptor/byte offset=] + |firstDescriptor|' [=pull-into descriptor/bytes filled=] is not |view|.\[[ByteOffset]], throw a {{RangeError}} exception. diff --git a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js index e7215c73f..aaee5be45 100644 --- a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js @@ -29,6 +29,10 @@ exports.implementation = class ReadableStreamBYOBRequestImpl { throw new TypeError('This BYOB request has been invalidated'); } + if (CanTransferArrayBuffer(view.buffer) === false) { + throw new TypeError('The given view\'s buffer is not transferable and so cannot be used as a response'); + } + aos.ReadableByteStreamControllerRespondWithNewView(this._controller, view); } }; diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 6d51ce555..5eacbdca1 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1301,6 +1301,7 @@ function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) { function ReadableByteStreamControllerRespondWithNewView(controller, view) { assert(controller._pendingPullIntos.length > 0); + assert(CanTransferArrayBuffer(view.buffer) === true); const firstDescriptor = controller._pendingPullIntos[0]; From 6608188d6e783eb80d5fd3f71ed8dbe52aef372e Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 22:53:03 +0200 Subject: [PATCH 17/44] Check that enqueue() is called with a transferable buffer --- index.bs | 3 +++ .../lib/ReadableByteStreamController-impl.js | 4 ++++ reference-implementation/lib/abstract-ops/readable-streams.js | 2 ++ 3 files changed, 9 insertions(+) diff --git a/index.bs b/index.bs index 907b9021d..bed2a1eb8 100644 --- a/index.bs +++ b/index.bs @@ -1817,6 +1817,8 @@ for="ReadableByteStreamController">enqueue(|chunk|) method steps are: 1. If |chunk|.\[[ByteLength]] is 0, throw a {{TypeError}} exception. 1. If |chunk|.\[[ViewedArrayBuffer]].\[[ArrayBufferByteLength]] is 0, throw a {{TypeError}} exception. + 1. If ! [$CanTransferArrayBuffer$](|chunk|.\[[ViewedArrayBuffer]]) is false, + throw a {{TypeError}} exception. 1. If [=this=].[=ReadableByteStreamController/[[closeRequested]]=] is true, throw a {{TypeError}} exception. 1. If [=this=].[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=] is not @@ -2894,6 +2896,7 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-enqueue">ReadableByteStreamControllerEnqueue(|controller|, |chunk|) performs the following steps: + 1. Assert: ! [$CanTransferArrayBuffer$](|chunk|.\[[ViewedArrayBuffer]]) is true. 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. 1. If |controller|.[=ReadableByteStreamController/[[closeRequested]]=] is true or |stream|.[=ReadableStream/[[state]]=] is not "`readable`", return. diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index 799ea3799..b0af7e620 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -1,6 +1,7 @@ 'use strict'; const assert = require('assert'); +const { CanTransferArrayBuffer } = require('./abstract-ops/ecmascript.js'); const { CancelSteps, PullSteps } = require('./abstract-ops/internal-methods.js'); const { ResetQueue } = require('./abstract-ops/queue-with-sizes.js'); const aos = require('./abstract-ops/readable-streams.js'); @@ -48,6 +49,9 @@ exports.implementation = class ReadableByteStreamControllerImpl { if (chunk.buffer.byteLength === 0) { throw new TypeError('chunk\'s buffer must have non-zero byteLength'); } + if (CanTransferArrayBuffer(chunk.buffer) === false) { + throw new TypeError('The given view\'s buffer is not transferable and so cannot be enqueued'); + } if (this._closeRequested === true) { throw new TypeError('stream is closed or draining'); diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 5eacbdca1..9e71af025 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -989,6 +989,8 @@ function ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescripto } function ReadableByteStreamControllerEnqueue(controller, chunk) { + assert(CanTransferArrayBuffer(chunk.buffer) === true); + const stream = controller._stream; if (controller._closeRequested === true || stream._state !== 'readable') { From 6d4ea401c1538d5de06d9c4c7f8ff8e931d50b04 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 23:05:05 +0200 Subject: [PATCH 18/44] Remove redundant assert --- index.bs | 1 - reference-implementation/lib/abstract-ops/readable-streams.js | 2 -- 2 files changed, 3 deletions(-) diff --git a/index.bs b/index.bs index bed2a1eb8..a567c7c34 100644 --- a/index.bs +++ b/index.bs @@ -2896,7 +2896,6 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-enqueue">ReadableByteStreamControllerEnqueue(|controller|, |chunk|) performs the following steps: - 1. Assert: ! [$CanTransferArrayBuffer$](|chunk|.\[[ViewedArrayBuffer]]) is true. 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. 1. If |controller|.[=ReadableByteStreamController/[[closeRequested]]=] is true or |stream|.[=ReadableStream/[[state]]=] is not "`readable`", return. diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 9e71af025..5eacbdca1 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -989,8 +989,6 @@ function ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescripto } function ReadableByteStreamControllerEnqueue(controller, chunk) { - assert(CanTransferArrayBuffer(chunk.buffer) === true); - const stream = controller._stream; if (controller._closeRequested === true || stream._state !== 'readable') { From 63e4cedc6d97477dd12e5f1473dc999332da5bc8 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 23:25:51 +0200 Subject: [PATCH 19/44] Move checks for bytesWritten from RespondInternal() to Respond() and RespondWithNewView() --- index.bs | 25 +++++++++-- .../lib/abstract-ops/readable-streams.js | 45 ++++++++++++++----- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/index.bs b/index.bs index a567c7c34..b557cd133 100644 --- a/index.bs +++ b/index.bs @@ -3140,6 +3140,16 @@ The following abstract operations support the implementation of the |bytesWritten|) performs the following steps: 1. Assert: |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not empty. + 1. Let |firstDescriptor| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. + 1. Let |state| be + |controller|.[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=]. + 1. If |state| is "`closed`", + 1. If |bytesWritten| is not 0, throw a {{TypeError}} exception. + 1. Otherwise, + 1. Assert: |state| is "`readable`". + 1. If |bytesWritten| is 0, throw a {{TypeError}} exception. + 1. If |firstDescriptor|'s [=pull-into descriptor/bytes filled=] + |bytesWritten| > + |firstDescriptor|'s [=pull-into descriptor/byte length=], throw a {{RangeError}} exception. 1. Perform ? [$ReadableByteStreamControllerRespondInternal$](|controller|, |bytesWritten|).
@@ -3165,8 +3175,8 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-respond-in-readable-state">ReadableByteStreamControllerRespondInReadableState(|controller|, |bytesWritten|, |pullIntoDescriptor|) performs the following steps: - 1. If |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] + |bytesWritten| > - |pullIntoDescriptor|'s [=pull-into descriptor/byte length=], throw a {{RangeError}} exception. + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] + |bytesWritten| <= + |pullIntoDescriptor|'s [=pull-into descriptor/byte length=]. 1. Perform ! [$ReadableByteStreamControllerFillHeadPullIntoDescriptor$](|controller|, |bytesWritten|, |pullIntoDescriptor|). 1. If |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] < |pullIntoDescriptor|'s @@ -3201,12 +3211,12 @@ The following abstract operations support the implementation of the 1. Let |state| be |controller|.[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=]. 1. If |state| is "`closed`", - 1. If |bytesWritten| is not 0, throw a {{TypeError}} exception. + 1. Assert: |bytesWritten| is 0. 1. Perform ! [$ReadableByteStreamControllerRespondInClosedState$](|controller|, |firstDescriptor|). 1. Otherwise, 1. Assert: |state| is "`readable`". - 1. If |bytesWritten| is 0, throw a {{TypeError}} exception. + 1. Assert: |bytesWritten| > 0. 1. Perform ? [$ReadableByteStreamControllerRespondInReadableState$](|controller|, |bytesWritten|, |firstDescriptor|). 1. Perform ! [$ReadableByteStreamControllerCallPullIfNeeded$](|controller|). @@ -3221,6 +3231,13 @@ The following abstract operations support the implementation of the empty|empty=]. 1. Assert: ! [$CanTransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]) is true. 1. Let |firstDescriptor| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. + 1. Let |state| be + |controller|.[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=]. + 1. If |state| is "`closed`", + 1. If |view|.\[[ByteLength]] is not 0, throw a {{TypeError}} exception. + 1. Otherwise, + 1. Assert: |state| is "`readable`". + 1. If |view|.\[[ByteLength]] is 0, throw a {{TypeError}} exception. 1. If |firstDescriptor|'s [=pull-into descriptor/byte offset=] + |firstDescriptor|' [=pull-into descriptor/bytes filled=] is not |view|.\[[ByteOffset]], throw a {{RangeError}} exception. 1. If |firstDescriptor|'s [=pull-into descriptor/buffer byte length=] is not diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 5eacbdca1..06d778020 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1230,6 +1230,23 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) function ReadableByteStreamControllerRespond(controller, bytesWritten) { assert(controller._pendingPullIntos.length > 0); + const firstDescriptor = controller._pendingPullIntos[0]; + const state = controller._stream._state; + + if (state === 'closed') { + if (bytesWritten !== 0) { + throw new TypeError('bytesWritten must be 0 when calling respond() on a closed stream'); + } + } else { + assert(state === 'readable'); + if (bytesWritten === 0) { + throw new TypeError('bytesWritten must be greater than 0 when calling respond() on a readable stream'); + } + if (firstDescriptor.bytesFilled + bytesWritten > firstDescriptor.byteLength) { + throw new RangeError('bytesWritten out of range'); + } + } + ReadableByteStreamControllerRespondInternal(controller, bytesWritten); } @@ -1248,9 +1265,7 @@ function ReadableByteStreamControllerRespondInClosedState(controller, firstDescr } function ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) { - if (pullIntoDescriptor.bytesFilled + bytesWritten > pullIntoDescriptor.byteLength) { - throw new RangeError('bytesWritten out of range'); - } + assert(pullIntoDescriptor.bytesFilled + bytesWritten <= pullIntoDescriptor.byteLength); ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor); @@ -1282,17 +1297,11 @@ function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) { const state = controller._stream._state; if (state === 'closed') { - if (bytesWritten !== 0) { - throw new TypeError('bytesWritten must be 0 when calling respond() on a closed stream'); - } - + assert(bytesWritten === 0); ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor); } else { assert(state === 'readable'); - if (bytesWritten === 0) { - throw new TypeError('bytesWritten must be greater than 0 when calling respond() on a readable stream'); - } - + assert(bytesWritten > 0); ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor); } @@ -1304,6 +1313,20 @@ function ReadableByteStreamControllerRespondWithNewView(controller, view) { assert(CanTransferArrayBuffer(view.buffer) === true); const firstDescriptor = controller._pendingPullIntos[0]; + const state = controller._stream._state; + + if (state === 'closed') { + if (view.byteLength !== 0) { + throw new TypeError('The view\'s length must be 0 when calling respondWithNewView() on a closed stream'); + } + } else { + assert(state === 'readable'); + if (view.byteLength === 0) { + throw new TypeError( + 'The view\'s length must be greater than 0 when calling respondWithNewView() on a readable stream' + ); + } + } if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) { throw new RangeError('The region specified by view does not match byobRequest'); From 098889f42b059f7072624b861e1272f3113cbb49 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Mon, 19 Apr 2021 23:33:39 +0200 Subject: [PATCH 20/44] Don't error the stream if enqueue() fails because of a transferred BYOB request --- index.bs | 5 +---- .../lib/abstract-ops/readable-streams.js | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/index.bs b/index.bs index b557cd133..fb4b439bf 100644 --- a/index.bs +++ b/index.bs @@ -2918,10 +2918,7 @@ The following abstract operations support the implementation of the 1. Let |firstPendingPullInto| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. 1. If ! [$CanTransferArrayBuffer$](|firstPendingPullInto|'s [=pull-into descriptor/buffer=]) - is false, - 1. Let |e| be a new {{TypeError}} exception. - 1. Perform ! [$ReadableByteStreamControllerError$](|controller|, |e|). - 1. Throw |e|. + is false, throw a {{TypeError}} exception. 1. Perform ! [$ReadableByteStreamControllerEnqueueChunkToQueue$](|controller|, |transferredBuffer|, |byteOffset|, |byteLength|). 1. Perform ! [$ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue$](|controller|). diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 06d778020..a3617c7a4 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1013,12 +1013,9 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) { if (controller._pendingPullIntos.length > 0) { const firstPendingPullInto = controller._pendingPullIntos[0]; if (CanTransferArrayBuffer(firstPendingPullInto.buffer) === false) { - const e = new TypeError( + throw new TypeError( 'The BYOB request\'s buffer has been detached and so cannot be filled with an enqueued chunk' ); - ReadableByteStreamControllerError(controller, e); - - throw e; } } From efed1f54f6830e1665acc2f60fdd827b8b143815 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 20 Apr 2021 00:00:52 +0200 Subject: [PATCH 21/44] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 212c09dbb..9b7f43580 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 212c09dbbc284fbb58b962df9cd238a7f5c7d60f +Subproject commit 9b7f4358098f0aea35eb8de8333ec5b6b6f46446 From 326ec81da86f3f448494adcb71b570bc1c1a327d Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 20 Apr 2021 00:14:48 +0200 Subject: [PATCH 22/44] Fix error message --- .../lib/ReadableByteStreamController-impl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index b0af7e620..ddc890cc4 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -50,7 +50,7 @@ exports.implementation = class ReadableByteStreamControllerImpl { throw new TypeError('chunk\'s buffer must have non-zero byteLength'); } if (CanTransferArrayBuffer(chunk.buffer) === false) { - throw new TypeError('The given view\'s buffer is not transferable and so cannot be enqueued'); + throw new TypeError('chunk\'s buffer is not transferable and so cannot be enqueued'); } if (this._closeRequested === true) { From 7dad495e3a3e4a9a52e1e19ad6874b1f660c77ef Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 20 Apr 2021 00:19:17 +0200 Subject: [PATCH 23/44] Check that view passed to byobReader.read() is transferable --- index.bs | 2 ++ reference-implementation/lib/ReadableStreamBYOBReader-impl.js | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/index.bs b/index.bs index fb4b439bf..ae2b320d5 100644 --- a/index.bs +++ b/index.bs @@ -1397,6 +1397,8 @@ value: newViewOnSameMemory, done: true } for closed streams, instead of t 1. If |view|.\[[ByteLength]] is 0, return [=a promise rejected with=] a {{TypeError}} exception. 1. If |view|.\[[ViewedArrayBuffer]].\[[ArrayBufferByteLength]] is 0, return [=a promise rejected with=] a {{TypeError}} exception. + 1. If ! [$CanTransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]) is false, return + [=a promise rejected with=] a {{TypeError}} exception. 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=] is undefined, return [=a promise rejected with=] a {{TypeError}} exception. 1. Let |promise| be [=a new promise=]. diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index b4feaa6ad..4f87cbc6d 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -1,6 +1,7 @@ 'use strict'; const { newPromise, resolvePromise, rejectPromise, promiseRejectedWith } = require('./helpers/webidl.js'); +const { CanTransferArrayBuffer } = require('./abstract-ops/ecmascript.js'); const aos = require('./abstract-ops/readable-streams.js'); const { mixin } = require('./helpers/miscellaneous.js'); const ReadableStreamGenericReaderImpl = require('./ReadableStreamGenericReader-impl.js').implementation; @@ -17,6 +18,9 @@ class ReadableStreamBYOBReaderImpl { if (view.buffer.byteLength === 0) { return promiseRejectedWith(new TypeError('view\'s buffer must have non-zero byteLength')); } + if (CanTransferArrayBuffer(view.buffer) === false) { + return promiseRejectedWith(new TypeError('view\'s buffer is not transferable')); + } if (this._stream === undefined) { return promiseRejectedWith(readerLockException('read')); From e7b82bde1e2b0e746fdac36112b9a4d9cb8253fe Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 22 Apr 2021 00:04:48 +0200 Subject: [PATCH 24/44] Always transfer the buffer when committing a pull-into descriptor --- index.bs | 7 +++---- .../lib/abstract-ops/readable-streams.js | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/index.bs b/index.bs index ae2b320d5..778f83186 100644 --- a/index.bs +++ b/index.bs @@ -2888,9 +2888,10 @@ The following abstract operations support the implementation of the 1. Let |elementSize| be |pullIntoDescriptor|'s [=pull-into descriptor/element size=]. 1. Assert: |bytesFilled| ≤ |pullIntoDescriptor|'s [=pull-into descriptor/byte length=]. 1. Assert: |bytesFilled| mod |elementSize| is 0. + 1. Let |buffer| be ! [$TransferArrayBuffer$](|pullIntoDescriptor|'s [=pull-into descriptor/buffer=]). 1. Return ! [$Construct$](|pullIntoDescriptor|'s [=pull-into descriptor/view constructor=], « - |pullIntoDescriptor|'s [=pull-into descriptor/buffer=], |pullIntoDescriptor|'s [=pull-into - descriptor/byte offset=], |bytesFilled| ÷ |elementSize| »). + |buffer|, |pullIntoDescriptor|'s [=pull-into descriptor/byte offset=], + |bytesFilled| ÷ |elementSize| »).
@@ -3190,8 +3191,6 @@ The following abstract operations support the implementation of the descriptor/buffer=], |end| − |remainderSize|, |remainderSize|, {{%ArrayBuffer%}}). 1. Perform ! [$ReadableByteStreamControllerEnqueueChunkToQueue$](|controller|, |remainder|, 0, |remainder|.\[[ByteLength]]). - 1. Set |pullIntoDescriptor|'s [=pull-into descriptor/buffer=] to ! - [$TransferArrayBuffer$](|pullIntoDescriptor|'s [=pull-into descriptor/buffer=]). 1. Set |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] to |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] − |remainderSize|. 1. Perform ! diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index a3617c7a4..e904027a2 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -984,8 +984,8 @@ function ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescripto assert(bytesFilled <= pullIntoDescriptor.byteLength); assert(bytesFilled % elementSize === 0); - return new pullIntoDescriptor.viewConstructor( - pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, bytesFilled / elementSize); + const buffer = TransferArrayBuffer(pullIntoDescriptor.buffer); + return new pullIntoDescriptor.viewConstructor(buffer, pullIntoDescriptor.byteOffset, bytesFilled / elementSize); } function ReadableByteStreamControllerEnqueue(controller, chunk) { @@ -1280,7 +1280,6 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder, 0, remainder.byteLength); } - pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer); pullIntoDescriptor.bytesFilled -= remainderSize; ReadableByteStreamControllerCommitPullIntoDescriptor(controller._stream, pullIntoDescriptor); From 1b28987b815b72b02ec082fb423b2f731fa0b0bb Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 22 Apr 2021 00:24:40 +0200 Subject: [PATCH 25/44] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 9b7f43580..335e356fd 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 9b7f4358098f0aea35eb8de8333ec5b6b6f46446 +Subproject commit 335e356fd4f36541cdd16ed9714ff850d247216b From 1002710d92951338835eec9dc37f1467d30cd2ff Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 24 Apr 2021 00:33:53 +0200 Subject: [PATCH 26/44] Always transfer first pull-into descriptor after enqueue() or respond() --- index.bs | 9 ++++++--- .../lib/abstract-ops/readable-streams.js | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/index.bs b/index.bs index 778f83186..36a1f243b 100644 --- a/index.bs +++ b/index.bs @@ -2922,6 +2922,8 @@ The following abstract operations support the implementation of the |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. 1. If ! [$CanTransferArrayBuffer$](|firstPendingPullInto|'s [=pull-into descriptor/buffer=]) is false, throw a {{TypeError}} exception. + 1. Set |firstPendingPullInto|'s [=pull-into descriptor/buffer=] to ! + [$TransferArrayBuffer$]([=pull-into descriptor/buffer=]). 1. Perform ! [$ReadableByteStreamControllerEnqueueChunkToQueue$](|controller|, |transferredBuffer|, |byteOffset|, |byteLength|). 1. Perform ! [$ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue$](|controller|). @@ -3150,6 +3152,8 @@ The following abstract operations support the implementation of the 1. If |bytesWritten| is 0, throw a {{TypeError}} exception. 1. If |firstDescriptor|'s [=pull-into descriptor/bytes filled=] + |bytesWritten| > |firstDescriptor|'s [=pull-into descriptor/byte length=], throw a {{RangeError}} exception. + 1. Set |firstDescriptor|'s [=pull-into descriptor/buffer=] to ! + [$TransferArrayBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]). 1. Perform ? [$ReadableByteStreamControllerRespondInternal$](|controller|, |bytesWritten|).
@@ -3158,8 +3162,6 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-respond-in-closed-state">ReadableByteStreamControllerRespondInClosedState(|controller|, |firstDescriptor|) performs the following steps: - 1. Set |firstDescriptor|'s [=pull-into descriptor/buffer=] to ! - [$TransferArrayBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]). 1. Assert: |firstDescriptor|'s [=pull-into descriptor/bytes filled=] is 0. 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. 1. If ! [$ReadableStreamHasBYOBReader$](|stream|) is true, @@ -3242,7 +3244,8 @@ The following abstract operations support the implementation of the |view|.\[[ViewedArrayBuffer]].\[[ByteLength]], throw a {{RangeError}} exception. 1. If |firstDescriptor|'s [=pull-into descriptor/bytes filled=] + |view|.\[[ByteLength]] > |firstDescriptor|'s [=pull-into descriptor/byte length=], throw a {{RangeError}} exception. - 1. Set |firstDescriptor|'s [=pull-into descriptor/buffer=] to |view|.\[[ViewedArrayBuffer]]. + 1. Set |firstDescriptor|'s [=pull-into descriptor/buffer=] to ! + [$TransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]). 1. Perform ? [$ReadableByteStreamControllerRespondInternal$](|controller|, |view|.\[[ByteLength]]). diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index e904027a2..15dadaa45 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1017,6 +1017,7 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) { 'The BYOB request\'s buffer has been detached and so cannot be filled with an enqueued chunk' ); } + firstPendingPullInto.buffer = TransferArrayBuffer(firstPendingPullInto.buffer); } // TODO: Ideally in this branch detaching should happen only if the buffer is not consumed fully. @@ -1244,12 +1245,12 @@ function ReadableByteStreamControllerRespond(controller, bytesWritten) { } } + firstDescriptor.buffer = TransferArrayBuffer(firstDescriptor.buffer); + ReadableByteStreamControllerRespondInternal(controller, bytesWritten); } function ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) { - firstDescriptor.buffer = TransferArrayBuffer(firstDescriptor.buffer); - assert(firstDescriptor.bytesFilled === 0); const stream = controller._stream; @@ -1267,7 +1268,6 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor); if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) { - // TODO: Figure out whether we should detach the buffer or not here. return; } @@ -1334,7 +1334,7 @@ function ReadableByteStreamControllerRespondWithNewView(controller, view) { throw new RangeError('The region specified by view is larger than byobRequest'); } - firstDescriptor.buffer = view.buffer; + firstDescriptor.buffer = TransferArrayBuffer(view.buffer); ReadableByteStreamControllerRespondInternal(controller, view.byteLength); } From 458f95c1bbe17d58e3588dedd53c1e8828ae4ed4 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 24 Apr 2021 00:43:22 +0200 Subject: [PATCH 27/44] Move check up a bit --- index.bs | 16 +++++++-------- .../lib/abstract-ops/readable-streams.js | 20 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/index.bs b/index.bs index 36a1f243b..418c56193 100644 --- a/index.bs +++ b/index.bs @@ -2902,6 +2902,14 @@ The following abstract operations support the implementation of the 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. 1. If |controller|.[=ReadableByteStreamController/[[closeRequested]]=] is true or |stream|.[=ReadableStream/[[state]]=] is not "`readable`", return. + 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not + [=list/is empty|empty=], + 1. Let |firstPendingPullInto| be + |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. + 1. If ! [$CanTransferArrayBuffer$](|firstPendingPullInto|'s [=pull-into descriptor/buffer=]) + is false, throw a {{TypeError}} exception. + 1. Set |firstPendingPullInto|'s [=pull-into descriptor/buffer=] to ! + [$TransferArrayBuffer$]([=pull-into descriptor/buffer=]). 1. Let |buffer| be |chunk|.\[[ViewedArrayBuffer]]. 1. Let |byteOffset| be |chunk|.\[[ByteOffset]]. 1. Let |byteLength| be |chunk|.\[[ByteLength]]. @@ -2916,14 +2924,6 @@ The following abstract operations support the implementation of the |byteOffset|, |byteLength| »). 1. Perform ! [$ReadableStreamFulfillReadRequest$](|stream|, |transferredView|, false). 1. Otherwise, if ! [$ReadableStreamHasBYOBReader$](|stream|) is true, - 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not - [=list/is empty|empty=], - 1. Let |firstPendingPullInto| be - |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. If ! [$CanTransferArrayBuffer$](|firstPendingPullInto|'s [=pull-into descriptor/buffer=]) - is false, throw a {{TypeError}} exception. - 1. Set |firstPendingPullInto|'s [=pull-into descriptor/buffer=] to ! - [$TransferArrayBuffer$]([=pull-into descriptor/buffer=]). 1. Perform ! [$ReadableByteStreamControllerEnqueueChunkToQueue$](|controller|, |transferredBuffer|, |byteOffset|, |byteLength|). 1. Perform ! [$ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue$](|controller|). diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 15dadaa45..3bf59d6f8 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -995,6 +995,16 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) { return; } + if (controller._pendingPullIntos.length > 0) { + const firstPendingPullInto = controller._pendingPullIntos[0]; + if (CanTransferArrayBuffer(firstPendingPullInto.buffer) === false) { + throw new TypeError( + 'The BYOB request\'s buffer has been detached and so cannot be filled with an enqueued chunk' + ); + } + firstPendingPullInto.buffer = TransferArrayBuffer(firstPendingPullInto.buffer); + } + const buffer = chunk.buffer; const byteOffset = chunk.byteOffset; const byteLength = chunk.byteLength; @@ -1010,16 +1020,6 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) { ReadableStreamFulfillReadRequest(stream, transferredView, false); } } else if (ReadableStreamHasBYOBReader(stream) === true) { - if (controller._pendingPullIntos.length > 0) { - const firstPendingPullInto = controller._pendingPullIntos[0]; - if (CanTransferArrayBuffer(firstPendingPullInto.buffer) === false) { - throw new TypeError( - 'The BYOB request\'s buffer has been detached and so cannot be filled with an enqueued chunk' - ); - } - firstPendingPullInto.buffer = TransferArrayBuffer(firstPendingPullInto.buffer); - } - // TODO: Ideally in this branch detaching should happen only if the buffer is not consumed fully. ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller); From ea2aa01335d53f3b00ac891ccd202d8b2a3edf68 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 24 Apr 2021 00:52:15 +0200 Subject: [PATCH 28/44] Invalidate BYOB request on every enqueue(), respond() or respondWithNewView() --- index.bs | 6 ++++-- .../lib/abstract-ops/readable-streams.js | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/index.bs b/index.bs index 418c56193..c341e98ae 100644 --- a/index.bs +++ b/index.bs @@ -2910,6 +2910,7 @@ The following abstract operations support the implementation of the is false, throw a {{TypeError}} exception. 1. Set |firstPendingPullInto|'s [=pull-into descriptor/buffer=] to ! [$TransferArrayBuffer$]([=pull-into descriptor/buffer=]). + 1. Perform ! [$ReadableByteStreamControllerInvalidateBYOBRequest$](|controller|). 1. Let |buffer| be |chunk|.\[[ViewedArrayBuffer]]. 1. Let |byteOffset| be |chunk|.\[[ByteOffset]]. 1. Let |byteLength| be |chunk|.\[[ByteLength]]. @@ -2968,7 +2969,7 @@ The following abstract operations support the implementation of the 1. Assert: either |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] [=list/is empty=], or |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0] is |pullIntoDescriptor|. - 1. Perform ! [$ReadableByteStreamControllerInvalidateBYOBRequest$](|controller|). + 1. Assert: |controller|.[=ReadableByteStreamController/[[byobRequest]]=] is null. 1. Set |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] to [=pull-into descriptor/bytes filled=] + |size|. @@ -3208,6 +3209,7 @@ The following abstract operations support the implementation of the 1. Let |firstDescriptor| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. 1. Assert: ! [$CanTransferArrayBuffer$](|firstDescriptor|'s [=pull-into descriptor/buffer=]) is true. + 1. Perform ! [$ReadableByteStreamControllerInvalidateBYOBRequest$](|controller|). 1. Let |state| be |controller|.[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=]. 1. If |state| is "`closed`", @@ -3254,10 +3256,10 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-shift-pending-pull-into">ReadableByteStreamControllerShiftPendingPullInto(|controller|) performs the following steps: + 1. Assert: |controller|.[=ReadableByteStreamController/[[byobRequest]]=] is null. 1. Let |descriptor| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. 1. [=list/Remove=] |descriptor| from |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=]. - 1. Perform ! [$ReadableByteStreamControllerInvalidateBYOBRequest$](|controller|). 1. Return |descriptor|. diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 3bf59d6f8..95753718a 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1005,6 +1005,8 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) { firstPendingPullInto.buffer = TransferArrayBuffer(firstPendingPullInto.buffer); } + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + const buffer = chunk.buffer; const byteOffset = chunk.byteOffset; const byteLength = chunk.byteLength; @@ -1052,8 +1054,7 @@ function ReadableByteStreamControllerError(controller, e) { function ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size, pullIntoDescriptor) { assert(controller._pendingPullIntos.length === 0 || controller._pendingPullIntos[0] === pullIntoDescriptor); - - ReadableByteStreamControllerInvalidateBYOBRequest(controller); + assert(controller._byobRequest === null); pullIntoDescriptor.bytesFilled += size; } @@ -1290,8 +1291,9 @@ function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) { const firstDescriptor = controller._pendingPullIntos[0]; assert(CanTransferArrayBuffer(firstDescriptor.buffer) === true); - const state = controller._stream._state; + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + const state = controller._stream._state; if (state === 'closed') { assert(bytesWritten === 0); ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor); @@ -1340,8 +1342,8 @@ function ReadableByteStreamControllerRespondWithNewView(controller, view) { } function ReadableByteStreamControllerShiftPendingPullInto(controller) { + assert(controller._byobRequest === null); const descriptor = controller._pendingPullIntos.shift(); - ReadableByteStreamControllerInvalidateBYOBRequest(controller); return descriptor; } From 5da8d5c2bfdde4e3ce34ec3e63f4bd3f86922390 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 24 Apr 2021 00:57:34 +0200 Subject: [PATCH 29/44] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 335e356fd..77f6894b5 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 335e356fd4f36541cdd16ed9714ff850d247216b +Subproject commit 77f6894b5ea437a08ad0ec145b5bb2acd64b1a05 From 9382dc3f5cf710ce3e2174cf70063170a2059101 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 May 2021 01:42:28 +0200 Subject: [PATCH 30/44] Make TransferArrayBuffer throw if the given buffer is non-transferable --- index.bs | 4 ++-- reference-implementation/lib/abstract-ops/ecmascript.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index c341e98ae..8d91246f3 100644 --- a/index.bs +++ b/index.bs @@ -6132,10 +6132,10 @@ The following abstract operations are a grab-bag of utilities. TransferArrayBuffer(|O|) performs the following steps: - 1. Assert: ! [$CanTransferArrayBuffer$](|O|) is true. + 1. Assert: ! [$IsDetachedBuffer$](|O|) is false. 1. Let |arrayBufferData| be |O|.\[[ArrayBufferData]]. 1. Let |arrayBufferByteLength| be |O|.\[[ArrayBufferByteLength]]. - 1. Perform ! [$DetachArrayBuffer$](|O|). + 1. Perform ? [$DetachArrayBuffer$](|O|). 1. Return a new {{ArrayBuffer}} object, created in [=the current Realm=], whose \[[ArrayBufferData]] internal slot value is |arrayBufferData| and whose \[[ArrayBufferByteLength]] internal slot value is |arrayBufferByteLength|. diff --git a/reference-implementation/lib/abstract-ops/ecmascript.js b/reference-implementation/lib/abstract-ops/ecmascript.js index 37fbb7a92..f2f3028b9 100644 --- a/reference-implementation/lib/abstract-ops/ecmascript.js +++ b/reference-implementation/lib/abstract-ops/ecmascript.js @@ -15,7 +15,7 @@ exports.CopyDataBlockBytes = (dest, destOffset, src, srcOffset, n) => { // Not implemented correctly exports.TransferArrayBuffer = O => { - assert(exports.CanTransferArrayBuffer(O)); + assert(!exports.IsDetachedBuffer(O)); const transferredIshVersion = O.slice(); // This is specifically to fool tests that test "is transferred" by taking a non-zero-length From 5d2c90af7a3bb86beb5950f05f5c3084e7da6d02 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 May 2021 01:58:11 +0200 Subject: [PATCH 31/44] Add note about transferring WebAssembly.Memory buffers --- index.bs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/index.bs b/index.bs index 8d91246f3..bc919e240 100644 --- a/index.bs +++ b/index.bs @@ -61,6 +61,11 @@ urlPrefix: https://tc39.es/ecma262/; spec: ECMASCRIPT text: Type; url: #sec-ecmascript-data-types-and-values text: TypeError; url: #sec-native-error-types-used-in-this-standard-typeerror; type: exception text: map; url: #sec-array.prototype.map; type: method; for: Array.prototype +urlPrefix: https://webassembly.github.io/spec/js-api/; spec: WASM-JS-API-1 + type: interface + text: WebAssembly.Memory; url: #memory + type: attribute + text: buffer; for: WebAssembly.Memory; url: #dom-memory-buffer url: https://wicg.github.io/compression/#compressionstream; spec: COMPRESSION; type: interface; text: CompressionStream @@ -6136,6 +6141,9 @@ The following abstract operations are a grab-bag of utilities. 1. Let |arrayBufferData| be |O|.\[[ArrayBufferData]]. 1. Let |arrayBufferByteLength| be |O|.\[[ArrayBufferByteLength]]. 1. Perform ? [$DetachArrayBuffer$](|O|). +

This will throw an exception if |O| has an \[[ArrayBufferDetachKey]] + that is not undefined, such as a {{WebAssembly.Memory}}'s {{WebAssembly.Memory/buffer}}. + [[WASM-JS-API-1]]

1. Return a new {{ArrayBuffer}} object, created in [=the current Realm=], whose \[[ArrayBufferData]] internal slot value is |arrayBufferData| and whose \[[ArrayBufferByteLength]] internal slot value is |arrayBufferByteLength|. From c0f3a2de4f176a4d8cb27c4b045e3ee7b5ea5cdc Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 May 2021 23:25:39 +0200 Subject: [PATCH 32/44] Propagate transfer errors in ReadableByteStreamControllerEnqueue --- index.bs | 11 +++++------ .../lib/ReadableByteStreamController-impl.js | 4 ---- .../lib/abstract-ops/readable-streams.js | 15 +++++++++------ 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/index.bs b/index.bs index bc919e240..ba8426ee8 100644 --- a/index.bs +++ b/index.bs @@ -1824,8 +1824,6 @@ for="ReadableByteStreamController">enqueue(|chunk|) method steps are: 1. If |chunk|.\[[ByteLength]] is 0, throw a {{TypeError}} exception. 1. If |chunk|.\[[ViewedArrayBuffer]].\[[ArrayBufferByteLength]] is 0, throw a {{TypeError}} exception. - 1. If ! [$CanTransferArrayBuffer$](|chunk|.\[[ViewedArrayBuffer]]) is false, - throw a {{TypeError}} exception. 1. If [=this=].[=ReadableByteStreamController/[[closeRequested]]=] is true, throw a {{TypeError}} exception. 1. If [=this=].[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=] is not @@ -2907,6 +2905,11 @@ The following abstract operations support the implementation of the 1. Let |stream| be |controller|.[=ReadableByteStreamController/[[stream]]=]. 1. If |controller|.[=ReadableByteStreamController/[[closeRequested]]=] is true or |stream|.[=ReadableStream/[[state]]=] is not "`readable`", return. + 1. Let |buffer| be |chunk|.\[[ViewedArrayBuffer]]. + 1. Let |byteOffset| be |chunk|.\[[ByteOffset]]. + 1. Let |byteLength| be |chunk|.\[[ByteLength]]. + 1. If ! [$IsDetachedBuffer$](|buffer|) is true, throw a {{TypeError}} exception. + 1. Let |transferredBuffer| be ? [$TransferArrayBuffer$](|buffer|). 1. If |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=], 1. Let |firstPendingPullInto| be @@ -2916,10 +2919,6 @@ The following abstract operations support the implementation of the 1. Set |firstPendingPullInto|'s [=pull-into descriptor/buffer=] to ! [$TransferArrayBuffer$]([=pull-into descriptor/buffer=]). 1. Perform ! [$ReadableByteStreamControllerInvalidateBYOBRequest$](|controller|). - 1. Let |buffer| be |chunk|.\[[ViewedArrayBuffer]]. - 1. Let |byteOffset| be |chunk|.\[[ByteOffset]]. - 1. Let |byteLength| be |chunk|.\[[ByteLength]]. - 1. Let |transferredBuffer| be ! [$TransferArrayBuffer$](|buffer|). 1. If ! [$ReadableStreamHasDefaultReader$](|stream|) is true 1. If ! [$ReadableStreamGetNumReadRequests$](|stream|) is 0, 1. Perform ! [$ReadableByteStreamControllerEnqueueChunkToQueue$](|controller|, diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index ddc890cc4..799ea3799 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -1,7 +1,6 @@ 'use strict'; const assert = require('assert'); -const { CanTransferArrayBuffer } = require('./abstract-ops/ecmascript.js'); const { CancelSteps, PullSteps } = require('./abstract-ops/internal-methods.js'); const { ResetQueue } = require('./abstract-ops/queue-with-sizes.js'); const aos = require('./abstract-ops/readable-streams.js'); @@ -49,9 +48,6 @@ exports.implementation = class ReadableByteStreamControllerImpl { if (chunk.buffer.byteLength === 0) { throw new TypeError('chunk\'s buffer must have non-zero byteLength'); } - if (CanTransferArrayBuffer(chunk.buffer) === false) { - throw new TypeError('chunk\'s buffer is not transferable and so cannot be enqueued'); - } if (this._closeRequested === true) { throw new TypeError('stream is closed or draining'); diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 95753718a..e175374a7 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -4,7 +4,7 @@ const assert = require('assert'); const { promiseResolvedWith, promiseRejectedWith, newPromise, resolvePromise, rejectPromise, uponPromise, setPromiseIsHandledToTrue, waitForAllPromise, transformPromiseWith, uponFulfillment, uponRejection } = require('../helpers/webidl.js'); -const { CanTransferArrayBuffer, CopyDataBlockBytes, CreateArrayFromList, TransferArrayBuffer } = +const { CanTransferArrayBuffer, CopyDataBlockBytes, CreateArrayFromList, IsDetachedBuffer, TransferArrayBuffer } = require('./ecmascript.js'); const { IsNonNegativeNumber } = require('./miscellaneous.js'); const { EnqueueValueWithSize, ResetQueue } = require('./queue-with-sizes.js'); @@ -995,6 +995,14 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) { return; } + const buffer = chunk.buffer; + const byteOffset = chunk.byteOffset; + const byteLength = chunk.byteLength; + if (IsDetachedBuffer(buffer) === true) { + throw new TypeError('chunk\'s buffer is detached and so cannot be enqueued'); + } + const transferredBuffer = TransferArrayBuffer(buffer); + if (controller._pendingPullIntos.length > 0) { const firstPendingPullInto = controller._pendingPullIntos[0]; if (CanTransferArrayBuffer(firstPendingPullInto.buffer) === false) { @@ -1007,11 +1015,6 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) { ReadableByteStreamControllerInvalidateBYOBRequest(controller); - const buffer = chunk.buffer; - const byteOffset = chunk.byteOffset; - const byteLength = chunk.byteLength; - const transferredBuffer = TransferArrayBuffer(buffer); - if (ReadableStreamHasDefaultReader(stream) === true) { if (ReadableStreamGetNumReadRequests(stream) === 0) { ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); From 1a20a2780766944f9d85dea46e913a0c3a37c8d5 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 May 2021 23:30:03 +0200 Subject: [PATCH 33/44] Propagate transfer errors in ReadableByteStreamControllerRespond --- index.bs | 4 ++-- .../lib/ReadableStreamBYOBRequest-impl.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index ba8426ee8..98ec4e9f4 100644 --- a/index.bs +++ b/index.bs @@ -1977,8 +1977,8 @@ following table: 1. If [=this=].[=ReadableStreamBYOBRequest/[[controller]]=] is undefined, throw a {{TypeError}} exception. - 1. If ! [$CanTransferArrayBuffer$]([=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ArrayBuffer]]) - is false, throw a {{TypeError}} exception. + 1. If ! [$IsDetachedBuffer$]([=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ArrayBuffer]]) + is true, throw a {{TypeError}} exception. 1. Assert: [=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ByteLength]] > 0. 1. Assert: [=this=].[=ReadableStreamBYOBRequest/[[view]]=].\[[ViewedArrayBuffer]].\[[ByteLength]] > 0. diff --git a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js index aaee5be45..34a6c43c8 100644 --- a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js @@ -1,7 +1,7 @@ 'use strict'; const assert = require('assert'); -const { CanTransferArrayBuffer } = require('./abstract-ops/ecmascript.js'); +const { CanTransferArrayBuffer, IsDetachedBuffer } = require('./abstract-ops/ecmascript.js'); const aos = require('./abstract-ops/readable-streams.js'); exports.implementation = class ReadableStreamBYOBRequestImpl { @@ -14,7 +14,7 @@ exports.implementation = class ReadableStreamBYOBRequestImpl { throw new TypeError('This BYOB request has been invalidated'); } - if (CanTransferArrayBuffer(this._view.buffer) === false) { + if (IsDetachedBuffer(this._view.buffer) === true) { throw new TypeError('The BYOB request\'s buffer has been detached and so cannot be used as a response'); } From 0b7850c8decf46a07eae39099e7203bd3a52ae6d Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 May 2021 23:34:23 +0200 Subject: [PATCH 34/44] Propagate transfer errors in ReadableByteStreamControllerRespondWithNewView --- index.bs | 6 +++--- .../lib/ReadableStreamBYOBRequest-impl.js | 6 +++--- .../lib/abstract-ops/readable-streams.js | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/index.bs b/index.bs index 98ec4e9f4..bc1017722 100644 --- a/index.bs +++ b/index.bs @@ -1993,7 +1993,7 @@ following table: 1. If [=this=].[=ReadableStreamBYOBRequest/[[controller]]=] is undefined, throw a {{TypeError}} exception. - 1. If ! [$CanTransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]) is false, + 1. If ! [$IsDetachedBuffer$](|view|.\[[ViewedArrayBuffer]]) is true, throw a {{TypeError}} exception. 1. Return ? [$ReadableByteStreamControllerRespondWithNewView$]([=this=].[=ReadableStreamBYOBRequest/[[controller]]=], @@ -3235,7 +3235,7 @@ The following abstract operations support the implementation of the 1. Assert: |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is empty|empty=]. - 1. Assert: ! [$CanTransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]) is true. + 1. Assert: ! [$IsDetachedBuffer$](|view|.\[[ViewedArrayBuffer]]) is false. 1. Let |firstDescriptor| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. 1. Let |state| be |controller|.[=ReadableByteStreamController/[[stream]]=].[=ReadableStream/[[state]]=]. @@ -3250,7 +3250,7 @@ The following abstract operations support the implementation of the |view|.\[[ViewedArrayBuffer]].\[[ByteLength]], throw a {{RangeError}} exception. 1. If |firstDescriptor|'s [=pull-into descriptor/bytes filled=] + |view|.\[[ByteLength]] > |firstDescriptor|'s [=pull-into descriptor/byte length=], throw a {{RangeError}} exception. - 1. Set |firstDescriptor|'s [=pull-into descriptor/buffer=] to ! + 1. Set |firstDescriptor|'s [=pull-into descriptor/buffer=] to ? [$TransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]). 1. Perform ? [$ReadableByteStreamControllerRespondInternal$](|controller|, |view|.\[[ByteLength]]). diff --git a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js index 34a6c43c8..6fa50f7f9 100644 --- a/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBRequest-impl.js @@ -1,7 +1,7 @@ 'use strict'; const assert = require('assert'); -const { CanTransferArrayBuffer, IsDetachedBuffer } = require('./abstract-ops/ecmascript.js'); +const { IsDetachedBuffer } = require('./abstract-ops/ecmascript.js'); const aos = require('./abstract-ops/readable-streams.js'); exports.implementation = class ReadableStreamBYOBRequestImpl { @@ -29,8 +29,8 @@ exports.implementation = class ReadableStreamBYOBRequestImpl { throw new TypeError('This BYOB request has been invalidated'); } - if (CanTransferArrayBuffer(view.buffer) === false) { - throw new TypeError('The given view\'s buffer is not transferable and so cannot be used as a response'); + if (IsDetachedBuffer(view.buffer) === true) { + throw new TypeError('The given view\'s buffer has been detached and so cannot be used as a response'); } aos.ReadableByteStreamControllerRespondWithNewView(this._controller, view); diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index e175374a7..d4445690f 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1311,7 +1311,7 @@ function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) { function ReadableByteStreamControllerRespondWithNewView(controller, view) { assert(controller._pendingPullIntos.length > 0); - assert(CanTransferArrayBuffer(view.buffer) === true); + assert(IsDetachedBuffer(view.buffer) === false); const firstDescriptor = controller._pendingPullIntos[0]; const state = controller._stream._state; From 17d1c2def40b0c7ddbc41672c305c0c30762a161 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 May 2021 23:36:49 +0200 Subject: [PATCH 35/44] Relax check in ReadableByteStreamControllerEnqueue --- index.bs | 4 ++-- reference-implementation/lib/abstract-ops/readable-streams.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index bc1017722..40962e263 100644 --- a/index.bs +++ b/index.bs @@ -2914,8 +2914,8 @@ The following abstract operations support the implementation of the [=list/is empty|empty=], 1. Let |firstPendingPullInto| be |controller|.[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. If ! [$CanTransferArrayBuffer$](|firstPendingPullInto|'s [=pull-into descriptor/buffer=]) - is false, throw a {{TypeError}} exception. + 1. If ! [$IsDetachedBuffer$](|firstPendingPullInto|'s [=pull-into descriptor/buffer=]) + is true, throw a {{TypeError}} exception. 1. Set |firstPendingPullInto|'s [=pull-into descriptor/buffer=] to ! [$TransferArrayBuffer$]([=pull-into descriptor/buffer=]). 1. Perform ! [$ReadableByteStreamControllerInvalidateBYOBRequest$](|controller|). diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index d4445690f..d26a2a6ed 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1005,7 +1005,7 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) { if (controller._pendingPullIntos.length > 0) { const firstPendingPullInto = controller._pendingPullIntos[0]; - if (CanTransferArrayBuffer(firstPendingPullInto.buffer) === false) { + if (IsDetachedBuffer(firstPendingPullInto.buffer) === true) { throw new TypeError( 'The BYOB request\'s buffer has been detached and so cannot be filled with an enqueued chunk' ); From 78d4a1a99c152787a1e9278688238cc78d215321 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Tue, 18 May 2021 23:49:58 +0200 Subject: [PATCH 36/44] Propagate transfer errors in ReadableByteStreamControllerPullInto --- index.bs | 8 ++++++-- .../lib/ReadableStreamBYOBReader-impl.js | 6 +++--- .../lib/abstract-ops/readable-streams.js | 9 ++++++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/index.bs b/index.bs index 40962e263..3dd254bb4 100644 --- a/index.bs +++ b/index.bs @@ -1402,7 +1402,7 @@ value: newViewOnSameMemory, done: true } for closed streams, instead of t 1. If |view|.\[[ByteLength]] is 0, return [=a promise rejected with=] a {{TypeError}} exception. 1. If |view|.\[[ViewedArrayBuffer]].\[[ArrayBufferByteLength]] is 0, return [=a promise rejected with=] a {{TypeError}} exception. - 1. If ! [$CanTransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]) is false, return + 1. If ! [$IsDetachedBuffer$](|view|.\[[ViewedArrayBuffer]]) is true, return [=a promise rejected with=] a {{TypeError}} exception. 1. If [=this=].[=ReadableStreamGenericReader/[[stream]]=] is undefined, return [=a promise rejected with=] a {{TypeError}} exception. @@ -3105,7 +3105,11 @@ The following abstract operations support the implementation of the |view|.\[[TypedArrayName]]. 1. Let |byteOffset| be |view|.\[[ByteOffset]]. 1. Let |byteLength| be |view|.\[[ByteLength]]. - 1. Let |buffer| be ! [$TransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]). + 1. Let |bufferResult| be [$TransferArrayBuffer$](|view|.\[[ViewedArrayBuffer]]). + 1. If |bufferResult| is an abrupt completion, + 1. Perform |readIntoRequest|'s [=read-into request/error steps=], given |bufferResult|.\[[Value]]. + 1. Return. + 1. Let |buffer| be |bufferResult|.\[[Value]]. 1. Let |pullIntoDescriptor| be a new [=pull-into descriptor=] with [=pull-into descriptor/buffer=] |buffer|, [=pull-into descriptor/buffer byte length=] |buffer|.\[[ArrayBufferByteLength]], [=pull-into descriptor/byte offset=] |byteOffset|, [=pull-into descriptor/byte length=] diff --git a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js index 4f87cbc6d..fe605ea14 100644 --- a/reference-implementation/lib/ReadableStreamBYOBReader-impl.js +++ b/reference-implementation/lib/ReadableStreamBYOBReader-impl.js @@ -1,7 +1,7 @@ 'use strict'; const { newPromise, resolvePromise, rejectPromise, promiseRejectedWith } = require('./helpers/webidl.js'); -const { CanTransferArrayBuffer } = require('./abstract-ops/ecmascript.js'); +const { IsDetachedBuffer } = require('./abstract-ops/ecmascript.js'); const aos = require('./abstract-ops/readable-streams.js'); const { mixin } = require('./helpers/miscellaneous.js'); const ReadableStreamGenericReaderImpl = require('./ReadableStreamGenericReader-impl.js').implementation; @@ -18,8 +18,8 @@ class ReadableStreamBYOBReaderImpl { if (view.buffer.byteLength === 0) { return promiseRejectedWith(new TypeError('view\'s buffer must have non-zero byteLength')); } - if (CanTransferArrayBuffer(view.buffer) === false) { - return promiseRejectedWith(new TypeError('view\'s buffer is not transferable')); + if (IsDetachedBuffer(view.buffer) === true) { + return promiseRejectedWith(new TypeError('view\'s buffer has been detached')); } if (this._stream === undefined) { diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index d26a2a6ed..988519581 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -1175,7 +1175,14 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) const ctor = view.constructor; - const buffer = TransferArrayBuffer(view.buffer); + let buffer; + try { + buffer = TransferArrayBuffer(view.buffer); + } catch (e) { + readIntoRequest.errorSteps(e); + return; + } + const pullIntoDescriptor = { buffer, bufferByteLength: buffer.byteLength, From 0ab00d17a251083b12bfae3bf23e442d9d67d989 Mon Sep 17 00:00:00 2001 From: Mattias Buelens <649348+MattiasBuelens@users.noreply.github.com> Date: Wed, 19 May 2021 22:23:48 +0200 Subject: [PATCH 37/44] =?UTF-8?q?Use=20=E2=89=A4=20instead=20of=20<=3D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Domenic Denicola --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 3dd254bb4..fa290151d 100644 --- a/index.bs +++ b/index.bs @@ -3186,7 +3186,7 @@ The following abstract operations support the implementation of the id="readable-byte-stream-controller-respond-in-readable-state">ReadableByteStreamControllerRespondInReadableState(|controller|, |bytesWritten|, |pullIntoDescriptor|) performs the following steps: - 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] + |bytesWritten| <= + 1. Assert: |pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=] + |bytesWritten| ≤ |pullIntoDescriptor|'s [=pull-into descriptor/byte length=]. 1. Perform ! [$ReadableByteStreamControllerFillHeadPullIntoDescriptor$](|controller|, |bytesWritten|, |pullIntoDescriptor|). From 01b7779b3226e56f651e79abc5e15f43118ad499 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 19 May 2021 22:30:07 +0200 Subject: [PATCH 38/44] Fix link to WebAssembly.Memory --- index.bs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index fa290151d..8f9e66d4c 100644 --- a/index.bs +++ b/index.bs @@ -63,9 +63,9 @@ urlPrefix: https://tc39.es/ecma262/; spec: ECMASCRIPT text: map; url: #sec-array.prototype.map; type: method; for: Array.prototype urlPrefix: https://webassembly.github.io/spec/js-api/; spec: WASM-JS-API-1 type: interface - text: WebAssembly.Memory; url: #memory + text: Memory; url: #memory type: attribute - text: buffer; for: WebAssembly.Memory; url: #dom-memory-buffer + text: buffer; for: Memory; url: #dom-memory-buffer url: https://wicg.github.io/compression/#compressionstream; spec: COMPRESSION; type: interface; text: CompressionStream @@ -6145,7 +6145,7 @@ The following abstract operations are a grab-bag of utilities. 1. Let |arrayBufferByteLength| be |O|.\[[ArrayBufferByteLength]]. 1. Perform ? [$DetachArrayBuffer$](|O|).

This will throw an exception if |O| has an \[[ArrayBufferDetachKey]] - that is not undefined, such as a {{WebAssembly.Memory}}'s {{WebAssembly.Memory/buffer}}. + that is not undefined, such as a {{Memory|WebAssembly.Memory}}'s {{Memory/buffer}}. [[WASM-JS-API-1]]

1. Return a new {{ArrayBuffer}} object, created in [=the current Realm=], whose \[[ArrayBufferData]] internal slot value is |arrayBufferData| and whose From bf4e8a3fc2a22c33f826f4fd2dd38e6ec101782a Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 19 May 2021 22:59:11 +0200 Subject: [PATCH 39/44] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 77f6894b5..a414e58ad 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 77f6894b5ea437a08ad0ec145b5bb2acd64b1a05 +Subproject commit a414e58ad4204941d4582082235b905b9be0e16e From fb8d710b11ae51fd04bda1c0e97e4988859975dc Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 19 May 2021 22:59:32 +0200 Subject: [PATCH 40/44] Ignore tests with non-transferable buffers --- reference-implementation/run-web-platform-tests.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/reference-implementation/run-web-platform-tests.js b/reference-implementation/run-web-platform-tests.js index d58969901..7c0e01d96 100644 --- a/reference-implementation/run-web-platform-tests.js +++ b/reference-implementation/run-web-platform-tests.js @@ -33,6 +33,11 @@ async function main() { const testsPath = path.resolve(wptPath, 'streams'); const filterGlobs = process.argv.length >= 3 ? process.argv.slice(2) : ['**/*.html']; + const excludeGlobs = [ + // These tests use ArrayBuffers backed by WebAssembly.Memory objects, which *should* be non-transferable. + // However, our TransferArrayBuffer implementation cannot detect these, and will incorrectly "transfer" them anyway. + 'readable-byte-streams/non-transferable-buffers.any.html' + ]; const anyTestPattern = /\.any\.html$/; const bundledJS = await bundle(entryPath); @@ -61,7 +66,8 @@ async function main() { return false; } - return filterGlobs.some(glob => minimatch(testPath, glob)); + return filterGlobs.some(glob => minimatch(testPath, glob)) && + !excludeGlobs.some(glob => minimatch(testPath, glob)); } }); From 5d0f3ab06d510dc1f47d22e9d1bcdab50e73ad7a Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Fri, 21 May 2021 00:09:33 +0200 Subject: [PATCH 41/44] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index a414e58ad..473ec364c 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit a414e58ad4204941d4582082235b905b9be0e16e +Subproject commit 473ec364ca7f450ab4b708ee2ca8417f30b4f0cc From c50c9bcfc2a1f397322ba4d6202e82a91d632a76 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Fri, 21 May 2021 00:11:33 +0200 Subject: [PATCH 42/44] Fix typo --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 8f9e66d4c..8e1e3f6ec 100644 --- a/index.bs +++ b/index.bs @@ -2917,7 +2917,7 @@ The following abstract operations support the implementation of the 1. If ! [$IsDetachedBuffer$](|firstPendingPullInto|'s [=pull-into descriptor/buffer=]) is true, throw a {{TypeError}} exception. 1. Set |firstPendingPullInto|'s [=pull-into descriptor/buffer=] to ! - [$TransferArrayBuffer$]([=pull-into descriptor/buffer=]). + [$TransferArrayBuffer$](|firstPendingPullInto|'s [=pull-into descriptor/buffer=]). 1. Perform ! [$ReadableByteStreamControllerInvalidateBYOBRequest$](|controller|). 1. If ! [$ReadableStreamHasDefaultReader$](|stream|) is true 1. If ! [$ReadableStreamGetNumReadRequests$](|stream|) is 0, From 30b3f50c95c16343b3f16aeb45424fe53945628d Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sat, 22 May 2021 01:44:49 +0200 Subject: [PATCH 43/44] Add note about respondWithNewView --- index.bs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/index.bs b/index.bs index 8e1e3f6ec..3f1341d17 100644 --- a/index.bs +++ b/index.bs @@ -1960,6 +1960,13 @@ following table: {{ReadableStreamBYOBRequest/view}}, the [=underlying byte source=] is providing a new {{ArrayBufferView}}, which will be given to the [=consumer=] of the [=readable byte stream=]. +

The new |view| has to be a view onto the same backing memory region as + {{ReadableStreamBYOBRequest/view}}, i.e. its buffer has to equal (or be a + transferred version of) {{ReadableStreamBYOBRequest/view}}'s + buffer. Its byteOffset has to equal {{ReadableStreamBYOBRequest/view}}'s + byteOffset, and its byteLength (representing the number of bytes written) + has to be less than or equal to that of {{ReadableStreamBYOBRequest/view}}. +

After this method is called, view will be transferred and no longer modifiable. From b22d61fcbc6b2d4f3f52a8347d78b7a640d4129b Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Wed, 26 May 2021 18:22:12 +0200 Subject: [PATCH 44/44] Roll WPT --- reference-implementation/web-platform-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 473ec364c..7b29ee36c 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 473ec364ca7f450ab4b708ee2ca8417f30b4f0cc +Subproject commit 7b29ee36cc22bdad06b4f98df73358ca959fe0a7