mmtk/util/
conversions.rs

1use crate::util::constants::*;
2use crate::util::heap::layout::vm_layout::*;
3use crate::util::Address;
4
5/// Is the address aligned to word boundary?
6pub fn is_address_aligned(addr: Address) -> bool {
7    addr.is_aligned_to(BYTES_IN_ADDRESS)
8}
9
10/// Align down an address to the nearest page.
11pub fn page_align_down(address: Address) -> Address {
12    address.align_down(BYTES_IN_PAGE)
13}
14
15/// Is the address aligned to page boundary?
16pub fn is_page_aligned(address: Address) -> bool {
17    address.is_aligned_to(BYTES_IN_PAGE)
18}
19
20/// Align up an address to the nearest chunk.
21pub const fn chunk_align_up(addr: Address) -> Address {
22    addr.align_up(BYTES_IN_CHUNK)
23}
24
25/// Align down an address to the nearest chunk.
26pub const fn chunk_align_down(addr: Address) -> Address {
27    addr.align_down(BYTES_IN_CHUNK)
28}
29
30/// Convert size in bytes to the number of chunks (aligned up).
31pub fn bytes_to_chunks_up(bytes: usize) -> usize {
32    (bytes + BYTES_IN_CHUNK - 1) >> LOG_BYTES_IN_CHUNK
33}
34
35/// Convert an address to the chunk index (aligned down).
36pub fn address_to_chunk_index(addr: Address) -> usize {
37    addr >> LOG_BYTES_IN_CHUNK
38}
39
40/// Convert a chunk index to the start address of the chunk.
41pub fn chunk_index_to_address(chunk: usize) -> Address {
42    unsafe { Address::from_usize(chunk << LOG_BYTES_IN_CHUNK) }
43}
44
45/// Align up an integer to the given alignment. `align` must be a power of two.
46pub const fn raw_align_up(val: usize, align: usize) -> usize {
47    // See https://github.com/rust-lang/rust/blob/e620d0f337d0643c757bab791fc7d88d63217704/src/libcore/alloc.rs#L192
48    val.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1)
49}
50
51/// Align down an integer to the given alignment. `align` must be a power of two.
52pub const fn raw_align_down(val: usize, align: usize) -> usize {
53    val & !align.wrapping_sub(1)
54}
55
56/// Is the integer aligned to the given alignment? `align` must be a power of two.
57pub const fn raw_is_aligned(val: usize, align: usize) -> bool {
58    val & align.wrapping_sub(1) == 0
59}
60
61/// Convert the number of pages to bytes.
62pub fn pages_to_bytes(pages: usize) -> usize {
63    pages << LOG_BYTES_IN_PAGE
64}
65
66/// Convert size in bytes to the number of pages (aligned up)
67pub fn bytes_to_pages_up(bytes: usize) -> usize {
68    raw_align_up(bytes, BYTES_IN_PAGE) >> LOG_BYTES_IN_PAGE
69}
70
71/// Convert size in bytes to a readable short string, such as 1GB, 2TB, etc. It only keeps the major unit and keeps no fraction.
72pub fn bytes_to_formatted_string(bytes: usize) -> String {
73    const UNITS: [&str; 6] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB"];
74    let mut i = 0;
75    let mut num = bytes;
76    while i < UNITS.len() - 1 {
77        let new_num = num >> 10;
78        if new_num == 0 {
79            return format!("{}{}", num, UNITS[i]);
80        }
81        num = new_num;
82        i += 1;
83    }
84    format!("{}{}", num, UNITS.last().unwrap())
85}
86
87/// Shift `num` by `bits` to the right.  Add 1 to the result if any `1` bits are shifted out to the
88/// right.  This is equivalent to dividing `num` by 2 to the power of `bits`, rounding up.
89///
90/// This function has undefined behavior if `bits` is greater or equal to the number of bits in
91/// `usize`.
92pub const fn rshift_align_up(num: usize, bits: usize) -> usize {
93    (num + ((1 << bits) - 1)) >> bits
94}
95
96#[cfg(test)]
97mod tests {
98    use crate::util::conversions::*;
99    use crate::util::Address;
100
101    #[test]
102    fn test_page_align() {
103        let addr = unsafe { Address::from_usize(0x2345_6789) };
104        assert_eq!(page_align_down(addr), unsafe {
105            Address::from_usize(0x2345_6000)
106        });
107        assert!(!is_page_aligned(addr));
108        assert!(is_page_aligned(page_align_down(addr)));
109    }
110
111    #[test]
112    fn test_chunk_align() {
113        let addr = unsafe { Address::from_usize(0x2345_6789) };
114        assert_eq!(chunk_align_down(addr), unsafe {
115            Address::from_usize(0x2340_0000)
116        });
117        assert_eq!(chunk_align_up(addr), unsafe {
118            Address::from_usize(0x2380_0000)
119        });
120    }
121
122    #[test]
123    fn test_bytes_to_formatted_string() {
124        assert_eq!(bytes_to_formatted_string(0), "0B");
125        assert_eq!(bytes_to_formatted_string(1023), "1023B");
126        assert_eq!(bytes_to_formatted_string(1024), "1KiB");
127        assert_eq!(bytes_to_formatted_string(1025), "1KiB");
128        assert_eq!(bytes_to_formatted_string(1 << 20), "1MiB");
129        assert_eq!(bytes_to_formatted_string(1 << 30), "1GiB");
130        #[cfg(target_pointer_width = "64")]
131        {
132            assert_eq!(bytes_to_formatted_string(1 << 40), "1TiB");
133            assert_eq!(bytes_to_formatted_string(1 << 50), "1PiB");
134            assert_eq!(bytes_to_formatted_string(1 << 60), "1024PiB");
135            assert_eq!(bytes_to_formatted_string(1 << 63), "8192PiB");
136        }
137    }
138}