Skip to content

Commit 9175e68

Browse files
authored
Implement AllocatorInfo (#889)
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)`.
1 parent 3cfdf75 commit 9175e68

File tree

7 files changed

+177
-84
lines changed

7 files changed

+177
-84
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jemalloc-sys = { version = "0.5.3", features = ["disable_initial_exec_tls"], opt
3636
lazy_static = "1.1"
3737
libc = "0.2"
3838
log = { version = "0.4", features = ["max_level_trace", "release_max_level_off"] }
39+
memoffset = "0.9"
3940
mimalloc-sys = { version = "0.1.6", optional = true }
4041
# MMTk macros
4142
mmtk-macros = { version = "0.18.0", path = "macros/" }

src/memory_manager.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use crate::vm::edge_shape::MemorySlice;
2727
use crate::vm::ReferenceGlue;
2828
use crate::vm::VMBinding;
2929
use std::sync::atomic::Ordering;
30-
3130
/// Initialize an MMTk instance. A VM should call this method after creating an [`crate::MMTK`]
3231
/// instance but before using any of the methods provided in MMTk (except `process()` and `process_bulk()`).
3332
///

src/util/alloc/allocators.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
use std::mem::size_of;
12
use std::mem::MaybeUninit;
23

4+
use memoffset::offset_of;
5+
36
use crate::plan::Plan;
47
use crate::policy::largeobjectspace::LargeObjectSpace;
58
use crate::policy::marksweepspace::malloc_ms::MallocSpace;
@@ -10,6 +13,7 @@ use crate::util::alloc::MallocAllocator;
1013
use crate::util::alloc::{Allocator, BumpAllocator, ImmixAllocator};
1114
use crate::util::VMMutatorThread;
1215
use crate::vm::VMBinding;
16+
use crate::Mutator;
1317

1418
use super::FreeListAllocator;
1519
use super::MarkCompactAllocator;
@@ -175,3 +179,69 @@ impl Default for AllocatorSelector {
175179
AllocatorSelector::None
176180
}
177181
}
182+
183+
/// This type describes allocator information. It is used to
184+
/// generate fast paths for the GC. All offset fields are relative to [`Mutator`](crate::Mutator).
185+
#[repr(C, u8)]
186+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
187+
pub enum AllocatorInfo {
188+
BumpPointer { bump_pointer_offset: usize },
189+
// FIXME: Add free-list fast-path
190+
Unimplemented,
191+
None,
192+
}
193+
194+
impl Default for AllocatorInfo {
195+
fn default() -> Self {
196+
AllocatorInfo::None
197+
}
198+
}
199+
200+
impl AllocatorInfo {
201+
/// Return an AllocatorInfo for the given allocator selector. This method is provided
202+
/// so that VM compilers may generate allocator fast-path and load fields for the fast-path.
203+
///
204+
/// Arguments:
205+
/// * `selector`: The allocator selector to query.
206+
pub fn new<VM: VMBinding>(selector: AllocatorSelector) -> AllocatorInfo {
207+
match selector {
208+
AllocatorSelector::BumpPointer(index) => {
209+
let base_offset = offset_of!(Mutator<VM>, allocators)
210+
+ offset_of!(Allocators<VM>, bump_pointer)
211+
+ size_of::<BumpAllocator<VM>>() * index as usize;
212+
let bump_pointer_offset = offset_of!(BumpAllocator<VM>, bump_pointer);
213+
214+
AllocatorInfo::BumpPointer {
215+
bump_pointer_offset: base_offset + bump_pointer_offset,
216+
}
217+
}
218+
219+
AllocatorSelector::Immix(index) => {
220+
let base_offset = offset_of!(Mutator<VM>, allocators)
221+
+ offset_of!(Allocators<VM>, immix)
222+
+ size_of::<ImmixAllocator<VM>>() * index as usize;
223+
let bump_pointer_offset = offset_of!(ImmixAllocator<VM>, bump_pointer);
224+
225+
AllocatorInfo::BumpPointer {
226+
bump_pointer_offset: base_offset + bump_pointer_offset,
227+
}
228+
}
229+
230+
AllocatorSelector::MarkCompact(index) => {
231+
let base_offset = offset_of!(Mutator<VM>, allocators)
232+
+ offset_of!(Allocators<VM>, markcompact)
233+
+ size_of::<MarkCompactAllocator<VM>>() * index as usize;
234+
let bump_offset =
235+
base_offset + offset_of!(MarkCompactAllocator<VM>, bump_allocator);
236+
let bump_pointer_offset = offset_of!(BumpAllocator<VM>, bump_pointer);
237+
238+
AllocatorInfo::BumpPointer {
239+
bump_pointer_offset: bump_offset + bump_pointer_offset,
240+
}
241+
}
242+
243+
AllocatorSelector::FreeList(_) => AllocatorInfo::Unimplemented,
244+
_ => AllocatorInfo::None,
245+
}
246+
}
247+
}

src/util/alloc/bumpallocator.rs

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use super::allocator::{align_allocation_no_fill, fill_alignment_gap};
21
use crate::util::Address;
32

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

27+
/// A common fast-path bump-pointer allocator shared across different allocator implementations
28+
/// that use bump-pointer allocation.
29+
#[repr(C)]
30+
pub struct BumpPointer {
31+
pub cursor: Address,
32+
pub limit: Address,
33+
}
34+
35+
impl BumpPointer {
36+
pub const fn new(start: Address, end: Address) -> Self {
37+
BumpPointer {
38+
cursor: start,
39+
limit: end,
40+
}
41+
}
42+
43+
pub fn reset(&mut self, start: Address, end: Address) {
44+
self.cursor = start;
45+
self.limit = end;
46+
}
47+
}
48+
3049
impl<VM: VMBinding> BumpAllocator<VM> {
3150
pub fn set_limit(&mut self, start: Address, limit: Address) {
32-
self.cursor = start;
33-
self.limit = limit;
51+
self.bump_pointer.reset(start, limit);
3452
}
3553

3654
pub fn reset(&mut self) {
37-
self.cursor = unsafe { Address::zero() };
38-
self.limit = unsafe { Address::zero() };
55+
let zero = unsafe { Address::zero() };
56+
self.bump_pointer.reset(zero, zero);
3957
}
4058

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

65+
use crate::util::alloc::allocator::align_allocation_no_fill;
66+
use crate::util::alloc::fill_alignment_gap;
67+
4768
impl<VM: VMBinding> Allocator<VM> for BumpAllocator<VM> {
4869
fn get_space(&self) -> &'static dyn Space<VM> {
4970
self.space
@@ -63,21 +84,21 @@ impl<VM: VMBinding> Allocator<VM> for BumpAllocator<VM> {
6384

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

69-
if new_cursor > self.limit {
90+
if new_cursor > self.bump_pointer.limit {
7091
trace!("Thread local buffer used up, go to alloc slow path");
7192
self.alloc_slow(size, align, offset)
7293
} else {
73-
fill_alignment_gap::<VM>(self.cursor, result);
74-
self.cursor = new_cursor;
94+
fill_alignment_gap::<VM>(self.bump_pointer.cursor, result);
95+
self.bump_pointer.cursor = new_cursor;
7596
trace!(
7697
"Bump allocation size: {}, result: {}, new_cursor: {}, limit: {}",
7798
size,
7899
result,
79-
self.cursor,
80-
self.limit
100+
self.bump_pointer.cursor,
101+
self.bump_pointer.limit
81102
);
82103
result
83104
}
@@ -108,24 +129,24 @@ impl<VM: VMBinding> Allocator<VM> for BumpAllocator<VM> {
108129
}
109130

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

114135
// For stress test, limit is [0, block_size) to artificially make the
115136
// check in the fastpath (alloc()) fail. The real limit is recovered by
116137
// adding it to the current cursor.
117-
if new_cursor > self.cursor + self.limit.as_usize() {
138+
if new_cursor > self.bump_pointer.cursor + self.bump_pointer.limit.as_usize() {
118139
self.acquire_block(size, align, offset, true)
119140
} else {
120-
fill_alignment_gap::<VM>(self.cursor, result);
121-
self.limit -= new_cursor - self.cursor;
122-
self.cursor = new_cursor;
141+
fill_alignment_gap::<VM>(self.bump_pointer.cursor, result);
142+
self.bump_pointer.limit -= new_cursor - self.bump_pointer.cursor;
143+
self.bump_pointer.cursor = new_cursor;
123144
trace!(
124145
"alloc_slow: Bump allocation size: {}, result: {}, new_cursor: {}, limit: {}",
125146
size,
126147
result,
127-
self.cursor,
128-
self.limit
148+
self.bump_pointer.cursor,
149+
self.bump_pointer.limit
129150
);
130151
result
131152
}
@@ -144,8 +165,7 @@ impl<VM: VMBinding> BumpAllocator<VM> {
144165
) -> Self {
145166
BumpAllocator {
146167
tls,
147-
cursor: unsafe { Address::zero() },
148-
limit: unsafe { Address::zero() },
168+
bump_pointer: unsafe { BumpPointer::new(Address::zero(), Address::zero()) },
149169
space,
150170
plan,
151171
}

0 commit comments

Comments
 (0)