pub struct Jit { /* private fields */ }Expand description
A just-in-time compiler for the host machine.
A Jit holds a code generator configured for the CPU it is running on, built once
in new. Each call to compile validates an
ir_lang::Function, lowers it to native machine code, and places that code in
executable memory, returning a Compiled that can be called. The engine carries
no per-function state, so one Jit compiles many functions, and it is Send and
Sync, so it can be shared across threads.
For a one-off compile where reuse does not matter, the free function
compile builds a Jit and compiles in a single call.
§Examples
Build the engine once, compile two functions, and run them:
use jit_lang::Jit;
use ir_lang::{Builder, BinOp, Type};
let jit = Jit::new().expect("the host is supported");
// fn inc(x: int) -> int { x + 1 }
let mut b = Builder::new("inc", &[Type::Int], Type::Int);
let x = b.block_params(b.entry())[0];
let one = b.iconst(1);
let sum = b.bin(BinOp::Add, x, one);
b.ret(Some(sum));
let inc = jit.compile(&b.finish()).expect("inc is well-formed");
// fn neg(x: int) -> int { 0 - x }
let mut b = Builder::new("neg", &[Type::Int], Type::Int);
let x = b.block_params(b.entry())[0];
let zero = b.iconst(0);
let r = b.bin(BinOp::Sub, zero, x);
b.ret(Some(r));
let neg = jit.compile(&b.finish()).expect("neg is well-formed");
// SAFETY: both signatures are `fn(int) -> int`, and each handle outlives its call.
let inc_fn: extern "C" fn(i64) -> i64 = unsafe { inc.entry() };
let neg_fn: extern "C" fn(i64) -> i64 = unsafe { neg.entry() };
assert_eq!(inc_fn(41), 42);
assert_eq!(neg_fn(42), -42);Implementations§
Source§impl Jit
impl Jit
Sourcepub fn new() -> Result<Self, JitError>
pub fn new() -> Result<Self, JitError>
Builds an engine targeting the host CPU, with its native instruction-set features enabled and the optimizing code path selected.
§Errors
JitError::Unsupportedif the host architecture has no Cranelift back-end.JitError::Codegenif the code generator rejects the configuration — not expected on a supported host.
§Examples
use jit_lang::Jit;
let jit = Jit::new().expect("the host is supported");
let _ = jit; // ready to compileSourcepub fn compile(&self, func: &Function) -> Result<Compiled, JitError>
pub fn compile(&self, func: &Function) -> Result<Compiled, JitError>
Compiles a function to native machine code and makes it runnable.
The function is validated, translated to Cranelift IR, compiled for the host,
and copied into a guard-flanked, read-execute memory region that the returned
Compiled owns. The emitted code is self-contained — a leaf function with no
outgoing calls — so it needs no runtime relocation; a function that somehow
required one is refused rather than run wrong.
§Errors
JitError::InvalidIrif the function is not well-formed SSA.JitError::Unsupportedif it uses something this back-end cannot lower, such as aUnit-typed parameter.JitError::Codegenif the code generator fails on otherwise valid input.JitError::Memoryif executable memory cannot be obtained or protected.
§Examples
use jit_lang::Jit;
use ir_lang::{Builder, BinOp, Type};
// fn mul(a: int, b: int) -> int { a * b }
let mut b = Builder::new("mul", &[Type::Int, Type::Int], Type::Int);
let a = b.block_params(b.entry())[0];
let c = b.block_params(b.entry())[1];
let p = b.bin(BinOp::Mul, a, c);
b.ret(Some(p));
let jit = Jit::new().unwrap();
let mul = jit.compile(&b.finish()).expect("mul is well-formed");
// SAFETY: the signature is `fn(int, int) -> int`, and `mul` outlives the call.
let mul_fn: extern "C" fn(i64, i64) -> i64 = unsafe { mul.entry() };
assert_eq!(mul_fn(6, 7), 42);