mmtk/util/
address.rs

1use atomic_traits::Atomic;
2use bytemuck::NoUninit;
3
4use std::fmt;
5use std::mem;
6use std::num::NonZeroUsize;
7use std::ops::*;
8use std::sync::atomic::Ordering;
9
10use crate::mmtk::{MMAPPER, SFT_MAP};
11use crate::util::metadata::log_bit::LOGGED_VALUE;
12use crate::util::VMThread;
13use crate::util::VMWorkerThread;
14use crate::vm::ObjectModel;
15
16/// size in bytes
17pub type ByteSize = usize;
18/// offset in byte
19pub type ByteOffset = isize;
20
21/// Address represents an arbitrary address. This is designed to represent
22/// address and do address arithmetic mostly in a safe way, and to allow
23/// mark some operations as unsafe. This type needs to be zero overhead
24/// (memory wise and time wise). The idea is from the paper
25/// High-level Low-level Programming (VEE09) and JikesRVM.
26#[repr(transparent)]
27#[derive(Copy, Clone, Eq, Hash, PartialOrd, Ord, PartialEq, NoUninit)]
28pub struct Address(usize);
29
30/// Address + ByteSize (positive)
31impl Add<ByteSize> for Address {
32    type Output = Address;
33    fn add(self, offset: ByteSize) -> Address {
34        Address(self.0 + offset)
35    }
36}
37
38/// Address += ByteSize (positive)
39impl AddAssign<ByteSize> for Address {
40    fn add_assign(&mut self, offset: ByteSize) {
41        self.0 += offset;
42    }
43}
44
45/// Address + ByteOffset (positive or negative)
46impl Add<ByteOffset> for Address {
47    type Output = Address;
48    fn add(self, offset: ByteOffset) -> Address {
49        Address((self.0 as isize + offset) as usize)
50    }
51}
52
53/// Address += ByteOffset (positive or negative)
54impl AddAssign<ByteOffset> for Address {
55    fn add_assign(&mut self, offset: ByteOffset) {
56        self.0 = (self.0 as isize + offset) as usize
57    }
58}
59
60/// Address - ByteSize (positive)
61impl Sub<ByteSize> for Address {
62    type Output = Address;
63    fn sub(self, offset: ByteSize) -> Address {
64        Address(self.0 - offset)
65    }
66}
67
68/// Address -= ByteSize (positive)
69impl SubAssign<ByteSize> for Address {
70    fn sub_assign(&mut self, offset: ByteSize) {
71        self.0 -= offset;
72    }
73}
74
75/// Address - Address (the first address must be higher)
76impl Sub<Address> for Address {
77    type Output = ByteSize;
78    fn sub(self, other: Address) -> ByteSize {
79        debug_assert!(
80            self.0 >= other.0,
81            "for (addr_a - addr_b), a({}) needs to be larger than b({})",
82            self,
83            other
84        );
85        self.0 - other.0
86    }
87}
88
89/// Address & mask
90impl BitAnd<usize> for Address {
91    type Output = usize;
92    fn bitand(self, other: usize) -> usize {
93        self.0 & other
94    }
95}
96// Be careful about the return type here. Address & u8 = u8
97// This is different from Address | u8 = usize
98impl BitAnd<u8> for Address {
99    type Output = u8;
100    fn bitand(self, other: u8) -> u8 {
101        (self.0 as u8) & other
102    }
103}
104
105/// Address | mask
106impl BitOr<usize> for Address {
107    type Output = usize;
108    fn bitor(self, other: usize) -> usize {
109        self.0 | other
110    }
111}
112// Be careful about the return type here. Address | u8 = size
113// This is different from Address & u8 = u8
114impl BitOr<u8> for Address {
115    type Output = usize;
116    fn bitor(self, other: u8) -> usize {
117        self.0 | (other as usize)
118    }
119}
120
121/// Address >> shift (get an index)
122impl Shr<usize> for Address {
123    type Output = usize;
124    fn shr(self, shift: usize) -> usize {
125        self.0 >> shift
126    }
127}
128
129/// Address << shift (get an index)
130impl Shl<usize> for Address {
131    type Output = usize;
132    fn shl(self, shift: usize) -> usize {
133        self.0 << shift
134    }
135}
136
137impl Address {
138    /// The lowest possible address.
139    pub const ZERO: Self = Address(0);
140    /// The highest possible address.
141    pub const MAX: Self = Address(usize::MAX);
142
143    /// creates Address from a pointer
144    pub fn from_ptr<T>(ptr: *const T) -> Address {
145        Address(ptr as usize)
146    }
147
148    /// creates Address from a Rust reference
149    pub fn from_ref<T>(r: &T) -> Address {
150        Address(r as *const T as usize)
151    }
152
153    /// creates Address from a mutable pointer
154    pub fn from_mut_ptr<T>(ptr: *mut T) -> Address {
155        Address(ptr as usize)
156    }
157
158    /// creates a null Address (0)
159    /// # Safety
160    /// It is unsafe and the user needs to be aware that they are creating an invalid address.
161    /// The zero address should only be used as unininitialized or sentinel values in performance critical code (where you dont want to use `Option<Address>`).
162    pub const unsafe fn zero() -> Address {
163        Address(0)
164    }
165
166    /// creates an Address of (usize::MAX)
167    /// # Safety
168    /// It is unsafe and the user needs to be aware that they are creating an invalid address.
169    /// The max address should only be used as unininitialized or sentinel values in performance critical code (where you dont want to use `Option<Address>`).
170    pub unsafe fn max() -> Address {
171        Address(usize::MAX)
172    }
173
174    /// creates an arbitrary Address
175    /// # Safety
176    /// It is unsafe and the user needs to be aware that they may create an invalid address.
177    /// This creates arbitrary addresses which may not be valid. This should only be used for hard-coded addresses. Any other uses of this function could be
178    /// replaced with more proper alternatives.
179    pub const unsafe fn from_usize(raw: usize) -> Address {
180        Address(raw)
181    }
182
183    /// shifts the address by N T-typed objects (returns addr + N * size_of(T))
184    pub fn shift<T>(self, offset: isize) -> Self {
185        self + mem::size_of::<T>() as isize * offset
186    }
187
188    // These const functions are duplicated with the operator traits. But we need them,
189    // as we need them to declare constants.
190
191    /// Get the number of bytes between two addresses. The current address needs to be higher than the other address.
192    pub const fn get_extent(self, other: Address) -> ByteSize {
193        self.0 - other.0
194    }
195
196    /// Get the offset from `other` to `self`. The result is negative is `self` is lower than `other`.
197    pub const fn get_offset(self, other: Address) -> ByteOffset {
198        self.0 as isize - other.0 as isize
199    }
200
201    // We implemented the Add trait but we still keep this add function.
202    // The add() function is const fn, and we can use it to declare Address constants.
203    // The Add trait function cannot be const.
204    #[allow(clippy::should_implement_trait)]
205    /// Add an offset to the address.
206    pub const fn add(self, size: usize) -> Address {
207        Address(self.0 + size)
208    }
209
210    /// Wrapping (modular) addition. Computes self + rhs, wrapping around at the boundary of the type.
211    pub const fn wrapping_add(self, size: usize) -> Address {
212        Address(self.0.wrapping_add(size))
213    }
214
215    // We implemented the Sub trait but we still keep this sub function.
216    // The sub() function is const fn, and we can use it to declare Address constants.
217    // The Sub trait function cannot be const.
218    #[allow(clippy::should_implement_trait)]
219    /// Subtract an offset from the address.
220    pub const fn sub(self, size: usize) -> Address {
221        Address(self.0 - size)
222    }
223
224    /// Apply an signed offset to the address.
225    pub const fn offset(self, offset: isize) -> Address {
226        Address(self.0.wrapping_add_signed(offset))
227    }
228
229    /// Bitwise 'and' with a mask.
230    pub const fn and(self, mask: usize) -> usize {
231        self.0 & mask
232    }
233
234    /// Perform a saturating subtract on the Address
235    pub const fn saturating_sub(self, size: usize) -> Address {
236        Address(self.0.saturating_sub(size))
237    }
238
239    /// loads a value of type T from the address
240    /// # Safety
241    /// This could throw a segment fault if the address is invalid
242    pub unsafe fn load<T: Copy>(self) -> T {
243        *(self.0 as *mut T)
244    }
245
246    /// stores a value of type T to the address
247    /// # Safety
248    /// This could throw a segment fault if the address is invalid
249    pub unsafe fn store<T>(self, value: T) {
250        // We use a ptr.write() operation as directly setting the pointer would drop the old value
251        // which may result in unexpected behaviour
252        (self.0 as *mut T).write(value);
253    }
254
255    /// atomic operation: load
256    /// # Safety
257    /// This could throw a segment fault if the address is invalid
258    pub unsafe fn atomic_load<T: Atomic>(self, order: Ordering) -> T::Type {
259        let loc = &*(self.0 as *const T);
260        loc.load(order)
261    }
262
263    /// atomic operation: store
264    /// # Safety
265    /// This could throw a segment fault if the address is invalid
266    pub unsafe fn atomic_store<T: Atomic>(self, val: T::Type, order: Ordering) {
267        let loc = &*(self.0 as *const T);
268        loc.store(val, order)
269    }
270
271    /// atomic operation: compare and exchange usize
272    /// # Safety
273    /// This could throw a segment fault if the address is invalid
274    pub unsafe fn compare_exchange<T: Atomic>(
275        self,
276        old: T::Type,
277        new: T::Type,
278        success: Ordering,
279        failure: Ordering,
280    ) -> Result<T::Type, T::Type> {
281        let loc = &*(self.0 as *const T);
282        loc.compare_exchange(old, new, success, failure)
283    }
284
285    /// is this address zero?
286    pub fn is_zero(self) -> bool {
287        self.0 == 0
288    }
289
290    /// aligns up the address to the given alignment
291    pub const fn align_up(self, align: ByteSize) -> Address {
292        use crate::util::conversions;
293        Address(conversions::raw_align_up(self.0, align))
294    }
295
296    /// aligns down the address to the given alignment
297    pub const fn align_down(self, align: ByteSize) -> Address {
298        use crate::util::conversions;
299        Address(conversions::raw_align_down(self.0, align))
300    }
301
302    /// is this address aligned to the given alignment
303    pub const fn is_aligned_to(self, align: usize) -> bool {
304        use crate::util::conversions;
305        conversions::raw_is_aligned(self.0, align)
306    }
307
308    /// converts the Address to a pointer
309    pub fn to_ptr<T>(self) -> *const T {
310        self.0 as *const T
311    }
312
313    /// converts the Address to a mutable pointer
314    pub fn to_mut_ptr<T>(self) -> *mut T {
315        self.0 as *mut T
316    }
317
318    /// converts the Address to a Rust reference
319    ///
320    /// # Safety
321    /// The caller must guarantee the address actually points to a Rust object.
322    pub unsafe fn as_ref<'a, T>(self) -> &'a T {
323        &*self.to_mut_ptr()
324    }
325
326    /// converts the Address to a mutable Rust reference
327    ///
328    /// # Safety
329    /// The caller must guarantee the address actually points to a Rust object.
330    pub unsafe fn as_mut_ref<'a, T>(self) -> &'a mut T {
331        &mut *self.to_mut_ptr()
332    }
333
334    /// converts the Address to a pointer-sized integer
335    pub const fn as_usize(self) -> usize {
336        self.0
337    }
338
339    /// returns the chunk index for this address
340    pub fn chunk_index(self) -> usize {
341        use crate::util::conversions;
342        conversions::address_to_chunk_index(self)
343    }
344
345    /// return true if the referenced memory is mapped
346    pub fn is_mapped(self) -> bool {
347        if self.0 == 0 {
348            false
349        } else {
350            MMAPPER.is_mapped_address(self)
351        }
352    }
353
354    /// Check whether the field at this address is logged, i.e. whether the field-level write
355    /// barrier has already recorded a write to it and can skip its slow path.
356    pub fn is_field_logged<VM: VMBinding>(self) -> bool {
357        debug_assert!(!self.is_zero());
358        unsafe {
359            VM::VMObjectModel::GLOBAL_FIELD_UNLOG_BIT_SPEC
360                .as_spec()
361                .extract_side_spec()
362                .load::<u8>(self)
363                == LOGGED_VALUE
364        }
365    }
366
367    /// Mark the field(s) covered by this address as unlogged (using a relaxed, non-atomic store),
368    /// so that a subsequent write to them will be caught by the field-level write barrier's slow path again.
369    pub fn unlog_field_relaxed<VM: VMBinding>(self) {
370        debug_assert!(!self.is_zero());
371        let heap_bytes_per_unlog_byte =
372            VM::VMObjectModel::GLOBAL_FIELD_UNLOG_BIT_SPEC.heap_bytes_per_unlog_byte();
373        let a = self.align_down(heap_bytes_per_unlog_byte);
374        unsafe {
375            VM::VMObjectModel::GLOBAL_FIELD_UNLOG_BIT_SPEC
376                .as_spec()
377                .extract_side_spec()
378                .store_byte_relaxed(a, 0xffu8)
379        }
380    }
381
382    /// Returns the intersection of the two address ranges. The returned range could
383    /// be empty if there is no intersection between the ranges.
384    pub fn range_intersection(r1: &Range<Address>, r2: &Range<Address>) -> Range<Address> {
385        r1.start.max(r2.start)..r1.end.min(r2.end)
386    }
387}
388
389/// allows print Address as upper-case hex value
390impl fmt::UpperHex for Address {
391    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
392        write!(f, "{:X}", self.0)
393    }
394}
395
396/// allows print Address as lower-case hex value
397impl fmt::LowerHex for Address {
398    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
399        write!(f, "{:x}", self.0)
400    }
401}
402
403/// allows Display format the Address (as upper-case hex value with 0x prefix)
404impl fmt::Display for Address {
405    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
406        write!(f, "{:#x}", self.0)
407    }
408}
409
410/// allows Debug format the Address (as upper-case hex value with 0x prefix)
411impl fmt::Debug for Address {
412    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
413        write!(f, "{:#x}", self.0)
414    }
415}
416
417impl std::str::FromStr for Address {
418    type Err = std::num::ParseIntError;
419
420    fn from_str(s: &str) -> Result<Self, Self::Err> {
421        let raw: usize = s.parse()?;
422        Ok(Address(raw))
423    }
424}
425
426#[cfg(test)]
427mod tests {
428    use crate::util::Address;
429
430    #[test]
431    fn align_up() {
432        unsafe {
433            assert_eq!(
434                Address::from_usize(0x10).align_up(0x10),
435                Address::from_usize(0x10)
436            );
437            assert_eq!(
438                Address::from_usize(0x11).align_up(0x10),
439                Address::from_usize(0x20)
440            );
441            assert_eq!(
442                Address::from_usize(0x20).align_up(0x10),
443                Address::from_usize(0x20)
444            );
445        }
446    }
447
448    #[test]
449    fn align_down() {
450        unsafe {
451            assert_eq!(
452                Address::from_usize(0x10).align_down(0x10),
453                Address::from_usize(0x10)
454            );
455            assert_eq!(
456                Address::from_usize(0x11).align_down(0x10),
457                Address::from_usize(0x10)
458            );
459            assert_eq!(
460                Address::from_usize(0x20).align_down(0x10),
461                Address::from_usize(0x20)
462            );
463        }
464    }
465
466    #[test]
467    fn is_aligned_to() {
468        unsafe {
469            assert!(Address::from_usize(0x10).is_aligned_to(0x10));
470            assert!(!Address::from_usize(0x11).is_aligned_to(0x10));
471            assert!(Address::from_usize(0x10).is_aligned_to(0x8));
472            assert!(!Address::from_usize(0x10).is_aligned_to(0x20));
473        }
474    }
475
476    #[test]
477    fn bit_and() {
478        unsafe {
479            assert_eq!(
480                Address::from_usize(0b1111_1111_1100usize) & 0b1010u8,
481                0b1000u8
482            );
483            assert_eq!(
484                Address::from_usize(0b1111_1111_1100usize) & 0b1000_0000_1010usize,
485                0b1000_0000_1000usize
486            );
487        }
488    }
489
490    #[test]
491    fn bit_or() {
492        unsafe {
493            assert_eq!(
494                Address::from_usize(0b1111_1111_1100usize) | 0b1010u8,
495                0b1111_1111_1110usize
496            );
497            assert_eq!(
498                Address::from_usize(0b1111_1111_1100usize) | 0b1000_0000_1010usize,
499                0b1111_1111_1110usize
500            );
501        }
502    }
503}
504
505use crate::vm::Scanning;
506use crate::vm::VMBinding;
507
508/// `ObjectReference` represents address for an object. Compared with `Address`, operations allowed
509/// on `ObjectReference` are very limited. No address arithmetics are allowed for `ObjectReference`.
510/// The idea is from the paper [Demystifying Magic: High-level Low-level Programming (VEE09)][FBC09]
511/// and [JikesRVM].
512///
513/// In MMTk, `ObjectReference` holds a non-zero address, i.e. its **raw address**.  It must satisfy
514/// the following requirements.
515///
516/// -   It uniquely references an MMTk object.
517/// -   The address must be within the address range of the object it refers to.
518/// -   The address must be word-aligned.
519/// -   It must be efficient to access object metadata from an `ObjectReference`.
520///
521/// Each `ObjectReference` uniquely identifies exactly one MMTk object.  There is no "null
522/// reference" (see below for details).
523///
524/// Conversely, each object has a unique (raw) address used for `ObjectReference`.  That address is
525/// nominated by the VM binding right after an object is allocated in the MMTk heap (i.e. the
526/// argument of [`crate::memory_manager::post_alloc`]).  The same address is used by all
527/// `ObjectReference` instances that refer to that object until the object is moved, at which time
528/// the VM binding shall choose another address to use as the `ObjectReference` of the new copy (in
529/// [`crate::vm::ObjectModel::copy`] or [`crate::vm::ObjectModel::get_reference_when_copied_to`])
530/// until the object is moved again.
531///
532/// In addition to the raw address, there are also two addresses related to each object allocated in
533/// MMTk heap, namely **starting address** and **header address**.  See the
534/// [`crate::vm::ObjectModel`] trait for their precise definition.
535///
536/// The VM binding may, in theory, pick any aligned address within the object, and it doesn't have
537/// to be the starting address.  However, during tracing, MMTk will need to access object metadata
538/// from a `ObjectReference`.  Particularly, it needs to identify reference fields, and query
539/// information about the object, such as object size.  Such information is usually accessed from
540/// object headers.  The choice of `ObjectReference` must make such accesses efficient.
541///
542/// Because the raw address is within the object, MMTk will also use the raw address to identify the
543/// space or region (chunk, block, line, etc.) that contains the object, and to access side metadata
544/// and the SFTMap.  If a VM binding needs to access side metadata directly (particularly, setting
545/// the "valid-object (VO) bit" in allocation fast paths), it shall use the raw address to compute
546/// the byte and bit address of the metadata bits.
547///
548/// # Notes
549///
550/// ## About VMs own concepts of "object references"
551///
552/// A runtime may define its own concept of "object references" differently from MMTk's
553/// `ObjectReference` type.  It may define its object reference as
554///
555/// -   the starting address of an object,
556/// -   an address inside an object,
557/// -   an address at a certain offset outside an object,
558/// -   a handle that points to an indirection table entry where a pointer to the object is held, or
559/// -   anything else that refers to an object.
560///
561/// Regardless, when passing an `ObjectReference` value to MMTk through the API, MMTk expectes its
562/// value to satisfy MMTk's definition.  This means MMTk's `ObjectReference` may not be the value
563/// held in an object field.  Some VM bindings may need to do conversions when passing object
564/// references to MMTk.  For example, adding an offset to the VM-level object reference so that the
565/// resulting address is within the object.  When using handles, the VM binding may use the *pointer
566/// stored in the entry* of the indirection table instead of the *pointer to the entry* itself as
567/// MMTk-level `ObjectReference`.
568///
569/// ## About null references
570///
571/// An [`ObjectReference`] always refers to an object.  Some VMs have special values (such as `null`
572/// in Java) that do not refer to any object.  Those values cannot be represented by
573/// `ObjectReference`.  When scanning roots and object fields, the VM binding should ignore slots
574/// that do not hold a reference to an object.  Specifically, [`crate::vm::slot::Slot::load`]
575/// returns `Option<ObjectReference>`.  It can return `None` so that MMTk skips that slot.
576///
577/// `Option<ObjectReference>` should be used for the cases where a non-null object reference may or
578/// may not exist,  That includes several API functions, including [`crate::vm::slot::Slot::load`].
579/// [`ObjectReference`] is backed by `NonZeroUsize` which cannot be zero, and it has the
580/// `#[repr(transparent)]` attribute. Thanks to [null pointer optimization (NPO)][NPO],
581/// `Option<ObjectReference>` has the same size as `NonZeroUsize` and `usize`.
582///
583/// For the convenience of passing `Option<ObjectReference>` to and from native (C/C++) programs,
584/// mmtk-core provides [`crate::util::api_util::NullableObjectReference`].
585///
586/// ## About the `VMSpace`
587///
588/// The `VMSpace` is managed by the VM binding.  The VM binding declare ranges of memory as part of
589/// the `VMSpace`, but MMTk never allocates into it.  The VM binding allocates objects into the
590/// `VMSpace` (usually by mapping boot-images), and refers to objects in the `VMSpace` using
591/// `ObjectReference`s whose raw addresses point inside those objects (and must be word-aligned,
592/// too).  MMTk will access metadata using methods of [`ObjectModel`] like other objects.  MMTk also
593/// has side metadata available for objects in the `VMSpace`.
594///
595/// ## About `ObjectReference` pointing outside MMTk spaces
596///
597/// If a VM binding implements [`crate::vm::ActivePlan::vm_trace_object`], `ObjectReference` is
598/// allowed to point to locations outside any MMTk spaces.  When tracing objects, such
599/// `ObjectReference` values will be processed by `ActivePlan::vm_trace_object` so that the VM
600/// binding can trace its own allocated objects during GC.  However, **this is an experimental
601/// feature**, and may not interact well with other parts of MMTk.  Notably, MMTk will not allocate
602/// side metadata for such `ObjectReference`, and attempts to access side metadata with a non-MMTk
603/// `ObjectReference` will result in crash. Use with caution.
604///
605/// [FBC09]: https://dl.acm.org/doi/10.1145/1508293.1508305
606/// [JikesRVM]: https://www.jikesrvm.org/
607/// [`ObjectModel`]: crate::vm::ObjectModel
608/// [NPO]: https://doc.rust-lang.org/std/option/index.html#representation
609#[repr(transparent)]
610#[derive(Copy, Clone, Eq, Hash, PartialOrd, Ord, PartialEq, NoUninit)]
611pub struct ObjectReference(NonZeroUsize);
612
613impl ObjectReference {
614    /// The required minimal alignment for object reference. If the object reference's raw address is not aligned to this value,
615    /// you will see an assertion failure in the debug build when constructing an object reference instance.
616    pub const ALIGNMENT: usize = crate::util::constants::BYTES_IN_ADDRESS;
617
618    /// Cast the object reference to its raw address.
619    pub fn to_raw_address(self) -> Address {
620        Address(self.0.get())
621    }
622
623    /// Cast a raw address to an object reference.
624    ///
625    /// If `addr` is 0, the result is `None`.
626    pub fn from_raw_address(addr: Address) -> Option<ObjectReference> {
627        debug_assert!(
628            addr.is_aligned_to(Self::ALIGNMENT),
629            "ObjectReference is required to be word aligned.  addr: {addr}"
630        );
631        NonZeroUsize::new(addr.0).map(ObjectReference)
632    }
633
634    /// Like `from_raw_address`, but assume `addr` is not zero.  This can be used to elide a check
635    /// against zero for performance-critical code.
636    ///
637    /// # Safety
638    ///
639    /// This method assumes `addr` is not zero.  It should only be used in cases where we know at
640    /// compile time that the input cannot be zero.  For example, if we compute the address by
641    /// adding a positive offset to a non-zero address, we know the result must not be zero.
642    pub unsafe fn from_raw_address_unchecked(addr: Address) -> ObjectReference {
643        debug_assert!(!addr.is_zero());
644        debug_assert!(
645            addr.is_aligned_to(Self::ALIGNMENT),
646            "ObjectReference is required to be word aligned.  addr: {addr}"
647        );
648        ObjectReference(NonZeroUsize::new_unchecked(addr.0))
649    }
650
651    /// Get the header base address from an object reference. This method is used by MMTk to get a base address for the
652    /// object header, and access the object header. This method is syntactic sugar for [`crate::vm::ObjectModel::ref_to_header`].
653    /// See the comments on [`crate::vm::ObjectModel::ref_to_header`].
654    pub fn to_header<VM: VMBinding>(self) -> Address {
655        use crate::vm::ObjectModel;
656        VM::VMObjectModel::ref_to_header(self)
657    }
658
659    /// Get the start of the allocation address for the object. This method is used by MMTk to get the start of the allocation
660    /// address originally returned from [`crate::memory_manager::alloc`] for the object.
661    /// This method is syntactic sugar for [`crate::vm::ObjectModel::ref_to_object_start`]. See comments on [`crate::vm::ObjectModel::ref_to_object_start`].
662    pub fn to_object_start<VM: VMBinding>(self) -> Address {
663        use crate::vm::ObjectModel;
664        let object_start = VM::VMObjectModel::ref_to_object_start(self);
665        debug_assert!(!VM::VMObjectModel::UNIFIED_OBJECT_REFERENCE_ADDRESS || object_start == self.to_raw_address(), "The binding claims unified object reference address, but for object reference {}, ref_to_object_start() returns {}", self, object_start);
666        debug_assert!(
667            self.to_raw_address()
668                >= object_start + VM::VMObjectModel::OBJECT_REF_OFFSET_LOWER_BOUND,
669            "The invariant `object_ref >= object_start + OBJECT_REF_OFFSET_LOWER_BOUND` is violated. \
670            object_ref: {}, object_start: {}, OBJECT_REF_OFFSET_LOWER_BOUND: {}",
671            self.to_raw_address(),
672            object_start,
673            VM::VMObjectModel::OBJECT_REF_OFFSET_LOWER_BOUND,
674        );
675        object_start
676    }
677
678    /// Is the object reachable, determined by the policy?
679    ///
680    /// # Scope
681    ///
682    /// This method is primarily used during weak reference processing.  It can check if an object
683    /// (particularly finalizable objects and objects pointed by weak references) has been reached
684    /// by following strong references or weak references of higher strength.
685    ///
686    /// This method can also be used during tracing for debug purposes.
687    ///
688    /// When called at other times, particularly during mutator time, the behavior is specific to
689    /// the implementation of the plan and policy due to their strategies of metadata clean-up.  If
690    /// the VM needs to know if any given reference is still valid, it should instead use the valid
691    /// object bit (VO-bit) metadata which is enabled by the Cargo feature "vo_bit".
692    ///
693    /// # Return value
694    ///
695    /// It returns `true` if one of the following is true:
696    ///
697    /// 1.  The object has been traced (i.e. reached) since tracing started.
698    /// 2.  The policy conservatively considers the object reachable even though it has not been
699    ///     traced.
700    ///     -   Particularly, if the plan is generational, this method will return `true` if the
701    ///         object is mature during nursery GC.
702    ///
703    /// Due to the conservativeness, if this method returns `true`, it does not necessarily mean the
704    /// object must be reachable from roots.  In generational GC, mature objects can be unreachable
705    /// from roots while the GC chooses not to reclaim their memory during nursery GC. Conversely,
706    /// all young objects reachable from the remembered set are retained even though some mature
707    /// objects in the remembered set can be unreachable in the first place.  (This is known as
708    /// *nepotism* in GC literature.)
709    ///
710    /// Note: Objects in ImmortalSpace may have `is_live = true` but are actually unreachable.
711    pub fn is_reachable(self) -> bool {
712        unsafe { SFT_MAP.get_unchecked(self.to_raw_address()) }.is_reachable(self)
713    }
714
715    /// Is the object live, determined by the policy?
716    pub fn is_live(self) -> bool {
717        unsafe { SFT_MAP.get_unchecked(self.to_raw_address()) }.is_live(self)
718    }
719
720    /// Can the object be moved?
721    pub fn is_movable(self) -> bool {
722        unsafe { SFT_MAP.get_unchecked(self.to_raw_address()) }.is_movable()
723    }
724
725    /// Get forwarding pointer if the object is forwarded.
726    pub fn get_forwarded_object(self) -> Option<Self> {
727        unsafe { SFT_MAP.get_unchecked(self.to_raw_address()) }.get_forwarded_object(self)
728    }
729
730    /// Is the object in any MMTk spaces?
731    pub fn is_in_any_space(self) -> bool {
732        unsafe { SFT_MAP.get_unchecked(self.to_raw_address()) }.is_in_space(self)
733    }
734
735    /// Is the object sane?
736    #[cfg(feature = "sanity")]
737    pub fn is_sane(self) -> bool {
738        unsafe { SFT_MAP.get_unchecked(self.to_raw_address()) }.is_sane()
739    }
740
741    /// Get the current size (in bytes) of the object, as determined by the VM's object model.
742    pub fn get_size<VM: VMBinding>(self) -> usize {
743        VM::VMObjectModel::get_current_size(self)
744    }
745
746    /// Iterate over the slots (fields) of the object, calling `f` for each slot the VM's scanning
747    /// implementation reports for this object.
748    pub fn iterate_fields<VM: VMBinding, F: FnMut(VM::VMSlot)>(self, _tls: VMThread, mut f: F) {
749        // FIXME: We should use tls from the arguments.
750        // See https://github.com/mmtk/mmtk-core/issues/1375
751        let fake_tls = VMWorkerThread(VMThread::UNINITIALIZED);
752        if !<VM::VMScanning as Scanning<VM>>::support_slot_enqueuing(fake_tls, self) {
753            panic!("SlotIterator::iterate_fields cannot be used on objects that don't support slot-enqueuing");
754        }
755        <VM::VMScanning as Scanning<VM>>::scan_object(fake_tls, self, &mut f);
756    }
757}
758
759/// allows print Address as upper-case hex value
760impl fmt::UpperHex for ObjectReference {
761    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
762        write!(f, "{:X}", self.0)
763    }
764}
765
766/// allows print Address as lower-case hex value
767impl fmt::LowerHex for ObjectReference {
768    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
769        write!(f, "{:x}", self.0)
770    }
771}
772
773/// allows Display format the Address (as upper-case hex value with 0x prefix)
774impl fmt::Display for ObjectReference {
775    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
776        write!(f, "{:#x}", self.0)
777    }
778}
779
780/// allows Debug format the Address (as upper-case hex value with 0x prefix)
781impl fmt::Debug for ObjectReference {
782    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
783        write!(f, "{:#x}", self.0)
784    }
785}