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 with Release)
- Root scanning
ScanMutatorRoots
ScanVMSpecificRoots
ProcessEdgesWorkRootsWorkFactory (implements RootsWorkFactory defined in src/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 (implements ObjectTracer defined in src/vm/scanning.rs)
UnsupportedProcessEdges
- Nodes
- trait
ScanObjectsWork
ScanObjects
PlanScanObjects
ProcessRootNode (for pinning and transitive-pinning roots)
- Finalizer and weak references
ProcessEdgesWorkTracerContext (implements TracerContext defined in src/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 to obj, regardless whether obj is loaded from a given Slot or obtained in VM-specific ways in Scanning::scan_object_and_trace_edges. In the end, if a VM binding only supports node-enqueuing tracing (such as Ruby), we have to wrap ProcessEdgesWork behind the ObjectTracer trait which only provides the trace_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.
The file
src/scheduler/gc_work.rscontains about 1200 lines of code, with more than 20 structs and more than 50implitems.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
structitems.ScheduleCollectionStopMutatorsPreparePrepareMutatorPrepareCollectorReleaseReleaseMutatorReleaseCollectorVMPostForwarding(running concurrently withRelease)ScanMutatorRootsScanVMSpecificRootsProcessEdgesWorkRootsWorkFactory(implementsRootsWorkFactorydefined insrc/vm/scanning.rs)RootsKindProcessEdgesBase(This is all about processing slots instead of edges).ProcessEdgesWork(This part really needs to be refactored.ProcessEdgesWork::trace_objectshouldn't be specific to slot-enqueued tracing.)SFTProcessEdgesPlanProcessEdgesProcessEdgesWorkTracer(implementsObjectTracerdefined insrc/vm/scanning.rs)UnsupportedProcessEdgesScanObjectsWorkScanObjectsPlanScanObjectsProcessRootNode(for pinning and transitive-pinning roots)ProcessEdgesWorkTracerContext(implementsTracerContextdefined insrc/vm/scanning.rs)VMProcessWeakRefsVMForwardWeakRefsRefactoring 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".
trace_object, and store back forwarded reference.trace_object(obj) -> new_objmethod. This effectively visits an object graph edge that points toobj, regardless whetherobjis loaded from a givenSlotor 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 wrapProcessEdgesWorkbehind theObjectTracertrait which only provides thetrace_objectmethod (that is,ProcessEdgesWorkTracer).I had a branch that refactors the
trace_objectinto a dedicated type and leaves theProcessEdgesWorkdedicated to slot processing. The code is here: #1278, but it is very old.And #599 contains more information about my intended refactoring.