luna_jit/lib.rs
1#![deny(missing_docs)]
2//! luna — a Lua runtime in pure Rust with a Cranelift-backed JIT.
3//!
4//! Primary dialect: Lua 5.5 (tracks official upstream).
5//! Compat modes: Lua 5.1 / 5.2 / 5.3 / 5.4.
6//!
7//! This crate is `luna-core` plus:
8//! - the Cranelift-backed method + trace JIT (`jit_backend`);
9//! - the `lua.h`-compatible C ABI (`capi`);
10//! - the `luna` CLI bin.
11//!
12//! Pure-Rust embedders that don't want the JIT (and don't want
13//! Cranelift in their dependency tree) can depend on `luna-core`
14//! directly — its API surface is a subset of this crate's.
15//!
16//! # Embedding contract
17//!
18//! ```no_run
19//! use luna_jit::{Vm, LuaVersion};
20//! // JIT-equipped Vm, fully-loaded stdlib:
21//! let mut vm = luna_jit::new_with_jit(LuaVersion::Lua55);
22//! vm.eval("return 1 + 2").unwrap();
23//! ```
24//!
25//! Sandbox embedders should call `vm.set_jit_enabled(false)` and
26//! `vm.set_bytecode_loading(false)` before running untrusted
27//! scripts. See `luna-core` rustdoc for the full caveat list.
28
29// v1.1 A1 Session C — re-export everything from luna-core so existing
30// `use luna_jit::vm::Vm`, `use luna_jit::version::LuaVersion`,
31// `use luna_jit::runtime::Value`, etc. paths continue to resolve. The
32// JIT-bearing surface (CraneliftBackend, the `luna_jit_*` helpers,
33// `enter_jit`, `cache_lookup_or_compile`, `try_compile_trace_with_options`)
34// hangs off `luna_jit::jit_backend` / the unified `luna_jit::jit`
35// re-export below.
36pub use luna_core::*;
37
38// v1.3 UD3 — re-export the derive macro + impl-block attr macro so
39// embedders writing `use luna_jit::LuaUserdata;` get both the trait
40// (from the `pub use luna_core::*;` above) and the derive (here).
41// Rust allows the same path to resolve to both a trait and a derive
42// — they live in different namespaces (mirrors serde's
43// `pub use serde_derive::Serialize;` pattern).
44pub use luna_jit_derive::{LuaUserdata, lua_userdata_methods};
45
46pub mod capi;
47pub mod jit_backend;
48pub mod lua_facade;
49
50/// v2.0 Track TL — pure-read inspection accessors over a live `Vm`.
51/// Re-exports [`luna_core::vm::inspect`] so the `luna-tools`
52/// binaries (`luna-heap-dump`, `luna-trace-inspect`,
53/// `luna-profile`) can `use luna_jit::inspect::*` without a
54/// separate `luna-core` direct dep.
55pub mod inspect {
56 pub use luna_core::vm::inspect::*;
57}
58
59pub use lua_facade::{IntoLuaArgs, Lua, LuaFunction, LuaRoot, LuaSandboxBuilder, LuaTable};
60
61/// Unified `jit` namespace — combines luna-core's trait surface +
62/// pure types with luna's Cranelift-backed implementations. Existing
63/// `use luna_jit::jit::TraceRecord`, `use luna_jit::jit::CraneliftBackend`,
64/// `use luna_jit::jit::cache_lookup_or_compile`, etc. resolve through
65/// this module.
66pub mod jit {
67 pub use crate::jit_backend::{
68 CraneliftBackend, cache_lookup_or_compile, enter_jit, try_compile_int_chunk,
69 };
70 pub use luna_core::jit::*;
71 // v2.0 Track J sub-step J-B — `cache_clear` + `cache_entry_count`
72 // are no longer `#[cfg(test)]` (the per-Vm storage migration made
73 // them harmless probes). Re-exported unconditionally so the J-B
74 // integration test + any embedder can probe a Vm's JIT cache size
75 // / reset it without a downcast.
76 pub use crate::jit_backend::{cache_clear, cache_entry_count};
77
78 /// v2.0 Track J sub-step J-A — `Send` wrapper newtype for
79 /// `cranelift_jit::JITModule`. Exposed `#[doc(hidden)]` so
80 /// integration tests under `crates/luna-jit/tests/` can run the
81 /// static-`Send` assertion + cross-thread smoke without a
82 /// `pub(crate)` carve-out. **Not a stable embedder API** — J-B
83 /// consumes this internally and the type will move to
84 /// `Vm.VmJitStorage` when the field migration lands.
85 #[doc(hidden)]
86 pub use crate::jit_backend::SendJitModule as __SendJitModule_for_j_a_test;
87 /// `luna_core::jit::trace` (the types) merged with
88 /// `luna_jit::jit_backend::trace` (the codegen entry points). Old
89 /// `crate::jit::trace::TraceRecord` paths in user code keep
90 /// working; new code can `use luna_jit::jit::trace::try_compile_trace_with_options`.
91 pub mod trace {
92 pub use crate::jit_backend::trace::{
93 base_var_scaffold_declared_count, last_compile_checkpoint,
94 reset_base_var_scaffold_declared_count, try_compile_trace,
95 try_compile_trace_with_options,
96 };
97 pub use luna_core::jit::trace_types::*;
98 }
99}
100
101/// v1.1 A1 Session C — build a JIT-equipped minimal Vm. Equivalent
102/// to `luna_core::vm::Vm::new_minimal(version)` followed by
103/// `install_default_jit(&mut vm)`. Use this as the v1.0
104/// drop-in replacement for `Vm::new_minimal` callers who want the
105/// Cranelift backend.
106pub fn new_minimal_with_jit(version: version::LuaVersion) -> vm::Vm {
107 let mut vm = vm::Vm::new_minimal(version);
108 install_default_jit(&mut vm);
109 vm
110}
111
112/// v1.1 A1 Session C — build a JIT-equipped, fully-loaded Vm.
113/// Equivalent to `new_minimal_with_jit(version)` followed by
114/// `vm.open_all_libs()`. Use this as the v1.0 drop-in replacement
115/// for `luna_jit::Vm::new` callers.
116pub fn new_with_jit(version: version::LuaVersion) -> vm::Vm {
117 let mut vm = new_minimal_with_jit(version);
118 vm.open_all_libs();
119 vm
120}
121
122/// v1.1 A1 Session C — install the default Cranelift backend on an
123/// already-constructed Vm. Idempotent on a JIT-equipped Vm; useful
124/// for re-arming a Vm previously running under `install_null_jit`.
125///
126/// Equivalent to v1.0's `Vm::install_default_jit`, lifted to a free
127/// fn because the trait orphan rule prevents adding inherent methods
128/// to `luna_core::vm::Vm` from this crate. The `VmExt` extension
129/// trait below restores the dotted-method form.
130///
131/// # v2.1 Phase 1K.D.4 — `LUNA_JIT_BACKEND` env-var override
132///
133/// The chosen backend is normally Cranelift. Set the
134/// `LUNA_JIT_BACKEND` env var to override at Vm-construction time:
135///
136/// | Value | Behaviour |
137/// |---|---|
138/// | unset / `cranelift` | Cranelift (default). |
139/// | `llvm` (with `--features llvm-jit`) | LLVM 18 backend. |
140/// | `llvm` (feature OFF) | `panic!` with a rebuild hint. |
141/// | any other value | `panic!` listing the accepted values. |
142///
143/// The env var is read **once per `install_default_jit` call**; the
144/// selection is then frozen into the Vm. Switching at runtime is
145/// out of scope (see `.dev/rfcs/v2.1-phase-1k-c-trait-audit.md`
146/// § 4.4).
147pub fn install_default_jit(vm: &mut vm::Vm) {
148 let backend = std::env::var("LUNA_JIT_BACKEND").unwrap_or_default();
149 match backend.as_str() {
150 "" | "cranelift" => install_cranelift_jit(vm),
151 "llvm" => install_llvm_jit(vm),
152 other => panic!(
153 "LUNA_JIT_BACKEND={other:?} not recognised; expected one of \
154 {{unset, \"cranelift\", \"llvm\"}}.",
155 ),
156 }
157}
158
159/// v2.1 Phase 1K.D.4 — concrete Cranelift backend installer. Always
160/// available; this is the install path `install_default_jit` lands
161/// on when `LUNA_JIT_BACKEND` is unset or `cranelift`.
162fn install_cranelift_jit(vm: &mut vm::Vm) {
163 vm.install_jit_backend(jit_backend::CraneliftBackend, jit_backend::CraneliftBackend);
164 // v2.0 Track J sub-step J-B — pair the CraneliftBackend trait
165 // impls with a fresh CraneliftJitStorage so the trait impls'
166 // `_storage` param downcasts to the right concrete type once
167 // Phases D/E/F start using it.
168 vm.install_jit_storage(jit_backend::storage::CraneliftJitStorage::default());
169}
170
171/// v2.1 Phase 1K.D.4 — concrete LLVM backend installer. Only
172/// compiled when `luna-jit` is built with `--features llvm-jit`.
173/// Selected at runtime via `LUNA_JIT_BACKEND=llvm`.
174#[cfg(feature = "llvm-jit")]
175fn install_llvm_jit(vm: &mut vm::Vm) {
176 vm.install_jit_backend(luna_jit_llvm::LlvmBackend, luna_jit_llvm::LlvmBackend);
177 vm.install_jit_storage(luna_jit_llvm::LlvmJitStorage::default());
178}
179
180/// v2.1 Phase 1K.D.4 — `LUNA_JIT_BACKEND=llvm` was requested but
181/// the build does not include the LLVM backend. Panic with a
182/// rebuild hint rather than silently falling back to Cranelift
183/// (silent fallback would mask the configuration error and lead
184/// to confusing bench / test results).
185#[cfg(not(feature = "llvm-jit"))]
186fn install_llvm_jit(_vm: &mut vm::Vm) {
187 panic!(
188 "LUNA_JIT_BACKEND=llvm requested but the `llvm-jit` cargo \
189 feature is OFF in this build of luna-jit. Rebuild with \
190 `cargo build -p luna-jit --features llvm-jit` (or add the \
191 feature to your Cargo.toml's luna-jit dep). See \
192 `.dev/rfcs/v2.1-phase-1k-c-trait-audit.md` § 4.3."
193 );
194}
195
196/// Extension trait that exposes the JIT-installing constructors and
197/// the `install_default_jit` shim as methods on `luna_core::vm::Vm`.
198/// Bring it into scope with `use luna_jit::VmExt;` to write
199/// `vm.install_default_jit()` (matches v1.0 syntax) instead of
200/// `luna_jit::install_default_jit(&mut vm)`.
201pub trait VmExt {
202 /// See [`install_default_jit`].
203 fn install_default_jit(&mut self);
204}
205
206impl VmExt for vm::Vm {
207 fn install_default_jit(&mut self) {
208 install_default_jit(self);
209 }
210}
211
212// LuaVersion is also a common entry point — re-export at the top
213// level so `use luna_jit::LuaVersion` works without an explicit
214// `luna_jit::version::LuaVersion` path.
215pub use version::LuaVersion;
216pub use vm::Vm;