Skip to main content

tidepool_codegen/
context.rs

1use std::mem;
2
3/// VM context passed as implicit first argument to all JIT-compiled functions.
4///
5/// Layout is frozen: gc_trigger reads fields by offset.
6/// alloc_ptr at 0, alloc_limit at 8, gc_trigger at 16, tail_callee at 24, tail_arg at 32.
7#[repr(C, align(16))]
8pub struct VMContext {
9    /// Current bump-pointer allocation cursor.
10    pub alloc_ptr: *mut u8,
11    /// End of the current nursery region.
12    pub alloc_limit: *const u8,
13    /// Host function called when alloc_ptr exceeds alloc_limit.
14    pub gc_trigger: unsafe extern "C" fn(*mut VMContext),
15    /// TCO: pending tail-call callee (closure pointer), null if no pending tail call.
16    pub tail_callee: *mut u8,
17    /// TCO: pending tail-call argument, null if no pending tail call.
18    pub tail_arg: *mut u8,
19}
20
21impl VMContext {
22    /// Create a new VMContext with the given nursery region and GC trigger.
23    pub fn new(
24        nursery_start: *mut u8,
25        nursery_end: *const u8,
26        gc_trigger: unsafe extern "C" fn(*mut VMContext),
27    ) -> Self {
28        Self {
29            alloc_ptr: nursery_start,
30            alloc_limit: nursery_end,
31            gc_trigger,
32            tail_callee: std::ptr::null_mut(),
33            tail_arg: std::ptr::null_mut(),
34        }
35    }
36}
37
38// Compile-time offset assertions
39const _: () = {
40    use crate::layout::*;
41    assert!(mem::offset_of!(VMContext, alloc_ptr) == VMCTX_ALLOC_PTR_OFFSET as usize);
42    assert!(mem::offset_of!(VMContext, alloc_limit) == VMCTX_ALLOC_LIMIT_OFFSET as usize);
43    assert!(mem::offset_of!(VMContext, gc_trigger) == VMCTX_GC_TRIGGER_OFFSET as usize);
44    assert!(mem::offset_of!(VMContext, tail_callee) == VMCTX_TAIL_CALLEE_OFFSET as usize);
45    assert!(mem::offset_of!(VMContext, tail_arg) == VMCTX_TAIL_ARG_OFFSET as usize);
46    assert!(mem::align_of::<VMContext>() == 16);
47};