Description
The file src/scheduler/gc_work.rs
contains about 1200 lines of code, with more than 20 structs and more than 50 impl
items.
- There are simply too many items, and
- they are not ordered or grouped in the way they are used. Not by use cases, and not in the temporal order in a GC.
This made it difficult for developers to find the right type or function when they want to make modification to MMTk. But one design goal of MMTk is to make this easy.
Reorganizing this file into multiple files
We can categorize the work packets and traits by their use cases.
Unless specified, items listed below are struct
items.
- Generic GC scheduling work packets.
ScheduleCollection
StopMutators
Prepare
PrepareMutator
PrepareCollector
Release
ReleaseMutator
ReleaseCollector
VMPostForwarding
(running concurrently withRelease
)
- Root scanning
ScanMutatorRoots
ScanVMSpecificRoots
ProcessEdgesWorkRootsWorkFactory
(implementsRootsWorkFactory
defined insrc/vm/scanning.rs
)- enum
RootsKind
- Tracing (transitive closure)
- Slots/edges
ProcessEdgesBase
(This is all about processing slots instead of edges).- trait
ProcessEdgesWork
(This part really needs to be refactored.ProcessEdgesWork::trace_object
shouldn't be specific to slot-enqueued tracing.) SFTProcessEdges
PlanProcessEdges
ProcessEdgesWorkTracer
(implementsObjectTracer
defined insrc/vm/scanning.rs
)UnsupportedProcessEdges
- Nodes
- trait
ScanObjectsWork
ScanObjects
PlanScanObjects
ProcessRootNode
(for pinning and transitive-pinning roots)
- trait
- Slots/edges
- Finalizer and weak references
ProcessEdgesWorkTracerContext
(implementsTracerContext
defined insrc/vm/scanning.rs
)VMProcessWeakRefs
VMForwardWeakRefs
Refactoring slots-processing work packets
In the early stage of the Rust port, MMTk was very focused on slot-enqueuing tracing because that's what OpenJDK and JikesRVM do. One design decision which I think is bad is that it mixed up "edge processing" and "slots processing".
- Slot processing: For each slot in a list of slots, load from it, call
trace_object
, and store back forwarded reference. - Edge visiting: The
trace_object(obj) -> new_obj
method. This effectively visits an object graph edge that points toobj
, regardless whetherobj
is loaded from a givenSlot
or obtained in VM-specific ways inScanning::scan_object_and_trace_edges
. In the end, if a VM binding only supports node-enqueuing tracing (such as Ruby), we have to wrapProcessEdgesWork
behind theObjectTracer
trait which only provides thetrace_object
method (that is,ProcessEdgesWorkTracer
).
I had a branch that refactors the trace_object
into a dedicated type and leaves the ProcessEdgesWork
dedicated to slot processing. The code is here: #1278, but it is very old.
And #599 contains more information about my intended refactoring.