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::DateTimeFromParts,
484 BuiltinFunction::DateTimeFromUnixSecs,
485 BuiltinFunction::MutexCtor,
487 BuiltinFunction::AtomicCtor,
488 BuiltinFunction::LazyCtor,
489 BuiltinFunction::ChannelCtor,
490 BuiltinFunction::Sign,
492 BuiltinFunction::Gcd,
493 BuiltinFunction::Lcm,
494 BuiltinFunction::Hypot,
495 BuiltinFunction::Clamp,
496 BuiltinFunction::IsNaN,
497 BuiltinFunction::IsFinite,
498 BuiltinFunction::MakeTableFromRows,
500];
501
502fn vm_only_opcode_reason(_opcode: OpCode) -> Option<&'static str> {
503 None
507}
508
509fn is_supported_builtin(_builtin: BuiltinFunction) -> bool {
510 true
513}
514
515pub fn preflight_instructions(instructions: &[Instruction]) -> JitPreflightReport {
521 let mut report = JitPreflightReport::default();
522
523 for instr in instructions {
524 if vm_only_opcode_reason(instr.opcode).is_some() {
525 push_unique_opcode(&mut report.vm_only_opcodes, instr.opcode);
526 }
527
528 if instr.opcode == OpCode::BuiltinCall {
529 if let Some(Operand::Builtin(builtin)) = instr.operand {
530 if !is_supported_builtin(builtin) {
531 push_unique_builtin(&mut report.unsupported_builtins, builtin);
532 }
533 }
534 }
535 }
536
537 sort_opcodes(&mut report.vm_only_opcodes);
538 sort_builtins(&mut report.unsupported_builtins);
539 report
540}
541
542pub fn preflight_blob_jit_compatibility(
548 blob: &shape_vm::bytecode::FunctionBlob,
549) -> JitPreflightReport {
550 preflight_instructions(&blob.instructions)
551}
552
553pub fn preflight_jit_compatibility(program: &BytecodeProgram) -> JitPreflightReport {
555 let mut report = JitPreflightReport::default();
556
557 for instr in &program.instructions {
558 if vm_only_opcode_reason(instr.opcode).is_some() {
559 push_unique_opcode(&mut report.vm_only_opcodes, instr.opcode);
560 }
561
562 if instr.opcode == OpCode::BuiltinCall {
563 if let Some(Operand::Builtin(builtin)) = instr.operand {
564 if !is_supported_builtin(builtin) {
565 push_unique_builtin(&mut report.unsupported_builtins, builtin);
566 }
567 }
568 }
569 }
570
571 sort_opcodes(&mut report.vm_only_opcodes);
572 sort_builtins(&mut report.unsupported_builtins);
573 report
574}
575
576pub fn build_program_parity_matrix(program: &BytecodeProgram) -> Vec<JitParityEntry> {
581 let mut opcodes = Vec::new();
582 let mut builtins = Vec::new();
583
584 for instr in &program.instructions {
585 push_unique_opcode(&mut opcodes, instr.opcode);
586 if instr.opcode == OpCode::BuiltinCall {
587 if let Some(Operand::Builtin(builtin)) = instr.operand {
588 push_unique_builtin(&mut builtins, builtin);
589 }
590 }
591 }
592
593 sort_opcodes(&mut opcodes);
594 sort_builtins(&mut builtins);
595
596 let mut matrix = Vec::with_capacity(opcodes.len() + builtins.len());
597
598 for opcode in opcodes {
599 if let Some(reason) = vm_only_opcode_reason(opcode) {
600 matrix.push(JitParityEntry {
601 target: JitParityTarget::Opcode(opcode),
602 jit_supported: false,
603 reason,
604 });
605 } else {
606 matrix.push(JitParityEntry {
607 target: JitParityTarget::Opcode(opcode),
608 jit_supported: true,
609 reason: "Opcode is lowered by the JIT translator.",
610 });
611 }
612 }
613
614 for builtin in builtins {
615 if is_supported_builtin(builtin) {
616 matrix.push(JitParityEntry {
617 target: JitParityTarget::Builtin(builtin),
618 jit_supported: true,
619 reason: "Builtin is lowered by JIT builtin handlers.",
620 });
621 } else {
622 matrix.push(JitParityEntry {
623 target: JitParityTarget::Builtin(builtin),
624 jit_supported: false,
625 reason: "Builtin is not lowered by JIT and must run on VM.",
626 });
627 }
628 }
629
630 matrix.sort_by_key(|entry| format!("{:?}", entry.target));
631 matrix
632}
633
634pub fn build_full_opcode_parity_matrix() -> Vec<JitParityEntry> {
636 let mut matrix = Vec::with_capacity(ALL_OPCODES.len());
637 for &opcode in ALL_OPCODES {
638 if let Some(reason) = vm_only_opcode_reason(opcode) {
639 matrix.push(JitParityEntry {
640 target: JitParityTarget::Opcode(opcode),
641 jit_supported: false,
642 reason,
643 });
644 } else {
645 matrix.push(JitParityEntry {
646 target: JitParityTarget::Opcode(opcode),
647 jit_supported: true,
648 reason: "Opcode is lowered by the JIT translator.",
649 });
650 }
651 }
652 matrix.sort_by_key(|entry| format!("{:?}", entry.target));
653 matrix
654}
655
656pub fn build_full_builtin_parity_matrix() -> Vec<JitParityEntry> {
658 let mut matrix = Vec::with_capacity(ALL_BUILTINS.len());
659 for &builtin in ALL_BUILTINS {
660 if is_supported_builtin(builtin) {
661 matrix.push(JitParityEntry {
662 target: JitParityTarget::Builtin(builtin),
663 jit_supported: true,
664 reason: "Builtin is lowered by JIT builtin handlers.",
665 });
666 } else {
667 matrix.push(JitParityEntry {
668 target: JitParityTarget::Builtin(builtin),
669 jit_supported: false,
670 reason: "Builtin is not lowered by JIT and must run on VM.",
671 });
672 }
673 }
674 matrix.sort_by_key(|entry| format!("{:?}", entry.target));
675 matrix
676}
677
678#[inline(always)]
680pub fn can_jit_compile(program: &BytecodeProgram) -> bool {
681 preflight_jit_compatibility(program).can_jit()
682}
683
684#[inline(always)]
686pub fn get_unsupported_opcodes(program: &BytecodeProgram) -> Vec<OpCode> {
687 let report = preflight_jit_compatibility(program);
688 let mut unsupported = report.vm_only_opcodes;
689
690 if !report.unsupported_builtins.is_empty() && !unsupported.contains(&OpCode::BuiltinCall) {
691 unsupported.push(OpCode::BuiltinCall);
692 }
693
694 sort_opcodes(&mut unsupported);
695 unsupported
696}
697
698pub fn get_incomplete_opcodes(_program: &BytecodeProgram) -> Vec<OpCode> {
700 Vec::new()
702}
703
704#[cfg(test)]
705mod tests {
706 use super::*;
707 use shape_vm::bytecode::{Instruction, Operand};
708
709 #[test]
710 fn preflight_accepts_all_opcodes() {
711 let program = BytecodeProgram {
713 instructions: vec![Instruction::simple(OpCode::Await)],
714 ..Default::default()
715 };
716 let report = preflight_jit_compatibility(&program);
717 assert!(report.can_jit());
718 }
719
720 #[test]
721 fn preflight_accepts_all_builtins() {
722 let program = BytecodeProgram {
724 instructions: vec![Instruction::new(
725 OpCode::BuiltinCall,
726 Some(Operand::Builtin(BuiltinFunction::Snapshot)),
727 )],
728 ..Default::default()
729 };
730 let report = preflight_jit_compatibility(&program);
731 assert!(report.can_jit());
732 }
733
734 #[test]
735 fn parity_matrix_marks_all_builtins_supported() {
736 let program = BytecodeProgram {
737 instructions: vec![Instruction::new(
738 OpCode::BuiltinCall,
739 Some(Operand::Builtin(BuiltinFunction::Snapshot)),
740 )],
741 ..Default::default()
742 };
743 let matrix = build_program_parity_matrix(&program);
744 assert!(matrix.iter().all(|row| row.jit_supported));
745 }
746
747 #[test]
748 fn preflight_instructions_compatible_slice() {
749 let instructions = vec![
750 Instruction::simple(OpCode::PushConst),
751 Instruction::simple(OpCode::Add),
752 Instruction::simple(OpCode::ReturnValue),
753 ];
754 let report = preflight_instructions(&instructions);
755 assert!(report.can_jit());
756 }
757
758 #[test]
759 fn preflight_instructions_all_opcodes_pass() {
760 let instructions = vec![
762 Instruction::simple(OpCode::PushConst),
763 Instruction::simple(OpCode::Await),
764 Instruction::simple(OpCode::ReturnValue),
765 ];
766 let report = preflight_instructions(&instructions);
767 assert!(report.can_jit());
768 }
769
770 #[test]
771 fn preflight_blob_passes_with_spawn_task() {
772 use shape_vm::bytecode::FunctionBlob;
773
774 let blob = FunctionBlob {
775 content_hash: shape_vm::bytecode::FunctionHash::ZERO,
776 name: "test_fn".to_string(),
777 arity: 0,
778 param_names: vec![],
779 locals_count: 0,
780 is_closure: false,
781 captures_count: 0,
782 is_async: false,
783 ref_params: vec![],
784 ref_mutates: vec![],
785 mutable_captures: vec![],
786 instructions: vec![
787 Instruction::simple(OpCode::PushConst),
788 Instruction::simple(OpCode::SpawnTask),
789 Instruction::simple(OpCode::ReturnValue),
790 ],
791 constants: vec![],
792 strings: vec![],
793 required_permissions: Default::default(),
794 dependencies: vec![],
795 callee_names: vec![],
796 type_schemas: vec![],
797 source_map: vec![],
798 foreign_dependencies: vec![],
799 frame_descriptor: None,
800 };
801
802 let report = preflight_blob_jit_compatibility(&blob);
803 assert!(report.can_jit());
804 }
805
806 #[test]
807 fn all_opcodes_pass_preflight() {
808 for &opcode in ALL_OPCODES {
810 assert!(
811 vm_only_opcode_reason(opcode).is_none(),
812 "Opcode {:?} should pass preflight",
813 opcode
814 );
815 }
816 }
817
818 #[test]
819 fn all_builtins_pass_preflight() {
820 for &builtin in ALL_BUILTINS {
822 assert!(
823 is_supported_builtin(builtin),
824 "Builtin {:?} should be supported",
825 builtin
826 );
827 }
828 }
829}