Open Bug 915097 Opened 6 years ago Updated 6 years ago

Traverse-only cycle collections


(Core :: XPCOM, defect)

Not set




(Reporter: smaug, Unassigned)



(1 file)

In order to detect cycles when there is a main-thread MessagePort connected to worker MessagePort, we need to run CC on both threads, but not actually unlink.

So, I was thinking we could have traverse-only cycle collections occasionally.
If such CC detects garbage, it wouldn't actually unlink, but only call some
method on cycle collectable.

MessagePort would report the reference coming from the other thread as its internal
reference (similar to WrappedJS), so it would be known.

Then, if a port is marked as garbage it would notify the other side about its state
and if that is also garbage, break the cycle. (well, it might need few round-trips in order to make sure possible garbage stays garbage.)

A port with some pending messages to dispatch to JS wouldn't ever be garbage, and also
using a port would make it drop the garbage bit.
Jonas is probably interested in this, as I am!
I've actually written one for ICC debugging.  IIRC, the main trick is non-destructive purple buffer scanning.
hmm, what you mean?
We could put all the garbage back to purple buffer, effectively just root/unroot should be enough in most cases.
though, non-destructive pb scanning should work even better :)
It looks something like this.  Using a template rather than a constant bool field may be premature optimization.
For the message ports we can end up with object graphs like

          P1 <------> P3
          |           |          | message channel
thread 1  |           |
   - - - -|- - - - - -|- - -    -> JS references
thread 2  |           |
          |           |         P1 MessagePort
          P2 <------> P4

So none of the ports could simply be GCed since they are being held alive by both their respective message channel as well as by other JS objects in the same scope.

So in order for this to be collected, when thread 1 is CCed, we'd have to notice that P1 and P3 are in a group of objects that are only referenced from other threads (i.e. through message channels). At some point later when we CC thread 2 we would notice the same things. Only then can we know that the relevant objects on both sides of the thread boundary can be collected.

To make matters more complicated we also have to watch out for the situation when the objects in P1 gains references between the CC in thread 1 and the CC in thread 2. This can happen when P1 or P3 receives a message.

Another thing that makes matters more complicated is that the cycle can be through any number of threads. Not just two as in the example above.

And then there is the fact that ports can at any point be passed to another thread.

So Traverse-only cycle collection is part of what we need here. But in addition to that we need multi-threaded cycle collection of MessagePort objects.
Yes, traverse-only is just one part, and what I said about WrappedJS is basically similar (not the same) what you just pictured. References from the other thread would be handled as internal.

We won't add true multi-threaded CC if just possible, and I believe it should be possible by detecting something as per-thread garbage and passing garbage generation to the other side.
(I'm somewhat against multi-threaded CC because so far it looks like the web platform will have
rather simple threading model and cycles between threads should be well-known)

The fact that port can be sent to yet another thread shouldn't make this more complicated
(I'm not saying this isn't isn't complicated ;) ).
Yes, we definitely don't need to add full multi-threaded support to the current cycle collector.

But I do think that in order to solve the problem discussed here, we need full multi-threaded cycle detection of MessagePort objects. But that would likely be done using other code than the current generic cycle collector.
You need to log in before you can comment on or make changes to this bug.