proc-macro

This commit is contained in:
playX18 2025-02-20 20:46:10 +07:00
parent 32662e9fc8
commit 6d565ad836
9 changed files with 982 additions and 16 deletions

0
.editorconfig Normal file
View file

2
Cargo.lock generated
View file

@ -1233,6 +1233,7 @@ dependencies = [
"parking_lot",
"rand",
"sysinfo 0.33.1",
"vmkit-proc",
"winapi",
]
@ -1243,6 +1244,7 @@ dependencies = [
"proc-macro2",
"quote",
"syn 2.0.98",
"synstructure",
]
[[package]]

View file

@ -7,7 +7,7 @@ edition = "2021"
proc-macro2 = "1.0.93"
quote = "1.0.38"
syn = { version = "2.0.98", features = ["full"] }
synstructure = { version = "0.13.1" }
[lib]
proc-macro = true

View file

@ -1,6 +1,591 @@
#[proc_macro]
pub fn define_options(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let _input = proc_macro2::TokenStream::from(input);
//! Proc macro to derive GCMetadata implementation for types.
proc_macro::TokenStream::new()
extern crate proc_macro;
use std::collections::HashSet;
use proc_macro::TokenStream;
use proc_macro2::{extra, Span};
use quote::quote;
use syn::{parse_macro_input, Arm, Data, DeriveInput};
use synstructure::{decl_derive, AddBounds};
struct ArrayLike {
pub length_field: Option<syn::Ident>,
/// Getter for length field.
pub length_getter: Option<syn::Expr>,
/// Setter for length field.
pub length_setter: Option<syn::Expr>,
pub element_type: syn::Type,
pub data_field: Option<syn::Ident>,
pub data_getter: Option<syn::Expr>,
pub trace: bool,
}
impl Default for ArrayLike {
fn default() -> Self {
Self {
length_field: None,
length_getter: None,
length_setter: None,
element_type: syn::parse_str("u8").unwrap(),
data_field: None,
data_getter: None,
trace: true,
}
}
}
fn find_arraylike(attrs: &[syn::Attribute]) -> syn::Result<Option<ArrayLike>> {
let mut length_field = None;
let mut length_getter = None;
let mut length_setter = None;
let mut element_type = None;
let mut data_field = None;
let mut data_getter = None;
let mut trace = None;
let mut has = false;
for attr in attrs.iter() {
if attr.meta.path().is_ident("arraylike") {
has = true;
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("trace") {
let value = meta.value()?.parse::<syn::LitBool>()?;
if value.value() {
trace = Some(true);
} else {
trace = Some(false);
}
}
if meta.path.is_ident("len") {
if length_field.is_some() || length_getter.is_some() || length_setter.is_some()
{
return Err(meta.error("multiple length fields found"));
}
// parse `len = field` or `len(getter = field)` or `len(setter = field)`
if meta.input.peek(syn::Token![=]) {
meta.input.parse::<syn::Token![=]>()?;
let field = meta.input.parse::<syn::Ident>()?;
if length_field.is_some() {
return Err(meta.error("multiple length fields found"));
}
length_field = Some(field);
} else if meta.input.peek(syn::token::Paren) {
meta.parse_nested_meta(|meta| {
if meta.path.is_ident("get") {
if length_getter.is_some() {
return Err(meta.error("multiple length getters found"));
}
let field = meta.input.parse::<syn::Expr>()?;
length_getter = Some(field);
} else if meta.path.is_ident("set") {
if length_setter.is_some() {
return Err(meta.error("multiple length setters found"));
}
let field = meta.input.parse::<syn::Expr>()?;
length_setter = Some(field);
} else {
return Err(meta.error("unknown length field"));
}
Ok(())
})?;
} else {
return Err(meta.error("unknown length attribute for #[arraylike]"));
}
}
if meta.path.is_ident("data") {
if data_field.is_some() || data_getter.is_some() {
return Err(meta.error("multiple data fields found"));
}
if meta.input.peek(syn::token::Paren) {
meta.parse_nested_meta(|meta| {
if meta.path.is_ident("get") {
if data_getter.is_some() {
return Err(meta.error("multiple data getters found"));
}
let field = meta.input.parse::<syn::Expr>()?;
data_getter = Some(field);
} else {
return Err(meta.error("unknown data field"));
}
Ok(())
})?;
} else {
let field = meta.input.parse::<syn::Ident>()?;
data_field = Some(field);
}
}
if meta.path.is_ident("data_type") {
if element_type.is_some() {
return Err(meta.error("multiple data types found"));
}
meta.input.parse::<syn::Token![=]>()?;
let field = meta.input.parse::<syn::Type>()?;
element_type = Some(field);
}
Ok(())
})?;
}
}
if has {
Ok(Some(ArrayLike {
length_field,
length_getter,
length_setter,
element_type: element_type
.ok_or_else(|| syn::Error::new(Span::call_site(), "missing data_type"))?,
data_field,
data_getter,
trace: trace.unwrap_or(true),
}))
} else {
Ok(None)
}
}
enum ObjectAlignment {
Auto,
Const(syn::Expr),
Compute(syn::Expr),
}
enum ObjectSize {
Auto,
Size(syn::Expr),
Compute(syn::Expr),
}
enum ObjectTrace {
NoTrace,
Auto(bool),
Trace(bool, syn::Expr),
}
struct GCMetadata {
vm: syn::Type,
alignment: ObjectAlignment,
size: ObjectSize,
trace: ObjectTrace,
}
fn find_gcmetadata(attrs: &[syn::Attribute]) -> syn::Result<GCMetadata> {
let mut vm = None;
let mut alignment = None;
let mut size = None;
let mut trace = None;
let mut has = false;
for attr in attrs.iter() {
if attr.meta.path().is_ident("gcmetadata") {
has = true;
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("vm") {
if vm.is_some() {
return Err(meta.error("multiple vm fields found"));
}
meta.input.parse::<syn::Token![=]>()?;
let field = meta.input.parse::<syn::Type>()?;
vm = Some(field);
}
if meta.path.is_ident("align") {
if alignment.is_some() {
return Err(meta.error("multiple alignment fields found"));
}
if meta.input.peek(syn::token::Paren) {
let constant = meta.input.parse::<syn::Expr>()?;
alignment = Some(ObjectAlignment::Const(constant));
} else {
let _ = meta.input.parse::<syn::Token![=]>()?;
let field = meta.input.parse::<syn::Expr>()?;
alignment = Some(ObjectAlignment::Compute(field));
}
}
if meta.path.is_ident("size") {
if size.is_some() {
return Err(meta.error("multiple size fields found"));
}
if meta.input.peek(syn::token::Paren) {
let constant = meta.input.parse::<syn::Expr>()?;
size = Some(ObjectSize::Size(constant));
} else {
let _ = meta.input.parse::<syn::Token![=]>()?;
let field = meta.input.parse::<syn::Expr>()?;
size = Some(ObjectSize::Compute(field));
}
}
if meta.path.is_ident("trace") {
if trace.is_some() {
return Err(meta.error("multiple trace fields found"));
}
if meta.input.is_empty() {
trace = Some(ObjectTrace::Auto(false));
} else {
let _ = meta.input.parse::<syn::Token![=]>()?;
let field = meta.input.parse::<syn::Expr>()?;
trace = Some(ObjectTrace::Trace(false, field));
}
} else if meta.path.is_ident("notrace") {
if trace.is_some() {
return Err(meta.error("multiple trace fields found"));
}
trace = Some(ObjectTrace::NoTrace);
} else if meta.path.is_ident("scan") {
if trace.is_some() {
return Err(meta.error("multiple trace fields found"));
}
if meta.input.is_empty() {
trace = Some(ObjectTrace::Auto(true));
} else {
let _ = meta.input.parse::<syn::Token![=]>()?;
let field = meta.input.parse::<syn::Expr>()?;
trace = Some(ObjectTrace::Trace(true, field));
}
}
Ok(())
})?;
}
}
if !has {
return Err(syn::Error::new(Span::call_site(), "missing gcmetadata"));
}
let vm = vm.ok_or_else(|| syn::Error::new(Span::call_site(), "VM for object not specified"))?;
Ok(GCMetadata {
vm,
alignment: alignment.unwrap_or(ObjectAlignment::Auto),
size: size.unwrap_or(ObjectSize::Auto),
trace: trace.unwrap_or(ObjectTrace::Auto(false)),
})
}
/*
#[proc_macro_derive(GCMetadata, attributes(arraylike, gcmetadata))]
pub fn derive_gcmetadata(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let arraylike = match find_arraylike(&input.attrs) {
Ok(arraylike) => arraylike,
Err(err) => return err.to_compile_error().into(),
};
let gc_meta = match find_gcmetadata(&input.attrs) {
Ok(gc_meta) => gc_meta,
Err(err) => return err.to_compile_error().into(),
};
let mut tracer = match gc_meta.trace {
ObjectTrace::NoTrace => quote! { TraceCallback::None },
ObjectTrace::Auto(scan_slots) => {
let call = |typ: syn::Type, field: syn::Expr| {
if scan_slots {
quote! {
<#typ as vmkit::mm::traits::Scan<_>>::scan_object(&#field, visitor);
}
} else {
quote! {
<#typ as vmkit::mm::traits::Trace>::trace_object(&mut #field, visitor)
}
}
};
let mut body = TokenStream::new();
match input.data {
Data::Enum(enumeration) => {
let mut match_: syn::ExprMatch = syn::parse_quote!(
match object.as_address().as_mut_ref::<#name>() {}
);
for variant in enumeration.variants {
let ident = variant.ident.clone();
let path = quote! { #name::#ident }
}
}
Data::Struct(structure) => {
}
}
}
}
TokenStream::new()
}
*/
decl_derive!([GCMetadata,attributes(gcmetadata, arraylike, ignore_trace)] => derive_gcmetadata);
fn derive_gcmetadata(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
let gc_metadata = match find_gcmetadata(&s.ast().attrs) {
Ok(gc) => gc,
Err(err) => return err.to_compile_error(),
};
let arraylike = match find_arraylike(&s.ast().attrs) {
Ok(arraylike) => arraylike,
Err(err) => return err.to_compile_error(),
};
let vm = &gc_metadata.vm;
let name = s.ast().ident.clone();
let mut fields_to_skip = HashSet::new();
if let Some(arraylike) = arraylike.as_ref() {
if let Some(field) = &arraylike.data_field {
fields_to_skip.insert(field.clone());
}
if let Some(field) = &arraylike.length_field {
fields_to_skip.insert(field.clone());
}
}
let (trace_impl, trace_callback) = match gc_metadata.trace {
ObjectTrace::NoTrace => (None, quote! { ::vmkit::prelude::TraceCallback::None }),
ObjectTrace::Auto(scan_slots) => {
let mut filtered = s.clone();
filtered.filter(|bi| {
!bi.ast()
.attrs
.iter()
.any(|attr| attr.path().is_ident("ignore_trace"))
&& (bi.ast().ident.is_none()
|| !fields_to_skip.contains(bi.ast().ident.as_ref().unwrap()))
});
filtered.add_bounds(AddBounds::Fields);
let trace_impl = if scan_slots {
let trace_body = filtered.each(|bi| {
quote! {
mark(#bi, visitor);
}
});
let full_path = quote! { <#vm as vmkit::VirtualMachine>::Slot };
let mut extra = quote! {
fn mark<T: ::vmkit::prelude::Scan<#full_path>>(t: &T, visitor: &mut dyn ::vmkit::prelude::SlotVisitor<#full_path>) {
::vmkit::prelude::Scan::<#full_path>::scan_object(t, visitor);
}
};
if let Some(arraylike) = arraylike.as_ref().filter(|x| x.trace) {
let element = &arraylike.element_type;
let length = if let Some(getter) = &arraylike.length_getter {
quote! { #getter }
} else if let Some(field) = &arraylike.length_field {
quote! { self.#field as usize }
} else {
panic!("length field not found");
};
let data_ptr = if let Some(getter) = &arraylike.data_getter {
quote! { #getter }
} else if let Some(field) = &arraylike.data_field {
quote! { self.#field.as_mut_ptr().cast::<#element>() }
} else {
panic!("data field not found");
};
extra.extend(quote! {
let length = #length;
let data = #data_ptr;
for i in 0..length {
unsafe {
let ptr = data.add(i).as_ref().unwrap();
::vmkit::prelude::Scan::<#full_path>::scan_object(ptr, visitor);
}
}
});
}
filtered.bound_impl(
quote! {::vmkit::prelude::Scan<#full_path> },
quote! {
#[inline]
fn scan_object(&self, visitor: &mut dyn ::vmkit::prelude::SlotVisitor<#full_path>) {
let this = self;
#extra
match *self { #trace_body }
}
}
)
} else {
filtered.bind_with(|_| synstructure::BindStyle::RefMut);
let trace_body = filtered.each(|bi| {
quote! {
mark(#bi, visitor);
}
});
let mut extra = quote! {
#[inline]
fn mark<T: ::vmkit::prelude::Trace>(t: &mut T, visitor: &mut dyn ::vmkit::prelude::ObjectTracer) {
::vmkit::prelude::Trace::trace_object(t, visitor);
}
};
if let Some(arraylike) = arraylike.as_ref().filter(|x| x.trace) {
let element = &arraylike.element_type;
let length = if let Some(getter) = &arraylike.length_getter {
quote! { #getter }
} else if let Some(field) = &arraylike.length_field {
quote! { self.#field as usize }
} else {
panic!("length field not found");
};
let data_ptr = if let Some(getter) = &arraylike.data_getter {
quote! { #getter }
} else if let Some(field) = &arraylike.data_field {
quote! { self.#field.as_mut_ptr().cast::<#element>() }
} else {
panic!("data field not found");
};
extra.extend(quote! {
let length = #length;
let data = #data_ptr;
for i in 0..length {
unsafe {
let ptr = data.add(i).as_mut().unwrap();
::vmkit::prelude::Trace::trace_object(ptr, visitor);
}
}
});
}
filtered.bound_impl(
quote! {::vmkit::prelude::Trace },
quote! {
#[inline]
fn trace_object(&mut self, visitor: &mut dyn ::vmkit::prelude::ObjectTracer) {
match *self { #trace_body };
let this = self;
#extra
}
}
)
};
(Some(trace_impl), if scan_slots {
let full_path = quote! { <#vm as vmkit::VirtualMachine>::Slot };
quote! { ::vmkit::prelude::TraceCallback::ScanSlots(|object, visitor| unsafe {
let object = object.as_address().as_ref::<#name>();
::vmkit::prelude::Scan::<#full_path>::scan_object(object, visitor);
}) }
} else {
quote! { ::vmkit::prelude::TraceCallback::TraceObject(|object, visitor| unsafe {
let object = object.as_address().as_mut_ref::<#name>();
::vmkit::prelude::Trace::trace_object(object, visitor);
}) }
})
}
ObjectTrace::Trace(scan_slots, expr) => {
if scan_slots {
(None, quote! {
::vmkit::prelude::TraceCallback::ScanSlots(|object, visitor| unsafe {
let this = object.as_address().as_ref::<#name>();
#expr
})
})
} else {
(None, quote! {
::vmkit::prelude::TraceCallback::TraceObject(|object, visitor| unsafe {
let this = object.as_address().as_mut_ref::<#name>();
#expr
})
})
}
}
,
};
let instance_size = match &gc_metadata.size {
ObjectSize::Auto if arraylike.is_some() => quote! { 0 },
ObjectSize::Size(_) if arraylike.is_some() => quote! { 0 },
ObjectSize::Compute(_) => quote! { 0 },
ObjectSize::Auto => quote! { ::std::mem::size_of::<#name>() },
ObjectSize::Size(size) => quote! { #size },
};
let alignment = match &gc_metadata.alignment {
ObjectAlignment::Auto => quote! { ::std::mem::align_of::<#name>() },
ObjectAlignment::Const(expr) => quote! { #expr },
ObjectAlignment::Compute(_) => quote! { 0 },
};
let compute_size = if let Some(arraylike) = arraylike.as_ref() {
match gc_metadata.size {
ObjectSize::Compute(expr) => quote! { Some(|object| unsafe {
let this = object.as_address().as_ref::<#name>();
#expr
}) },
_ => {
let length = if let Some(getter) = &arraylike.length_getter {
quote! { #getter }
} else if let Some(field) = &arraylike.length_field {
quote! { this.#field as usize }
} else {
panic!("length field not found");
};
let element = &arraylike.element_type;
quote! { Some(|object| unsafe {
let this = object.as_address().as_ref::<#name>();
let length = #length;
size_of::<#name>() + (length * ::std::mem::size_of::<#element>())
}) }
}
}
} else {
match gc_metadata.size {
ObjectSize::Compute(expr) => quote! { Some(|object| unsafe {
let this = object.as_address().as_ref::<#name>();
#expr
}) },
_ => quote! { None },
}
};
let mut output = quote! {
impl #name {
pub fn gc_metadata() -> &'static ::vmkit::prelude::GCMetadata<#vm> {
static METADATA: ::vmkit::prelude::GCMetadata<#vm> = ::vmkit::prelude::GCMetadata {
trace: #trace_callback,
instance_size: #instance_size,
compute_size: #compute_size,
alignment: #alignment,
compute_alignment: None,
};
&METADATA
}
}
};
if let Some(trace_impl) = trace_impl {
output.extend(trace_impl);
}
output.into()
}

View file

@ -1,3 +0,0 @@
fn main() {
println!("Hello, world!");
}

View file

@ -17,14 +17,15 @@ mmtk = { git = "https://github.com/mmtk/mmtk-core" }
parking_lot = "0.12.3"
rand = "0.9.0"
sysinfo = "0.33.1"
vmkit-proc = { path = "../vmkit-proc", optional = true }
[features]
default = ["cooperative", "address_based_hashing", "object_pinning"]
default = ["cooperative", "address_based_hashing", "object_pinning", "derive"]
vmside_forwarding = []
derive = ["vmkit-proc"]
object_pinning = ["mmtk/object_pinning"]
address_based_hashing = []
uncooperative = ["cooperative", "mmtk/immix_non_moving", "mmtk/immix_zero_on_release"]

View file

@ -216,3 +216,15 @@ impl<VM: VirtualMachine> VMKit<VM> {
&self.thread_manager
}
}
#[cfg(feature="derive")]
pub use vmkit_proc::GCMetadata;
pub mod prelude {
pub use super::GCMetadata;
pub use super::mm::traits::*;
pub use super::object_model::object::*;
pub use super::object_model::metadata::*;
pub use mmtk::vm::ObjectTracer;
pub use mmtk::vm::SlotVisitor;
}

View file

@ -1,9 +1,276 @@
use easy_bitfield::BitFieldTrait;
use vmkit::object_model::header::{HashState, HashStateField};
use mmtk::util::Address;
use mmtk::vm::slot::UnimplementedMemorySlice;
use mmtk::{util::options::PlanSelector, vm::slot::SimpleSlot, AllocationSemantics, MMTKBuilder};
use vmkit::GCMetadata;
use std::cell::RefCell;
use std::mem::offset_of;
use std::sync::Arc;
use std::sync::OnceLock;
use vmkit::threading::parked_scope;
use vmkit::{
mm::{traits::Trace, MemoryManager},
object_model::{
metadata::{GCMetadata, TraceCallback},
object::VMKitObject,
},
sync::Monitor,
threading::{GCBlockAdapter, Thread, ThreadContext},
VMKit, VirtualMachine,
};
#[repr(C)]
struct Node {
left: NodeRef,
right: NodeRef,
}
static METADATA: GCMetadata<BenchVM> = GCMetadata {
trace: TraceCallback::TraceObject(|object, tracer| unsafe {
let node = object.as_address().as_mut_ref::<Node>();
node.left.0.trace_object(tracer);
node.right.0.trace_object(tracer);
}),
instance_size: size_of::<Node>(),
compute_size: None,
alignment: 16,
compute_alignment: None,
};
struct BenchVM {
vmkit: VMKit<Self>,
}
static VM: OnceLock<BenchVM> = OnceLock::new();
struct ThreadBenchContext;
impl ThreadContext<BenchVM> for ThreadBenchContext {
fn new(_: bool) -> Self {
Self
}
fn save_thread_state(&self) {}
fn scan_roots(
&self,
_factory: impl mmtk::vm::RootsWorkFactory<<BenchVM as VirtualMachine>::Slot>,
) {
}
fn scan_conservative_roots(
&self,
_croots: &mut vmkit::mm::conservative_roots::ConservativeRoots,
) {
}
}
impl VirtualMachine for BenchVM {
type BlockAdapterList = (GCBlockAdapter, ());
type Metadata = &'static GCMetadata<Self>;
type Slot = SimpleSlot;
type ThreadContext = ThreadBenchContext;
type MemorySlice = UnimplementedMemorySlice;
#[cfg(feature="vmside_forwarding")]
const LOCAL_FORWARDING_POINTER_SPEC: mmtk::vm::VMLocalForwardingPointerSpec = mmtk::vm::VMLocalForwardingPointerSpec::in_header(0);
#[cfg(feature="vmside_forwarding")]
const LOCAL_FORWARDING_BITS_SPEC: mmtk::vm::VMLocalForwardingBitsSpec = mmtk::vm::VMLocalForwardingBitsSpec::in_header(62);
fn get() -> &'static Self {
VM.get().unwrap()
}
fn vmkit(&self) -> &VMKit<Self> {
&self.vmkit
}
fn prepare_for_roots_re_scanning() {}
fn notify_initial_thread_scan_complete(partial_scan: bool, tls: mmtk::util::VMWorkerThread) {
let _ = partial_scan;
let _ = tls;
}
fn forward_weak_refs(
_worker: &mut mmtk::scheduler::GCWorker<vmkit::mm::MemoryManager<Self>>,
_tracer_context: impl mmtk::vm::ObjectTracerContext<vmkit::mm::MemoryManager<Self>>,
) {
}
fn scan_roots_in_mutator_thread(
_tls: mmtk::util::VMWorkerThread,
_mutator: &'static mut mmtk::Mutator<vmkit::mm::MemoryManager<Self>>,
_factory: impl mmtk::vm::RootsWorkFactory<
<vmkit::mm::MemoryManager<Self> as mmtk::vm::VMBinding>::VMSlot,
>,
) {
}
fn scan_vm_specific_roots(
_tls: mmtk::util::VMWorkerThread,
_factory: impl mmtk::vm::RootsWorkFactory<
<vmkit::mm::MemoryManager<Self> as mmtk::vm::VMBinding>::VMSlot,
>,
) {
}
}
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)]
struct NodeRef(VMKitObject);
impl NodeRef {
pub fn new(thread: &Thread<BenchVM>, left: NodeRef, right: NodeRef) -> Self {
let node = MemoryManager::<BenchVM>::allocate(
thread,
size_of::<Node>(),
32,
&METADATA,
AllocationSemantics::Default,
);
//node.hashcode::<BenchVM>();
node.set_field_object::<BenchVM, false>(offset_of!(Node, left), left.0);
node.set_field_object::<BenchVM, false>(offset_of!(Node, right), right.0);
Self(node)
}
pub fn left(self) -> NodeRef {
unsafe {
let node = self.0.as_address().as_ref::<Node>();
node.left
}
}
pub fn right(self) -> NodeRef {
unsafe {
let node = self.0.as_address().as_ref::<Node>();
node.right
}
}
pub fn null() -> Self {
Self(VMKitObject::NULL)
}
pub fn item_check(&self) -> usize {
if self.left() == NodeRef::null() {
1
} else {
1 + self.left().item_check() + self.right().item_check()
}
}
pub fn leaf(thread: &Thread<BenchVM>) -> Self {
Self::new(thread, NodeRef::null(), NodeRef::null())
}
}
fn bottom_up_tree(thread: &Thread<BenchVM>, depth: usize) -> NodeRef {
if thread.take_yieldpoint() != 0 {
Thread::<BenchVM>::yieldpoint(0, Address::ZERO);
}
if depth > 0 {
NodeRef::new(
thread,
bottom_up_tree(thread, depth - 1),
bottom_up_tree(thread, depth - 1),
)
} else {
NodeRef::leaf(thread)
}
}
const MIN_DEPTH: usize = 4;
#[derive(GCMetadata)]
#[gcmetadata(
vm = BenchVM,
scan
)]
enum Object {
Fixnum(#[ignore_trace] i32),
Boxed(VMKitObject)
}
fn main() {
let encoded = HashStateField::encode(HashState::HashedAndMoved);
println!("{:x}", encoded);
println!("{}", HashStateField::NEXT_BIT);
println!("{:?}", HashStateField::decode(encoded));
env_logger::init();
let nthreads = std::env::var("THREADS")
.unwrap_or("4".to_string())
.parse::<usize>()
.unwrap();
let mut builder = MMTKBuilder::new();
builder.options.plan.set(PlanSelector::StickyImmix);
builder.options.threads.set(nthreads);
VM.set(BenchVM {
vmkit: VMKit::new(&mut builder),
})
.unwrap_or_else(|_| panic!());
Thread::<BenchVM>::main(ThreadBenchContext, || {
let thread = Thread::<BenchVM>::current();
let start = std::time::Instant::now();
let n = std::env::var("DEPTH")
.unwrap_or("18".to_string())
.parse::<usize>()
.unwrap();
let max_depth = if n < MIN_DEPTH + 2 { MIN_DEPTH + 2 } else { n };
let stretch_depth = max_depth + 1;
println!("stretch tree of depth {stretch_depth}");
let _ = bottom_up_tree(&thread, stretch_depth);
let duration = start.elapsed();
println!("time: {duration:?}");
let results = Arc::new(Monitor::new(vec![
RefCell::new(String::new());
(max_depth - MIN_DEPTH) / 2 + 1
]));
let mut handles = Vec::new();
for d in (MIN_DEPTH..=max_depth).step_by(2) {
let depth = d;
let thread = Thread::<BenchVM>::for_mutator(ThreadBenchContext);
let results = results.clone();
let handle = thread.start(move || {
let thread = Thread::<BenchVM>::current();
let mut check = 0;
let iterations = 1 << (max_depth - depth + MIN_DEPTH);
for _ in 1..=iterations {
let tree_node = bottom_up_tree(&thread, depth);
check += tree_node.item_check();
}
*results.lock_with_handshake::<BenchVM>()[(depth - MIN_DEPTH) / 2].borrow_mut() =
format!("{iterations}\t trees of depth {depth}\t check: {check}");
});
handles.push(handle);
}
println!("created {} threads", handles.len());
parked_scope::<(), BenchVM>(|| {
while let Some(handle) = handles.pop() {
handle.join().unwrap();
}
});
for result in results.lock_with_handshake::<BenchVM>().iter() {
println!("{}", result.borrow());
}
println!(
"long lived tree of depth {max_depth}\t check: {}",
bottom_up_tree(&thread, max_depth).item_check()
);
let duration = start.elapsed();
println!("time: {duration:?}");
});
}

View file

@ -3,6 +3,8 @@ use crate::threading::Thread;
use crate::{mm::MemoryManager, VirtualMachine};
use atomic::Atomic;
use core::ops::Range;
use std::mem::MaybeUninit;
use std::ptr::NonNull;
use mmtk::util::{
constants::LOG_BYTES_IN_ADDRESS, conversions::raw_align_up, Address, ObjectReference,
};
@ -738,3 +740,103 @@ impl<SL: SlotExtra> MemorySlice for SimpleMemorySlice<SL> {
}
}
}
pub struct GcPtr<T> {
ptr: NonNull<T>,
}
impl<T> GcPtr<T> {
pub fn new(ptr: NonNull<T>) -> Self {
Self { ptr }
}
pub fn as_ptr(&self) -> *mut T {
self.ptr.as_ptr()
}
pub fn as_ref(&self) -> &T {
unsafe { self.ptr.as_ref() }
}
pub fn as_mut(&mut self) -> &mut T {
unsafe { self.ptr.as_mut() }
}
pub fn as_address(&self) -> Address {
Address::from_mut_ptr(self.ptr.as_ptr())
}
pub fn from_address(address: Address) -> Self {
assert!(!address.is_zero());
Self {
ptr: NonNull::new(address.to_mut_ptr()).unwrap(),
}
}
pub fn from_ptr(ptr: *mut T) -> Self {
assert!(!ptr.is_null());
Self {
ptr: NonNull::new(ptr).unwrap(),
}
}
}
impl<T> GcPtr<MaybeUninit<T>> {
pub unsafe fn assume_init(self) -> GcPtr<T> {
GcPtr::new(self.ptr.cast())
}
}
impl<T> std::ops::Deref for GcPtr<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<T> std::ops::DerefMut for GcPtr<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut()
}
}
impl<T: fmt::Debug> fmt::Debug for GcPtr<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", **self)
}
}
impl<T: Hash> Hash for GcPtr<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<T: PartialEq> PartialEq for GcPtr<T> {
fn eq(&self, other: &Self) -> bool {
**self == **other
}
}
impl<T: Eq> Eq for GcPtr<T> {}
impl<T: PartialOrd> PartialOrd for GcPtr<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<T: Ord> Ord for GcPtr<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl<T> Clone for GcPtr<T> {
fn clone(&self) -> Self {
Self::new(self.ptr)
}
}
impl<T> Copy for GcPtr<T> {}