Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce ArcFlexMut for Space references #965

Draft
wants to merge 28 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
efe572d
Move global state from BasePlan to GlobalState
qinsoon Sep 7, 2023
8768970
Move more stuff out of BasePlan. Allocator no longer keeps a ref to
qinsoon Sep 8, 2023
2e2e9aa
Fix build and style
qinsoon Sep 8, 2023
c4b3160
Remove ActivePlan::global
qinsoon Sep 8, 2023
f14ad1a
Introduce notify_collection_required and refactor collection_required.
qinsoon Sep 12, 2023
a6fd28a
Fix docs
qinsoon Sep 12, 2023
d2c929d
Some cleanup
qinsoon Sep 12, 2023
5c13a6c
Merge branch 'master' into refactor-global-state
qinsoon Sep 12, 2023
280758a
Revert changes about collection_required
qinsoon Sep 19, 2023
6bf649e
Add SpaceRef
qinsoon Sep 26, 2023
9fd91b3
Use peace_lock
qinsoon Sep 27, 2023
63e8057
Implement SharedRef
qinsoon Sep 28, 2023
f968c07
Use SharedRef for spaces
qinsoon Sep 28, 2023
f209311
Refactor for all the plans. Rename SharedRef to ArcFlexMut
qinsoon Sep 29, 2023
48615af
Update docs
qinsoon Sep 29, 2023
92cb35c
Remove get_plan_mut and UnsafeCell for plan. prepare/release/end_of_gc
qinsoon Sep 29, 2023
0fc150c
Add comments for ArcFlexMut
qinsoon Sep 29, 2023
b95ff4b
Clean up deps
qinsoon Sep 29, 2023
9e5ef1c
Merge branch 'master' into space-ref
qinsoon Sep 29, 2023
dcdb87a
Fix style check in tests
qinsoon Sep 29, 2023
5e4c0a0
Disabling PrepareMutator from PlanConstraints (#964)
qinsoon Oct 3, 2023
edb8c50
Merge branch 'master' into space-ref
qinsoon Oct 3, 2023
edc393e
Fix doc code
qinsoon Oct 3, 2023
c15b1cb
Merge branch 'master' into space-ref
qinsoon Oct 25, 2023
1c254f4
Minor cleanup
qinsoon Oct 26, 2023
2c27b79
Add criterion bench for post_alloc
qinsoon Oct 26, 2023
f20e3c3
Remove tag in comments
qinsoon Oct 26, 2023
2e69a01
Get StatsForDefrag before use write on the space
qinsoon Oct 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ mimalloc-sys = { version = "0.1.6", optional = true }
mmtk-macros = { version = "0.20.0", path = "macros/" }
num_cpus = "1.8"
num-traits = "0.2"
peace-lock = "0.1.3"
pfm = { version = "0.1.0-beta.3", optional = true }
probe = "0.5"
portable-atomic = "1.4.3"
Expand Down Expand Up @@ -72,6 +73,9 @@ perf_counter = ["pfm"]
# Do not modify the following line - ci-common.sh matches it
# -- Non mutually exclusive features --

# Turn on checks for the type ArcFlexMut (we use peace-lock for the type so just turn on check for peace-lock).
check_flex_mut = ["peace-lock/check"]

# spaces with different semantics

# A VM-allocated/managed space. A binding could use this for their boot image, metadata space, etc.
Expand Down Expand Up @@ -129,7 +133,7 @@ nogc_no_zeroing = ["nogc_lock_free"]
single_worker = []

# To run expensive comprehensive runtime checks, such as checking duplicate edges
extreme_assertions = []
extreme_assertions = ["check_flex_mut"]

# Enable multiple spaces for NoGC, each allocator maps to an individual ImmortalSpace.
nogc_multi_space = []
Expand Down
8 changes: 4 additions & 4 deletions docs/userguide/src/tutorial/code/mygc_semispace/gc_work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ impl<VM: VMBinding> ProcessEdgesWork for MyGCProcessEdges<VM> {
}
let worker = self.worker();
let queue = &mut self.base.nodes;
if self.plan.tospace().in_space(object) {
self.plan.tospace().trace_object(
if self.plan.tospace().read().in_space(object) {
self.plan.tospace().read().trace_object(
queue,
object,
Some(CopySemantics::DefaultCopy),
worker,
)
} else if self.plan.fromspace().in_space(object) {
self.plan.fromspace().trace_object(
} else if self.plan.fromspace().read().in_space(object) {
self.plan.fromspace().read().trace_object(
queue,
object,
Some(CopySemantics::DefaultCopy),
Expand Down
51 changes: 18 additions & 33 deletions docs/userguide/src/tutorial/code/mygc_semispace/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::util::copy::*;
use crate::util::heap::VMRequest;
use crate::util::metadata::side_metadata::SideMetadataContext;
use crate::util::opaque_pointer::*;
use crate::util::rust_util::flex_mut::ArcFlexMut;
use crate::vm::VMBinding;
use enum_map::EnumMap;
use std::sync::atomic::{AtomicBool, Ordering}; // Add
Expand All @@ -32,10 +33,10 @@ pub struct MyGC<VM: VMBinding> {
pub hi: AtomicBool,
#[space]
#[copy_semantics(CopySemantics::DefaultCopy)]
pub copyspace0: CopySpace<VM>,
pub copyspace0: ArcFlexMut<CopySpace<VM>>,
#[space]
#[copy_semantics(CopySemantics::DefaultCopy)]
pub copyspace1: CopySpace<VM>,
pub copyspace1: ArcFlexMut<CopySpace<VM>>,
#[parent]
pub common: CommonPlan<VM>,
}
Expand Down Expand Up @@ -66,7 +67,7 @@ impl<VM: VMBinding> Plan for MyGC<VM> {
},
space_mapping: vec![
// The tospace argument doesn't matter, we will rebind before a GC anyway.
(CopySelector::CopySpace(0), &self.copyspace0)
(CopySelector::CopySpace(0), self.copyspace0.clone().into_dyn_space())
],
constraints: &MYGC_CONSTRAINTS,
}
Expand All @@ -92,48 +93,48 @@ impl<VM: VMBinding> Plan for MyGC<VM> {

// Modify
// ANCHOR: prepare
fn prepare(&mut self, tls: VMWorkerThread) {
fn prepare(&self, tls: VMWorkerThread) {
self.common.prepare(tls, true);

self.hi
.store(!self.hi.load(Ordering::SeqCst), Ordering::SeqCst);
// Flips 'hi' to flip space definitions
let hi = self.hi.load(Ordering::SeqCst);
self.copyspace0.prepare(hi);
self.copyspace1.prepare(!hi);
self.copyspace0.read().prepare(hi);
self.copyspace1.read().prepare(!hi);

self.fromspace_mut()
self.fromspace().write()
.set_copy_for_sft_trace(Some(CopySemantics::DefaultCopy));
self.tospace_mut().set_copy_for_sft_trace(None);
self.tospace().write().set_copy_for_sft_trace(None);
}
// ANCHOR_END: prepare

// Add
// ANCHOR: prepare_worker
fn prepare_worker(&self, worker: &mut GCWorker<VM>) {
unsafe { worker.get_copy_context_mut().copy[0].assume_init_mut() }.rebind(self.tospace());
unsafe { worker.get_copy_context_mut().copy[0].assume_init_mut() }.rebind(self.tospace().clone());
}
// ANCHOR_END: prepare_worker

// Modify
// ANCHOR: release
fn release(&mut self, tls: VMWorkerThread) {
fn release(&self, tls: VMWorkerThread) {
self.common.release(tls, true);
self.fromspace().release();
self.fromspace().read().release();
}
// ANCHOR_END: release

// Modify
// ANCHOR: plan_get_collection_reserve
fn get_collection_reserved_pages(&self) -> usize {
self.tospace().reserved_pages()
self.tospace().read().reserved_pages()
}
// ANCHOR_END: plan_get_collection_reserve

// Modify
// ANCHOR: plan_get_used_pages
fn get_used_pages(&self) -> usize {
self.tospace().reserved_pages() + self.common.get_used_pages()
self.tospace().read().reserved_pages() + self.common.get_used_pages()
}
// ANCHOR_END: plan_get_used_pages

Expand Down Expand Up @@ -170,9 +171,9 @@ impl<VM: VMBinding> MyGC<VM> {
let res = MyGC {
hi: AtomicBool::new(false),
// ANCHOR: copyspace_new
copyspace0: CopySpace::new(plan_args.get_space_args("copyspace0", true, VMRequest::discontiguous()), false),
copyspace0: ArcFlexMut::new(CopySpace::new(plan_args.get_space_args("copyspace0", true, VMRequest::discontiguous()), false)),
// ANCHOR_END: copyspace_new
copyspace1: CopySpace::new(plan_args.get_space_args("copyspace1", true, VMRequest::discontiguous()), true),
copyspace1: ArcFlexMut::new(CopySpace::new(plan_args.get_space_args("copyspace1", true, VMRequest::discontiguous()), true)),
common: CommonPlan::new(plan_args),
};

Expand All @@ -183,36 +184,20 @@ impl<VM: VMBinding> MyGC<VM> {
// ANCHOR_END: plan_new

// ANCHOR: plan_space_access
pub fn tospace(&self) -> &CopySpace<VM> {
pub fn tospace(&self) -> &ArcFlexMut<CopySpace<VM>> {
if self.hi.load(Ordering::SeqCst) {
&self.copyspace1
} else {
&self.copyspace0
}
}

pub fn fromspace(&self) -> &CopySpace<VM> {
pub fn fromspace(&self) -> &ArcFlexMut<CopySpace<VM>> {
if self.hi.load(Ordering::SeqCst) {
&self.copyspace0
} else {
&self.copyspace1
}
}

pub fn tospace_mut(&mut self) -> &mut CopySpace<VM> {
if self.hi.load(Ordering::SeqCst) {
&mut self.copyspace1
} else {
&mut self.copyspace0
}
}

pub fn fromspace_mut(&mut self) -> &mut CopySpace<VM> {
if self.hi.load(Ordering::SeqCst) {
&mut self.copyspace0
} else {
&mut self.copyspace1
}
}
// ANCHOR_END: plan_space_access
}
4 changes: 2 additions & 2 deletions docs/userguide/src/tutorial/code/mygc_semispace/mutator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub fn mygc_mutator_release<VM: VMBinding>(
.plan
.downcast_ref::<MyGC<VM>>()
.unwrap()
.tospace(),
.tospace().clone().into_dyn_space(),
);
}
// ANCHOR_END: release
Expand Down Expand Up @@ -78,7 +78,7 @@ pub fn create_mygc_mutator<VM: VMBinding>(
// ANCHOR: space_mapping
space_mapping: Box::new({
let mut vec = create_space_mapping(RESERVED_ALLOCATORS, true, mygc);
vec.push((AllocatorSelector::BumpPointer(0), mygc.tospace()));
vec.push((AllocatorSelector::BumpPointer(0), mygc.tospace().clone().into_dyn_space()));
vec
}),
// ANCHOR_END: space_mapping
Expand Down
7 changes: 5 additions & 2 deletions docs/userguide/src/tutorial/mygc/ss/alloc.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ Change `pub struct MyGC<VM: VMBinding>` to add new instance variables.
1. Delete the existing fields in the constructor.
2. Add `pub hi: AtomicBool,`. This is a thread-safe bool, indicating which
copyspace is the tospace.
3. Add `pub copyspace0: CopySpace<VM>,`
and `pub copyspace1: CopySpace<VM>,`. These are the two copyspaces.
3. Add `pub copyspace0: ArcFlexMut<CopySpace<VM>>,`
and `pub copyspace1: ArcFlexMut<CopySpace<VM>>,`. These are the two copyspaces.
We use the type `ArcFlexMut` from `mmtk::util::rust_util::flex_mut`, which
allows us to share the reference among different types and allows us to
flexibly acquire mutable references.
4. Add `pub common: CommonPlan<VM>,`.
This holds an instance of the common plan.

Expand Down
8 changes: 5 additions & 3 deletions macros/src/has_spaces_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ pub(crate) fn generate_impl_items<'a>(
let f_ident = f.ident.as_ref().unwrap();

let visitor = quote! {
__func(&self.#f_ident);
let space = self.#f_ident.read();
__func(&*space);
};

let visitor_mut = quote! {
__func(&mut self.#f_ident);
let mut space = self.#f_ident.write();
__func(&mut *space);
};

space_visitors.push(visitor);
Expand All @@ -75,7 +77,7 @@ pub(crate) fn generate_impl_items<'a>(
#parent_visitor
}

fn for_each_space_mut(&mut self, __func: &mut dyn FnMut(&mut dyn Space<VM>)) {
fn for_each_space_mut(&self, __func: &mut dyn FnMut(&mut dyn Space<VM>)) {
#(#space_visitors_mut)*
#parent_visitor_mut
}
Expand Down
41 changes: 29 additions & 12 deletions macros/src/plan_trace_object_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ pub(crate) fn generate_trace_object<'a>(
// Generate a check with early return for each space
let space_field_handler = space_fields.iter().map(|f| {
let f_ident = f.ident.as_ref().unwrap();
let f_ty = &f.ty;

// Figure out copy
let maybe_copy_semantics_attr = util::get_field_attribute(f, "copy_semantics");
Expand All @@ -71,8 +70,11 @@ pub(crate) fn generate_trace_object<'a>(
};

quote! {
if self.#f_ident.in_space(__mmtk_objref) {
return <#f_ty as PolicyTraceObject #ty_generics>::trace_object::<Q, KIND>(&self.#f_ident, __mmtk_queue, __mmtk_objref, #copy, __mmtk_worker);
{
let space = self.#f_ident.read();
if space.in_space(__mmtk_objref) {
return PolicyTraceObject::trace_object::<Q, KIND>(&*space, __mmtk_queue, __mmtk_objref, #copy, __mmtk_worker);
}
}
}
});
Expand Down Expand Up @@ -108,13 +110,15 @@ pub(crate) fn generate_post_scan_object<'a>(
) -> TokenStream2 {
let scan_field_handler = post_scan_object_fields.iter().map(|f| {
let f_ident = f.ident.as_ref().unwrap();
let f_ty = &f.ty;

quote! {
if self.#f_ident.in_space(__mmtk_objref) {
use crate::policy::gc_work::PolicyTraceObject;
<#f_ty as PolicyTraceObject #ty_generics>::post_scan_object(&self.#f_ident, __mmtk_objref);
return;
{
let space = self.#f_ident.read();
if space.in_space(__mmtk_objref) {
use crate::policy::gc_work::PolicyTraceObject;
PolicyTraceObject::post_scan_object(&*space, __mmtk_objref);
return;
}
}
}
});
Expand Down Expand Up @@ -148,10 +152,23 @@ pub(crate) fn generate_may_move_objects<'a>(
) -> TokenStream2 {
// If any space or the parent may move objects, the plan may move objects
let space_handlers = space_fields.iter().map(|f| {
let f_ty = &f.ty;

quote! {
|| <#f_ty as PolicyTraceObject #ty_generics>::may_move_objects::<KIND>()
use syn::{Type, PathArguments};
// We assume the space field is `ArcFlexMut<T>`
if let Type::Path(type_path) = &f.ty {
if type_path.path.segments[0].ident == "ArcFlexMut" {
if let PathArguments::AngleBracketed(angle_bracketed_args) = &type_path.path.segments[0].arguments {
let inner_type = &angle_bracketed_args.args.first().unwrap();
quote! {
|| <#inner_type as PolicyTraceObject #ty_generics>::may_move_objects::<KIND>()
}
} else {
unreachable!("Failed to get the inner type of ArcFlexMut: {:?}", f.ty)
}
} else {
panic!("Expected a space to be ArcFlexMut<T>, found {:?}", f.ty)
}
} else {
panic!("Failed to get the type of a space: {:?}", f.ty)
}
});

Expand Down
5 changes: 3 additions & 2 deletions src/memory_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ pub fn mmtk_init<VM: VMBinding>(builder: &MMTKBuilder) -> Box<MMTK<VM>> {
/// Currently we do not allow removing regions from VM space.
#[cfg(feature = "vm_space")]
pub fn set_vm_space<VM: VMBinding>(mmtk: &'static mut MMTK<VM>, start: Address, size: usize) {
unsafe { mmtk.get_plan_mut() }
.base_mut()
mmtk.get_plan()
.base()
.vm_space
.write()
.set_vm_region(start, size);
}

Expand Down
17 changes: 3 additions & 14 deletions src/mmtk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use crate::util::sanity::sanity_checker::SanityChecker;
use crate::util::statistics::stats::Stats;
use crate::vm::ReferenceGlue;
use crate::vm::VMBinding;
use std::cell::UnsafeCell;
use std::default::Default;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
Expand Down Expand Up @@ -107,7 +106,7 @@ impl Default for MMTKBuilder {
pub struct MMTK<VM: VMBinding> {
pub(crate) options: Arc<Options>,
pub(crate) state: Arc<GlobalState>,
pub(crate) plan: UnsafeCell<Box<dyn Plan<VM = VM>>>,
pub(crate) plan: Box<dyn Plan<VM = VM>>,
pub(crate) reference_processors: ReferenceProcessors,
pub(crate) finalizable_processor:
Mutex<FinalizableProcessor<<VM::VMReferenceGlue as ReferenceGlue<VM>>::FinalizableType>>,
Expand Down Expand Up @@ -198,7 +197,7 @@ impl<VM: VMBinding> MMTK<VM> {
MMTK {
options,
state,
plan: UnsafeCell::new(plan),
plan,
reference_processors: ReferenceProcessors::new(),
finalizable_processor: Mutex::new(FinalizableProcessor::<
<VM::VMReferenceGlue as ReferenceGlue<VM>>::FinalizableType,
Expand Down Expand Up @@ -339,17 +338,7 @@ impl<VM: VMBinding> MMTK<VM> {
}

pub fn get_plan(&self) -> &dyn Plan<VM = VM> {
unsafe { &**(self.plan.get()) }
}

/// Get the plan as mutable reference.
///
/// # Safety
///
/// This is unsafe because the caller must ensure that the plan is not used by other threads.
#[allow(clippy::mut_from_ref)]
pub unsafe fn get_plan_mut(&self) -> &mut dyn Plan<VM = VM> {
&mut **(self.plan.get())
&*self.plan
}

pub fn get_options(&self) -> &Options {
Expand Down
Loading