Skip to content
7 changes: 4 additions & 3 deletions docs/dummyvm/src/scanning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::DummyVM;
use crate::DummyVMSlot;
use mmtk::util::opaque_pointer::*;
use mmtk::util::ObjectReference;
use mmtk::vm::RefScanPolicy;
use mmtk::vm::RootsWorkFactory;
use mmtk::vm::Scanning;
use mmtk::vm::SlotVisitor;
Expand All @@ -21,10 +22,10 @@ impl Scanning<DummyVM> for VMScanning {
fn scan_vm_specific_roots(_tls: VMWorkerThread, _factory: impl RootsWorkFactory<DummyVMSlot>) {
unimplemented!()
}
fn scan_object<SV: SlotVisitor<DummyVMSlot>>(
_tls: VMWorkerThread,
fn scan_object<R: RefScanPolicy>(
_tls: VMThread,
_object: ObjectReference,
_slot_visitor: &mut SV,
_slot_visitor: &mut impl SlotVisitor<DummyVMSlot>,
) {
unimplemented!()
}
Expand Down
20 changes: 17 additions & 3 deletions src/plan/concurrent/barrier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::sync::atomic::Ordering;
use super::{concurrent_marking_work::ProcessModBufSATB, Pause};
use crate::plan::global::PlanTraceObject;
use crate::policy::gc_work::TraceKind;
use crate::util::ref_scan_policy;
use crate::util::VMMutatorThread;
use crate::{
plan::{barriers::BarrierSemantics, concurrent::global::ConcurrentPlan, VectorQueue},
Expand Down Expand Up @@ -156,8 +157,21 @@ impl<VM: VMBinding, P: ConcurrentPlan<VM = VM> + PlanTraceObject<VM>, const KIND
}

fn object_probable_write_slow(&mut self, obj: ObjectReference) {
crate::plan::tracing::SlotIterator::<VM>::iterate_fields(obj, self.tls.0, |s| {
self.enqueue_node(Some(obj), s, None);
});
// Note: The SATB barrier ensures all *strongly reachable* objects from roots at the
// beginning of a trace (i.e. the SATB) will eventually be marked. To do this, the SATB
// barrier enqueues the current children of *strong fields*, but it doesn't mark the current
// object or its children. Instead, the marking and scanning will happen in the
// `ConcurrentTraceObjects` work packet which is executed either during the concurrent
// tracing, or during `FinalMark`. For this reason, the barrier itself is not the right
// time to do "reference discovery" because we only discover references of objects
// determined to be live. Therefore, we use `StrongOnly` here and only visit children of
// strong fields.
crate::plan::tracing::SlotIterator::<VM>::iterate_fields::<ref_scan_policy::StrongOnly>(
obj,
self.tls.0,
|s| {
self.enqueue_node(Some(obj), s, None);
},
);
}
}
3 changes: 2 additions & 1 deletion src/plan/concurrent/concurrent_marking_work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::plan::PlanTraceObject;
use crate::plan::VectorQueue;
use crate::policy::gc_work::TraceKind;
use crate::scheduler::gc_work::{ScanObjects, SlotOf};
use crate::util::ref_scan_policy;
use crate::util::ObjectReference;
use crate::vm::slot::Slot;
use crate::{
Expand Down Expand Up @@ -74,7 +75,7 @@ impl<VM: VMBinding, P: ConcurrentPlan<VM = VM> + PlanTraceObject<VM>, const KIND
}

fn scan_and_enqueue(&mut self, object: ObjectReference) {
crate::plan::tracing::SlotIterator::<VM>::iterate_fields(
crate::plan::tracing::SlotIterator::<VM>::iterate_fields::<ref_scan_policy::Closure>(
object,
self.worker().tls.0,
|s| {
Expand Down
17 changes: 9 additions & 8 deletions src/plan/tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use std::marker::PhantomData;

use crate::scheduler::gc_work::{ProcessEdgesWork, SlotOf};
use crate::scheduler::{GCWorker, WorkBucketStage, EDGES_WORK_BUFFER_SIZE};
use crate::util::{ObjectReference, VMThread, VMWorkerThread};
use crate::vm::{Scanning, SlotVisitor, VMBinding};
use crate::util::{ObjectReference, VMThread};
use crate::vm::{RefScanPolicy, Scanning, SlotVisitor, VMBinding};

/// This trait represents an object queue to enqueue objects during tracing.
pub trait ObjectQueue {
Expand Down Expand Up @@ -157,13 +157,14 @@ pub(crate) struct SlotIterator<VM: VMBinding> {

impl<VM: VMBinding> SlotIterator<VM> {
/// Iterate over the slots of an object by applying a function to each slot.
pub fn iterate_fields<F: FnMut(VM::VMSlot)>(object: ObjectReference, _tls: VMThread, mut f: F) {
// FIXME: We should use tls from the arguments.
// See https://github.com/mmtk/mmtk-core/issues/1375
let fake_tls = VMWorkerThread(VMThread::UNINITIALIZED);
if !<VM::VMScanning as Scanning<VM>>::support_slot_enqueuing(fake_tls, object) {
pub fn iterate_fields<R: RefScanPolicy>(
object: ObjectReference,
tls: VMThread,
mut f: impl FnMut(VM::VMSlot),
) {
if !<VM::VMScanning as Scanning<VM>>::support_slot_enqueuing(tls, object) {
panic!("SlotIterator::iterate_fields cannot be used on objects that don't support slot-enqueuing");
}
<VM::VMScanning as Scanning<VM>>::scan_object(fake_tls, object, &mut f);
<VM::VMScanning as Scanning<VM>>::scan_object::<R>(tls, object, &mut f);
}
}
25 changes: 16 additions & 9 deletions src/policy/compressor/compressorspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::util::metadata::extract_side_metadata;
use crate::util::metadata::vo_bit;
use crate::util::metadata::MetadataSpec;
use crate::util::object_enum::{self, ObjectEnumerator};
use crate::util::ref_scan_policy;
use crate::util::{Address, ObjectReference};
use crate::vm::slot::Slot;
use crate::MMTK;
Expand Down Expand Up @@ -340,16 +341,22 @@ impl<VM: VMBinding> CompressorSpace<VM> {
}

fn update_references(&self, worker: &mut GCWorker<VM>, object: ObjectReference) {
if VM::VMScanning::support_slot_enqueuing(worker.tls, object) {
VM::VMScanning::scan_object(worker.tls, object, &mut |s: VM::VMSlot| {
if let Some(o) = s.load() {
s.store(self.forward(o, false));
}
});
if VM::VMScanning::support_slot_enqueuing(worker.tls.into(), object) {
VM::VMScanning::scan_object::<ref_scan_policy::RefUpdate>(
worker.tls.into(),
object,
&mut |s: VM::VMSlot| {
if let Some(o) = s.load() {
s.store(self.forward(o, false));
}
},
);
} else {
VM::VMScanning::scan_object_and_trace_edges(worker.tls, object, &mut |o| {
self.forward(o, false)
});
VM::VMScanning::scan_object_and_trace_edges::<ref_scan_policy::RefUpdate>(
worker.tls.into(),
object,
&mut |o| self.forward(o, false),
);
}
}

Expand Down
17 changes: 10 additions & 7 deletions src/scheduler/gc_work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use super::*;
use crate::global_state::GcStatus;
use crate::plan::ObjectsClosure;
use crate::plan::VectorObjectQueue;
use crate::util::ref_scan_policy;
use crate::util::*;
use crate::vm::slot::Slot;
use crate::vm::*;
Expand Down Expand Up @@ -864,10 +865,14 @@ pub trait ScanObjectsWork<VM: VMBinding>: GCWork<VM> + Sized {
}

for object in objects_to_scan.iter().copied() {
if <VM as VMBinding>::VMScanning::support_slot_enqueuing(tls, object) {
if <VM as VMBinding>::VMScanning::support_slot_enqueuing(tls.into(), object) {
trace!("Scan object (slot) {}", object);
// If an object supports slot-enqueuing, we enqueue its slots.
<VM as VMBinding>::VMScanning::scan_object(tls, object, &mut closure);
<VM as VMBinding>::VMScanning::scan_object::<ref_scan_policy::Closure>(
tls.into(),
object,
&mut closure,
);
self.post_scan_object(object);
} else {
// If an object does not support slot-enqueuing, we have to use
Expand Down Expand Up @@ -896,11 +901,9 @@ pub trait ScanObjectsWork<VM: VMBinding>: GCWork<VM> + Sized {
// Scan objects and trace their outgoing edges at the same time.
for object in scan_later.iter().copied() {
trace!("Scan object (node) {}", object);
<VM as VMBinding>::VMScanning::scan_object_and_trace_edges(
tls,
object,
object_tracer,
);
<VM as VMBinding>::VMScanning::scan_object_and_trace_edges::<
ref_scan_policy::Closure,
>(tls.into(), object, object_tracer);
self.post_scan_object(object);
}
});
Expand Down
2 changes: 2 additions & 0 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ pub(crate) mod logger;
pub(crate) mod object_enum;
/// Forwarding word in object copying.
pub(crate) mod object_forwarding;
/// RefScanPolicy implementations.
pub(crate) mod ref_scan_policy;
/// Reference processing implementation.
pub(crate) mod reference_processor;
/// Utilities funcitons for Rust
Expand Down
14 changes: 14 additions & 0 deletions src/util/opaque_pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,23 @@ impl VMThread {
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct VMMutatorThread(pub VMThread);

/// Allow unchecked explicit conversion from [VMMutatorThread] to [VMThread]
impl From<VMMutatorThread> for VMThread {
fn from(value: VMMutatorThread) -> Self {
value.0
}
}

/// A VMWorkerThread is a VMThread that is associates with a [`crate::scheduler::GCWorker`].
/// When a VMWorkerThread is used as an argument or a field of a type, it generally means
/// the function or the functions for the type is executed in the context of the mutator thread.
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct VMWorkerThread(pub VMThread);

/// Allow unchecked explicit conversion from [VMWorkerThread] to [VMThread]
impl From<VMWorkerThread> for VMThread {
fn from(value: VMWorkerThread) -> Self {
value.0
}
}
67 changes: 67 additions & 0 deletions src/util/ref_scan_policy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! This module holds common reference scanning policies used in MMTk core.

use crate::vm::RefScanPolicy;

#[allow(unused)] // For doc comments.
use crate::vm::{ObjectTracer, SlotVisitor};

/// An object is scanned during the strong transitive closure stage. The VM binding should visit
/// fields that contain strong references using the [`SlotVisitor`] or [`ObjectTracer`] callbacks.
///
/// The VM binding should not visit weak reference fields using the [`SlotVisitor`] or
/// [`ObjectTracer`] callbacks. If a VM binding chooses to discover weak references during tracing,
/// it should record relevant information (e.g. the current object, its fields, etc.) in VM-specific
/// data structures, as described in the [Porting Guide][pg-weakref]. If the VM binding chooses not
/// to discover weak reference fields this way, it can ignore weak fields.
///
/// [pg-weakref]:
/// https://docs.mmtk.io/portingguide/concerns/weakref.html#identifying-weak-references
pub struct Closure;

impl RefScanPolicy for Closure {
const VISIT_STRONG: bool = true;
const VISIT_WEAK: bool = false;
const DISCOVER_WEAK: bool = true;
}

/// An object is scanned to update its references after objects are moved or after the new
/// addresses of objects have been calculated. The VM binding should visit all reference fields
/// of an object, regardless whether they are holding strong or weak reference.
pub struct RefUpdate;

impl RefScanPolicy for RefUpdate {
const VISIT_STRONG: bool = true;
const VISIT_WEAK: bool = false;
const DISCOVER_WEAK: bool = false;
}

/// Instruct the VM binding to visit all fields of an object, both strong and weak, without any
/// hints about the MMTk's intention to call the object-scanning function.
pub struct All;

impl RefScanPolicy for All {
const VISIT_STRONG: bool = true;
const VISIT_WEAK: bool = true;
const DISCOVER_WEAK: bool = false;
}

/// Instruct the VM binding to visit all strong fields, without any hints about the MMTk's
/// intention to call the object-scanning function. Particularly, the VM binding should not
/// discover weak references which the [`Closure`] policy implies.
pub struct StrongOnly;

impl RefScanPolicy for StrongOnly {
const VISIT_STRONG: bool = true;
const VISIT_WEAK: bool = false;
const DISCOVER_WEAK: bool = false;
}

/// Instruct the VM binding to visit all weak fields, without any hints about the MMTk's
/// intention to call the object-scanning function.
pub struct WeakOnly;

impl RefScanPolicy for WeakOnly {
const VISIT_STRONG: bool = false;
const VISIT_WEAK: bool = true;
const DISCOVER_WEAK: bool = false;
}
29 changes: 12 additions & 17 deletions src/util/test_util/mock_vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::vm::object_model::specs::*;
use crate::vm::GCThreadContext;
use crate::vm::ObjectTracer;
use crate::vm::ObjectTracerContext;
use crate::vm::RefScanPolicy;
use crate::vm::RootsWorkFactory;
use crate::vm::SlotVisitor;
use crate::vm::VMBinding;
Expand Down Expand Up @@ -243,23 +244,17 @@ pub struct MockVM {
pub weakref_get_referent: MockMethod<ObjectReference, Option<ObjectReference>>,
pub weakref_enqueue_references: MockMethod<(&'static [ObjectReference], VMWorkerThread), ()>,
// scanning
pub support_slot_enqueuing: MockMethod<(VMWorkerThread, ObjectReference), bool>,
pub support_slot_enqueuing: MockMethod<(VMThread, ObjectReference), bool>,
pub scan_object: MockMethod<
(
VMWorkerThread,
VMThread,
ObjectReference,
&'static mut dyn SlotVisitor<<MockVM as VMBinding>::VMSlot>,
),
(),
>,
pub scan_object_and_trace_edges: MockMethod<
(
VMWorkerThread,
ObjectReference,
&'static mut dyn ObjectTracer,
),
(),
>,
pub scan_object_and_trace_edges:
MockMethod<(VMThread, ObjectReference, &'static mut dyn ObjectTracer), ()>,
pub scan_roots_in_mutator_thread: Box<dyn MockAny>,
pub scan_vm_specific_roots: Box<dyn MockAny>,
pub notify_initial_thread_scan_complete: MockMethod<(bool, VMWorkerThread), ()>,
Expand Down Expand Up @@ -552,24 +547,24 @@ impl crate::vm::ReferenceGlue<MockVM> for MockVM {
}

impl crate::vm::Scanning<MockVM> for MockVM {
fn support_slot_enqueuing(tls: VMWorkerThread, object: ObjectReference) -> bool {
fn support_slot_enqueuing(tls: VMThread, object: ObjectReference) -> bool {
mock!(support_slot_enqueuing(tls, object))
}
fn scan_object<SV: SlotVisitor<<MockVM as VMBinding>::VMSlot>>(
tls: VMWorkerThread,
fn scan_object<R: RefScanPolicy>(
tls: VMThread,
object: ObjectReference,
slot_visitor: &mut SV,
slot_visitor: &mut impl SlotVisitor<<MockVM as VMBinding>::VMSlot>,
) {
mock!(scan_object(
tls,
object,
lifetime!(slot_visitor as &mut dyn SlotVisitor<<MockVM as VMBinding>::VMSlot>)
))
}
fn scan_object_and_trace_edges<OT: ObjectTracer>(
tls: VMWorkerThread,
fn scan_object_and_trace_edges<R: RefScanPolicy>(
tls: VMThread,
object: ObjectReference,
object_tracer: &mut OT,
object_tracer: &mut impl ObjectTracer,
) {
mock!(scan_object_and_trace_edges(
tls,
Expand Down
1 change: 1 addition & 0 deletions src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub use self::reference_glue::Finalizable;
pub use self::reference_glue::ReferenceGlue;
pub use self::scanning::ObjectTracer;
pub use self::scanning::ObjectTracerContext;
pub use self::scanning::RefScanPolicy;
pub use self::scanning::RootsWorkFactory;
pub use self::scanning::Scanning;
pub use self::scanning::SlotVisitor;
Expand Down
Loading
Loading