shape_gc/fixup.rs
1//! Pointer fixup after relocation.
2//!
3//! After objects are relocated and the forwarding table is populated,
4//! we must update all pointers (in live objects and root set) to point
5//! to the new locations.
6
7use crate::region::Region;
8use crate::relocator::ForwardingTable;
9
10/// Fix up all pointers in the root set using the forwarding table.
11///
12/// `trace_roots` should iterate all root pointers. For each pointer that
13/// has a forwarding entry, update it to the new address.
14pub fn fixup_roots(
15 forwarding: &ForwardingTable,
16 trace_roots: &mut dyn FnMut(&mut dyn FnMut(*mut u8, &mut *mut u8)),
17) {
18 trace_roots(&mut |old_ptr, slot| {
19 if let Some(new_ptr) = forwarding.lookup(old_ptr) {
20 *slot = new_ptr;
21 }
22 });
23}
24
25/// Fix up pointers within all live objects in a region.
26///
27/// For each live object, trace its inner pointers and update any that
28/// appear in the forwarding table.
29pub fn fixup_region(region: &mut Region, _forwarding: &ForwardingTable) {
30 region.for_each_object_mut(|header, _obj_ptr| {
31 // Only process live objects
32 if header.size == 0 {
33 return;
34 }
35
36 // Walk the object's pointer fields and update forwarded ones.
37 // For now, this is a placeholder — real implementation needs type-specific
38 // tracing via HeapKind to know which fields are pointers.
39 // The actual fixup happens via the Trace trait in the VM integration.
40 });
41}
42
43/// Fix up a single raw pointer if it has a forwarding entry.
44#[inline]
45pub fn fixup_ptr(ptr: *mut u8, forwarding: &ForwardingTable) -> *mut u8 {
46 if let Some(new) = forwarding.lookup(ptr) {
47 new
48 } else {
49 ptr
50 }
51}
52
53/// Fix up a NaN-boxed u64 value in-place if it contains a forwarded heap pointer.
54#[inline]
55pub fn fixup_nanboxed_bits(bits: &mut u64, forwarding: &ForwardingTable) {
56 const TAG_BASE: u64 = 0xFFF8_0000_0000_0000;
57 const PAYLOAD_MASK: u64 = 0x0000_FFFF_FFFF_FFFF;
58 const TAG_MASK: u64 = 0x0007_0000_0000_0000;
59 const TAG_SHIFT: u32 = 48;
60 const TAG_HEAP: u64 = 0b000;
61
62 let is_tagged = (*bits & TAG_BASE) == TAG_BASE;
63 if !is_tagged {
64 return;
65 }
66
67 let tag = (*bits & TAG_MASK) >> TAG_SHIFT;
68 if tag != TAG_HEAP {
69 return;
70 }
71
72 // Mask off bit 0 (ownership flag): owned Box-backed values have bit 0 set,
73 // but the actual pointer is aligned. Preserve the bit when writing the new
74 // pointer back so ownership metadata is retained across GC compaction.
75 const HEAP_PTR_MASK: u64 = !1;
76 let owned_bit = *bits & 1;
77 let old_ptr = (*bits & PAYLOAD_MASK & HEAP_PTR_MASK) as *mut u8;
78 if old_ptr.is_null() {
79 return;
80 }
81
82 if let Some(new_ptr) = forwarding.lookup(old_ptr) {
83 let new_payload = ((new_ptr as u64) & PAYLOAD_MASK) | owned_bit;
84 *bits = (*bits & !PAYLOAD_MASK) | new_payload;
85 }
86}