1use super::setup::JITCompiler;
7use crate::context::JittedStrategyFn;
8use shape_vm::bytecode::{BuiltinFunction, BytecodeProgram, Instruction, OpCode, Operand};
9
10impl JITCompiler {
11 #[inline(always)]
13 pub fn get_function_table(&self) -> &[*const u8] {
14 &self.function_table
15 }
16
17 #[inline(always)]
19 pub fn get_function_by_index(&self, idx: usize) -> Option<JittedStrategyFn> {
20 self.function_table.get(idx).and_then(|&ptr| {
21 if ptr.is_null() {
22 None
23 } else {
24 Some(unsafe { std::mem::transmute(ptr) })
25 }
26 })
27 }
28}
29
30#[derive(Debug, Clone, Default, PartialEq, Eq)]
32pub struct JitPreflightReport {
33 pub vm_only_opcodes: Vec<OpCode>,
35 pub unsupported_builtins: Vec<BuiltinFunction>,
37}
38
39impl JitPreflightReport {
40 pub fn can_jit(&self) -> bool {
42 self.vm_only_opcodes.is_empty() && self.unsupported_builtins.is_empty()
43 }
44
45 pub fn blockers_summary(&self) -> String {
47 let mut parts = Vec::new();
48
49 if !self.vm_only_opcodes.is_empty() {
50 let opcodes = self
51 .vm_only_opcodes
52 .iter()
53 .map(|op| format!("{op:?}"))
54 .collect::<Vec<_>>()
55 .join(", ");
56 parts.push(format!("opcodes=[{opcodes}]"));
57 }
58
59 if !self.unsupported_builtins.is_empty() {
60 let builtins = self
61 .unsupported_builtins
62 .iter()
63 .map(|builtin| format!("{builtin:?}"))
64 .collect::<Vec<_>>()
65 .join(", ");
66 parts.push(format!("builtins=[{builtins}]"));
67 }
68
69 if parts.is_empty() {
70 "none".to_string()
71 } else {
72 parts.join("; ")
73 }
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct JitParityEntry {
80 pub target: JitParityTarget,
81 pub jit_supported: bool,
82 pub reason: &'static str,
83}
84
85#[derive(Debug, Clone, PartialEq, Eq)]
87pub enum JitParityTarget {
88 Opcode(OpCode),
89 Builtin(BuiltinFunction),
90}
91
92fn push_unique_opcode(out: &mut Vec<OpCode>, opcode: OpCode) {
93 if !out.contains(&opcode) {
94 out.push(opcode);
95 }
96}
97
98fn push_unique_builtin(out: &mut Vec<BuiltinFunction>, builtin: BuiltinFunction) {
99 if !out.contains(&builtin) {
100 out.push(builtin);
101 }
102}
103
104fn sort_opcodes(opcodes: &mut [OpCode]) {
105 opcodes.sort_by_key(|op| format!("{op:?}"));
106}
107
108fn sort_builtins(builtins: &mut [BuiltinFunction]) {
109 builtins.sort_by_key(|builtin| format!("{builtin:?}"));
110}
111
112const ALL_OPCODES: &[OpCode] = &[
113 OpCode::PushConst,
114 OpCode::PushNull,
115 OpCode::Pop,
116 OpCode::Dup,
117 OpCode::Swap,
118 OpCode::Add,
119 OpCode::Sub,
120 OpCode::Mul,
121 OpCode::Div,
122 OpCode::Mod,
123 OpCode::Neg,
124 OpCode::Pow,
125 OpCode::BitAnd,
126 OpCode::BitOr,
127 OpCode::BitShl,
128 OpCode::BitShr,
129 OpCode::BitNot,
130 OpCode::BitXor,
131 OpCode::Gt,
132 OpCode::Lt,
133 OpCode::Gte,
134 OpCode::Lte,
135 OpCode::Eq,
136 OpCode::Neq,
137 OpCode::GtInt,
138 OpCode::GtNumber,
139 OpCode::GtDecimal,
140 OpCode::LtInt,
141 OpCode::LtNumber,
142 OpCode::LtDecimal,
143 OpCode::GteInt,
144 OpCode::GteNumber,
145 OpCode::GteDecimal,
146 OpCode::LteInt,
147 OpCode::EqInt,
148 OpCode::EqNumber,
149 OpCode::NeqInt,
150 OpCode::NeqNumber,
151 OpCode::And,
152 OpCode::Or,
153 OpCode::Not,
154 OpCode::AddInt,
155 OpCode::AddNumber,
156 OpCode::AddDecimal,
157 OpCode::SubInt,
158 OpCode::SubNumber,
159 OpCode::SubDecimal,
160 OpCode::MulInt,
161 OpCode::MulNumber,
162 OpCode::MulDecimal,
163 OpCode::DivInt,
164 OpCode::DivNumber,
165 OpCode::DivDecimal,
166 OpCode::ModInt,
167 OpCode::Jump,
168 OpCode::JumpIfFalse,
169 OpCode::JumpIfFalseTrusted,
170 OpCode::JumpIfTrue,
171 OpCode::Call,
172 OpCode::Return,
173 OpCode::ReturnValue,
174 OpCode::CallValue,
175 OpCode::LoadLocal,
176 OpCode::LoadLocalTrusted,
177 OpCode::StoreLocal,
178 OpCode::LoadModuleBinding,
179 OpCode::StoreModuleBinding,
180 OpCode::LoadClosure,
181 OpCode::StoreClosure,
182 OpCode::MakeClosure,
183 OpCode::CloseUpvalue,
184 OpCode::MakeRef,
185 OpCode::DerefLoad,
186 OpCode::DerefStore,
187 OpCode::SetIndexRef,
188 OpCode::NewArray,
189 OpCode::NewTypedArray,
190 OpCode::NewObject,
191 OpCode::GetProp,
192 OpCode::SetProp,
193 OpCode::Length,
194 OpCode::ArrayPush,
195 OpCode::ArrayPop,
196 OpCode::MergeObject,
197 OpCode::SetLocalIndex,
198 OpCode::SetModuleBindingIndex,
199 OpCode::ArrayPushLocal,
200 OpCode::LoopStart,
201 OpCode::LoopEnd,
202 OpCode::Break,
203 OpCode::Continue,
204 OpCode::IterNext,
205 OpCode::IterDone,
206 OpCode::CallMethod,
207 OpCode::PushTimeframe,
208 OpCode::PopTimeframe,
209 OpCode::BuiltinCall,
210 OpCode::TypeCheck,
211 OpCode::Convert,
212 OpCode::ModNumber,
213 OpCode::ModDecimal,
214 OpCode::PowInt,
215 OpCode::PowNumber,
216 OpCode::PowDecimal,
217 OpCode::LteNumber,
218 OpCode::LteDecimal,
219 OpCode::SetupTry,
220 OpCode::PopHandler,
221 OpCode::Throw,
222 OpCode::TryUnwrap,
223 OpCode::UnwrapOption,
224 OpCode::ErrorContext,
225 OpCode::IsOk,
226 OpCode::IsErr,
227 OpCode::UnwrapOk,
228 OpCode::UnwrapErr,
229 OpCode::SliceAccess,
230 OpCode::NullCoalesce,
231 OpCode::MakeRange,
232 OpCode::GetDataField,
233 OpCode::GetDataRow,
234 OpCode::GetFieldTyped,
235 OpCode::SetFieldTyped,
236 OpCode::NewTypedObject,
237 OpCode::TypedMergeObject,
238 OpCode::WrapTypeAnnotation,
239 OpCode::Yield,
240 OpCode::Suspend,
241 OpCode::Resume,
242 OpCode::Poll,
243 OpCode::AwaitBar,
244 OpCode::AwaitTick,
245 OpCode::Await,
246 OpCode::SpawnTask,
247 OpCode::EmitAlert,
248 OpCode::EmitEvent,
249 OpCode::JoinInit,
250 OpCode::JoinAwait,
251 OpCode::CancelTask,
252 OpCode::AsyncScopeEnter,
253 OpCode::AsyncScopeExit,
254 OpCode::LoadColF64,
255 OpCode::LoadColI64,
256 OpCode::LoadColBool,
257 OpCode::LoadColStr,
258 OpCode::BindSchema,
259 OpCode::BoxTraitObject,
260 OpCode::DynMethodCall,
261 OpCode::Nop,
262 OpCode::Halt,
263 OpCode::Debug,
264 OpCode::IntToNumber,
265 OpCode::NumberToInt,
266 OpCode::CallForeign,
267 OpCode::AddTyped,
268 OpCode::SubTyped,
269 OpCode::MulTyped,
270 OpCode::DivTyped,
271 OpCode::ModTyped,
272 OpCode::CmpTyped,
273 OpCode::StoreLocalTyped,
274 OpCode::StoreModuleBindingTyped,
275 OpCode::CastWidth,
276];
277
278const ALL_BUILTINS: &[BuiltinFunction] = &[
279 BuiltinFunction::Abs,
281 BuiltinFunction::Sqrt,
282 BuiltinFunction::Ln,
283 BuiltinFunction::Pow,
284 BuiltinFunction::Exp,
285 BuiltinFunction::Log,
286 BuiltinFunction::Min,
287 BuiltinFunction::Max,
288 BuiltinFunction::Floor,
289 BuiltinFunction::Ceil,
290 BuiltinFunction::Round,
291 BuiltinFunction::Sin,
292 BuiltinFunction::Cos,
293 BuiltinFunction::Tan,
294 BuiltinFunction::Asin,
295 BuiltinFunction::Acos,
296 BuiltinFunction::Atan,
297 BuiltinFunction::StdDev,
298 BuiltinFunction::Range,
300 BuiltinFunction::Slice,
301 BuiltinFunction::Push,
302 BuiltinFunction::Pop,
303 BuiltinFunction::First,
304 BuiltinFunction::Last,
305 BuiltinFunction::Zip,
306 BuiltinFunction::Filled,
307 BuiltinFunction::Map,
309 BuiltinFunction::Filter,
310 BuiltinFunction::Reduce,
311 BuiltinFunction::ForEach,
312 BuiltinFunction::Find,
313 BuiltinFunction::FindIndex,
314 BuiltinFunction::Some,
315 BuiltinFunction::Every,
316 BuiltinFunction::Print,
318 BuiltinFunction::Format,
319 BuiltinFunction::Len,
320 BuiltinFunction::Snapshot,
321 BuiltinFunction::Exit,
322 BuiltinFunction::ObjectRest,
324 BuiltinFunction::ControlFold,
326 BuiltinFunction::TypeOf,
328 BuiltinFunction::IsNumber,
329 BuiltinFunction::IsString,
330 BuiltinFunction::IsBool,
331 BuiltinFunction::IsArray,
332 BuiltinFunction::IsObject,
333 BuiltinFunction::IsDataRow,
334 BuiltinFunction::ToString,
336 BuiltinFunction::ToNumber,
337 BuiltinFunction::ToBool,
338 BuiltinFunction::NativePtrSize,
340 BuiltinFunction::NativePtrNewCell,
341 BuiltinFunction::NativePtrFreeCell,
342 BuiltinFunction::NativePtrReadPtr,
343 BuiltinFunction::NativePtrWritePtr,
344 BuiltinFunction::NativeTableFromArrowC,
345 BuiltinFunction::NativeTableFromArrowCTyped,
346 BuiltinFunction::NativeTableBindType,
347 BuiltinFunction::FormatValueWithMeta,
349 BuiltinFunction::FormatValueWithSpec,
350 BuiltinFunction::IntrinsicSum,
352 BuiltinFunction::IntrinsicMean,
353 BuiltinFunction::IntrinsicMin,
354 BuiltinFunction::IntrinsicMax,
355 BuiltinFunction::IntrinsicStd,
356 BuiltinFunction::IntrinsicVariance,
357 BuiltinFunction::IntrinsicRandom,
359 BuiltinFunction::IntrinsicRandomInt,
360 BuiltinFunction::IntrinsicRandomSeed,
361 BuiltinFunction::IntrinsicRandomNormal,
362 BuiltinFunction::IntrinsicRandomArray,
363 BuiltinFunction::IntrinsicDistUniform,
365 BuiltinFunction::IntrinsicDistLognormal,
366 BuiltinFunction::IntrinsicDistExponential,
367 BuiltinFunction::IntrinsicDistPoisson,
368 BuiltinFunction::IntrinsicDistSampleN,
369 BuiltinFunction::IntrinsicBrownianMotion,
371 BuiltinFunction::IntrinsicGbm,
372 BuiltinFunction::IntrinsicOuProcess,
373 BuiltinFunction::IntrinsicRandomWalk,
374 BuiltinFunction::IntrinsicRollingSum,
376 BuiltinFunction::IntrinsicRollingMean,
377 BuiltinFunction::IntrinsicRollingStd,
378 BuiltinFunction::IntrinsicRollingMin,
379 BuiltinFunction::IntrinsicRollingMax,
380 BuiltinFunction::IntrinsicEma,
381 BuiltinFunction::IntrinsicLinearRecurrence,
382 BuiltinFunction::IntrinsicShift,
384 BuiltinFunction::IntrinsicDiff,
385 BuiltinFunction::IntrinsicPctChange,
386 BuiltinFunction::IntrinsicFillna,
387 BuiltinFunction::IntrinsicCumsum,
388 BuiltinFunction::IntrinsicCumprod,
389 BuiltinFunction::IntrinsicClip,
390 BuiltinFunction::IntrinsicCorrelation,
392 BuiltinFunction::IntrinsicCovariance,
393 BuiltinFunction::IntrinsicPercentile,
394 BuiltinFunction::IntrinsicMedian,
395 BuiltinFunction::IntrinsicAtan2,
397 BuiltinFunction::IntrinsicSinh,
398 BuiltinFunction::IntrinsicCosh,
399 BuiltinFunction::IntrinsicTanh,
400 BuiltinFunction::IntrinsicCharCode,
402 BuiltinFunction::IntrinsicFromCharCode,
403 BuiltinFunction::IntrinsicSeries,
405 BuiltinFunction::IntrinsicVecAbs,
407 BuiltinFunction::IntrinsicVecSqrt,
408 BuiltinFunction::IntrinsicVecLn,
409 BuiltinFunction::IntrinsicVecExp,
410 BuiltinFunction::IntrinsicVecAdd,
411 BuiltinFunction::IntrinsicVecSub,
412 BuiltinFunction::IntrinsicVecMul,
413 BuiltinFunction::IntrinsicVecDiv,
414 BuiltinFunction::IntrinsicVecMax,
415 BuiltinFunction::IntrinsicVecMin,
416 BuiltinFunction::IntrinsicVecSelect,
417 BuiltinFunction::IntrinsicMatMulVec,
419 BuiltinFunction::IntrinsicMatMulMat,
420 BuiltinFunction::EvalTimeRef,
422 BuiltinFunction::EvalDateTimeExpr,
423 BuiltinFunction::EvalDataDateTimeRef,
424 BuiltinFunction::EvalDataSet,
425 BuiltinFunction::EvalDataRelative,
426 BuiltinFunction::EvalDataRelativeRange,
427 BuiltinFunction::SomeCtor,
429 BuiltinFunction::OkCtor,
430 BuiltinFunction::ErrCtor,
431 BuiltinFunction::HashMapCtor,
433 BuiltinFunction::SetCtor,
434 BuiltinFunction::DequeCtor,
435 BuiltinFunction::PriorityQueueCtor,
436 BuiltinFunction::JsonObjectGet,
438 BuiltinFunction::JsonArrayAt,
439 BuiltinFunction::JsonObjectKeys,
440 BuiltinFunction::JsonArrayLen,
441 BuiltinFunction::JsonObjectLen,
442 BuiltinFunction::WindowRowNumber,
444 BuiltinFunction::WindowRank,
445 BuiltinFunction::WindowDenseRank,
446 BuiltinFunction::WindowNtile,
447 BuiltinFunction::WindowLag,
448 BuiltinFunction::WindowLead,
449 BuiltinFunction::WindowFirstValue,
450 BuiltinFunction::WindowLastValue,
451 BuiltinFunction::WindowNthValue,
452 BuiltinFunction::WindowSum,
453 BuiltinFunction::WindowAvg,
454 BuiltinFunction::WindowMin,
455 BuiltinFunction::WindowMax,
456 BuiltinFunction::WindowCount,
457 BuiltinFunction::JoinExecute,
459 BuiltinFunction::Reflect,
461 BuiltinFunction::MakeContentText,
463 BuiltinFunction::MakeContentFragment,
464 BuiltinFunction::ApplyContentStyle,
465 BuiltinFunction::MakeContentChartFromValue,
466 BuiltinFunction::ContentChart,
467 BuiltinFunction::ContentTextCtor,
468 BuiltinFunction::ContentTableCtor,
469 BuiltinFunction::ContentCodeCtor,
470 BuiltinFunction::ContentKvCtor,
471 BuiltinFunction::ContentFragmentCtor,
472 BuiltinFunction::DateTimeNow,
474 BuiltinFunction::DateTimeUtc,
475 BuiltinFunction::DateTimeParse,
476 BuiltinFunction::DateTimeFromEpoch,
477 BuiltinFunction::DateTimeFromParts,
478 BuiltinFunction::DateTimeFromUnixSecs,
479 BuiltinFunction::MutexCtor,
481 BuiltinFunction::AtomicCtor,
482 BuiltinFunction::LazyCtor,
483 BuiltinFunction::ChannelCtor,
484 BuiltinFunction::Sign,
486 BuiltinFunction::Gcd,
487 BuiltinFunction::Lcm,
488 BuiltinFunction::Hypot,
489 BuiltinFunction::Clamp,
490 BuiltinFunction::IsNaN,
491 BuiltinFunction::IsFinite,
492 BuiltinFunction::MakeTableFromRows,
494];
495
496fn vm_only_opcode_reason(_opcode: OpCode) -> Option<&'static str> {
497 None
501}
502
503fn is_supported_builtin(_builtin: BuiltinFunction) -> bool {
504 true
507}
508
509pub fn preflight_instructions(instructions: &[Instruction]) -> JitPreflightReport {
515 let mut report = JitPreflightReport::default();
516
517 for instr in instructions {
518 if vm_only_opcode_reason(instr.opcode).is_some() {
519 push_unique_opcode(&mut report.vm_only_opcodes, instr.opcode);
520 }
521
522 if instr.opcode == OpCode::BuiltinCall {
523 if let Some(Operand::Builtin(builtin)) = instr.operand {
524 if !is_supported_builtin(builtin) {
525 push_unique_builtin(&mut report.unsupported_builtins, builtin);
526 }
527 }
528 }
529 }
530
531 sort_opcodes(&mut report.vm_only_opcodes);
532 sort_builtins(&mut report.unsupported_builtins);
533 report
534}
535
536pub fn preflight_blob_jit_compatibility(
542 blob: &shape_vm::bytecode::FunctionBlob,
543) -> JitPreflightReport {
544 preflight_instructions(&blob.instructions)
545}
546
547pub fn preflight_jit_compatibility(program: &BytecodeProgram) -> JitPreflightReport {
549 let mut report = JitPreflightReport::default();
550
551 for instr in &program.instructions {
552 if vm_only_opcode_reason(instr.opcode).is_some() {
553 push_unique_opcode(&mut report.vm_only_opcodes, instr.opcode);
554 }
555
556 if instr.opcode == OpCode::BuiltinCall {
557 if let Some(Operand::Builtin(builtin)) = instr.operand {
558 if !is_supported_builtin(builtin) {
559 push_unique_builtin(&mut report.unsupported_builtins, builtin);
560 }
561 }
562 }
563 }
564
565 sort_opcodes(&mut report.vm_only_opcodes);
566 sort_builtins(&mut report.unsupported_builtins);
567 report
568}
569
570pub fn build_program_parity_matrix(program: &BytecodeProgram) -> Vec<JitParityEntry> {
575 let mut opcodes = Vec::new();
576 let mut builtins = Vec::new();
577
578 for instr in &program.instructions {
579 push_unique_opcode(&mut opcodes, instr.opcode);
580 if instr.opcode == OpCode::BuiltinCall {
581 if let Some(Operand::Builtin(builtin)) = instr.operand {
582 push_unique_builtin(&mut builtins, builtin);
583 }
584 }
585 }
586
587 sort_opcodes(&mut opcodes);
588 sort_builtins(&mut builtins);
589
590 let mut matrix = Vec::with_capacity(opcodes.len() + builtins.len());
591
592 for opcode in opcodes {
593 if let Some(reason) = vm_only_opcode_reason(opcode) {
594 matrix.push(JitParityEntry {
595 target: JitParityTarget::Opcode(opcode),
596 jit_supported: false,
597 reason,
598 });
599 } else {
600 matrix.push(JitParityEntry {
601 target: JitParityTarget::Opcode(opcode),
602 jit_supported: true,
603 reason: "Opcode is lowered by the JIT translator.",
604 });
605 }
606 }
607
608 for builtin in builtins {
609 if is_supported_builtin(builtin) {
610 matrix.push(JitParityEntry {
611 target: JitParityTarget::Builtin(builtin),
612 jit_supported: true,
613 reason: "Builtin is lowered by JIT builtin handlers.",
614 });
615 } else {
616 matrix.push(JitParityEntry {
617 target: JitParityTarget::Builtin(builtin),
618 jit_supported: false,
619 reason: "Builtin is not lowered by JIT and must run on VM.",
620 });
621 }
622 }
623
624 matrix.sort_by_key(|entry| format!("{:?}", entry.target));
625 matrix
626}
627
628pub fn build_full_opcode_parity_matrix() -> Vec<JitParityEntry> {
630 let mut matrix = Vec::with_capacity(ALL_OPCODES.len());
631 for &opcode in ALL_OPCODES {
632 if let Some(reason) = vm_only_opcode_reason(opcode) {
633 matrix.push(JitParityEntry {
634 target: JitParityTarget::Opcode(opcode),
635 jit_supported: false,
636 reason,
637 });
638 } else {
639 matrix.push(JitParityEntry {
640 target: JitParityTarget::Opcode(opcode),
641 jit_supported: true,
642 reason: "Opcode is lowered by the JIT translator.",
643 });
644 }
645 }
646 matrix.sort_by_key(|entry| format!("{:?}", entry.target));
647 matrix
648}
649
650pub fn build_full_builtin_parity_matrix() -> Vec<JitParityEntry> {
652 let mut matrix = Vec::with_capacity(ALL_BUILTINS.len());
653 for &builtin in ALL_BUILTINS {
654 if is_supported_builtin(builtin) {
655 matrix.push(JitParityEntry {
656 target: JitParityTarget::Builtin(builtin),
657 jit_supported: true,
658 reason: "Builtin is lowered by JIT builtin handlers.",
659 });
660 } else {
661 matrix.push(JitParityEntry {
662 target: JitParityTarget::Builtin(builtin),
663 jit_supported: false,
664 reason: "Builtin is not lowered by JIT and must run on VM.",
665 });
666 }
667 }
668 matrix.sort_by_key(|entry| format!("{:?}", entry.target));
669 matrix
670}
671
672#[inline(always)]
674pub fn can_jit_compile(program: &BytecodeProgram) -> bool {
675 preflight_jit_compatibility(program).can_jit()
676}
677
678#[inline(always)]
680pub fn get_unsupported_opcodes(program: &BytecodeProgram) -> Vec<OpCode> {
681 let report = preflight_jit_compatibility(program);
682 let mut unsupported = report.vm_only_opcodes;
683
684 if !report.unsupported_builtins.is_empty() && !unsupported.contains(&OpCode::BuiltinCall) {
685 unsupported.push(OpCode::BuiltinCall);
686 }
687
688 sort_opcodes(&mut unsupported);
689 unsupported
690}
691
692pub fn get_incomplete_opcodes(_program: &BytecodeProgram) -> Vec<OpCode> {
694 Vec::new()
696}
697
698#[cfg(test)]
699mod tests {
700 use super::*;
701 use shape_vm::bytecode::{Instruction, Operand};
702
703 #[test]
704 fn preflight_accepts_all_opcodes() {
705 let program = BytecodeProgram {
707 instructions: vec![Instruction::simple(OpCode::Await)],
708 ..Default::default()
709 };
710 let report = preflight_jit_compatibility(&program);
711 assert!(report.can_jit());
712 }
713
714 #[test]
715 fn preflight_accepts_all_builtins() {
716 let program = BytecodeProgram {
718 instructions: vec![Instruction::new(
719 OpCode::BuiltinCall,
720 Some(Operand::Builtin(BuiltinFunction::Snapshot)),
721 )],
722 ..Default::default()
723 };
724 let report = preflight_jit_compatibility(&program);
725 assert!(report.can_jit());
726 }
727
728 #[test]
729 fn parity_matrix_marks_all_builtins_supported() {
730 let program = BytecodeProgram {
731 instructions: vec![Instruction::new(
732 OpCode::BuiltinCall,
733 Some(Operand::Builtin(BuiltinFunction::Snapshot)),
734 )],
735 ..Default::default()
736 };
737 let matrix = build_program_parity_matrix(&program);
738 assert!(matrix.iter().all(|row| row.jit_supported));
739 }
740
741 #[test]
742 fn preflight_instructions_compatible_slice() {
743 let instructions = vec![
744 Instruction::simple(OpCode::PushConst),
745 Instruction::simple(OpCode::Add),
746 Instruction::simple(OpCode::ReturnValue),
747 ];
748 let report = preflight_instructions(&instructions);
749 assert!(report.can_jit());
750 }
751
752 #[test]
753 fn preflight_instructions_all_opcodes_pass() {
754 let instructions = vec![
756 Instruction::simple(OpCode::PushConst),
757 Instruction::simple(OpCode::Await),
758 Instruction::simple(OpCode::ReturnValue),
759 ];
760 let report = preflight_instructions(&instructions);
761 assert!(report.can_jit());
762 }
763
764 #[test]
765 fn preflight_blob_passes_with_spawn_task() {
766 use shape_vm::bytecode::FunctionBlob;
767
768 let blob = FunctionBlob {
769 content_hash: shape_vm::bytecode::FunctionHash::ZERO,
770 name: "test_fn".to_string(),
771 arity: 0,
772 param_names: vec![],
773 locals_count: 0,
774 is_closure: false,
775 captures_count: 0,
776 is_async: false,
777 ref_params: vec![],
778 ref_mutates: vec![],
779 mutable_captures: vec![],
780 instructions: vec![
781 Instruction::simple(OpCode::PushConst),
782 Instruction::simple(OpCode::SpawnTask),
783 Instruction::simple(OpCode::ReturnValue),
784 ],
785 constants: vec![],
786 strings: vec![],
787 required_permissions: Default::default(),
788 dependencies: vec![],
789 callee_names: vec![],
790 type_schemas: vec![],
791 source_map: vec![],
792 foreign_dependencies: vec![],
793 frame_descriptor: None,
794 };
795
796 let report = preflight_blob_jit_compatibility(&blob);
797 assert!(report.can_jit());
798 }
799
800 #[test]
801 fn all_opcodes_pass_preflight() {
802 for &opcode in ALL_OPCODES {
804 assert!(
805 vm_only_opcode_reason(opcode).is_none(),
806 "Opcode {:?} should pass preflight",
807 opcode
808 );
809 }
810 }
811
812 #[test]
813 fn all_builtins_pass_preflight() {
814 for &builtin in ALL_BUILTINS {
816 assert!(
817 is_supported_builtin(builtin),
818 "Builtin {:?} should be supported",
819 builtin
820 );
821 }
822 }
823}