mmtk/util/heap/layout/
vm_layout.rs1use std::ptr::addr_of;
4use std::sync::atomic::AtomicBool;
5
6use atomic::Ordering;
7
8use super::heap_parameters::*;
9use crate::util::constants::*;
10use crate::util::Address;
11
12use crate::util::conversions::{chunk_align_down, chunk_align_up};
13
14pub const LOG_BYTES_IN_CHUNK: usize = 22;
16pub const BYTES_IN_CHUNK: usize = 1 << LOG_BYTES_IN_CHUNK;
18pub const CHUNK_MASK: usize = (1 << LOG_BYTES_IN_CHUNK) - 1;
20pub const PAGES_IN_CHUNK: usize = 1 << (LOG_BYTES_IN_CHUNK - LOG_BYTES_IN_PAGE as usize);
22
23#[derive(Clone, Debug)]
25pub struct VMLayout {
26 pub log_address_space: usize,
28 pub heap_start: Address,
30 pub heap_end: Address,
32 pub log_space_extent: usize,
35 pub force_use_contiguous_spaces: bool,
39}
40
41impl VMLayout {
42 cfg_if::cfg_if! {
43 if #[cfg(target_pointer_width = "32")] {
44 pub const LOG_ARCH_ADDRESS_SPACE: usize = 32;
46 } else if #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
47 pub const LOG_ARCH_ADDRESS_SPACE: usize = 48;
52 } else {
53 pub const LOG_ARCH_ADDRESS_SPACE: usize = 47;
56 }
57 }
58
59 pub const fn max_space_extent(&self) -> usize {
62 1 << self.log_space_extent
63 }
64 pub const fn available_start(&self) -> Address {
66 self.heap_start
67 }
68 pub const fn available_end(&self) -> Address {
70 self.heap_end
71 }
72 pub const fn available_bytes(&self) -> usize {
74 self.available_end().get_extent(self.available_start())
75 }
76 pub const fn max_chunks(&self) -> usize {
78 1 << self.log_max_chunks()
79 }
80 pub const fn log_max_chunks(&self) -> usize {
82 Self::LOG_ARCH_ADDRESS_SPACE - LOG_BYTES_IN_CHUNK
83 }
84 pub(crate) fn space_shift_64(&self) -> usize {
87 self.log_space_extent
88 }
89 pub(crate) fn space_mask_64(&self) -> usize {
93 ((1 << LOG_MAX_SPACES) - 1) << self.space_shift_64()
94 }
95 pub(crate) fn space_size_64(&self) -> usize {
100 self.max_space_extent()
101 }
102 pub(crate) fn log_pages_in_space64(&self) -> usize {
104 self.log_space_extent - LOG_BYTES_IN_PAGE as usize
105 }
106 pub(crate) fn pages_in_space64(&self) -> usize {
108 1 << self.log_pages_in_space64()
109 }
110
111 pub(crate) fn address_mask(&self) -> usize {
114 0x1f << self.log_space_extent
115 }
116
117 const fn validate(&self) {
118 assert!(self.heap_start.is_aligned_to(BYTES_IN_CHUNK));
119 assert!(self.heap_end.is_aligned_to(BYTES_IN_CHUNK));
120 assert!(self.heap_start.as_usize() < self.heap_end.as_usize());
121 assert!(self.log_address_space <= Self::LOG_ARCH_ADDRESS_SPACE);
122 assert!(self.log_space_extent <= self.log_address_space);
123 if self.force_use_contiguous_spaces {
124 assert!(self.log_space_extent <= (self.log_address_space - LOG_MAX_SPACES));
125 assert!(self.heap_start.is_aligned_to(self.max_space_extent()));
126 }
127 }
128
129 pub(crate) fn validate_address_space(&self) {
130 let log_mappable_bytes = crate::mmtk::MMAPPER.log_mappable_bytes();
131 assert!(
132 self.log_address_space <= log_mappable_bytes as usize,
133 "log_address_space is {log_address_space}, but \
134 the MMAPPER can only handle up to {log_mappable_bytes} bits",
135 log_address_space = self.log_address_space,
136 );
137 }
138}
139
140impl VMLayout {
141 pub const fn new_32bit() -> Self {
143 let layout32 = Self {
144 log_address_space: 32,
145 heap_start: chunk_align_down(unsafe { Address::from_usize(0x8000_0000) }),
146 heap_end: chunk_align_up(unsafe { Address::from_usize(0xd000_0000) }),
147 log_space_extent: 31,
148 force_use_contiguous_spaces: false,
149 };
150 layout32.validate();
151 layout32
152 }
153 #[cfg(target_pointer_width = "64")]
155 pub const fn new_64bit() -> Self {
156 let layout64 = Self {
157 log_address_space: 47,
158 heap_start: chunk_align_down(unsafe {
159 Address::from_usize(0x0000_0200_0000_0000usize)
160 }),
161 heap_end: chunk_align_up(unsafe { Address::from_usize(0x0000_2200_0000_0000usize) }),
162 log_space_extent: 41,
163 force_use_contiguous_spaces: true,
164 };
165 layout64.validate();
166 layout64
167 }
168
169 pub(crate) fn set_custom_vm_layout(constants: VMLayout) {
172 if cfg!(debug_assertions) {
173 assert!(
174 !VM_LAYOUT_FETCHED.load(Ordering::SeqCst),
175 "vm_layout is already been used before setup"
176 );
177 }
178 constants.validate();
179 unsafe {
180 VM_LAYOUT = constants;
181 }
182 }
183}
184
185impl std::default::Default for VMLayout {
187 #[cfg(target_pointer_width = "32")]
188 fn default() -> Self {
189 Self::new_32bit()
190 }
191
192 #[cfg(target_pointer_width = "64")]
193 fn default() -> Self {
194 Self::new_64bit()
195 }
196}
197
198#[cfg(target_pointer_width = "32")]
199static mut VM_LAYOUT: VMLayout = VMLayout::new_32bit();
200#[cfg(target_pointer_width = "64")]
201static mut VM_LAYOUT: VMLayout = VMLayout::new_64bit();
202
203static VM_LAYOUT_FETCHED: AtomicBool = AtomicBool::new(false);
204
205pub fn vm_layout() -> &'static VMLayout {
209 if cfg!(debug_assertions) {
210 VM_LAYOUT_FETCHED.store(true, Ordering::SeqCst);
211 }
212 unsafe { &*addr_of!(VM_LAYOUT) }
213}