Conversation
Collaborator
|
Review requested:
|
The shared "no pending request" records in the writable stream were `__proto__: null` literals, which V8 creates in dictionary mode. They sit in inFlightWriteRequest, closeRequest and pendingAbortRequest whenever nothing is pending, and their promise field is checked several times per write, so those loads did a hash lookup on every write and every pipe. They are now built as plain literals and get their null prototype afterwards, which keeps them in fast mode. The readable controllers also initialized their state slot with an empty object that setup replaced immediately. That throwaway allocation is gone, matching the writable and transform controllers. Add a writable-write benchmark: nothing in benchmark/webstreams drove WritableStreamDefaultWriter.write() directly. Signed-off-by: Matteo Collina <hello@matteocollina.com>
mcollina
force-pushed
the
webstream-perf-round19
branch
from
September 23, 2026 06:34
992b90b to
bc320cd
Compare
|
|
||
| class ReadableStreamDefaultController { | ||
| [kType] = 'ReadableStreamDefaultController'; | ||
| [kState] = {}; |
Contributor
There was a problem hiding this comment.
Would this also work? That should ensure that all constructed objects already have the correct "shape", I think?
Suggested change
| [kState] = {}; | |
| [kState]; |
Comment on lines
+108
to
+110
| // state reset (one per write on the hot path). The prototype is nulled | ||
| // after creation: a `__proto__: null` literal is created in dictionary | ||
| // mode, and these fields are loaded several times per write. |
Contributor
There was a problem hiding this comment.
We're using { __proto__: null, ... } a lot across the entire codebase... Should we do a broader review of how we're using this pattern, or is this specific to how webstreams is using these particular objects?
Member
There was a problem hiding this comment.
It could certainly use an audit, I think. It's a bit tricky trying to balance performance with prototype polution safety.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Round 19 of the webstreams performance work (follows #66154). A small one: two shared sentinel objects on the writable side were in dictionary mode, and every write and every pipe paid for it.
Nil requests in fast mode
The shared "no pending request" records in
writablestream.js(kNilRequest,kNilPendingAbortRequest) were{ __proto__: null, ... }literals, which V8 creates in dictionary mode (the same trap #65625 removed from the per-stream state records). They sit ininFlightWriteRequest,closeRequestandpendingAbortRequestwhenever nothing is pending, and theirpromisefield is checked several times per write, so each of those loads was a hash lookup. They are now built as plain literals and get their null prototype afterwards withObjectSetPrototypeOf(), which keeps them in fast mode (only an object created with a null prototype starts in dictionary mode).Readable controllers: no throwaway state object
ReadableStreamDefaultControllerandReadableByteStreamControllerinitialized[kState]with an empty object that setup replaced immediately. The field initializer is gone, matching the writable and transform controllers; every construction site goes straight into setup.New benchmark
benchmark/webstreams/writable-write.js: nothing inbenchmark/webstreamsdroveWritableStreamDefaultWriter.write()directly (awaiteach write, or queue them all).Benchmarks
node benchmark/compare.js --runs 20on the final code (pipe-to, pipe-through, lifecycle, writable-write), significant rows only:writable-writeis noisy on this machine: an earlier 30-run pass measuredawaitat +6.5 % () andqueuedat +3.6 % (); herequeuedis +2.6 % ±3.0 %.An earlier full-suite run (creation, tee, readable-read, readable-read-buffered, readable-async-iterator, from, js_transfer as well) showed no other significant change; its one negative flag,
creation.js kind='ReadableStream.tee'at −3.6 % (*), re-ran at 30 runs as −2.05 % ±2.14 %, not significant.No behavior change: a 48-scenario microtask-ordering stress logs identically against
main, and WPT streams plus the webstreams parallel batch are green.AI generated, humanly reviewed.