use luna_core::compiler::compile_chunk;
use luna_core::frontend::parser::parse;
use luna_core::jit::send_compat::{TArc, TCellBool, TCellPtr, TCellU32, TRefLock};
use luna_core::jit::trace::{CompiledTrace, ExitTag, TagResKind, classify_exit_tags};
use luna_core::runtime::Heap;
use luna_core::version::LuaVersion;
use luna_core::vm::Vm;
unsafe extern "C" fn dummy_entry(_reg_state: *mut i64) -> i64 {
0
}
fn make_dummy_trace(head_pc: u32, max_stack: u32) -> CompiledTrace {
let exit_tags: TArc<[ExitTag]> = (0..max_stack)
.map(|_| ExitTag::Untouched)
.collect::<Vec<_>>()
.into();
let global_kind: TagResKind = classify_exit_tags(&exit_tags);
let entry_tags: TArc<[u8]> = vec![0u8; max_stack as usize].into();
CompiledTrace {
head_pc,
entry: dummy_entry,
n_ops: 1,
dispatchable: true,
window_size: max_stack,
exit_tags,
global_tag_res_kind: global_kind,
entry_tags,
per_exit_tags: TArc::from(Vec::<(u32, TArc<[ExitTag]>)>::new()),
per_exit_inline: TArc::from(Vec::new()),
exit_hit_counts: TArc::from(vec![TCellU32::new(0u32)]),
exit_side_trace_ptrs: TArc::from(vec![TCellPtr::null()]),
tags_side_trace_ptrs: TArc::from(Vec::new()),
global_side_trace_ptr: Box::new(TCellPtr::null()),
side_trace_cache: TRefLock::new(std::collections::HashMap::new()),
has_any_side_wired: TCellBool::new(false),
is_inline_abort_close: false,
dispatch_off_reason: None,
sinkable_sites_seen: 0,
accum_bufferable_seen: 0,
sunk_alloc_seen: 0,
materialize_emit_count: 0,
closure_seen: 0,
body_writes: Box::new([]),
downrec_link: None,
downrec_multi_way_count: 0,
}
}
#[test]
fn collect_proto_hashes_walks_tree() {
let src = "local function f() return 1 end\n\
local function g() return 2 end\n\
return f, g";
let ast = parse(src.as_bytes(), LuaVersion::Lua55).expect("parse");
let mut heap = Heap::new();
let root = compile_chunk(&ast, LuaVersion::Lua55, b"=test", &mut heap).expect("compile");
let vm = Vm::new(LuaVersion::Lua55);
let hashes = vm.collect_proto_hashes(root);
assert_eq!(hashes.len(), 3, "expected root + 2 nested protos");
let unique: std::collections::HashSet<[u8; 16]> = hashes.iter().map(|(_, h)| *h).collect();
assert_eq!(unique.len(), 3, "proto hashes must be distinct");
}
#[test]
fn install_aot_trace_pushes_onto_proto_traces() {
let src = "return 1";
let ast = parse(src.as_bytes(), LuaVersion::Lua55).expect("parse");
let mut heap = Heap::new();
let root = compile_chunk(&ast, LuaVersion::Lua55, b"=test", &mut heap).expect("compile");
assert_eq!(
root.traces.borrow().len(),
0,
"fresh Proto starts with no traces"
);
let mut vm = Vm::new(LuaVersion::Lua55);
let trace = make_dummy_trace(0, root.max_stack as u32);
vm.install_aot_trace(root, trace);
let traces = root.traces.borrow();
assert_eq!(traces.len(), 1, "install must push exactly one trace");
assert_eq!(traces[0].head_pc, 0);
assert!(
traces[0].dispatchable,
"dummy trace was marked dispatchable"
);
}
#[test]
fn install_then_lookup_via_collect_hashes() {
let src = "local s = 0\nfor i = 1, 5 do s = s + 1 end\nreturn s";
let ast = parse(src.as_bytes(), LuaVersion::Lua55).expect("parse");
let mut heap = Heap::new();
let root = compile_chunk(&ast, LuaVersion::Lua55, b"=test", &mut heap).expect("compile");
let target_hash = root.stable_hash();
let mut vm = Vm::new(LuaVersion::Lua55);
let hashes = vm.collect_proto_hashes(root);
let matched = hashes
.iter()
.find(|(_, h)| *h == target_hash)
.map(|(p, _)| *p)
.expect("root proto must be present in collected pairs");
let trace = make_dummy_trace(3, root.max_stack as u32);
vm.install_aot_trace(matched, trace);
assert_eq!(
root.traces.borrow().len(),
1,
"trace must end up on the matched proto"
);
}