mmtk/plan/
global.rs

1//! The global part of a plan implementation.
2
3use super::PlanConstraints;
4use crate::global_state::GlobalState;
5use crate::mmtk::MMTK;
6use crate::plan::gc_work::{ClearCommonPlanUnlogBits, SetCommonPlanUnlogBits};
7use crate::plan::tracing::ObjectQueue;
8use crate::plan::Mutator;
9use crate::policy::immortalspace::ImmortalSpace;
10use crate::policy::largeobjectspace::LargeObjectSpace;
11use crate::policy::space::{PlanCreateSpaceArgs, Space};
12#[cfg(feature = "vm_space")]
13use crate::policy::vmspace::VMSpace;
14use crate::scheduler::*;
15use crate::util::alloc::allocators::AllocatorSelector;
16use crate::util::copy::{CopyConfig, GCWorkerCopyContext};
17use crate::util::heap::gc_trigger::GCTrigger;
18use crate::util::heap::gc_trigger::SpaceStats;
19use crate::util::heap::layout::Mmapper;
20use crate::util::heap::layout::VMMap;
21use crate::util::heap::HeapMeta;
22use crate::util::heap::VMRequest;
23use crate::util::metadata::log_bit::UnlogBitsOperation;
24use crate::util::metadata::side_metadata::SideMetadataSanity;
25use crate::util::metadata::side_metadata::SideMetadataSpec;
26use crate::util::options::Options;
27use crate::util::options::PlanSelector;
28use crate::util::statistics::stats::Stats;
29use crate::util::{conversions, ObjectReference};
30use crate::util::{VMMutatorThread, VMWorkerThread};
31use crate::vm::*;
32use downcast_rs::Downcast;
33use enum_map::EnumMap;
34use std::sync::atomic::Ordering;
35use std::sync::Arc;
36
37use mmtk_macros::{HasSpaces, PlanTraceObject};
38
39pub fn create_mutator<VM: VMBinding>(
40    tls: VMMutatorThread,
41    mmtk: &'static MMTK<VM>,
42) -> Box<Mutator<VM>> {
43    Box::new(match *mmtk.options.plan {
44        PlanSelector::NoGC => crate::plan::nogc::mutator::create_nogc_mutator(tls, mmtk),
45        PlanSelector::SemiSpace => crate::plan::semispace::mutator::create_ss_mutator(tls, mmtk),
46        PlanSelector::GenCopy => {
47            crate::plan::generational::copying::mutator::create_gencopy_mutator(tls, mmtk)
48        }
49        PlanSelector::GenImmix => {
50            crate::plan::generational::immix::mutator::create_genimmix_mutator(tls, mmtk)
51        }
52        PlanSelector::MarkSweep => crate::plan::marksweep::mutator::create_ms_mutator(tls, mmtk),
53        PlanSelector::Immix => crate::plan::immix::mutator::create_immix_mutator(tls, mmtk),
54        PlanSelector::PageProtect => {
55            crate::plan::pageprotect::mutator::create_pp_mutator(tls, mmtk)
56        }
57        PlanSelector::Lisp2 => {
58            crate::plan::markcompact::lisp2::mutator::create_lisp2_mutator(tls, mmtk)
59        }
60        PlanSelector::StickyImmix => {
61            crate::plan::sticky::immix::mutator::create_stickyimmix_mutator(tls, mmtk)
62        }
63        PlanSelector::ConcurrentImmix => {
64            crate::plan::concurrent::immix::mutator::create_concurrent_immix_mutator(tls, mmtk)
65        }
66        PlanSelector::OVC => crate::plan::markcompact::ovc::mutator::create_ovc_mutator(tls, mmtk),
67    })
68}
69
70/// Create a plan and the spaces for the plan.
71///
72/// It is very important that in the constructor of each plan (including the constructor of each space),
73/// sft and side metadata is not available for access. If a plan or a space needs to initialize sft or side metadata
74/// in its constructor, it needs to postpone the initialization to [`Plan::initialize_sft`], [`Plan::initialize_side_metadata`],
75/// [`Space::initialize_sft`] or [`Space::initialize_side_metadata`].
76/// If a plan or a space tries to access sft or side metadata in its constructor, it may cause undefined behavior.
77pub fn create_plan<VM: VMBinding>(
78    plan: PlanSelector,
79    args: CreateGeneralPlanArgs<VM>,
80) -> Box<dyn Plan<VM = VM>> {
81    match plan {
82        PlanSelector::NoGC => {
83            Box::new(crate::plan::nogc::NoGC::new(args)) as Box<dyn Plan<VM = VM>>
84        }
85        PlanSelector::SemiSpace => {
86            Box::new(crate::plan::semispace::SemiSpace::new(args)) as Box<dyn Plan<VM = VM>>
87        }
88        PlanSelector::GenCopy => Box::new(crate::plan::generational::copying::GenCopy::new(args))
89            as Box<dyn Plan<VM = VM>>,
90        PlanSelector::GenImmix => Box::new(crate::plan::generational::immix::GenImmix::new(args))
91            as Box<dyn Plan<VM = VM>>,
92        PlanSelector::MarkSweep => {
93            Box::new(crate::plan::marksweep::MarkSweep::new(args)) as Box<dyn Plan<VM = VM>>
94        }
95        PlanSelector::Immix => {
96            Box::new(crate::plan::immix::Immix::new(args)) as Box<dyn Plan<VM = VM>>
97        }
98        PlanSelector::PageProtect => {
99            Box::new(crate::plan::pageprotect::PageProtect::new(args)) as Box<dyn Plan<VM = VM>>
100        }
101        PlanSelector::Lisp2 => {
102            Box::new(crate::plan::markcompact::lisp2::Lisp2::new(args)) as Box<dyn Plan<VM = VM>>
103        }
104        PlanSelector::StickyImmix => {
105            Box::new(crate::plan::sticky::immix::StickyImmix::new(args)) as Box<dyn Plan<VM = VM>>
106        }
107        PlanSelector::ConcurrentImmix => {
108            Box::new(crate::plan::concurrent::immix::ConcurrentImmix::new(args))
109                as Box<dyn Plan<VM = VM>>
110        }
111        PlanSelector::OVC => {
112            Box::new(crate::plan::markcompact::ovc::OVC::new(args)) as Box<dyn Plan<VM = VM>>
113        }
114    }
115}
116
117/// Create thread local GC worker.
118pub fn create_gc_worker_context<VM: VMBinding>(
119    tls: VMWorkerThread,
120    mmtk: &'static MMTK<VM>,
121) -> GCWorkerCopyContext<VM> {
122    GCWorkerCopyContext::<VM>::new(tls, mmtk, mmtk.get_plan().create_copy_config())
123}
124
125/// A plan describes the global core functionality for all memory management schemes.
126/// All global MMTk plans should implement this trait.
127///
128/// The global instance defines and manages static resources
129/// (such as memory and virtual memory resources).
130///
131/// Constructor:
132///
133/// For the constructor of a new plan, there are a few things the constructor _must_ do
134/// (please check existing plans and see what they do in the constructor):
135/// 1. Create a HeapMeta, and use this HeapMeta to initialize all the spaces.
136/// 2. Create a vector of all the side metadata specs with `SideMetadataContext::new_global_specs()`,
137///    the parameter is a vector of global side metadata specs that are specific to the plan.
138/// 3. Initialize all the spaces the plan uses with the heap meta, and the global metadata specs vector.
139/// 4. Invoke the `verify_side_metadata_sanity()` method of the plan.
140///    It will create a `SideMetadataSanity` object, and invoke verify_side_metadata_sanity() for each space (or
141///    invoke verify_side_metadata_sanity() in `CommonPlan`/`BasePlan` for the spaces in the common/base plan).
142///
143/// Methods in this trait:
144///
145/// Only methods that will be overridden by each specific plan should be included in this trait. The trait may
146/// provide a default implementation, and each plan can override the implementation. For methods that won't be
147/// overridden, we should implement those methods in BasePlan (or CommonPlan) and call them from there instead.
148/// We should avoid having methods with the same name in both Plan and BasePlan, as this may confuse people, and
149/// they may call a wrong method by mistake.
150// TODO: Some methods that are not overriden can be moved from the trait to BasePlan.
151pub trait Plan: 'static + HasSpaces + Sync + Downcast {
152    /// Get the plan constraints for the plan.
153    /// This returns a non-constant value. A constant value can be found in each plan's module if needed.
154    fn constraints(&self) -> &'static PlanConstraints;
155
156    /// Create a copy config for this plan. A copying GC plan MUST override this method,
157    /// and provide a valid config.
158    fn create_copy_config(&'static self) -> CopyConfig<Self::VM> {
159        // Use the empty default copy config for non copying GC.
160        CopyConfig::default()
161    }
162
163    /// Get a immutable reference to the base plan. `BasePlan` is included by all the MMTk GC plans.
164    fn base(&self) -> &BasePlan<Self::VM>;
165
166    /// Get a mutable reference to the base plan. `BasePlan` is included by all the MMTk GC plans.
167    fn base_mut(&mut self) -> &mut BasePlan<Self::VM>;
168
169    /// Schedule work for the upcoming GC.
170    fn schedule_collection(&'static self, _scheduler: &GCWorkScheduler<Self::VM>);
171
172    /// Get the common plan. CommonPlan is included by most of MMTk GC plans.
173    fn common(&self) -> &CommonPlan<Self::VM> {
174        panic!("Common Plan not handled!")
175    }
176
177    /// Get a mutable reference to the common plan. See [`Self::common`].
178    fn common_mut(&mut self) -> &mut CommonPlan<Self::VM> {
179        panic!("Common Plan not handled!")
180    }
181
182    /// Return a reference to `GenerationalPlan` to allow
183    /// access methods specific to generational plans if the plan is a generational plan.
184    fn generational(
185        &self,
186    ) -> Option<&dyn crate::plan::generational::global::GenerationalPlan<VM = Self::VM>> {
187        None
188    }
189
190    /// Return a reference to `ConcurrentPlan` to allow
191    /// access methods specific to concurrent plans if the plan is a concurrent plan.
192    fn concurrent(
193        &self,
194    ) -> Option<&dyn crate::plan::concurrent::global::ConcurrentPlan<VM = Self::VM>> {
195        None
196    }
197
198    /// Get the current run time options.
199    fn options(&self) -> &Options {
200        &self.base().options
201    }
202
203    /// Get the allocator mapping between [`crate::AllocationSemantics`] and [`crate::util::alloc::AllocatorSelector`].
204    /// This defines what space this plan will allocate objects into for different semantics.
205    fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector>;
206
207    /// Called when all mutators are paused. This is called before prepare.
208    ///
209    /// A plan that overrides this function need to manage the invocation of `GCTriggerPolicy::on_gc_start` at the proper timing for the plan.
210    fn notify_mutators_paused(&self, mmtk: &'static MMTK<Self::VM>) {
211        assert!(
212            self.concurrent().is_none(),
213            "ConcurrentPlan must override notify_mutators_paused"
214        );
215        mmtk.gc_trigger.policy.on_gc_start(mmtk);
216    }
217
218    /// Prepare the plan before a GC. This is invoked in an initial step in the GC.
219    /// This is invoked once per GC by one worker thread. `tls` is the worker thread that executes this method.
220    fn prepare(&mut self, tls: VMWorkerThread);
221
222    /// Prepare a worker for a GC. Each worker has its own prepare method. This hook is for plan-specific
223    /// per-worker preparation. This method is invoked once per worker by the worker thread passed as the argument.
224    fn prepare_worker(&self, _worker: &mut GCWorker<Self::VM>) {}
225
226    /// Release the plan after transitive closure. A plan can implement this method to call each policy's release,
227    /// or create any work packet that should be done in release.
228    /// This is invoked once per GC by one worker thread. `tls` is the worker thread that executes this method.
229    fn release(&mut self, tls: VMWorkerThread);
230
231    /// Inform the plan about the end of a pause. It is guaranteed that there is no further work
232    /// for this pause. This is invoked once per pause by one worker thread. `tls` is the worker
233    /// thread that executes this method.
234    ///
235    /// A plan that overrides this function need to do whatever the default implementation does at the proper timing
236    /// for the plan, such as calling `CommonPlan::end_of_pause` and `GCTriggerPolicy::on_gc_end`.
237    fn end_of_pause(&mut self, mmtk: &'static MMTK<Self::VM>, tls: VMWorkerThread) {
238        self.common_mut().end_of_pause(tls);
239        assert!(
240            self.concurrent().is_none(),
241            "ConcurrentPlan must override end_of_pause"
242        );
243        mmtk.gc_trigger.policy.on_gc_end(mmtk);
244    }
245
246    /// Notify the plan that an emergency collection will happen. The plan should try to free as much memory as possible.
247    /// The default implementation will force a full heap collection for generational plans.
248    fn notify_emergency_collection(&self) {
249        if let Some(gen) = self.generational() {
250            gen.force_full_heap_collection();
251        }
252    }
253
254    /// Ask the plan if they would trigger a GC. If MMTk is in charge of triggering GCs, this method is called
255    /// periodically during allocation. However, MMTk may delegate the GC triggering decision to the runtime,
256    /// in which case, this method may not be called. This method returns true to trigger a collection.
257    ///
258    /// # Arguments
259    /// * `space_full`: the allocation to a specific space failed, must recover pages within 'space'.
260    /// * `space`: an option to indicate if there is a space that has failed in an allocation.
261    fn collection_required(&self, space_full: bool, space: Option<SpaceStats<Self::VM>>) -> bool;
262
263    // Note: The following methods are about page accounting. The default implementation should
264    // work fine for non-copying plans. For copying plans, the plan should override any of these methods
265    // if necessary.
266
267    /// Get the number of pages that are reserved, including pages used by MMTk spaces, pages that
268    /// will be used (e.g. for copying), and live pages allocated outside MMTk spaces as reported
269    /// by the VM binding.
270    fn get_reserved_pages(&self) -> usize {
271        let used_pages = self.get_used_pages();
272        let collection_reserve = self.get_collection_reserved_pages();
273        let vm_live_bytes = <Self::VM as VMBinding>::VMCollection::vm_live_bytes();
274        // Note that `vm_live_bytes` may not be the exact number of bytes in whole pages.  The VM
275        // binding is allowed to return an approximate value if it is expensive or impossible to
276        // compute the exact number of pages occupied.
277        let vm_live_pages = conversions::bytes_to_pages_up(vm_live_bytes);
278        let total = used_pages + collection_reserve + vm_live_pages;
279
280        trace!(
281            "Reserved pages = {}, used pages: {}, collection reserve: {}, VM live pages: {}",
282            total,
283            used_pages,
284            collection_reserve,
285            vm_live_pages,
286        );
287
288        total
289    }
290
291    /// Get the total number of pages for the heap.
292    fn get_total_pages(&self) -> usize {
293        self.base()
294            .gc_trigger
295            .policy
296            .get_current_heap_size_in_pages()
297    }
298
299    /// Get the number of pages that are still available for use. The available pages
300    /// should always be positive or 0.
301    fn get_available_pages(&self) -> usize {
302        let reserved_pages = self.get_reserved_pages();
303        let total_pages = self.get_total_pages();
304
305        // It is possible that the reserved pages is larger than the total pages so we are doing
306        // a saturating subtraction to make sure we return a non-negative number.
307        // For example,
308        // 1. our GC trigger checks if reserved pages is more than total pages.
309        // 2. when the heap is almost full of live objects (such as in the case of an OOM) and we are doing a copying GC, it is possible
310        //    the reserved pages is larger than total pages after the copying GC (the reserved pages after a GC
311        //    may be larger than the reserved pages before a GC, as we may end up using more memory for thread local
312        //    buffers for copy allocators).
313        // 3. the binding disabled GC, and we end up over-allocating beyond the total pages determined by the GC trigger.
314        let available_pages = total_pages.saturating_sub(reserved_pages);
315        trace!(
316            "Total pages = {}, reserved pages = {}, available pages = {}",
317            total_pages,
318            reserved_pages,
319            available_pages,
320        );
321        available_pages
322    }
323
324    /// Get the number of pages that are reserved for collection. By default, we return 0.
325    /// For copying plans, they need to override this and calculate required pages to complete
326    /// a copying GC.
327    fn get_collection_reserved_pages(&self) -> usize {
328        0
329    }
330
331    /// Get the number of pages that are used.
332    fn get_used_pages(&self) -> usize;
333
334    /// Get the number of pages that are NOT used. This is clearly different from available pages.
335    /// Free pages are unused, but some of them may have been reserved for some reason.
336    fn get_free_pages(&self) -> usize {
337        let total_pages = self.get_total_pages();
338        let used_pages = self.get_used_pages();
339
340        // It is possible that the used pages is larger than the total pages, so we use saturating
341        // subtraction.  See the comments in `get_available_pages`.
342        total_pages.saturating_sub(used_pages)
343    }
344
345    /// Return whether last GC was an exhaustive attempt to collect the heap.
346    /// For example, for generational GCs, minor collection is not an exhaustive collection.
347    /// For example, for Immix, fast collection (no defragmentation) is not an exhaustive collection.
348    fn last_collection_was_exhaustive(&self) -> bool {
349        true
350    }
351
352    /// Return whether the current GC may move any object.  The VM binding can make use of this
353    /// information and choose to or not to update some data structures that record the addresses
354    /// of objects.
355    ///
356    /// This function is callable during a GC.  From the VM binding's point of view, the information
357    /// of whether the current GC moves object or not is available since `Collection::stop_mutators`
358    /// is called, and remains available until (but not including) `resume_mutators` at which time
359    /// the current GC has just finished.
360    fn current_gc_may_move_object(&self) -> bool;
361
362    /// An object is firstly reached by a sanity GC. So the object is reachable
363    /// in the current GC, and all the GC work has been done for the object (such as
364    /// tracing and releasing). A plan can implement this to
365    /// use plan specific semantics to check if the object is sane.
366    /// Return true if the object is considered valid by the plan.
367    fn sanity_check_object(&self, _object: ObjectReference) -> bool {
368        true
369    }
370
371    /// Call `space.verify_side_metadata_sanity` for all spaces in this plan.
372    fn verify_side_metadata_sanity(&self) {
373        let mut side_metadata_sanity_checker = SideMetadataSanity::new();
374        self.for_each_space(&mut |space| {
375            space.verify_side_metadata_sanity(&mut side_metadata_sanity_checker);
376        })
377    }
378
379    /// Call `space.initialize_sft` for all spaces in this plan, and notify the SFT map about the creation of each space.
380    /// This method should only be called after 1. side metadata is initialized (as some SFT maps may use side metadata), 2. the plan is created in the heap and won't be moved,
381    /// and 3. the side metadata sanity is initialized (otherwise we may try access side metadata and trigger sanity check before side metadata sanity is initialized)
382    fn initialize_sft(&self) {
383        let sft_map: &mut dyn crate::policy::sft_map::SFTMap =
384            unsafe { crate::mmtk::SFT_MAP.get_mut() }.as_mut();
385        self.for_each_space(&mut |s| {
386            sft_map.notify_space_creation(s.as_sft());
387            s.initialize_sft(sft_map);
388        });
389    }
390
391    /// Call `space.initialize_side_metadata` for all spaces in this plan.
392    /// This is called after the plan is created in the heap and won't be moved, and after side metadata is initialized.
393    /// If a plan needs to access side metadata during space construction, it can override this method for its own initialization.
394    fn initialize_side_metadata(&self) {
395        self.for_each_space(&mut |s| s.initialize_side_metadata());
396    }
397}
398
399impl_downcast!(Plan assoc VM);
400
401/**
402BasePlan should contain all plan-related state and functions that are _fundamental_ to _all_ plans.  These include VM-specific (but not plan-specific) features such as a code space or vm space, which are fundamental to all plans for a given VM.  Features that are common to _many_ (but not intrinsically _all_) plans should instead be included in CommonPlan.
403*/
404#[derive(HasSpaces, PlanTraceObject)]
405pub struct BasePlan<VM: VMBinding> {
406    pub(crate) global_state: Arc<GlobalState>,
407    pub options: Arc<Options>,
408    pub gc_trigger: Arc<GCTrigger<VM>>,
409    pub scheduler: Arc<GCWorkScheduler<VM>>,
410
411    // Spaces in base plan
412    #[cfg(feature = "code_space")]
413    #[space]
414    pub code_space: ImmortalSpace<VM>,
415    #[cfg(feature = "code_space")]
416    #[space]
417    pub code_lo_space: ImmortalSpace<VM>,
418    #[cfg(feature = "ro_space")]
419    #[space]
420    pub ro_space: ImmortalSpace<VM>,
421
422    /// A VM space is a space allocated and populated by the VM.  Currently it is used by JikesRVM
423    /// for boot image.
424    ///
425    /// If VM space is present, it has some special interaction with the
426    /// `memory_manager::is_mmtk_object` and the `memory_manager::is_in_mmtk_spaces` functions.
427    ///
428    /// -   The functions `is_mmtk_object` and `find_object_from_internal_pointer` require
429    ///     the valid object (VO) bit side metadata to identify objects.
430    ///     If the binding maintains the VO bit for objects in VM spaces, those functions will work accordingly.
431    ///     Otherwise, calling them is undefined behavior.
432    ///
433    /// -   The `is_in_mmtk_spaces` currently returns `true` if the given object reference is in
434    ///     the VM space.
435    #[cfg(feature = "vm_space")]
436    #[space]
437    pub vm_space: VMSpace<VM>,
438}
439
440/// Args needed for creating any plan. This includes a set of contexts from MMTK or global. This
441/// is passed to each plan's constructor.
442pub struct CreateGeneralPlanArgs<'a, VM: VMBinding> {
443    pub vm_map: &'static dyn VMMap,
444    pub mmapper: &'static dyn Mmapper,
445    pub options: Arc<Options>,
446    pub state: Arc<GlobalState>,
447    pub gc_trigger: Arc<crate::util::heap::gc_trigger::GCTrigger<VM>>,
448    pub scheduler: Arc<GCWorkScheduler<VM>>,
449    pub stats: &'a Stats,
450    pub heap: &'a mut HeapMeta,
451}
452
453/// Args needed for creating a specific plan. This includes plan-specific args, such as plan constrainst
454/// and their global side metadata specs. This is created in each plan's constructor, and will be passed
455/// to `CommonPlan` or `BasePlan`. Also you can create `PlanCreateSpaceArg` from this type, and use that
456/// to create spaces.
457pub struct CreateSpecificPlanArgs<'a, VM: VMBinding> {
458    pub global_args: CreateGeneralPlanArgs<'a, VM>,
459    pub constraints: &'static PlanConstraints,
460    pub global_side_metadata_specs: Vec<SideMetadataSpec>,
461}
462
463impl<VM: VMBinding> CreateSpecificPlanArgs<'_, VM> {
464    /// Get a PlanCreateSpaceArgs that can be used to create a space
465    pub fn _get_space_args(
466        &mut self,
467        name: &'static str,
468        zeroed: bool,
469        permission_exec: bool,
470        unlog_allocated_object: bool,
471        unlog_traced_object: bool,
472        vmrequest: VMRequest,
473    ) -> PlanCreateSpaceArgs<'_, VM> {
474        PlanCreateSpaceArgs {
475            name,
476            zeroed,
477            permission_exec,
478            vmrequest,
479            unlog_allocated_object,
480            unlog_traced_object,
481            global_side_metadata_specs: self.global_side_metadata_specs.clone(),
482            vm_map: self.global_args.vm_map,
483            mmapper: self.global_args.mmapper,
484            heap: self.global_args.heap,
485            constraints: self.constraints,
486            gc_trigger: self.global_args.gc_trigger.clone(),
487            scheduler: self.global_args.scheduler.clone(),
488            options: self.global_args.options.clone(),
489            global_state: self.global_args.state.clone(),
490        }
491    }
492
493    // The following are some convenience methods for common presets.
494    // These are not an exhaustive list -- it is just common presets that are used by most plans.
495
496    /// Get a preset for a nursery space (where young objects are located).
497    pub fn get_nursery_space_args(
498        &mut self,
499        name: &'static str,
500        zeroed: bool,
501        permission_exec: bool,
502        vmrequest: VMRequest,
503    ) -> PlanCreateSpaceArgs<'_, VM> {
504        // Objects are allocatd as young, and when traced, they stay young. If they are copied out of the nursery space, they will be moved to a mature space,
505        // and log bits will be set in that case by the mature space.
506        self._get_space_args(name, zeroed, permission_exec, false, false, vmrequest)
507    }
508
509    /// Get a preset for a mature space (where mature objects are located).
510    pub fn get_mature_space_args(
511        &mut self,
512        name: &'static str,
513        zeroed: bool,
514        permission_exec: bool,
515        vmrequest: VMRequest,
516    ) -> PlanCreateSpaceArgs<'_, VM> {
517        // Objects are allocated as mature (pre-tenured), and when traced, they stay mature.
518        // If an object gets copied into a mature space, the object is also mature,
519        self._get_space_args(name, zeroed, permission_exec, true, true, vmrequest)
520    }
521
522    // Get a preset for a mixed age space (where both young and mature objects are located).
523    pub fn get_mixed_age_space_args(
524        &mut self,
525        name: &'static str,
526        zeroed: bool,
527        permission_exec: bool,
528        vmrequest: VMRequest,
529    ) -> PlanCreateSpaceArgs<'_, VM> {
530        // Objects are allocated as young, and when traced, they become mature objects.
531        self._get_space_args(name, zeroed, permission_exec, false, true, vmrequest)
532    }
533
534    /// Get a preset for spaces in a non-generational plan.
535    pub fn get_normal_space_args(
536        &mut self,
537        name: &'static str,
538        zeroed: bool,
539        permission_exec: bool,
540        vmrequest: VMRequest,
541    ) -> PlanCreateSpaceArgs<'_, VM> {
542        // Non generational plan: we do not use any of the flags about log bits.
543        self._get_space_args(name, zeroed, permission_exec, false, false, vmrequest)
544    }
545
546    /// Get a preset for spaces in [`crate::plan::global::CommonPlan`].
547    /// Spaces like LOS which may include both young and mature objects should not use this method.
548    pub fn get_common_space_args(
549        &mut self,
550        generational: bool,
551        name: &'static str,
552    ) -> PlanCreateSpaceArgs<'_, VM> {
553        self.get_base_space_args(
554            generational,
555            name,
556            false, // Common spaces are not executable.
557        )
558    }
559
560    /// Get a preset for spaces in [`crate::plan::global::BasePlan`].
561    pub fn get_base_space_args(
562        &mut self,
563        generational: bool,
564        name: &'static str,
565        permission_exec: bool,
566    ) -> PlanCreateSpaceArgs<'_, VM> {
567        if generational {
568            // In generational plans, common/base spaces behave like a mature space:
569            // * the objects in these spaces are not traced in a nursery GC
570            // * the log bits for the objects are maintained exactly the same as a mature space.
571            // Thus we consider them as mature spaces.
572            self.get_mature_space_args(name, true, permission_exec, VMRequest::discontiguous())
573        } else {
574            self.get_normal_space_args(name, true, permission_exec, VMRequest::discontiguous())
575        }
576    }
577}
578
579impl<VM: VMBinding> BasePlan<VM> {
580    #[allow(unused_mut)] // 'args' only needs to be mutable for certain features
581    pub fn new(mut args: CreateSpecificPlanArgs<VM>) -> BasePlan<VM> {
582        let _generational = args.constraints.generational;
583        BasePlan {
584            #[cfg(feature = "code_space")]
585            code_space: ImmortalSpace::new(args.get_base_space_args(
586                _generational,
587                "code_space",
588                true,
589            )),
590            #[cfg(feature = "code_space")]
591            code_lo_space: ImmortalSpace::new(args.get_base_space_args(
592                _generational,
593                "code_lo_space",
594                true,
595            )),
596            #[cfg(feature = "ro_space")]
597            ro_space: ImmortalSpace::new(args.get_base_space_args(
598                _generational,
599                "ro_space",
600                false,
601            )),
602            #[cfg(feature = "vm_space")]
603            vm_space: VMSpace::new(args.get_base_space_args(
604                _generational,
605                "vm_space",
606                false, // it doesn't matter -- we are not mmapping for VM space.
607            )),
608
609            global_state: args.global_args.state.clone(),
610            gc_trigger: args.global_args.gc_trigger,
611            options: args.global_args.options,
612            scheduler: args.global_args.scheduler,
613        }
614    }
615
616    // Depends on what base spaces we use, unsync may be unused.
617    pub fn get_used_pages(&self) -> usize {
618        // Depends on what base spaces we use, pages may be unchanged.
619        #[allow(unused_mut)]
620        let mut pages = 0;
621
622        #[cfg(feature = "code_space")]
623        {
624            pages += self.code_space.reserved_pages();
625            pages += self.code_lo_space.reserved_pages();
626        }
627        #[cfg(feature = "ro_space")]
628        {
629            pages += self.ro_space.reserved_pages();
630        }
631
632        // If we need to count malloc'd size as part of our heap, we add it here.
633        #[cfg(feature = "malloc_counted_size")]
634        {
635            pages += self.global_state.get_malloc_bytes_in_pages();
636        }
637
638        // The VM space may be used as an immutable boot image, in which case, we should not count
639        // it as part of the heap size.
640        pages
641    }
642
643    pub fn prepare(&mut self, _tls: VMWorkerThread, _full_heap: bool) {
644        #[cfg(feature = "code_space")]
645        self.code_space.prepare();
646        #[cfg(feature = "code_space")]
647        self.code_lo_space.prepare();
648        #[cfg(feature = "ro_space")]
649        self.ro_space.prepare();
650        #[cfg(feature = "vm_space")]
651        self.vm_space.prepare();
652    }
653
654    pub fn release(&mut self, _tls: VMWorkerThread, _full_heap: bool) {
655        #[cfg(feature = "code_space")]
656        self.code_space.release();
657        #[cfg(feature = "code_space")]
658        self.code_lo_space.release();
659        #[cfg(feature = "ro_space")]
660        self.ro_space.release();
661        #[cfg(feature = "vm_space")]
662        self.vm_space.release();
663    }
664
665    pub fn clear_side_log_bits(&self) {
666        #[cfg(feature = "code_space")]
667        self.code_space.clear_side_log_bits();
668        #[cfg(feature = "code_space")]
669        self.code_lo_space.clear_side_log_bits();
670        #[cfg(feature = "ro_space")]
671        self.ro_space.clear_side_log_bits();
672        #[cfg(feature = "vm_space")]
673        self.vm_space.clear_side_log_bits();
674    }
675
676    pub fn set_side_log_bits(&self) {
677        #[cfg(feature = "code_space")]
678        self.code_space.set_side_log_bits();
679        #[cfg(feature = "code_space")]
680        self.code_lo_space.set_side_log_bits();
681        #[cfg(feature = "ro_space")]
682        self.ro_space.set_side_log_bits();
683        #[cfg(feature = "vm_space")]
684        self.vm_space.set_side_log_bits();
685    }
686
687    pub fn end_of_pause(&mut self, _tls: VMWorkerThread) {
688        // Do nothing here. None of the spaces needs end_of_pause.
689    }
690
691    pub(crate) fn collection_required<P: Plan>(&self, plan: &P, space_full: bool) -> bool {
692        let stress_force_gc =
693            crate::util::heap::gc_trigger::GCTrigger::<VM>::should_do_stress_gc_inner(
694                &self.global_state,
695                &self.options,
696            );
697        if stress_force_gc {
698            debug!(
699                "Stress GC: allocation_bytes = {}, stress_factor = {}",
700                self.global_state.allocation_bytes.load(Ordering::Relaxed),
701                *self.options.stress_factor
702            );
703            debug!("Doing stress GC");
704            self.global_state
705                .allocation_bytes
706                .store(0, Ordering::SeqCst);
707        }
708
709        debug!(
710            "self.get_reserved_pages()={}, self.get_total_pages()={}",
711            plan.get_reserved_pages(),
712            plan.get_total_pages()
713        );
714        // Check if we reserved more pages (including the collection copy reserve)
715        // than the heap's total pages. In that case, we will have to do a GC.
716        let heap_full = plan.base().gc_trigger.is_heap_full();
717
718        space_full || stress_force_gc || heap_full
719    }
720}
721
722cfg_if::cfg_if! {
723    // Use immortal or mark sweep as the non moving space if the features are enabled. Otherwise use Immix.
724    if #[cfg(feature = "immortal_as_nonmoving")] {
725        pub type NonMovingSpace<VM> = crate::policy::immortalspace::ImmortalSpace<VM>;
726    } else if #[cfg(feature = "marksweep_as_nonmoving")] {
727        pub type NonMovingSpace<VM> = crate::policy::marksweepspace::native_ms::MarkSweepSpace<VM>;
728    } else {
729        pub type NonMovingSpace<VM> = crate::policy::immix::ImmixSpace<VM>;
730    }
731}
732
733/**
734CommonPlan is for representing state and features used by _many_ plans, but that are not fundamental to _all_ plans.  Examples include the Large Object Space and an Immortal space.  Features that are fundamental to _all_ plans must be included in BasePlan.
735*/
736#[derive(HasSpaces, PlanTraceObject)]
737pub struct CommonPlan<VM: VMBinding> {
738    #[space]
739    pub immortal: ImmortalSpace<VM>,
740    #[space]
741    pub los: LargeObjectSpace<VM>,
742    #[space]
743    #[cfg_attr(
744        not(any(feature = "immortal_as_nonmoving", feature = "marksweep_as_nonmoving")),
745        post_scan
746    )] // Immix space needs post_scan
747    pub nonmoving: NonMovingSpace<VM>,
748    #[parent]
749    pub base: BasePlan<VM>,
750}
751
752impl<VM: VMBinding> CommonPlan<VM> {
753    pub fn new(mut args: CreateSpecificPlanArgs<VM>) -> CommonPlan<VM> {
754        let needs_log_bit = args.constraints.needs_log_bit;
755        let generational = args.constraints.generational;
756        CommonPlan {
757            immortal: ImmortalSpace::new(args.get_common_space_args(generational, "immortal")),
758            los: LargeObjectSpace::new(
759                // LOS is a bit special, as it is a mixed age space. It has a logical nursery.
760                if generational {
761                    args.get_mixed_age_space_args("los", true, false, VMRequest::discontiguous())
762                } else {
763                    args.get_normal_space_args("los", true, false, VMRequest::discontiguous())
764                },
765                false,
766                needs_log_bit,
767            ),
768            nonmoving: Self::new_nonmoving_space(&mut args),
769            base: BasePlan::new(args),
770        }
771    }
772
773    pub fn get_used_pages(&self) -> usize {
774        self.immortal.reserved_pages()
775            + self.los.reserved_pages()
776            + self.nonmoving.reserved_pages()
777            + self.base.get_used_pages()
778    }
779
780    pub fn prepare(&mut self, tls: VMWorkerThread, full_heap: bool) {
781        self.immortal.prepare();
782        self.los.prepare(full_heap);
783        self.prepare_nonmoving_space(full_heap);
784        self.base.prepare(tls, full_heap)
785    }
786
787    pub fn release(&mut self, tls: VMWorkerThread, full_heap: bool) {
788        self.immortal.release();
789        self.los.release(full_heap);
790        self.release_nonmoving_space(full_heap);
791        self.base.release(tls, full_heap)
792    }
793
794    pub(crate) fn schedule_unlog_bits_op(&mut self, unlog_bits_op: UnlogBitsOperation) {
795        if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() {
796            // # Safety: CommonPlan reference is always valid within this collection cycle.
797            let common_plan = unsafe { &*(self as *const CommonPlan<VM>) };
798
799            match unlog_bits_op {
800                UnlogBitsOperation::NoOp => {}
801                UnlogBitsOperation::BulkSet => {
802                    self.base.scheduler.work_buckets[WorkBucketStage::Prepare]
803                        .add(SetCommonPlanUnlogBits { common_plan });
804                }
805                UnlogBitsOperation::BulkClear => {
806                    self.base.scheduler.work_buckets[WorkBucketStage::Release]
807                        .add(ClearCommonPlanUnlogBits { common_plan });
808                }
809            }
810        }
811    }
812
813    pub fn clear_side_log_bits(&self) {
814        self.immortal.clear_side_log_bits();
815        self.los.clear_side_log_bits();
816        self.base.clear_side_log_bits();
817    }
818
819    pub fn set_side_log_bits(&self) {
820        self.immortal.set_side_log_bits();
821        self.los.set_side_log_bits();
822        self.base.set_side_log_bits();
823    }
824
825    pub fn end_of_pause(&mut self, tls: VMWorkerThread) {
826        self.end_of_gc_nonmoving_space();
827        self.base.end_of_pause(tls);
828    }
829
830    pub fn get_immortal(&self) -> &ImmortalSpace<VM> {
831        &self.immortal
832    }
833
834    pub fn get_los(&self) -> &LargeObjectSpace<VM> {
835        &self.los
836    }
837
838    pub fn get_nonmoving(&self) -> &NonMovingSpace<VM> {
839        &self.nonmoving
840    }
841
842    fn new_nonmoving_space(args: &mut CreateSpecificPlanArgs<VM>) -> NonMovingSpace<VM> {
843        let space_args = args.get_common_space_args(args.constraints.generational, "nonmoving");
844        cfg_if::cfg_if! {
845            if #[cfg(any(feature = "immortal_as_nonmoving", feature = "marksweep_as_nonmoving"))] {
846                NonMovingSpace::new(space_args)
847            } else {
848                // Immix requires extra args.
849                NonMovingSpace::new(
850                    space_args,
851                    crate::policy::immix::ImmixSpaceArgs {
852                        mixed_age: false,
853                        never_move_objects: true,
854                    },
855                )
856            }
857        }
858    }
859
860    fn prepare_nonmoving_space(&mut self, _full_heap: bool) {
861        cfg_if::cfg_if! {
862            if #[cfg(feature = "immortal_as_nonmoving")] {
863                self.nonmoving.prepare();
864            } else if #[cfg(feature = "marksweep_as_nonmoving")] {
865                self.nonmoving.prepare(_full_heap);
866            } else {
867                self.nonmoving.prepare(_full_heap, None, UnlogBitsOperation::NoOp);
868            }
869        }
870    }
871
872    fn release_nonmoving_space(&mut self, _full_heap: bool) {
873        cfg_if::cfg_if! {
874            if #[cfg(feature = "immortal_as_nonmoving")] {
875                self.nonmoving.release();
876            } else if #[cfg(feature = "marksweep_as_nonmoving")] {
877                self.nonmoving.prepare(_full_heap);
878            } else {
879                self.nonmoving.release(_full_heap, UnlogBitsOperation::NoOp);
880            }
881        }
882    }
883
884    fn end_of_gc_nonmoving_space(&mut self) {
885        cfg_if::cfg_if! {
886            if #[cfg(feature = "immortal_as_nonmoving")] {
887                // Nothing we need to do for immortal space.
888            } else if #[cfg(feature = "marksweep_as_nonmoving")] {
889                self.nonmoving.end_of_gc();
890            } else {
891                self.nonmoving.end_of_gc();
892            }
893        }
894    }
895}
896
897use crate::policy::gc_work::TraceKind;
898use crate::vm::VMBinding;
899
900/// A trait for anything that contains spaces.
901/// Examples include concrete plans as well as `Gen`, `CommonPlan` and `BasePlan`.
902/// All plans must implement this trait.
903///
904/// This trait provides methods for enumerating spaces in a struct, including spaces in nested
905/// struct.
906///
907/// This trait can be implemented automatically by adding the `#[derive(HasSpaces)]` attribute to a
908/// struct.  It uses the derive macro defined in the `mmtk-macros` crate.
909///
910/// This trait visits spaces as `dyn`, so it should only be used when performance is not critical.
911/// For performance critical methods that visit spaces in a plan, such as `trace_object`, it is
912/// recommended to define a trait (such as `PlanTraceObject`) for concrete plans to implement, and
913/// implement (by hand or automatically) the method without `dyn`.
914pub trait HasSpaces {
915    // The type of the VM.
916    type VM: VMBinding;
917
918    /// Visit each space field immutably.
919    ///
920    /// If `Self` contains nested fields that contain more spaces, this method shall visit spaces
921    /// in the outer struct first.
922    fn for_each_space(&self, func: &mut dyn FnMut(&dyn Space<Self::VM>));
923
924    /// Visit each space field mutably.
925    ///
926    /// If `Self` contains nested fields that contain more spaces, this method shall visit spaces
927    /// in the outer struct first.
928    fn for_each_space_mut(&mut self, func: &mut dyn FnMut(&mut dyn Space<Self::VM>));
929}
930
931/// A plan that uses [`PlanTrace`] needs to provide an implementation for this trait.
932/// Generally a plan does not need to manually implement this trait. Instead, we provide
933/// a procedural macro that helps generate an implementation. Please check `macros/trace_object`.
934///
935/// A plan could also manually implement this trait. For the sake of performance, the implementation
936/// of this trait should mark methods as `[inline(always)]`.
937///
938/// [`PlanTrace`]: crate::plan::tracing::PlanTrace
939pub trait PlanTraceObject<VM: VMBinding> {
940    /// Trace objects in the plan.
941    ///
942    /// See [`crate::plan::tracing::Trace::trace_object`].
943    fn trace_object<Q: ObjectQueue, const KIND: TraceKind>(
944        &self,
945        queue: &mut Q,
946        object: ObjectReference,
947        worker: &mut GCWorker<VM>,
948    ) -> ObjectReference;
949
950    /// Post-scan objects in the plan.
951    ///
952    /// See [`crate::plan::tracing::Trace::post_scan_object`].
953    fn post_scan_object(&self, object: ObjectReference);
954
955    /// Whether objects in this plan may move.
956    ///
957    /// See [`crate::plan::tracing::Trace::post_scan_object`].
958    fn may_move_objects<const KIND: TraceKind>() -> bool;
959}
960
961use enum_map::Enum;
962/// Allocation semantics that MMTk provides.
963/// Each allocation request requires a desired semantic for the object to allocate.
964#[repr(i32)]
965#[derive(Clone, Copy, Debug, Enum, PartialEq, Eq)]
966pub enum AllocationSemantics {
967    /// The default semantic. This means there is no specific requirement for the allocation.
968    /// The actual semantic of the default will depend on the GC plan in use.
969    Default = 0,
970    /// Immortal objects will not be reclaimed. MMTk still traces immortal objects, but will not
971    /// reclaim the objects even if they are dead.
972    Immortal = 1,
973    /// Large objects. It is usually desirable to allocate large objects specially. Large objects
974    /// are allocated with page granularity and will not be moved.
975    /// Each plan provides `max_non_los_default_alloc_bytes` (see [`crate::plan::PlanConstraints`]),
976    /// which defines a threshold for objects that can be allocated with the default semantic. Any object that is larger than the
977    /// threshold must be allocated with the `Los` semantic.
978    /// This semantic may get removed and MMTk will transparently allocate into large object space for large objects.
979    Los = 2,
980    /// Code objects have execution permission.
981    /// Note that we do not currently support this semantic.
982    Code = 3,
983    /// Read-only objects cannot be mutated once it is initialized.
984    /// Note that we do not currently support this semantic.
985    ReadOnly = 4,
986    /// Los + Code.
987    /// Note that we do not currently support this semantic.
988    LargeCode = 5,
989    /// Non moving objects will not be moved by GC.
990    NonMoving = 6,
991}