Destructors of cppgc::GarbageCollected

37 views
Skip to first unread message

jo...@igalia.com

unread,
Jan 10, 2025, 8:02:38 AM1/10/25
to v8-dev
Hi,

We've been working on migration of existing wrapper classes in Node.js to use cppgc::GargageCollected, and ran into some questions regarding what can be done in the destructors. The conditions of the destructors don't seem to be very clear from the headers, so asking here for some clarification.

1. Is the destructor of cppgc::GargageCollected always called in the thread where they are created? It also seems possible for them to be called from platform worker threads? In the case where there's no guarantee about this, is the recommendation to use prefinalizers to make sure clean up is performed on the creation thread?
2. Is it okay to dereference v8::TracedReference held by a cppgc::GargageCollected in its destructor? Are they guaranteed to be still valid at that point?
3. It seems trying to mutate the heap from a cppgc::GargageCollected destructor (e.g. set internal pointers of an object, so I'd assume calling into JS or allocating objects would be even more forbidden) would result in a crash. Is that something that should not be done, or is there way to do it properly? Is it safe to do these from prefinalizers instead?

Appreciate any answers we can get, thanks!

Michael Lippautz

unread,
Jan 10, 2025, 8:09:37 AM1/10/25
to v8-...@googlegroups.com
On Fri, Jan 10, 2025 at 2:02 PM jo...@igalia.com <jo...@igalia.com> wrote:
Hi,

We've been working on migration of existing wrapper classes in Node.js to use cppgc::GargageCollected, and ran into some questions regarding what can be done in the destructors. The conditions of the destructors don't seem to be very clear from the headers, so asking here for some clarification.

1. Is the destructor of cppgc::GargageCollected always called in the thread where they are created? It also seems possible for them to be called from platform worker threads? In the case where there's no guarantee about this, is the recommendation to use prefinalizers to make sure clean up is performed on the creation thread?

It's guaranteed to be called on the creation thread where they were created. This should not be platform workers but always threads that are used to run the Isolate. There's no known issue where this is not the case, so please file a bug if you observe otherwise.
 
2. Is it okay to dereference v8::TracedReference held by a cppgc::GargageCollected in its destructor? Are they guaranteed to be still valid at that point?

No, see 3.
 
3. It seems trying to mutate the heap from a cppgc::GargageCollected destructor (e.g. set internal pointers of an object, so I'd assume calling into JS or allocating objects would be even more forbidden) would result in a crash. Is that something that should not be done, or is there way to do it properly? Is it safe to do these from prefinalizers instead?

Destructors should never refer to other managed objects, neither Oilpan nor V8. That's because the finalization order is undefined. This also means that in 2. you should not refer through a TracedReference as there's no guarantee that the V8 object is still alive. (Technically, we may have also tinkered with the TracedReference at this point. We at least did in older V8 versions).

If you need to reach through the heap you need a pre-finalizer.

-Michael

jo...@igalia.com

unread,
Jan 10, 2025, 8:12:09 AM1/10/25
to v8-dev
Thanks for the quick response!
Reply all
Reply to author
Forward
0 new messages