1use std::sync::Arc;
4use std::sync::atomic::Ordering;
5
6use crate::bytecode::{Instruction, OpCode};
7use shape_value::{KindedSlot, NativeKind, VMError, ValueSlot};
8
9use super::debugger_integration::DebuggerIntegration;
10use super::{DebugVMState, ExecutionResult, VirtualMachine, async_ops};
11
12impl VirtualMachine {
13 pub fn execute(
26 &mut self,
27 ctx: Option<&mut shape_runtime::context::ExecutionContext>,
28 ) -> Result<KindedSlot, VMError> {
29 match self.execute_with_suspend(ctx)? {
30 ExecutionResult::Completed(slot) => Ok(slot),
31 ExecutionResult::Suspended { future_id, .. } => Err(VMError::Suspended {
32 future_id,
33 resume_ip: 0,
34 }),
35 }
36 }
37
38 pub fn execute_raw(
45 &mut self,
46 ctx: Option<&mut shape_runtime::context::ExecutionContext>,
47 ) -> Result<u64, VMError> {
48 match self.execute_with_suspend(ctx)? {
49 ExecutionResult::Completed(slot) => Ok(slot.raw()),
50 ExecutionResult::Suspended { future_id, .. } => Err(VMError::Suspended {
51 future_id,
52 resume_ip: 0,
53 }),
54 }
55 }
56
57 #[inline]
67 pub(crate) fn program_top_level_return_kind(&self) -> Option<NativeKind> {
68 self.program.top_level_frame.as_ref()?.return_kind
73 }
74
75 pub fn execute_with_suspend(
80 &mut self,
81 mut ctx: Option<&mut shape_runtime::context::ExecutionContext>,
82 ) -> Result<ExecutionResult, VMError> {
83 let _shape_scope =
89 shape_value::SyncShapeTableScope::enter(self.shape_table.clone());
90
91 self.clear_last_uncaught_exception();
92
93 if self.debugger.is_none() && !self.config.trace_execution {
96 return self.execute_fast_with_exceptions(ctx);
97 }
98
99 if let Some(ref mut debugger) = self.debugger {
101 debugger.start();
102 }
103
104 while self.ip < self.program.instructions.len() {
105 let should_break = if let Some(ref mut debugger) = self.debugger {
107 debugger.should_break(
108 &DebugVMState {
109 ip: self.ip,
110 call_stack_depth: self.call_stack.len(),
111 },
112 self.ip,
113 )
114 } else {
115 false
116 };
117
118 if should_break {
119 if let Some(ref mut debugger) = self.debugger {
120 debugger.debug_break(
121 &DebugVMState {
122 ip: self.ip,
123 call_stack_depth: self.call_stack.len(),
124 },
125 &self.program,
126 );
127 }
128 }
129
130 let instruction = self.program.instructions[self.ip];
131
132 if let Some(ref mut metrics) = self.metrics {
134 metrics.record_instruction();
135 }
136
137 if self.config.trace_execution {
139 if let Some(ref debugger) = self.debugger {
140 debugger.trace_instruction(
141 &DebugVMState {
142 ip: self.ip,
143 call_stack_depth: self.call_stack.len(),
144 },
145 &self.program,
146 &instruction,
147 );
148 } else {
149 self.trace_state();
150 }
151 }
152
153 self.ip += 1;
154 self.instruction_count += 1;
155
156 if self.instruction_count & 0x3FF == 0 && self.interrupt.load(Ordering::Relaxed) > 0 {
158 return Err(VMError::Interrupted);
159 }
160
161 if let Some(ref mut usage) = self.resource_usage {
163 usage
164 .tick_instruction()
165 .map_err(|e| VMError::RuntimeError(e.to_string()))?;
166 }
167
168 if self.instruction_count & 0x3FF == 0 {
170 self.poll_tier_completions();
171 }
172
173 #[cfg(feature = "gc")]
175 if self.instruction_count & 0x3FF == 0 {
176 self.gc_safepoint_poll();
177
178 if self.gc_heap.as_ref().map_or(false, |h| h.is_marking()) {
181 self.gc_incremental_mark_step();
182 }
183 }
184
185 if let Some(ref mut tt) = self.time_travel {
187 let current_ip = self.ip.saturating_sub(1);
188 let is_call_or_return = matches!(
189 instruction.opcode,
190 OpCode::Call
191 | OpCode::CallValue
192 | OpCode::CallClosure
193 | OpCode::CallFunctionIndirect
194 | OpCode::Return
195 | OpCode::ReturnValue
196 | OpCode::ReturnValueI64
197 | OpCode::ReturnValueU64
198 | OpCode::ReturnValueF64
199 | OpCode::ReturnValueI32
200 | OpCode::ReturnValueU32
201 | OpCode::ReturnValueI16
202 | OpCode::ReturnValueU16
203 | OpCode::ReturnValueI8
204 | OpCode::ReturnValueU8
205 | OpCode::ReturnValueBool
206 | OpCode::ReturnValuePtr
207 );
208 if tt.should_capture(current_ip, self.instruction_count as u64, is_call_or_return) {
209 if let Ok(store) = tt.snapshot_store() {
210 let store_ptr = store as *const shape_runtime::snapshot::SnapshotStore;
211 if let Ok(snap) = self.snapshot(unsafe { &*store_ptr }) {
212 let call_depth = self.call_stack.len();
213 self.time_travel.as_mut().unwrap().record(
214 snap,
215 current_ip,
216 self.instruction_count as u64,
217 call_depth,
218 );
219 }
220 }
221 }
222 }
223
224 let error_ip = self.ip.saturating_sub(1);
226
227 if let Err(err) = self.execute_instruction(&instruction, ctx.as_deref_mut()) {
228 if let VMError::Suspended {
230 future_id,
231 resume_ip,
232 } = err
233 {
234 return Ok(ExecutionResult::Suspended {
235 future_id,
236 resume_ip,
237 });
238 }
239
240 if matches!(err, VMError::ResumeRequested) {
242 self.apply_pending_resume()?;
243 continue;
244 }
245
246 if !self.exception_handlers.is_empty() {
247 let raw_payload = KindedSlot::from_string_arc(Arc::new(err.to_string()));
263 let payload = self.normalize_err_payload(raw_payload)?;
264 self.handle_exception(payload)?;
265 } else {
266 return Err(self.enrich_error_with_location(err, error_ip));
268 }
269 }
270
271 if self.pending_frame_resume.is_some() {
273 self.apply_pending_frame_resume()?;
274 }
275
276 if matches!(instruction.opcode, OpCode::Halt) {
278 break;
279 }
280 }
281
282 let tl = self.program.top_level_locals_count as usize;
287 Ok(ExecutionResult::Completed(if self.sp > tl {
288 self.sp -= 1;
289 let (bits, kind) = self.stack_take_kinded(self.sp);
290 KindedSlot::new(ValueSlot::from_raw(bits), kind)
291 } else {
292 KindedSlot::new(ValueSlot::none(), NativeKind::Bool)
293 }))
294 }
295
296 fn execute_fast_with_exceptions(
299 &mut self,
300 mut ctx: Option<&mut shape_runtime::context::ExecutionContext>,
301 ) -> Result<ExecutionResult, VMError> {
302 while self.ip < self.program.instructions.len() {
303 let ip = self.ip;
304 self.ip += 1;
305 self.instruction_count += 1;
306
307 if self.instruction_count & 0x3FF == 0 && self.interrupt.load(Ordering::Relaxed) > 0 {
309 return Err(VMError::Interrupted);
310 }
311
312 if self.instruction_count & 0x3FF == 0 {
314 self.poll_tier_completions();
315 }
316
317 #[cfg(feature = "gc")]
319 if self.instruction_count & 0x3FF == 0 {
320 self.gc_safepoint_poll();
321
322 if self.gc_heap.as_ref().map_or(false, |h| h.is_marking()) {
325 self.gc_incremental_mark_step();
326 }
327 }
328
329 let instruction = self.program.instructions[ip];
330
331 if let Some(ref mut metrics) = self.metrics {
333 metrics.record_instruction();
334 }
335
336 if let Some(ref mut tt) = self.time_travel {
338 let is_call_or_return = matches!(
339 instruction.opcode,
340 OpCode::Call
341 | OpCode::CallValue
342 | OpCode::CallClosure
343 | OpCode::CallFunctionIndirect
344 | OpCode::Return
345 | OpCode::ReturnValue
346 | OpCode::ReturnValueI64
347 | OpCode::ReturnValueU64
348 | OpCode::ReturnValueF64
349 | OpCode::ReturnValueI32
350 | OpCode::ReturnValueU32
351 | OpCode::ReturnValueI16
352 | OpCode::ReturnValueU16
353 | OpCode::ReturnValueI8
354 | OpCode::ReturnValueU8
355 | OpCode::ReturnValueBool
356 | OpCode::ReturnValuePtr
357 );
358 if tt.should_capture(ip, self.instruction_count as u64, is_call_or_return) {
359 if let Ok(store) = tt.snapshot_store() {
360 let store_ptr = store as *const shape_runtime::snapshot::SnapshotStore;
361 if let Ok(snap) = self.snapshot(unsafe { &*store_ptr }) {
362 let call_depth = self.call_stack.len();
363 self.time_travel.as_mut().unwrap().record(
364 snap,
365 ip,
366 self.instruction_count as u64,
367 call_depth,
368 );
369 }
370 }
371 }
372 }
373
374 if let Err(err) = self.execute_instruction(&instruction, ctx.as_deref_mut()) {
375 if let VMError::Suspended {
377 future_id,
378 resume_ip,
379 } = err
380 {
381 return Ok(ExecutionResult::Suspended {
382 future_id,
383 resume_ip,
384 });
385 }
386
387 if matches!(err, VMError::ResumeRequested) {
389 self.apply_pending_resume()?;
390 continue;
391 }
392
393 if !self.exception_handlers.is_empty() {
394 let raw_payload = KindedSlot::from_string_arc(Arc::new(err.to_string()));
404 let payload = self.normalize_err_payload(raw_payload)?;
405 self.handle_exception(payload)?;
406 } else {
407 return Err(self.enrich_error_with_location(err, ip));
408 }
409 }
410
411 if self.pending_frame_resume.is_some() {
413 self.apply_pending_frame_resume()?;
414 }
415
416 if matches!(instruction.opcode, OpCode::Halt) {
417 break;
418 }
419 }
420
421 let tl = self.program.top_level_locals_count as usize;
422 Ok(ExecutionResult::Completed(if self.sp > tl {
423 self.sp -= 1;
424 let (bits, kind) = self.stack_take_kinded(self.sp);
425 KindedSlot::new(ValueSlot::from_raw(bits), kind)
426 } else {
427 KindedSlot::new(ValueSlot::none(), NativeKind::Bool)
428 }))
429 }
430
431 #[inline]
435 pub(crate) fn execute_fast(
436 &mut self,
437 mut ctx: Option<&mut shape_runtime::context::ExecutionContext>,
438 ) -> Result<KindedSlot, VMError> {
439 while self.ip < self.program.instructions.len() {
440 let ip = self.ip;
442 self.ip += 1;
443 self.instruction_count += 1;
444
445 if self.instruction_count & 0x3FF == 0 && self.interrupt.load(Ordering::Relaxed) > 0 {
447 return Err(VMError::Interrupted);
448 }
449
450 #[cfg(feature = "gc")]
452 if self.instruction_count & 0x3FF == 0 {
453 self.gc_safepoint_poll();
454
455 if self.gc_heap.as_ref().map_or(false, |h| h.is_marking()) {
458 self.gc_incremental_mark_step();
459 }
460 }
461
462 let instruction = self.program.instructions[ip];
463
464 if let Some(ref mut metrics) = self.metrics {
466 metrics.record_instruction();
467 }
468
469 self.execute_instruction(&instruction, ctx.as_deref_mut())?;
470
471 if matches!(instruction.opcode, OpCode::Halt) {
472 break;
473 }
474 }
475
476 let tl = self.program.top_level_locals_count as usize;
477 Ok(if self.sp > tl {
478 self.sp -= 1;
479 let (bits, kind) = self.stack_take_kinded(self.sp);
480 KindedSlot::new(ValueSlot::from_raw(bits), kind)
481 } else {
482 KindedSlot::new(ValueSlot::none(), NativeKind::Bool)
483 })
484 }
485
486 pub(crate) fn execute_until_call_depth(
487 &mut self,
488 target_depth: usize,
489 mut ctx: Option<&mut shape_runtime::context::ExecutionContext>,
490 ) -> Result<(), VMError> {
491 loop {
492 if self.ip >= self.program.instructions.len() {
493 break;
494 }
495
496 let instruction = self.program.instructions[self.ip];
497 self.ip += 1;
498 self.instruction_count += 1;
499
500 match self.execute_instruction(&instruction, ctx.as_deref_mut()) {
501 Ok(()) => {}
502 Err(VMError::ResumeRequested) => {
503 self.apply_pending_resume()?;
504 continue;
505 }
506 Err(err) => return Err(err),
507 }
508
509 if self.pending_frame_resume.is_some() {
510 self.apply_pending_frame_resume()?;
511 }
512
513 if matches!(instruction.opcode, OpCode::Halt) || self.call_stack.len() == target_depth {
514 break;
515 }
516 }
517 Ok(())
518 }
519
520 pub(crate) fn execute_instruction(
522 &mut self,
523 instruction: &Instruction,
524 ctx: Option<&mut shape_runtime::context::ExecutionContext>,
525 ) -> Result<(), VMError> {
526 use OpCode::*;
527
528 match instruction.opcode {
529 PushConst | PushNull | Pop | Dup | Swap | PromoteToOwned | ReturnOwned
531 | PromoteToShared => {
532 return self.exec_stack_ops(instruction);
533 }
534
535 BitAnd | BitOr | BitXor | BitShl | BitShr | BitNot => {
541 return self.exec_dyn_bit_dispatch(instruction);
542 }
543
544 AddInt | AddNumber | AddDecimal | SubInt | SubNumber | SubDecimal | MulInt
551 | MulNumber | MulDecimal | DivInt | DivNumber | DivDecimal | ModInt | ModNumber
552 | ModDecimal | PowInt | PowNumber | PowDecimal | IntToNumber | NumberToInt
553 | NegInt | NegNumber | NegDecimal | BitAndInt | BitOrInt | BitXorInt
554 | BitShlInt | BitShrInt | BitNotInt => {
555 return self.exec_typed_arithmetic(instruction);
556 }
557
558 AddTyped | SubTyped | MulTyped | DivTyped | ModTyped | CmpTyped => {
563 return self.exec_compact_typed_arithmetic(instruction);
564 }
565
566 CastWidth => {
568 return self.op_cast_width(instruction);
569 }
570
571 GtInt | GtNumber | GtDecimal | LtInt | LtNumber | LtDecimal | GteInt | GteNumber
573 | GteDecimal | LteInt | LteNumber | LteDecimal | EqInt | EqNumber | NeqInt
574 | NeqNumber | EqString | EqDecimal | IsNull | GtString | LtString | GteString
575 | LteString => {
576 return self.exec_typed_comparison(instruction);
577 }
578
579 And | Or | Not => {
581 return self.exec_logical(instruction);
582 }
583
584 Jump | JumpIfFalse | JumpIfTrue | JumpIfFalseTrusted | Call | CallValue
586 | CallClosure | CallFunctionIndirect | CallForeign | Return | ReturnValue
587 | ReturnValueI64 | ReturnValueU64 | ReturnValueF64 | ReturnValueI32
588 | ReturnValueU32 | ReturnValueI16 | ReturnValueU16 | ReturnValueI8
589 | ReturnValueU8 | ReturnValueBool | ReturnValuePtr => {
590 return self.exec_control_flow(instruction, ctx);
591 }
592
593 LoadLocal
595 | LoadLocalTrusted
596 | LoadLocalMove
597 | LoadLocalClone
598 | StoreLocal
599 | StoreLocalTyped
600 | StoreLocalDrop
601 | LoadLocalI64
602 | LoadLocalU64
603 | LoadLocalF64
604 | LoadLocalI32
605 | LoadLocalU32
606 | LoadLocalI16
607 | LoadLocalU16
608 | LoadLocalI8
609 | LoadLocalU8
610 | LoadLocalBool
611 | LoadLocalPtr
612 | StoreLocalI64
613 | StoreLocalU64
614 | StoreLocalF64
615 | StoreLocalI32
616 | StoreLocalU32
617 | StoreLocalI16
618 | StoreLocalU16
619 | StoreLocalI8
620 | StoreLocalU8
621 | StoreLocalBool
622 | StoreLocalPtr
623 | LoadModuleBinding
624 | StoreModuleBinding
625 | StoreModuleBindingTyped
626 | LoadModuleBindingI64
627 | LoadModuleBindingU64
628 | LoadModuleBindingF64
629 | LoadModuleBindingI32
630 | LoadModuleBindingU32
631 | LoadModuleBindingI16
632 | LoadModuleBindingU16
633 | LoadModuleBindingI8
634 | LoadModuleBindingU8
635 | LoadModuleBindingBool
636 | LoadModuleBindingPtr
637 | StoreModuleBindingI64
638 | StoreModuleBindingU64
639 | StoreModuleBindingF64
640 | StoreModuleBindingI32
641 | StoreModuleBindingU32
642 | StoreModuleBindingI16
643 | StoreModuleBindingU16
644 | StoreModuleBindingI8
645 | StoreModuleBindingU8
646 | StoreModuleBindingBool
647 | StoreModuleBindingPtr
648 | LoadClosure
649 | StoreClosure
650 | CloseUpvalue
651 | MakeRef
652 | MakeFieldRef
653 | MakeIndexRef
654 | DerefLoad
655 | DerefStore
656 | SetIndexRef
657 | LoadOwnedMutableCapture
658 | StoreOwnedMutableCapture
659 | LoadOwnedMutableCaptureI64
660 | LoadOwnedMutableCaptureU64
661 | LoadOwnedMutableCaptureF64
662 | LoadOwnedMutableCaptureI32
663 | LoadOwnedMutableCaptureU32
664 | LoadOwnedMutableCaptureI16
665 | LoadOwnedMutableCaptureU16
666 | LoadOwnedMutableCaptureI8
667 | LoadOwnedMutableCaptureU8
668 | LoadOwnedMutableCaptureBool
669 | LoadOwnedMutableCapturePtr
670 | StoreOwnedMutableCaptureI64
671 | StoreOwnedMutableCaptureU64
672 | StoreOwnedMutableCaptureF64
673 | StoreOwnedMutableCaptureI32
674 | StoreOwnedMutableCaptureU32
675 | StoreOwnedMutableCaptureI16
676 | StoreOwnedMutableCaptureU16
677 | StoreOwnedMutableCaptureI8
678 | StoreOwnedMutableCaptureU8
679 | StoreOwnedMutableCaptureBool
680 | StoreOwnedMutableCapturePtr
681 | LoadSharedCapture
682 | StoreSharedCapture
683 | LoadSharedCaptureI64
684 | LoadSharedCaptureU64
685 | LoadSharedCaptureF64
686 | LoadSharedCaptureI32
687 | LoadSharedCaptureU32
688 | LoadSharedCaptureI16
689 | LoadSharedCaptureU16
690 | LoadSharedCaptureI8
691 | LoadSharedCaptureU8
692 | LoadSharedCaptureBool
693 | LoadSharedCapturePtr
694 | StoreSharedCaptureI64
695 | StoreSharedCaptureU64
696 | StoreSharedCaptureF64
697 | StoreSharedCaptureI32
698 | StoreSharedCaptureU32
699 | StoreSharedCaptureI16
700 | StoreSharedCaptureU16
701 | StoreSharedCaptureI8
702 | StoreSharedCaptureU8
703 | StoreSharedCaptureBool
704 | StoreSharedCapturePtr
705 | AllocSharedLocal
706 | LoadSharedLocal
707 | StoreSharedLocal
708 | DropSharedLocal
709 | AllocSharedModuleBinding
710 | LoadSharedModuleBinding
711 | StoreSharedModuleBinding => {
712 return self.exec_variables(instruction);
713 }
714
715 NewArray
717 | NewMatrix
718 | NewObject
719 | GetProp
720 | SetProp
721 | SetLocalIndex
722 | SetModuleBindingIndex
723 | Length
724 | ArrayPush
725 | ArrayPushLocal
726 | ArrayPop
727 | MakeClosure
728 | MergeObject
729 | NewTypedObject
730 | NewTypedArray
731 | TypedMergeObject
732 | WrapTypeAnnotation => {
733 return self.exec_objects(instruction, ctx);
734 }
735
736 BuiltinCall | TypeCheck | Convert => {
738 return self.exec_builtins(instruction, ctx);
739 }
740
741 ConvertToInt => return self.op_convert_to_int(),
743 ConvertToNumber => return self.op_convert_to_number(),
744 ConvertToString => return self.op_convert_to_string(),
745 ConvertToBool => return self.op_convert_to_bool(),
746 ConvertToDecimal => return self.op_convert_to_decimal(),
747 ConvertToChar => return self.op_convert_to_char(),
748 TryConvertToInt => return self.op_try_convert_to_int(),
749 TryConvertToNumber => return self.op_try_convert_to_number(),
750 TryConvertToString => return self.op_try_convert_to_string(),
751 TryConvertToBool => return self.op_try_convert_to_bool(),
752 TryConvertToDecimal => return self.op_try_convert_to_decimal(),
753 TryConvertToChar => return self.op_try_convert_to_char(),
754
755 SetupTry | PopHandler | Throw | TryUnwrap | UnwrapOption | ErrorContext | IsOk
757 | IsErr | UnwrapOk | UnwrapErr => {
758 return self.exec_exceptions(instruction);
759 }
760
761 SliceAccess | NullCoalesce | MakeRange => {
763 return self.exec_additional(instruction);
764 }
765
766 LoopStart | LoopEnd | Break | Continue | IterNext | IterDone => {
768 return self.exec_loops(instruction);
769 }
770
771 CallMethod => {
773 return self.op_call_method(instruction, ctx);
774 }
775
776 StringConcat => {
780 return self.op_string_concat();
781 }
782 ArrayConcat => {
783 return self.op_array_concat();
784 }
785
786 PushTimeframe => {
787 return Err(VMError::NotImplemented(
788 "Opcode 'PushTimeframe' is reserved but not yet implemented".into(),
789 ));
790 }
791 PopTimeframe => {
792 return Err(VMError::NotImplemented(
793 "Opcode 'PopTimeframe' is reserved but not yet implemented".into(),
794 ));
795 }
796
797 LoadColF64 | LoadColI64 | LoadColBool | LoadColStr => {
799 return self.exec_load_col(instruction);
800 }
801
802 BindSchema => {
804 return self.exec_bind_schema(instruction);
805 }
806
807 GetFieldTyped | SetFieldTyped => {
809 return self.exec_jit_ops(instruction);
810 }
811
812 FieldLoadF64 | FieldLoadI64 | FieldLoadI32 | FieldLoadBool | FieldLoadPtr
814 | FieldStoreF64 | FieldStoreI64 | FieldStoreI32 | NewTypedStruct => {
815 return self.exec_v2_typed_field(instruction);
816 }
817
818 AddI32 | SubI32 | MulI32 | DivI32 | ModI32 | EqI32 | NeqI32 | LtI32 | GtI32
820 | LteI32 | GteI32 => {
821 return self.exec_v2_sized_int(instruction);
822 }
823
824 Yield | Suspend | Resume | Poll | AwaitBar | AwaitTick | EmitAlert | EmitEvent
826 | Await | SpawnTask | JoinInit | JoinAwait | CancelTask | AsyncScopeEnter
827 | AsyncScopeExit => {
828 match self.exec_async_op(instruction) {
829 Ok(async_ops::AsyncExecutionResult::Continue) => return Ok(()),
830 Ok(async_ops::AsyncExecutionResult::Yielded) => {
831 return Ok(());
832 }
833 Ok(async_ops::AsyncExecutionResult::Suspended(info)) => {
834 match info.wait_type {
836 async_ops::WaitType::Future { id } => {
837 return Err(VMError::Suspended {
838 future_id: id,
839 resume_ip: info.resume_ip,
840 });
841 }
842 async_ops::WaitType::TaskGroup { kind, task_ids } => {
843 let marker_id = task_ids.first().copied().unwrap_or(0);
846 let _ = (kind, task_ids); return Err(VMError::Suspended {
848 future_id: marker_id,
849 resume_ip: info.resume_ip,
850 });
851 }
852 _ => {
853 while let Some(mut scope_tasks) = self.async_scope_stack.pop() {
857 scope_tasks.reverse();
858 for task_id in scope_tasks {
859 self.task_scheduler.cancel(task_id);
860 }
861 }
862 return Ok(());
863 }
864 }
865 }
866 Err(e) => return Err(e),
867 }
868 }
869
870 BoxTraitObject | DynMethodCall | DropCall | DropCallAsync => {
872 return self.exec_trait_object_ops(instruction, ctx);
873 }
874
875 NewTypedArrayF64
877 | NewTypedArrayI64
878 | NewTypedArrayI32
879 | NewTypedArrayBool
880 | TypedArrayGetF64
881 | TypedArrayGetI64
882 | TypedArrayGetI32
883 | TypedArrayGetBool
884 | TypedArraySetF64
885 | TypedArraySetI64
886 | TypedArraySetI32
887 | TypedArraySetBool
888 | TypedArrayPushF64
889 | TypedArrayPushI64
890 | TypedArrayPushI32
891 | TypedArrayPushBool
892 | TypedArrayLen
893 | NewTypedArrayI8
895 | TypedArrayGetI8
896 | TypedArrayPushI8
897 | TypedArraySetI8
898 | NewTypedArrayU8
899 | TypedArrayGetU8
900 | TypedArrayPushU8
901 | TypedArraySetU8
902 | NewTypedArrayI16
903 | TypedArrayGetI16
904 | TypedArrayPushI16
905 | TypedArraySetI16
906 | NewTypedArrayU16
907 | TypedArrayGetU16
908 | TypedArrayPushU16
909 | TypedArraySetU16
910 | NewTypedArrayU32
911 | TypedArrayGetU32
912 | TypedArrayPushU32
913 | TypedArraySetU32
914 | NewTypedArrayF32
919 | TypedArrayGetF32
920 | TypedArrayPushF32
921 | TypedArraySetF32
922 | NewTypedArrayChar
923 | TypedArrayGetChar
924 | TypedArrayPushChar
925 | TypedArraySetChar
926 | NewTypedArrayString
928 | TypedArrayGetString
929 | TypedArrayPushString
930 | TypedArraySetString
931 | NewTypedArrayDecimal
932 | TypedArrayGetDecimal
933 | TypedArrayPushDecimal
934 | TypedArraySetDecimal
935 | NewTypedArrayTypedObject
940 | TypedArrayGetTypedObject
941 | TypedArrayPushTypedObject
942 | TypedArraySetTypedObject
943 | NewStringV2
950 | NewDecimalV2 => {
951 return self.exec_v2_typed_array(instruction);
952 }
953
954 GetElemI64 | GetElemF64 | SetElemI64 | SetElemF64
956 | ArrayPushI64 | ArrayPushF64 | ArrayLenTyped => {
957 return self.exec_typed_array_elem_ops(instruction);
958 }
959
960 MapGetStrI64 | MapGetStrF64 | MapSetStrI64 | MapHasStr | MapLenTyped => {
962 return self.exec_typed_map_access(instruction);
963 }
964
965 StringLenTyped | StringCharAt | StringConcatTyped
972 | StringConcatInt | StringConcatNumber | StringConcatBool => {
973 return self.exec_typed_string_access(instruction);
974 }
975
976 NewTypedMapStringF64
978 | NewTypedMapStringI64
979 | NewTypedMapStringPtr
980 | NewTypedMapI64F64
981 | NewTypedMapI64I64
982 | NewTypedMapI64Ptr
983 | TypedMapStringF64Get
984 | TypedMapStringI64Get
985 | TypedMapStringPtrGet
986 | TypedMapI64F64Get
987 | TypedMapI64I64Get
988 | TypedMapI64PtrGet
989 | TypedMapStringF64Set
990 | TypedMapStringI64Set
991 | TypedMapStringPtrSet
992 | TypedMapI64F64Set
993 | TypedMapI64I64Set
994 | TypedMapI64PtrSet
995 | TypedMapStringF64Has
996 | TypedMapStringI64Has
997 | TypedMapStringPtrHas
998 | TypedMapI64F64Has
999 | TypedMapI64I64Has
1000 | TypedMapI64PtrHas
1001 | TypedMapStringF64Delete
1002 | TypedMapStringI64Delete
1003 | TypedMapStringPtrDelete
1004 | TypedMapI64F64Delete
1005 | TypedMapI64I64Delete
1006 | TypedMapI64PtrDelete => {
1007 return self.exec_v2_typed_map(instruction);
1008 }
1009
1010 Nop => {}
1012 Halt => {}
1013 MoveLocal => self.op_move_local(instruction)?,
1025 CloneLocal => self.op_clone_local(instruction)?,
1026 DropLocal => self.op_drop_local(instruction)?,
1027
1028 _ => return Err(VMError::InvalidOperand),
1039 }
1040
1041 Ok(())
1042 }
1043
1044 pub(crate) fn enrich_error_with_location(&mut self, error: VMError, ip: usize) -> VMError {
1049 let debug_info = &self.program.debug_info;
1050
1051 let location = debug_info.get_location_for_instruction(ip);
1053
1054 if let Some((file_id, line_num)) = location {
1055 self.last_error_line = Some(line_num);
1057 self.last_error_file = debug_info
1058 .source_map
1059 .get_file(file_id)
1060 .map(|s| s.to_string());
1061
1062 let source_context = debug_info
1064 .get_source_line_from_file(file_id, line_num as usize)
1065 .map(|s| s.trim())
1066 .filter(|s| !s.is_empty());
1067
1068 let base_msg = match &error {
1069 VMError::RuntimeError(msg) => msg.clone(),
1070 VMError::TypeError { expected, got } => {
1071 format!("TypeError: expected {}, got {}", expected, got)
1072 }
1073 VMError::StackUnderflow => "Stack underflow".to_string(),
1074 VMError::StackOverflow => "Stack overflow".to_string(),
1075 VMError::DivisionByZero => "Division by zero".to_string(),
1076 VMError::UndefinedVariable(name) => format!("Undefined variable: {}", name),
1077 VMError::UndefinedProperty(name) => format!("Undefined property: {}", name),
1078 VMError::InvalidCall => "Invalid function call".to_string(),
1079 VMError::IndexOutOfBounds { index, length } => {
1080 format!("Index {} out of bounds (length {})", index, length)
1081 }
1082 VMError::InvalidOperand => "Invalid operand".to_string(),
1083 VMError::ArityMismatch {
1084 function,
1085 expected,
1086 got,
1087 } => {
1088 format!(
1089 "{}() expects {} argument(s), got {}",
1090 function, expected, got
1091 )
1092 }
1093 VMError::InvalidArgument { function, message } => {
1094 format!("{}(): {}", function, message)
1095 }
1096 VMError::NotImplemented(feature) => format!("Not implemented: {}", feature),
1097 VMError::Suspended { .. } | VMError::Interrupted | VMError::ResumeRequested => {
1098 return error;
1099 } };
1101
1102 let enhanced = if let Some(source) = source_context {
1104 format!(
1105 "{}\n --> line {}\n |\n{:>3} | {}\n |",
1106 base_msg, line_num, line_num, source
1107 )
1108 } else {
1109 format!("{} (line {})", base_msg, line_num)
1110 };
1111
1112 VMError::RuntimeError(enhanced)
1113 } else {
1114 self.last_error_line = None;
1115 self.last_error_file = None;
1116 error
1117 }
1118 }
1119
1120 }