Trait mmtk::vm::Scanning

source ·
pub trait Scanning<VM: VMBinding> {
    // Required methods
    fn scan_object<SV: SlotVisitor<VM::VMSlot>>(
        tls: VMWorkerThread,
        object: ObjectReference,
        slot_visitor: &mut SV
    );
    fn notify_initial_thread_scan_complete(
        partial_scan: bool,
        tls: VMWorkerThread
    );
    fn scan_roots_in_mutator_thread(
        tls: VMWorkerThread,
        mutator: &'static mut Mutator<VM>,
        factory: impl RootsWorkFactory<VM::VMSlot>
    );
    fn scan_vm_specific_roots(
        tls: VMWorkerThread,
        factory: impl RootsWorkFactory<VM::VMSlot>
    );
    fn supports_return_barrier() -> bool;
    fn prepare_for_roots_re_scanning();

    // Provided methods
    fn support_slot_enqueuing(
        _tls: VMWorkerThread,
        _object: ObjectReference
    ) -> bool { ... }
    fn scan_object_and_trace_edges<OT: ObjectTracer>(
        _tls: VMWorkerThread,
        _object: ObjectReference,
        _object_tracer: &mut OT
    ) { ... }
    fn process_weak_refs(
        _worker: &mut GCWorker<VM>,
        _tracer_context: impl ObjectTracerContext<VM>
    ) -> bool { ... }
    fn forward_weak_refs(
        _worker: &mut GCWorker<VM>,
        _tracer_context: impl ObjectTracerContext<VM>
    ) { ... }
}
Expand description

VM-specific methods for scanning roots/objects.

Required Methods§

source

fn scan_object<SV: SlotVisitor<VM::VMSlot>>( tls: VMWorkerThread, object: ObjectReference, slot_visitor: &mut SV )

Delegated scanning of a object, visiting each reference field encountered.

The VM shall call slot_visitor.visit_slot on each reference field. This effectively visits all outgoing edges from the current object in the form of slots.

The VM may skip a reference field if it is not holding an object reference (e.g. if the field is holding a null reference, or a tagged non-reference value such as small integer). Even if not skipped, Slot::load will still return None if the slot is not holding an object reference.

The memory_manager::is_mmtk_object function can be used in this function if

  • the “is_mmtk_object” feature is enabled, and
  • VM::VMObjectModel::NEED_VO_BITS_DURING_TRACING is true.

Arguments:

  • tls: The VM-specific thread-local storage for the current worker.
  • object: The object to be scanned.
  • slot_visitor: Called back for each field.
source

fn notify_initial_thread_scan_complete(partial_scan: bool, tls: VMWorkerThread)

MMTk calls this method at the first time during a collection that thread’s stacks have been scanned. This can be used (for example) to clean up obsolete compiled methods that are no longer being executed.

Arguments:

  • partial_scan: Whether the scan was partial or full-heap.
  • tls: The GC thread that is performing the thread scan.
source

fn scan_roots_in_mutator_thread( tls: VMWorkerThread, mutator: &'static mut Mutator<VM>, factory: impl RootsWorkFactory<VM::VMSlot> )

Scan one mutator for stack roots.

Some VM bindings may not be able to implement this method. For example, the VM binding may only be able to enumerate all threads and scan them while enumerating, but cannot scan stacks individually when given the references of threads. In that case, it can leave this method empty, and deal with stack roots in Scanning::scan_vm_specific_roots. However, in that case, MMTk does not know those roots are stack roots, and cannot perform any possible optimization for the stack roots.

The memory_manager::is_mmtk_object function can be used in this function if

  • the “is_mmtk_object” feature is enabled.

Arguments:

  • tls: The GC thread that is performing this scanning.
  • mutator: The reference to the mutator whose roots will be scanned.
  • factory: The VM uses it to create work packets for scanning roots.
source

fn scan_vm_specific_roots( tls: VMWorkerThread, factory: impl RootsWorkFactory<VM::VMSlot> )

Scan VM-specific roots. The creation of all root scan tasks (except thread scanning) goes here.

The memory_manager::is_mmtk_object function can be used in this function if

  • the “is_mmtk_object” feature is enabled.

Arguments:

  • tls: The GC thread that is performing this scanning.
  • factory: The VM uses it to create work packets for scanning roots.
source

fn supports_return_barrier() -> bool

Return whether the VM supports return barriers. This is unused at the moment.

source

fn prepare_for_roots_re_scanning()

Prepare for another round of root scanning in the same GC. Some GC algorithms need multiple transitive closures, and each transitive closure starts from root scanning. We expect the binding to provide the same root set for every round of root scanning in the same GC. Bindings can use this call to get ready for another round of root scanning to make sure that the same root set will be returned in the upcoming calls of root scanning methods, such as crate::vm::Scanning::scan_roots_in_mutator_thread and crate::vm::Scanning::scan_vm_specific_roots.

Provided Methods§

source

fn support_slot_enqueuing( _tls: VMWorkerThread, _object: ObjectReference ) -> bool

Return true if the given object supports slot enqueuing.

  • If this returns true, MMTk core will call scan_object on the object.
  • Otherwise, MMTk core will call scan_object_and_trace_edges on the object.

For maximum performance, the VM should support slot-enqueuing for as many objects as practical. Also note that this method is called for every object to be scanned, so it must be fast. The VM binding should avoid expensive checks and keep it as efficient as possible.

Arguments:

  • tls: The VM-specific thread-local storage for the current worker.
  • object: The object to be scanned.
source

fn scan_object_and_trace_edges<OT: ObjectTracer>( _tls: VMWorkerThread, _object: ObjectReference, _object_tracer: &mut OT )

Delegated scanning of a object, visiting each reference field encountered, and tracing the objects pointed by each field.

The VM shall call object_tracer.trace_object with the argument being the object reference held in each reference field. If the GC moves the object, the VM shall update the field so that it refers to the object using the object reference returned from trace_object. This effectively traces through all outgoing edges from the current object directly.

The VM must skip reference fields that are not holding object references (e.g. if the field is holding a null reference, or a tagged non-reference value such as small integer).

The memory_manager::is_mmtk_object function can be used in this function if

  • the “is_mmtk_object” feature is enabled, and
  • VM::VMObjectModel::NEED_VO_BITS_DURING_TRACING is true.

Arguments:

  • tls: The VM-specific thread-local storage for the current worker.
  • object: The object to be scanned.
  • object_tracer: Called back for the object reference held in each field.
source

fn process_weak_refs( _worker: &mut GCWorker<VM>, _tracer_context: impl ObjectTracerContext<VM> ) -> bool

Process weak references.

This function is called after a transitive closure is completed.

MMTk core enables the VM binding to do the following in this function:

  1. Query if an object is already reached in this transitive closure.
  2. Get the new address of an object if it is already reached.
  3. Keep an object and its descendents alive if not yet reached.
  4. Request this function to be called again after transitive closure is finished again.

The VM binding can query if an object is currently reached by calling ObjectReference::is_reachable().

If an object is already reached, the VM binding can get its new address by calling ObjectReference::get_forwarded_object() as the object may have been moved.

If an object is not yet reached, the VM binding can keep that object and its descendents alive. To do this, the VM binding should use tracer_context.with_tracer to get access to an ObjectTracer, and then call its trace_object(object) method. The trace_object method will return the new address of the object if it moved the object, or its original address if not moved. Implementation-wise, the ObjectTracer may contain an internal queue for newly traced objects, and will flush the queue when tracer_context.with_tracer returns. Therefore, it is recommended to reuse the ObjectTracer instance to trace multiple objects.

Note that if trace_object is called on an already reached object, the behavior will be equivalent to ObjectReference::get_forwarded_object(). It will return the new address if the GC already moved the object when tracing that object, or the original address if the GC did not move the object when tracing it. In theory, the VM binding can use trace_object wherever ObjectReference::get_forwarded_object() is needed. However, if a VM never resurrects objects, it should completely avoid touching tracer_context, and exclusively use ObjectReference::get_forwarded_object() to get new addresses of objects. By doing so, the VM binding can avoid accidentally resurrecting objects.

The VM binding can return true from process_weak_refs to request process_weak_refs to be called again after the MMTk core finishes transitive closure again from the objects newly visited by ObjectTracer::trace_object. This is useful if a VM supports multiple levels of reachabilities (such as Java) or ephemerons.

Implementation-wise, this function is called as the “sentinel” of the VMRefClosure work bucket, which means it is called when all work packets in that bucket have finished. The tracer_context expands the transitive closure by adding more work packets in the same bucket. This means if process_weak_refs returns true, those work packets will have finished (completing the transitive closure) by the time process_weak_refs is called again. The VM binding can make use of this by adding custom work packets into the VMRefClosure bucket. The bucket will be VMRefForwarding, instead, when forwarding. See below.

The memory_manager::is_mmtk_object function can be used in this function if

  • the “is_mmtk_object” feature is enabled, and
  • VM::VMObjectModel::NEED_VO_BITS_DURING_TRACING is true.

Arguments:

  • worker: The current GC worker.
  • tracer_context: Use this to get access an ObjectTracer and use it to retain and update weak references.

This function shall return true if this function needs to be called again after the GC finishes expanding the transitive closure from the objects kept alive.

source

fn forward_weak_refs( _worker: &mut GCWorker<VM>, _tracer_context: impl ObjectTracerContext<VM> )

Forward weak references.

This function will only be called in the forwarding stage when using the mark-compact GC algorithm. Mark-compact computes transive closure twice during each GC. It marks objects in the first transitive closure, and forward references in the second transitive closure.

Arguments:

  • worker: The current GC worker.
  • tracer_context: Use this to get access an ObjectTracer and use it to update weak references.

Object Safety§

This trait is not object safe.

Implementors§