mmtk/vm/collection.rs
1use crate::util::alloc::AllocationError;
2use crate::util::heap::gc_trigger::GCTriggerPolicy;
3use crate::util::opaque_pointer::*;
4use crate::vm::VMBinding;
5use crate::{scheduler::*, Mutator};
6
7/// Thread context for the spawned GC thread. It is used by `spawn_gc_thread`.
8/// Currently, `GCWorker` is the only kind of thread that mmtk-core will create.
9pub enum GCThreadContext<VM: VMBinding> {
10 /// The GC thread to spawn is a worker thread. There can be multiple worker threads.
11 Worker(Box<GCWorker<VM>>),
12}
13
14/// VM-specific methods for garbage collection.
15pub trait Collection<VM: VMBinding> {
16 /// Stop all the mutator threads. MMTk calls this method when it requires all the mutator to yield for a pause.
17 /// This method should not return until all the threads are yielded. When the method returns, MMTk assumes the pause starts.
18 /// The actual thread synchronization mechanism is up to the VM, and MMTk does not make assumptions on that.
19 /// MMTk provides a callback function and expects the binding to use the callback for each mutator when it
20 /// is ready for stack scanning. Usually a stack can be scanned as soon as the thread stops in the yieldpoint.
21 ///
22 /// Arguments:
23 /// * `tls`: The thread pointer for the GC worker.
24 /// * `mutator_visitor`: A callback. Call it with a mutator as argument to notify MMTk that the mutator is ready to be scanned.
25 fn stop_all_mutators<F>(tls: VMWorkerThread, mutator_visitor: F)
26 where
27 F: FnMut(&'static mut Mutator<VM>);
28
29 /// Resume all the mutator threads, the opposite of the above. When a pause is finished, MMTk calls this method.
30 ///
31 /// This method may not be called by the same GC thread that called `stop_all_mutators`.
32 ///
33 /// Arguments:
34 /// * `tls`: The thread pointer for the GC worker.
35 fn resume_mutators(tls: VMWorkerThread);
36
37 /// Block the current thread for GC. This is called when an allocation request cannot be fulfilled and a GC
38 /// is needed. MMTk calls this method to inform the VM that the current thread needs to be blocked as a GC
39 /// is going to happen. Then MMTk starts a GC. For a stop-the-world GC, MMTk will then call `stop_all_mutators()`
40 /// before the GC, and call `resume_mutators()` after the GC.
41 ///
42 /// Arguments:
43 /// * `tls`: The current thread pointer that should be blocked. The VM can optionally check if the current thread matches `tls`.
44 fn block_for_gc(tls: VMMutatorThread);
45
46 /// Ask the VM to spawn a GC thread for MMTk. A GC thread may later call into the VM through these VM traits. Some VMs
47 /// have assumptions that those calls needs to be within VM internal threads.
48 /// As a result, MMTk does not spawn GC threads itself to avoid breaking this kind of assumptions.
49 /// MMTk calls this method to spawn GC threads during [`crate::mmtk::MMTK::initialize_collection`]
50 /// and [`crate::mmtk::MMTK::after_fork`].
51 ///
52 /// Arguments:
53 /// * `tls`: The thread pointer for the parent thread that we spawn new threads from. This is the same `tls` when the VM
54 /// calls `initialize_collection()` and passes as an argument.
55 /// * `ctx`: The context for the GC thread.
56 /// * If [`GCThreadContext::Worker`] is passed, it means spawning a thread to run as a GC worker.
57 /// The spawned thread shall call the entry point function `GCWorker::run`.
58 /// Currently `Worker` is the only kind of thread which mmtk-core will create.
59 fn spawn_gc_thread(tls: VMThread, ctx: GCThreadContext<VM>);
60
61 /// Inform the VM of an out-of-memory error. The binding should hook into the VM's error
62 /// routine for OOM. Note that there are two different categories of OOM:
63 /// * Critical OOM: This is the case where the OS is unable to mmap or acquire more memory.
64 /// MMTk expects the VM to abort immediately if such an error is thrown.
65 /// * Heap OOM: This is the case where the specified heap size is insufficient to execute the
66 /// application. MMTk expects the binding to notify the VM about this OOM. MMTk makes no
67 /// assumptions about whether the VM will continue executing or abort immediately.
68 ///
69 /// See [`AllocationError`] for more information.
70 ///
71 /// Arguments:
72 /// * `tls`: The thread pointer for the mutator which failed the allocation and triggered the OOM.
73 /// * `err_kind`: The type of OOM error that was encountered.
74 ///
75 /// # Warnings about stack unwinding
76 ///
77 /// Some programming languages throw exceptions when the heap is out of memory. We recommend
78 /// letting `Collection::out_of_memory` return so that [`crate::memory_manager::alloc`] or
79 /// [`crate::memory_manager::alloc_with_options`] will return `Address::ZERO`. The VM binding
80 /// then throws exceptions when it detects such a return value. In the case of
81 /// `alloc_with_option` where it may also return `Address::ZERO` if not at safepoint, the VM
82 /// binding can set some thread-local flags in `Collection::out_of_memory` to distinguish
83 /// between the two different cases that return zero.
84 ///
85 /// It may be tempting to implement throwing exceptions by unwinding the stack from within
86 /// `Collection::out_of_memory`. But the VM binding developers must be aware that the behavior
87 /// of
88 ///
89 /// 1. whether any stack frame can be unwound, and
90 /// 2. whether local variables that implement the [`Drop`] trait will be dropped
91 ///
92 /// depends on many factors, including but not limited to:
93 ///
94 /// - the unwinding mechanism, such as `panic!()` (Rust), `throw` (C++), `longjmp` (C), etc.
95 /// - the ABI of the function of each stack frame, such as "Rust", "C-unwind", "C", etc.
96 /// - inlining decisions made by the compiler
97 /// - the Rust [panic handler]
98 /// - the [`panic` codegen option]
99 /// - whether any native (C/C++/etc.) functions are compiled with `-fno-exceptions`
100 /// - whether C++ functions have the `noexcept` specifier
101 /// - the implementation-specified behaviour in C++ where `throw` is executed but no exception
102 /// handler is found on the stack (the implementation may choose to terminate immediately
103 /// without unwinding at all)
104 ///
105 /// [panic handler]: https://doc.rust-lang.org/reference/panic.html#r-panic.panic_handler
106 /// [`panic` codegen option]: https://doc.rust-lang.org/rustc/codegen-options/index.html#panic
107 ///
108 /// The Rust Documentation [specifies][rust-unw] that when unwinding across certain ABI
109 /// boundaries, it will result in aborting or [undefined behavior][rust-ub]. The VM binding
110 /// developers need to be extremely careful about those details, but the obvious alternative is
111 /// simply returning from `Collection::out_of_memory`.
112 ///
113 /// [rust-unw]: https://doc.rust-lang.org/reference/items/functions.html#unwinding
114 /// [rust-ub]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
115 fn out_of_memory(_tls: VMThread, err_kind: AllocationError) {
116 panic!("Out of memory with {:?}!", err_kind);
117 }
118
119 /// Inform the VM to schedule finalization threads.
120 ///
121 /// Arguments:
122 /// * `tls`: The thread pointer for the current GC thread.
123 fn schedule_finalization(_tls: VMWorkerThread) {}
124
125 /// A hook for the VM to do work after forwarding objects.
126 ///
127 /// This function is called after all of the following have finished:
128 /// - The life and death of objects are determined. Objects determined to be live will not
129 /// be reclaimed in this GC.
130 /// - Live objects have been moved to their destinations. (copying GC only)
131 /// - References in objects have been updated to point to new addresses. (copying GC only)
132 ///
133 /// And this function may run concurrently with the release work of GC, i.e. freeing the space
134 /// occupied by dead objects.
135 ///
136 /// It is safe for the VM to read and write object fields at this time, although GC has not
137 /// finished yet. GC will be reclaiming spaces of dead objects, but will not damage live
138 /// objects. However, the VM cannot allocate new objects at this time.
139 ///
140 /// One possible use of this hook is enqueuing `{Soft,Weak,Phantom}Reference` instances to
141 /// reference queues (for Java). VMs (including JVM implementations) do not have to handle
142 /// weak references this way, but mmtk-core provides this opportunity.
143 ///
144 /// Arguments:
145 /// * `tls_worker`: The thread pointer for the worker thread performing this call.
146 fn post_forwarding(_tls: VMWorkerThread) {}
147
148 /// Return the amount of memory (in bytes) which the VM allocated outside the MMTk heap but
149 /// wants to include into the current MMTk heap size. MMTk core will consider the reported
150 /// memory as part of MMTk heap for the purpose of heap size accounting.
151 ///
152 /// This amount should include memory that is kept alive by heap objects and can be released by
153 /// executing finalizers (or other language-specific cleaning-up routines) that are executed
154 /// when the heap objects are dead. For example, if a language implementation allocates array
155 /// headers in the MMTk heap, but allocates their underlying buffers that hold the actual
156 /// elements using `malloc`, then those buffers should be included in this amount. When the GC
157 /// finds such an array dead, its finalizer shall `free` the buffer and reduce this amount.
158 ///
159 /// If possible, the VM should account off-heap memory in pages. That is, count the number of
160 /// pages occupied by off-heap objects, and report the number of bytes of those whole pages
161 /// instead of individual objects. Because the underlying operating system manages memory at
162 /// page granularity, the occupied pages (instead of individual objects) determine the memory
163 /// footprint of a process, and how much memory MMTk spaces can obtain from the OS.
164 ///
165 /// However, if the VM is incapable of accounting off-heap memory in pages (for example, if the
166 /// VM uses `malloc` and the implementation of `malloc` is opaque to the VM), the VM binding
167 /// can simply return the total number of bytes of those off-heap objects as an approximation.
168 ///
169 /// # Performance note
170 ///
171 /// This function will be called when MMTk polls for GC. It happens every time the MMTk
172 /// allocators have allocated a certain amount of memory, usually one or a few blocks. Because
173 /// this function is called very frequently, its implementation must be efficient. If it is
174 /// too expensive to compute the exact amount, an approximate value should be sufficient for
175 /// MMTk to trigger GC promptly in order to release off-heap memory, and keep the memory
176 /// footprint under control.
177 fn vm_live_bytes() -> usize {
178 // By default, MMTk assumes the amount of memory the VM allocates off-heap is negligible.
179 0
180 }
181
182 /// Callback function to ask the VM whether GC is enabled or disabled, allowing or disallowing MMTk
183 /// to trigger garbage collection. When collection is disabled, you can still allocate through MMTk,
184 /// but MMTk will not trigger a GC even if the heap is full. In such a case, the allocation will
185 /// exceed MMTk's heap size (the soft heap limit). However, there is no guarantee that the physical
186 /// allocation will succeed, and if it succeeds, there is no guarantee that further allocation will
187 /// keep succeeding. So if a VM disables collection, it needs to allocate with careful consideration
188 /// to make sure that the physical memory allows the amount of allocation. We highly recommend
189 /// to have GC always enabled (i.e. that this method always returns true). However, we support
190 /// this to accomodate some VMs that require this behavior. Note that
191 /// `handle_user_collection_request()` calls this function, too. If this function returns
192 /// false, `handle_user_collection_request()` will not trigger GC, either. Note also that any synchronization
193 /// involving enabling and disabling collections by mutator threads should be implemented by the VM.
194 fn is_collection_enabled() -> bool {
195 // By default, MMTk assumes that collections are always enabled, and the binding should define
196 // this method if the VM supports disabling GC, or if the VM cannot safely trigger GC until some
197 // initialization is done, such as initializing class metadata for scanning objects.
198 true
199 }
200
201 /// Ask the binding to create a [`GCTriggerPolicy`] if the option `gc_trigger` is set to
202 /// `crate::util::options::GCTriggerSelector::Delegated`.
203 fn create_gc_trigger() -> Box<dyn GCTriggerPolicy<VM>> {
204 unimplemented!()
205 }
206}