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