| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent eaba4cd commit c438250
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2476,21 +2476,26 @@ function readableStreamDefaultControllerClose(controller) { | |||
| 2476 | 2476 | } | |
| 2477 | 2477 | ||
| 2478 | 2478 | function readableStreamDefaultControllerEnqueue(controller, chunk) { | |
| 2479 | - if (!readableStreamDefaultControllerCanCloseOrEnqueue(controller)) | ||
| 2479 | + // Equivalent to readableStreamDefaultControllerCanCloseOrEnqueue() | ||
| 2480 | + // followed by isReadableStreamLocked() and | ||
| 2481 | + // readableStreamGetNumReadRequests(), but with the state loaded once: | ||
| 2482 | + // this runs for every enqueued chunk. | ||
| 2483 | + const controllerState = controller[kState]; | ||
| 2484 | + const stream = controllerState.stream; | ||
| 2485 | + if (controllerState.closeRequested || stream[kState].state !== 'readable') | ||
| 2480 | 2486 | return; | |
| 2481 | 2487 | ||
| 2482 | - const { | ||
| 2483 | - stream, | ||
| 2484 | - } = controller[kState]; | ||
| 2485 | - | ||
| 2486 | - if (isReadableStreamLocked(stream) && | ||
| 2487 | - readableStreamGetNumReadRequests(stream)) { | ||
| 2488 | + const reader = stream[kState].reader; | ||
| 2489 | + if (reader !== undefined && | ||
| 2490 | + reader[kState] !== undefined && | ||
| 2491 | + reader[kType] === 'ReadableStreamDefaultReader' && | ||
| 2492 | + reader[kState].readRequests.length) { | ||
| 2488 | 2493 | readableStreamFulfillReadRequest(stream, chunk, false); | |
| 2489 | 2494 | } else { | |
| 2490 | 2495 | try { | |
| 2491 | 2496 | const chunkSize = | |
| 2492 | 2497 | FunctionPrototypeCall( | |
| 2493 | - controller[kState].sizeAlgorithm, | ||
| 2498 | + controllerState.sizeAlgorithm, | ||
| 2494 | 2499 | undefined, | |
| 2495 | 2500 | chunk); | |
| 2496 | 2501 | enqueueValueWithSize(controller, chunk, chunkSize); | |
@@ -2529,22 +2534,27 @@ function readableStreamDefaultControllerGetDesiredSize(controller) { | |||
| 2529 | 2534 | } | |
| 2530 | 2535 | ||
| 2531 | 2536 | function readableStreamDefaultControllerShouldCallPull(controller) { | |
| 2532 | - const { | ||
| 2533 | - stream, | ||
| 2534 | - } = controller[kState]; | ||
| 2535 | - if (!readableStreamDefaultControllerCanCloseOrEnqueue(controller) || | ||
| 2536 | - !controller[kState].started) | ||
| 2537 | + // Single-pass version of the spec's predicate chain (CanCloseOrEnqueue, | ||
| 2538 | + // IsLocked, HasDefaultReader, GetNumReadRequests, GetDesiredSize): this | ||
| 2539 | + // runs at least once per chunk on every default-stream path. The | ||
| 2540 | + // desired-size computation is inlined because the stream state is | ||
| 2541 | + // already known to be 'readable' here. | ||
| 2542 | + const controllerState = controller[kState]; | ||
| 2543 | + const stream = controllerState.stream; | ||
| 2544 | + if (controllerState.closeRequested || | ||
| 2545 | + stream[kState].state !== 'readable' || | ||
| 2546 | + !controllerState.started) | ||
| 2537 | 2547 | return false; | |
| 2538 | 2548 | ||
| 2539 | - if (isReadableStreamLocked(stream) && | ||
| 2540 | - readableStreamGetNumReadRequests(stream)) { | ||
| 2549 | + const reader = stream[kState].reader; | ||
| 2550 | + if (reader !== undefined && | ||
| 2551 | + reader[kState] !== undefined && | ||
| 2552 | + reader[kType] === 'ReadableStreamDefaultReader' && | ||
| 2553 | + reader[kState].readRequests.length) { | ||
| 2541 | 2554 | return true; | |
| 2542 | 2555 | } | |
| 2543 | 2556 | ||
| 2544 | - const desiredSize = readableStreamDefaultControllerGetDesiredSize(controller); | ||
| 2545 | - assert(desiredSize !== null); | ||
| 2546 | - | ||
| 2547 | - return desiredSize > 0; | ||
| 2557 | + return controllerState.highWaterMark - controllerState.queueTotalSize > 0; | ||
| 2548 | 2558 | } | |
| 2549 | 2559 | ||
| 2550 | 2560 | function readableStreamDefaultControllerCallPullIfNeeded(controller) { | |
@@ -2794,28 +2804,29 @@ function readableByteStreamControllerGetDesiredSize(controller) { | |||
| 2794 | 2804 | } | |
| 2795 | 2805 | ||
| 2796 | 2806 | function readableByteStreamControllerShouldCallPull(controller) { | |
| 2797 | - const { | ||
| 2798 | - stream, | ||
| 2799 | - } = controller[kState]; | ||
| 2807 | + // Single-pass version of the spec's predicate chain (HasDefaultReader, | ||
| 2808 | + // GetNumReadRequests, HasBYOBReader, GetNumReadIntoRequests, | ||
| 2809 | + // GetDesiredSize): this runs at least once per chunk on every byte | ||
| 2810 | + // stream path. The desired-size computation is inlined because the | ||
| 2811 | + // stream state is already known to be 'readable' here. | ||
| 2812 | + const controllerState = controller[kState]; | ||
| 2813 | + const stream = controllerState.stream; | ||
| 2800 | 2814 | if (stream[kState].state !== 'readable' || | |
| 2801 | - controller[kState].closeRequested || | ||
| 2802 | - !controller[kState].started) { | ||
| 2815 | + controllerState.closeRequested || | ||
| 2816 | + !controllerState.started) { | ||
| 2803 | 2817 | return false; | |
| 2804 | 2818 | } | |
| 2805 | - if (readableStreamHasDefaultReader(stream) && | ||
| 2806 | - readableStreamGetNumReadRequests(stream) > 0) { | ||
| 2807 | - return true; | ||
| 2808 | - } | ||
| 2809 | - | ||
| 2810 | - if (readableStreamHasBYOBReader(stream) && | ||
| 2811 | - readableStreamGetNumReadIntoRequests(stream) > 0) { | ||
| 2812 | - return true; | ||
| 2819 | + const reader = stream[kState].reader; | ||
| 2820 | + if (reader !== undefined && reader[kState] !== undefined) { | ||
| 2821 | + const type = reader[kType]; | ||
| 2822 | + if (type === 'ReadableStreamDefaultReader') { | ||
| 2823 | + if (reader[kState].readRequests.length) return true; | ||
| 2824 | + } else if (type === 'ReadableStreamBYOBReader') { | ||
| 2825 | + if (reader[kState].readIntoRequests.length) return true; | ||
| 2826 | + } | ||
| 2813 | 2827 | } | |
| 2814 | 2828 | ||
| 2815 | - const desiredSize = readableByteStreamControllerGetDesiredSize(controller); | ||
| 2816 | - assert(desiredSize !== null); | ||
| 2817 | - | ||
| 2818 | - return desiredSize > 0; | ||
| 2829 | + return controllerState.highWaterMark - controllerState.queueTotalSize > 0; | ||
| 2819 | 2830 | } | |
| 2820 | 2831 | ||
| 2821 | 2832 | function readableByteStreamControllerHandleQueueDrain(controller) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -258,12 +258,7 @@ function InternalTransferredTransformStream() { | |||
| 258 | 258 | readable: undefined, | |
| 259 | 259 | writable: undefined, | |
| 260 | 260 | backpressure: undefined, | |
| 261 | - backpressureChange: { | ||
| 262 | - __proto__: null, | ||
| 263 | - promise: undefined, | ||
| 264 | - resolve: undefined, | ||
| 265 | - reject: undefined, | ||
| 266 | - }, | ||
| 261 | + backpressureChange: undefined, | ||
| 267 | 262 | controller: undefined, | |
| 268 | 263 | }; | |
| 269 | 264 | } | |
@@ -390,12 +385,7 @@ function initializeTransformStream( | |||
| 390 | 385 | writable, | |
| 391 | 386 | controller: undefined, | |
| 392 | 387 | backpressure: undefined, | |
| 393 | - backpressureChange: { | ||
| 394 | - __proto__: null, | ||
| 395 | - promise: undefined, | ||
| 396 | - resolve: undefined, | ||
| 397 | - reject: undefined, | ||
| 398 | - }, | ||
| 388 | + backpressureChange: undefined, | ||
| 399 | 389 | }; | |
| 400 | 390 | ||
| 401 | 391 | transformStreamSetBackpressure(stream, true); | |
@@ -429,12 +419,27 @@ function transformStreamUnblockWrite(stream) { | |||
| 429 | 419 | transformStreamSetBackpressure(stream, false); | |
| 430 | 420 | } | |
| 431 | 421 | ||
| 422 | + // The spec's [[backpressureChangePromise]] is only ever observed by the | ||
| 423 | + // source pull algorithm (settles when backpressure next becomes true) and | ||
| 424 | + // by a sink write arriving while backpressure is set (settles when | ||
| 425 | + // backpressure next becomes false). Instead of allocating a fresh promise | ||
| 426 | + // record on every flip, the record is materialized lazily on first | ||
| 427 | + // observation and dropped once settled; flips nobody is waiting on | ||
| 428 | + // allocate nothing. | ||
| 429 | + function transformStreamBackpressureChangePromise(stream) { | ||
| 430 | + const state = stream[kState]; | ||
| 431 | + return (state.backpressureChange ??= PromiseWithResolvers()).promise; | ||
| 432 | + } | ||
| 433 | + | ||
| 432 | 434 | function transformStreamSetBackpressure(stream, backpressure) { | |
| 433 | - assert(stream[kState].backpressure !== backpressure); | ||
| 434 | - if (stream[kState].backpressureChange.promise !== undefined) | ||
| 435 | - stream[kState].backpressureChange.resolve?.(); | ||
| 436 | - stream[kState].backpressureChange = PromiseWithResolvers(); | ||
| 437 | - stream[kState].backpressure = backpressure; | ||
| 435 | + const state = stream[kState]; | ||
| 436 | + assert(state.backpressure !== backpressure); | ||
| 437 | + const backpressureChange = state.backpressureChange; | ||
| 438 | + if (backpressureChange !== undefined) { | ||
| 439 | + state.backpressureChange = undefined; | ||
| 440 | + backpressureChange.resolve(); | ||
| 441 | + } | ||
| 442 | + state.backpressure = backpressure; | ||
| 438 | 443 | } | |
| 439 | 444 | ||
| 440 | 445 | function setupTransformStreamDefaultController( | |
@@ -554,7 +559,7 @@ function transformStreamDefaultSinkWriteAlgorithm(stream, chunk) { | |||
| 554 | 559 | } = stream[kState]; | |
| 555 | 560 | assert(writable[kState].state === 'writable'); | |
| 556 | 561 | if (stream[kState].backpressure) { | |
| 557 | - const backpressureChange = stream[kState].backpressureChange.promise; | ||
| 562 | + const backpressureChange = transformStreamBackpressureChangePromise(stream); | ||
| 558 | 563 | return PromisePrototypeThen( | |
| 559 | 564 | backpressureChange, | |
| 560 | 565 | () => { | |
@@ -638,9 +643,8 @@ function transformStreamDefaultSinkCloseAlgorithm(stream) { | |||
| 638 | 643 | ||
| 639 | 644 | function transformStreamDefaultSourcePullAlgorithm(stream) { | |
| 640 | 645 | assert(stream[kState].backpressure); | |
| 641 | - assert(stream[kState].backpressureChange.promise !== undefined); | ||
| 642 | 646 | transformStreamSetBackpressure(stream, false); | |
| 643 | - return stream[kState].backpressureChange.promise; | ||
| 647 | + return transformStreamBackpressureChangePromise(stream); | ||
| 644 | 648 | } | |
| 645 | 649 | ||
| 646 | 650 | function transformStreamDefaultSourceCancelAlgorithm(stream, reason) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -134,45 +134,44 @@ function isBrandCheck(brand) { | |||
| 134 | 134 | }; | |
| 135 | 135 | } | |
| 136 | 136 | ||
| 137 | + // The queue helpers below run once per chunk on the hot paths of every | ||
| 138 | + // default readable/writable stream, so they load the controller state a | ||
| 139 | + // single time and don't assert the existence of the queue fields (both | ||
| 140 | + // are unconditionally initialized during controller setup and only ever | ||
| 141 | + // replaced wholesale). | ||
| 137 | 142 | function dequeueValue(controller) { | |
| 138 | - assert(controller[kState].queue !== undefined); | ||
| 139 | - assert(controller[kState].queueTotalSize !== undefined); | ||
| 140 | - assert(controller[kState].queue.length); | ||
| 143 | + const state = controller[kState]; | ||
| 144 | + assert(state.queue.length); | ||
| 141 | 145 | const { | |
| 142 | 146 | value, | |
| 143 | 147 | size, | |
| 144 | - } = ArrayPrototypeShift(controller[kState].queue); | ||
| 145 | - controller[kState].queueTotalSize = | ||
| 146 | - MathMax(0, controller[kState].queueTotalSize - size); | ||
| 148 | + } = ArrayPrototypeShift(state.queue); | ||
| 149 | + state.queueTotalSize = MathMax(0, state.queueTotalSize - size); | ||
| 147 | 150 | return value; | |
| 148 | 151 | } | |
| 149 | 152 | ||
| 150 | 153 | function resetQueue(controller) { | |
| 151 | - assert(controller[kState].queue !== undefined); | ||
| 152 | - assert(controller[kState].queueTotalSize !== undefined); | ||
| 153 | - controller[kState].queue = []; | ||
| 154 | - controller[kState].queueTotalSize = 0; | ||
| 154 | + const state = controller[kState]; | ||
| 155 | + state.queue = []; | ||
| 156 | + state.queueTotalSize = 0; | ||
| 155 | 157 | } | |
| 156 | 158 | ||
| 157 | 159 | function peekQueueValue(controller) { | |
| 158 | - assert(controller[kState].queue !== undefined); | ||
| 159 | - assert(controller[kState].queueTotalSize !== undefined); | ||
| 160 | - assert(controller[kState].queue.length); | ||
| 161 | - return controller[kState].queue[0].value; | ||
| 160 | + const state = controller[kState]; | ||
| 161 | + assert(state.queue.length); | ||
| 162 | + return state.queue[0].value; | ||
| 162 | 163 | } | |
| 163 | 164 | ||
| 164 | 165 | function enqueueValueWithSize(controller, value, size) { | |
| 165 | - assert(controller[kState].queue !== undefined); | ||
| 166 | - assert(controller[kState].queueTotalSize !== undefined); | ||
| 166 | + const state = controller[kState]; | ||
| 167 | 167 | const coercedSize = +size; | |
| 168 | 168 | if (NumberIsNaN(coercedSize) || | |
| 169 | 169 | coercedSize < 0 || | |
| 170 | 170 | coercedSize === Infinity) { | |
| 171 | 171 | throw new ERR_INVALID_ARG_VALUE.RangeError('size', size); | |
| 172 | 172 | } | |
| 173 | - size = coercedSize; | ||
| 174 | - ArrayPrototypePush(controller[kState].queue, { value, size }); | ||
| 175 | - controller[kState].queueTotalSize += size; | ||
| 173 | + ArrayPrototypePush(state.queue, { value, size: coercedSize }); | ||
| 174 | + state.queueTotalSize += coercedSize; | ||
| 176 | 175 | } | |
| 177 | 176 | ||
| 178 | 177 | // Arity-specialized variants of the promise-callback wrapper. The generic | |
| Back | FazBrowse Home | New Git URL |
0 commit comments