1use super::*;
2use crate::VM;
3impl JitCompiler {
4 pub fn new() -> Self {
5 Self {
6 ops: Assembler::new().unwrap(),
7 leaked_constants: Vec::new(),
8 }
9 }
10
11 pub fn compile_trace(
12 &mut self,
13 trace: &Trace,
14 trace_id: TraceId,
15 parent: Option<TraceId>,
16 hoisted_constants: Vec<(u8, Value)>,
17 ) -> Result<CompiledTrace> {
18 let mut guards = Vec::new();
19 let mut guard_index = 0i32;
20 dynasm!(self.ops
21 ; push rbp
22 ; mov rbp, rsp
23 ; push rbx
24 ; push r12
25 ; push r13
26 ; push r14
27 ; push r15
28 ; mov r12, rdi
29 ; mov r13, rsi
30 );
31 for (dest, value) in &hoisted_constants {
32 self.compile_load_const(*dest, value)?;
33 }
34
35 for (_i, op) in trace.ops.iter().enumerate() {
36 match op {
37 TraceOp::LoadConst { dest, value } => {
38 self.compile_load_const(*dest, value)?;
39 }
40
41 TraceOp::Move { dest, src } => {
42 self.compile_move(*dest, *src)?;
43 }
44
45 TraceOp::Add {
46 dest,
47 lhs,
48 rhs,
49 lhs_type,
50 rhs_type,
51 } => {
52 self.compile_add_specialized(*dest, *lhs, *rhs, *lhs_type, *rhs_type)?;
53 }
54
55 TraceOp::Sub {
56 dest,
57 lhs,
58 rhs,
59 lhs_type,
60 rhs_type,
61 } => {
62 self.compile_sub_specialized(*dest, *lhs, *rhs, *lhs_type, *rhs_type)?;
63 }
64
65 TraceOp::Mul {
66 dest,
67 lhs,
68 rhs,
69 lhs_type,
70 rhs_type,
71 } => {
72 self.compile_mul_specialized(*dest, *lhs, *rhs, *lhs_type, *rhs_type)?;
73 }
74
75 TraceOp::Div {
76 dest,
77 lhs,
78 rhs,
79 lhs_type,
80 rhs_type,
81 } => {
82 self.compile_div_specialized(*dest, *lhs, *rhs, *lhs_type, *rhs_type)?;
83 }
84
85 TraceOp::Mod {
86 dest,
87 lhs,
88 rhs,
89 lhs_type,
90 rhs_type,
91 } => {
92 self.compile_mod_specialized(*dest, *lhs, *rhs, *lhs_type, *rhs_type)?;
93 }
94
95 TraceOp::Neg { dest, src } => {
96 self.compile_neg(*dest, *src)?;
97 }
98
99 TraceOp::Lt { dest, lhs, rhs } => {
100 self.compile_lt(*dest, *lhs, *rhs)?;
101 }
102
103 TraceOp::Le { dest, lhs, rhs } => {
104 self.compile_le(*dest, *lhs, *rhs)?;
105 }
106
107 TraceOp::Gt { dest, lhs, rhs } => {
108 self.compile_gt(*dest, *lhs, *rhs)?;
109 }
110
111 TraceOp::Ge { dest, lhs, rhs } => {
112 self.compile_ge(*dest, *lhs, *rhs)?;
113 }
114
115 TraceOp::Eq { dest, lhs, rhs } => {
116 self.compile_eq(*dest, *lhs, *rhs)?;
117 }
118
119 TraceOp::Ne { dest, lhs, rhs } => {
120 self.compile_ne(*dest, *lhs, *rhs)?;
121 }
122
123 TraceOp::And { dest, lhs, rhs } => {
124 self.compile_and(*dest, *lhs, *rhs)?;
125 }
126
127 TraceOp::Or { dest, lhs, rhs } => {
128 self.compile_or(*dest, *lhs, *rhs)?;
129 }
130
131 TraceOp::Not { dest, src } => {
132 self.compile_not(*dest, *src)?;
133 }
134
135 TraceOp::Concat { dest, lhs, rhs } => {
136 self.compile_concat(*dest, *lhs, *rhs)?;
137 }
138
139 TraceOp::GetIndex { dest, array, index } => {
140 self.compile_get_index(*dest, *array, *index)?;
141 }
142
143 TraceOp::ArrayLen { dest, array } => {
144 self.compile_array_len(*dest, *array)?;
145 }
146
147 TraceOp::GuardNativeFunction { register, function } => {
148 let expected_ptr = function.pointer();
149 crate::jit::log(|| format!("🔒 JIT: guard native reg {}", register));
150 let guard = self.compile_guard_native_function(
151 *register,
152 expected_ptr,
153 guard_index as usize,
154 )?;
155 guards.push(guard);
156 guard_index += 1;
157 }
158
159 TraceOp::CallNative {
160 dest,
161 callee,
162 function,
163 first_arg,
164 arg_count,
165 } => {
166 let expected_ptr = function.pointer();
167 self.compile_call_native(
168 *dest,
169 *callee,
170 expected_ptr,
171 *first_arg,
172 *arg_count,
173 )?;
174 }
175
176 TraceOp::CallMethod {
177 dest,
178 object,
179 method_name,
180 first_arg,
181 arg_count,
182 } => {
183 self.compile_call_method(*dest, *object, method_name, *first_arg, *arg_count)?;
184 }
185
186 TraceOp::GetField {
187 dest,
188 object,
189 field_name,
190 field_index,
191 value_type,
192 is_weak,
193 } => {
194 self.compile_get_field(
195 *dest,
196 *object,
197 field_name,
198 *field_index,
199 *value_type,
200 *is_weak,
201 )?;
202 }
203
204 TraceOp::SetField {
205 object,
206 field_name,
207 value,
208 field_index,
209 value_type,
210 is_weak,
211 } => {
212 self.compile_set_field(
213 *object,
214 field_name,
215 *value,
216 *field_index,
217 *value_type,
218 *is_weak,
219 )?;
220 }
221
222 TraceOp::NewStruct {
223 dest,
224 struct_name,
225 field_names,
226 field_registers,
227 } => {
228 self.compile_new_struct(*dest, struct_name, field_names, field_registers)?;
229 }
230
231 TraceOp::Guard {
232 register,
233 expected_type,
234 } => {
235 let guard =
236 self.compile_guard(*register, *expected_type, guard_index as usize)?;
237 guards.push(guard);
238 guard_index += 1;
239 }
240
241 TraceOp::GuardLoopContinue {
242 condition_register,
243 bailout_ip,
244 } => {
245 let guard = self.compile_loop_continue_guard(
246 *condition_register,
247 *bailout_ip,
248 guard_index as usize,
249 )?;
250 guards.push(guard);
251 guard_index += 1;
252 }
253
254 TraceOp::NestedLoopCall {
255 function_idx,
256 loop_start_ip,
257 bailout_ip,
258 } => {
259 jit::log(|| {
260 format!(
261 "🔗 JIT: Nested loop detected at func {} ip {} (guard #{})",
262 function_idx, loop_start_ip, guard_index
263 )
264 });
265 guards.push(Guard {
266 index: guard_index as usize,
267 bailout_ip: *bailout_ip,
268 kind: GuardKind::NestedLoop {
269 function_idx: *function_idx,
270 loop_start_ip: *loop_start_ip,
271 },
272 fail_count: 0,
273 side_trace: None,
274 });
275 let current_guard_index = guard_index;
276 dynasm!(self.ops
277 ; mov eax, DWORD (current_guard_index + 1)
278 ; jmp >exit
279 );
280 guard_index += 1;
281 }
282
283 TraceOp::Return { .. } => {}
284 }
285 }
286
287 dynasm!(self.ops
288 ; xor eax, eax
289 ; exit:
290 ; pop r15
291 ; pop r14
292 ; pop r13
293 ; pop r12
294 ; pop rbx
295 ; pop rbp
296 ; ret
297 ; fail:
298 ; mov eax, DWORD -1
299 ; jmp <exit
300 );
301 let ops = mem::replace(&mut self.ops, Assembler::new().unwrap());
302 let buffer = ops.finalize().unwrap();
303 let entry_point = buffer.ptr(dynasmrt::AssemblyOffset(0));
304 let entry: extern "C" fn(*mut Value, *mut VM, *const Function) -> i32 =
305 unsafe { mem::transmute(entry_point) };
306 Box::leak(Box::new(buffer));
307 let leaked_constants = mem::take(&mut self.leaked_constants);
308 Ok(CompiledTrace {
309 id: trace_id,
310 entry,
311 trace: trace.clone(),
312 guards,
313 parent,
314 side_traces: Vec::new(),
315 leaked_constants,
316 hoisted_constants,
317 })
318 }
319}