(&mut self, opcode: OpCode, operand: u16, chunk: &SSAChunk, slots: &mut [Val], ip: &mut usize, exc_base: usize)
| 560 | } |
| 561 | |
| 562 | fn dispatch_generic(&mut self, opcode: OpCode, operand: u16, chunk: &SSAChunk, slots: &mut [Val], ip: &mut usize, exc_base: usize) -> Result<Option<Val>, VmErr> { |
| 563 | match opcode { |
| 564 | OpCode::BitAnd | OpCode::BitOr | OpCode::BitXor |
| 565 | | OpCode::BitNot | OpCode::Shl | OpCode::Shr |
| 566 | | OpCode::InPlaceBitOr | OpCode::InPlaceBitAnd | OpCode::InPlaceBitXor => self.handle_bitwise(opcode, chunk, slots)?, |
| 567 | OpCode::In | OpCode::NotIn | OpCode::Is | OpCode::IsNot => self.handle_identity(opcode, chunk, slots)?, |
| 568 | |
| 569 | OpCode::BuildList | OpCode::BuildTuple | OpCode::BuildDict |
| 570 | | OpCode::BuildString | OpCode::BuildSet | OpCode::BuildSlice => self.handle_build(opcode, operand)?, |
| 571 | |
| 572 | OpCode::StoreItem => { self.mark_impure(); self.store_item(chunk, slots)?; } |
| 573 | OpCode::DelItem => { self.mark_impure(); self.del_item(chunk, slots)?; } |
| 574 | OpCode::DelAttr => { self.mark_impure(); self.exec_del_attr(operand, chunk)?; } |
| 575 | OpCode::UnpackSequence | OpCode::UnpackEx | OpCode::FormatValue => self.handle_container(opcode, operand, chunk, slots)?, |
| 576 | |
| 577 | OpCode::ListAppend | OpCode::SetAdd | OpCode::MapAdd => self.handle_comprehension(opcode)?, |
| 578 | OpCode::DictUpdate | OpCode::SetUpdate | OpCode::ListExtend => self.handle_spread_merge(opcode)?, |
| 579 | |
| 580 | OpCode::Yield => self.handle_yield()?, |
| 581 | OpCode::LoadYieldFrom => self.push(self.yield_from_value), |
| 582 | OpCode::LoadEllipsis => { |
| 583 | let v = self.heap.alloc(HeapObj::Ellipsis)?; |
| 584 | self.push(v); |
| 585 | } |
| 586 | OpCode::Dup => { |
| 587 | let v = *self.stack.last().ok_or(cold_runtime("stack underflow"))?; |
| 588 | self.push(v); |
| 589 | } |
| 590 | OpCode::MatchSeq => { |
| 591 | // Sequence patterns match only list/tuple, not str/bytes. |
| 592 | let v = self.pop()?; |
| 593 | let is_seq = v.is_heap() && matches!(self.heap.get(v), HeapObj::List(_) | HeapObj::Tuple(_)); |
| 594 | self.push(Val::bool(is_seq)); |
| 595 | } |
| 596 | OpCode::Dup2 => { |
| 597 | let b = self.pop()?; let a = self.pop()?; |
| 598 | self.push(a); self.push(b); self.push(a); self.push(b); |
| 599 | } |
| 600 | OpCode::Assert | OpCode::Del | OpCode::Global | OpCode::Nonlocal |
| 601 | | OpCode::Raise | OpCode::RaiseFrom | OpCode::Await => { |
| 602 | self.handle_side(opcode, operand, chunk, slots)?; |
| 603 | } |
| 604 | OpCode::SetupExcept => { |
| 605 | self.exception_stack.push(ExceptionFrame { |
| 606 | kind: BlockKind::Except, |
| 607 | handler_ip: operand as usize, |
| 608 | stack_depth: self.stack.len(), |
| 609 | iter_depth: self.iter_stack.len(), |
| 610 | with_depth: self.with_stack.len(), |
| 611 | unwind_depth: self.unwind_stack.len(), |
| 612 | }); |
| 613 | } |
| 614 | // Cleanup frame run on every exit path; handler is the finally body or WithExit. |
| 615 | OpCode::SetupFinally => { |
| 616 | self.exception_stack.push(ExceptionFrame { |
| 617 | kind: BlockKind::Finally, |
| 618 | handler_ip: operand as usize, |
| 619 | stack_depth: self.stack.len(), |
no test coverage detected