Skip to content

src: track cppgc wrappers with a list in Realm - #56534

Merged
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
joyeecheung:cppgc-list
May 19, 2025
Merged

nodejs-github-bot merged 2 commits into
nodejs:mainfrom
joyeecheung:cppgc-list

Conversation

@joyeecheung

@joyeecheung joyeecheung commented Jan 9, 2025 •

Copy link
Copy Markdown
Member

src: track cppgc wrappers with a list in Realm

This allows us to perform cleanups of cppgc wrappers that rely
on a living Realm during Realm shutdown. Otherwise
the cleanup may happen during object destruction, which can
be triggered by GC after Realm shutdown, leading to invalid
access to Realm.

The general pattern for this type of non-trivial destruction is
designed to be:

class MyWrap final : CPPGC_MIXIN(MyWrap) {
 public:
  ~MyWrap() { this->Finalize(); }
  void Clean(Realm* realm) override {
     // Do cleanup that relies on a living Realm. This would be
     // called by CppgcMixin::Finalize() first during Realm shutdown,
     // while the Realm is still alive. If the destructor calls
     // Finalize() again later during garbage collection that happens after
     // Realm shutdown, Clean() would be skipped, preventing
     // invalid access to the Realm.
  }
}

In addition, this allows us to trace external memory held by the wrappers
in the heap snapshots if we add synthethic edges between the wrappers
and other nodes in the embdder graph callback, or to perform snapshot
serialization for them.

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Jan 9, 2025
@joyeecheung joyeecheung added the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Jan 9, 2025
Comment thread src/cppgc_helpers.h Resolved
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Jan 9, 2025
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@codecov

codecov Bot commented Jan 9, 2025 •

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 58.21918% with 61 lines in your changes missing coverage. Please review.

Project coverage is 90.12%. Comparing base (4bfcad1) to head (bdd34b1).
Report is 286 commits behind head on main.

Files with missing lines Patch % Lines
src/memory_tracker-inl.h 22.41% 42 Missing and 3 partials ⚠️
src/cppgc_helpers.cc 75.00% 4 Missing and 2 partials ⚠️
src/cppgc_helpers-inl.h 86.20% 1 Missing and 3 partials ⚠️
src/cppgc_helpers.h 66.66% 4 Missing ⚠️
src/node_contextify.h 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #56534      +/-   ##
==========================================
- Coverage   90.14%   90.12%   -0.03%     
==========================================
  Files         630      632       +2     
  Lines      186784   186905     +121     
  Branches    36653    36682      +29     
==========================================
+ Hits       168377   168447      +70     
- Misses      11205    11247      +42     
- Partials     7202     7211       +9     
Files with missing lines Coverage Δ
src/memory_tracker.h 100.00% <100.00%> (ø)
src/node_realm-inl.h 89.83% <100.00%> (+0.73%) ⬆️
src/node_realm.cc 75.14% <100.00%> (+1.73%) ⬆️
src/node_realm.h 100.00% <100.00%> (ø)
src/node_contextify.h 70.58% <0.00%> (-9.42%) ⬇️
src/cppgc_helpers-inl.h 86.20% <86.20%> (ø)
src/cppgc_helpers.h 73.33% <66.66%> (-13.04%) ⬇️
src/cppgc_helpers.cc 75.00% <75.00%> (ø)
src/memory_tracker-inl.h 57.43% <22.41%> (-11.51%) ⬇️

... and 37 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread src/README.md Resolved
Comment thread src/README.md Resolved
@legendecas legendecas added the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Jan 23, 2025
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Jan 23, 2025
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Comment thread src/README.md Resolved
Comment thread src/README.md Resolved
@joyeecheung

joyeecheung commented Feb 14, 2025 •

Copy link
Copy Markdown
Member Author

Trying to rebase #51017 on top of it to verify the "use list for heap snapshot integration" idea. It seems we'll need to update the MemoryTracker code to stop creating duplicate nodes for cppgc wrappers (either that, or use something different for the cppgc wrapper list). Still looking into it..

@joyeecheung
joyeecheung force-pushed the cppgc-list branch 3 times, most recently from ed3648a to 036116a Compare March 7, 2025 15:54
Comment thread src/README.md Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these rules may be non-obvious to many developers. For example, let's say someone has a wrapped object that is holding a BaseObjectPtr<Foo> as a member... Just based on reading this documentation, as a newcomer I would not know which of these conditions may apply. Do I need to clear the BaseObjectPtr in the CleanEnvResource callback? What about if it has a v8::Global<...> member field? Is it ok to just let that be cleared by the default destructor? etc. I think calling out a few more detailed examples (and not partial examples like you have currently) of each case would be most helpful.

@joyeecheung joyeecheung Mar 7, 2025 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's say someone has a wrapped object that is holding a BaseObjectPtr<Foo> as a member

I don't think this would be supported in the nearest future, or will ever be supported - a cppgc-object should not hold on to a BaseObjectPtr<Foo> without converting that BaseObjectPtr<Foo> to cppgc-managed first - and then in that case they should use cppgc::Member<Foo> to hold on to that instead. The migration needs to be done bottom-to-top. In the case of using cppgc::Member<Foo>, nothing special needs to be done in the destructor, V8 will handle that properly.

What about if it has a v8::Global<...> member field?

I think in most cases, this should be v8::TracedReference instead. In that case nothing special needs to be done in the destructor. This has been documented in the Creating C++ to JavaScript references in cppgc-managed objects section.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a note about not supporting cross BaseObject and cppgc-managed wrapeprs. I don't think it's impossible but someone needs to implement some helpers for that first (I am not 100% sure what needs to be done, but using cppgc::Persistent would be a start).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can somehow have c++ linting detect it for us if someone includes a BaseObjectPtr member in one of these? .... in any case, this all sounds fine, I'd just like to make sure this gets included somehow in the documentation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it comes up in the future that some people attempt to use BaseObjectPtr in a cppgc wrapper, we can consider adding some linting rules. For now it seems a bit too premature. Since we are still in an early phase of cppgc migration, I think the rule of thumb is probably:

  • If you are not looking into also updating the cppgc helpers, only use cppgc on classes that aren't more than what existing cppgc wrappers are doing (at this point in time, v8 handles and MemoryRetainer over other plain types are supported, cppgc members are supposed to be supported by we haven't tried it internally yet)
  • If you want to tread on untrodden paths and manage more complex memory structures, like a cppgc wrapper referencing BaseObject, expect to figure out how to make it work and update the cppgc helpers yourself.

Comment thread src/cppgc_helpers.h Resolved
@joyeecheung joyeecheung changed the title src: track cppgc wrappers with CppgcWrapperList in Environment src: track cppgc wrappers with a list in Realm Mar 7, 2025
@joyeecheung
joyeecheung force-pushed the cppgc-list branch 2 times, most recently from 909a80a to 6fd34b0 Compare March 7, 2025 16:44
@joyeecheung

joyeecheung commented Mar 7, 2025 •

Copy link
Copy Markdown
Member Author

I did a few updates to the design:

  • The cleanup pattern is now Finalize() calling Clean() which takes a Realm. I think Finalize() sounds better and is less confusing.
  • The wrapper list is now per-Realm instead of per-Environment, similar to how BaseObjects are managed.
  • This makes the CppgcMixin a MemoryRetainer and includes de-duplication code of the MemoryRetainerNode, so that subclasses can implement MemoryInfo to track additional data just like before. For an example of what it looks like, see wip: crypto: use cppgc to manage Hash #51017 (comment)

ckerr added a commit to electron/electron that referenced this pull request Aug 5, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
ckerr added a commit to electron/electron that referenced this pull request Aug 5, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
ckerr added a commit to electron/electron that referenced this pull request Aug 5, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
ckerr added a commit to electron/electron that referenced this pull request Aug 5, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
ckerr added a commit to electron/electron that referenced this pull request Aug 7, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
jkleinsc pushed a commit to electron/electron that referenced this pull request Aug 20, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
jkleinsc pushed a commit to electron/electron that referenced this pull request Aug 24, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
jkleinsc pushed a commit to electron/electron that referenced this pull request Aug 24, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
jkleinsc pushed a commit to electron/electron that referenced this pull request Aug 24, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
jkleinsc pushed a commit to electron/electron that referenced this pull request Aug 25, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
jkleinsc pushed a commit to electron/electron that referenced this pull request Aug 25, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
jkleinsc pushed a commit to electron/electron that referenced this pull request Aug 25, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
deepak1556 pushed a commit to electron/electron that referenced this pull request Aug 26, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
jkleinsc pushed a commit to electron/electron that referenced this pull request Aug 26, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
deepak1556 added a commit to electron/electron that referenced this pull request Aug 27, 2026
* chore: bump node in DEPS to v24.19.0

* chore: remove upstreamed patch

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* chore: update patches (trivial only)

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): add perfetto trace agent

Backport Node's Perfetto tracing agent now that Chromium V8 no longer exposes the legacy tracing controller APIs.

Ref: nodejs/node#64565

Ref: nodejs/node#64721

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64565: src: rename legacy trace event headers

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): sample delay per event loop iteration

Ref: nodejs/node#62935

Ref: nodejs/node#64480

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): avoid redundant std::get_if<>() call

Ref: nodejs/node#64094

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): add perfetto trace agent

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64053: src: abstract tracing agent for legacy and perfetto

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): add perfetto trace agent

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64053: src: abstract tracing agent for legacy and perfetto

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): support native IPC serialization in V8 sandbox

Ref: nodejs/node#63933

Co-Authored-By: GitHub Copilot <copilot@github.com>

* test: hide output package.json in node spec runner

Virtual CommonJS files rooted at process.execPath inherit the output directory's type=module package unless the runner hides it alongside Chromium's root package.

Ref: nodejs/node#44713

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): account for libc++ rm error on Electron Linux

Node's fs.rmSync() delegates recursive deletion to
std::filesystem::remove_all(). Electron's Linux build uses libc++, which
reports ENOTEMPTY here while Node's libstdc++ build reports EACCES.

Ref: nodejs/node#57103

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): mark worker stack-size test flaky

Ref: nodejs/node#33085

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): restore user timing trace events

Ref: #50591

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): own fallback tracing controller

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): release cppgc wrapper tracking nodes

Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>

* test: extend cpp heap remote app timeout

The ChunkedDataPipeReadableStream liveness test can exceed the remote fixture's 30-second watchdog under Linux ASAN, which disconnects the control socket before assertions run.

Ref: #52447

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): remove unused legacy tracing backend

Electron builds Node exclusively with Perfetto since #50591. Wire the upstream Perfetto agent directly and drop the legacy header split and dual-backend source lists.

Ref: #50591

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* docs: better explanation of test_account_for_libc_rm_error_on_electron_linux.patch

* refactor: node tracing agent and track event registration (#52678)

* fix: register Node tracing in utility processes

The Node upgrade moved tracing setup out of JavascriptEnvironment, but the utility process did not adopt the explicit registration used by other embedded Node hosts. Register its TrackEvent data source with Chromium before creating the isolate.

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* chore: update patches (trivial only)

* chore: update patches

* Revert "fix(patch): mark worker stack-size test flaky"

This reverts commit f2e5cb5.

* fixup! support native IPC serialization in V8 sandbox

* chore: address review feedback

* fixup! support native IPC serialization in V8 sandbox

Allocate ValueSerializer buffers as V8 backing stores and retain the
original backing store when adopting the released buffer. This preserves
the shared allocator lifetime when serialized buffers are transferred
from a worker and outlive its isolate.

* fixup! refactor: node tracing agent and track event registration

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
Co-authored-by: Robo <hop2deep@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
jkleinsc pushed a commit to electron/electron that referenced this pull request Aug 27, 2026
Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>
MarshallOfSound pushed a commit to electron/electron that referenced this pull request Aug 28, 2026
* chore: bump node in DEPS to v24.19.0

* chore: remove upstreamed patch

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* chore: update patches (trivial only)

* fix(patch): add perfetto trace agent

Backport Node's Perfetto tracing agent now that Chromium V8 no longer exposes the legacy tracing controller APIs.

Ref: nodejs/node#64565

Ref: nodejs/node#64721

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64565: src: rename legacy trace event headers

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): sample delay per event loop iteration

Ref: nodejs/node#62935

Ref: nodejs/node#64480

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): avoid redundant std::get_if<>() call

Ref: nodejs/node#64094

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): add perfetto trace agent

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64053: src: abstract tracing agent for legacy and perfetto

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): add perfetto trace agent

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64053: src: abstract tracing agent for legacy and perfetto

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): support native IPC serialization in V8 sandbox

Ref: nodejs/node#63933

Co-Authored-By: GitHub Copilot <copilot@github.com>

* test: hide output package.json in node spec runner

Virtual CommonJS files rooted at process.execPath inherit the output directory's type=module package unless the runner hides it alongside Chromium's root package.

Ref: nodejs/node#44713

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): account for libc++ rm error on Electron Linux

Node's fs.rmSync() delegates recursive deletion to
std::filesystem::remove_all(). Electron's Linux build uses libc++, which
reports ENOTEMPTY here while Node's libstdc++ build reports EACCES.

Ref: nodejs/node#57103

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): mark worker stack-size test flaky

Ref: nodejs/node#33085

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): restore user timing trace events

Ref: #50591

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): own fallback tracing controller

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): release cppgc wrapper tracking nodes

Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): remove unused legacy tracing backend

Electron builds Node exclusively with Perfetto since #50591. Wire the upstream Perfetto agent directly and drop the legacy header split and dual-backend source lists.

Ref: #50591

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* docs: better explanation of test_account_for_libc_rm_error_on_electron_linux.patch

* refactor: node tracing agent and track event registration (#52678)

* fix: register Node tracing in utility processes

The Node upgrade moved tracing setup out of JavascriptEnvironment, but the utility process did not adopt the explicit registration used by other embedded Node hosts. Register its TrackEvent data source with Chromium before creating the isolate.

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* chore: update patches (trivial only)

* chore: update patches (trivial only)

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): skip unsupported WebCrypto fixtures with BoringSSL

Ref: nodejs/node#63520

Co-Authored-By: GitHub Copilot <copilot@github.com>

* Revert "fix(patch): mark worker stack-size test flaky"

This reverts commit f2e5cb5.

* chore: address review feedback

(cherry picked from commit b8f475c)

* fixup! refactor: node tracing agent and track event registration

(cherry picked from commit d898f33)

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
Co-authored-by: Robo <hop2deep@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
MarshallOfSound pushed a commit to electron/electron that referenced this pull request Aug 28, 2026
* chore: bump node in DEPS to v24.19.0

* chore: remove upstreamed patch

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* chore: update patches (trivial only)

* fix(patch): add perfetto trace agent

Backport Node's Perfetto tracing agent now that Chromium V8 no longer exposes the legacy tracing controller APIs.

Ref: nodejs/node#64565

Ref: nodejs/node#64721

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64565: src: rename legacy trace event headers

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): sample delay per event loop iteration

Ref: nodejs/node#62935

Ref: nodejs/node#64480

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): avoid redundant std::get_if<>() call

Ref: nodejs/node#64094

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): add perfetto trace agent

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64053: src: abstract tracing agent for legacy and perfetto

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): add perfetto trace agent

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64053: src: abstract tracing agent for legacy and perfetto

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): support native IPC serialization in V8 sandbox

Ref: nodejs/node#63933

Co-Authored-By: GitHub Copilot <copilot@github.com>

* test: hide output package.json in node spec runner

Virtual CommonJS files rooted at process.execPath inherit the output directory's type=module package unless the runner hides it alongside Chromium's root package.

Ref: nodejs/node#44713

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): account for libc++ rm error on Electron Linux

Node's fs.rmSync() delegates recursive deletion to
std::filesystem::remove_all(). Electron's Linux build uses libc++, which
reports ENOTEMPTY here while Node's libstdc++ build reports EACCES.

Ref: nodejs/node#57103

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): mark worker stack-size test flaky

Ref: nodejs/node#33085

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): restore user timing trace events

Ref: #50591

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): own fallback tracing controller

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): release cppgc wrapper tracking nodes

Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>

* test: extend cpp heap remote app timeout

The ChunkedDataPipeReadableStream liveness test can exceed the remote fixture's 30-second watchdog under Linux ASAN, which disconnects the control socket before assertions run.

Ref: #52447

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): remove unused legacy tracing backend

Electron builds Node exclusively with Perfetto since #50591. Wire the upstream Perfetto agent directly and drop the legacy header split and dual-backend source lists.

Ref: #50591

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* docs: better explanation of test_account_for_libc_rm_error_on_electron_linux.patch

* refactor: node tracing agent and track event registration (#52678)

* fix: register Node tracing in utility processes

The Node upgrade moved tracing setup out of JavascriptEnvironment, but the utility process did not adopt the explicit registration used by other embedded Node hosts. Register its TrackEvent data source with Chromium before creating the isolate.

Co-Authored-By: John Kleinschmidt <jkleinsc@electronjs.org>

* chore: update patches (trivial only)

* chore: update patches (trivial only)

Co-Authored-By: GitHub Copilot <copilot@github.com>

* Revert "fix(patch): mark worker stack-size test flaky"

This reverts commit f2e5cb5.

* fixup! support native IPC serialization in V8 sandbox

* chore: address review feedback

(cherry picked from commit b8f475c)

* fixup! support native IPC serialization in V8 sandbox

Allocate ValueSerializer buffers as V8 backing stores and retain the
original backing store when adopting the released buffer. This preserves
the shared allocator lifetime when serialized buffers are transferred
from a worker and outlive its isolate.

(cherry picked from commit f35b26d)

* fixup! refactor: node tracing agent and track event registration

(cherry picked from commit d898f33)

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
Co-authored-by: Robo <hop2deep@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
jkleinsc added a commit to electron/electron that referenced this pull request Aug 28, 2026
* chore: bump node in DEPS to v24.19.0

* chore: remove upstreamed patch

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* chore: update patches (trivial only)

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): add perfetto trace agent

Backport Node's Perfetto tracing agent now that Chromium V8 no longer exposes the legacy tracing controller APIs.

Ref: nodejs/node#64565

Ref: nodejs/node#64721

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64565: src: rename legacy trace event headers

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): sample delay per event loop iteration

Ref: nodejs/node#62935

Ref: nodejs/node#64480

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): avoid redundant std::get_if<>() call

Ref: nodejs/node#64094

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): add perfetto trace agent

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64053: src: abstract tracing agent for legacy and perfetto

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): add perfetto trace agent

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* node#64053: src: abstract tracing agent for legacy and perfetto

Ref: nodejs/node#64053

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): support native IPC serialization in V8 sandbox

Ref: nodejs/node#63933

Co-Authored-By: GitHub Copilot <copilot@github.com>

* test: hide output package.json in node spec runner

Virtual CommonJS files rooted at process.execPath inherit the output directory's type=module package unless the runner hides it alongside Chromium's root package.

Ref: nodejs/node#44713

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): account for libc++ rm error on Electron Linux

Node's fs.rmSync() delegates recursive deletion to
std::filesystem::remove_all(). Electron's Linux build uses libc++, which
reports ENOTEMPTY here while Node's libstdc++ build reports EACCES.

Ref: nodejs/node#57103

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): mark worker stack-size test flaky

Ref: nodejs/node#33085

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): restore user timing trace events

Ref: #50591

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): own fallback tracing controller

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): release cppgc wrapper tracking nodes

Ref: nodejs/node#56534

Co-Authored-By: GitHub Copilot <copilot@github.com>

* test: extend cpp heap remote app timeout

The ChunkedDataPipeReadableStream liveness test can exceed the remote fixture's 30-second watchdog under Linux ASAN, which disconnects the control socket before assertions run.

Ref: #52447

Co-Authored-By: GitHub Copilot <copilot@github.com>

* fix(patch): remove unused legacy tracing backend

Electron builds Node exclusively with Perfetto since #50591. Wire the upstream Perfetto agent directly and drop the legacy header split and dual-backend source lists.

Ref: #50591

Ref: nodejs/node#64565

Co-Authored-By: GitHub Copilot <copilot@github.com>

* docs: better explanation of test_account_for_libc_rm_error_on_electron_linux.patch

* refactor: node tracing agent and track event registration (#52678)

* fix: register Node tracing in utility processes

The Node upgrade moved tracing setup out of JavascriptEnvironment, but the utility process did not adopt the explicit registration used by other embedded Node hosts. Register its TrackEvent data source with Chromium before creating the isolate.

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* chore: update patches (trivial only)

* chore: update patches (trivial only)

Co-Authored-By: GitHub Copilot <copilot@github.com>

* Revert "fix(patch): mark worker stack-size test flaky"

This reverts commit f2e5cb5.

* fixup! support native IPC serialization in V8 sandbox

* chore: update patch

* chore: address review feedback

(cherry picked from commit b8f475c)

* fixup! support native IPC serialization in V8 sandbox

Allocate ValueSerializer buffers as V8 backing stores and retain the
original backing store when adopting the released buffer. This preserves
the shared allocator lifetime when serialized buffers are transferred
from a worker and outlive its isolate.

(cherry picked from commit f35b26d)

* fixup! refactor: node tracing agent and track event registration

(cherry picked from commit d898f33)

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
Co-authored-by: Robo <hop2deep@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
codebytere added a commit to codebytere/node that referenced this pull request Sep 4, 2026
`Realm::RunCleanup()` finalizes the cppgc-managed wrappers it tracks
so that none of them touches the Realm once it is gone, but it reaches
them through weak persistents, and the GC clears those as soon as it
finds a wrapper dead. With lazy and concurrent sweeping the destructor
can run much later, so a wrapper collected shortly before
`FreeEnvironment()` and swept after it was skipped by the cleanup and
kept its `realm_`: `~CppgcMixin()` then wrote
`should_purge_empty_cppgc_wrappers_` into the freed Realm, and a
subclass destructor calling `Finalize()` as documented would have
called `Clean()` with a dangling Realm. A Worker that compiles a few
`vm.Script`s, gets a full GC from external memory pressure and calls
`process.exit()` is enough to hit the first case.

Move the Realm pointer into the list node, which the wrapper now owns
and deletes in its destructor. `CppgcWrapperList::Cleanup()` unlinks
every node, finalizing the wrappers that are still alive and clearing
the Realm pointer for the collected ones, which only their own
destructor may still touch. `Realm::PendingCleanup()` accounts for the
list so it is always drained. The purge flag, its GC epilogue callback
and `PurgeEmpty()` are no longer needed, and removing them also stops
the list nodes of wrappers that are alive at `FreeEnvironment()` from
leaking.

Refs: nodejs#56534
Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
codebytere added a commit to codebytere/node that referenced this pull request Sep 7, 2026
`MemoryTracker::AddNode(const CppgcMixin*)` allocates a
`MemoryRetainerNode` that only stands in for the wrapper's JS node while
its `MemoryInfo()` runs; unlike the other node kinds it is not handed
to the `EmbedderGraph`, and nothing freed it. Every heap snapshot (or
other `BuildEmbedderGraph` call) leaked one node per live `vm.Script`
or `vm` context.

Keep the placeholders in the tracker and free them with it, and make
the already-seen path in `Track(const CppgcMixin*)` add its edge to the
wrapper's JS node like the first visit does, so the graph never refers
to a placeholder.

Refs: nodejs#56534
Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
codebytere added a commit to codebytere/node that referenced this pull request Sep 10, 2026
`MemoryTracker::AddNode(const CppgcMixin*)` allocates a
`MemoryRetainerNode` that only stands in for the wrapper's JS node while
its `MemoryInfo()` runs; unlike the other node kinds it is not handed
to the `EmbedderGraph`, and nothing freed it. Every heap snapshot (or
other `BuildEmbedderGraph` call) leaked one node per live `vm.Script`
or `vm` context.

Keep the placeholders in the tracker and free them with it, and make
the already-seen path in `Track(const CppgcMixin*)` add its edge to the
wrapper's JS node like the first visit does, so the graph never refers
to a placeholder.

Refs: nodejs#56534
Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
codebytere added a commit that referenced this pull request Sep 11, 2026
`Realm::RunCleanup()` finalizes the cppgc-managed wrappers it tracks
so that none of them touches the Realm once it is gone, but it reaches
them through weak persistents, and the GC clears those as soon as it
finds a wrapper dead. With lazy and concurrent sweeping the destructor
can run much later, so a wrapper collected shortly before
`FreeEnvironment()` and swept after it was skipped by the cleanup and
kept its `realm_`: `~CppgcMixin()` then wrote
`should_purge_empty_cppgc_wrappers_` into the freed Realm, and a
subclass destructor calling `Finalize()` as documented would have
called `Clean()` with a dangling Realm. A Worker that compiles a few
`vm.Script`s, gets a full GC from external memory pressure and calls
`process.exit()` is enough to hit the first case.

Move the Realm pointer into the list node, which the wrapper now owns
and deletes in its destructor. `CppgcWrapperList::Cleanup()` unlinks
every node, finalizing the wrappers that are still alive and clearing
the Realm pointer for the collected ones, which only their own
destructor may still touch. `Realm::PendingCleanup()` accounts for the
list so it is always drained. The purge flag, its GC epilogue callback
and `PurgeEmpty()` are no longer needed, and removing them also stops
the list nodes of wrappers that are alive at `FreeEnvironment()` from
leaking.

Refs: #56534
Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
PR-URL: #65778
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
codebytere added a commit to codebytere/node that referenced this pull request Sep 11, 2026
`MemoryTracker::AddNode(const CppgcMixin*)` allocates a
`MemoryRetainerNode` that only stands in for the wrapper's JS node while
its `MemoryInfo()` runs; unlike the other node kinds it is not handed
to the `EmbedderGraph`, and nothing freed it. Every heap snapshot (or
other `BuildEmbedderGraph` call) leaked one node per live `vm.Script`
or `vm` context.

Keep the placeholders in the tracker and free them with it, and make
the already-seen path in `Track(const CppgcMixin*)` add its edge to the
wrapper's JS node like the first visit does, so the graph never refers
to a placeholder.

Refs: nodejs#56534
Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
codebytere added a commit to codebytere/node that referenced this pull request Sep 13, 2026
`MemoryTracker::AddNode(const CppgcMixin*)` allocates a
`MemoryRetainerNode` that only stands in for the wrapper's JS node while
its `MemoryInfo()` runs; unlike the other node kinds it is not handed
to the `EmbedderGraph`, and nothing freed it. Every heap snapshot (or
other `BuildEmbedderGraph` call) leaked one node per live `vm.Script`
or `vm` context.

Keep the placeholders in the tracker and free them with it, and make
the already-seen path in `Track(const CppgcMixin*)` add its edge to the
wrapper's JS node like the first visit does, so the graph never refers
to a placeholder.

Refs: nodejs#56534
Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
codebytere added a commit to codebytere/node that referenced this pull request Sep 16, 2026
`MemoryTracker::AddNode(const CppgcMixin*)` allocates a
`MemoryRetainerNode` that only stands in for the wrapper's JS node while
its `MemoryInfo()` runs; unlike the other node kinds it is not handed
to the `EmbedderGraph`, and nothing freed it. Every heap snapshot (or
other `BuildEmbedderGraph` call) leaked one node per live `vm.Script`
or `vm` context.

Keep the placeholders in the tracker and free them with it, and make
the already-seen path in `Track(const CppgcMixin*)` add its edge to the
wrapper's JS node like the first visit does, so the graph never refers
to a placeholder.

Refs: nodejs#56534
Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
aduh95 pushed a commit that referenced this pull request Sep 16, 2026
`Realm::RunCleanup()` finalizes the cppgc-managed wrappers it tracks
so that none of them touches the Realm once it is gone, but it reaches
them through weak persistents, and the GC clears those as soon as it
finds a wrapper dead. With lazy and concurrent sweeping the destructor
can run much later, so a wrapper collected shortly before
`FreeEnvironment()` and swept after it was skipped by the cleanup and
kept its `realm_`: `~CppgcMixin()` then wrote
`should_purge_empty_cppgc_wrappers_` into the freed Realm, and a
subclass destructor calling `Finalize()` as documented would have
called `Clean()` with a dangling Realm. A Worker that compiles a few
`vm.Script`s, gets a full GC from external memory pressure and calls
`process.exit()` is enough to hit the first case.

Move the Realm pointer into the list node, which the wrapper now owns
and deletes in its destructor. `CppgcWrapperList::Cleanup()` unlinks
every node, finalizing the wrappers that are still alive and clearing
the Realm pointer for the collected ones, which only their own
destructor may still touch. `Realm::PendingCleanup()` accounts for the
list so it is always drained. The purge flag, its GC epilogue callback
and `PurgeEmpty()` are no longer needed, and removing them also stops
the list nodes of wrappers that are alive at `FreeEnvironment()` from
leaking.

Refs: #56534
Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
PR-URL: #65778
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-requested-v22.x PRs awaiting manual backport to the v22.x-staging branch. c++ Issues and PRs that require attention from people who are familiar with C++. commit-queue-squash PRs the Commit Queue should land as one squashed commit. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants