Skip to main content

qcode_jit/
lib.rs

1//! A Cranelift JIT backend for QCode: an execution strategy alongside the
2//! interpreter, not a replacement for it.
3//!
4//! [`qcode_emulator`] interprets QCode one operation at a time, which means
5//! every intermediate value is materialised into its value table and every
6//! operand is resolved through the module. Compiled code does neither: a QCode
7//! block is already SSA, so it maps onto Cranelift's SSA directly and values
8//! consumed inside the block stay in machine registers.
9//!
10//! The backend is deliberately partial — see [`compile::Unsupported`]. A block
11//! it declines is run by the interpreter instead, so coverage can grow without
12//! ever being a correctness question.//!
13//! # Installing it
14//!
15//! The JIT is a [`qcode_vm`] block executor; a machine runs identically with
16//! or without it, only faster.
17//!
18//! ```no_run
19//! use qcode_jit::Jit;
20//! use qcode_vm::{Vm, VmMemory, perm};
21//! use wazabin_qcode_sleigh::vm_source::SleighCodeSource;
22//!
23//! # fn run(code: &[u8]) {
24//! let source = SleighCodeSource::new(sleigh_precompile::x64::spec());
25//! let ctx = source.new_context();
26//!
27//! let mut memory = VmMemory::new();
28//! memory.mmu.write_unchecked(0x1000, code, perm::READ | perm::EXEC);
29//!
30//! let mut vm = Vm::at_address(ctx, 0x1000, source, memory).expect("the entry decodes");
31//! vm.set_block_executor(Box::new(Jit::new()));
32//! vm.run(10_000);
33//!
34//! // How much the JIT actually took on, rather than handed back.
35//! println!("compiled {} blocks natively", vm.stats.native_bodies);
36//! # }
37//! ```
38//!
39//! [`qcode_vm`]: https://docs.rs/qcode_vm
40
41pub mod compile;
42pub mod jit;
43
44pub use compile::{Export, SpaceTable, Unsupported};
45pub use jit::{Jit, JitStats};