comet/
header.rs

1use crate::internal::gc_info::GCInfoIndex;
2use modular_bitfield::prelude::*;
3use std::mem::size_of;
4
5/// HeapObjectHeader contains meta data per object and is prepended to each
6/// object.
7///```
8/// +-----------------+------+------------------------------------------+
9/// | name            | bits |                                          |
10/// +-----------------+------+------------------------------------------+
11/// | padding         |   32 | Only present on 64-bit platform.         |
12/// +-----------------+------+------------------------------------------+
13/// | GCInfoIndex     |   14 |                                          |
14/// | unused          |    1 |                                          |
15/// | unused          |    1 | In construction encoded as |false|.      |
16/// +-----------------+------+------------------------------------------+
17/// | size            |   13 | 17 bits because allocations are aligned. |
18/// | unused          |    1 |                                          |
19/// | cell state      |    2 |                                          |
20/// +-----------------+------+------------------------------------------+
21///```
22/// Notes:
23/// - See [GCInfoTable](crate::gc_info_table::GCInfoTable) for constraints on GCInfoIndex.
24/// - `size` for regular objects is encoded with 14 bits but can actually
25///   represent sizes up to |kBlinkPageSize| (2^17) because allocations are
26///   always 8 byte aligned (see kAllocationGranularity).
27/// - `size` for large objects is encoded as 0. The size of a large object is
28///   stored in [PreciseAllocation::cell_size](crate::large_space::PreciseAllocation::cell_size).
29#[derive(Clone, Copy)]
30#[repr(C)]
31pub struct HeapObjectHeader {
32    #[cfg(target_pointer_width = "64")]
33    _padding: u32,
34    encoded_high: EncodedHigh,
35    encoded_low: u16,
36}
37
38pub const ALLOCATION_GRANULARITY: usize = size_of::<usize>();
39
40impl HeapObjectHeader {
41    /// Check if allocation is "precise". Precise allocations are large allocations that have larger header stored behind `HeapObjectHeader`. 
42    pub fn is_precise(&self) -> bool {
43        self.get_size() == 0
44    }
45    /// Set this header as free. 
46    pub fn set_free(&mut self) {
47        self.encoded_low = 0;
48    }
49    /// Creates heap object header from object pointer. It must be valid pointer. 
50    #[inline(always)]
51    pub unsafe fn from_object(obj: *const u8) -> *mut Self {
52        (obj as usize - size_of::<Self>()) as _
53    }
54    /// Returns payload of this heap object header. 
55    #[inline(always)]
56    pub fn payload(&self) -> *const u8 {
57        (self as *const Self as usize + size_of::<Self>()) as _
58    }
59    /// Returns [GCInfoIndex] of allocated object. 
60    #[inline(always)]
61    pub fn get_gc_info_index(&self) -> GCInfoIndex {
62        debug_assert!(
63            self.encoded_low > 0,
64            "Trying to access non-allocated header {:p} (idx {})",
65            self,
66            self.encoded_low
67        );
68        GCInfoIndex(self.encoded_low)
69    }
70    /// Returns size of an object. If it is allocated in large object space `0` is returned.
71    #[inline(always)]
72    pub fn get_size(self) -> usize {
73        let size = self.encoded_high.size();
74        size as usize * ALLOCATION_GRANULARITY
75    }
76    #[inline(always)]
77    pub fn set_size(&mut self, size: usize) {
78        self.encoded_high
79            .set_size((size / ALLOCATION_GRANULARITY) as _);
80    }
81    #[inline(always)]
82    pub fn is_grey(self) -> bool {
83        self.encoded_high.state() == CellState::PossiblyGrey
84    }
85    #[inline(always)]
86    pub fn is_white(self) -> bool {
87        self.encoded_high.state() == CellState::DefinitelyWhite
88    }
89    #[inline(always)]
90    pub fn is_black(self) -> bool {
91        self.encoded_high.state() == CellState::PossiblyBlack
92    }
93
94    #[inline(always)]
95    pub fn set_state(&mut self, current: CellState, new: CellState) -> bool {
96        if self.encoded_high.state() != current {
97            return false;
98        }
99        self.encoded_high.set_state(new);
100        debug_assert_eq!(self.state(), new);
101        true
102    }
103    #[inline(always)]
104    pub fn force_set_state(&mut self, state: CellState) {
105        self.encoded_high.set_state(state);
106    }
107    #[inline(always)]
108    pub fn set_gc_info(&mut self, index: GCInfoIndex) {
109        self.encoded_low = index.0;
110    }
111    #[inline(always)]
112    pub fn is_free(&self) -> bool {
113        self.get_gc_info_index().0 == 0
114    }
115
116    #[inline]
117    pub fn state(&self) -> CellState {
118        self.encoded_high.state()
119    }
120}
121
122#[bitfield(bits = 16)]
123#[derive(Clone, Copy)]
124pub struct EncodedHigh {
125    size: B13,
126    #[allow(dead_code)]
127    pinned: B1,
128    #[bits = 2]
129    state: CellState,
130}
131
132#[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord, BitfieldSpecifier)]
133#[bits = 2]
134pub enum CellState {
135    DefinitelyWhite,
136    PossiblyGrey,
137    PossiblyBlack,
138}