mmtk/
memory_manager.rs

1//! VM-to-MMTk interface: safe Rust APIs.
2//!
3//! This module provides a safe Rust API for mmtk-core.
4//! We expect the VM binding to inherit and extend this API by:
5//! 1. adding their VM-specific functions
6//! 2. exposing the functions to native if necessary. And the VM binding needs to manage the unsafety
7//!    for exposing this safe API to FFI.
8//!
9//! For example, for mutators, this API provides a `Box<Mutator>`, and requires a `&mut Mutator` for allocation.
10//! A VM binding can borrow a mutable reference directly from `Box<Mutator>`, and call `alloc()`. Alternatively,
11//! it can turn the `Box` pointer to a native pointer (`*mut Mutator`), and forge a mut reference from the native
12//! pointer. Either way, the VM binding code needs to guarantee the safety.
13
14use crate::global_state::GcStatus;
15use crate::mmtk::MMTKBuilder;
16use crate::mmtk::MMTK;
17use crate::plan::AllocationSemantics;
18use crate::plan::{Mutator, MutatorContext};
19use crate::scheduler::WorkBucketStage;
20use crate::scheduler::{GCWork, GCWorker};
21use crate::util::alloc::allocator::AllocationOptions;
22use crate::util::alloc::allocators::AllocatorSelector;
23use crate::util::constants::LOG_BYTES_IN_PAGE;
24use crate::util::heap::layout::vm_layout::vm_layout;
25use crate::util::opaque_pointer::*;
26use crate::util::{Address, ObjectReference};
27use crate::vm::slot::MemorySlice;
28use crate::vm::ReferenceGlue;
29use crate::vm::VMBinding;
30
31use std::collections::HashMap;
32
33/// Initialize an MMTk instance. A VM should call this method after creating an [`crate::MMTK`]
34/// instance but before using any of the methods provided in MMTk (except `process()` and `process_bulk()`).
35///
36/// We expect a binding to ininitialize MMTk in the following steps:
37///
38/// 1. Create an [`crate::MMTKBuilder`] instance.
39/// 2. Set command line options for MMTKBuilder by [`crate::memory_manager::process`] or [`crate::memory_manager::process_bulk`].
40/// 3. Initialize MMTk by calling this function, `mmtk_init()`, and pass the builder earlier. This call will return an MMTK instance.
41///    Usually a binding store the MMTK instance statically as a singleton. We plan to allow multiple instances, but this is not yet fully
42///    supported. Currently we assume a binding will only need one MMTk instance. Note that GC is enabled by default and the binding should
43///    implement `VMCollection::is_collection_enabled()` if it requires that the GC should be disabled at a particular time.
44///
45/// This method will attempt to initialize the built-in `env_logger` if the Cargo feature "builtin_env_logger" is enabled (by default).
46/// If the VM would like to use its own logger, it should disable the default feature "builtin_env_logger" in `Cargo.toml`.
47///
48/// Note that, to allow MMTk to do GC properly, `initialize_collection()` needs to be called after this call when
49/// the VM's thread system is ready to spawn GC workers.
50///
51/// Note that this method returns a boxed pointer of MMTK, which means MMTk has a bound lifetime with the box pointer. However, some of our current APIs assume
52/// that MMTk has a static lifetime, which presents a mismatch with this API. We plan to address the lifetime issue in the future. At this point, we recommend a binding
53/// to 'expand' the lifetime for the boxed pointer to static. There could be multiple ways to achieve it: 1. `Box::leak()` will turn the box pointer to raw pointer
54/// which has static lifetime, 2. create MMTK as a lazily initialized static variable
55/// (see [what we do for our dummy binding](https://github.com/mmtk/mmtk-core/blob/master/vmbindings/dummyvm/src/lib.rs#L42))
56///
57/// Arguments:
58/// * `builder`: The reference to a MMTk builder.
59pub fn mmtk_init<VM: VMBinding>(builder: &MMTKBuilder) -> Box<MMTK<VM>> {
60    crate::util::logger::try_init();
61
62    #[cfg(all(feature = "perf_counter", target_os = "linux"))]
63    {
64        use std::fs::File;
65        use std::io::Read;
66        let mut status = File::open("/proc/self/status").unwrap();
67        let mut contents = String::new();
68        status.read_to_string(&mut contents).unwrap();
69        for line in contents.lines() {
70            let split: Vec<&str> = line.split('\t').collect();
71            if split[0] == "Threads:" {
72                let threads = split[1].parse::<i32>().unwrap();
73                if threads != 1 {
74                    warn!("Current process has {} threads, process-wide perf event measurement will only include child threads spawned from this thread", threads);
75                }
76            }
77        }
78    }
79
80    let mmtk = builder.build();
81    info!(
82        "Initialized MMTk with {:?} ({:?})",
83        *mmtk.options.plan, *mmtk.options.gc_trigger
84    );
85    #[cfg(feature = "extreme_assertions")]
86    warn!("The feature 'extreme_assertions' is enabled. MMTk will run expensive run-time checks. Slow performance should be expected.");
87    Box::new(mmtk)
88}
89
90/// Shut down an MMTk instance.
91/// This would asynchronously request GC workers to stop. Bindings need to check if all GC workers have quit in binding-specific ways.
92pub fn mmtk_shutdown<VM: VMBinding>(mmtk: &'static MMTK<VM>) {
93    mmtk.shutdown();
94}
95
96/// Add an externally mmapped region to the VM space. A VM space can be set through MMTk options (`vm_space_start` and `vm_space_size`),
97/// and can also be set through this function call. A VM space can be discontiguous. This function can be called multiple times,
98/// and all the address ranges passed as arguments in the function will be considered as part of the VM space.
99/// Currently we do not allow removing regions from VM space.
100#[cfg(feature = "vm_space")]
101pub fn set_vm_space<VM: VMBinding>(mmtk: &'static mut MMTK<VM>, start: Address, size: usize) {
102    unsafe { mmtk.get_plan_mut() }
103        .base_mut()
104        .vm_space
105        .set_vm_region(start, size);
106}
107
108/// Request MMTk to create a mutator for the given thread. The ownership
109/// of returned boxed mutator is transferred to the binding, and the binding needs to take care of its
110/// lifetime. For performance reasons, A VM should store the returned mutator in a thread local storage
111/// that can be accessed efficiently. A VM may also copy and embed the mutator stucture to a thread-local data
112/// structure, and use that as a reference to the mutator (it is okay to drop the box once the content is copied --
113/// Note that `Mutator` may contain pointers so a binding may drop the box only if they perform a deep copy).
114///
115/// MMTk generally does not expect the runtime to create or destroy mutators during a pause. See also [`crate::vm::ActivePlan::mutators`].
116///
117/// Arguments:
118/// * `mmtk`: A reference to an MMTk instance.
119/// * `tls`: The thread that will be associated with the mutator.
120pub fn bind_mutator<VM: VMBinding>(
121    mmtk: &'static MMTK<VM>,
122    tls: VMMutatorThread,
123) -> Box<Mutator<VM>> {
124    let mutator = crate::plan::create_mutator(tls, mmtk);
125
126    const LOG_ALLOCATOR_MAPPING: bool = false;
127    if LOG_ALLOCATOR_MAPPING {
128        info!("{:?}", mutator.config);
129    }
130    mutator
131}
132
133/// Report to MMTk that a mutator is no longer needed. All mutator state is flushed before it is
134/// destroyed. A binding should not attempt to use the mutator after this call. MMTk will not
135/// attempt to reclaim the memory for the mutator, so a binding should properly reclaim the memory
136/// for the mutator after this call.
137///
138/// MMTk generally does not expect the runtime to create or destroy mutators during a pause. See also [`crate::vm::ActivePlan::mutators`].
139///
140/// Arguments:
141/// * `mutator`: A reference to the mutator to be destroyed.
142pub fn destroy_mutator<VM: VMBinding>(mutator: &mut Mutator<VM>) {
143    mutator.flush();
144    mutator.on_destroy();
145}
146
147/// Flush the mutator's local states.
148///
149/// Arguments:
150/// * `mutator`: A reference to the mutator.
151pub fn flush_mutator<VM: VMBinding>(mutator: &mut Mutator<VM>) {
152    mutator.flush()
153}
154
155/// Allocate memory for an object.
156///
157/// When the allocation is successful, it returns the starting address of the new object.  The
158/// memory range for the new object is `size` bytes starting from the returned address, and
159/// `RETURNED_ADDRESS + offset` is guaranteed to be aligned to the `align` parameter.  The returned
160/// address of a successful allocation will never be zero.
161///
162/// If MMTk fails to allocate memory, it will attempt a GC to free up some memory and retry the
163/// allocation.  After triggering GC, it will call [`crate::vm::Collection::block_for_gc`] to suspend
164/// the current thread that is allocating. Callers of `alloc` must be aware of this behavior.
165/// For example, JIT compilers that support
166/// precise stack scanning need to make the call site of `alloc` a GC-safe point by generating stack maps. See
167/// [`alloc_with_options`] if it is undesirable to trigger GC at this allocation site.
168///
169/// If MMTk has attempted at least one GC, and still cannot free up enough memory, it will call
170/// [`crate::vm::Collection::out_of_memory`] to inform the binding. The VM binding
171/// can implement that method to handle the out-of-memory event in a VM-specific way, including but
172/// not limited to throwing exceptions or errors. If [`crate::vm::Collection::out_of_memory`] returns
173/// normally without panicking or throwing exceptions, this function will return zero.
174///
175/// For performance reasons, a VM should implement the allocation fast-path on their side rather
176/// than just calling this function.
177///
178/// Arguments:
179/// * `mutator`: The mutator to perform this allocation request.
180/// * `size`: The number of bytes required for the object.
181/// * `align`: Required alignment for the object.
182/// * `offset`: Offset associated with the alignment.
183/// * `semantics`: The allocation semantic required for the allocation.
184pub fn alloc<VM: VMBinding>(
185    mutator: &mut Mutator<VM>,
186    size: usize,
187    align: usize,
188    offset: usize,
189    semantics: AllocationSemantics,
190) -> Address {
191    #[cfg(debug_assertions)]
192    crate::util::alloc::allocator::assert_allocation_args::<VM>(size, align, offset);
193
194    mutator.alloc(size, align, offset, semantics)
195}
196
197/// Allocate memory for an object.
198///
199/// This allocation function allows alternation to the allocation behaviors, specified by the
200/// [`crate::util::alloc::AllocationOptions`]. For example, one can allow
201/// overcommit the memory to go beyond the heap size without triggering a GC. This function can be
202/// used in certain cases where the runtime needs a different allocation behavior other than
203/// what the default [`alloc`] provides.
204///
205/// Arguments:
206/// * `mutator`: The mutator to perform this allocation request.
207/// * `size`: The number of bytes required for the object.
208/// * `align`: Required alignment for the object.
209/// * `offset`: Offset associated with the alignment.
210/// * `semantics`: The allocation semantic required for the allocation.
211/// * `options`: the allocation options to change the default allocation behavior for this request.
212pub fn alloc_with_options<VM: VMBinding>(
213    mutator: &mut Mutator<VM>,
214    size: usize,
215    align: usize,
216    offset: usize,
217    semantics: AllocationSemantics,
218    options: crate::util::alloc::allocator::AllocationOptions,
219) -> Address {
220    #[cfg(debug_assertions)]
221    crate::util::alloc::allocator::assert_allocation_args::<VM>(size, align, offset);
222
223    mutator.alloc_with_options(size, align, offset, semantics, options)
224}
225
226/// Invoke the allocation slow path of [`alloc`].
227/// Like [`alloc`], this function may trigger GC and call [`crate::vm::Collection::block_for_gc`] or
228/// [`crate::vm::Collection::out_of_memory`].  The caller needs to be aware of that.
229///
230/// *Notes*: This is only intended for use when a binding implements the fastpath on
231/// the binding side. When the binding handles fast path allocation and the fast path fails, it can use this
232/// method for slow path allocation. Calling before exhausting fast path allocaiton buffer will lead to bad
233/// performance.
234///
235/// Arguments:
236/// * `mutator`: The mutator to perform this allocation request.
237/// * `size`: The number of bytes required for the object.
238/// * `align`: Required alignment for the object.
239/// * `offset`: Offset associated with the alignment.
240/// * `semantics`: The allocation semantic required for the allocation.
241pub fn alloc_slow<VM: VMBinding>(
242    mutator: &mut Mutator<VM>,
243    size: usize,
244    align: usize,
245    offset: usize,
246    semantics: AllocationSemantics,
247) -> Address {
248    mutator.alloc_slow(size, align, offset, semantics)
249}
250
251/// Invoke the allocation slow path of [`alloc_with_options`].
252///
253/// Like [`alloc_with_options`], This allocation function allows alternation to the allocation behaviors, specified by the
254/// [`crate::util::alloc::AllocationOptions`]. For example, one can allow
255/// overcommit the memory to go beyond the heap size without triggering a GC. This function can be
256/// used in certain cases where the runtime needs a different allocation behavior other than
257/// what the default [`alloc`] provides.
258///
259/// Like [`alloc_slow`], this function is also only intended for use when a binding implements the
260/// fastpath on the binding side.
261///
262/// Arguments:
263/// * `mutator`: The mutator to perform this allocation request.
264/// * `size`: The number of bytes required for the object.
265/// * `align`: Required alignment for the object.
266/// * `offset`: Offset associated with the alignment.
267/// * `semantics`: The allocation semantic required for the allocation.
268pub fn alloc_slow_with_options<VM: VMBinding>(
269    mutator: &mut Mutator<VM>,
270    size: usize,
271    align: usize,
272    offset: usize,
273    semantics: AllocationSemantics,
274    options: AllocationOptions,
275) -> Address {
276    mutator.alloc_slow_with_options(size, align, offset, semantics, options)
277}
278
279/// Perform post-allocation actions, usually initializing object metadata. For many allocators none are
280/// required. For performance reasons, a VM should implement the post alloc fast-path on their side
281/// rather than just calling this function.
282///
283/// Arguments:
284/// * `mutator`: The mutator to perform post-alloc actions.
285/// * `refer`: The newly allocated object.
286/// * `bytes`: The size of the space allocated for the object (in bytes).
287/// * `semantics`: The allocation semantics used for the allocation.
288pub fn post_alloc<VM: VMBinding>(
289    mutator: &mut Mutator<VM>,
290    refer: ObjectReference,
291    bytes: usize,
292    semantics: AllocationSemantics,
293) {
294    mutator.post_alloc(refer, bytes, semantics);
295}
296
297/// The *subsuming* write barrier by MMTk. For performance reasons, a VM should implement the write barrier
298/// fast-path on their side rather than just calling this function.
299///
300/// For a correct barrier implementation, a VM binding needs to choose one of the following options:
301/// * Use subsuming barrier `object_reference_write`
302/// * Use both `object_reference_write_pre` and `object_reference_write_post`, or both, if the binding has difficulty delegating the store to mmtk-core with the subsuming barrier.
303/// * Implement fast-path on the VM side, and call the generic api `object_reference_write_slow` as barrier slow-path call.
304/// * Implement fast-path on the VM side, and do a specialized slow-path call.
305///
306/// Arguments:
307/// * `mutator`: The mutator for the current thread.
308/// * `src`: The modified source object.
309/// * `slot`: The location of the field to be modified.
310/// * `target`: The target for the write operation.
311///
312/// # Deprecated
313///
314/// This function needs to be redesigned.  Its current form has multiple issues.
315///
316/// -   It is only able to write non-null object references into the slot.  But dynamic language
317///     VMs may write non-reference values, such as tagged small integers, special values such as
318///     `null`, `undefined`, `true`, `false`, etc. into a field that previous contains an object
319///     reference.
320/// -   It relies on `slot.store` to write `target` into the slot, but `slot.store` is designed for
321///     forwarding references when an object is moved by GC, and is supposed to preserve tagged
322///     type information, the offset (if it is an interior pointer), etc.  A write barrier is
323///     associated to an assignment operation, which usually updates such information instead.
324///
325/// We will redesign a more general subsuming write barrier to address those problems and replace
326/// the current `object_reference_write`.  Before that happens, VM bindings should use
327/// `object_reference_write_pre` and `object_reference_write_post` instead.
328#[deprecated = "Use `object_reference_write_pre` and `object_reference_write_post` instead, until this function is redesigned"]
329pub fn object_reference_write<VM: VMBinding>(
330    mutator: &mut Mutator<VM>,
331    src: ObjectReference,
332    slot: VM::VMSlot,
333    target: ObjectReference,
334) {
335    mutator.barrier().object_reference_write(src, slot, target);
336}
337
338/// The write barrier by MMTk. This is a *pre* write barrier, which we expect a binding to call
339/// *before* it modifies an object. For performance reasons, a VM should implement the write barrier
340/// fast-path on their side rather than just calling this function.
341///
342/// For a correct barrier implementation, a VM binding needs to choose one of the following options:
343/// * Use subsuming barrier `object_reference_write`
344/// * Use both `object_reference_write_pre` and `object_reference_write_post`, or both, if the binding has difficulty delegating the store to mmtk-core with the subsuming barrier.
345/// * Implement fast-path on the VM side, and call the generic api `object_reference_write_slow` as barrier slow-path call.
346/// * Implement fast-path on the VM side, and do a specialized slow-path call.
347///
348/// Arguments:
349/// * `mutator`: The mutator for the current thread.
350/// * `src`: The modified source object.
351/// * `slot`: The location of the field to be modified.
352/// * `target`: The target for the write operation.  `None` if the slot did not hold an object
353///   reference before the write operation.  For example, the slot may be holding a `null`
354///   reference, a small integer, or special values such as `true`, `false`, `undefined`, etc.
355pub fn object_reference_write_pre<VM: VMBinding>(
356    mutator: &mut Mutator<VM>,
357    src: ObjectReference,
358    slot: VM::VMSlot,
359    target: Option<ObjectReference>,
360) {
361    mutator
362        .barrier()
363        .object_reference_write_pre(src, slot, target);
364}
365
366/// The write barrier by MMTk. This is a *post* write barrier, which we expect a binding to call
367/// *after* it modifies an object. For performance reasons, a VM should implement the write barrier
368/// fast-path on their side rather than just calling this function.
369///
370/// For a correct barrier implementation, a VM binding needs to choose one of the following options:
371/// * Use subsuming barrier `object_reference_write`
372/// * Use both `object_reference_write_pre` and `object_reference_write_post`, or both, if the binding has difficulty delegating the store to mmtk-core with the subsuming barrier.
373/// * Implement fast-path on the VM side, and call the generic api `object_reference_write_slow` as barrier slow-path call.
374/// * Implement fast-path on the VM side, and do a specialized slow-path call.
375///
376/// Arguments:
377/// * `mutator`: The mutator for the current thread.
378/// * `src`: The modified source object.
379/// * `slot`: The location of the field to be modified.
380/// * `target`: The target for the write operation.  `None` if the slot no longer hold an object
381///   reference after the write operation.  This may happen when writing a `null` reference, a small
382///   integers, or a special value such as`true`, `false`, `undefined`, etc., into the slot.
383pub fn object_reference_write_post<VM: VMBinding>(
384    mutator: &mut Mutator<VM>,
385    src: ObjectReference,
386    slot: VM::VMSlot,
387    target: Option<ObjectReference>,
388) {
389    mutator
390        .barrier()
391        .object_reference_write_post(src, slot, target);
392}
393
394/// The *subsuming* memory region copy barrier by MMTk.
395/// This is called when the VM tries to copy a piece of heap memory to another.
396/// The data within the slice does not necessarily to be all valid pointers,
397/// but the VM binding will be able to filter out non-reference values on slot iteration.
398///
399/// For VMs that performs a heap memory copy operation, for example OpenJDK's array copy operation, the binding needs to
400/// call `memory_region_copy*` APIs. Same as `object_reference_write*`, the binding can choose either the subsuming barrier,
401/// or the pre/post barrier.
402///
403/// Arguments:
404/// * `mutator`: The mutator for the current thread.
405/// * `src`: Source memory slice to copy from.
406/// * `dst`: Destination memory slice to copy to.
407///
408/// The size of `src` and `dst` shoule be equal
409pub fn memory_region_copy<VM: VMBinding>(
410    mutator: &'static mut Mutator<VM>,
411    src: VM::VMMemorySlice,
412    dst: VM::VMMemorySlice,
413) {
414    debug_assert_eq!(src.bytes(), dst.bytes());
415    mutator.barrier().memory_region_copy(src, dst);
416}
417
418/// The *generic* memory region copy *pre* barrier by MMTk, which we expect a binding to call
419/// *before* it performs memory copy.
420/// This is called when the VM tries to copy a piece of heap memory to another.
421/// The data within the slice does not necessarily to be all valid pointers,
422/// but the VM binding will be able to filter out non-reference values on slot iteration.
423///
424/// For VMs that performs a heap memory copy operation, for example OpenJDK's array copy operation, the binding needs to
425/// call `memory_region_copy*` APIs. Same as `object_reference_write*`, the binding can choose either the subsuming barrier,
426/// or the pre/post barrier.
427///
428/// Arguments:
429/// * `mutator`: The mutator for the current thread.
430/// * `src`: Source memory slice to copy from.
431/// * `dst`: Destination memory slice to copy to.
432///
433/// The size of `src` and `dst` shoule be equal
434pub fn memory_region_copy_pre<VM: VMBinding>(
435    mutator: &'static mut Mutator<VM>,
436    src: VM::VMMemorySlice,
437    dst: VM::VMMemorySlice,
438) {
439    debug_assert_eq!(src.bytes(), dst.bytes());
440    mutator.barrier().memory_region_copy_pre(src, dst);
441}
442
443/// The *generic* memory region copy *post* barrier by MMTk, which we expect a binding to call
444/// *after* it performs memory copy.
445/// This is called when the VM tries to copy a piece of heap memory to another.
446/// The data within the slice does not necessarily to be all valid pointers,
447/// but the VM binding will be able to filter out non-reference values on slot iteration.
448///
449/// For VMs that performs a heap memory copy operation, for example OpenJDK's array copy operation, the binding needs to
450/// call `memory_region_copy*` APIs. Same as `object_reference_write*`, the binding can choose either the subsuming barrier,
451/// or the pre/post barrier.
452///
453/// Arguments:
454/// * `mutator`: The mutator for the current thread.
455/// * `src`: Source memory slice to copy from.
456/// * `dst`: Destination memory slice to copy to.
457///
458/// The size of `src` and `dst` shoule be equal
459pub fn memory_region_copy_post<VM: VMBinding>(
460    mutator: &'static mut Mutator<VM>,
461    src: VM::VMMemorySlice,
462    dst: VM::VMMemorySlice,
463) {
464    debug_assert_eq!(src.bytes(), dst.bytes());
465    mutator.barrier().memory_region_copy_post(src, dst);
466}
467
468/// Return an AllocatorSelector for the given allocation semantic. This method is provided
469/// so that VM compilers may call it to help generate allocation fast-path.
470///
471/// Arguments:
472/// * `mmtk`: The reference to an MMTk instance.
473/// * `semantics`: The allocation semantic to query.
474pub fn get_allocator_mapping<VM: VMBinding>(
475    mmtk: &MMTK<VM>,
476    semantics: AllocationSemantics,
477) -> AllocatorSelector {
478    mmtk.get_plan().get_allocator_mapping()[semantics]
479}
480
481/// The standard malloc. MMTk either uses its own allocator, or forward the call to a
482/// library malloc.
483pub fn malloc(size: usize) -> Address {
484    crate::util::malloc::malloc(size)
485}
486
487/// The standard malloc except that with the feature `malloc_counted_size`, MMTk will count the allocated memory into its heap size.
488/// Thus the method requires a reference to an MMTk instance. MMTk either uses its own allocator, or forward the call to a
489/// library malloc.
490#[cfg(feature = "malloc_counted_size")]
491pub fn counted_malloc<VM: VMBinding>(mmtk: &MMTK<VM>, size: usize) -> Address {
492    crate::util::malloc::counted_malloc(mmtk, size)
493}
494
495/// The standard calloc.
496pub fn calloc(num: usize, size: usize) -> Address {
497    crate::util::malloc::calloc(num, size)
498}
499
500/// The standard calloc except that with the feature `malloc_counted_size`, MMTk will count the allocated memory into its heap size.
501/// Thus the method requires a reference to an MMTk instance.
502#[cfg(feature = "malloc_counted_size")]
503pub fn counted_calloc<VM: VMBinding>(mmtk: &MMTK<VM>, num: usize, size: usize) -> Address {
504    crate::util::malloc::counted_calloc(mmtk, num, size)
505}
506
507/// The standard realloc.
508pub fn realloc(addr: Address, size: usize) -> Address {
509    crate::util::malloc::realloc(addr, size)
510}
511
512/// The standard realloc except that with the feature `malloc_counted_size`, MMTk will count the allocated memory into its heap size.
513/// Thus the method requires a reference to an MMTk instance, and the size of the existing memory that will be reallocated.
514/// The `addr` in the arguments must be an address that is earlier returned from MMTk's `malloc()`, `calloc()` or `realloc()`.
515#[cfg(feature = "malloc_counted_size")]
516pub fn realloc_with_old_size<VM: VMBinding>(
517    mmtk: &MMTK<VM>,
518    addr: Address,
519    size: usize,
520    old_size: usize,
521) -> Address {
522    crate::util::malloc::realloc_with_old_size(mmtk, addr, size, old_size)
523}
524
525/// The standard free.
526/// The `addr` in the arguments must be an address that is earlier returned from MMTk's `malloc()`, `calloc()` or `realloc()`.
527pub fn free(addr: Address) {
528    crate::util::malloc::free(addr)
529}
530
531/// The standard free except that with the feature `malloc_counted_size`, MMTk will count the allocated memory into its heap size.
532/// Thus the method requires a reference to an MMTk instance, and the size of the memory to free.
533/// The `addr` in the arguments must be an address that is earlier returned from MMTk's `malloc()`, `calloc()` or `realloc()`.
534#[cfg(feature = "malloc_counted_size")]
535pub fn free_with_size<VM: VMBinding>(mmtk: &MMTK<VM>, addr: Address, old_size: usize) {
536    crate::util::malloc::free_with_size(mmtk, addr, old_size)
537}
538
539/// Get the current active malloc'd bytes. Here MMTk only accounts for bytes that are done through those 'counted malloc' functions.
540#[cfg(feature = "malloc_counted_size")]
541pub fn get_malloc_bytes<VM: VMBinding>(mmtk: &MMTK<VM>) -> usize {
542    use std::sync::atomic::Ordering;
543    mmtk.state.malloc_bytes.load(Ordering::SeqCst)
544}
545
546/// Poll for GC. MMTk will decide if a GC is needed. If so, this call will block
547/// the current thread, and trigger a GC. Otherwise, it will simply return.
548/// Usually a binding does not need to call this function. MMTk will poll for GC during its allocation.
549/// However, if a binding uses counted malloc (which won't poll for GC), they may want to poll for GC manually.
550/// This function should only be used by mutator threads.
551pub fn gc_poll<VM: VMBinding>(mmtk: &MMTK<VM>, tls: VMMutatorThread) {
552    use crate::vm::{ActivePlan, Collection};
553    debug_assert!(
554        VM::VMActivePlan::is_mutator(tls.0),
555        "gc_poll() can only be called by a mutator thread."
556    );
557
558    if mmtk.gc_trigger.poll(false, None) {
559        debug!("Collection required");
560        if !mmtk.state.is_initialized() {
561            panic!("GC is not allowed here: collection is not initialized (did you call initialize_collection()?).");
562        }
563        VM::VMCollection::block_for_gc(tls);
564    }
565}
566
567/// Wrapper for [`crate::scheduler::GCWorker::run`].
568pub fn start_worker<VM: VMBinding>(
569    mmtk: &'static MMTK<VM>,
570    tls: VMWorkerThread,
571    worker: Box<GCWorker<VM>>,
572) {
573    worker.run(tls, mmtk);
574}
575
576/// Wrapper for [`crate::mmtk::MMTK::initialize_collection`].
577pub fn initialize_collection<VM: VMBinding>(mmtk: &'static MMTK<VM>, tls: VMThread) {
578    mmtk.initialize_collection(tls);
579}
580
581/// Wrapper for [`crate::mmtk::MMTK::disable_collection`].
582pub fn disable_collection<VM: VMBinding>(mmtk: &MMTK<VM>) -> Result<bool, GcStatus> {
583    mmtk.disable_collection()
584}
585
586/// Wrapper for [`crate::mmtk::MMTK::enable_collection`].
587pub fn enable_collection<VM: VMBinding>(mmtk: &MMTK<VM>) -> bool {
588    mmtk.enable_collection()
589}
590
591/// Wrapper for [`crate::mmtk::MMTK::is_collection_enabled`].
592pub fn is_collection_enabled<VM: VMBinding>(mmtk: &MMTK<VM>) -> bool {
593    mmtk.is_collection_enabled()
594}
595
596/// Process MMTk run-time options. Returns true if the option is processed successfully.
597///
598/// Arguments:
599/// * `mmtk`: A reference to an MMTk instance.
600/// * `name`: The name of the option.
601/// * `value`: The value of the option (as a string).
602pub fn process(builder: &mut MMTKBuilder, name: &str, value: &str) -> bool {
603    builder.set_option(name, value)
604}
605
606/// Process multiple MMTk run-time options. Returns true if all the options are processed successfully.
607///
608/// Arguments:
609/// * `mmtk`: A reference to an MMTk instance.
610/// * `options`: a string that is key value pairs separated by white spaces, e.g. "threads=1 stress_factor=4096"
611pub fn process_bulk(builder: &mut MMTKBuilder, options: &str) -> bool {
612    builder.set_options_bulk_by_str(options)
613}
614
615/// Return used memory in bytes. MMTk accounts for memory in pages, thus this method always returns a value in
616/// page granularity.
617///
618/// Arguments:
619/// * `mmtk`: A reference to an MMTk instance.
620pub fn used_bytes<VM: VMBinding>(mmtk: &MMTK<VM>) -> usize {
621    mmtk.get_plan().get_used_pages() << LOG_BYTES_IN_PAGE
622}
623
624/// Return free memory in bytes. MMTk accounts for memory in pages, thus this method always returns a value in
625/// page granularity.
626///
627/// Arguments:
628/// * `mmtk`: A reference to an MMTk instance.
629pub fn free_bytes<VM: VMBinding>(mmtk: &MMTK<VM>) -> usize {
630    mmtk.get_plan().get_free_pages() << LOG_BYTES_IN_PAGE
631}
632
633/// Return a hash map for live bytes statistics in the last GC for each space.
634///
635/// MMTk usually accounts for memory in pages by each space.
636/// This is a special method that we count the size of every live object in a GC, and sum up the total bytes.
637/// We provide this method so users can use [`crate::LiveBytesStats`] to know if
638/// the space is fragmented.
639/// The value returned by this method is only updated when we finish tracing in a GC. A recommended timing
640/// to call this method is at the end of a GC (e.g. when the runtime is about to resume threads).
641pub fn live_bytes_in_last_gc<VM: VMBinding>(
642    mmtk: &MMTK<VM>,
643) -> HashMap<&'static str, crate::LiveBytesStats> {
644    mmtk.state.live_bytes_in_last_gc.borrow().clone()
645}
646
647/// Return the starting address of the heap. *Note that currently MMTk uses
648/// a fixed address range as heap.*
649pub fn starting_heap_address() -> Address {
650    vm_layout().heap_start
651}
652
653/// Return the ending address of the heap. *Note that currently MMTk uses
654/// a fixed address range as heap.*
655pub fn last_heap_address() -> Address {
656    vm_layout().heap_end
657}
658
659/// Return the total memory in bytes.
660///
661/// Arguments:
662/// * `mmtk`: A reference to an MMTk instance.
663pub fn total_bytes<VM: VMBinding>(mmtk: &MMTK<VM>) -> usize {
664    mmtk.get_plan().get_total_pages() << LOG_BYTES_IN_PAGE
665}
666
667/// The application code has requested a collection. This is just a GC hint, and
668/// we may ignore it.
669///
670/// Returns whether a GC was ran or not. If MMTk triggers a GC, this method will block the
671/// calling thread and return true when the GC finishes. Otherwise, this method returns
672/// false immediately.
673///
674/// Arguments:
675/// * `mmtk`: A reference to an MMTk instance.
676/// * `tls`: The thread that triggers this collection request.
677pub fn handle_user_collection_request<VM: VMBinding>(
678    mmtk: &MMTK<VM>,
679    tls: VMMutatorThread,
680) -> bool {
681    mmtk.handle_user_collection_request(tls, false, false)
682}
683
684/// Is the object alive?
685///
686/// Arguments:
687/// * `object`: The object reference to query.
688pub fn is_live_object(object: ObjectReference) -> bool {
689    object.is_live()
690}
691
692/// Check if `addr` is the raw address of an object reference to an MMTk object.
693///
694/// Concretely:
695/// 1.  Return `Some(object)` if `ObjectReference::from_raw_address(addr)` is a valid object
696///     reference to an object in any space in MMTk. `object` is the result of
697///     `ObjectReference::from_raw_address(addr)`.
698/// 2.  Return `None` otherwise.
699///
700/// This function is useful for conservative root scanning.  The VM can iterate through all words in
701/// a stack, filter out zeros, misaligned words, obviously out-of-range words (such as addresses
702/// greater than `0x0000_7fff_ffff_ffff` on Linux on x86_64), and use this function to deside if the
703/// word is really a reference.
704///
705/// This function does not handle internal pointers. If a binding may have internal pointers on
706/// the stack, and requires identifying the base reference for an internal pointer, they should use
707/// [`find_object_from_internal_pointer`] instead.
708///
709/// Note: This function has special behaviors if the VM space (enabled by the `vm_space` feature)
710/// is present.  See `crate::plan::global::BasePlan::vm_space`.
711///
712/// Argument:
713/// * `addr`: A non-zero word-aligned address.  Because the raw address of an `ObjectReference`
714///   cannot be zero and must be word-aligned, the caller must filter out zero and misaligned
715///   addresses before calling this function.  Otherwise the behavior is undefined.
716#[cfg(feature = "vo_bit")]
717pub fn is_mmtk_object(addr: Address) -> Option<ObjectReference> {
718    crate::util::is_mmtk_object::check_object_reference(addr)
719}
720
721/// Find if there is an object with VO bit set for the given address range.
722/// This should be used instead of [`crate::memory_manager::is_mmtk_object`] for conservative stack scanning if
723/// the binding may have internal pointers on the stack.
724///
725/// Note that, we only consider pointers that point to addresses that are equal to or greater than
726/// the raw addresss of the object's `ObjectReference`, and within the allocation as 'internal
727/// pointers'. To be precise, for each object ref `obj_ref`, internal pointers are in the range
728/// `[obj_ref.to_raw_address(), obj_ref.to_object_start() +
729/// ObjectModel::get_current_size(obj_ref))`. If a binding defines internal pointers differently,
730/// calling this method is undefined behavior. If this is the case for you, please submit an issue
731/// or engage us on Zulip to discuss more.
732///
733/// Note that, in the similar situation as [`crate::memory_manager::is_mmtk_object`], the binding should filter
734/// out obvious non-pointers (e.g. alignment check, bound check, etc) before calling this function to avoid unnecessary
735/// cost. This method is not cheap.
736///
737/// To minimize the cost, the user should also use a small `max_search_bytes`.
738///
739/// Note: This function has special behaviors if the VM space (enabled by the `vm_space` feature)
740/// is present.  See `crate::plan::global::BasePlan::vm_space`.
741///
742/// Argument:
743/// * `internal_ptr`: The address to start searching. We search backwards from this address (including this address) to find the base reference.
744/// * `max_search_bytes`: The maximum number of bytes we may search for an object with VO bit set. `internal_ptr - max_search_bytes` is not included.
745#[cfg(feature = "vo_bit")]
746pub fn find_object_from_internal_pointer(
747    internal_ptr: Address,
748    max_search_bytes: usize,
749) -> Option<ObjectReference> {
750    crate::util::is_mmtk_object::check_internal_reference(internal_ptr, max_search_bytes)
751}
752
753/// Return true if the `object` lies in a region of memory where
754/// -   only MMTk can allocate into, or
755/// -   only MMTk's delegated memory allocator (such as a malloc implementation) can allocate into
756///     for allocation requests from MMTk.
757///
758/// Return false otherwise.  This function never panics.
759///
760/// Particularly, if this function returns true, `object` cannot be an object allocated by the VM
761/// itself.
762///
763/// If this function returns true, the object cannot be allocate by the `malloc` function called by
764/// the VM, either. In other words, if the `MallocSpace` of MMTk called `malloc` to allocate the
765/// object for the VM in response to `memory_manager::alloc`, this function will return true; but
766/// if the VM directly called `malloc` to allocate the object, this function will return false.
767///
768/// If `is_mmtk_object(object.to_raw_address())` returns true, `is_in_mmtk_spaces(object)` must also
769/// return true.
770///
771/// This function is useful if an object reference in the VM can be either a pointer into the MMTk
772/// heap, or a pointer to non-MMTk objects.  If the VM has a pre-built boot image that contains
773/// primordial objects, or if the VM has its own allocator or uses any third-party allocators, or
774/// if the VM allows an object reference to point to native objects such as C++ objects, this
775/// function can distinguish between MMTk-allocated objects and other objects.
776///
777/// Note: This function has special behaviors if the VM space (enabled by the `vm_space` feature)
778/// is present.  See `crate::plan::global::BasePlan::vm_space`.
779///
780/// Arguments:
781/// * `object`: The object reference to query.
782pub fn is_in_mmtk_spaces(object: ObjectReference) -> bool {
783    use crate::mmtk::SFT_MAP;
784    SFT_MAP
785        .get_checked(object.to_raw_address())
786        .is_in_space(object)
787}
788
789/// Is the address in the mapped memory? The runtime can use this function to check
790/// if an address is mapped by MMTk. Note that this is different than is_in_mmtk_spaces().
791/// For malloc spaces, MMTk does not map those addresses (malloc does the mmap), so
792/// this function will return false, but is_in_mmtk_spaces will return true if the address
793/// is actually a valid object in malloc spaces. To check if an object is in our heap,
794/// the runtime should always use is_in_mmtk_spaces(). This function is_mapped_address()
795/// may get removed at some point.
796///
797/// Arguments:
798/// * `address`: The address to query.
799// TODO: Do we really need this function? Can a runtime always use is_mapped_object()?
800pub fn is_mapped_address(address: Address) -> bool {
801    address.is_mapped()
802}
803
804/// Add a reference to the list of weak references. A binding may
805/// call this either when a weak reference is created, or when a weak reference is traced during GC.
806///
807/// Arguments:
808/// * `mmtk`: A reference to an MMTk instance.
809/// * `reff`: The weak reference to add.
810pub fn add_weak_candidate<VM: VMBinding>(mmtk: &MMTK<VM>, reff: ObjectReference) {
811    mmtk.reference_processors.add_weak_candidate(reff);
812}
813
814/// Add a reference to the list of soft references. A binding may
815/// call this either when a weak reference is created, or when a weak reference is traced during GC.
816///
817/// Arguments:
818/// * `mmtk`: A reference to an MMTk instance.
819/// * `reff`: The soft reference to add.
820pub fn add_soft_candidate<VM: VMBinding>(mmtk: &MMTK<VM>, reff: ObjectReference) {
821    mmtk.reference_processors.add_soft_candidate(reff);
822}
823
824/// Add a reference to the list of phantom references. A binding may
825/// call this either when a weak reference is created, or when a weak reference is traced during GC.
826///
827/// Arguments:
828/// * `mmtk`: A reference to an MMTk instance.
829/// * `reff`: The phantom reference to add.
830pub fn add_phantom_candidate<VM: VMBinding>(mmtk: &MMTK<VM>, reff: ObjectReference) {
831    mmtk.reference_processors.add_phantom_candidate(reff);
832}
833
834/// Generic hook to allow benchmarks to be harnessed. We do a full heap
835/// GC, and then start recording statistics for MMTk.
836///
837/// Arguments:
838/// * `mmtk`: A reference to an MMTk instance.
839/// * `tls`: The thread that calls the function (and triggers a collection).
840pub fn harness_begin<VM: VMBinding>(mmtk: &MMTK<VM>, tls: VMMutatorThread) {
841    mmtk.harness_begin(tls);
842}
843
844/// Generic hook to allow benchmarks to be harnessed. We stop collecting
845/// statistics, and print stats values.
846///
847/// Arguments:
848/// * `mmtk`: A reference to an MMTk instance.
849pub fn harness_end<VM: VMBinding>(mmtk: &'static MMTK<VM>) {
850    mmtk.harness_end();
851}
852
853/// Register a finalizable object. MMTk will retain the liveness of
854/// the object even if it is not reachable from the program.
855/// Note that finalization upon exit is not supported.
856///
857/// Arguments:
858/// * `mmtk`: A reference to an MMTk instance
859/// * `object`: The object that has a finalizer
860pub fn add_finalizer<VM: VMBinding>(
861    mmtk: &'static MMTK<VM>,
862    object: <VM::VMReferenceGlue as ReferenceGlue<VM>>::FinalizableType,
863) {
864    if *mmtk.options.no_finalizer {
865        warn!("add_finalizer() is called when no_finalizer = true");
866    }
867
868    mmtk.finalizable_processor.lock().unwrap().add(object);
869}
870
871/// Pin an object. MMTk will make sure that the object does not move
872/// during GC. Note that action cannot happen in some plans, eg, semispace.
873/// It returns true if the pinning operation has been performed, i.e.,
874/// the object status changed from non-pinned to pinned
875///
876/// Arguments:
877/// * `object`: The object to be pinned
878#[cfg(feature = "object_pinning")]
879pub fn pin_object(object: ObjectReference) -> bool {
880    use crate::mmtk::SFT_MAP;
881    SFT_MAP
882        .get_checked(object.to_raw_address())
883        .pin_object(object)
884}
885
886/// Unpin an object.
887/// Returns true if the unpinning operation has been performed, i.e.,
888/// the object status changed from pinned to non-pinned
889///
890/// Arguments:
891/// * `object`: The object to be pinned
892#[cfg(feature = "object_pinning")]
893pub fn unpin_object(object: ObjectReference) -> bool {
894    use crate::mmtk::SFT_MAP;
895    SFT_MAP
896        .get_checked(object.to_raw_address())
897        .unpin_object(object)
898}
899
900/// Check whether an object is currently pinned
901///
902/// Arguments:
903/// * `object`: The object to be checked
904#[cfg(feature = "object_pinning")]
905pub fn is_pinned(object: ObjectReference) -> bool {
906    use crate::mmtk::SFT_MAP;
907    SFT_MAP
908        .get_checked(object.to_raw_address())
909        .is_object_pinned(object)
910}
911
912/// Get an object that is ready for finalization. After each GC, if any registered object is not
913/// alive, this call will return one of the objects. MMTk will retain the liveness of those objects
914/// until they are popped through this call. Once an object is popped, it is the responsibility of
915/// the VM to make sure they are properly finalized before reclaimed by the GC. This call is non-blocking,
916/// and will return None if no object is ready for finalization.
917///
918/// Arguments:
919/// * `mmtk`: A reference to an MMTk instance.
920pub fn get_finalized_object<VM: VMBinding>(
921    mmtk: &'static MMTK<VM>,
922) -> Option<<VM::VMReferenceGlue as ReferenceGlue<VM>>::FinalizableType> {
923    if *mmtk.options.no_finalizer {
924        warn!("get_finalized_object() is called when no_finalizer = true");
925    }
926
927    mmtk.finalizable_processor
928        .lock()
929        .unwrap()
930        .get_ready_object()
931}
932
933/// Pop all the finalizers that were registered for finalization. The returned objects may or may not be ready for
934/// finalization. After this call, MMTk's finalizer processor should have no registered finalizer any more.
935///
936/// This is useful for some VMs which require all finalizable objects to be finalized on exit.
937///
938/// Arguments:
939/// * `mmtk`: A reference to an MMTk instance.
940pub fn get_all_finalizers<VM: VMBinding>(
941    mmtk: &'static MMTK<VM>,
942) -> Vec<<VM::VMReferenceGlue as ReferenceGlue<VM>>::FinalizableType> {
943    if *mmtk.options.no_finalizer {
944        warn!("get_all_finalizers() is called when no_finalizer = true");
945    }
946
947    mmtk.finalizable_processor
948        .lock()
949        .unwrap()
950        .get_all_finalizers()
951}
952
953/// Pop finalizers that were registered and associated with a certain object. The returned objects may or may not be ready for finalization.
954/// This is useful for some VMs that may manually execute finalize method for an object.
955///
956/// Arguments:
957/// * `mmtk`: A reference to an MMTk instance.
958/// * `object`: the given object that MMTk will pop its finalizers
959pub fn get_finalizers_for<VM: VMBinding>(
960    mmtk: &'static MMTK<VM>,
961    object: ObjectReference,
962) -> Vec<<VM::VMReferenceGlue as ReferenceGlue<VM>>::FinalizableType> {
963    if *mmtk.options.no_finalizer {
964        warn!("get_finalizers() is called when no_finalizer = true");
965    }
966
967    mmtk.finalizable_processor
968        .lock()
969        .unwrap()
970        .get_finalizers_for(object)
971}
972
973/// Get the number of workers. MMTk spawns worker threads for the 'threads' defined in the options.
974/// So the number of workers is derived from the threads option. Note the feature single_worker overwrites
975/// the threads option, and force one worker thread.
976///
977/// Arguments:
978/// * `mmtk`: A reference to an MMTk instance.
979pub fn num_of_workers<VM: VMBinding>(mmtk: &'static MMTK<VM>) -> usize {
980    mmtk.scheduler.num_workers()
981}
982
983/// Add a work packet to the given work bucket. Note that this simply adds the work packet to the given
984/// work bucket, and the scheduler will decide when to execute the work packet.
985///
986/// Arguments:
987/// * `mmtk`: A reference to an MMTk instance.
988/// * `bucket`: Which work bucket to add this packet to.
989/// * `packet`: The work packet to be added.
990pub fn add_work_packet<VM: VMBinding, W: GCWork<VM>>(
991    mmtk: &'static MMTK<VM>,
992    bucket: WorkBucketStage,
993    packet: W,
994) {
995    mmtk.scheduler.work_buckets[bucket].add(packet)
996}
997
998/// Bulk add a number of work packets to the given work bucket. Note that this simply adds the work packets
999/// to the given work bucket, and the scheduler will decide when to execute the work packets.
1000///
1001/// Arguments:
1002/// * `mmtk`: A reference to an MMTk instance.
1003/// * `bucket`: Which work bucket to add these packets to.
1004/// * `packet`: The work packets to be added.
1005pub fn add_work_packets<VM: VMBinding>(
1006    mmtk: &'static MMTK<VM>,
1007    bucket: WorkBucketStage,
1008    packets: Vec<Box<dyn GCWork<VM>>>,
1009) {
1010    mmtk.scheduler.work_buckets[bucket].bulk_add(packets)
1011}