We've fixed this issue. I believe the problem was due to not correctly
handling wrapper objects allocated white after their parent had already
been traced. (In the past I had had a bug that occurred due to objects
allocated black, and I had been left with the impression that objects were
always allocated black... oops.)

On Wed, Jan 30, 2019 at 12:49 PM Michael Lippautz <[email protected]>
wrote:

> Well, barriers are only needed for incremental (and concurrent)
> collection. From an embedder perspective all references reported by V8 can
> be traced after EmbedderHeapTracer::EnterFinalPause() is called which would
> mean that there's no incremental collection and barriers are unnecessary.
>

That would feel like a cop-out though. :) I'd like to get the full power of
incremental tracing.

We suggest using actually tracing for C++ to solve this problem. This way
> objects are traced through until they reach entry points into V8.
>
> It's more engineering effort but simple to reason about.
>

Yes, we do actually trace through the C++ objects (otherwise we couldn't
collect cycles). But we don't track our own "roots", but instead try to
keep track of which JS wrappers need to be considered "roots" at any
particular time, which when combined with lazy wrapper allocation creates
some complexity. I think I've figured it out at this point, though.

The weak callback is only for the destructor, right? How do you
> differentiate between a C++ object without JS wrapper (lazy creation) and a
> C++ object that should be destructed?
>

Our C++ objects are refcounted. We count references from other C++ objects,
and then when we create a JS wrapper, we increment the refcount once for
that as well. So the weak callback decrements the refcount.

This has the nice property that a bug in our GC integration has the
worst-case effect that the wrapper gets dropped and recreated (losing any
properties that were added to it from JS code), rather than a
use-after-free.

- A strong handle, when any non-traced references exist from C++, to keep
>> the wrapper alive.
>>
>
> These should usually be temporary (ideally Local<T>) and looks fine to me.
>

These references aren't necessarily held on the stack, though.

On Wed, Jan 30, 2019 at 12:55 PM Michael Lippautz <[email protected]>
wrote:

> The redundant trace can be avoided by having a color marker on the C++
> object itself so that it only traces through it once.
>

> Ultimately, solving all those issues leads to having a fully trace-based
> system with marking colors on the C++ side too. We went that way because we
> need a system to collect reference cycles and the easiest way to do so is
> by basing the whole system on tracing.
>

I ended up having each of my C++ objects remember the last trace cycle in
which they we reached -- so if they're reached a second time in the same
cycle, I can return early. I guess this is effectively a two-color system
(lastSeen == currentTrace => black, lastSeen < currentTrace => white). I
don't need a "gray" for my C++ objects because I do the tracing depth-first
(which works fine because my C++ object trees are all very small).

-Kenton

-- 
-- 
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to