Webstreams cpp - #7
Closed
mcollina wants to merge 83 commits into
Closed
Conversation
Signed-off-by: Matteo Collina <hello@matteocollina.com> PR-URL: nodejs#63621 Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com> PR-URL: nodejs#63517 Refs: https://hackerone.com/reports/3752489 Reviewed-By: James M Snell <jasnell@gmail.com>
Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> PR-URL: nodejs#63650 Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com> PR-URL: nodejs#63625 Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Signed-off-by: Chengzhong Wu <cwu631@bloomberg.net> PR-URL: nodejs#63629 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Resolve pending next() calls when broadcast consumers are returned, so the promise does not remain pending after iterator cleanup. Fixes: nodejs#63519 Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: nodejs#63603 Fixes: nodejs#63519 Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Signed-off-by: Filip Skokan <panva.ip@gmail.com> PR-URL: nodejs#63556 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Signed-off-by: Filip Skokan <panva.ip@gmail.com> PR-URL: nodejs#63556 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Signed-off-by: Filip Skokan <panva.ip@gmail.com> PR-URL: nodejs#63556 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Signed-off-by: Filip Skokan <panva.ip@gmail.com> PR-URL: nodejs#63556 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Signed-off-by: Filip Skokan <panva.ip@gmail.com> PR-URL: nodejs#63556 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: nodejs#63536 Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: nodejs#63539 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Signed-off-by: Mert Can Altin <mertgold60@gmail.com> PR-URL: nodejs#63385 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Signed-off-by: Tim Perry <pimterry@gmail.com> PR-URL: nodejs#63249 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Notable changes: buffer: * (SEMVER-MINOR) increase `Buffer.poolSize` default to 64 KiB (Matteo Collina) nodejs#63597 crypto: * update root certificates to NSS 3.123.1 (Node.js GitHub Bot) nodejs#63527 doc: * downgrade macOS x64 support to Tier 2 (Antoine du Hamel) nodejs#63055 http: * (SEMVER-MINOR) add `httpValidation` option to configure header value validation (RajeshKumar11) nodejs#61597 inspector: * (SEMVER-MINOR) expose precise coverage start to JS runtime (sangwook) nodejs#63079 lib,permission: * (SEMVER-MINOR) add `permission.drop` (Rafael Gonzaga) nodejs#62672 PR-URL: nodejs#63664
Signed-off-by: Richard Lau <richard.lau@ibm.com> PR-URL: nodejs#63474 Reviewed-By: Stewart X Addison <sxa@redhat.com>
Treat writer.writev() returning undefined as synchronous success to match the existing write() fallback behavior for duck-typed writers. This avoids calling Promise.prototype.then on undefined after a batch write has already been accepted. Fixes: nodejs#63560 Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: nodejs#63561 Fixes: nodejs#63560 Reviewed-By: James M Snell <jasnell@gmail.com>
PR-URL: nodejs#63647 Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Add more log points in the probe mode and enable the debuglog int the probe mode tests. Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> PR-URL: nodejs#63663 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Kohei Ueno <kohei.ueno119@gmail.com>
Follow-up to df09b2a. Refs: nodejs#63482 Signed-off-by: Anna Henningsen <anna@addaleax.net> PR-URL: nodejs#63666 Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reject reads based on writer state so explicit falsy fail reasons do not leave reads pending. Fixes: nodejs#63568 Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: nodejs#63569 Fixes: nodejs#63568 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
PR-URL: nodejs#63671 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Fix build warnings by casting the number literals to the size_t constants they are compared against. Signed-off-by: Maya Lekova <maya@igalia.com> PR-URL: nodejs#63490 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
This was just a copy of the immediately preceding `handle_` field in `uv_lib_t`. Signed-off-by: Anna Henningsen <anna@addaleax.net> PR-URL: nodejs#63665 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it>
PR-URL: nodejs#63668 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
PR-URL: nodejs#63669 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Signed-off-by: Mohamed Sayed <k@3zrv.com> PR-URL: nodejs#63601 Fixes: nodejs#63513 Reviewed-By: LiviaMedeiros <livia@cirno.name> Reviewed-By: Matthew Aitken <maitken033380023@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
`shouldSkipFileCoverage(url)` is invoked twice for every covered script (once during source-map mapping and once during merge), and the same script URL is typically reported by every worker. The result depends only on `options.cwd`, `coverageExcludeGlobs`, and `coverageIncludeGlobs`, all of which are fixed for the lifetime of a TestCoverage instance, so the URL -> boolean mapping is deterministic and safe to cache. Add a private `#skipCache` SafeMap and split the method into a thin caching wrapper plus a private `#computeShouldSkipFileCoverage` that holds the original logic. Callers are unchanged. This eliminates redundant glob and URL parsing work proportional to the number of workers x scripts in the coverage report. Refs: nodejs#55103 Signed-off-by: sangwook <rewq5991@gmail.com> PR-URL: nodejs#63675 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
`shouldSkipFileCoverage()` called `matchGlobPattern()` for each covered file, and `matchGlobPattern()` builds a fresh Minimatch (a full glob parse and regexp compile) on every call. The coverage exclude/include globs never change during a run, so the same patterns were recompiled once per file, which dominated the coverage report time. Compile `coverageExcludeGlobs`/`coverageIncludeGlobs` to matchers once per `TestCoverage` instance and reuse them for every file. Expose `createMatcher()` from `internal/fs/glob` for this. On a synthetic 200-test-file project this drops shouldSkipFileCoverage from ~117ms to ~11ms (cpu-prof, isolation=none); the saving scales with files * globs. Refs: nodejs#55103 Signed-off-by: sangwook <rewq5991@gmail.com> PR-URL: nodejs#63675 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Bumps [actions/stale](https://github.com/actions/stale) from 10.2.0 to 10.3.0. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](actions/stale@b5d41d4...eb5cf3a) --- updated-dependencies: - dependency-name: actions/stale dependency-version: 10.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> PR-URL: nodejs#63728 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Bumps [cachix/cachix-action](https://github.com/cachix/cachix-action) from 1eb2ef646ac0255473d23a5907ad7b04ce94065c to 5f2d7c5294214f71b873db4b969586b980625e71. - [Release notes](https://github.com/cachix/cachix-action/releases) - [Changelog](https://github.com/cachix/cachix-action/blob/master/RELEASE.md) - [Commits](cachix/cachix-action@1eb2ef6...5f2d7c5) --- updated-dependencies: - dependency-name: cachix/cachix-action dependency-version: 5f2d7c5294214f71b873db4b969586b980625e71 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> PR-URL: nodejs#63729 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Bumps the eslint group in /tools/eslint with 7 updates: Updates `@babel/core` from 8.0.0-rc.4 to 8.0.0-rc.6 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) Updates `@babel/eslint-parser` from 8.0.0-rc.4 to 8.0.0-rc.6 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) Updates `@babel/plugin-syntax-import-source` from 8.0.0-rc.4 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) Updates `@eslint/markdown` from 8.0.1 to 8.0.2 - [Release notes](https://github.com/eslint/markdown/releases) - [Changelog](https://github.com/eslint/markdown/blob/main/CHANGELOG.md) - [Commits](eslint/markdown@v8.0.1...v8.0.2) Updates `eslint` from 10.2.1 to 10.4.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](eslint/eslint@v10.2.1...v10.4.0) Updates `eslint-plugin-jsdoc` from 62.9.0 to 63.0.0 - [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases) Updates `globals` from 17.5.0 to 17.6.0 - [Release notes](https://github.com/sindresorhus/globals/releases) --- updated-dependencies: - dependency-name: "@babel/core" dependency-version: 8.0.0-rc.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: eslint - dependency-name: "@babel/eslint-parser" dependency-version: 8.0.0-rc.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: eslint - dependency-name: "@babel/plugin-syntax-import-source" dependency-version: 8.0.0-rc.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: eslint - dependency-name: "@eslint/markdown" dependency-version: 8.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: eslint - dependency-name: eslint dependency-version: 10.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: eslint - dependency-name: eslint-plugin-jsdoc dependency-version: 63.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: eslint - dependency-name: globals dependency-version: 17.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: eslint ... Signed-off-by: dependabot[bot] <support@github.com> PR-URL: nodejs#63730 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Signed-off-by: semimikoh <ejffjeosms@gmail.com> PR-URL: nodejs#63470 Fixes: nodejs#63452 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day> Reviewed-By: Tim Perry <pimterry@gmail.com>
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](codecov/codecov-action@57e3a13...e79a696) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> PR-URL: nodejs#63725 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](actions/checkout@de0fac2...df4cb1c) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> PR-URL: nodejs#63726 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Signed-off-by: Mert Can Altin <mertgold60@gmail.com> PR-URL: nodejs#63639 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Daniel Lemire <daniel@lemire.me> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
The `hasIt` block has `Local<Function>`s, but it's capture in the lambda, yet the lambda is used after the locals go out of scope. Signed-off-by: ndossche <nora.dossche@ugent.be> PR-URL: nodejs#63640 Reviewed-By: Anna Henningsen <anna@addaleax.net>
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.4 to 5.0.5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](actions/cache@6682284...27d5ce7) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 5.0.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> PR-URL: nodejs#62847 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.3 to 4.36.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](github/codeql-action@e46ed2c...87557b9) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.36.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> PR-URL: nodejs#63724 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Add cleanup hooks to make sure that addons making use of this legacy API can do so safely in Worker threads or embedder-controlled Node.js instances. Refs: nodejs#63575 Fixes: nodejs#63540 Signed-off-by: Anna Henningsen <anna@addaleax.net> PR-URL: nodejs#63642 Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This content is taken from nodejs#63575. The original commit message is preserved below: --- worker: fix premature addon unload Weak callbacks could run after addons were unloaded, leading to a crash. Signed-off-by: Mohamed Akram <mohd.akram@outlook.com> PR-URL: nodejs#63642 Fixes: nodejs#63540 Refs: nodejs#63575 Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Wait for the Brotli decoder to fill its readable buffer before checking that decompression stops at the high water mark. This avoids racing the fixed timeout against libuv worker-pool scheduling. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: nodejs#63389 Refs: https://github.com/nodejs/reliability/blob/main/reports/2026-05-17.md#jstest-failure Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Tim Perry <pimterry@gmail.com>
Phase 1 + Phase 2 (C++ object model) of the WHATWG Streams rewrite from JS to
C++.
Phase 1: register a new `webstreams` internal binding
(src/streams/streams_binding.{h,cc}) as a SnapshotableObject, wired into all
binding registries and node.gyp. Builds, snapshots, and loads with no behavior
change.
Phase 2 (object model): src/streams/readable_stream.{h,cc} implements
ReadableStream, ReadableStreamDefaultController and ReadableStreamDefaultReader
in C++:
- value queue is a single JS Array (no per-chunk v8::Global) plus a C++
std::deque<double> for sizes (no Number boxing);
- pending reads are a C++ deque of Promise::Resolver, resolved directly with no
.then chains or read-request objects;
- stream<->controller<->reader relationships are stored in GC-traced internal
fields, with all objects MakeWeak'd (applied after MakeBaseObject) so they
live and die with their JS wrappers, mirroring the JS object graph's lifetime;
- a SizeMode enum recognizes the built-in CountQueuingStrategy /
ByteLengthQueuingStrategy so the per-chunk size() crossing into JS is skipped.
The model is exercised in isolation via createReadableStream /
acquireReadableStreamDefaultReader binding entry points (pull/enqueue/close/read,
parked-read-then-fulfill, cancel, desiredSize backpressure, error propagation).
It is not yet wired to the public API, so existing tests are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements the byte-stream half of the WHATWG ReadableStream rewrite in C++,
compiled-but-unwired (the public JS API still uses the JS implementation; the
unified flip is the next step).
Adds a shared StreamBaseObject base carrying a 1-byte Kind tag so a controller
or reader recovered from a GC-traced internal field can be safely downcast
(BaseObject::FromJSObject is an unchecked static_cast and RTTI is disabled).
ReadableStream now holds either a default or a byte controller, and either a
default or a BYOB reader, dispatched by tag.
New classes in src/streams/readable_stream.{h,cc}:
- ReadableByteStreamController: zero-copy byte queue (deque of owned
BackingStores; enqueue transfers the view's ArrayBuffer via GetBackingStore +
Detach) and pending pull-into descriptors filled/committed with pure-C++
memcpy. The user-visible view is materialized once at fulfillment.
- ReadableStreamBYOBReader and ReadableStreamBYOBRequest.
Binding entries createReadableByteStream / acquireReadableStreamBYOBReader.
Default readers can read byte streams (PullSteps + autoAllocateChunkSize).
Validated by an isolation test (default-reader-on-bytes, BYOB respond /
respondWithNewView, autoAllocate, BYOB-on-closed, enqueue-fills-pending-BYOB,
minimumFill, partial-fill remainder, cancel, error, desiredSize) plus the
existing public suite (test-whatwg-readablebytestream*, test-webstream*,
20 files) — all green; snapshot builds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements the WritableStream half of the WHATWG streams rewrite in C++,
compiled-but-unwired (the public JS API still uses the JS implementation; the
unified readable+writable+transform flip is the next step).
New src/streams/writable_stream.{h,cc} with WritableStream,
WritableStreamDefaultWriter, and WritableStreamDefaultController. The full
erroring/abort/in-flight state machine is ported faithfully:
- writeRequests as a deque of promise resolvers; close / inFlightWrite /
inFlightClose as resolver slots (empty == the spec's "undefined" request);
pendingAbort tracked on the stream.
- A PromiseSlot type models the writer's ready/closed {promise,resolve,reject},
including the settled-without-resolver case.
- The close sentinel is modeled by a close_queued_ flag (close is always the
last queue entry).
- The controller's AbortController is passed in from JS at setup; the signal
getter and abort() delegate to it. size_mode_ keeps the built-in queuing
strategy fast path.
The shared StreamBaseObject base, Kind tag, and SizeMode move into
streams_binding.h so readable and writable share them.
Binding entries createWritableStream / acquireWritableStreamDefaultWriter.
Validated by an isolation test (write+close, backpressure/desiredSize, size
strategy, close-flushes-queued-writes, abort, controller.error,
write-algorithm-rejects, signal, releaseLock, getWriter-locked) plus the
existing public suite (38 files incl. writablestream/transformstream/adapters/
transfer/compression) — all green; snapshot builds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements the TransformStream half of the WHATWG streams rewrite in C++,
compiled-but-unwired (the unified readable+writable+transform flip is next).
New src/streams/transform_stream.{h,cc} with TransformStream and
TransformStreamDefaultController. TransformStream is pure orchestration over the
C++ readable+writable halves: it builds a C++ readable and writable via the
extracted helpers NewReadableStream / NewWritableStream (refactored out of the
readable/writable binding entries) and wires their controller algorithms with
small JS trampolines (created once at setup, carrying the transform stream as
their Data) that call back into C++ sink/source algorithms. Continuations that
must capture chunk/reason use a 2-element holder Array as the reaction Data.
Ported faithfully: backpressure coordination (backpressureChange promise,
SetBackpressure / UnblockWrite), SinkWrite (await backpressure then transform),
SinkClose / SinkAbort / SourceCancel (finishPromise + flush/cancel algorithms),
SourcePull, controller enqueue/error/terminate/performTransform, and the shared
start promise. The transform controller drives the readable/writable through
their already-public C++ operations.
Binding entry createTransformStream. Validated by an isolation test (identity,
mapping transform, flush-enqueue + close, terminate, controller.error,
transform-throws, desiredSize) plus the public suite (38 files) and all four
stream isolation suites — green; snapshot builds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds ExposeReadableStreamConstructors / ExposeWritableStreamConstructors / ExposeTransformStreamConstructors, called from CreatePerContextProperties, so the JS layer can obtain the 11 native constructor functions (and their prototypes) from the `webstreams` binding. The native prototypes are already spec-shaped: methods and accessor getters are enumerable + configurable and the constructor .name is correct, so the JS layer only needs to add Symbol.toStringTag, the JS-only methods, and construction wrappers when the flip wires them up. Groundwork only: the exposed constructors are not yet used by the public API (still the JS implementation), so behavior is unchanged. Builds + snapshot + full public suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lands the small, additive prerequisites the unified JS flip needs, kept compiled-but-unwired so the tree stays green: - C++: expose internal introspection over the existing (already-settled) stream state + closed-promise infrastructure as binding functions (readableStreamStateField/Disturbed/ClosedPromise, writableStreamStateField/ClosedPromise) rather than prototype properties, so the public WebIDL surface is unchanged. These back the node:stream interop hooks (kIsDisturbed/kIsErrored/kIsReadable/kIsWritable/ kIsClosedPromise) once the JS layer is flipped. - C++: fix ReadableStream/WritableStream closed_promise() to settle immediately when the stream is already in a terminal state, so a late requester (e.g. node:stream finished() on an already-closed stream) does not hang. - JS: add util.extractSizeMode() to classify a strategy.size into the C++ SizeMode enum, and export the built-in queuing-strategy size functions so they can be recognized by identity (skipping the per-chunk size() cross). WPT streams: 69 passed / 1403 subtests / 0 unexpected. Public suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrites lib/internal/webstreams/{readablestream,writablestream,transformstream}
.js as thin wrappers whose instances ARE the native C++ objects, plus
transfer.js deferred-port support. The build is green and the public classes
work; WPT streams went from ~250+ failures to 24 unexpected + 1 hang.
This is an intentional checkpoint commit to preserve in-progress work — the
conformance bar (full WPT + parallel suite) is NOT yet met, so this must not be
treated as complete. Remaining failures are catalogued in the plan file
(pipeTo error/abort priority, byte tee hang, byte read detach, transform size
propagation, then-interception, tee error propagation, patched-global).
Highlights of fixes already in this commit:
- transformstream requires readable/writable so C++ transform halves get the
grafted public prototypes
- ClassifyView distinguishes real Buffer from Uint8Array via prototype
- TypeError (not Error/RangeError) for released-reader/writer, byte brand,
min<=0, non-ArrayBufferView, non-detachable transfer
- EnqueueInternal no longer loses size() throws to a TryCatch destructor
- WritableStream::Abort re-reads state after signalling (no assert)
- closed_promise settles immediately when already terminal
- pipeTo no longer drops the last read chunk or masks the real error; uses
new writableStreamStateField / writableStreamCloseQueuedOrInFlight accessors
- subclassing honored via new.target in all three constructors
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drives the C++ flip to full WPT conformance: `node test/wpt/test-streams.js` is green (1404 subtests, 0 unexpected), as are the WPT compression and encoding suites. Down from ~45 unexpected failures + a crash + a hang. Web IDL binding conformance (idlharness): accessor getters are named "get <prop>"; operations carry correct `.length`; Promise-returning operations and Promise-typed attribute getters REJECT (not throw) on a foreign receiver via a HasInstance brand check + IllegalInvocationRejection (removing the V8 receiver signature, which would crash FromJSObject on an arbitrary object); respond() validates its required argument. Byte streams: default reader Release now runs the byte controller's release steps (re-tags the first pending pull-into "none") — fixes a crash and the autoAllocate+releaseLock cases; InvalidateBYOBRequest detaches the handed-out view's buffer (spec transfers the descriptor buffer on respond/enqueue); enqueue() throws when the BYOB request buffer was detached; respondWithNewView buffer-length mismatch -> ERR_INVALID_ARG_VALUE. tee: byte-tee no longer hangs (BYOB read-into close steps surface the empty view so the branch read settles); readableStreamCancel uses a lock-bypassing native helper; default tee uses guarded internal enqueue/close/error and the internal constructor (no WebIDL parse / global lookup -> survives a patched Object.prototype); error propagation deferred one tick so the final chunk is enqueued before branches error. pipeTo: spec priority-ordered shutdown checks (isOrBecomesErrored/Closed) backed by native stored-error accessors; abort actions guarded by state; close-with-error-propagation no-ops on an already-closed dest. Primordial safety: internal (pipeTo/tee) reads produce null-prototype results (forAuthorCode) so a patched Object.prototype.then can't observe piping; async iterator uses captured original read/cancel/releaseLock. Transfer: a BaseObject with no native transfer mode but implementing the JS transferable protocol (markTransferMode + @@ktransfer) is driven through that protocol in node_messaging.cc — makes the C++ stream objects structuredClone/ worker-transferable. Transform: size() throw propagates out of enqueue (TryCatch-cancel fix); readable/writable brand-check with ERR_INVALID_THIS. Parallel suite: 76/85 webstream/whatwg tests pass. The 9 remaining are internal-coupled oracle tests probing the old `kState` structure via --expose-internals (to be rewritten against the public API) plus the systematic native brand-check parity (native "Illegal invocation" vs ERR_INVALID_THIS) for controller methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the V8 receiver signatures from every synchronous webstreams operation/getter and brand-check internally, throwing an ERR_INVALID_THIS-coded TypeError (via the new CheckReceiverInvalidThis helper) instead of V8's bare "Illegal invocation". Promise-returning operations already brand-checked and rejected; route their rejection through ERR_INVALID_THIS too (IllegalInvocationRejection). This matches Node's public surface, which reports ERR_INVALID_THIS for a foreign receiver. idlharness still accepts the (still-TypeError) behavior, so WPT stays green; the parallel test-whatwg-transformstream controller brand-check assertions now pass. WPT streams: 1404 subtests, 0 unexpected failures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flipped controller's custom inspect passed an empty data object, so
`inspect(controller, { depth: 0 })` rendered `... {}` instead of the
upstream `... [Object]`. Add an internal-only
`transformStreamControllerStream` binding and have controllerInspect
report `{ stream }`, matching the original JS implementation.
test-whatwg-transformstream now passes; WPT streams stays green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrite the white-box assertions to the public surface: capture the
controller via start(c) for the instanceof check, and use stream's
isErrored() for the post-abort state check. Add a
writableStreamControllerStream introspection binding so the controller's
custom inspect can report `{ stream }` (matching the original JS), fixing
the depth-0 `[Object]` rendering.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two changes: 1. node_messaging: JSTransferable::NestedTransferables registered a nested C++ stream half (a BaseObject with no native transfer mode that implements the JS transferable protocol) as the raw BaseObject, while the serializer later writes it through its idempotent JSTransferable wrapper. The two never matched, so transferring a TransformStream threw "Object that needs transfer was found in message but not listed in transferList". Bridge the nested BaseObject to its JSTransferable wrapper, mirroring the serializer delegate. TransformStream transfer (postMessage/worker) now works. 2. Introspection: add a readableStreamController(stream) binding and readableStreamState/readableStreamStoredError + writableStreamState/writableStreamStoredError lib helpers, then rewrite test-whatwg-readablebytestream, test-whatwg-webstreams-transfer and the four adapters-to-* tests off the removed stream[kState] structure. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pipeTo args Rewrite the last white-box test off the removed stream[kState] structure: - state/storedError checks -> readableStreamState/readableStreamStoredError - post-cancel "algorithms cleared" -> observable closed state - reader<->stream identity + readRequests.length -> the locking/rejection behavior already asserted alongside - releasing the async iterator's internal reader -> new readableStreamReleaseReader(stream) introspection binding - drop the two blocks that drove now-removed internal byte-controller helpers; replace with the equivalent public post-cancel behavior This block was never reached before (the test used to crash on kState at line 326), which exposed a real bug: the exported readableStreamPipeTo called the native reader-acquire (a CHECK on receiver type) without first validating its arguments, so readableStreamPipeTo(1) aborted instead of rejecting. Validate source/dest up front. All 39 webstream parallel tests pass; WPT streams/compression/encoding green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flip's JS-transferable bridge in the message serializer dereferenced `host_object->GetTransferMode()` unconditionally. For a transfer-list entry whose native object was already freed — e.g. a detached MessagePort, where `BaseObject::Unwrap` returns nullptr — this is a null dereference and crashed (SIGSEGV in Message::Serialize). main never dereferences there: its detached-port check leads with `!host_object ||`. Guard all three bridge sites (transfer-list processing, the serializer delegate path is already null-safe via its own deref, and NestedTransferables) with a `host_object`/`base` null check so a freed entry falls through to the existing detached-port error path. Regression test test-worker-message-port-transfer-closed now passes (was a 100% SIGSEGV); full worker/messaging suite (148) green, webstreams parallel suite green, WPT streams 1404 subtests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two `make test` failures surfaced: 1. test-webapi-sharedarraybuffer-rejection: the C++ byte path lost the SharedArrayBuffer guard the JS implementation had. A SAB cannot be transferred/detached, so ReadableByteStreamController.enqueue() and ReadableStreamBYOBReader.read() must reject a SAB-backed view with ERR_INVALID_ARG_VALUE. Re-add the check (throw for enqueue, reject for read) before the buffer is otherwise used. 2. test-blob: read the blob stream's controller.desiredSize via the removed stream[kState].controller; switch it to the readableStreamController introspection binding. WPT streams green; both tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The per-pull hot path allocated two V8 Functions on every CallPullIfNeeded (the fulfil/reject reactions for the user pull() promise), via Function::New per chunk. Cache them per-controller (Data == the controller wrapper), created on first pull and reused thereafter; reset in ClearAlgorithms to break the controller<->wrapper cycle on terminal states. Effect (vs JS baseline, 30 runs): readable-read byob -42% -> -5%, normal -77% -> -49%, async-iterator -81% -> -64%, pipe-to -81% -> -75%. WPT streams (1404) + 39 webstream parallel tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
No description provided.