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::Pattern,
207 OpCode::CallMethod,
208 OpCode::PushTimeframe,
209 OpCode::PopTimeframe,
210 OpCode::RunSimulation,
211 OpCode::BuiltinCall,
212 OpCode::TypeCheck,
213 OpCode::Convert,
214 OpCode::ModNumber,
215 OpCode::ModDecimal,
216 OpCode::PowInt,
217 OpCode::PowNumber,
218 OpCode::PowDecimal,
219 OpCode::LteNumber,
220 OpCode::LteDecimal,
221 OpCode::SetupTry,
222 OpCode::PopHandler,
223 OpCode::Throw,
224 OpCode::TryUnwrap,
225 OpCode::UnwrapOption,
226 OpCode::ErrorContext,
227 OpCode::IsOk,
228 OpCode::IsErr,
229 OpCode::UnwrapOk,
230 OpCode::UnwrapErr,
231 OpCode::SliceAccess,
232 OpCode::NullCoalesce,
233 OpCode::MakeRange,
234 OpCode::GetDataField,
235 OpCode::GetDataRow,
236 OpCode::GetFieldTyped,
237 OpCode::SetFieldTyped,
238 OpCode::NewTypedObject,
239 OpCode::TypedMergeObject,
240 OpCode::WrapTypeAnnotation,
241 OpCode::Yield,
242 OpCode::Suspend,
243 OpCode::Resume,
244 OpCode::Poll,
245 OpCode::AwaitBar,
246 OpCode::AwaitTick,
247 OpCode::Await,
248 OpCode::SpawnTask,
249 OpCode::EmitAlert,
250 OpCode::EmitEvent,
251 OpCode::JoinInit,
252 OpCode::JoinAwait,
253 OpCode::CancelTask,
254 OpCode::AsyncScopeEnter,
255 OpCode::AsyncScopeExit,
256 OpCode::LoadColF64,
257 OpCode::LoadColI64,
258 OpCode::LoadColBool,
259 OpCode::LoadColStr,
260 OpCode::BindSchema,
261 OpCode::BoxTraitObject,
262 OpCode::DynMethodCall,
263 OpCode::Nop,
264 OpCode::Halt,
265 OpCode::Debug,
266 OpCode::IntToNumber,
267 OpCode::NumberToInt,
268 OpCode::CallForeign,
269 OpCode::AddTyped,
270 OpCode::SubTyped,
271 OpCode::MulTyped,
272 OpCode::DivTyped,
273 OpCode::ModTyped,
274 OpCode::CmpTyped,
275 OpCode::StoreLocalTyped,
276 OpCode::CastWidth,
277];
278
279const ALL_BUILTINS: &[BuiltinFunction] = &[
280 BuiltinFunction::Abs,
282 BuiltinFunction::Sqrt,
283 BuiltinFunction::Ln,
284 BuiltinFunction::Pow,
285 BuiltinFunction::Exp,
286 BuiltinFunction::Log,
287 BuiltinFunction::Min,
288 BuiltinFunction::Max,
289 BuiltinFunction::Floor,
290 BuiltinFunction::Ceil,
291 BuiltinFunction::Round,
292 BuiltinFunction::Sin,
293 BuiltinFunction::Cos,
294 BuiltinFunction::Tan,
295 BuiltinFunction::Asin,
296 BuiltinFunction::Acos,
297 BuiltinFunction::Atan,
298 BuiltinFunction::StdDev,
299 BuiltinFunction::Range,
301 BuiltinFunction::Slice,
302 BuiltinFunction::Push,
303 BuiltinFunction::Pop,
304 BuiltinFunction::First,
305 BuiltinFunction::Last,
306 BuiltinFunction::Zip,
307 BuiltinFunction::Filled,
308 BuiltinFunction::Map,
310 BuiltinFunction::Filter,
311 BuiltinFunction::Reduce,
312 BuiltinFunction::ForEach,
313 BuiltinFunction::Find,
314 BuiltinFunction::FindIndex,
315 BuiltinFunction::Some,
316 BuiltinFunction::Every,
317 BuiltinFunction::Print,
319 BuiltinFunction::Format,
320 BuiltinFunction::Len,
321 BuiltinFunction::Snapshot,
322 BuiltinFunction::Exit,
323 BuiltinFunction::ObjectRest,
325 BuiltinFunction::ControlFold,
327 BuiltinFunction::TypeOf,
329 BuiltinFunction::IsNumber,
330 BuiltinFunction::IsString,
331 BuiltinFunction::IsBool,
332 BuiltinFunction::IsArray,
333 BuiltinFunction::IsObject,
334 BuiltinFunction::IsDataRow,
335 BuiltinFunction::ToString,
337 BuiltinFunction::ToNumber,
338 BuiltinFunction::ToBool,
339 BuiltinFunction::IntoInt,
340 BuiltinFunction::IntoNumber,
341 BuiltinFunction::IntoDecimal,
342 BuiltinFunction::IntoBool,
343 BuiltinFunction::IntoString,
344 BuiltinFunction::TryIntoInt,
345 BuiltinFunction::TryIntoNumber,
346 BuiltinFunction::TryIntoDecimal,
347 BuiltinFunction::TryIntoBool,
348 BuiltinFunction::TryIntoString,
349 BuiltinFunction::NativePtrSize,
351 BuiltinFunction::NativePtrNewCell,
352 BuiltinFunction::NativePtrFreeCell,
353 BuiltinFunction::NativePtrReadPtr,
354 BuiltinFunction::NativePtrWritePtr,
355 BuiltinFunction::NativeTableFromArrowC,
356 BuiltinFunction::NativeTableFromArrowCTyped,
357 BuiltinFunction::NativeTableBindType,
358 BuiltinFunction::FormatValueWithMeta,
360 BuiltinFunction::FormatValueWithSpec,
361 BuiltinFunction::IntrinsicSum,
363 BuiltinFunction::IntrinsicMean,
364 BuiltinFunction::IntrinsicMin,
365 BuiltinFunction::IntrinsicMax,
366 BuiltinFunction::IntrinsicStd,
367 BuiltinFunction::IntrinsicVariance,
368 BuiltinFunction::IntrinsicRandom,
370 BuiltinFunction::IntrinsicRandomInt,
371 BuiltinFunction::IntrinsicRandomSeed,
372 BuiltinFunction::IntrinsicRandomNormal,
373 BuiltinFunction::IntrinsicRandomArray,
374 BuiltinFunction::IntrinsicDistUniform,
376 BuiltinFunction::IntrinsicDistLognormal,
377 BuiltinFunction::IntrinsicDistExponential,
378 BuiltinFunction::IntrinsicDistPoisson,
379 BuiltinFunction::IntrinsicDistSampleN,
380 BuiltinFunction::IntrinsicBrownianMotion,
382 BuiltinFunction::IntrinsicGbm,
383 BuiltinFunction::IntrinsicOuProcess,
384 BuiltinFunction::IntrinsicRandomWalk,
385 BuiltinFunction::IntrinsicRollingSum,
387 BuiltinFunction::IntrinsicRollingMean,
388 BuiltinFunction::IntrinsicRollingStd,
389 BuiltinFunction::IntrinsicRollingMin,
390 BuiltinFunction::IntrinsicRollingMax,
391 BuiltinFunction::IntrinsicEma,
392 BuiltinFunction::IntrinsicLinearRecurrence,
393 BuiltinFunction::IntrinsicShift,
395 BuiltinFunction::IntrinsicDiff,
396 BuiltinFunction::IntrinsicPctChange,
397 BuiltinFunction::IntrinsicFillna,
398 BuiltinFunction::IntrinsicCumsum,
399 BuiltinFunction::IntrinsicCumprod,
400 BuiltinFunction::IntrinsicClip,
401 BuiltinFunction::IntrinsicCorrelation,
403 BuiltinFunction::IntrinsicCovariance,
404 BuiltinFunction::IntrinsicPercentile,
405 BuiltinFunction::IntrinsicMedian,
406 BuiltinFunction::IntrinsicCharCode,
408 BuiltinFunction::IntrinsicFromCharCode,
409 BuiltinFunction::IntrinsicSeries,
411 BuiltinFunction::IntrinsicVecAbs,
413 BuiltinFunction::IntrinsicVecSqrt,
414 BuiltinFunction::IntrinsicVecLn,
415 BuiltinFunction::IntrinsicVecExp,
416 BuiltinFunction::IntrinsicVecAdd,
417 BuiltinFunction::IntrinsicVecSub,
418 BuiltinFunction::IntrinsicVecMul,
419 BuiltinFunction::IntrinsicVecDiv,
420 BuiltinFunction::IntrinsicVecMax,
421 BuiltinFunction::IntrinsicVecMin,
422 BuiltinFunction::IntrinsicVecSelect,
423 BuiltinFunction::IntrinsicMatMulVec,
425 BuiltinFunction::IntrinsicMatMulMat,
426 BuiltinFunction::EvalTimeRef,
428 BuiltinFunction::EvalDateTimeExpr,
429 BuiltinFunction::EvalDataDateTimeRef,
430 BuiltinFunction::EvalDataSet,
431 BuiltinFunction::EvalDataRelative,
432 BuiltinFunction::EvalDataRelativeRange,
433 BuiltinFunction::SomeCtor,
435 BuiltinFunction::OkCtor,
436 BuiltinFunction::ErrCtor,
437 BuiltinFunction::HashMapCtor,
439 BuiltinFunction::SetCtor,
440 BuiltinFunction::DequeCtor,
441 BuiltinFunction::PriorityQueueCtor,
442 BuiltinFunction::JsonObjectGet,
444 BuiltinFunction::JsonArrayAt,
445 BuiltinFunction::JsonObjectKeys,
446 BuiltinFunction::JsonArrayLen,
447 BuiltinFunction::JsonObjectLen,
448 BuiltinFunction::WindowRowNumber,
450 BuiltinFunction::WindowRank,
451 BuiltinFunction::WindowDenseRank,
452 BuiltinFunction::WindowNtile,
453 BuiltinFunction::WindowLag,
454 BuiltinFunction::WindowLead,
455 BuiltinFunction::WindowFirstValue,
456 BuiltinFunction::WindowLastValue,
457 BuiltinFunction::WindowNthValue,
458 BuiltinFunction::WindowSum,
459 BuiltinFunction::WindowAvg,
460 BuiltinFunction::WindowMin,
461 BuiltinFunction::WindowMax,
462 BuiltinFunction::WindowCount,
463 BuiltinFunction::JoinExecute,
465 BuiltinFunction::Reflect,
467 BuiltinFunction::MakeContentText,
469 BuiltinFunction::MakeContentFragment,
470 BuiltinFunction::ApplyContentStyle,
471 BuiltinFunction::MakeContentChartFromValue,
472 BuiltinFunction::ContentChart,
473 BuiltinFunction::ContentTextCtor,
474 BuiltinFunction::ContentTableCtor,
475 BuiltinFunction::ContentCodeCtor,
476 BuiltinFunction::ContentKvCtor,
477 BuiltinFunction::ContentFragmentCtor,
478 BuiltinFunction::DateTimeNow,
480 BuiltinFunction::DateTimeUtc,
481 BuiltinFunction::DateTimeParse,
482 BuiltinFunction::DateTimeFromEpoch,
483 BuiltinFunction::MutexCtor,
485 BuiltinFunction::AtomicCtor,
486 BuiltinFunction::LazyCtor,
487 BuiltinFunction::ChannelCtor,
488 BuiltinFunction::Sign,
490 BuiltinFunction::Gcd,
491 BuiltinFunction::Lcm,
492 BuiltinFunction::Hypot,
493 BuiltinFunction::Clamp,
494 BuiltinFunction::IsNaN,
495 BuiltinFunction::IsFinite,
496 BuiltinFunction::MakeTableFromRows,
498];
499
500fn vm_only_opcode_reason(_opcode: OpCode) -> Option<&'static str> {
501 None
505}
506
507fn is_supported_builtin(_builtin: BuiltinFunction) -> bool {
508 true
511}
512
513pub fn preflight_instructions(instructions: &[Instruction]) -> JitPreflightReport {
519 let mut report = JitPreflightReport::default();
520
521 for instr in instructions {
522 if vm_only_opcode_reason(instr.opcode).is_some() {
523 push_unique_opcode(&mut report.vm_only_opcodes, instr.opcode);
524 }
525
526 if instr.opcode == OpCode::BuiltinCall {
527 if let Some(Operand::Builtin(builtin)) = instr.operand {
528 if !is_supported_builtin(builtin) {
529 push_unique_builtin(&mut report.unsupported_builtins, builtin);
530 }
531 }
532 }
533 }
534
535 sort_opcodes(&mut report.vm_only_opcodes);
536 sort_builtins(&mut report.unsupported_builtins);
537 report
538}
539
540pub fn preflight_blob_jit_compatibility(
546 blob: &shape_vm::bytecode::FunctionBlob,
547) -> JitPreflightReport {
548 preflight_instructions(&blob.instructions)
549}
550
551pub fn preflight_jit_compatibility(program: &BytecodeProgram) -> JitPreflightReport {
553 let mut report = JitPreflightReport::default();
554
555 for instr in &program.instructions {
556 if vm_only_opcode_reason(instr.opcode).is_some() {
557 push_unique_opcode(&mut report.vm_only_opcodes, instr.opcode);
558 }
559
560 if instr.opcode == OpCode::BuiltinCall {
561 if let Some(Operand::Builtin(builtin)) = instr.operand {
562 if !is_supported_builtin(builtin) {
563 push_unique_builtin(&mut report.unsupported_builtins, builtin);
564 }
565 }
566 }
567 }
568
569 sort_opcodes(&mut report.vm_only_opcodes);
570 sort_builtins(&mut report.unsupported_builtins);
571 report
572}
573
574pub fn build_program_parity_matrix(program: &BytecodeProgram) -> Vec<JitParityEntry> {
579 let mut opcodes = Vec::new();
580 let mut builtins = Vec::new();
581
582 for instr in &program.instructions {
583 push_unique_opcode(&mut opcodes, instr.opcode);
584 if instr.opcode == OpCode::BuiltinCall {
585 if let Some(Operand::Builtin(builtin)) = instr.operand {
586 push_unique_builtin(&mut builtins, builtin);
587 }
588 }
589 }
590
591 sort_opcodes(&mut opcodes);
592 sort_builtins(&mut builtins);
593
594 let mut matrix = Vec::with_capacity(opcodes.len() + builtins.len());
595
596 for opcode in opcodes {
597 if let Some(reason) = vm_only_opcode_reason(opcode) {
598 matrix.push(JitParityEntry {
599 target: JitParityTarget::Opcode(opcode),
600 jit_supported: false,
601 reason,
602 });
603 } else {
604 matrix.push(JitParityEntry {
605 target: JitParityTarget::Opcode(opcode),
606 jit_supported: true,
607 reason: "Opcode is lowered by the JIT translator.",
608 });
609 }
610 }
611
612 for builtin in builtins {
613 if is_supported_builtin(builtin) {
614 matrix.push(JitParityEntry {
615 target: JitParityTarget::Builtin(builtin),
616 jit_supported: true,
617 reason: "Builtin is lowered by JIT builtin handlers.",
618 });
619 } else {
620 matrix.push(JitParityEntry {
621 target: JitParityTarget::Builtin(builtin),
622 jit_supported: false,
623 reason: "Builtin is not lowered by JIT and must run on VM.",
624 });
625 }
626 }
627
628 matrix.sort_by_key(|entry| format!("{:?}", entry.target));
629 matrix
630}
631
632pub fn build_full_opcode_parity_matrix() -> Vec<JitParityEntry> {
634 let mut matrix = Vec::with_capacity(ALL_OPCODES.len());
635 for &opcode in ALL_OPCODES {
636 if let Some(reason) = vm_only_opcode_reason(opcode) {
637 matrix.push(JitParityEntry {
638 target: JitParityTarget::Opcode(opcode),
639 jit_supported: false,
640 reason,
641 });
642 } else {
643 matrix.push(JitParityEntry {
644 target: JitParityTarget::Opcode(opcode),
645 jit_supported: true,
646 reason: "Opcode is lowered by the JIT translator.",
647 });
648 }
649 }
650 matrix.sort_by_key(|entry| format!("{:?}", entry.target));
651 matrix
652}
653
654pub fn build_full_builtin_parity_matrix() -> Vec<JitParityEntry> {
656 let mut matrix = Vec::with_capacity(ALL_BUILTINS.len());
657 for &builtin in ALL_BUILTINS {
658 if is_supported_builtin(builtin) {
659 matrix.push(JitParityEntry {
660 target: JitParityTarget::Builtin(builtin),
661 jit_supported: true,
662 reason: "Builtin is lowered by JIT builtin handlers.",
663 });
664 } else {
665 matrix.push(JitParityEntry {
666 target: JitParityTarget::Builtin(builtin),
667 jit_supported: false,
668 reason: "Builtin is not lowered by JIT and must run on VM.",
669 });
670 }
671 }
672 matrix.sort_by_key(|entry| format!("{:?}", entry.target));
673 matrix
674}
675
676#[inline(always)]
678pub fn can_jit_compile(program: &BytecodeProgram) -> bool {
679 preflight_jit_compatibility(program).can_jit()
680}
681
682#[inline(always)]
684pub fn get_unsupported_opcodes(program: &BytecodeProgram) -> Vec<OpCode> {
685 let report = preflight_jit_compatibility(program);
686 let mut unsupported = report.vm_only_opcodes;
687
688 if !report.unsupported_builtins.is_empty() && !unsupported.contains(&OpCode::BuiltinCall) {
689 unsupported.push(OpCode::BuiltinCall);
690 }
691
692 sort_opcodes(&mut unsupported);
693 unsupported
694}
695
696pub fn get_incomplete_opcodes(_program: &BytecodeProgram) -> Vec<OpCode> {
698 Vec::new()
700}
701
702#[cfg(test)]
703mod tests {
704 use super::*;
705 use shape_vm::bytecode::{Instruction, Operand};
706
707 #[test]
708 fn preflight_accepts_all_opcodes() {
709 let program = BytecodeProgram {
711 instructions: vec![Instruction::simple(OpCode::Await)],
712 ..Default::default()
713 };
714 let report = preflight_jit_compatibility(&program);
715 assert!(report.can_jit());
716 }
717
718 #[test]
719 fn preflight_accepts_all_builtins() {
720 let program = BytecodeProgram {
722 instructions: vec![Instruction::new(
723 OpCode::BuiltinCall,
724 Some(Operand::Builtin(BuiltinFunction::Snapshot)),
725 )],
726 ..Default::default()
727 };
728 let report = preflight_jit_compatibility(&program);
729 assert!(report.can_jit());
730 }
731
732 #[test]
733 fn parity_matrix_marks_all_builtins_supported() {
734 let program = BytecodeProgram {
735 instructions: vec![Instruction::new(
736 OpCode::BuiltinCall,
737 Some(Operand::Builtin(BuiltinFunction::Snapshot)),
738 )],
739 ..Default::default()
740 };
741 let matrix = build_program_parity_matrix(&program);
742 assert!(matrix.iter().all(|row| row.jit_supported));
743 }
744
745 #[test]
746 fn preflight_instructions_compatible_slice() {
747 let instructions = vec![
748 Instruction::simple(OpCode::PushConst),
749 Instruction::simple(OpCode::Add),
750 Instruction::simple(OpCode::ReturnValue),
751 ];
752 let report = preflight_instructions(&instructions);
753 assert!(report.can_jit());
754 }
755
756 #[test]
757 fn preflight_instructions_all_opcodes_pass() {
758 let instructions = vec![
760 Instruction::simple(OpCode::PushConst),
761 Instruction::simple(OpCode::Await),
762 Instruction::simple(OpCode::ReturnValue),
763 ];
764 let report = preflight_instructions(&instructions);
765 assert!(report.can_jit());
766 }
767
768 #[test]
769 fn preflight_blob_passes_with_spawn_task() {
770 use shape_vm::bytecode::FunctionBlob;
771
772 let blob = FunctionBlob {
773 content_hash: shape_vm::bytecode::FunctionHash::ZERO,
774 name: "test_fn".to_string(),
775 arity: 0,
776 param_names: vec![],
777 locals_count: 0,
778 is_closure: false,
779 captures_count: 0,
780 is_async: false,
781 ref_params: vec![],
782 ref_mutates: vec![],
783 mutable_captures: vec![],
784 instructions: vec![
785 Instruction::simple(OpCode::PushConst),
786 Instruction::simple(OpCode::SpawnTask),
787 Instruction::simple(OpCode::ReturnValue),
788 ],
789 constants: vec![],
790 strings: vec![],
791 required_permissions: Default::default(),
792 dependencies: vec![],
793 callee_names: vec![],
794 type_schemas: vec![],
795 source_map: vec![],
796 foreign_dependencies: vec![],
797 };
798
799 let report = preflight_blob_jit_compatibility(&blob);
800 assert!(report.can_jit());
801 }
802
803 #[test]
804 fn all_opcodes_pass_preflight() {
805 for &opcode in ALL_OPCODES {
807 assert!(
808 vm_only_opcode_reason(opcode).is_none(),
809 "Opcode {:?} should pass preflight",
810 opcode
811 );
812 }
813 }
814
815 #[test]
816 fn all_builtins_pass_preflight() {
817 for &builtin in ALL_BUILTINS {
819 assert!(
820 is_supported_builtin(builtin),
821 "Builtin {:?} should be supported",
822 builtin
823 );
824 }
825 }
826}