use crate::compiler::JITCompiler;
use crate::mixed_table::FunctionEntry;
use crate::JITConfig;
fn compile_to_mixed_table(
source: &str,
) -> (
shape_vm::bytecode::BytecodeProgram,
crate::mixed_table::MixedFunctionTable,
) {
use shape_vm::BytecodeCompiler;
shape_runtime::initialize_shared_runtime().ok();
let program = shape_ast::parse_program(source).expect("parse failed");
let mut loader = shape_runtime::module_loader::ModuleLoader::new();
let (graph, stdlib_names, prelude_imports) =
shape_vm::module_resolution::build_graph_and_stdlib_names(
&program,
&mut loader,
&[],
)
.expect("module graph construction failed");
let mut compiler = BytecodeCompiler::new();
compiler.stdlib_function_names = stdlib_names;
compiler.set_source(source);
let bytecode = compiler
.compile_with_graph_and_prelude(&program, graph, &prelude_imports)
.expect("bytecode compilation failed");
let jit_config = JITConfig::default();
let mut jit = JITCompiler::new(jit_config).expect("JIT init failed");
let (_jit_fn, mixed_table) = jit
.compile_program_selective("main", &bytecode)
.expect("JIT compilation failed");
(bytecode, mixed_table)
}
fn has_native_closure(
program: &shape_vm::bytecode::BytecodeProgram,
table: &crate::mixed_table::MixedFunctionTable,
) -> bool {
program
.functions
.iter()
.enumerate()
.any(|(idx, func)| {
func.is_closure
&& matches!(table.get(idx), Some(FunctionEntry::Native(_)))
})
}
fn jit_run(source: &str) -> shape_wire::WireValue {
use shape_runtime::engine::{ProgramExecutor, ShapeEngine};
shape_runtime::initialize_shared_runtime().ok();
let mut engine = ShapeEngine::new().expect("engine creation failed");
let program = shape_ast::parse_program(source).expect("parse failed");
let mut executor = crate::executor::JITExecutor::new();
let result = executor
.execute_program(&mut engine, &program)
.or_else(|e| {
Err(e)
})
.expect("JIT execution failed");
result.wire_value
}
#[test]
fn a1d2_jit_let_mut_closure_body_is_natively_compiled() {
let source = r#"
fn main() -> int {
let mut x: int = 0
let f = || { x = x + 1; x }
f()
}
main()
"#;
let (program, table) = compile_to_mixed_table(source);
assert!(
has_native_closure(&program, &table),
"A.1D.2: closure body containing Load/StoreOwnedMutableCapture must \
JIT-compile to FunctionEntry::Native. native={} interpreted={}",
table.native_count(),
table.interpreted_count()
);
}
#[test]
fn a1d2_jit_let_mut_closure_preflight_did_not_reject() {
let source = r#"
fn main() -> int {
let mut counter: int = 0
let f = || { counter = counter + 1; counter }
f()
}
main()
"#;
let (_program, table) = compile_to_mixed_table(source);
assert!(
table.native_count() > 0,
"A.1D.2: at least one function must JIT-compile to native code"
);
}
#[test]
fn a1d2_closure_layout_capture_kinds_classify_correctly() {
use shape_value::v2::closure_layout::{CaptureKind, ClosureLayout};
use shape_value::v2::ConcreteType;
let capture_types = vec![
ConcreteType::I64,
ConcreteType::I64,
ConcreteType::F64,
];
let kinds = vec![
CaptureKind::Immutable,
CaptureKind::OwnedMutable,
CaptureKind::Immutable,
];
let layout = ClosureLayout::from_capture_types(&capture_types, &kinds);
assert_eq!(layout.capture_storage_kind(0), CaptureKind::Immutable);
assert_eq!(layout.capture_storage_kind(1), CaptureKind::OwnedMutable);
assert_eq!(layout.capture_storage_kind(2), CaptureKind::Immutable);
assert_eq!(
layout.owned_mutable_capture_mask, 0b010,
"owned_mutable_capture_mask must have exactly bit 1 set for \
the single OwnedMutable capture at index 1"
);
assert_eq!(layout.heap_capture_mask, 0);
assert_eq!(layout.shared_capture_mask, 0);
}
#[test]
fn a1d2_jit_let_mut_counter_increments() {
let source = r#"
fn main() -> int {
let mut x: int = 0
let f = || { x = x + 1; x }
f()
f()
f()
}
main()
"#;
match jit_run(source) {
shape_wire::WireValue::Integer(n) => {
assert_eq!(n, 3, "counter must reach 3 after three f() calls");
}
shape_wire::WireValue::Number(n) => {
assert!(
(n - 3.0).abs() < 1e-9,
"counter must reach 3 (got Number {})",
n
);
}
other => panic!("expected Integer(3), got {:?}", other),
}
}
#[test]
fn a1d2_jit_let_mut_mixed_immutable() {
let source = r#"
fn main() -> int {
let base: int = 10
let mut x: int = 0
let f = || { x = x + base; x }
f()
f()
}
main()
"#;
match jit_run(source) {
shape_wire::WireValue::Integer(n) => {
assert_eq!(n, 20, "x should be 0 + 10 + 10 = 20");
}
shape_wire::WireValue::Number(n) => {
assert!((n - 20.0).abs() < 1e-9, "expected 20, got Number {}", n);
}
other => panic!("expected Integer(20), got {:?}", other),
}
}
#[test]
fn a1d2_jit_let_mut_closure_release_drops_box() {
let source = r#"
fn main() -> int {
var result: int = 0
{
let mut x: int = 42
let f = || { x = x + 1; x }
result = f()
}
result
}
main()
"#;
match jit_run(source) {
shape_wire::WireValue::Integer(n) => assert_eq!(n, 43),
shape_wire::WireValue::Number(n) => {
assert!((n - 43.0).abs() < 1e-9, "expected 43, got Number {}", n)
}
other => panic!("expected Integer(43), got {:?}", other),
}
}