From 6a0a266a06fc583383d45816b276b1e2f0520761 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Thu, 21 Sep 2023 21:56:03 +0200 Subject: [PATCH 01/21] perf(ext/streams): optimize async iterator --- ext/web/06_streams.js | 57 +++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 7f43d3fc274abe..37711dfba17320 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -4734,6 +4734,32 @@ const asyncIteratorPrototype = ObjectGetPrototypeOf(AsyncGeneratorPrototype); const _iteratorNext = Symbol("[[iteratorNext]]"); const _iteratorFinished = Symbol("[[iteratorFinished]]"); +class ReadableStreamAsyncIteratorReadRequest { + constructor(reader, promise) { + this.reader = reader; + this.promise = promise; + } + + chunkSteps(chunk) { + this.reader[_iteratorNext] = null; + this.promise.resolve({ value: chunk, done: false }); + } + + closeSteps() { + this.reader[_iteratorNext] = null; + this.reader[_iteratorFinished] = true; + readableStreamDefaultReaderRelease(this.reader); + this.promise.resolve({ value: undefined, done: true }); + } + + errorSteps(e) { + this.reader[_iteratorNext] = null; + this.reader[_iteratorFinished] = true; + readableStreamDefaultReaderRelease(this.reader); + this.promise.reject(e); + } +} + /** @type {AsyncIterator} */ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ /** @returns {Promise>} */ @@ -4755,34 +4781,13 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ /** @type {Deferred>} */ const promise = new Deferred(); - /** @type {ReadRequest} */ - const readRequest = { - chunkSteps(chunk) { - promise.resolve({ value: chunk, done: false }); - }, - closeSteps() { - readableStreamDefaultReaderRelease(reader); - promise.resolve({ value: undefined, done: true }); - }, - errorSteps(e) { - readableStreamDefaultReaderRelease(reader); - promise.reject(e); - }, - }; + const readRequest = new ReadableStreamAsyncIteratorReadRequest( + reader, + promise, + ); readableStreamDefaultReaderRead(reader, readRequest); - return PromisePrototypeThen(promise.promise, (result) => { - reader[_iteratorNext] = null; - if (result.done === true) { - reader[_iteratorFinished] = true; - return { value: undefined, done: true }; - } - return result; - }, (reason) => { - reader[_iteratorNext] = null; - reader[_iteratorFinished] = true; - throw reason; - }); + return PromisePrototypeThen(promise.promise); } reader[_iteratorNext] = reader[_iteratorNext] From 7c8495ae77c7f0084c2fb4cbb532824339e2f76f Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sun, 17 Sep 2023 19:14:30 +0200 Subject: [PATCH 02/21] perf(ext/streams): optimize streams --- ext/web/06_streams.js | 108 ++++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 45 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 37711dfba17320..7ac1cb41a3e00b 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -218,6 +218,45 @@ function uponPromise(promise, onFulfilled, onRejected) { ); } +class Queue { + head = null; + tail = null; + size = 0; + + enqueue(value) { + const node = { value, next: null }; + if (!this.head) { + this.head = node; + this.tail = node; + } else { + this.tail.next = node; + this.tail = node; + } + return ++this.size; + } + + dequeue() { + if (!this.head) { + return null; + } + const node = this.head; + if (this.head === this.tail) { + this.tail = null; + } + this.head = this.head.next; + this.size--; + return node.value; + } + + peek() { + if (!this.head) { + return null; + } + + return this.head.value; + } +} + /** * @param {ArrayBufferLike} O * @returns {boolean} @@ -454,19 +493,15 @@ function createWritableStream( * @returns {T} */ function dequeueValue(container) { - assert( - ReflectHas(container, _queue) && - ReflectHas(container, _queueTotalSize), - ); - assert(container[_queue].length); - const valueWithSize = ArrayPrototypeShift(container[_queue]); + assert(container[_queue] && typeof container[_queueTotalSize] === "number"); + assert(container[_queue].size); + const valueWithSize = container[_queue].dequeue(); container[_queueTotalSize] -= valueWithSize.size; if (container[_queueTotalSize] < 0) { container[_queueTotalSize] = 0; } return valueWithSize.value; } - /** * @template T * @param {{ [_queue]: Array>, [_queueTotalSize]: number }} container @@ -475,17 +510,14 @@ function dequeueValue(container) { * @returns {void} */ function enqueueValueWithSize(container, value, size) { - assert( - ReflectHas(container, _queue) && - ReflectHas(container, _queueTotalSize), - ); + assert(container[_queue] && typeof container[_queueTotalSize] === "number"); if (isNonNegativeNumber(size) === false) { throw RangeError("chunk size isn't a positive number"); } if (size === Infinity) { throw RangeError("chunk size is invalid"); } - ArrayPrototypePush(container[_queue], { value, size }); + container[_queue].enqueue({ value, size }); container[_queueTotalSize] += size; } @@ -646,16 +678,7 @@ function initializeWritableStream(stream) { * @returns {v is number} */ function isNonNegativeNumber(v) { - if (typeof v !== "number") { - return false; - } - if (NumberIsNaN(v)) { - return false; - } - if (v < 0) { - return false; - } - return true; + return typeof v === "number" && v >= 0; } /** @@ -663,8 +686,7 @@ function isNonNegativeNumber(v) { * @returns {value is ReadableStream} */ function isReadableStream(value) { - return !(typeof value !== "object" || value === null || - !ReflectHas(value, _controller)); + return !(typeof value !== "object" || value === null || !value[_controller]); } /** @@ -684,7 +706,7 @@ function isReadableStreamLocked(stream) { */ function isReadableStreamDefaultReader(value) { return !(typeof value !== "object" || value === null || - !ReflectHas(value, _readRequests)); + !value[_readRequests]); } /** @@ -1173,11 +1195,11 @@ function isWritableStreamLocked(stream) { */ function peekQueueValue(container) { assert( - ReflectHas(container, _queue) && - ReflectHas(container, _queueTotalSize), + container[_queue] && + typeof container[_queueTotalSize] === "number", ); - assert(container[_queue].length); - const valueWithSize = container[_queue][0]; + assert(container[_queue].size); + const valueWithSize = container[_queue].peek(); return valueWithSize.value; } @@ -1347,7 +1369,7 @@ function readableByteStreamControllerEnqueue(controller, chunk) { byteLength, ); } else { - assert(controller[_queue].length === 0); + assert(controller[_queue].size === 0); if (controller[_pendingPullIntos].length !== 0) { assert(controller[_pendingPullIntos][0].readerType === "default"); readableByteStreamControllerShiftPendingPullInto(controller); @@ -1394,7 +1416,7 @@ function readableByteStreamControllerEnqueueChunkToQueue( byteOffset, byteLength, ) { - ArrayPrototypePush(controller[_queue], { buffer, byteOffset, byteLength }); + controller[_queue].enqueue({ buffer, byteOffset, byteLength }); controller[_queueTotalSize] += byteLength; } @@ -1504,7 +1526,7 @@ function readableByteStreamControllerGetDesiredSize(controller) { * @returns {void} */ function resetQueue(container) { - container[_queue] = []; + container[_queue] = new Queue(); container[_queueTotalSize] = 0; } @@ -1676,11 +1698,7 @@ function readableStreamDefaultControllerCallPullIfNeeded(controller) { */ function readableStreamDefaultControllerCanCloseOrEnqueue(controller) { const state = controller[_stream][_state]; - if (controller[_closeRequested] === false && state === "readable") { - return true; - } else { - return false; - } + return controller[_closeRequested] === false && state === "readable"; } /** @param {ReadableStreamDefaultController} controller */ @@ -1699,7 +1717,7 @@ function readableStreamDefaultControllerClose(controller) { } const stream = controller[_stream]; controller[_closeRequested] = true; - if (controller[_queue].length === 0) { + if (controller[_queue].size === 0) { readableStreamDefaultControllerClearAlgorithms(controller); readableStreamClose(stream); } @@ -2326,7 +2344,7 @@ function readableByteStreamControllerFillPullIntoDescriptorFromQueue( } const queue = controller[_queue]; while (totalBytesToCopyRemaining > 0) { - const headOfQueue = queue[0]; + const headOfQueue = queue.peek(); const bytesToCopy = MathMin( totalBytesToCopyRemaining, // deno-lint-ignore prefer-primordials @@ -2353,7 +2371,7 @@ function readableByteStreamControllerFillPullIntoDescriptorFromQueue( // deno-lint-ignore prefer-primordials if (headOfQueue.byteLength === bytesToCopy) { - ArrayPrototypeShift(queue); + queue.dequeue(); } else { headOfQueue.byteOffset += bytesToCopy; headOfQueue.byteLength -= bytesToCopy; @@ -2384,7 +2402,7 @@ function readableByteStreamControllerFillReadRequestFromQueue( readRequest, ) { assert(controller[_queueTotalSize] > 0); - const entry = ArrayPrototypeShift(controller[_queue]); + const entry = controller[_queue].dequeue(); // deno-lint-ignore prefer-primordials controller[_queueTotalSize] -= entry.byteLength; readableByteStreamControllerHandleQueueDrain(controller); @@ -4244,7 +4262,7 @@ function writableStreamDefaultControllerAdvanceQueueIfNeeded(controller) { writableStreamFinishErroring(stream); return; } - if (controller[_queue].length === 0) { + if (controller[_queue].size === 0) { return; } const value = peekQueueValue(controller); @@ -4330,7 +4348,7 @@ function writableStreamDefaultControllerProcessClose(controller) { const stream = controller[_stream]; writableStreamMarkCloseRequestInFlight(stream); dequeueValue(controller); - assert(controller[_queue].length === 0); + assert(controller[_queue].size === 0); const sinkClosePromise = controller[_closeAlgorithm](); writableStreamDefaultControllerClearAlgorithms(controller); uponPromise(sinkClosePromise, () => { @@ -5869,9 +5887,9 @@ class ReadableStreamDefaultController { */ [_pullSteps](readRequest) { const stream = this[_stream]; - if (this[_queue].length) { + if (this[_queue].size) { const chunk = dequeueValue(this); - if (this[_closeRequested] && this[_queue].length === 0) { + if (this[_closeRequested] && this[_queue].size === 0) { readableStreamDefaultControllerClearAlgorithms(this); readableStreamClose(stream); } else { From 2c92dd4cadc567fc7eb89330dddd100e1b2c70ca Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 15:31:39 +0200 Subject: [PATCH 03/21] perf: use PromiseResolve instead of PromiseResolveWith --- ext/web/06_streams.js | 57 ++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 7ac1cb41a3e00b..7f613f391fd573 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -143,15 +143,6 @@ class Deferred { } } -/** - * @template T - * @param {T | PromiseLike} value - * @returns {Promise} - */ -function resolvePromiseWith(value) { - return new Promise((resolve) => resolve(value)); -} - /** @param {any} e */ function rethrowAssertionErrorRejection(e) { if (e && ObjectPrototypeIsPrototypeOf(AssertionError.prototype, e)) { @@ -642,7 +633,7 @@ function initializeTransformStream( function cancelAlgorithm(reason) { transformStreamErrorWritableAndUnblockWrite(stream, reason); - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); } stream[_readable] = createReadableStream( @@ -1609,7 +1600,7 @@ function readableStreamAddReadIntoRequest(stream, readRequest) { function readableStreamCancel(stream, reason) { stream[_disturbed] = true; if (stream[_state] === "closed") { - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); } if (stream[_state] === "errored") { return PromiseReject(stream[_storedError]); @@ -2639,7 +2630,7 @@ function readableStreamPipeTo( const writer = acquireWritableStreamDefaultWriter(dest); source[_disturbed] = true; let shuttingDown = false; - let currentWrite = resolvePromiseWith(undefined); + let currentWrite = PromiseResolve(undefined); /** @type {Deferred} */ const promise = new Deferred(); /** @type {() => void} */ @@ -2654,7 +2645,7 @@ function readableStreamPipeTo( if (dest[_state] === "writable") { return writableStreamAbort(dest, error); } else { - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); } }); } @@ -2663,7 +2654,7 @@ function readableStreamPipeTo( if (source[_state] === "readable") { return readableStreamCancel(source, error); } else { - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); } }); } @@ -2698,7 +2689,7 @@ function readableStreamPipeTo( /** @returns {Promise} */ function pipeStep() { if (shuttingDown === true) { - return resolvePromiseWith(true); + return PromiseResolve(true); } return transformPromiseWith(writer[_readyPromise].promise, () => { @@ -3015,7 +3006,7 @@ function readableStreamDefaultTee(stream, cloneForBranch2) { function pullAlgorithm() { if (reading === true) { readAgain = true; - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); } reading = true; /** @type {ReadRequest} */ @@ -3091,7 +3082,7 @@ function readableStreamDefaultTee(stream, cloneForBranch2) { }, }; readableStreamDefaultReaderRead(reader, readRequest); - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); } /** @@ -3476,7 +3467,7 @@ function setUpReadableByteStreamController( controller[_pendingPullIntos] = []; stream[_controller] = controller; const startResult = startAlgorithm(); - const startPromise = resolvePromiseWith(startResult); + const startPromise = PromiseResolve(startResult); setPromiseIsHandledToTrue( PromisePrototypeThen( startPromise, @@ -3509,9 +3500,9 @@ function setUpReadableByteStreamControllerFromUnderlyingSource( /** @type {() => void} */ let startAlgorithm = () => undefined; /** @type {() => Promise} */ - let pullAlgorithm = () => resolvePromiseWith(undefined); + let pullAlgorithm = () => PromiseResolve(undefined); /** @type {(reason: any) => Promise} */ - let cancelAlgorithm = (_reason) => resolvePromiseWith(undefined); + let cancelAlgorithm = (_reason) => PromiseResolve(undefined); if (underlyingSourceDict.start !== undefined) { startAlgorithm = () => webidl.invokeCallbackFunction( @@ -3592,7 +3583,7 @@ function setUpReadableStreamDefaultController( controller[_cancelAlgorithm] = cancelAlgorithm; stream[_controller] = controller; const startResult = startAlgorithm(controller); - const startPromise = resolvePromiseWith(startResult); + const startPromise = PromiseResolve(startResult); uponPromise(startPromise, () => { controller[_started] = true; assert(controller[_pulling] === false); @@ -3622,9 +3613,9 @@ function setUpReadableStreamDefaultControllerFromUnderlyingSource( /** @type {() => Promise} */ let startAlgorithm = () => undefined; /** @type {() => Promise} */ - let pullAlgorithm = () => resolvePromiseWith(undefined); + let pullAlgorithm = () => PromiseResolve(undefined); /** @type {(reason?: any) => Promise} */ - let cancelAlgorithm = () => resolvePromiseWith(undefined); + let cancelAlgorithm = () => PromiseResolve(undefined); if (underlyingSourceDict.start !== undefined) { startAlgorithm = () => webidl.invokeCallbackFunction( @@ -3744,10 +3735,10 @@ function setUpTransformStreamDefaultControllerFromTransformer( } catch (e) { return PromiseReject(e); } - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); }; /** @type {(controller: TransformStreamDefaultController) => Promise} */ - let flushAlgorithm = () => resolvePromiseWith(undefined); + let flushAlgorithm = () => PromiseResolve(undefined); if (transformerDict.transform !== undefined) { transformAlgorithm = (chunk, controller) => webidl.invokeCallbackFunction( @@ -3816,7 +3807,7 @@ function setUpWritableStreamDefaultController( ); writableStreamUpdateBackpressure(stream, backpressure); const startResult = startAlgorithm(controller); - const startPromise = resolvePromiseWith(startResult); + const startPromise = PromiseResolve(startResult); uponPromise(startPromise, () => { assert(stream[_state] === "writable" || stream[_state] === "erroring"); controller[_started] = true; @@ -3847,10 +3838,10 @@ function setUpWritableStreamDefaultControllerFromUnderlyingSink( /** @type {(controller: WritableStreamDefaultController) => any} */ let startAlgorithm = () => undefined; /** @type {(chunk: W, controller: WritableStreamDefaultController) => Promise} */ - let writeAlgorithm = () => resolvePromiseWith(undefined); - let closeAlgorithm = () => resolvePromiseWith(undefined); + let writeAlgorithm = () => PromiseResolve(undefined); + let closeAlgorithm = () => PromiseResolve(undefined); /** @type {(reason?: any) => Promise} */ - let abortAlgorithm = () => resolvePromiseWith(undefined); + let abortAlgorithm = () => PromiseResolve(undefined); if (underlyingSinkDict.start !== undefined) { startAlgorithm = () => @@ -4031,7 +4022,7 @@ function transformStreamDefaultControllerTerminate(controller) { */ function transformStreamDefaultSinkAbortAlgorithm(stream, reason) { transformStreamError(stream, reason); - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); } /** @@ -4148,11 +4139,11 @@ function transformStreamSetBackpressure(stream, backpressure) { function writableStreamAbort(stream, reason) { const state = stream[_state]; if (state === "closed" || state === "errored") { - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); } stream[_controller][_signal][signalAbort](reason); if (state === "closed" || state === "errored") { - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); } if (stream[_pendingAbortRequest] !== undefined) { return stream[_pendingAbortRequest].deferred.promise; @@ -4448,7 +4439,7 @@ function writableStreamDefaultWriterCloseWithErrorPropagation(writer) { if ( writableStreamCloseQueuedOrInFlight(stream) === true || state === "closed" ) { - return resolvePromiseWith(undefined); + return PromiseResolve(undefined); } if (state === "errored") { return PromiseReject(stream[_storedError]); From b3745217930f986c8c8108c7d268dc282a746da3 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 15:53:41 +0200 Subject: [PATCH 04/21] perf: use new instead of webidl.createBranded --- ext/web/06_streams.js | 103 ++++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 34 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 7f613f391fd573..2e85bb9b002e46 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -380,6 +380,7 @@ const _writable = Symbol("[[writable]]"); const _writeAlgorithm = Symbol("[[writeAlgorithm]]"); const _writer = Symbol("[[writer]]"); const _writeRequests = Symbol("[[writeRequests]]"); +const _brand = webidl.brand; /** * @template R @@ -387,7 +388,9 @@ const _writeRequests = Symbol("[[writeRequests]]"); * @returns {ReadableStreamDefaultReader} */ function acquireReadableStreamDefaultReader(stream) { - return new ReadableStreamDefaultReader(stream); + const reader = new ReadableStreamDefaultReader(_brand); + setUpReadableStreamDefaultReader(reader, stream); + return reader; } /** @@ -396,7 +399,7 @@ function acquireReadableStreamDefaultReader(stream) { * @returns {ReadableStreamBYOBReader} */ function acquireReadableStreamBYOBReader(stream) { - const reader = webidl.createBranded(ReadableStreamBYOBReader); + const reader = new ReadableStreamBYOBReader(_brand); setUpReadableStreamBYOBReader(reader, stream); return reader; } @@ -428,9 +431,9 @@ function createReadableStream( ) { assert(isNonNegativeNumber(highWaterMark)); /** @type {ReadableStream} */ - const stream = webidl.createBranded(ReadableStream); + const stream = new ReadableStream(_brand); initializeReadableStream(stream); - const controller = webidl.createBranded(ReadableStreamDefaultController); + const controller = new ReadableStreamDefaultController(_brand); setUpReadableStreamDefaultController( stream, controller, @@ -462,9 +465,9 @@ function createWritableStream( sizeAlgorithm, ) { assert(isNonNegativeNumber(highWaterMark)); - const stream = webidl.createBranded(WritableStream); + const stream = new WritableStream(_brand); initializeWritableStream(stream); - const controller = webidl.createBranded(WritableStreamDefaultController); + const controller = new WritableStreamDefaultController(_brand); setUpWritableStreamDefaultController( stream, controller, @@ -559,9 +562,9 @@ function createReadableByteStream( pullAlgorithm, cancelAlgorithm, ) { - const stream = webidl.createBranded(ReadableStream); + const stream = new ReadableStream(_brand); initializeReadableStream(stream); - const controller = webidl.createBranded(ReadableByteStreamController); + const controller = new ReadableByteStreamController(_brand); setUpReadableByteStreamController( stream, controller, @@ -886,7 +889,7 @@ const _original = Symbol("[[original]]"); * @returns {ReadableStream} */ function readableStreamForRid(rid, autoClose = true) { - const stream = webidl.createBranded(ReadableStream); + const stream = new ReadableStream(_brand); stream[_resourceBacking] = { rid, autoClose }; const tryClose = () => { @@ -956,7 +959,7 @@ const _isUnref = Symbol("isUnref"); * @returns {ReadableStream} */ function readableStreamForRidUnrefable(rid) { - const stream = webidl.createBranded(ReadableStream); + const stream = new ReadableStream(_brand); stream[promiseIdSymbol] = undefined; stream[_isUnref] = false; stream[_resourceBackingUnrefable] = { rid, autoClose: true }; @@ -1107,7 +1110,7 @@ async function readableStreamCollectIntoUint8Array(stream) { * @returns {ReadableStream} */ function writableStreamForRid(rid, autoClose = true) { - const stream = webidl.createBranded(WritableStream); + const stream = new WritableStream(_brand); stream[_resourceBacking] = { rid, autoClose }; const tryClose = () => { @@ -1489,7 +1492,7 @@ function readableByteStreamControllerGetBYOBRequest(controller) { // deno-lint-ignore prefer-primordials firstDescriptor.byteLength - firstDescriptor.bytesFilled, ); - const byobRequest = webidl.createBranded(ReadableStreamBYOBRequest); + const byobRequest = new ReadableStreamBYOBRequest(_brand); byobRequest[_controller] = controller; byobRequest[_view] = view; controller[_byobRequest] = byobRequest; @@ -3496,7 +3499,7 @@ function setUpReadableByteStreamControllerFromUnderlyingSource( underlyingSourceDict, highWaterMark, ) { - const controller = webidl.createBranded(ReadableByteStreamController); + const controller = new ReadableByteStreamController(_brand); /** @type {() => void} */ let startAlgorithm = () => undefined; /** @type {() => Promise} */ @@ -3609,7 +3612,7 @@ function setUpReadableStreamDefaultControllerFromUnderlyingSource( highWaterMark, sizeAlgorithm, ) { - const controller = webidl.createBranded(ReadableStreamDefaultController); + const controller = new ReadableStreamDefaultController(_brand); /** @type {() => Promise} */ let startAlgorithm = () => undefined; /** @type {() => Promise} */ @@ -3727,7 +3730,7 @@ function setUpTransformStreamDefaultControllerFromTransformer( transformerDict, ) { /** @type {TransformStreamDefaultController} */ - const controller = webidl.createBranded(TransformStreamDefaultController); + const controller = new TransformStreamDefaultController(_brand); /** @type {(chunk: O, controller: TransformStreamDefaultController) => Promise} */ let transformAlgorithm = (chunk) => { try { @@ -3834,7 +3837,7 @@ function setUpWritableStreamDefaultControllerFromUnderlyingSink( highWaterMark, sizeAlgorithm, ) { - const controller = webidl.createBranded(WritableStreamDefaultController); + const controller = new WritableStreamDefaultController(_brand); /** @type {(controller: WritableStreamDefaultController) => any} */ let startAlgorithm = () => undefined; /** @type {(chunk: W, controller: WritableStreamDefaultController) => Promise} */ @@ -4847,7 +4850,7 @@ class ByteLengthQueuingStrategy { const prefix = "Failed to construct 'ByteLengthQueuingStrategy'"; webidl.requiredArguments(arguments.length, 1, prefix); init = webidl.converters.QueuingStrategyInit(init, prefix, "Argument 1"); - this[webidl.brand] = webidl.brand; + this[_brand] = _brand; this[_globalObject] = globalThis; this[_highWaterMark] = init.highWaterMark; } @@ -4901,7 +4904,7 @@ class CountQueuingStrategy { const prefix = "Failed to construct 'CountQueuingStrategy'"; webidl.requiredArguments(arguments.length, 1, prefix); init = webidl.converters.QueuingStrategyInit(init, prefix, "Argument 1"); - this[webidl.brand] = webidl.brand; + this[_brand] = _brand; this[_globalObject] = globalThis; this[_highWaterMark] = init.highWaterMark; } @@ -4999,6 +5002,11 @@ class ReadableStream { * @param {QueuingStrategy=} strategy */ constructor(underlyingSource = undefined, strategy = undefined) { + if (underlyingSource === _brand) { + this[_brand] = _brand; + return; + } + const prefix = "Failed to construct 'ReadableStream'"; if (underlyingSource !== undefined) { underlyingSource = webidl.converters.object( @@ -5018,7 +5026,7 @@ class ReadableStream { } else { strategy = {}; } - this[webidl.brand] = webidl.brand; + this[_brand] = _brand; let underlyingSourceDict = {}; if (underlyingSource !== undefined) { underlyingSourceDict = webidl.converters.UnderlyingSource( @@ -5286,10 +5294,14 @@ class ReadableStreamDefaultReader { /** @param {ReadableStream} stream */ constructor(stream) { + if (stream === _brand) { + this[_brand] = _brand; + return; + } const prefix = "Failed to construct 'ReadableStreamDefaultReader'"; webidl.requiredArguments(arguments.length, 1, prefix); stream = webidl.converters.ReadableStream(stream, prefix, "Argument 1"); - this[webidl.brand] = webidl.brand; + this[_brand] = _brand; setUpReadableStreamDefaultReader(this, stream); } @@ -5383,10 +5395,14 @@ class ReadableStreamBYOBReader { /** @param {ReadableStream} stream */ constructor(stream) { + if (stream === _brand) { + this[_brand] = _brand; + return; + } const prefix = "Failed to construct 'ReadableStreamBYOBReader'"; webidl.requiredArguments(arguments.length, 1, prefix); stream = webidl.converters.ReadableStream(stream, prefix, "Argument 1"); - this[webidl.brand] = webidl.brand; + this[_brand] = _brand; setUpReadableStreamBYOBReader(this, stream); } @@ -5513,8 +5529,11 @@ class ReadableStreamBYOBRequest { return this[_view]; } - constructor() { - webidl.illegalConstructor(); + constructor(brand = undefined) { + if (brand !== _brand) { + webidl.illegalConstructor(); + } + this[_brand] = _brand; } respond(bytesWritten) { @@ -5609,8 +5628,11 @@ class ReadableByteStreamController { /** @type {ReadableStream} */ [_stream]; - constructor() { - webidl.illegalConstructor(); + constructor(brand = undefined) { + if (brand !== _brand) { + webidl.illegalConstructor(); + } + this[_brand] = _brand; } /** @returns {ReadableStreamBYOBRequest | null} */ @@ -5804,8 +5826,11 @@ class ReadableStreamDefaultController { /** @type {ReadableStream} */ [_stream]; - constructor() { - webidl.illegalConstructor(); + constructor(brand = undefined) { + if (brand !== _brand) { + webidl.illegalConstructor(); + } + this[_brand] = _brand; } /** @returns {number | null} */ @@ -5944,7 +5969,7 @@ class TransformStream { prefix, "Argument 3", ); - this[webidl.brand] = webidl.brand; + this[_brand] = _brand; if (transformer === undefined) { transformer = null; } @@ -6028,8 +6053,11 @@ class TransformStreamDefaultController { /** @type {(chunk: O, controller: this) => Promise} */ [_transformAlgorithm]; - constructor() { - webidl.illegalConstructor(); + constructor(brand = undefined) { + if (brand !== _brand) { + webidl.illegalConstructor(); + } + this[_brand] = _brand; } /** @returns {number | null} */ @@ -6117,6 +6145,10 @@ class WritableStream { * @param {QueuingStrategy=} strategy */ constructor(underlyingSink = undefined, strategy = {}) { + if (underlyingSink === _brand) { + this[_brand] = _brand; + return; + } const prefix = "Failed to construct 'WritableStream'"; if (underlyingSink !== undefined) { underlyingSink = webidl.converters.object( @@ -6130,7 +6162,7 @@ class WritableStream { prefix, "Argument 2", ); - this[webidl.brand] = webidl.brand; + this[_brand] = _brand; if (underlyingSink === undefined) { underlyingSink = null; } @@ -6239,7 +6271,7 @@ class WritableStreamDefaultWriter { const prefix = "Failed to construct 'WritableStreamDefaultWriter'"; webidl.requiredArguments(arguments.length, 1, prefix); stream = webidl.converters.WritableStream(stream, prefix, "Argument 1"); - this[webidl.brand] = webidl.brand; + this[_brand] = _brand; setUpWritableStreamDefaultWriter(this, stream); } @@ -6396,8 +6428,11 @@ class WritableStreamDefaultController { return this[_signal]; } - constructor() { - webidl.illegalConstructor(); + constructor(brand = undefined) { + if (brand !== _brand) { + webidl.illegalConstructor(); + } + this[_brand] = _brand; } /** From fe9cc021d13ec48694ae8f6f9f75dd52d02c2ee1 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 15:33:48 +0200 Subject: [PATCH 05/21] perf: use Queue --- ext/web/06_streams.js | 68 +++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 2e85bb9b002e46..91a656aeb58183 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -216,7 +216,7 @@ class Queue { enqueue(value) { const node = { value, next: null }; - if (!this.head) { + if (this.head === null) { this.head = node; this.tail = node; } else { @@ -227,10 +227,11 @@ class Queue { } dequeue() { - if (!this.head) { + const node = this.head; + if (node === null) { return null; } - const node = this.head; + if (this.head === this.tail) { this.tail = null; } @@ -240,7 +241,7 @@ class Queue { } peek() { - if (!this.head) { + if (this.head === null) { return null; } @@ -1580,7 +1581,7 @@ function readableByteStreamControllerShouldCallPull(controller) { function readableStreamAddReadRequest(stream, readRequest) { assert(isReadableStreamDefaultReader(stream[_reader])); assert(stream[_state] === "readable"); - ArrayPrototypePush(stream[_reader][_readRequests], readRequest); + stream[_reader][_readRequests].enqueue(readRequest); } /** @@ -1639,9 +1640,9 @@ function readableStreamClose(stream) { if (isReadableStreamDefaultReader(reader)) { /** @type {Array>} */ const readRequests = reader[_readRequests]; - reader[_readRequests] = []; - for (let i = 0; i < readRequests.length; ++i) { - const readRequest = readRequests[i]; + // reader[_readRequests] = new Queue(); + while (readRequests.size !== 0) { + const readRequest = readRequests.dequeue(); readRequest.closeSteps(); } } @@ -1797,7 +1798,6 @@ function readableStreamDefaultcontrollerHasBackpressure(controller) { * @returns {boolean} */ function readableStreamDefaultcontrollerShouldCallPull(controller) { - const stream = controller[_stream]; if ( readableStreamDefaultControllerCanCloseOrEnqueue(controller) === false ) { @@ -1806,6 +1806,7 @@ function readableStreamDefaultcontrollerShouldCallPull(controller) { if (controller[_started] === false) { return false; } + const stream = controller[_stream]; if ( isReadableStreamLocked(stream) && readableStreamGetNumReadRequests(stream) > 0 @@ -1815,10 +1816,11 @@ function readableStreamDefaultcontrollerShouldCallPull(controller) { const desiredSize = readableStreamDefaultControllerGetDesiredSize( controller, ); - assert(desiredSize !== null); + if (desiredSize > 0) { return true; } + assert(desiredSize !== null); return false; } @@ -1858,9 +1860,9 @@ function readableStreamBYOBReaderRelease(reader) { */ function readableStreamDefaultReaderErrorReadRequests(reader, e) { const readRequests = reader[_readRequests]; - reader[_readRequests] = []; - for (let i = 0; i < readRequests.length; ++i) { - const readRequest = readRequests[i]; + reader[_readRequests] = new Queue(); + while (readRequests.size !== 0) { + const readRequest = readRequests.dequeue(); readRequest.errorSteps(e); } } @@ -1899,11 +1901,11 @@ function readableByteStreamControllerProcessReadRequestsUsingQueue( ) { const reader = controller[_stream][_reader]; assert(isReadableStreamDefaultReader(reader)); - while (reader[_readRequests].length !== 0) { + while (reader[_readRequests].size !== 0) { if (controller[_queueTotalSize] === 0) { return; } - const readRequest = ArrayPrototypeShift(reader[_readRequests]); + const readRequest = reader[_readRequests].dequeue(); readableByteStreamControllerFillReadRequestFromQueue( controller, readRequest, @@ -2538,9 +2540,9 @@ function readableStreamFulfillReadRequest(stream, chunk, done) { assert(readableStreamHasDefaultReader(stream) === true); /** @type {ReadableStreamDefaultReader} */ const reader = stream[_reader]; - assert(reader[_readRequests].length); + assert(reader[_readRequests].size); /** @type {ReadRequest} */ - const readRequest = ArrayPrototypeShift(reader[_readRequests]); + const readRequest = reader[_readRequests].dequeue(); if (done) { readRequest.closeSteps(); } else { @@ -2563,7 +2565,7 @@ function readableStreamGetNumReadIntoRequests(stream) { */ function readableStreamGetNumReadRequests(stream) { assert(readableStreamHasDefaultReader(stream) === true); - return stream[_reader][_readRequests].length; + return stream[_reader][_readRequests].size; } /** @@ -3261,7 +3263,7 @@ function readableByteStreamTee(stream) { function pullWithBYOBReader(view, forBranch2) { if (isReadableStreamDefaultReader(reader)) { - assert(reader[_readRequests].length === 0); + assert(reader[_readRequests].size === 0); readableStreamDefaultReaderRelease(reader); reader = acquireReadableStreamBYOBReader(stream); forwardReaderError(reader); @@ -3693,7 +3695,7 @@ function setUpReadableStreamDefaultReader(reader, stream) { throw new TypeError("ReadableStream is locked."); } readableStreamReaderGenericInitialize(reader, stream); - reader[_readRequests] = []; + reader[_readRequests] = new Queue(); } /** @@ -4802,11 +4804,9 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ return PromisePrototypeThen(promise.promise); } - reader[_iteratorNext] = reader[_iteratorNext] + return reader[_iteratorNext] = reader[_iteratorNext] ? PromisePrototypeThen(reader[_iteratorNext], nextSteps, nextSteps) : nextSteps(); - - return reader[_iteratorNext]; }, /** * @param {unknown} arg @@ -4824,7 +4824,7 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ if (reader[_stream] === undefined) { return PromiseResolve({ value: undefined, done: true }); } - assert(reader[_readRequests].length === 0); + assert(reader[_readRequests].size === 0); if (this[_preventCancel] === false) { const result = readableStreamReaderGenericCancel(reader, arg); readableStreamDefaultReaderRelease(reader); @@ -5247,19 +5247,23 @@ class ReadableStream { * @param {ReadableStreamIteratorOptions=} options * @returns {AsyncIterableIterator} */ - values(options = {}) { + values(options = undefined) { webidl.assertBranded(this, ReadableStreamPrototype); - const prefix = "Failed to execute 'values' on 'ReadableStream'"; - options = webidl.converters.ReadableStreamIteratorOptions( - options, - prefix, - "Argument 1", - ); + let preventCancel = false; + if (options !== undefined) { + const prefix = "Failed to execute 'values' on 'ReadableStream'"; + options = webidl.converters.ReadableStreamIteratorOptions( + options, + prefix, + "Argument 1", + ); + preventCancel = options.preventCancel; + } /** @type {AsyncIterableIterator} */ const iterator = ObjectCreate(readableStreamAsyncIteratorPrototype); const reader = acquireReadableStreamDefaultReader(this); iterator[_reader] = reader; - iterator[_preventCancel] = options.preventCancel; + iterator[_preventCancel] = preventCancel; return iterator; } From fdd27e57477f8ad9d55d8f1de3e799a470bd190f Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 16:53:55 +0200 Subject: [PATCH 06/21] perf: optimize ReadableStream constructor --- ext/web/06_streams.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 91a656aeb58183..236512dfa28b32 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -5027,14 +5027,15 @@ class ReadableStream { strategy = {}; } this[_brand] = _brand; - let underlyingSourceDict = {}; - if (underlyingSource !== undefined) { - underlyingSourceDict = webidl.converters.UnderlyingSource( + + const underlyingSourceDict = underlyingSource !== undefined + ? webidl.converters.UnderlyingSource( underlyingSource, prefix, "underlyingSource", - ); - } + ) + : {}; + initializeReadableStream(this); if (underlyingSourceDict.type === "bytes") { if (strategy.size !== undefined) { @@ -5051,7 +5052,6 @@ class ReadableStream { highWaterMark, ); } else { - assert(!(ReflectHas(underlyingSourceDict, "type"))); const sizeAlgorithm = extractSizeAlgorithm(strategy); const highWaterMark = extractHighWaterMark(strategy, 1); setUpReadableStreamDefaultControllerFromUnderlyingSource( From 4b0151b70f4a1491fc6aa58b66b70193e176ce81 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 17:16:15 +0200 Subject: [PATCH 07/21] cleanup --- ext/web/06_streams.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 236512dfa28b32..6bdb43300b8de2 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -689,10 +689,7 @@ function isReadableStream(value) { * @returns {boolean} */ function isReadableStreamLocked(stream) { - if (stream[_reader] === undefined) { - return false; - } - return true; + return stream[_reader] !== undefined; } /** @@ -1640,7 +1637,6 @@ function readableStreamClose(stream) { if (isReadableStreamDefaultReader(reader)) { /** @type {Array>} */ const readRequests = reader[_readRequests]; - // reader[_readRequests] = new Queue(); while (readRequests.size !== 0) { const readRequest = readRequests.dequeue(); readRequest.closeSteps(); @@ -1860,7 +1856,6 @@ function readableStreamBYOBReaderRelease(reader) { */ function readableStreamDefaultReaderErrorReadRequests(reader, e) { const readRequests = reader[_readRequests]; - reader[_readRequests] = new Queue(); while (readRequests.size !== 0) { const readRequest = readRequests.dequeue(); readRequest.errorSteps(e); From e65808dcbc7a52264599a0cc8cceef3b90d18418 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 17:17:52 +0200 Subject: [PATCH 08/21] perf: move isDetachedBuffer check in .read --- ext/web/06_streams.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 6bdb43300b8de2..46bc3c12d2a4fc 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -5435,16 +5435,19 @@ class ReadableStreamBYOBReader { new TypeError("view must have non-zero byteLength"), ); } + if (getArrayBufferByteLength(buffer) === 0) { + if (isDetachedBuffer(buffer)) { + return PromiseReject( + new TypeError("view's buffer has been detached"), + ); + } + return PromiseReject( new TypeError("view's buffer must have non-zero byteLength"), ); } - if (isDetachedBuffer(buffer)) { - return PromiseReject( - new TypeError("view's buffer has been detached"), - ); - } + if (this[_stream] === undefined) { return PromiseReject( new TypeError("Reader has no associated stream."), From 9592ea5fa0199b56be2d9723ba814ba7dc16c064 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 18:04:48 +0200 Subject: [PATCH 09/21] perf: optimize WritableStream constructor --- ext/web/06_streams.js | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 46bc3c12d2a4fc..80155cc522bb9b 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -383,6 +383,16 @@ const _writer = Symbol("[[writer]]"); const _writeRequests = Symbol("[[writeRequests]]"); const _brand = webidl.brand; +function noop() {} +async function noopAsync() {} +const _defaultStartAlgorithm = noop; +const _defaultWriteAlgorithm = noopAsync; +const _defaultCloseAlgorithm = noopAsync; +const _defaultAbortAlgorithm = noopAsync; +const _defaultPullAlgorithm = noopAsync; +const _defaultFlushAlgorithm = noopAsync; +const _defaultCancelAlgorithm = noopAsync; + /** * @template R * @param {ReadableStream} stream @@ -1618,7 +1628,7 @@ function readableStreamCancel(stream, reason) { } /** @type {Promise} */ const sourceCancelPromise = stream[_controller][_cancelSteps](reason); - return PromisePrototypeThen(sourceCancelPromise, () => undefined); + return PromisePrototypeThen(sourceCancelPromise, noop); } /** @@ -3498,9 +3508,9 @@ function setUpReadableByteStreamControllerFromUnderlyingSource( ) { const controller = new ReadableByteStreamController(_brand); /** @type {() => void} */ - let startAlgorithm = () => undefined; + let startAlgorithm = _defaultStartAlgorithm; /** @type {() => Promise} */ - let pullAlgorithm = () => PromiseResolve(undefined); + let pullAlgorithm = _defaultPullAlgorithm; /** @type {(reason: any) => Promise} */ let cancelAlgorithm = (_reason) => PromiseResolve(undefined); if (underlyingSourceDict.start !== undefined) { @@ -3611,11 +3621,11 @@ function setUpReadableStreamDefaultControllerFromUnderlyingSource( ) { const controller = new ReadableStreamDefaultController(_brand); /** @type {() => Promise} */ - let startAlgorithm = () => undefined; + let startAlgorithm = _defaultStartAlgorithm; /** @type {() => Promise} */ - let pullAlgorithm = () => PromiseResolve(undefined); + let pullAlgorithm = _defaultPullAlgorithm; /** @type {(reason?: any) => Promise} */ - let cancelAlgorithm = () => PromiseResolve(undefined); + let cancelAlgorithm = _defaultCancelAlgorithm; if (underlyingSourceDict.start !== undefined) { startAlgorithm = () => webidl.invokeCallbackFunction( @@ -3738,7 +3748,7 @@ function setUpTransformStreamDefaultControllerFromTransformer( return PromiseResolve(undefined); }; /** @type {(controller: TransformStreamDefaultController) => Promise} */ - let flushAlgorithm = () => PromiseResolve(undefined); + let flushAlgorithm = _defaultFlushAlgorithm; if (transformerDict.transform !== undefined) { transformAlgorithm = (chunk, controller) => webidl.invokeCallbackFunction( @@ -3836,12 +3846,12 @@ function setUpWritableStreamDefaultControllerFromUnderlyingSink( ) { const controller = new WritableStreamDefaultController(_brand); /** @type {(controller: WritableStreamDefaultController) => any} */ - let startAlgorithm = () => undefined; + let startAlgorithm = _defaultStartAlgorithm; /** @type {(chunk: W, controller: WritableStreamDefaultController) => Promise} */ - let writeAlgorithm = () => PromiseResolve(undefined); - let closeAlgorithm = () => PromiseResolve(undefined); + let writeAlgorithm = _defaultWriteAlgorithm; + let closeAlgorithm = _defaultCloseAlgorithm; /** @type {(reason?: any) => Promise} */ - let abortAlgorithm = () => PromiseResolve(undefined); + let abortAlgorithm = _defaultAbortAlgorithm; if (underlyingSinkDict.start !== undefined) { startAlgorithm = () => @@ -5069,7 +5079,7 @@ class ReadableStream { const iterator = getIterator(asyncIterable, true); - const stream = createReadableStream(() => undefined, async () => { + const stream = createReadableStream(noop, async () => { // deno-lint-ignore prefer-primordials const res = await iterator.next(); if (typeof res !== "object") { @@ -6146,7 +6156,7 @@ class WritableStream { * @param {UnderlyingSink=} underlyingSink * @param {QueuingStrategy=} strategy */ - constructor(underlyingSink = undefined, strategy = {}) { + constructor(underlyingSink = undefined, strategy = undefined) { if (underlyingSink === _brand) { this[_brand] = _brand; return; @@ -6159,11 +6169,11 @@ class WritableStream { "Argument 1", ); } - strategy = webidl.converters.QueuingStrategy( + strategy = strategy !== undefined ? webidl.converters.QueuingStrategy( strategy, prefix, "Argument 2", - ); + ) : {}; this[_brand] = _brand; if (underlyingSink === undefined) { underlyingSink = null; From d499af2e0e87d3df3c7674f0b0be69cf0965e697 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 18:10:05 +0200 Subject: [PATCH 10/21] cleanup --- ext/web/06_streams.js | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 80155cc522bb9b..9bb8f978333f0d 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -5013,25 +5013,20 @@ class ReadableStream { } const prefix = "Failed to construct 'ReadableStream'"; - if (underlyingSource !== undefined) { - underlyingSource = webidl.converters.object( + underlyingSource = underlyingSource !== undefined + ? webidl.converters.object( underlyingSource, prefix, "Argument 1", - ); - } else { - underlyingSource = null; - } - if (strategy !== undefined) { - strategy = webidl.converters.QueuingStrategy( + ) + : null; + strategy = strategy !== undefined + ? webidl.converters.QueuingStrategy( strategy, prefix, "Argument 2", - ); - } else { - strategy = {}; - } - this[_brand] = _brand; + ) + : {}; const underlyingSourceDict = underlyingSource !== undefined ? webidl.converters.UnderlyingSource( @@ -5040,6 +5035,7 @@ class ReadableStream { "underlyingSource", ) : {}; + this[_brand] = _brand; initializeReadableStream(this); if (underlyingSourceDict.type === "bytes") { @@ -6169,11 +6165,13 @@ class WritableStream { "Argument 1", ); } - strategy = strategy !== undefined ? webidl.converters.QueuingStrategy( - strategy, - prefix, - "Argument 2", - ) : {}; + strategy = strategy !== undefined + ? webidl.converters.QueuingStrategy( + strategy, + prefix, + "Argument 2", + ) + : {}; this[_brand] = _brand; if (underlyingSink === undefined) { underlyingSink = null; From 4d73707b7a05faa56991373ded6667466a4cd9a8 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 18:42:10 +0200 Subject: [PATCH 11/21] use _defaultCancelAlgorithm --- ext/web/06_streams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 9bb8f978333f0d..35f4765ecec7c6 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -3512,7 +3512,7 @@ function setUpReadableByteStreamControllerFromUnderlyingSource( /** @type {() => Promise} */ let pullAlgorithm = _defaultPullAlgorithm; /** @type {(reason: any) => Promise} */ - let cancelAlgorithm = (_reason) => PromiseResolve(undefined); + let cancelAlgorithm = _defaultCancelAlgorithm; if (underlyingSourceDict.start !== undefined) { startAlgorithm = () => webidl.invokeCallbackFunction( From 0b72a92c486d0736ba16cceb1070448510624a8a Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 20:56:18 +0200 Subject: [PATCH 12/21] refactor Queue --- ext/web/06_streams.js | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 35f4765ecec7c6..2bca34d6bc6282 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -210,42 +210,46 @@ function uponPromise(promise, onFulfilled, onRejected) { } class Queue { - head = null; - tail = null; - size = 0; + #head = null; + #tail = null; + #size = 0; enqueue(value) { const node = { value, next: null }; - if (this.head === null) { - this.head = node; - this.tail = node; + if (this.#head === null) { + this.#head = node; + this.#tail = node; } else { - this.tail.next = node; - this.tail = node; + this.#tail.next = node; + this.#tail = node; } - return ++this.size; + return ++this.#size; } dequeue() { - const node = this.head; + const node = this.#head; if (node === null) { return null; } - if (this.head === this.tail) { - this.tail = null; + if (this.#head === this.#tail) { + this.#tail = null; } - this.head = this.head.next; - this.size--; + this.#head = this.#head.next; + this.#size--; return node.value; } peek() { - if (this.head === null) { + if (this.#head === null) { return null; } - return this.head.value; + return this.#head.value; + } + + get size() { + return this.#size; } } From fb6f85ef6ca55a856623a7c067c98a5f79e5361a Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 21:17:01 +0200 Subject: [PATCH 13/21] update readableStreamVeryLongReadAll test --- cli/tests/unit/streams_test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/tests/unit/streams_test.ts b/cli/tests/unit/streams_test.ts index e496b5c4f399ee..6fe37958ee0bb2 100644 --- a/cli/tests/unit/streams_test.ts +++ b/cli/tests/unit/streams_test.ts @@ -249,9 +249,9 @@ Deno.test(async function readableStreamLongAsyncReadAll() { }); Deno.test(async function readableStreamVeryLongReadAll() { - const rid = resourceForReadableStream(veryLongTinyPacketStream(10000)); + const rid = resourceForReadableStream(veryLongTinyPacketStream(1_000_000)); const buffer = await core.ops.op_read_all(rid); - assertEquals(buffer.length, 10000); + assertEquals(buffer.length, 1_000_000); core.ops.op_close(rid); }); From bdf278453bebe42fd0c18a9bbb5250f6a72b8f28 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 21:19:00 +0200 Subject: [PATCH 14/21] remove Array.shift comment --- cli/tests/unit/streams_test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cli/tests/unit/streams_test.ts b/cli/tests/unit/streams_test.ts index 6fe37958ee0bb2..7713cb4b5e0510 100644 --- a/cli/tests/unit/streams_test.ts +++ b/cli/tests/unit/streams_test.ts @@ -126,9 +126,7 @@ function emptyChunkStream() { }); } -// Try to blow up any recursive reads. Note that because of the use of Array.shift in -// ReadableStream, this might not actually be able to complete with larger values of -// length. +// Try to blow up any recursive reads. function veryLongTinyPacketStream(length: number) { return new ReadableStream({ start(controller) { From 6369ad452b6520a8d4de2778bdfc69c72e9a9df5 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sat, 23 Sep 2023 21:50:28 +0200 Subject: [PATCH 15/21] CI From d17a1673eed4966d96ff66d741c8e0ce091dccdf Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sun, 24 Sep 2023 07:18:26 +0200 Subject: [PATCH 16/21] private properties in ReadableStreamAsyncIteratorReadRequest --- ext/web/06_streams.js | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 2bca34d6bc6282..c894bb22b11a93 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -4758,28 +4758,31 @@ const _iteratorNext = Symbol("[[iteratorNext]]"); const _iteratorFinished = Symbol("[[iteratorFinished]]"); class ReadableStreamAsyncIteratorReadRequest { + #reader; + #promise; + constructor(reader, promise) { - this.reader = reader; - this.promise = promise; + this.#reader = reader; + this.#promise = promise; } chunkSteps(chunk) { - this.reader[_iteratorNext] = null; - this.promise.resolve({ value: chunk, done: false }); + this.#reader[_iteratorNext] = null; + this.#promise.resolve({ value: chunk, done: false }); } closeSteps() { - this.reader[_iteratorNext] = null; - this.reader[_iteratorFinished] = true; - readableStreamDefaultReaderRelease(this.reader); - this.promise.resolve({ value: undefined, done: true }); + this.#reader[_iteratorNext] = null; + this.#reader[_iteratorFinished] = true; + readableStreamDefaultReaderRelease(this.#reader); + this.#promise.resolve({ value: undefined, done: true }); } errorSteps(e) { - this.reader[_iteratorNext] = null; - this.reader[_iteratorFinished] = true; - readableStreamDefaultReaderRelease(this.reader); - this.promise.reject(e); + this.#reader[_iteratorNext] = null; + this.#reader[_iteratorFinished] = true; + readableStreamDefaultReaderRelease(this.#reader); + this.#promise.reject(e); } } From 30fc1656378eda51186084283b60b4db97d4b6d3 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sun, 24 Sep 2023 07:55:34 +0200 Subject: [PATCH 17/21] CI From 0e19611d6c78770028abd96aa97642587284dfb8 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Sun, 24 Sep 2023 08:14:01 +0200 Subject: [PATCH 18/21] CI From 098e6f41d70834067d32c39572357665b53ec375 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Thu, 28 Sep 2023 18:17:54 +0200 Subject: [PATCH 19/21] add comment --- ext/web/06_streams.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index c894bb22b11a93..826bf9135dbd71 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -4807,6 +4807,9 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ /** @type {Deferred>} */ const promise = new Deferred(); + // internal values (_iteratorNext & _iteratorFinished) are modified inside + // ReadableStreamAsyncIteratorReadRequest methods + // see: https://webidl.spec.whatwg.org/#es-default-asynchronous-iterator-object const readRequest = new ReadableStreamAsyncIteratorReadRequest( reader, promise, From 6bf7e302b29961e04b8a7339b8bd0a66804bdade Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Fri, 13 Oct 2023 12:41:47 +0200 Subject: [PATCH 20/21] fix new WPT --- ext/web/06_streams.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index ecf05c415ff614..66be90a61f7d09 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -143,6 +143,15 @@ class Deferred { } } +/** + * @template T + * @param {T | PromiseLike} value + * @returns {Promise} + */ +function resolvePromiseWith(value) { + return new Promise((resolve) => resolve(value)); +} + /** @param {any} e */ function rethrowAssertionErrorRejection(e) { if (e && ObjectPrototypeIsPrototypeOf(AssertionError.prototype, e)) { @@ -3837,7 +3846,7 @@ function setUpWritableStreamDefaultController( ); writableStreamUpdateBackpressure(stream, backpressure); const startResult = startAlgorithm(controller); - const startPromise = PromiseResolve(startResult); + const startPromise = resolvePromiseWith(startResult); uponPromise(startPromise, () => { assert(stream[_state] === "writable" || stream[_state] === "erroring"); controller[_started] = true; From aa344557ce0b00eeba5503d6c8874533c2d9ac77 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande Date: Fri, 13 Oct 2023 13:11:26 +0200 Subject: [PATCH 21/21] CI