use luna_core::jit::JitVmGuard;
thread_local! {
static JIT_VM: std::cell::Cell<*mut luna_core::vm::Vm> =
const { std::cell::Cell::new(std::ptr::null_mut()) };
static JIT_CL: std::cell::Cell<*const luna_core::runtime::LuaClosure> =
const { std::cell::Cell::new(std::ptr::null()) };
}
pub fn enter_jit(
vm: &mut luna_core::vm::Vm,
cl: Option<luna_core::runtime::Gc<luna_core::runtime::LuaClosure>>,
) -> JitVmGuard {
scoped_rebind::scoped_jit_vm_rebind(vm, cl)
}
#[doc(hidden)]
pub fn __j_d_tls_ptrs() -> (
*mut luna_core::vm::Vm,
*const luna_core::runtime::LuaClosure,
) {
let vm = JIT_VM.with(|c| c.get());
let cl = JIT_CL.with(|c| c.get());
(vm, cl)
}
#[inline]
unsafe fn current_jit_vm<'a>() -> &'a mut luna_core::vm::Vm {
let p = JIT_VM.with(|cell| cell.get());
debug_assert!(!p.is_null(), "JIT helper called outside enter_jit scope");
unsafe { &mut *p }
}
#[inline]
unsafe fn current_jit_closure() -> luna_core::runtime::Gc<luna_core::runtime::LuaClosure> {
let p = JIT_CL.with(|cell| cell.get());
debug_assert!(
!p.is_null(),
"luna_jit_upval_get called outside an upval-aware enter_jit scope"
);
luna_core::runtime::Gc::from_ptr(p as *mut luna_core::runtime::LuaClosure)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_new_table() -> i64 {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return 0;
}
let g = vm.heap.new_table();
g.as_ptr() as i64
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_new_table_sized(asize: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return 0;
}
let n = if asize > 0 { asize as usize } else { 0 };
let g = vm.heap.new_table_sized(n);
g.as_ptr() as i64
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_materialize_sunk_table(
cap: i64,
raws_ptr: *const u64,
kinds_ptr: *const u8,
n_hash: i64,
hash_keys_ptr: *const u64,
hash_raws_ptr: *const u64,
hash_kinds_ptr: *const u8,
) -> i64 {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return 0;
}
let cap_u = if cap > 0 { cap as usize } else { 0 };
let n_hash_u = if n_hash > 0 { n_hash as usize } else { 0 };
let g = vm.heap.new_table_sized(cap_u);
let table = unsafe { g.as_mut() };
if cap_u > 0 {
for i in 0..cap_u {
let raw_bits = unsafe { *raws_ptr.add(i) };
let kind = unsafe { *kinds_ptr.add(i) };
let raw = luna_core::runtime::value::RawVal { zero: raw_bits };
let v = unsafe { luna_core::runtime::Value::pack(kind, raw) };
let _ = table.set_int(&mut vm.heap, (i + 1) as i64, v);
}
}
if n_hash_u > 0 {
for i in 0..n_hash_u {
let key_ptr_bits = unsafe { *hash_keys_ptr.add(i) };
let raw_bits = unsafe { *hash_raws_ptr.add(i) };
let kind = unsafe { *hash_kinds_ptr.add(i) };
let key_gc: luna_core::runtime::Gc<luna_core::runtime::LuaStr> =
luna_core::runtime::Gc::from_ptr(key_ptr_bits as *mut luna_core::runtime::LuaStr);
let raw = luna_core::runtime::value::RawVal { zero: raw_bits };
let v = unsafe { luna_core::runtime::Value::pack(kind, raw) };
let _ = table.set(&mut vm.heap, luna_core::runtime::Value::Str(key_gc), v);
}
}
g.as_ptr() as i64
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_table_set_int(t: i64, key: i64, val: i64) {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return;
}
let g: luna_core::runtime::Gc<luna_core::runtime::Table> =
luna_core::runtime::Gc::from_ptr(t as *mut luna_core::runtime::Table);
if g.metatable().is_some() {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: table has metatable"));
return;
}
let table = unsafe { g.as_mut() };
let _ = table.set_int(&mut vm.heap, key, luna_core::runtime::Value::Int(val));
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_table_set_raw(t: i64, key: i64, raw_bits: i64, tag: i64) {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return;
}
let g: luna_core::runtime::Gc<luna_core::runtime::Table> =
luna_core::runtime::Gc::from_ptr(t as *mut luna_core::runtime::Table);
if g.metatable().is_some() {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: table has metatable"));
return;
}
let table = unsafe { g.as_mut() };
let v = unsafe {
luna_core::runtime::Value::pack(
tag as u8,
luna_core::runtime::value::RawVal {
zero: raw_bits as u64,
},
)
};
let _ = table.set_int(&mut vm.heap, key, v);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_table_set_field(
t: i64,
key_ptr: i64,
val_raw: i64,
val_tag: i64,
) {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return;
}
let g: luna_core::runtime::Gc<luna_core::runtime::Table> =
luna_core::runtime::Gc::from_ptr(t as *mut luna_core::runtime::Table);
if g.metatable().is_some() {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: table has metatable"));
return;
}
let key_gc: luna_core::runtime::Gc<luna_core::runtime::LuaStr> =
luna_core::runtime::Gc::from_ptr(key_ptr as *mut luna_core::runtime::LuaStr);
let key = luna_core::runtime::Value::Str(key_gc);
let table = unsafe { g.as_mut() };
let v = unsafe {
luna_core::runtime::Value::pack(
val_tag as u8,
luna_core::runtime::value::RawVal {
zero: val_raw as u64,
},
)
};
let _ = table.set(&mut vm.heap, key, v);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_table_get_field(t: i64, key_ptr: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return 0;
}
let g: luna_core::runtime::Gc<luna_core::runtime::Table> =
luna_core::runtime::Gc::from_ptr(t as *mut luna_core::runtime::Table);
if g.metatable().is_some() {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: table has metatable"));
return 0;
}
let key_gc: luna_core::runtime::Gc<luna_core::runtime::LuaStr> =
luna_core::runtime::Gc::from_ptr(key_ptr as *mut luna_core::runtime::LuaStr);
let v = g.get(luna_core::runtime::Value::Str(key_gc));
let (_tag, raw) = v.unpack();
unsafe { raw.zero as i64 }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_op_get_tab_up(upval_idx: i64, key_ptr: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return 0;
}
let cl = unsafe { current_jit_closure() };
let env = vm.upval_get(cl, upval_idx as u32);
let g: luna_core::runtime::Gc<luna_core::runtime::Table> = match env {
luna_core::runtime::Value::Table(t) => t,
_ => {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: GetTabUp upval not Table"));
return 0;
}
};
if g.metatable().is_some() {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: GetTabUp env has metatable"));
return 0;
}
let key_gc: luna_core::runtime::Gc<luna_core::runtime::LuaStr> =
luna_core::runtime::Gc::from_ptr(key_ptr as *mut luna_core::runtime::LuaStr);
let v = g.get(luna_core::runtime::Value::Str(key_gc));
let (_tag, raw) = v.unpack();
unsafe { raw.zero as i64 }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_table_set_nil(t: i64, key: i64) {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return;
}
let g: luna_core::runtime::Gc<luna_core::runtime::Table> =
luna_core::runtime::Gc::from_ptr(t as *mut luna_core::runtime::Table);
if g.metatable().is_some() {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: table has metatable"));
return;
}
let table = unsafe { g.as_mut() };
let _ = table.set_int(&mut vm.heap, key, luna_core::runtime::Value::Nil);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_table_set_float_float(t: i64, key_bits: i64, val_bits: i64) {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return;
}
let g: luna_core::runtime::Gc<luna_core::runtime::Table> =
luna_core::runtime::Gc::from_ptr(t as *mut luna_core::runtime::Table);
if g.metatable().is_some() {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: table has metatable"));
return;
}
let table = unsafe { g.as_mut() };
let k = luna_core::runtime::Value::Float(f64::from_bits(key_bits as u64));
let v = luna_core::runtime::Value::Float(f64::from_bits(val_bits as u64));
let _ = table.set(&mut vm.heap, k, v);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_table_get_int(t: i64, key: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return 0;
}
let g: luna_core::runtime::Gc<luna_core::runtime::Table> =
luna_core::runtime::Gc::from_ptr(t as *mut luna_core::runtime::Table);
if g.metatable().is_some() {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: table has metatable"));
return 0;
}
let v = g.get_int(key);
let (_tag, raw) = v.unpack();
unsafe { raw.zero as i64 }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_table_get_float(t: i64, key_bits: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return 0;
}
let g: luna_core::runtime::Gc<luna_core::runtime::Table> =
luna_core::runtime::Gc::from_ptr(t as *mut luna_core::runtime::Table);
if g.metatable().is_some() {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: table has metatable"));
return 0;
}
let k = luna_core::runtime::Value::Float(f64::from_bits(key_bits as u64));
let v = g.get(k);
let (_tag, raw) = v.unpack();
unsafe { raw.zero as i64 }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_upval_get(idx: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return 0;
}
let cl = unsafe { current_jit_closure() };
let v = vm.upval_get(cl, idx as u32);
let (_tag, raw) = v.unpack();
unsafe { raw.zero as i64 }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_op_close(start_offset: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
vm.jit_op_close(start_offset as u32)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_stack_update_raw(slot_offset: i64, raw_bits: i64) {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return;
}
vm.jit_stack_update_raw(slot_offset as u32, raw_bits as u64);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_op_concat(slot_offset: i64, n: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
vm.jit_op_concat(slot_offset as u32, n as i32)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_str_buf_acquire() -> i64 {
let vm = unsafe { current_jit_vm() };
vm.jit_str_buf_acquire() as i64
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_str_buf_release(buf: i64) {
let vm = unsafe { current_jit_vm() };
vm.jit_str_buf_release(buf as *mut Vec<u8>);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_str_buf_extend(buf: i64, str_ptr: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
vm.jit_str_buf_extend(buf as *mut Vec<u8>, str_ptr)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_str_buf_intern(buf: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
vm.jit_str_buf_intern(buf as *mut Vec<u8>)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_op_tforcall(
abs_offset: i64,
nvars: i64,
ctrl_out: *mut i64,
key_out: *mut i64,
val_out: *mut i64,
) -> i64 {
let vm = unsafe { current_jit_vm() };
vm.jit_op_tforcall(abs_offset as u32, nvars as i32, ctrl_out, key_out, val_out)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_stack_load(slot_offset: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
vm.jit_stack_load(slot_offset as u32)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_stack_tag(slot_offset: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
vm.jit_stack_tag(slot_offset as u32) as i64
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_spill_to_stack(slot_offset: i64, tag: i64, raw_bits: i64) {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return;
}
vm.jit_spill_stack(slot_offset as u32, tag as u8, raw_bits as u64);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_op_closure(proto_idx: i64) -> i64 {
use luna_core::runtime::function::{INLINE_UPVALS_N, UpvalState, Upvalue};
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return 0;
}
let cl = unsafe { current_jit_closure() };
let inner = cl.proto.protos[proto_idx as usize];
let n_ups = inner.upvals.len();
let base = match vm.jit_last_lua_frame() {
Some(f) => f.base,
None => {
vm.jit.pending_err = Some(vm.rt_err("JIT op_closure: no Lua frame"));
return 0;
}
};
let mut stack_buf: [std::mem::MaybeUninit<luna_core::runtime::Gc<Upvalue>>; INLINE_UPVALS_N] =
[std::mem::MaybeUninit::uninit(); INLINE_UPVALS_N];
let mut heap_buf: Vec<luna_core::runtime::Gc<Upvalue>> = Vec::new();
let use_inline = n_ups <= INLINE_UPVALS_N;
if !use_inline {
heap_buf.reserve_exact(n_ups);
}
for (i, d) in inner.upvals.iter().enumerate() {
let uv = if d.in_stack {
vm.find_or_create_upval(base + d.index as u32)
} else {
cl.upvals()[d.index as usize]
};
if use_inline {
stack_buf[i] = std::mem::MaybeUninit::new(uv);
} else {
heap_buf.push(uv);
}
}
let ups: &mut [luna_core::runtime::Gc<Upvalue>] = if use_inline {
unsafe {
std::slice::from_raw_parts_mut(
stack_buf.as_mut_ptr() as *mut luna_core::runtime::Gc<Upvalue>,
n_ups,
)
}
} else {
&mut heap_buf[..]
};
let v51 = vm.version() <= luna_core::version::LuaVersion::Lua51;
if v51 && inner.env_upval_idx != u8::MAX {
let i = inner.env_upval_idx as usize;
let cur = match ups[i].state() {
UpvalState::Open { slot, thread } => vm.read_slot(slot, thread),
UpvalState::Closed(v) => v,
};
ups[i] = vm.heap.new_upvalue(UpvalState::Closed(cur));
}
let ups_slice: &[luna_core::runtime::Gc<Upvalue>] = ups;
let nc = if v51 {
vm.heap.new_closure_inline(inner, ups_slice)
} else {
let cached = inner.cache.get().filter(|c| {
c.upvals().len() == ups_slice.len()
&& c.upvals()
.iter()
.zip(ups_slice.iter())
.all(|(a, b)| std::ptr::eq(a.as_ptr(), b.as_ptr()))
});
match cached {
Some(c) => c,
None => {
let n = vm.heap.new_closure_inline(inner, ups_slice);
inner.cache.set(Some(n));
n
}
}
};
let (_tag, raw) = luna_core::runtime::Value::Closure(nc).unpack();
unsafe { raw.zero as i64 }
}
pub static TRACE_MATERIALIZE_FRAMES_FIRES: std::sync::atomic::AtomicU64 =
std::sync::atomic::AtomicU64::new(0);
pub fn trace_materialize_frames_fires() -> u64 {
TRACE_MATERIALIZE_FRAMES_FIRES.load(std::sync::atomic::Ordering::Relaxed)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_trace_materialize_frames(
n: u64,
metas: *const luna_core::jit::trace::FrameMaterializeInfo,
) -> i64 {
TRACE_MATERIALIZE_FRAMES_FIRES.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return -1;
}
let cl = unsafe { current_jit_closure() };
let head_frame = match vm.jit_last_lua_frame() {
Some(f) => f,
None => return -1,
};
let max_stack = cl.proto.max_stack as u32;
for i in 0..n as usize {
let m = unsafe { *metas.add(i) };
let new_base = head_frame.base + m.base_offset;
vm.jit_ensure_stack((new_base + max_stack) as usize);
vm.jit_push_inlined_frame(cl, new_base, m.pc, m.nresults);
}
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn luna_jit_table_len(t: i64) -> i64 {
let vm = unsafe { current_jit_vm() };
if vm.jit.pending_err.is_some() {
return 0;
}
let g: luna_core::runtime::Gc<luna_core::runtime::Table> =
luna_core::runtime::Gc::from_ptr(t as *mut luna_core::runtime::Table);
if g.metatable().is_some() {
vm.jit.pending_err = Some(vm.rt_err("JIT deopt: table has metatable"));
return 0;
}
g.len()
}
mod scoped_rebind;