Expand description
luna-runtime-helpers — the static-link runtime entry for the
binaries that luna-aot produces.
§Role in the v1.3 Phase AOT pipeline
luna-aot compile foo.lua --out foo walks:
- Parse + compile
foo.luato a luna bytecode dump (Stages 1-2). - Emit a
.luna.bytecodedata section in a fresh.o(Stage 5). - Build this crate as a
staticlib—libluna_runtime_helpers.abundles the rust stdlib + luna-core + this thin C-ABI entry. - Emit a tiny C
mainthat calls intoluna_aot_runpassing the bracket-symbol bounds of the bytecode section (Stage 6). cclinksbytecode.o+main.o+libluna_runtime_helpers.a-lpthread -ldl -lminto the final executable.
The produced binary at run time:
- the C
maincallsluna_aot_run(bytecode_ptr, len) luna_aot_runconstructs aVm, allows bytecode loading, callsVm::load(slice, b"=embedded")(which routes throughluna_core::vm::dump::undumpbecause the slice starts with\x1bLua), thenVm::call_valueon the resulting root closure- normal
print(...)from the script lands on stdout viastd::io::stdoutinside luna-core’s builtins (no surprises) - exit code 0 on success, 1 on load / runtime error
§Why a separate crate (not folded into luna-aot)
luna-aot is the build-time tool — it pulls object + clap
and eventually all of cranelift. The deploy-side binary must
not pull cranelift; it only needs the luna interp. Splitting this
entry into its own crate keeps the deploy-side .a tight (rust
stdlib + luna-core only) and lets luna-aot invoke
cargo build -p luna-runtime-helpers --release without dragging
its own dep tree into the link.
§luna-core 0-third-party-dep contract
Unchanged. cargo tree -p luna-core --prefix none | grep -cE " v[0-9]"
continues to report 1. This crate sits above luna-core in the
dep graph; nothing here flows back into luna-core.
Modules§
- aot_
inline_ chain_ resolver - v1.3 Phase AOT Stage 7 polish 6 —
FrameMaterializeInfochain pointer reloc resolver. See parent-module preamble for the full design rationale; this module owns the deploy-side walk + per-chain Rc materialization + slot write. - aot_
strkey_ resolver - v1.3 Phase AOT Stage 7 sub-piece 3 — deploy-side interned-string slot resolver.
- aot_
trace_ registry - v1.3 Phase AOT Stage 7 sub-piece 4 — deploy-side trace-meta walker.
Functions§
- force_
link_ aot_ entry - Force-link the C-ABI symbol so a
cargo buildof a dependent rlib doesn’t dead-strip it. Without this, the symbol is technically reachable (no_mangle + extern “C”), but rustc / lld can be over- eager in some pipelines; calling this fromlib.rs::pre_mainor from abuild.rsartifact ensures the staticlib export survives. - force_
link_ jit_ helpers - v1.3 Stage 7 follow-on — pull all 27
luna_jit_*Cranelift trace-mcode helper symbols into the deploy-side staticlib’s linkmap. Called by the AOT-generated Cmainstub or by the integration tests to make sure the helper symbols are still resolvable aftercargo build -p luna-runtime-helpers --release. - luna_
aot_ ⚠run - AOT-binary C-ABI entry. The auto-generated C
maincalls this once with a pointer + length pair derived from the bracket symbols__luna_bytecode_start/__luna_bytecode_endthatluna-aotemits into the.luna.bytecodesection. - luna_
jit_ ⚠materialize_ sunk_ table - P12-S5-C — materialize a Sinkable site’s virtual array slots into
a heap
Gc<Table>at a side-exit emit point. The JIT emit lays out two parallel stack buffers per site per exit (raws_ptrofcap× u64 andkinds_ptrofcap× u8, one entry per virt slot) and calls this helper. The caller writes the returnedValue::Tableraw bits into the slot’sreg_statecell + sets the per-exit-tags entry toExitTag::Tableso the dispatcher repacks correctly on deopt. - luna_
jit_ ⚠new_ table - P11-S5c — allocate an empty
Gc<Table>on the active Vm’s heap. Returns the Gc pointer pun’d toi64. The fresh table is rooted only through the Cranelift Variable the JIT writes it into; nomaybe_collect_garbageruns inside the helper so the SSA-only rooting suffices for the duration of the JIT entry. - luna_
jit_ ⚠new_ table_ sized - P11-S5c.B —
Heap::new_table_sized(n)variant. JIT emit reaches for this when theNewTablewindow is immediately followed by a countedfor i = 1, N do … endwith a compile-time-knownN— pre-allocating the array part skips ~13 intermediaterehashrounds for N=10000, which dominates the hot loop’s wall-clock ontable_alloc_10k. Negative or zero hints degrade to an empty table (matchesnew_table). - luna_
jit_ ⚠op_ close - P12-S7-C — trace JIT helper for
Op::Close A. WrapsVm::jit_op_closewhich does the predict-and-deopt logic: returns 0 to continue the trace, 1 to deopt (handler would run or pre-existing pending_err). - luna_
jit_ ⚠op_ closure - P12-S7-A — trace JIT helper for
Op::Closure A Bx. - luna_
jit_ ⚠op_ concat - P12-S12-C v1 — trace JIT helper for
Op::Concat A B. - luna_
jit_ ⚠op_ get_ tab_ up - v1.2 D3 Path B — read
upvals[upval_idx][key_str]and return raw payload bits. Mirrorsluna_jit_table_get_fieldbut resolves the table via the trace head closure’s upvalue list first (the trace dispatcher’senter_jit(vm, Some(cl))pinsJIT_CL). - luna_
jit_ ⚠op_ tforcall - P12-S12-B-v2 — trace JIT helper for
Op::TForCall A 0 C. - luna_
jit_ ⚠spill_ to_ stack - P12-S7-B — spill a trace’s per-register live value into the
caller frame’s
vm.stack[base + slot_offset]. Always called just beforeluna_jit_op_closurefor eachin_stack: trueupval in the inner proto, so the open upval the helper creates points to a slot holding the right value. - luna_
jit_ ⚠stack_ load - P12-S12-B-v2 — load the raw
i64payload ofvm.stack[base + slot_offset]for the active trace’s head frame. Used to reload trace IRVariables after a helper (e.g.luna_jit_op_tforcall) has mutatedvm.stackdirectly. - luna_
jit_ ⚠stack_ tag - P12-S12-B-v2 — read the tag byte of
vm.stack[base + slot_offset]for the active trace’s head frame. Used byOp::TForLoopemit to dispatch on the iterator’s return-key tag (Nil → loop end, Int → continue for ipairs, other → deopt for v2). - luna_
jit_ ⚠stack_ update_ raw - P12-S12-C v1 — update only the raw payload of
vm.stack[base + slot_offset], preserving its existing tag. Used byOp::Concatbody emit to spill trace-IR Variables back to vm.stack for operands whosecurrent_kindsisUnset(e.g. Str slots that round-trip as pointer raw bits but have noRegKind::Strvariant). The interp’s previous execution of the same op already wrote the righttagto that slot — the trace just needs to refresh the raw bits. - luna_
jit_ ⚠str_ buf_ acquire - P14-S14-B v2 — trace JIT helper:acquire a fresh accumulator
buffer from the Vm’s pool. Returns a
*mut Vec<u8>boxed-leaked pointer that the trace fn keeps in a stack slot through the loop. - luna_
jit_ ⚠str_ buf_ extend - P14-S14-B v2 — trace JIT helper:append a LuaStr’s bytes to a
previously-acquired accumulator buffer. The trace IR calls this
at each loop iter inside the
s = s .. vidiom. - luna_
jit_ ⚠str_ buf_ intern - P14-S14-B v2 — trace JIT helper:drain the accumulator buffer
into a fresh
LuaStrviaheap.intern, returning the raw ptr bits for the trace to write into the accumulator slot. - luna_
jit_ ⚠str_ buf_ release - P14-S14-B v2 — trace JIT helper:release a buffer back to the Vm’s pool.
- luna_
jit_ ⚠table_ get_ field - P12-S11-A — read
t[key_ptr_as_str]and return raw payload bits. String key is aGc<LuaStr>raw pointer baked into IR. Caller (trace JIT GetField emit) infers exit_tag for the dst slot viainfer_getx_exit; absent inference, dispatchable=false. - luna_
jit_ ⚠table_ get_ float - P11-S5d.E’ —
t[k]wherekis a Float key. luna 5.1 / 5.2’sOP_GETTABLEtypically loads the key viaLoadF(no Int subtype in those dialects); the emit handskasf64::to_bitsso the helper can reconstruct the Float value before callingTable::get.Table::getnormalises integral Floats back to the Int slot, sot[1.0]lands ont[1]exactly like PUC does. Returns the raw 8-byte payload (same convention asluna_jit_table_get_int). - luna_
jit_ ⚠table_ get_ int - P11-S5c —
t[key]where the JIT statically expects an Int result. Pulls the rawValuefrom the table and unpacks the Int payload. If the slot is anything but Int (Nil, Float, Str, …) the helper returns 0 — the JIT scan only admits chunks that store Ints, so the divergence is observable only when the user-facing semantics violate the static expectation. - luna_
jit_ ⚠table_ len - P11-S5c —
#t(table length). - luna_
jit_ ⚠table_ set_ field - P12-S11-A — write
Value::pack(tag, raw)tot[key_ptr_as_str]. String key is aGc<LuaStr>raw pointer (baked into IR at emit time fromhead_proto.consts[ins.b()]); value goes through the standard tag/raw round-trip. Used for Op::SetField trace JIT support (helper path; sunk emit is S11-B). - luna_
jit_ ⚠table_ set_ float_ float - P11-S5c — Float-key, Float-value variant. luna 5.1 / 5.2 lower
for i = 1, N do t[i] = i endwith a Float loop var (no Int subtype in those dialects), so the SetTable’s key and value arguments arrive as f64 bit-patterns.Table::setnormalizes integral Float keys back to Int slots so#tstill reports the array length we’d expect — same shape PUC produces. - luna_
jit_ ⚠table_ set_ int - P11-S5c —
t[key] = valwheretis a Table Gc (i64 pun),keyis an Int andvalis an Int. WrapsTable::set_int(&mut Heap, i64, Value). Returns nothing (errors swallowed — luna’sset_intonly returnsErron table-size pathology that the interpreter would also surface; JIT’d workloads bounded by N=10k don’t reach it). Future caller-visible error reporting would route through a deopt return path. - luna_
jit_ ⚠table_ set_ nil - P12-S6-A2 — write
Value::Niltot[key](Int key). Used by trace JIT when a SetList/SetI/SetTable’s source register is aRegKind::Nil(e.g. Lua’slocal t = {nil, nil}table constructor expands toNewTable; LoadNil×N; SetListand without a Nil-specific helper the existing_table_set_intwould silently coerce the Nil toValue::Int(0)). - luna_
jit_ ⚠table_ set_ raw - P12-S7-C — write an arbitrary
Value::pack(tag, raw_bits)tot[key](Int key). Generalises_table_set_int/_table_set_nil: trace JIT emit dispatches Int/Nil to their specialized helpers (slightly less overhead) and Closure/Table/Float/etc. to this helper. Without it, a SetTable whose src is a Closure (post-S7 Op::Closure trace JIT) silently wraps the closure pointer asValue::Int(ptr_bits)— a number that later calls fail with “attempt to call a number value”. - luna_
jit_ ⚠trace_ materialize_ frames - P12-S4-step4b — frame materialization helper.
- luna_
jit_ ⚠upval_ get - P11-S5d.J —
R[A] = upvals[idx]value-read variant. Reads the active closure’s upvalue cell, dispatching open/closed via the interpreter’sVm::upval_get(so an open upvalue resolves to its current stack slot — matters when a closure is called from inside an enclosing function whose upvalues are still open). Returns the raw 8-byte payload (same convention as the table helpers): the JIT-emitted caller bitcasts to F64 if the slot’s declared kind is Float, leaves as I64 otherwise. - run_
bytecode - Convenience entry for in-process Rust drivers (
luna-aot’s integration tests, embedders that want to invoke the same code path without going throughcclink).