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