mmtk/policy/
immortalspace.rs

1use atomic::Ordering;
2
3use crate::policy::sft::SFT;
4use crate::policy::space::{CommonSpace, Space};
5use crate::util::address::Address;
6use crate::util::heap::{MonotonePageResource, PageResource};
7use crate::util::metadata::mark_bit::MarkState;
8
9use crate::util::object_enum::{self, ObjectEnumerator};
10use crate::util::{metadata, ObjectReference};
11
12use crate::plan::tracing::{ObjectQueue, OptionObjectQueue};
13
14use crate::policy::sft::GCWorkerMutRef;
15use crate::vm::{ObjectModel, VMBinding};
16
17/// This type implements a simple immortal collection
18/// policy. Under this policy all that is required is for the
19/// "collector" to propagate marks in a liveness trace.  It does not
20/// actually collect.
21pub struct ImmortalSpace<VM: VMBinding> {
22    mark_state: MarkState,
23    common: CommonSpace<VM>,
24    pr: MonotonePageResource<VM>,
25}
26
27impl<VM: VMBinding> SFT for ImmortalSpace<VM> {
28    fn name(&self) -> &'static str {
29        self.get_name()
30    }
31    fn is_live(&self, _object: ObjectReference) -> bool {
32        true
33    }
34    fn is_reachable(&self, object: ObjectReference) -> bool {
35        self.mark_state.is_marked::<VM>(object)
36    }
37    #[cfg(feature = "object_pinning")]
38    fn pin_object(&self, _object: ObjectReference) -> bool {
39        false
40    }
41    #[cfg(feature = "object_pinning")]
42    fn unpin_object(&self, _object: ObjectReference) -> bool {
43        false
44    }
45    #[cfg(feature = "object_pinning")]
46    fn is_object_pinned(&self, _object: ObjectReference) -> bool {
47        true
48    }
49    fn is_movable(&self) -> bool {
50        false
51    }
52    #[cfg(feature = "sanity")]
53    fn is_sane(&self) -> bool {
54        true
55    }
56    fn initialize_object_metadata(&self, object: ObjectReference, bytes: usize) {
57        self.mark_state
58            .on_object_metadata_initialization::<VM>(object);
59        if self.common.unlog_allocated_object {
60            VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::<VM>(object, Ordering::SeqCst);
61            if self.common.needs_field_log_bit {
62                VM::VMObjectModel::GLOBAL_FIELD_UNLOG_BIT_SPEC
63                    .as_spec()
64                    .extract_side_spec()
65                    .bset_metadata(object.to_object_start::<VM>(), bytes);
66            }
67        }
68        #[cfg(feature = "vo_bit")]
69        crate::util::metadata::vo_bit::set_vo_bit(object);
70    }
71    #[cfg(feature = "vo_bit")]
72    fn is_mmtk_object(&self, addr: Address) -> Option<ObjectReference> {
73        crate::util::metadata::vo_bit::is_vo_bit_set_for_addr(addr)
74    }
75    #[cfg(feature = "vo_bit")]
76    fn find_object_from_internal_pointer(
77        &self,
78        ptr: Address,
79        max_search_bytes: usize,
80    ) -> Option<ObjectReference> {
81        crate::util::metadata::vo_bit::find_object_from_internal_pointer::<VM>(
82            ptr,
83            max_search_bytes,
84        )
85    }
86    fn sft_trace_object(
87        &self,
88        queue: &mut OptionObjectQueue,
89        object: ObjectReference,
90        _worker: GCWorkerMutRef,
91    ) -> ObjectReference {
92        self.trace_object(queue, object)
93    }
94    fn debug_print_object_info(&self, object: ObjectReference) {
95        println!("marked = {}", self.mark_state.is_marked::<VM>(object));
96        self.common.debug_print_object_global_info(object);
97    }
98}
99
100impl<VM: VMBinding> Space<VM> for ImmortalSpace<VM> {
101    fn as_space(&self) -> &dyn Space<VM> {
102        self
103    }
104    fn as_sft(&self) -> &(dyn SFT + Sync + 'static) {
105        self
106    }
107    fn get_page_resource(&self) -> &dyn PageResource<VM> {
108        &self.pr
109    }
110    fn maybe_get_page_resource_mut(&mut self) -> Option<&mut dyn PageResource<VM>> {
111        Some(&mut self.pr)
112    }
113    fn common(&self) -> &CommonSpace<VM> {
114        &self.common
115    }
116
117    fn initialize_sft(&self, sft_map: &mut dyn crate::policy::sft_map::SFTMap) {
118        self.common().initialize_sft(self.as_sft(), sft_map)
119    }
120
121    fn release_multiple_pages(&mut self, _start: Address) {
122        panic!("immortalspace only releases pages enmasse")
123    }
124
125    fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator) {
126        object_enum::enumerate_blocks_from_monotonic_page_resource(enumerator, &self.pr);
127    }
128
129    fn clear_side_log_bits(&self) {
130        let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec();
131        for (start, size) in self.pr.iterate_allocated_regions() {
132            log_bit.bzero_metadata(start, size);
133        }
134    }
135
136    fn set_side_log_bits(&self) {
137        let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec();
138        for (start, size) in self.pr.iterate_allocated_regions() {
139            log_bit.bset_metadata(start, size);
140        }
141    }
142}
143
144use crate::scheduler::GCWorker;
145use crate::util::copy::CopySemantics;
146
147impl<VM: VMBinding> crate::policy::gc_work::PolicyTraceObject<VM> for ImmortalSpace<VM> {
148    fn trace_object<Q: ObjectQueue, const KIND: crate::policy::gc_work::TraceKind>(
149        &self,
150        queue: &mut Q,
151        object: ObjectReference,
152        _copy: Option<CopySemantics>,
153        _worker: &mut GCWorker<VM>,
154    ) -> ObjectReference {
155        self.trace_object(queue, object)
156    }
157    fn may_move_objects<const KIND: crate::policy::gc_work::TraceKind>() -> bool {
158        false
159    }
160}
161
162impl<VM: VMBinding> ImmortalSpace<VM> {
163    pub fn new(args: crate::policy::space::PlanCreateSpaceArgs<VM>) -> Self {
164        let vm_map = args.vm_map;
165        let is_discontiguous = args.vmrequest.is_discontiguous();
166        let common = CommonSpace::new(args.into_policy_args(
167            false,
168            true,
169            metadata::extract_side_metadata(&[*VM::VMObjectModel::LOCAL_MARK_BIT_SPEC]),
170        ));
171        ImmortalSpace {
172            mark_state: MarkState::new(),
173            pr: if is_discontiguous {
174                MonotonePageResource::new_discontiguous(vm_map)
175            } else {
176                MonotonePageResource::new_contiguous(common.start, common.extent, vm_map)
177            },
178            common,
179        }
180    }
181
182    pub fn prepare(&mut self) {
183        self.mark_state.on_global_prepare::<VM>();
184        // Reset the mark bit for the allocated regions.
185        for (addr, size) in self.pr.iterate_allocated_regions() {
186            debug!(
187                "{:?}: reset mark bit from {} to {}",
188                self.name(),
189                addr,
190                addr + size
191            );
192            self.mark_state.on_block_reset::<VM>(addr, size);
193        }
194    }
195
196    pub fn release(&mut self) {
197        self.mark_state.on_global_release::<VM>();
198    }
199
200    pub fn trace_object<Q: ObjectQueue>(
201        &self,
202        queue: &mut Q,
203        object: ObjectReference,
204    ) -> ObjectReference {
205        #[cfg(feature = "vo_bit")]
206        debug_assert!(
207            crate::util::metadata::vo_bit::is_vo_bit_set(object),
208            "{:x}: VO bit not set",
209            object
210        );
211        if self.mark_state.test_and_mark::<VM>(object) {
212            // Set the unlog bit if required
213            if self.common.unlog_traced_object {
214                VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.store_atomic::<VM, u8>(
215                    object,
216                    1,
217                    None,
218                    Ordering::SeqCst,
219                );
220            }
221            queue.enqueue(object);
222        }
223        object
224    }
225}