Skip to content

Commit 6d83b67

Browse files
committed
Resize objects to optimal size when moving
1 parent 9ecc803 commit 6d83b67

4 files changed

Lines changed: 67 additions & 4 deletions

File tree

‎gc/mmtk/mmtk.c‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,22 @@ static void
308308
rb_mmtk_move_obj_during_marking(MMTk_ObjectReference from, MMTk_ObjectReference to)
309309
{
310310
rb_gc_move_obj_during_marking((VALUE)from, (VALUE)to);
311+
312+
size_t from_slot_size = rb_gc_impl_obj_slot_size((VALUE)from);
313+
size_t to_slot_size = rb_gc_impl_obj_slot_size((VALUE)to);
314+
if (from_slot_size != to_slot_size) {
315+
/* The object was copied to a differently sized slot; transition the
316+
* shape so its capacity matches the new slot size. The re-embedding
317+
* of contents (e.g. arrays, strings, object fields) happens later
318+
* during reference updating. */
319+
rb_gc_obj_changed_slot_size((VALUE)to, to_slot_size);
320+
}
321+
}
322+
323+
static size_t
324+
rb_mmtk_obj_optimal_size(MMTk_ObjectReference obj)
325+
{
326+
return rb_gc_obj_optimal_size((VALUE)obj);
311327
}
312328

313329
static void
@@ -543,6 +559,7 @@ MMTk_RubyUpcalls ruby_upcalls = {
543559
rb_mmtk_scan_gc_roots,
544560
rb_mmtk_scan_objspace,
545561
rb_mmtk_move_obj_during_marking,
562+
rb_mmtk_obj_optimal_size,
546563
rb_mmtk_update_object_references,
547564
rb_mmtk_call_gc_mark_children,
548565
rb_mmtk_handle_weak_references,
@@ -1271,6 +1288,16 @@ rb_gc_impl_obj_became_shareable(void *objspace_ptr, VALUE obj)
12711288
void
12721289
rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj)
12731290
{
1291+
if (!ruby_native_thread_p()) {
1292+
/* Called from an MMTk GC worker thread (via gc_ref_update_object's
1293+
* re-embedding path during reference updating). There is no mutator
1294+
* whose modbuf we could log the object into. This is only reachable
1295+
* during a moving GC, and moving GCs are always full-heap (major)
1296+
* GCs, so the object and its children are all marked by the current
1297+
* GC and no remembering is needed. */
1298+
return;
1299+
}
1300+
12741301
struct MMTk_ractor_cache *cache = rb_gc_get_ractor_newobj_cache();
12751302

12761303
mmtk_object_reference_write_post(cache->mutator, (MMTk_ObjectReference)obj);

‎gc/mmtk/mmtk.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ typedef struct MMTk_RubyUpcalls {
6868
void (*scan_gc_roots)(void);
6969
void (*scan_objspace)(void);
7070
void (*move_obj_during_marking)(MMTk_ObjectReference from, MMTk_ObjectReference to);
71+
size_t (*obj_optimal_size)(MMTk_ObjectReference object);
7172
void (*update_object_references)(MMTk_ObjectReference object);
7273
void (*call_gc_mark_children)(MMTk_ObjectReference object);
7374
void (*handle_weak_references)(MMTk_ObjectReference object, bool moving);

‎gc/mmtk/src/abi.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ pub struct RubyUpcalls {
312312
pub scan_gc_roots: extern "C" fn(),
313313
pub scan_objspace: extern "C" fn(),
314314
pub move_obj_during_marking: extern "C" fn(from: ObjectReference, to: ObjectReference),
315+
pub obj_optimal_size: extern "C" fn(object: ObjectReference) -> usize,
315316
pub update_object_references: extern "C" fn(object: ObjectReference),
316317
pub call_gc_mark_children: extern "C" fn(object: ObjectReference),
317318
pub handle_weak_references: extern "C" fn(object: ObjectReference, moving: bool),

‎gc/mmtk/src/object_model.rs‎

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,52 @@ impl ObjectModel<Ruby> for VMObjectModel {
5252
let from_acc = RubyObjectAccess::from_objref(from);
5353
let from_start = from_acc.obj_start();
5454
let object_size = from_acc.object_size();
55-
let to_start = copy_context.alloc_copy(from, object_size, MIN_OBJ_ALIGN, 0, semantics);
55+
56+
let optimal_payload = (crate::binding().upcalls().obj_optimal_size)(from);
57+
let new_size = if optimal_payload != 0 {
58+
let size = (RubyObjectAccess::prefix_size()
59+
+ optimal_payload
60+
+ RubyObjectAccess::suffix_size())
61+
.next_multiple_of(MIN_OBJ_ALIGN);
62+
// Never resize beyond the non-LOS allocation limit.
63+
let max_non_los = crate::mmtk()
64+
.get_plan()
65+
.constraints()
66+
.max_non_los_default_alloc_bytes;
67+
if size <= max_non_los {
68+
size
69+
} else {
70+
object_size
71+
}
72+
} else {
73+
object_size
74+
};
75+
76+
let to_start = copy_context.alloc_copy(from, new_size, MIN_OBJ_ALIGN, 0, semantics);
5677
debug_assert!(!to_start.is_zero());
5778
let to_payload = to_start.add(OBJREF_OFFSET);
5879
unsafe {
59-
copy_nonoverlapping::<u8>(from_start.to_ptr(), to_start.to_mut_ptr(), object_size);
80+
copy_nonoverlapping::<u8>(
81+
from_start.to_ptr(),
82+
to_start.to_mut_ptr(),
83+
object_size.min(new_size),
84+
);
6085
}
6186
let to_obj = unsafe { ObjectReference::from_raw_address_unchecked(to_payload) };
62-
copy_context.post_copy(to_obj, object_size, semantics);
63-
trace!("Copied object from {} to {}", from, to_obj);
87+
88+
if new_size != object_size {
89+
unsafe {
90+
to_start.store(
91+
new_size - RubyObjectAccess::prefix_size() - RubyObjectAccess::suffix_size(),
92+
);
93+
}
94+
}
6495

6596
(crate::binding().upcalls().move_obj_during_marking)(from, to_obj);
6697

98+
copy_context.post_copy(to_obj, new_size, semantics);
99+
trace!("Copied object from {} to {}", from, to_obj);
100+
67101
#[cfg(feature = "clear_old_copy")]
68102
{
69103
trace!(

0 commit comments

Comments
 (0)