1use crate::mmtk::SFT_MAP;
2use crate::plan::tracing::OptionObjectQueue;
3use crate::plan::ObjectQueue;
4use crate::policy::sft::GCWorkerMutRef;
5use crate::policy::sft::SFT;
6use crate::policy::space::{CommonSpace, Space};
7use crate::util::address::Address;
8use crate::util::alloc::allocator::AllocationOptions;
9use crate::util::constants::BYTES_IN_PAGE;
10use crate::util::heap::externalpageresource::{ExternalPageResource, ExternalPages};
11use crate::util::heap::layout::vm_layout::BYTES_IN_CHUNK;
12use crate::util::heap::PageResource;
13use crate::util::metadata::mark_bit::MarkState;
14#[cfg(feature = "set_unlog_bits_vm_space")]
15use crate::util::metadata::MetadataSpec;
16use crate::util::object_enum::ObjectEnumerator;
17use crate::util::opaque_pointer::*;
18use crate::util::ObjectReference;
19use crate::vm::{ObjectModel, VMBinding};
20
21use std::sync::atomic::Ordering;
22
23pub struct VMSpace<VM: VMBinding> {
28 mark_state: MarkState,
29 common: CommonSpace<VM>,
30 pr: ExternalPageResource<VM>,
31}
32
33impl<VM: VMBinding> SFT for VMSpace<VM> {
34 fn name(&self) -> &'static str {
35 self.common.name
36 }
37 fn is_live(&self, _object: ObjectReference) -> bool {
38 true
39 }
40 fn is_reachable(&self, object: ObjectReference) -> bool {
41 self.mark_state.is_marked::<VM>(object)
42 }
43 #[cfg(feature = "object_pinning")]
44 fn pin_object(&self, _object: ObjectReference) -> bool {
45 false
46 }
47 #[cfg(feature = "object_pinning")]
48 fn unpin_object(&self, _object: ObjectReference) -> bool {
49 false
50 }
51 #[cfg(feature = "object_pinning")]
52 fn is_object_pinned(&self, _object: ObjectReference) -> bool {
53 true
54 }
55 fn is_movable(&self) -> bool {
56 false
57 }
58 #[cfg(feature = "sanity")]
59 fn is_sane(&self) -> bool {
60 true
61 }
62 fn initialize_object_metadata(&self, object: ObjectReference, _bytes: usize) {
63 self.mark_state
64 .on_object_metadata_initialization::<VM>(object);
65 if self.common.unlog_allocated_object {
66 VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::<VM>(object, Ordering::SeqCst);
67 }
68 #[cfg(feature = "vo_bit")]
69 crate::util::metadata::vo_bit::set_vo_bit(object);
70 }
71 #[cfg(feature = "vo_bit")]
72 fn is_mmtk_object(&self, addr: Address) -> Option<ObjectReference> {
73 crate::util::metadata::vo_bit::is_vo_bit_set_for_addr(addr)
74 }
75 #[cfg(feature = "vo_bit")]
76 fn find_object_from_internal_pointer(
77 &self,
78 ptr: Address,
79 max_search_bytes: usize,
80 ) -> Option<ObjectReference> {
81 crate::util::metadata::vo_bit::find_object_from_internal_pointer::<VM>(
82 ptr,
83 max_search_bytes,
84 )
85 }
86 fn sft_trace_object(
87 &self,
88 queue: &mut OptionObjectQueue,
89 object: ObjectReference,
90 _worker: GCWorkerMutRef,
91 ) -> ObjectReference {
92 self.trace_object(queue, object)
93 }
94}
95
96impl<VM: VMBinding> Space<VM> for VMSpace<VM> {
97 fn as_space(&self) -> &dyn Space<VM> {
98 self
99 }
100 fn as_sft(&self) -> &(dyn SFT + Sync + 'static) {
101 self
102 }
103 fn get_page_resource(&self) -> &dyn PageResource<VM> {
104 &self.pr
105 }
106 fn maybe_get_page_resource_mut(&mut self) -> Option<&mut dyn PageResource<VM>> {
107 Some(&mut self.pr)
108 }
109 fn common(&self) -> &CommonSpace<VM> {
110 &self.common
111 }
112
113 fn initialize_sft(&self, sft_map: &mut dyn crate::policy::sft_map::SFTMap) {
114 let vm_regions = self.pr.get_external_pages();
117 assert!(vm_regions.len() <= 1);
120 for external_pages in vm_regions.iter() {
121 let start = external_pages.start.align_down(BYTES_IN_CHUNK);
123 let size = external_pages.end.align_up(BYTES_IN_CHUNK) - start;
124 debug_assert_eq!(
126 sft_map.get_checked(start).name(),
127 crate::policy::sft::EMPTY_SFT_NAME
128 );
129 self.set_sft(start, size);
130 }
131 }
132
133 fn initialize_side_metadata(&self) {
134 let vm_regions = self.pr.get_external_pages();
135 for external_pages in vm_regions.iter() {
136 let chunk_start = external_pages.start.align_down(BYTES_IN_CHUNK);
138 let chunk_size = external_pages.end.align_up(BYTES_IN_CHUNK) - chunk_start;
139 let raw_start = external_pages.start;
140 let raw_size = external_pages.end - external_pages.start;
141 self.set_side_metadata(chunk_start, chunk_size, raw_start, raw_size);
142 }
143 }
144
145 fn release_multiple_pages(&mut self, _start: Address) {
146 unreachable!()
147 }
148
149 fn acquire(&self, _tls: VMThread, _pages: usize, _alloc_options: AllocationOptions) -> Address {
150 unreachable!()
151 }
152
153 fn address_in_space(&self, start: Address) -> bool {
154 SFT_MAP.get_checked(start).name() == self.name()
158 }
159
160 fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator) {
161 let external_pages = self.pr.get_external_pages();
162 for ep in external_pages.iter() {
163 enumerator.visit_address_range(ep.start, ep.end);
164 }
165 }
166
167 fn clear_side_log_bits(&self) {
168 let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec();
169 let external_pages = self.pr.get_external_pages();
170 for ep in external_pages.iter() {
171 log_bit.bzero_metadata(ep.start, ep.end - ep.start);
172 }
173 }
174
175 fn set_side_log_bits(&self) {
176 let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec();
177 let external_pages = self.pr.get_external_pages();
178 for ep in external_pages.iter() {
179 log_bit.bset_metadata(ep.start, ep.end - ep.start);
180 }
181 }
182}
183
184use crate::scheduler::GCWorker;
185use crate::util::copy::CopySemantics;
186
187impl<VM: VMBinding> crate::policy::gc_work::PolicyTraceObject<VM> for VMSpace<VM> {
188 fn trace_object<Q: ObjectQueue, const KIND: crate::policy::gc_work::TraceKind>(
189 &self,
190 queue: &mut Q,
191 object: ObjectReference,
192 _copy: Option<CopySemantics>,
193 _worker: &mut GCWorker<VM>,
194 ) -> ObjectReference {
195 self.trace_object(queue, object)
196 }
197 fn may_move_objects<const KIND: crate::policy::gc_work::TraceKind>() -> bool {
198 false
199 }
200}
201
202impl<VM: VMBinding> VMSpace<VM> {
203 pub fn new(args: crate::policy::space::PlanCreateSpaceArgs<VM>) -> Self {
204 let (vm_space_start, vm_space_size) =
205 (*args.options.vm_space_start, *args.options.vm_space_size);
206 let space = Self {
207 mark_state: MarkState::new(),
208 pr: ExternalPageResource::new(args.vm_map),
209 common: CommonSpace::new(args.into_policy_args(
210 false,
211 true,
212 crate::util::metadata::extract_side_metadata(&[
213 *VM::VMObjectModel::LOCAL_MARK_BIT_SPEC,
214 ]),
215 )),
216 };
217
218 if !vm_space_start.is_zero() {
219 space.set_vm_region_inner(vm_space_start, vm_space_size, true);
221 }
222
223 space
224 }
225
226 pub fn set_vm_region(&mut self, start: Address, size: usize) {
227 self.set_vm_region_inner(start, size, false);
228 }
229
230 fn set_vm_region_inner(&self, start: Address, size: usize, init: bool) {
231 assert!(size > 0);
232 assert!(!start.is_zero());
233
234 let end = start + size;
235
236 let chunk_start = start.align_down(BYTES_IN_CHUNK);
237 let chunk_end = end.align_up(BYTES_IN_CHUNK);
238 let chunk_size = chunk_end - chunk_start;
239
240 assert!(Address::range_intersection(
243 &(chunk_start..chunk_end),
244 &crate::util::heap::layout::available_range()
245 )
246 .is_empty());
247
248 debug!(
249 "Align VM space ({}, {}) to chunk ({}, {})",
250 start, end, chunk_start, chunk_end
251 );
252
253 self.common.mmapper.mark_as_mapped(chunk_start, chunk_size);
255 if !init {
257 self.set_side_metadata(chunk_start, chunk_size, start, size);
258 }
259 if !init {
263 self.set_sft(chunk_start, chunk_size);
264 }
265
266 self.pr.add_new_external_pages(ExternalPages {
267 start: start.align_down(BYTES_IN_PAGE),
268 end: end.align_up(BYTES_IN_PAGE),
269 });
270 }
271
272 fn set_sft(&self, chunk_start: Address, chunk_size: usize) {
273 assert!(SFT_MAP.has_sft_entry(chunk_start), "The VM space start (aligned to {}) does not have a valid SFT entry. Possibly the address range is not in the address range we use.", chunk_start);
274 unsafe {
275 SFT_MAP.update(self.as_sft(), chunk_start, chunk_size);
276 }
277 }
278
279 fn set_side_metadata(
280 &self,
281 chunk_start: Address,
282 chunk_size: usize,
283 _raw_start: Address,
284 _raw_size: usize,
285 ) {
286 self.common
287 .metadata
288 .try_map_metadata_space(chunk_start, chunk_size, self.get_name())
289 .unwrap();
290 #[cfg(feature = "set_unlog_bits_vm_space")]
291 if self.common.needs_log_bit {
292 if let MetadataSpec::OnSide(side) = *VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC {
295 side.bset_metadata(_raw_start, _raw_size);
296 }
297 }
298 }
299
300 pub fn prepare(&mut self) {
301 self.mark_state.on_global_prepare::<VM>();
302 for external_pages in self.pr.get_external_pages().iter() {
303 self.mark_state.on_block_reset::<VM>(
304 external_pages.start,
305 external_pages.end - external_pages.start,
306 );
307 }
308 }
309
310 pub fn release(&mut self) {
311 self.mark_state.on_global_release::<VM>();
312 }
313
314 pub fn trace_object<Q: ObjectQueue>(
315 &self,
316 queue: &mut Q,
317 object: ObjectReference,
318 ) -> ObjectReference {
319 #[cfg(feature = "vo_bit")]
320 debug_assert!(
321 crate::util::metadata::vo_bit::is_vo_bit_set(object),
322 "{:x}: VO bit not set",
323 object
324 );
325 debug_assert!(self.in_space(object));
326 if self.mark_state.test_and_mark::<VM>(object) {
327 #[cfg(feature = "set_unlog_bits_vm_space")]
330 if self.common.unlog_traced_object {
331 VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.store_atomic::<VM, u8>(
332 object,
333 1,
334 None,
335 Ordering::SeqCst,
336 );
337 }
338 queue.enqueue(object);
339 }
340 object
341 }
342}