1#[cfg(feature = "std")]
2pub mod codegen;
3pub mod optimizer;
4pub mod profiler;
5pub mod specialization;
6pub mod trace;
7use crate::bytecode::Value;
8use crate::VM;
9#[cfg(feature = "std")]
10pub use codegen::JitCompiler;
11#[cfg(not(feature = "std"))]
12pub struct JitCompiler;
13use alloc::{string::String, vec::Vec};
14use hashbrown::HashMap;
15pub use optimizer::TraceOptimizer;
16pub use profiler::{HotSpot, Profiler};
17pub use trace::{Trace, TraceOp, TraceRecorder};
18#[cfg(not(feature = "std"))]
19impl JitCompiler {
20 pub fn new() -> Self {
21 Self
22 }
23
24 pub fn compile_trace(
25 &mut self,
26 _trace: &Trace,
27 _trace_id: TraceId,
28 _parent: Option<TraceId>,
29 _hoisted_constants: Vec<(u8, Value)>,
30 ) -> crate::Result<CompiledTrace> {
31 Err(crate::LustError::RuntimeError {
32 message: "JIT is unavailable without the `std` feature".into(),
33 })
34 }
35}
36#[cfg(all(debug_assertions, feature = "std"))]
37#[inline]
38pub(crate) fn log<F>(message: F)
39where
40 F: FnOnce() -> String,
41{
42 println!("{}", message());
43}
44
45#[cfg(not(all(debug_assertions, feature = "std")))]
46#[inline]
47pub(crate) fn log<F>(_message: F)
48where
49 F: FnOnce() -> String,
50{
51}
52
53pub const HOT_THRESHOLD: u32 = 5;
54pub const MAX_TRACE_LENGTH: usize = 2000; pub const SIDE_EXIT_THRESHOLD: u32 = 10;
56pub const UNROLL_FACTOR: usize = 32;
57pub const LOOP_UNROLL_COUNT: usize = 32;
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
60pub struct TraceId(pub usize);
61pub struct CompiledTrace {
62 pub id: TraceId,
63 pub entry: extern "C" fn(*mut Value, *mut VM, *const crate::bytecode::Function) -> i32,
64 pub trace: Trace,
65 pub guards: Vec<Guard>,
66 pub parent: Option<TraceId>,
67 pub side_traces: Vec<TraceId>,
68 pub leaked_constants: Vec<*const Value>,
69 pub hoisted_constants: Vec<(u8, Value)>,
70}
71
72#[derive(Debug, Clone)]
73pub struct Guard {
74 pub index: usize,
75 pub bailout_ip: usize,
76 pub kind: GuardKind,
77 pub fail_count: u32,
78 pub side_trace: Option<TraceId>,
79}
80
81#[derive(Debug, Clone)]
82pub enum GuardKind {
83 IntType {
84 register: u8,
85 },
86 FloatType {
87 register: u8,
88 },
89 BoolType {
90 register: u8,
91 },
92 Truthy {
93 register: u8,
94 },
95 Falsy {
96 register: u8,
97 },
98 ArrayBoundsCheck {
99 array_register: u8,
100 index_register: u8,
101 },
102 NestedLoop {
103 function_idx: usize,
104 loop_start_ip: usize,
105 },
106 NativeFunction {
107 register: u8,
108 expected: *const (),
109 },
110 Function {
111 register: u8,
112 function_idx: usize,
113 },
114 Closure {
115 register: u8,
116 function_idx: usize,
117 upvalues_ptr: *const (),
118 },
119}
120
121pub struct JitState {
122 pub profiler: Profiler,
123 pub traces: HashMap<TraceId, CompiledTrace>,
124 pub root_traces: HashMap<(usize, usize), TraceId>,
125 next_trace_id: usize,
126 pub enabled: bool,
127}
128
129impl JitState {
130 pub fn new() -> Self {
131 let enabled = cfg!(all(feature = "std", target_arch = "x86_64"));
132 Self {
133 profiler: Profiler::new(),
134 traces: HashMap::new(),
135 root_traces: HashMap::new(),
136 next_trace_id: 0,
137 enabled,
138 }
139 }
140
141 pub fn alloc_trace_id(&mut self) -> TraceId {
142 let id = TraceId(self.next_trace_id);
143 self.next_trace_id += 1;
144 id
145 }
146
147 pub fn check_hot(&mut self, func_idx: usize, ip: usize) -> bool {
148 if !self.enabled {
149 return false;
150 }
151
152 self.profiler.record_backedge(func_idx, ip) >= HOT_THRESHOLD
153 }
154
155 pub fn get_root_trace(&self, func_idx: usize, ip: usize) -> Option<&CompiledTrace> {
156 self.root_traces
157 .get(&(func_idx, ip))
158 .and_then(|id| self.traces.get(id))
159 }
160
161 pub fn get_trace(&self, id: TraceId) -> Option<&CompiledTrace> {
162 self.traces.get(&id)
163 }
164
165 pub fn get_trace_mut(&mut self, id: TraceId) -> Option<&mut CompiledTrace> {
166 self.traces.get_mut(&id)
167 }
168
169 pub fn store_root_trace(&mut self, func_idx: usize, ip: usize, trace: CompiledTrace) {
170 let id = trace.id;
171 self.root_traces.insert((func_idx, ip), id);
172 self.traces.insert(id, trace);
173 }
174
175 pub fn store_side_trace(&mut self, trace: CompiledTrace) {
176 let id = trace.id;
177 self.traces.insert(id, trace);
178 }
179}
180
181impl Default for JitState {
182 fn default() -> Self {
183 Self::new()
184 }
185}