Skip to content

Commit

Permalink
Implement AllocatorInfo (#889)
Browse files Browse the repository at this point in the history
This type adds `AllocatorInfo` enum that can be used to query offset of
allocator fields for fast-path generation. Currently all bindings have
to re-declare `*Allocator` types with the same layout as in mmtk-core in
order to get offset of these fields. This enum simplifies that, all you
need to do is invoke `get_allocator_info(selector)`.
  • Loading branch information
playXE authored Aug 22, 2023
1 parent 3cfdf75 commit 9175e68
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 84 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jemalloc-sys = { version = "0.5.3", features = ["disable_initial_exec_tls"], opt
lazy_static = "1.1"
libc = "0.2"
log = { version = "0.4", features = ["max_level_trace", "release_max_level_off"] }
memoffset = "0.9"
mimalloc-sys = { version = "0.1.6", optional = true }
# MMTk macros
mmtk-macros = { version = "0.18.0", path = "macros/" }
Expand Down
1 change: 0 additions & 1 deletion src/memory_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use crate::vm::edge_shape::MemorySlice;
use crate::vm::ReferenceGlue;
use crate::vm::VMBinding;
use std::sync::atomic::Ordering;

/// Initialize an MMTk instance. A VM should call this method after creating an [`crate::MMTK`]
/// instance but before using any of the methods provided in MMTk (except `process()` and `process_bulk()`).
///
Expand Down
70 changes: 70 additions & 0 deletions src/util/alloc/allocators.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use std::mem::size_of;
use std::mem::MaybeUninit;

use memoffset::offset_of;

use crate::plan::Plan;
use crate::policy::largeobjectspace::LargeObjectSpace;
use crate::policy::marksweepspace::malloc_ms::MallocSpace;
Expand All @@ -10,6 +13,7 @@ use crate::util::alloc::MallocAllocator;
use crate::util::alloc::{Allocator, BumpAllocator, ImmixAllocator};
use crate::util::VMMutatorThread;
use crate::vm::VMBinding;
use crate::Mutator;

use super::FreeListAllocator;
use super::MarkCompactAllocator;
Expand Down Expand Up @@ -175,3 +179,69 @@ impl Default for AllocatorSelector {
AllocatorSelector::None
}
}

/// This type describes allocator information. It is used to
/// generate fast paths for the GC. All offset fields are relative to [`Mutator`](crate::Mutator).
#[repr(C, u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum AllocatorInfo {
BumpPointer { bump_pointer_offset: usize },
// FIXME: Add free-list fast-path
Unimplemented,
None,
}

impl Default for AllocatorInfo {
fn default() -> Self {
AllocatorInfo::None
}
}

impl AllocatorInfo {
/// Return an AllocatorInfo for the given allocator selector. This method is provided
/// so that VM compilers may generate allocator fast-path and load fields for the fast-path.
///
/// Arguments:
/// * `selector`: The allocator selector to query.
pub fn new<VM: VMBinding>(selector: AllocatorSelector) -> AllocatorInfo {
match selector {
AllocatorSelector::BumpPointer(index) => {
let base_offset = offset_of!(Mutator<VM>, allocators)
+ offset_of!(Allocators<VM>, bump_pointer)
+ size_of::<BumpAllocator<VM>>() * index as usize;
let bump_pointer_offset = offset_of!(BumpAllocator<VM>, bump_pointer);

AllocatorInfo::BumpPointer {
bump_pointer_offset: base_offset + bump_pointer_offset,
}
}

AllocatorSelector::Immix(index) => {
let base_offset = offset_of!(Mutator<VM>, allocators)
+ offset_of!(Allocators<VM>, immix)
+ size_of::<ImmixAllocator<VM>>() * index as usize;
let bump_pointer_offset = offset_of!(ImmixAllocator<VM>, bump_pointer);

AllocatorInfo::BumpPointer {
bump_pointer_offset: base_offset + bump_pointer_offset,
}
}

AllocatorSelector::MarkCompact(index) => {
let base_offset = offset_of!(Mutator<VM>, allocators)
+ offset_of!(Allocators<VM>, markcompact)
+ size_of::<MarkCompactAllocator<VM>>() * index as usize;
let bump_offset =
base_offset + offset_of!(MarkCompactAllocator<VM>, bump_allocator);
let bump_pointer_offset = offset_of!(BumpAllocator<VM>, bump_pointer);

AllocatorInfo::BumpPointer {
bump_pointer_offset: bump_offset + bump_pointer_offset,
}
}

AllocatorSelector::FreeList(_) => AllocatorInfo::Unimplemented,
_ => AllocatorInfo::None,
}
}
}
68 changes: 44 additions & 24 deletions src/util/alloc/bumpallocator.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use super::allocator::{align_allocation_no_fill, fill_alignment_gap};
use crate::util::Address;

use crate::util::alloc::Allocator;
Expand All @@ -17,25 +16,44 @@ const BLOCK_MASK: usize = BLOCK_SIZE - 1;
pub struct BumpAllocator<VM: VMBinding> {
/// [`VMThread`] associated with this allocator instance
pub tls: VMThread,
/// Current cursor for bump pointer
cursor: Address,
/// Limit for bump pointer
limit: Address,
/// Bump-pointer itself.
pub(in crate::util::alloc) bump_pointer: BumpPointer,
/// [`Space`](src/policy/space/Space) instance associated with this allocator instance.
space: &'static dyn Space<VM>,
/// [`Plan`] instance that this allocator instance is associated with.
plan: &'static dyn Plan<VM = VM>,
}

/// A common fast-path bump-pointer allocator shared across different allocator implementations
/// that use bump-pointer allocation.
#[repr(C)]
pub struct BumpPointer {
pub cursor: Address,
pub limit: Address,
}

impl BumpPointer {
pub const fn new(start: Address, end: Address) -> Self {
BumpPointer {
cursor: start,
limit: end,
}
}

pub fn reset(&mut self, start: Address, end: Address) {
self.cursor = start;
self.limit = end;
}
}

impl<VM: VMBinding> BumpAllocator<VM> {
pub fn set_limit(&mut self, start: Address, limit: Address) {
self.cursor = start;
self.limit = limit;
self.bump_pointer.reset(start, limit);
}

pub fn reset(&mut self) {
self.cursor = unsafe { Address::zero() };
self.limit = unsafe { Address::zero() };
let zero = unsafe { Address::zero() };
self.bump_pointer.reset(zero, zero);
}

pub fn rebind(&mut self, space: &'static dyn Space<VM>) {
Expand All @@ -44,6 +62,9 @@ impl<VM: VMBinding> BumpAllocator<VM> {
}
}

use crate::util::alloc::allocator::align_allocation_no_fill;
use crate::util::alloc::fill_alignment_gap;

impl<VM: VMBinding> Allocator<VM> for BumpAllocator<VM> {
fn get_space(&self) -> &'static dyn Space<VM> {
self.space
Expand All @@ -63,21 +84,21 @@ impl<VM: VMBinding> Allocator<VM> for BumpAllocator<VM> {

fn alloc(&mut self, size: usize, align: usize, offset: usize) -> Address {
trace!("alloc");
let result = align_allocation_no_fill::<VM>(self.cursor, align, offset);
let result = align_allocation_no_fill::<VM>(self.bump_pointer.cursor, align, offset);
let new_cursor = result + size;

if new_cursor > self.limit {
if new_cursor > self.bump_pointer.limit {
trace!("Thread local buffer used up, go to alloc slow path");
self.alloc_slow(size, align, offset)
} else {
fill_alignment_gap::<VM>(self.cursor, result);
self.cursor = new_cursor;
fill_alignment_gap::<VM>(self.bump_pointer.cursor, result);
self.bump_pointer.cursor = new_cursor;
trace!(
"Bump allocation size: {}, result: {}, new_cursor: {}, limit: {}",
size,
result,
self.cursor,
self.limit
self.bump_pointer.cursor,
self.bump_pointer.limit
);
result
}
Expand Down Expand Up @@ -108,24 +129,24 @@ impl<VM: VMBinding> Allocator<VM> for BumpAllocator<VM> {
}

trace!("alloc_slow stress_test");
let result = align_allocation_no_fill::<VM>(self.cursor, align, offset);
let result = align_allocation_no_fill::<VM>(self.bump_pointer.cursor, align, offset);
let new_cursor = result + size;

// For stress test, limit is [0, block_size) to artificially make the
// check in the fastpath (alloc()) fail. The real limit is recovered by
// adding it to the current cursor.
if new_cursor > self.cursor + self.limit.as_usize() {
if new_cursor > self.bump_pointer.cursor + self.bump_pointer.limit.as_usize() {
self.acquire_block(size, align, offset, true)
} else {
fill_alignment_gap::<VM>(self.cursor, result);
self.limit -= new_cursor - self.cursor;
self.cursor = new_cursor;
fill_alignment_gap::<VM>(self.bump_pointer.cursor, result);
self.bump_pointer.limit -= new_cursor - self.bump_pointer.cursor;
self.bump_pointer.cursor = new_cursor;
trace!(
"alloc_slow: Bump allocation size: {}, result: {}, new_cursor: {}, limit: {}",
size,
result,
self.cursor,
self.limit
self.bump_pointer.cursor,
self.bump_pointer.limit
);
result
}
Expand All @@ -144,8 +165,7 @@ impl<VM: VMBinding> BumpAllocator<VM> {
) -> Self {
BumpAllocator {
tls,
cursor: unsafe { Address::zero() },
limit: unsafe { Address::zero() },
bump_pointer: unsafe { BumpPointer::new(Address::zero(), Address::zero()) },
space,
plan,
}
Expand Down
Loading

0 comments on commit 9175e68

Please sign in to comment.