Now that all of MarkRoots's state is stored on the heap, it can be run
incrementally. Like with Collect, it takes a budget to determine how
long it can run. Any residual budget will be available to the caller.
One difference is that Collect calls checkOverBudget() which always checks
the time, but MarkRoots uses isOverBudget() to determine if there is
any time remaining. This only checks the current time every
kNumNodesBetweenTimeChecks nodes, to reduce the overhead of checking.
To make nsCycleCollector::MarkRoots incremental, we have to store all of its state on
the heap, so we can resume it. The only remaining state to convert is the NodePool
enumerator.
This patch makes it so that Collect takes a time budget that describes
how much longer the collection can be run for. Then we run the current phase.
Once this is done, we check whether we have exceeded our time budget or
if we have finished a collection. If neither of those have happened, we
run the cycle collector some more.
If we're a manually triggered CC, and we were in the middle of an ICC when
the CC started, then once the current CC is complete, we start a new CC
immediately. This is needed to ensure that a manually specified listener
is used, and to ensure that any garbage objects the caller expects to be
collected are in fact collected.
Note that in this patch we are always passing in an unlimited budget to
Collect, so cycle collections will always be run to completion.
Cycle collection protects against reentrancy by setting a flag to indicate a collection
is in progress. With synchronous CC, it is okay to set this in BeginCollection, and
clear it in CleanupAfterCollection. With ICC, this must be set and cleared in every
slice, so I moved the fixing of it to Collect. I also changed the name of the variable,
because we can be in the middle of an ICC without the CC being actively running,
and it is only the latter we are worried about here.
With ICC, we may have to remove things from the graph after we have finished building
the graph, so move the mapping to graph addresses into the graph itself to create a
more self-contained structure.
nsJSEnvironment::CycleCollectNow does work before and after a CC runs. With ICC, nsJSEnv won't
know where in the CC when a CC is about to begin or end, so this patch reorganizes that work
into two separate callback hooks. This requires adding a new struct, CycleCollectorStats, to
hold data nsJSEnv needs between the two calls.
Rather than trying to pass around a pointer to a results structure, this patch just adds
it to the nsCycleCollector struct, and always stores them. The results are passed back
to the end CC callback.
With ICC, mScanInProgress gets set and cleared a bunch of times so add an RAII class to turn
it on when we're doing stuff and clear it when we're not.
With that in place, we can easily move MarkRoots and ScanRoots out of BeginCollection
in preparation for making them separate phases in ICC.