Skip to content

Commit 1b481f7

Browse files
authored
Gencopy LOS nursery allocation (#380)
1 parent 4ca3d2b commit 1b481f7

File tree

14 files changed

+85
-48
lines changed

14 files changed

+85
-48
lines changed

src/plan/barriers.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ impl Barrier for NoBarrier {
3737
pub struct ObjectRememberingBarrier<E: ProcessEdgesWork> {
3838
mmtk: &'static MMTK<E::VM>,
3939
modbuf: Vec<ObjectReference>,
40+
/// The metadata used for log bit. Though this allows taking an arbitrary metadata spec,
41+
/// for this field, 0 means logged, and 1 means unlogged (the same as the vm::object_model::VMGlobalLogBitSpec).
4042
meta: MetadataSpec,
4143
}
4244

@@ -52,6 +54,7 @@ impl<E: ProcessEdgesWork> ObjectRememberingBarrier<E> {
5254

5355
#[inline(always)]
5456
fn enqueue_node<VM: VMBinding>(&mut self, obj: ObjectReference) {
57+
// If the objecct is unlogged, log it and push it to mod buffer
5558
if compare_exchange_metadata::<VM>(
5659
&self.meta,
5760
obj,

src/plan/gencopy/gc_work.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use crate::policy::space::Space;
77
use crate::scheduler::gc_work::*;
88
use crate::scheduler::WorkerLocal;
99
use crate::util::alloc::{Allocator, BumpAllocator};
10-
use crate::util::metadata::store_metadata;
1110
use crate::util::object_forwarding;
1211
use crate::util::opaque_pointer::*;
1312
use crate::util::{Address, ObjectReference};
@@ -57,13 +56,7 @@ impl<VM: VMBinding> CopyContext for GenCopyCopyContext<VM> {
5756
) {
5857
object_forwarding::clear_forwarding_bits::<VM>(obj);
5958
if !super::NO_SLOW && super::ACTIVE_BARRIER == BarrierSelector::ObjectBarrier {
60-
store_metadata::<VM>(
61-
&VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC,
62-
obj,
63-
0b1,
64-
None,
65-
Some(Ordering::SeqCst),
66-
);
59+
VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::<VM>(obj, Ordering::SeqCst);
6760
}
6861
}
6962
}
@@ -120,6 +113,14 @@ impl<VM: VMBinding> ProcessEdgesWork for GenCopyNurseryProcessEdges<VM> {
120113
unsafe { self.worker().local::<GenCopyCopyContext<VM>>() },
121114
);
122115
}
116+
// We may alloc large object into LOS as nursery objects. Trace them here.
117+
if self.gencopy().common.get_los().in_space(object) {
118+
return self
119+
.gencopy()
120+
.common
121+
.get_los()
122+
.trace_object::<Self>(self, object);
123+
}
123124
debug_assert!(!self.gencopy().fromspace().in_space(object));
124125
debug_assert!(self.gencopy().tospace().in_space(object));
125126
object

src/plan/gencopy/global.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,12 @@ pub const GENCOPY_CONSTRAINTS: PlanConstraints = PlanConstraints {
4848
gc_header_bits: 2,
4949
gc_header_words: 0,
5050
num_specialized_scans: 1,
51+
needs_log_bit: true,
5152
barrier: super::ACTIVE_BARRIER,
52-
// TODO: We should use MAX_NON_LOS_ALLOC_BYTES_COPYING_PLAN which will allocate
53-
// large objects directly to LOS. However, there are bugs in gencopy that prevents us doing it.
54-
// I will do a separate PR to fix it.
55-
// max_non_los_default_alloc_bytes: crate::util::rust_util::min_of_usize(
56-
// crate::plan::plan_constraints::MAX_NON_LOS_ALLOC_BYTES_COPYING_PLAN,
57-
// crate::util::options::NURSERY_SIZE,
58-
// ),
59-
max_non_los_default_alloc_bytes: crate::util::options::NURSERY_SIZE,
53+
max_non_los_default_alloc_bytes: crate::util::rust_util::min_of_usize(
54+
crate::plan::plan_constraints::MAX_NON_LOS_ALLOC_BYTES_COPYING_PLAN,
55+
crate::util::options::NURSERY_SIZE,
56+
),
6057
..PlanConstraints::default()
6158
};
6259

@@ -153,9 +150,10 @@ impl<VM: VMBinding> Plan for GenCopy<VM> {
153150
}
154151

155152
fn prepare(&mut self, tls: VMWorkerThread) {
156-
self.common.prepare(tls, true);
153+
let full_heap = !self.is_current_gc_nursery();
154+
self.common.prepare(tls, full_heap);
157155
self.nursery.prepare(true);
158-
if !self.is_current_gc_nursery() {
156+
if full_heap {
159157
self.hi
160158
.store(!self.hi.load(Ordering::SeqCst), Ordering::SeqCst); // flip the semi-spaces
161159
}
@@ -165,9 +163,10 @@ impl<VM: VMBinding> Plan for GenCopy<VM> {
165163
}
166164

167165
fn release(&mut self, tls: VMWorkerThread) {
168-
self.common.release(tls, true);
166+
let full_heap = !self.is_current_gc_nursery();
167+
self.common.release(tls, full_heap);
169168
self.nursery.release();
170-
if !self.is_current_gc_nursery() {
169+
if full_heap {
171170
self.fromspace().release();
172171
}
173172

src/plan/plan_constraints.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub struct PlanConstraints {
1919
/// Size (in bytes) beyond which copied objects must be copied to the LOS.
2020
/// This depends on the copy allocator.
2121
pub max_non_los_copy_bytes: usize,
22+
/// Does this plan use the log bit? See vm::ObjectModel::GLOBAL_LOG_BIT_SPEC.
23+
pub needs_log_bit: bool,
2224
/// Some plans may allow benign race for testing mark bit, and this will lead to trace the same edges
2325
/// multiple times. If a plan allows tracing duplicate edges, we will not run duplicate edge check
2426
/// in extreme_assertions.
@@ -45,6 +47,7 @@ impl PlanConstraints {
4547
generate_gc_trace: false,
4648
may_trace_duplicate_edges: false,
4749
needs_forward_after_liveness: false,
50+
needs_log_bit: false,
4851
barrier: BarrierSelector::NoBarrier,
4952
}
5053
}

src/policy/copyspace.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ impl<VM: VMBinding> CopySpace<VM> {
9696
name,
9797
movable: true,
9898
immortal: false,
99+
needs_log_bit: false,
99100
zeroed,
100101
vmrequest,
101102
side_metadata_specs: SideMetadataContext {

src/policy/immortalspace.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ impl<VM: VMBinding> SFT for ImmortalSpace<VM> {
6969
None,
7070
Some(Ordering::SeqCst),
7171
);
72+
73+
if self.common.needs_log_bit {
74+
VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::<VM>(object, Ordering::SeqCst);
75+
}
7276
}
7377
}
7478

@@ -104,13 +108,14 @@ impl<VM: VMBinding> ImmortalSpace<VM> {
104108
vm_map: &'static VMMap,
105109
mmapper: &'static Mmapper,
106110
heap: &mut HeapMeta,
107-
_constraints: &'static PlanConstraints,
111+
constraints: &'static PlanConstraints,
108112
) -> Self {
109113
let common = CommonSpace::new(
110114
SpaceOptions {
111115
name,
112116
movable: false,
113117
immortal: true,
118+
needs_log_bit: constraints.needs_log_bit,
114119
zeroed,
115120
vmrequest,
116121
side_metadata_specs: SideMetadataContext {

src/policy/largeobjectspace.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ impl<VM: VMBinding> SFT for LargeObjectSpace<VM> {
6969
Some(Ordering::SeqCst),
7070
);
7171

72+
if self.common.needs_log_bit {
73+
VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::<VM>(object, Ordering::SeqCst);
74+
}
75+
7276
let cell = VM::VMObjectModel::object_start_ref(object);
7377
self.treadmill.add_to_treadmill(cell, alloc);
7478
}
@@ -84,7 +88,9 @@ impl<VM: VMBinding> Space<VM> for LargeObjectSpace<VM> {
8488
fn get_page_resource(&self) -> &dyn PageResource<VM> {
8589
&self.pr
8690
}
87-
fn init(&mut self, _vm_map: &'static VMMap) {}
91+
fn init(&mut self, _vm_map: &'static VMMap) {
92+
self.common().init(self.as_space());
93+
}
8894

8995
fn common(&self) -> &CommonSpace<VM> {
9096
&self.common
@@ -105,7 +111,7 @@ impl<VM: VMBinding> LargeObjectSpace<VM> {
105111
vm_map: &'static VMMap,
106112
mmapper: &'static Mmapper,
107113
heap: &mut HeapMeta,
108-
_constraints: &'static PlanConstraints,
114+
constraints: &'static PlanConstraints,
109115
protect_memory_on_release: bool,
110116
) -> Self {
111117
let common = CommonSpace::new(
@@ -114,6 +120,7 @@ impl<VM: VMBinding> LargeObjectSpace<VM> {
114120
movable: false,
115121
immortal: false,
116122
zeroed,
123+
needs_log_bit: constraints.needs_log_bit,
117124
vmrequest,
118125
side_metadata_specs: SideMetadataContext {
119126
global: global_side_metadata_specs,

src/policy/space.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,10 @@ pub struct CommonSpace<VM: VMBinding> {
482482

483483
pub metadata: SideMetadataContext,
484484

485+
/// This field equals to needs_log_bit in the plan constraints.
486+
// TODO: This should be a constant for performance.
487+
pub needs_log_bit: bool,
488+
485489
p: PhantomData<VM>,
486490
}
487491

@@ -490,6 +494,7 @@ pub struct SpaceOptions {
490494
pub movable: bool,
491495
pub immortal: bool,
492496
pub zeroed: bool,
497+
pub needs_log_bit: bool,
493498
pub vmrequest: VMRequest,
494499
pub side_metadata_specs: SideMetadataContext,
495500
}
@@ -517,6 +522,7 @@ impl<VM: VMBinding> CommonSpace<VM> {
517522
head_discontiguous_region: unsafe { Address::zero() },
518523
vm_map,
519524
mmapper,
525+
needs_log_bit: opt.needs_log_bit,
520526
metadata: opt.side_metadata_specs,
521527
p: PhantomData,
522528
};

src/util/metadata/log_bit.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use crate::util::metadata::*;
2+
use crate::util::ObjectReference;
3+
use crate::vm::VMBinding;
4+
use crate::vm::VMGlobalLogBitSpec;
5+
use std::sync::atomic::Ordering;
6+
7+
impl VMGlobalLogBitSpec {
8+
/// Mark the log bit as unlogged (1 means unlogged)
9+
pub fn mark_as_unlogged<VM: VMBinding>(&self, object: ObjectReference, order: Ordering) {
10+
store_metadata::<VM>(&self, object, 1, None, Some(order))
11+
}
12+
}

src/util/metadata/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,6 @@ mod global;
222222
pub mod header_metadata;
223223
pub mod side_metadata;
224224

225+
pub(crate) mod log_bit;
226+
225227
pub use global::*;

src/util/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ pub mod metadata;
4444
pub(crate) mod object_forwarding;
4545
/// MMTk command line options.
4646
pub(crate) mod options;
47+
/// Utilities funcitons for Rust
48+
pub(crate) mod rust_util;
4749
/// Sanity checker for GC.
4850
#[cfg(feature = "sanity")]
4951
pub(crate) mod sanity;

src/util/rust_util.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/// Const funciton for min value of two usize numbers.
2+
pub const fn min_of_usize(a: usize, b: usize) -> usize {
3+
if a > b {
4+
b
5+
} else {
6+
a
7+
}
8+
}

src/util/treadmill.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,24 @@ use std::sync::Mutex;
44

55
use crate::util::Address;
66

7-
#[derive(Debug)]
87
pub struct TreadMill {
98
from_space: Mutex<HashSet<Address>>,
109
to_space: Mutex<HashSet<Address>>,
1110
collect_nursery: Mutex<HashSet<Address>>,
1211
alloc_nursery: Mutex<HashSet<Address>>,
1312
}
1413

14+
impl std::fmt::Debug for TreadMill {
15+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16+
f.debug_struct("TreadMill")
17+
.field("from", &self.from_space.lock().unwrap())
18+
.field("to", &self.to_space.lock().unwrap())
19+
.field("collect_nursery", &self.collect_nursery.lock().unwrap())
20+
.field("alloc_nursery", &self.alloc_nursery.lock().unwrap())
21+
.finish()
22+
}
23+
}
24+
1525
impl TreadMill {
1626
pub fn new() -> Self {
1727
TreadMill {

src/vm/object_model.rs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -70,33 +70,11 @@ pub trait ObjectModel<VM: VMBinding> {
7070
// Any side metadata offset calculation must consider these to prevent overlaps. A binding should start their
7171
// side metadata from GLOBAL_SIDE_METADATA_VM_BASE_ADDRESS or LOCAL_SIDE_METADATA_VM_BASE_ADDRESS.
7272

73-
// --------------------------------------------------
74-
//
75-
// Global Metadata
76-
//
77-
// MMTk reserved Global side metadata offsets:
78-
//
79-
// 1 - MarkSweep Active Chunk byte:
80-
// - Offset `GLOBAL_SIDE_METADATA_BASE_ADDRESS`
81-
//
82-
// --------------------------------------------------
83-
8473
/// The metadata specification of the global log bit. 1 bit.
74+
/// Note that for this bit, 0 represents logged (default), and 1 represents unlogged.
75+
/// This bit is also referred to as unlogged bit in Java MMTk for this reason.
8576
const GLOBAL_LOG_BIT_SPEC: VMGlobalLogBitSpec;
8677

87-
// --------------------------------------------------
88-
// PolicySpecific Metadata
89-
//
90-
// MMTk reserved PolicySpecific side metadata offsets:
91-
//
92-
// 1 - MarkSweep Alloc bit:
93-
// - Offset `0x0` on 32-bits
94-
// - Offset `LOCAL_SIDE_METADATA_BASE_ADDRESS` on 64-bits
95-
// 2 - MarkSweep Active Page byte:
96-
// - Offset `Alloc bit`.offset + `Alloc bit`.metadata_address_range_size()
97-
//
98-
// --------------------------------------------------
99-
10078
/// The metadata specification for the forwarding pointer, used by copying plans. Word size.
10179
const LOCAL_FORWARDING_POINTER_SPEC: VMLocalForwardingPointerSpec;
10280
/// The metadata specification for the forwarding status bits, used by copying plans. 2 bits.

0 commit comments

Comments
 (0)