Skip to main content

shape_jit/ffi/
gc.rs

1// Heap allocation audit (PR-9 V8 Gap Closure):
2//   Category A (NaN-boxed returns): 0 sites
3//   Category B (intermediate/consumed): 0 sites
4//   Category C (heap islands): 0 sites
5//     (GC module performs safepoint polling only, no allocations)
6//!
7//! GC integration FFI functions for JIT-compiled code
8//!
9//! Provides safepoint polling and root scanning for GC-enabled builds.
10//! Without `gc` feature: no-ops that compile away.
11
12use crate::context::JITContext;
13
14/// GC safepoint poll called from JIT code at loop headers.
15///
16/// This function is called at every loop back-edge in JIT-compiled code.
17/// Fast path (no GC pending): checks a single byte and returns.
18/// Slow path (GC requested): scans JITContext roots and participates in collection.
19///
20/// # Safety
21/// `ctx` must point to a valid JITContext.
22#[unsafe(no_mangle)]
23pub extern "C" fn jit_gc_safepoint(ctx: *mut JITContext) {
24    if ctx.is_null() {
25        return;
26    }
27
28    let ctx = unsafe { &*ctx };
29
30    // Fast path: check if GC safepoint flag pointer is set
31    if ctx.gc_safepoint_flag_ptr.is_null() {
32        return;
33    }
34
35    // Load the flag byte (AtomicBool's raw storage)
36    let flag = unsafe { *ctx.gc_safepoint_flag_ptr };
37    if flag == 0 {
38        return;
39    }
40
41    // Slow path: GC is requested, scan roots
42    #[cfg(feature = "gc")]
43    gc_scan_jit_roots(ctx);
44}
45
46/// Scan JITContext roots for the garbage collector.
47///
48/// Traces all NaN-boxed values in locals and stack that may contain
49/// heap pointers, allowing the GC to find all live objects reachable
50/// from JIT-compiled code.
51#[cfg(feature = "gc")]
52fn gc_scan_jit_roots(ctx: &JITContext) {
53    use shape_gc::safepoint::safepoint_poll;
54
55    // If a GcHeap is available, participate in the safepoint protocol
56    if !ctx.gc_heap_ptr.is_null() {
57        let heap = unsafe { &*(ctx.gc_heap_ptr as *const shape_gc::GcHeap) };
58        safepoint_poll(heap.safepoint());
59    }
60
61    // Root scanning is handled by the VM's gc_integration module which
62    // has access to the full VM state. The JIT safepoint just needs to
63    // signal that this thread has reached a safe point. The actual root
64    // scanning of JITContext locals/stack happens when the VM calls
65    // run_gc_collection() which iterates through the JIT context.
66}
67
68/// Write barrier for heap pointer overwrites in JIT-compiled code.
69///
70/// Called before overwriting a heap slot. `old_bits` is the NaN-boxed value
71/// being replaced; `new_bits` is the value about to be written.
72///
73/// Without `gc` feature: unconditional no-op (compiles to a single `ret`).
74/// With `gc` feature: enqueues the old reference into the SATB buffer if
75/// an incremental marking cycle is active, and marks the card table dirty.
76#[unsafe(no_mangle)]
77pub extern "C" fn jit_write_barrier(_old_bits: u64, _new_bits: u64) {
78    #[cfg(feature = "gc")]
79    {
80        // Will wire to shape_gc write_barrier / write_barrier_combined here
81        // when GC is activated. The JITContext will carry a GcHeap pointer
82        // that can be used to call heap.write_barrier(old_ptr).
83    }
84}