Skip to content

Commit 37c55d0

Browse files
committed
Change the way we handle generic fields table
The upstream has changed its way to handle the generic fields table. The generic_fields_tbl_ now maps each object to an imemo:fields, and the imemo:fields object will hold all the fields. We now treat the imemo:fields object as a child of its corresponding key in generic_fields_tbl_, which is just like CRuby's default GC. Like the default GC, we handle generic_fields_tbl_ like other weak tables during weak processing time. On the Rust side, we replaced the moved_gen_fields_tables hash map with a simple "backwarding table" that simply maps each moved object using generic_fields_tbl_ to its old address.
1 parent beaf504 commit 37c55d0

File tree

6 files changed

+31
-107
lines changed

6 files changed

+31
-107
lines changed

mmtk/src/abi.rs

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ pub const GC_THREAD_KIND_WORKER: libc::c_int = 1;
1111

1212
pub const HIDDEN_SIZE_MASK: usize = 0x0000FFFFFFFFFFFF;
1313

14-
// Should keep in sync with C code.
15-
const RUBY_FL_EXIVAR: usize = 1 << 10;
16-
1714
// An opaque type for the C counterpart.
1815
#[allow(non_camel_case_types)]
1916
pub struct st_table;
@@ -92,8 +89,8 @@ impl RubyObjectAccess {
9289
unsafe { self.flags_field().load::<usize>() }
9390
}
9491

95-
pub fn has_exivar_flag(&self) -> bool {
96-
(self.load_flags() & RUBY_FL_EXIVAR) != 0
92+
pub fn has_exivar(&self) -> bool {
93+
(upcalls().has_exivar)(self.objref)
9794
}
9895

9996
pub fn prefix_size() -> usize {
@@ -109,29 +106,6 @@ impl RubyObjectAccess {
109106
pub fn object_size(&self) -> usize {
110107
Self::prefix_size() + self.payload_size() + Self::suffix_size()
111108
}
112-
113-
pub fn get_gen_fields_tbl(&self) -> *mut libc::c_void {
114-
self.get_original_gen_fields_tbl()
115-
.or_else(|| {
116-
let moved_gen_fields_tables = crate::binding().moved_gen_fields_tables.lock().unwrap();
117-
moved_gen_fields_tables.get(&self.objref).map(|entry| entry.gen_fields_tbl)
118-
})
119-
.unwrap_or_else(|| {
120-
panic!(
121-
"The gen_fields_tbl of object {} is not found in generic_fields_tbl_ or binding().moved_gen_fields_tables",
122-
self.objref
123-
)
124-
})
125-
}
126-
127-
pub fn get_original_gen_fields_tbl(&self) -> Option<*mut libc::c_void> {
128-
let addr = (upcalls().get_original_gen_fields_tbl)(self.objref);
129-
if addr.is_null() {
130-
None
131-
} else {
132-
Some(addr)
133-
}
134-
}
135109
}
136110

137111
type ObjectClosureFunction =
@@ -359,11 +333,9 @@ pub struct RubyUpcalls {
359333
pub scan_object_ruby_style: extern "C" fn(object: ObjectReference),
360334
pub call_gc_mark_children: extern "C" fn(object: ObjectReference),
361335
pub call_obj_free: extern "C" fn(object: ObjectReference),
362-
pub cleanup_generic_fields_tbl: extern "C" fn(),
363-
pub get_original_gen_fields_tbl: extern "C" fn(object: ObjectReference) -> *mut libc::c_void,
364-
pub reinsert_generic_fields_tbl_entry:
365-
extern "C" fn(old_objref: ObjectReference, new_objref: ObjectReference),
366336
pub vm_live_bytes: extern "C" fn() -> usize,
337+
pub has_exivar: extern "C" fn(object: ObjectReference) -> bool,
338+
pub update_generic_fields_table: extern "C" fn(),
367339
pub update_frozen_strings_table: extern "C" fn(),
368340
pub update_finalizer_and_obj_id_tables: extern "C" fn(),
369341
pub update_global_symbols_table: extern "C" fn(),

mmtk/src/api.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use crate::abi;
99
use crate::abi::HiddenHeader;
1010
use crate::abi::RawVecOfObjRef;
1111
use crate::abi::RubyBindingOptions;
12-
use crate::abi::RubyObjectAccess;
1312
use crate::binding;
1413
use crate::binding::RubyBinding;
1514
use crate::mmtk;
@@ -320,9 +319,9 @@ pub unsafe extern "C" fn mmtk_register_ppps(objects: *const ObjectReference, len
320319
}
321320

322321
#[no_mangle]
323-
pub extern "C" fn mmtk_get_gen_fields_tbl_during_gc(object: ObjectReference) -> *mut libc::c_void {
324-
let acc = RubyObjectAccess::from_objref(object);
325-
acc.get_gen_fields_tbl()
322+
pub extern "C" fn mmtk_get_backwarded_object(object: ObjectReference) -> ObjectReference {
323+
let backwarding_table = crate::binding().backwarding_table.lock().unwrap();
324+
backwarding_table.get(&object).copied().unwrap_or(object)
326325
}
327326

328327
#[no_mangle]

mmtk/src/binding.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use std::sync::atomic::AtomicBool;
55
use std::sync::Mutex;
66
use std::thread::JoinHandle;
77

8-
use libc::c_void;
98
use mmtk::util::ObjectReference;
109
use mmtk::MMTK;
1110

@@ -49,19 +48,16 @@ impl RubyBindingFastMut {
4948
}
5049
}
5150

52-
pub(crate) struct MovedGenFieldsTablesEntry {
53-
pub old_objref: ObjectReference,
54-
pub gen_fields_tbl: *mut c_void,
55-
}
56-
5751
pub struct RubyBinding {
5852
pub mmtk: &'static MMTK<Ruby>,
5953
pub options: RubyBindingOptions,
6054
pub upcalls: *const abi::RubyUpcalls,
6155
pub plan_name: Mutex<Option<CString>>,
6256
pub weak_proc: WeakProcessor,
6357
pub ppp_registry: PPPRegistry,
64-
pub(crate) moved_gen_fields_tables: Mutex<HashMap<ObjectReference, MovedGenFieldsTablesEntry>>,
58+
/// A "backwarding" table that can look up the old addresses of some moved objects,
59+
/// specifically objects using generic fields table.
60+
pub(crate) backwarding_table: Mutex<HashMap<ObjectReference, ObjectReference>>,
6561
pub gc_thread_join_handles: Mutex<Vec<JoinHandle<()>>>,
6662
pub wb_unprotected_objects: Mutex<HashSet<ObjectReference>>,
6763
pub st_entries_chunk_size: usize,
@@ -104,7 +100,7 @@ impl RubyBinding {
104100
plan_name: Mutex::new(None),
105101
weak_proc: WeakProcessor::new(),
106102
ppp_registry: PPPRegistry::new(),
107-
moved_gen_fields_tables: Default::default(),
103+
backwarding_table: Default::default(),
108104
gc_thread_join_handles: Default::default(),
109105
wb_unprotected_objects: Default::default(),
110106
st_entries_chunk_size,

mmtk/src/collection.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::abi::GCThreadTLS;
22

33
use crate::api::RubyMutator;
4-
use crate::{mmtk, upcalls, Ruby};
4+
use crate::{binding, mmtk, upcalls, Ruby};
55
use mmtk::memory_manager;
66
use mmtk::scheduler::*;
77
use mmtk::util::{VMMutatorThread, VMThread, VMWorkerThread};
@@ -74,6 +74,14 @@ impl Collection<Ruby> for VMCollection {
7474
fn vm_live_bytes() -> usize {
7575
(upcalls().vm_live_bytes)()
7676
}
77+
78+
fn post_forwarding(_tls: VMWorkerThread) {
79+
let mut backwarding_table = binding()
80+
.backwarding_table
81+
.try_lock()
82+
.expect("Should not have race during post_forwarding");
83+
backwarding_table.clear();
84+
}
7785
}
7886

7987
impl VMCollection {

mmtk/src/object_model.rs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,7 @@ impl ObjectModel<Ruby> for VMObjectModel {
4343
copy_context: &mut GCWorkerCopyContext<Ruby>,
4444
) -> ObjectReference {
4545
let from_acc = RubyObjectAccess::from_objref(from);
46-
let maybe_gen_fields_tbl = from_acc.has_exivar_flag().then(|| {
47-
from_acc
48-
.get_original_gen_fields_tbl()
49-
.unwrap_or_else(|| panic!("Object {} has FL_EXIVAR but no gen_fields_tbl.", from))
50-
});
46+
let has_exivar = from_acc.has_exivar();
5147
let from_start = from_acc.obj_start();
5248
let object_size = from_acc.object_size();
5349
let to_start = copy_context.alloc_copy(from, object_size, MIN_OBJ_ALIGN, 0, semantics);
@@ -74,16 +70,12 @@ impl ObjectModel<Ruby> for VMObjectModel {
7470
unsafe { std::ptr::write_bytes::<u8>(from_start.to_mut_ptr(), 0, object_size) }
7571
}
7672

77-
if let Some(gen_fields_tbl) = maybe_gen_fields_tbl {
78-
let mut moved_gen_fields_tables =
79-
crate::binding().moved_gen_fields_tables.lock().unwrap();
80-
moved_gen_fields_tables.insert(
81-
to_obj,
82-
crate::binding::MovedGenFieldsTablesEntry {
83-
old_objref: from,
84-
gen_fields_tbl,
85-
},
86-
);
73+
if has_exivar {
74+
let mut backwarding_table = crate::binding().backwarding_table.lock().unwrap();
75+
trace!("Inserting into backwarding table: from: {from} <- to_obj: {to_obj}");
76+
backwarding_table.insert(to_obj, from);
77+
} else {
78+
trace!("No exivar: from: {from} <- to_obj: {to_obj}");
8779
}
8880

8981
to_obj

mmtk/src/weak_proc.rs

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use mmtk::{
88

99
use crate::{
1010
abi::{st_table, GCThreadTLS},
11-
binding::MovedGenFieldsTablesEntry,
1211
extra_assert, is_mmtk_object_safe, upcalls,
1312
utils::AfterAll,
1413
Ruby,
@@ -157,51 +156,6 @@ impl WeakProcessor {
157156

158157
worker.scheduler().work_buckets[WorkBucketStage::VMRefClosure].bulk_add(entries_packets);
159158
}
160-
161-
/// Update generic instance variable tables.
162-
///
163-
/// Objects moved during GC should have their entries in the global `generic_fields_tbl_` hash
164-
/// table updated, and dead objects should have their entries removed.
165-
fn update_generic_fields_tbl() {
166-
// Update `generic_fields_tbl_` entries for moved objects. We could update the entries in
167-
// `ObjectModel::move`. However, because `st_table` is not thread-safe, we postpone the
168-
// update until now in the VMRefClosure stage.
169-
log::debug!("Updating generic_fields_tbl_ entries...");
170-
let items_moved = {
171-
let mut moved_gen_fields_tables = crate::binding()
172-
.moved_gen_fields_tables
173-
.try_lock()
174-
.expect("Should have no race in weak_proc");
175-
let items_moved = moved_gen_fields_tables.len();
176-
for (new_objref, MovedGenFieldsTablesEntry { old_objref, .. }) in
177-
moved_gen_fields_tables.drain()
178-
{
179-
trace!(
180-
" generic_fields_tbl_ entry: {} -> {}",
181-
old_objref,
182-
new_objref
183-
);
184-
(upcalls().reinsert_generic_fields_tbl_entry)(old_objref, new_objref);
185-
}
186-
items_moved
187-
};
188-
log::debug!("Updated generic_fields_tbl_ entries. {items_moved} items moved.");
189-
190-
// Clean up entries for dead objects.
191-
let generic_fields_tbl = (upcalls().get_generic_fields_tbl)();
192-
let old_size = (upcalls().st_get_num_entries)(generic_fields_tbl);
193-
log::debug!("Cleaning up generic_fields_tbl_ entries ({old_size} entries before)...");
194-
(crate::upcalls().cleanup_generic_fields_tbl)();
195-
let new_size = (upcalls().st_get_num_entries)(generic_fields_tbl);
196-
log::debug!("Cleaned up generic_fields_tbl_ entries ({new_size} entries after).");
197-
probe!(
198-
mmtk_ruby,
199-
update_generic_fields_tbl,
200-
items_moved,
201-
old_size,
202-
new_size
203-
);
204-
}
205159
}
206160

207161
struct ProcessObjFreeCandidates;
@@ -286,7 +240,10 @@ macro_rules! define_global_table_processor {
286240
}
287241

288242
define_global_table_processor!(UpdateGenericFieldsTbl, {
289-
WeakProcessor::update_generic_fields_tbl();
243+
general_update_weak_table(
244+
upcalls().get_generic_fields_tbl,
245+
upcalls().update_generic_fields_table,
246+
);
290247
});
291248

292249
define_global_table_processor!(UpdateFrozenStringsTable, {

0 commit comments

Comments
 (0)