Skip to content

Commit eae75e1

Browse files
committed
Implement rb_gc_impl_mark_weak
1 parent e9e71de commit eae75e1

File tree

5 files changed

+70
-28
lines changed

5 files changed

+70
-28
lines changed

Diff for: gc/mmtk.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ void *
450450
rb_gc_impl_objspace_alloc(void)
451451
{
452452
MMTk_Builder *builder = mmtk_builder_default();
453-
mmtk_init_binding(builder, NULL, &ruby_upcalls);
453+
mmtk_init_binding(builder, NULL, &ruby_upcalls, (MMTk_ObjectReference)Qundef);
454454

455455
return calloc(1, sizeof(struct objspace));
456456
}
@@ -738,21 +738,23 @@ rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj)
738738
}
739739

740740
void
741-
rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj) {
741+
rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj)
742+
{
742743
if (rb_gc_impl_pointer_to_heap_p(objspace_ptr, (const void *)obj)) {
743744
rb_gc_impl_mark_and_pin(objspace_ptr, obj);
744745
}
745746
}
746747

747748
void
748-
rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr) {
749-
rb_bug("unimplemented");
749+
rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr)
750+
{
751+
mmtk_mark_weak((const MMTk_ObjectReference *)ptr);
750752
}
751753

752754
void
753755
rb_gc_impl_remove_weak(void *objspace_ptr, VALUE parent_obj, VALUE *ptr)
754756
{
755-
rb_bug("unimplemented");
757+
mmtk_remove_weak((const MMTk_ObjectReference *)ptr);
756758
}
757759

758760
// Compaction

Diff for: gc/mmtk.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ MMTk_Builder *mmtk_builder_default(void);
101101

102102
void mmtk_init_binding(MMTk_Builder *builder,
103103
const struct MMTk_RubyBindingOptions *_binding_options,
104-
const struct MMTk_RubyUpcalls *upcalls);
104+
const struct MMTk_RubyUpcalls *upcalls,
105+
MMTk_ObjectReference weak_reference_dead_value);
105106

106107
void mmtk_initialize_collection(MMTk_VMThread tls);
107108

@@ -126,6 +127,10 @@ void mmtk_post_alloc(MMTk_Mutator *mutator,
126127

127128
void mmtk_add_obj_free_candidate(MMTk_ObjectReference object);
128129

130+
void mmtk_mark_weak(const MMTk_ObjectReference *ptr);
131+
132+
void mmtk_remove_weak(const MMTk_ObjectReference *ptr);
133+
129134
void mmtk_object_reference_write_post(MMTk_Mutator *mutator, MMTk_ObjectReference object);
130135

131136
void mmtk_register_wb_unprotected_object(MMTk_ObjectReference object);

Diff for: gc/mmtk/src/api.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub extern "C" fn mmtk_init_binding(
5555
builder: *mut MMTKBuilder,
5656
_binding_options: *const RubyBindingOptions,
5757
upcalls: *const RubyUpcalls,
58+
weak_reference_dead_value: ObjectReference,
5859
) {
5960
crate::set_panic_hook();
6061

@@ -63,7 +64,7 @@ pub extern "C" fn mmtk_init_binding(
6364
let mmtk_boxed = mmtk_init(&builder);
6465
let mmtk_static = Box::leak(Box::new(mmtk_boxed));
6566

66-
let binding = RubyBinding::new(mmtk_static, &binding_options, upcalls);
67+
let binding = RubyBinding::new(mmtk_static, &binding_options, upcalls, weak_reference_dead_value);
6768

6869
crate::BINDING
6970
.set(binding)
@@ -133,6 +134,18 @@ pub extern "C" fn mmtk_add_obj_free_candidate(object: ObjectReference) {
133134
binding().weak_proc.add_obj_free_candidate(object)
134135
}
135136

137+
// =============== Marking ===============
138+
139+
#[no_mangle]
140+
pub extern "C" fn mmtk_mark_weak(ptr: &'static mut ObjectReference) {
141+
binding().weak_proc.add_weak_reference(ptr);
142+
}
143+
144+
#[no_mangle]
145+
pub extern "C" fn mmtk_remove_weak(ptr: &ObjectReference) {
146+
binding().weak_proc.remove_weak_reference(ptr);
147+
}
148+
136149
// =============== Write barriers ===============
137150

138151
#[no_mangle]

Diff for: gc/mmtk/src/binding.rs

+5-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::collections::{HashMap, HashSet};
22
use std::ffi::CString;
3-
use std::str::FromStr;
43
use std::sync::atomic::AtomicBool;
54
use std::sync::Mutex;
65
use std::thread::JoinHandle;
@@ -66,39 +65,24 @@ pub struct RubyBinding {
6665
pub(crate) moved_givtbl: Mutex<HashMap<ObjectReference, MovedGIVTblEntry>>,
6766
pub gc_thread_join_handles: Mutex<Vec<JoinHandle<()>>>,
6867
pub wb_unprotected_objects: Mutex<HashSet<ObjectReference>>,
69-
pub st_entries_chunk_size: usize,
70-
pub st_bins_chunk_size: usize,
68+
69+
pub weak_reference_dead_value: ObjectReference,
7170
}
7271

7372
unsafe impl Sync for RubyBinding {}
7473
unsafe impl Send for RubyBinding {}
7574

76-
fn env_default<T>(name: &str, default: T) -> T
77-
where
78-
T: FromStr,
79-
{
80-
std::env::var(name)
81-
.ok()
82-
.and_then(|x| x.parse::<T>().ok())
83-
.unwrap_or(default)
84-
}
85-
8675
impl RubyBinding {
8776
pub fn new(
8877
mmtk: &'static MMTK<Ruby>,
8978
binding_options: &RubyBindingOptions,
9079
upcalls: *const abi::RubyUpcalls,
80+
weak_reference_dead_value: ObjectReference,
9181
) -> Self {
9282
unsafe {
9383
crate::BINDING_FAST.suffix_size = binding_options.suffix_size;
9484
}
9585

96-
let st_entries_chunk_size = env_default::<usize>("RUBY_MMTK_ENTRIES_CHUNK_SIZE", 1024);
97-
let st_bins_chunk_size = env_default::<usize>("RUBY_MMTK_BINS_CHUNK_SIZE", 4096);
98-
99-
debug!("st_entries_chunk_size: {st_entries_chunk_size}");
100-
debug!("st_bins_chunk_size: {st_bins_chunk_size}");
101-
10286
Self {
10387
mmtk,
10488
options: binding_options.clone(),
@@ -109,8 +93,8 @@ impl RubyBinding {
10993
moved_givtbl: Default::default(),
11094
gc_thread_join_handles: Default::default(),
11195
wb_unprotected_objects: Default::default(),
112-
st_entries_chunk_size,
113-
st_bins_chunk_size,
96+
97+
weak_reference_dead_value
11498
}
11599
}
116100

Diff for: gc/mmtk/src/weak_proc.rs

+38
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub struct WeakProcessor {
1818
/// If it is a bottleneck, replace it with a lock-free data structure,
1919
/// or add candidates in batch.
2020
obj_free_candidates: Mutex<Vec<ObjectReference>>,
21+
weak_references: Mutex<Vec<&'static mut ObjectReference>>,
2122
}
2223

2324
impl Default for WeakProcessor {
@@ -30,6 +31,7 @@ impl WeakProcessor {
3031
pub fn new() -> Self {
3132
Self {
3233
obj_free_candidates: Mutex::new(Vec::new()),
34+
weak_references: Mutex::new(Vec::new()),
3335
}
3436
}
3537

@@ -56,12 +58,28 @@ impl WeakProcessor {
5658
std::mem::take(obj_free_candidates.as_mut())
5759
}
5860

61+
pub fn add_weak_reference(&self, ptr: &'static mut ObjectReference) {
62+
let mut weak_references = self.weak_references.lock().unwrap();
63+
weak_references.push(ptr);
64+
}
65+
66+
pub fn remove_weak_reference(&self, ptr: &ObjectReference) {
67+
let mut weak_references = self.weak_references.lock().unwrap();
68+
for (i, curr_ptr) in weak_references.iter().enumerate() {
69+
if *curr_ptr == ptr {
70+
weak_references.swap_remove(i);
71+
break;
72+
}
73+
}
74+
}
75+
5976
pub fn process_weak_stuff(
6077
&self,
6178
worker: &mut GCWorker<Ruby>,
6279
_tracer_context: impl ObjectTracerContext<Ruby>,
6380
) {
6481
worker.add_work(WorkBucketStage::VMRefClosure, ProcessObjFreeCandidates);
82+
worker.add_work(WorkBucketStage::VMRefClosure, ProcessWeakReferences);
6583

6684
worker.scheduler().work_buckets[WorkBucketStage::VMRefClosure].bulk_add(vec![
6785
Box::new(UpdateGenericIvTbl) as _,
@@ -141,6 +159,26 @@ impl GCWork<Ruby> for ProcessObjFreeCandidates {
141159
}
142160
}
143161

162+
struct ProcessWeakReferences;
163+
164+
impl GCWork<Ruby> for ProcessWeakReferences {
165+
fn do_work(&mut self, _worker: &mut GCWorker<Ruby>, _mmtk: &'static mmtk::MMTK<Ruby>) {
166+
let mut weak_references = crate::binding()
167+
.weak_proc
168+
.weak_references
169+
.try_lock()
170+
.expect("Mutators should not be holding the lock.");
171+
172+
for ptr_ptr in weak_references.iter_mut() {
173+
if !(**ptr_ptr).is_reachable() {
174+
**ptr_ptr = crate::binding().weak_reference_dead_value;
175+
}
176+
}
177+
178+
weak_references.clear();
179+
}
180+
}
181+
144182
trait GlobalTableProcessingWork {
145183
fn process_table(&mut self);
146184

0 commit comments

Comments
 (0)