Skip to content

Commit 10883f4

Browse files
committed
Introduce SpaceInspector and RegionInspector
1 parent c5ead72 commit 10883f4

File tree

9 files changed

+201
-5
lines changed

9 files changed

+201
-5
lines changed

macros/src/has_spaces_impl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ pub(crate) fn generate_impl_items<'a>(
7070
};
7171

7272
quote! {
73-
fn for_each_space(&self, __func: &mut dyn FnMut(&dyn Space<VM>)) {
73+
fn for_each_space<'a>(&'a self, __func: &mut dyn FnMut(&'a dyn Space<VM>)) {
7474
#(#space_visitors)*
7575
#parent_visitor
7676
}
7777

78-
fn for_each_space_mut(&mut self, __func: &mut dyn FnMut(&mut dyn Space<VM>)) {
78+
fn for_each_space_mut<'a>(&'a mut self, __func: &mut dyn FnMut(&'a mut dyn Space<VM>)) {
7979
#(#space_visitors_mut)*
8080
#parent_visitor_mut
8181
}

src/mmtk.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::util::address::ObjectReference;
1212
use crate::util::analysis::AnalysisManager;
1313
use crate::util::finalizable_processor::FinalizableProcessor;
1414
use crate::util::heap::gc_trigger::GCTrigger;
15+
use crate::util::heap::inspection::SpaceInspector;
1516
use crate::util::heap::layout::heap_parameters::MAX_SPACES;
1617
use crate::util::heap::layout::vm_layout::VMLayout;
1718
use crate::util::heap::layout::{self, Mmapper, VMMap};
@@ -596,4 +597,14 @@ impl<VM: VMBinding> MMTK<VM> {
596597
.vm_space
597598
.initialize_object_metadata(object, false)
598599
}
600+
601+
pub fn inspect_spaces<'a>(&'a self) -> Vec<&'a dyn SpaceInspector> {
602+
let mut ret = vec![];
603+
self.get_plan().for_each_space(&mut |space| {
604+
if let Some(inspector) = space.as_inspector() {
605+
ret.push(inspector);
606+
}
607+
});
608+
ret
609+
}
599610
}

src/plan/global.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -714,13 +714,13 @@ pub trait HasSpaces {
714714
///
715715
/// If `Self` contains nested fields that contain more spaces, this method shall visit spaces
716716
/// in the outer struct first.
717-
fn for_each_space(&self, func: &mut dyn FnMut(&dyn Space<Self::VM>));
717+
fn for_each_space<'a>(&'a self, func: &mut dyn FnMut(&'a dyn Space<Self::VM>));
718718

719719
/// Visit each space field mutably.
720720
///
721721
/// If `Self` contains nested fields that contain more spaces, this method shall visit spaces
722722
/// in the outer struct first.
723-
fn for_each_space_mut(&mut self, func: &mut dyn FnMut(&mut dyn Space<Self::VM>));
723+
fn for_each_space_mut<'a>(&'a mut self, func: &mut dyn FnMut(&'a mut dyn Space<Self::VM>));
724724
}
725725

726726
/// A plan that uses `PlanProcessEdges` needs to provide an implementation for this trait.

src/policy/immix/immixspace.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ impl<VM: VMBinding> Space<VM> for ImmixSpace<VM> {
167167
fn as_sft(&self) -> &(dyn SFT + Sync + 'static) {
168168
self
169169
}
170+
fn as_inspector(&self) -> Option<&dyn crate::util::heap::inspection::SpaceInspector> {
171+
Some(self)
172+
}
170173
fn get_page_resource(&self) -> &dyn PageResource<VM> {
171174
&self.pr
172175
}
@@ -409,7 +412,7 @@ impl<VM: VMBinding> ImmixSpace<VM> {
409412
if self.common.needs_log_bit {
410413
if let MetadataSpec::OnSide(side) = *VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC {
411414
for chunk in self.chunk_map.all_chunks() {
412-
side.bzero_metadata(chunk.start(), Chunk::BYTES);
415+
side.bzero_metadata(chunk .start(), Chunk::BYTES);
413416
}
414417
}
415418
}
@@ -1178,3 +1181,27 @@ impl ClearVOBitsAfterPrepare {
11781181
}
11791182
}
11801183
}
1184+
1185+
mod inspector {
1186+
use super::*;
1187+
use crate::util::heap::inspection::{RegionInspector, SpaceInspector, list_child_regions};
1188+
impl<VM: VMBinding> SpaceInspector for ImmixSpace<VM> {
1189+
fn name(&self) -> &str {
1190+
SFT::name(self)
1191+
}
1192+
1193+
fn list_regions(&self, parent_region: Option<&dyn RegionInspector>) -> Vec<Box<dyn RegionInspector>> {
1194+
if let Some(parent_region) = parent_region {
1195+
list_child_regions::<Chunk, Block>(parent_region).or_else(|| {
1196+
if !crate::policy::immix::BLOCK_ONLY {
1197+
list_child_regions::<Block, Line>(parent_region)
1198+
} else {
1199+
None
1200+
}
1201+
}).unwrap_or_else(|| vec![])
1202+
} else {
1203+
self.chunk_map.all_chunks().map(|r: Chunk| Box::new(r) as Box<dyn RegionInspector>).collect()
1204+
}
1205+
}
1206+
}
1207+
}

src/policy/space.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::global_state::GlobalState;
22
use crate::plan::PlanConstraints;
33
use crate::scheduler::GCWorkScheduler;
44
use crate::util::conversions::*;
5+
use crate::util::heap::inspection::SpaceInspector;
56
use crate::util::metadata::side_metadata::{
67
SideMetadataContext, SideMetadataSanity, SideMetadataSpec,
78
};
@@ -42,6 +43,9 @@ use downcast_rs::Downcast;
4243
pub trait Space<VM: VMBinding>: 'static + SFT + Sync + Downcast {
4344
fn as_space(&self) -> &dyn Space<VM>;
4445
fn as_sft(&self) -> &(dyn SFT + Sync + 'static);
46+
fn as_inspector(&self) -> Option<&dyn SpaceInspector> {
47+
None
48+
}
4549
fn get_page_resource(&self) -> &dyn PageResource<VM>;
4650

4751
/// Get a mutable reference to the underlying page resource, or `None` if the space does not

src/util/heap/inspection/mod.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use crate::policy::sft::SFT;
2+
use crate::util::linear_scan::RegionIterator;
3+
use crate::util::{linear_scan::Region, Address, ObjectReference};
4+
use crate::util::metadata::side_metadata::spec_defs::VO_BIT;
5+
use crate::util::heap::chunk_map::Chunk;
6+
7+
pub trait SpaceInspector {
8+
fn name(&self) -> &str;
9+
fn list_regions(&self, parent_region: Option<&dyn RegionInspector>) -> Vec<Box<dyn RegionInspector>>;
10+
}
11+
12+
pub(crate) fn list_child_regions<PARENT: Region, CHILD: Region + 'static>(region: &dyn RegionInspector) -> Option<Vec<Box<dyn RegionInspector>>> {
13+
if region.region_type() == std::any::type_name::<PARENT>() {
14+
let start_child_region = CHILD::from_aligned_address(region.start());
15+
let end_child_region = CHILD::from_aligned_address(region.start() + region.size());
16+
Some(RegionIterator::<CHILD>::new(start_child_region, end_child_region)
17+
.map(|r| Box::new(r) as Box<dyn RegionInspector>)
18+
.collect())
19+
} else {
20+
None
21+
}
22+
}
23+
24+
pub trait RegionInspector {
25+
fn region_type(&self) -> &str;
26+
fn start(&self) -> Address;
27+
fn size(&self) -> usize;
28+
#[cfg(feature = "vo_bit")]
29+
fn list_objects(&self) -> Vec<ObjectReference> {
30+
let mut objects = vec![];
31+
VO_BIT.scan_non_zero_values::<u8>(self.start(), self.start() + self.size(), &mut |address| {
32+
use crate::util::metadata::vo_bit;
33+
let object = vo_bit::get_object_ref_for_vo_addr(address);
34+
objects.push(object);
35+
});
36+
objects
37+
}
38+
}
39+
40+
impl<R: Region> RegionInspector for R {
41+
fn region_type(&self) -> &str {
42+
std::any::type_name::<R>()
43+
}
44+
45+
fn start(&self) -> Address {
46+
Region::start(self)
47+
}
48+
49+
fn size(&self) -> usize {
50+
Self::BYTES
51+
}
52+
}

src/util/heap/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ pub use self::layout::vm_layout;
2222
pub(crate) use self::monotonepageresource::MonotonePageResource;
2323
pub(crate) use self::pageresource::PageResource;
2424
pub(crate) use self::vmrequest::VMRequest;
25+
26+
pub mod inspection;
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// GITHUB-CI: MMTK_PLAN=Immix
2+
// GITHUB-CI: FEATURES=vo_bit
3+
4+
use std::collections::HashSet;
5+
6+
use constants::BYTES_IN_WORD;
7+
8+
use super::mock_test_prelude::*;
9+
10+
use crate::{util::*, AllocationSemantics, MMTK};
11+
12+
lazy_static! {
13+
static ref FIXTURE: Fixture<MutatorFixture> = Fixture::new();
14+
}
15+
16+
pub fn get_all_objects(mmtk: &'static MMTK<MockVM>) -> HashSet<ObjectReference> {
17+
let mut result = HashSet::new();
18+
mmtk.enumerate_objects(|object| {
19+
result.insert(object);
20+
});
21+
result
22+
}
23+
24+
#[test]
25+
pub fn test_heap_inspector() {
26+
with_mockvm(
27+
default_setup,
28+
|| {
29+
FIXTURE.with_fixture_mut(|fixture| {
30+
let mmtk = fixture.mmtk();
31+
let mutator = &mut fixture.mutator;
32+
let space_inspector = mmtk.inspect_spaces();
33+
assert!(space_inspector.len() > 0);
34+
35+
let get_immix_inspector = || {
36+
space_inspector.iter().find(|s| s.name() == "immix").unwrap()
37+
};
38+
39+
{
40+
let immix_space_inspector = get_immix_inspector();
41+
let chunk_inspector = immix_space_inspector.list_regions(None);
42+
assert_eq!(chunk_inspector.len(), 0);
43+
}
44+
45+
let mut new_obj = |size: usize, semantics: AllocationSemantics| {
46+
let align = BYTES_IN_WORD;
47+
let start = memory_manager::alloc(mutator, size, align, 0, semantics);
48+
let object = MockVM::object_start_to_ref(start);
49+
memory_manager::post_alloc(mutator, object, size, semantics);
50+
object
51+
};
52+
53+
// Allocate one object
54+
let object = new_obj(40, AllocationSemantics::Default);
55+
56+
{
57+
let immix_space_inspector = get_immix_inspector();
58+
// Check chunks
59+
let chunk_inspector = immix_space_inspector.list_regions(None);
60+
assert_eq!(chunk_inspector.len(), 1);
61+
assert_eq!(chunk_inspector[0].region_type(), "mmtk::util::heap::chunk_map::Chunk");
62+
let objects = chunk_inspector[0].list_objects();
63+
assert_eq!(objects.len(), 1);
64+
assert_eq!(objects[0], object);
65+
// Check blocks
66+
let block_inspector = immix_space_inspector.list_regions(Some(&*chunk_inspector[0]));
67+
assert_eq!(block_inspector.len(), 128); // 128 blocks in a chunk
68+
assert_eq!(block_inspector[0].region_type(), "mmtk::policy::immix::block::Block");
69+
let objects = block_inspector[0].list_objects();
70+
assert_eq!(objects.len(), 1);
71+
assert_eq!(objects[0], object);
72+
// Check lines
73+
let line_inspector = immix_space_inspector.list_regions(Some(&*block_inspector[0]));
74+
assert_eq!(line_inspector.len(), 128); // 128 lines in a block
75+
assert_eq!(line_inspector[0].region_type(), "mmtk::policy::immix::line::Line");
76+
let objects = line_inspector[0].list_objects();
77+
assert_eq!(objects.len(), 1);
78+
assert_eq!(objects[0], object);
79+
}
80+
81+
// Allocate another object
82+
let object2 = new_obj(40, AllocationSemantics::Default);
83+
84+
{
85+
let immix_space_inspector = get_immix_inspector();
86+
// Check checks
87+
let chunk_inspector = immix_space_inspector.list_regions(None);
88+
assert_eq!(chunk_inspector.len(), 1);
89+
assert_eq!(chunk_inspector[0].region_type(), "mmtk::util::heap::chunk_map::Chunk");
90+
let objects = chunk_inspector[0].list_objects();
91+
assert_eq!(objects.len(), 2);
92+
assert_eq!(objects[0], object);
93+
assert_eq!(objects[1], object2);
94+
}
95+
});
96+
},
97+
no_cleanup,
98+
)
99+
}

src/vm/tests/mock_tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ mod mock_test_handle_mmap_conflict;
4040
mod mock_test_handle_mmap_oom;
4141
#[cfg(feature = "vo_bit")]
4242
mod mock_test_heap_traversal;
43+
mod mock_test_heap_inspector;
4344
mod mock_test_init_fork;
4445
#[cfg(feature = "is_mmtk_object")]
4546
mod mock_test_internal_ptr_before_object_ref;

0 commit comments

Comments
 (0)