Skip to main content

luna_core/jit/
storage.rs

1//! Per-`Vm` JIT storage trait + null impl.
2//!
3//! The Cranelift JIT keeps three thread-local collections that own
4//! mmap'd code pages for compiled chunk fns and compiled traces:
5//!
6//! - `JIT_CACHE` — hash map of bytecode-key → cached compile result
7//! - `JIT_CACHE_HANDLES` — `Vec<JitHandle>` holding each compiled
8//!   chunk's `JITModule` so the entry pointer stays callable
9//! - `TRACE_JIT_HANDLES` — `Vec<TraceHandle>` holding each compiled
10//!   trace's `JITModule`
11//!
12//! These live in per-`Vm` field storage rather than `thread_local!`.
13//! The Cranelift types (`JITModule`, `CacheEntry`,
14//! `JitHandle`, `TraceHandle`) live in luna-jit, so luna-core only
15//! sees an opaque [`JitStorage`] trait + a no-op
16//! [`NullJitStorage`] default; the concrete `CraneliftJitStorage`
17//! impl lives in `luna_jit::jit_backend::storage`.
18
19/// Per-`Vm` JIT storage. Held as `Box<dyn JitStorage>` on
20/// [`crate::vm::jit_state::JitState::storage`]. The concrete impl is
21/// chosen by whoever installs the JIT backend (luna-core's default
22/// is [`NullJitStorage`]; the `luna_jit` crate swaps in its
23/// `CraneliftJitStorage` via a setter alongside `install_jit_backend`).
24///
25/// luna-core treats the trait as opaque — readers downcast through
26/// [`std::any::Any`] to reach concrete fields. This keeps the
27/// `JITModule`-bearing types (and therefore the Cranelift dep) out
28/// of luna-core.
29pub trait JitStorage: std::any::Any {
30    /// Mutable downcast hook. luna-jit's `CraneliftBackend`
31    /// implementations call this then `downcast_mut::<CraneliftJitStorage>()`
32    /// to reach the concrete cache + handle collections.
33    fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
34
35    /// Immutable downcast hook. Symmetric with [`Self::as_any_mut`];
36    /// used by read-only diagnostics.
37    fn as_any(&self) -> &dyn std::any::Any;
38
39    /// Called by the `Vm` identified by `vm` before it asks its compilers
40    /// for code through this storage. Code a storage holds can be
41    /// released only if every compile through it came from one `Vm`.
42    #[doc(hidden)]
43    fn claim(&mut self, vm: u64) {
44        let _ = vm;
45    }
46
47    /// Frees the machine code this storage holds, provided every compile
48    /// through it was claimed by `vm`; otherwise keeps it.
49    ///
50    /// # Safety
51    ///
52    /// `vm` is going away: none of its code is running and none will be
53    /// entered again. The `Vm` calls this from its `Drop`.
54    #[doc(hidden)]
55    unsafe fn release_code(&mut self, vm: u64) {
56        let _ = vm;
57    }
58}
59
60/// No-op storage installed by [`crate::vm::Vm::new_minimal`]. Holds
61/// nothing; downcasting from luna-jit will fail by design (a
62/// `NullJitBackend` is paired with `NullJitStorage` — neither
63/// `try_compile` nor `try_compile_trace` reaches the downcast site
64/// because both immediately return `Skipped` / `None`).
65#[derive(Default)]
66pub struct NullJitStorage;
67
68impl JitStorage for NullJitStorage {
69    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
70        self
71    }
72
73    fn as_any(&self) -> &dyn std::any::Any {
74        self
75    }
76}