rustpython_vm/
frame.rs

1use crate::common::{boxvec::BoxVec, lock::PyMutex};
2use crate::{
3    builtins::{
4        asyncgenerator::PyAsyncGenWrappedValue,
5        function::{PyCell, PyCellRef, PyFunction},
6        tuple::{PyTuple, PyTupleRef, PyTupleTyped},
7        PyBaseExceptionRef, PyCode, PyCoroutine, PyDict, PyDictRef, PyGenerator, PyList, PySet,
8        PySlice, PyStr, PyStrInterned, PyStrRef, PyTraceback, PyType,
9    },
10    bytecode,
11    convert::{IntoObject, ToPyResult},
12    coroutine::Coro,
13    exceptions::ExceptionCtor,
14    function::{ArgMapping, Either, FuncArgs},
15    protocol::{PyIter, PyIterReturn},
16    scope::Scope,
17    source_code::SourceLocation,
18    stdlib::{builtins, typing::_typing},
19    vm::{Context, PyMethod},
20    AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
21};
22use indexmap::IndexMap;
23use itertools::Itertools;
24#[cfg(feature = "threading")]
25use std::sync::atomic;
26use std::{fmt, iter::zip};
27
28#[derive(Clone, Debug)]
29struct Block {
30    /// The type of block.
31    typ: BlockType,
32    /// The level of the value stack when the block was entered.
33    level: usize,
34}
35
36#[derive(Clone, Debug)]
37enum BlockType {
38    Loop,
39    TryExcept {
40        handler: bytecode::Label,
41    },
42    Finally {
43        handler: bytecode::Label,
44    },
45
46    /// Active finally sequence
47    FinallyHandler {
48        reason: Option<UnwindReason>,
49        prev_exc: Option<PyBaseExceptionRef>,
50    },
51    ExceptHandler {
52        prev_exc: Option<PyBaseExceptionRef>,
53    },
54}
55
56pub type FrameRef = PyRef<Frame>;
57
58/// The reason why we might be unwinding a block.
59/// This could be return of function, exception being
60/// raised, a break or continue being hit, etc..
61#[derive(Clone, Debug)]
62enum UnwindReason {
63    /// We are returning a value from a return statement.
64    Returning { value: PyObjectRef },
65
66    /// We hit an exception, so unwind any try-except and finally blocks. The exception should be
67    /// on top of the vm exception stack.
68    Raising { exception: PyBaseExceptionRef },
69
70    // NoWorries,
71    /// We are unwinding blocks, since we hit break
72    Break { target: bytecode::Label },
73
74    /// We are unwinding blocks since we hit a continue statements.
75    Continue { target: bytecode::Label },
76}
77
78#[derive(Debug)]
79struct FrameState {
80    // We need 1 stack per frame
81    /// The main data frame of the stack machine
82    stack: BoxVec<PyObjectRef>,
83    /// Block frames, for controlling loops and exceptions
84    blocks: Vec<Block>,
85    /// index of last instruction ran
86    #[cfg(feature = "threading")]
87    lasti: u32,
88}
89
90#[cfg(feature = "threading")]
91type Lasti = atomic::AtomicU32;
92#[cfg(not(feature = "threading"))]
93type Lasti = std::cell::Cell<u32>;
94
95#[pyclass(module = false, name = "frame")]
96pub struct Frame {
97    pub code: PyRef<PyCode>,
98
99    pub fastlocals: PyMutex<Box<[Option<PyObjectRef>]>>,
100    pub(crate) cells_frees: Box<[PyCellRef]>,
101    pub locals: ArgMapping,
102    pub globals: PyDictRef,
103    pub builtins: PyDictRef,
104
105    // on feature=threading, this is a duplicate of FrameState.lasti, but it's faster to do an
106    // atomic store than it is to do a fetch_add, for every instruction executed
107    /// index of last instruction ran
108    pub lasti: Lasti,
109    /// tracer function for this frame (usually is None)
110    pub trace: PyMutex<PyObjectRef>,
111    state: PyMutex<FrameState>,
112
113    // member
114    pub trace_lines: PyMutex<bool>,
115    pub temporary_refs: PyMutex<Vec<PyObjectRef>>,
116}
117
118impl PyPayload for Frame {
119    fn class(ctx: &Context) -> &'static Py<PyType> {
120        ctx.types.frame_type
121    }
122}
123
124// Running a frame can result in one of the below:
125pub enum ExecutionResult {
126    Return(PyObjectRef),
127    Yield(PyObjectRef),
128}
129
130/// A valid execution result, or an exception
131type FrameResult = PyResult<Option<ExecutionResult>>;
132
133impl Frame {
134    pub(crate) fn new(
135        code: PyRef<PyCode>,
136        scope: Scope,
137        builtins: PyDictRef,
138        closure: &[PyCellRef],
139        vm: &VirtualMachine,
140    ) -> Frame {
141        let cells_frees = std::iter::repeat_with(|| PyCell::default().into_ref(&vm.ctx))
142            .take(code.cellvars.len())
143            .chain(closure.iter().cloned())
144            .collect();
145
146        let state = FrameState {
147            stack: BoxVec::new(code.max_stackdepth as usize),
148            blocks: Vec::new(),
149            #[cfg(feature = "threading")]
150            lasti: 0,
151        };
152
153        Frame {
154            fastlocals: PyMutex::new(vec![None; code.varnames.len()].into_boxed_slice()),
155            cells_frees,
156            locals: scope.locals,
157            globals: scope.globals,
158            builtins,
159            code,
160            lasti: Lasti::new(0),
161            state: PyMutex::new(state),
162            trace: PyMutex::new(vm.ctx.none()),
163            trace_lines: PyMutex::new(true),
164            temporary_refs: PyMutex::new(vec![]),
165        }
166    }
167
168    pub fn current_location(&self) -> SourceLocation {
169        self.code.locations[self.lasti() as usize - 1]
170    }
171
172    pub fn lasti(&self) -> u32 {
173        #[cfg(feature = "threading")]
174        {
175            self.lasti.load(atomic::Ordering::Relaxed)
176        }
177        #[cfg(not(feature = "threading"))]
178        {
179            self.lasti.get()
180        }
181    }
182
183    pub fn locals(&self, vm: &VirtualMachine) -> PyResult<ArgMapping> {
184        let locals = &self.locals;
185        let code = &**self.code;
186        let map = &code.varnames;
187        let j = std::cmp::min(map.len(), code.varnames.len());
188        if !code.varnames.is_empty() {
189            let fastlocals = self.fastlocals.lock();
190            for (&k, v) in zip(&map[..j], &**fastlocals) {
191                match locals.mapping().ass_subscript(k, v.clone(), vm) {
192                    Ok(()) => {}
193                    Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {}
194                    Err(e) => return Err(e),
195                }
196            }
197        }
198        if !code.cellvars.is_empty() || !code.freevars.is_empty() {
199            let map_to_dict = |keys: &[&PyStrInterned], values: &[PyCellRef]| {
200                for (&k, v) in zip(keys, values) {
201                    if let Some(value) = v.get() {
202                        locals.mapping().ass_subscript(k, Some(value), vm)?;
203                    } else {
204                        match locals.mapping().ass_subscript(k, None, vm) {
205                            Ok(()) => {}
206                            Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {}
207                            Err(e) => return Err(e),
208                        }
209                    }
210                }
211                Ok(())
212            };
213            map_to_dict(&code.cellvars, &self.cells_frees)?;
214            if code.flags.contains(bytecode::CodeFlags::IS_OPTIMIZED) {
215                map_to_dict(&code.freevars, &self.cells_frees[code.cellvars.len()..])?;
216            }
217        }
218        Ok(locals.clone())
219    }
220}
221
222impl Py<Frame> {
223    #[inline(always)]
224    fn with_exec<R>(&self, f: impl FnOnce(ExecutingFrame) -> R) -> R {
225        let mut state = self.state.lock();
226        let exec = ExecutingFrame {
227            code: &self.code,
228            fastlocals: &self.fastlocals,
229            cells_frees: &self.cells_frees,
230            locals: &self.locals,
231            globals: &self.globals,
232            builtins: &self.builtins,
233            lasti: &self.lasti,
234            object: self,
235            state: &mut state,
236        };
237        f(exec)
238    }
239
240    // #[cfg_attr(feature = "flame-it", flame("Frame"))]
241    pub fn run(&self, vm: &VirtualMachine) -> PyResult<ExecutionResult> {
242        self.with_exec(|mut exec| exec.run(vm))
243    }
244
245    pub(crate) fn resume(
246        &self,
247        value: Option<PyObjectRef>,
248        vm: &VirtualMachine,
249    ) -> PyResult<ExecutionResult> {
250        self.with_exec(|mut exec| {
251            if let Some(value) = value {
252                exec.push_value(value)
253            }
254            exec.run(vm)
255        })
256    }
257
258    pub(crate) fn gen_throw(
259        &self,
260        vm: &VirtualMachine,
261        exc_type: PyObjectRef,
262        exc_val: PyObjectRef,
263        exc_tb: PyObjectRef,
264    ) -> PyResult<ExecutionResult> {
265        self.with_exec(|mut exec| exec.gen_throw(vm, exc_type, exc_val, exc_tb))
266    }
267
268    pub fn yield_from_target(&self) -> Option<PyObjectRef> {
269        self.with_exec(|exec| exec.yield_from_target().map(PyObject::to_owned))
270    }
271
272    pub fn is_internal_frame(&self) -> bool {
273        let code = self.f_code();
274        let filename = code.co_filename();
275
276        filename.as_str().contains("importlib") && filename.as_str().contains("_bootstrap")
277    }
278
279    pub fn next_external_frame(&self, vm: &VirtualMachine) -> Option<FrameRef> {
280        self.f_back(vm).map(|mut back| loop {
281            back = if let Some(back) = back.to_owned().f_back(vm) {
282                back
283            } else {
284                break back;
285            };
286
287            if !back.is_internal_frame() {
288                break back;
289            }
290        })
291    }
292}
293
294/// An executing frame; essentially just a struct to combine the immutable data outside the mutex
295/// with the mutable data inside
296struct ExecutingFrame<'a> {
297    code: &'a PyRef<PyCode>,
298    fastlocals: &'a PyMutex<Box<[Option<PyObjectRef>]>>,
299    cells_frees: &'a [PyCellRef],
300    locals: &'a ArgMapping,
301    globals: &'a PyDictRef,
302    builtins: &'a PyDictRef,
303    object: &'a Py<Frame>,
304    lasti: &'a Lasti,
305    state: &'a mut FrameState,
306}
307
308impl fmt::Debug for ExecutingFrame<'_> {
309    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
310        f.debug_struct("ExecutingFrame")
311            .field("code", self.code)
312            // .field("scope", self.scope)
313            .field("state", self.state)
314            .finish()
315    }
316}
317
318impl ExecutingFrame<'_> {
319    #[inline(always)]
320    fn update_lasti(&mut self, f: impl FnOnce(&mut u32)) {
321        #[cfg(feature = "threading")]
322        {
323            f(&mut self.state.lasti);
324            self.lasti
325                .store(self.state.lasti, atomic::Ordering::Relaxed);
326        }
327        #[cfg(not(feature = "threading"))]
328        {
329            let mut lasti = self.lasti.get();
330            f(&mut lasti);
331            self.lasti.set(lasti);
332        }
333    }
334
335    #[inline(always)]
336    fn lasti(&self) -> u32 {
337        #[cfg(feature = "threading")]
338        {
339            self.state.lasti
340        }
341        #[cfg(not(feature = "threading"))]
342        {
343            self.lasti.get()
344        }
345    }
346
347    fn run(&mut self, vm: &VirtualMachine) -> PyResult<ExecutionResult> {
348        flame_guard!(format!("Frame::run({})", self.code.obj_name));
349        // Execute until return or exception:
350        let instrs = &self.code.instructions;
351        let mut arg_state = bytecode::OpArgState::default();
352        loop {
353            let idx = self.lasti() as usize;
354            // eprintln!(
355            //     "location: {:?} {}",
356            //     self.code.locations[idx], self.code.source_path
357            // );
358            self.update_lasti(|i| *i += 1);
359            let bytecode::CodeUnit { op, arg } = instrs[idx];
360            let arg = arg_state.extend(arg);
361            let mut do_extend_arg = false;
362            let result = self.execute_instruction(op, arg, &mut do_extend_arg, vm);
363            match result {
364                Ok(None) => {}
365                Ok(Some(value)) => {
366                    break Ok(value);
367                }
368                // Instruction raised an exception
369                Err(exception) => {
370                    #[cold]
371                    fn handle_exception(
372                        frame: &mut ExecutingFrame,
373                        exception: PyBaseExceptionRef,
374                        idx: usize,
375                        vm: &VirtualMachine,
376                    ) -> FrameResult {
377                        // 1. Extract traceback from exception's '__traceback__' attr.
378                        // 2. Add new entry with current execution position (filename, lineno, code_object) to traceback.
379                        // 3. Unwind block stack till appropriate handler is found.
380
381                        let loc = frame.code.locations[idx];
382                        let next = exception.traceback();
383                        let new_traceback =
384                            PyTraceback::new(next, frame.object.to_owned(), frame.lasti(), loc.row);
385                        vm_trace!("Adding to traceback: {:?} {:?}", new_traceback, loc.row());
386                        exception.set_traceback(Some(new_traceback.into_ref(&vm.ctx)));
387
388                        vm.contextualize_exception(&exception);
389
390                        frame.unwind_blocks(vm, UnwindReason::Raising { exception })
391                    }
392
393                    match handle_exception(self, exception, idx, vm) {
394                        Ok(None) => {}
395                        Ok(Some(result)) => break Ok(result),
396                        // TODO: append line number to traceback?
397                        // traceback.append();
398                        Err(exception) => break Err(exception),
399                    }
400                }
401            }
402            if !do_extend_arg {
403                arg_state.reset()
404            }
405        }
406    }
407
408    fn yield_from_target(&self) -> Option<&PyObject> {
409        if let Some(bytecode::CodeUnit {
410            op: bytecode::Instruction::YieldFrom,
411            ..
412        }) = self.code.instructions.get(self.lasti() as usize)
413        {
414            Some(self.top_value())
415        } else {
416            None
417        }
418    }
419
420    /// Ok(Err(e)) means that an error occurred while calling throw() and the generator should try
421    /// sending it
422    fn gen_throw(
423        &mut self,
424        vm: &VirtualMachine,
425        exc_type: PyObjectRef,
426        exc_val: PyObjectRef,
427        exc_tb: PyObjectRef,
428    ) -> PyResult<ExecutionResult> {
429        if let Some(gen) = self.yield_from_target() {
430            // borrow checker shenanigans - we only need to use exc_type/val/tb if the following
431            // variable is Some
432            let thrower = if let Some(coro) = self.builtin_coro(gen) {
433                Some(Either::A(coro))
434            } else {
435                vm.get_attribute_opt(gen.to_owned(), "throw")?
436                    .map(Either::B)
437            };
438            if let Some(thrower) = thrower {
439                let ret = match thrower {
440                    Either::A(coro) => coro
441                        .throw(gen, exc_type, exc_val, exc_tb, vm)
442                        .to_pyresult(vm), // FIXME:
443                    Either::B(meth) => meth.call((exc_type, exc_val, exc_tb), vm),
444                };
445                return ret.map(ExecutionResult::Yield).or_else(|err| {
446                    self.pop_value();
447                    self.update_lasti(|i| *i += 1);
448                    if err.fast_isinstance(vm.ctx.exceptions.stop_iteration) {
449                        let val = vm.unwrap_or_none(err.get_arg(0));
450                        self.push_value(val);
451                        self.run(vm)
452                    } else {
453                        let (ty, val, tb) = vm.split_exception(err);
454                        self.gen_throw(vm, ty, val, tb)
455                    }
456                });
457            }
458        }
459        let exception = vm.normalize_exception(exc_type, exc_val, exc_tb)?;
460        match self.unwind_blocks(vm, UnwindReason::Raising { exception }) {
461            Ok(None) => self.run(vm),
462            Ok(Some(result)) => Ok(result),
463            Err(exception) => Err(exception),
464        }
465    }
466
467    fn unbound_cell_exception(&self, i: usize, vm: &VirtualMachine) -> PyBaseExceptionRef {
468        if let Some(&name) = self.code.cellvars.get(i) {
469            vm.new_exception_msg(
470                vm.ctx.exceptions.unbound_local_error.to_owned(),
471                format!("local variable '{name}' referenced before assignment"),
472            )
473        } else {
474            let name = self.code.freevars[i - self.code.cellvars.len()];
475            vm.new_name_error(
476                format!("free variable '{name}' referenced before assignment in enclosing scope"),
477                name.to_owned(),
478            )
479        }
480    }
481
482    /// Execute a single instruction.
483    #[inline(always)]
484    fn execute_instruction(
485        &mut self,
486        instruction: bytecode::Instruction,
487        arg: bytecode::OpArg,
488        extend_arg: &mut bool,
489        vm: &VirtualMachine,
490    ) -> FrameResult {
491        vm.check_signals()?;
492
493        flame_guard!(format!(
494            "Frame::execute_instruction({})",
495            instruction.display(arg, &self.code.code).to_string()
496        ));
497
498        #[cfg(feature = "vm-tracing-logging")]
499        {
500            trace!("=======");
501            /* TODO:
502            for frame in self.frames.iter() {
503                trace!("  {:?}", frame);
504            }
505            */
506            trace!("  {:#?}", self);
507            trace!(
508                "  Executing op code: {}",
509                instruction.display(arg, &self.code.code).to_string()
510            );
511            trace!("=======");
512        }
513
514        #[cold]
515        fn name_error(name: &'static PyStrInterned, vm: &VirtualMachine) -> PyBaseExceptionRef {
516            vm.new_name_error(format!("name '{name}' is not defined"), name.to_owned())
517        }
518
519        match instruction {
520            bytecode::Instruction::LoadConst { idx } => {
521                self.push_value(self.code.constants[idx.get(arg) as usize].clone().into());
522                Ok(None)
523            }
524            bytecode::Instruction::ImportName { idx } => {
525                self.import(vm, Some(self.code.names[idx.get(arg) as usize]))?;
526                Ok(None)
527            }
528            bytecode::Instruction::ImportNameless => {
529                self.import(vm, None)?;
530                Ok(None)
531            }
532            bytecode::Instruction::ImportStar => {
533                self.import_star(vm)?;
534                Ok(None)
535            }
536            bytecode::Instruction::ImportFrom { idx } => {
537                let obj = self.import_from(vm, idx.get(arg))?;
538                self.push_value(obj);
539                Ok(None)
540            }
541            bytecode::Instruction::LoadFast(idx) => {
542                #[cold]
543                fn reference_error(
544                    varname: &'static PyStrInterned,
545                    vm: &VirtualMachine,
546                ) -> PyBaseExceptionRef {
547                    vm.new_exception_msg(
548                        vm.ctx.exceptions.unbound_local_error.to_owned(),
549                        format!("local variable '{varname}' referenced before assignment",),
550                    )
551                }
552                let idx = idx.get(arg) as usize;
553                let x = self.fastlocals.lock()[idx]
554                    .clone()
555                    .ok_or_else(|| reference_error(self.code.varnames[idx], vm))?;
556                self.push_value(x);
557                Ok(None)
558            }
559            bytecode::Instruction::LoadNameAny(idx) => {
560                let name = self.code.names[idx.get(arg) as usize];
561                let result = self.locals.mapping().subscript(name, vm);
562                match result {
563                    Ok(x) => self.push_value(x),
564                    Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {
565                        self.push_value(self.load_global_or_builtin(name, vm)?);
566                    }
567                    Err(e) => return Err(e),
568                }
569                Ok(None)
570            }
571            bytecode::Instruction::LoadGlobal(idx) => {
572                let name = &self.code.names[idx.get(arg) as usize];
573                let x = self.load_global_or_builtin(name, vm)?;
574                self.push_value(x);
575                Ok(None)
576            }
577            bytecode::Instruction::LoadDeref(i) => {
578                let i = i.get(arg) as usize;
579                let x = self.cells_frees[i]
580                    .get()
581                    .ok_or_else(|| self.unbound_cell_exception(i, vm))?;
582                self.push_value(x);
583                Ok(None)
584            }
585            bytecode::Instruction::LoadClassDeref(i) => {
586                let i = i.get(arg) as usize;
587                let name = self.code.freevars[i - self.code.cellvars.len()];
588                let value = self.locals.mapping().subscript(name, vm).ok();
589                self.push_value(match value {
590                    Some(v) => v,
591                    None => self.cells_frees[i]
592                        .get()
593                        .ok_or_else(|| self.unbound_cell_exception(i, vm))?,
594                });
595                Ok(None)
596            }
597            bytecode::Instruction::StoreFast(idx) => {
598                let value = self.pop_value();
599                self.fastlocals.lock()[idx.get(arg) as usize] = Some(value);
600                Ok(None)
601            }
602            bytecode::Instruction::StoreLocal(idx) => {
603                let name = self.code.names[idx.get(arg) as usize];
604                let value = self.pop_value();
605                self.locals.mapping().ass_subscript(name, Some(value), vm)?;
606                Ok(None)
607            }
608            bytecode::Instruction::StoreGlobal(idx) => {
609                let value = self.pop_value();
610                self.globals
611                    .set_item(self.code.names[idx.get(arg) as usize], value, vm)?;
612                Ok(None)
613            }
614            bytecode::Instruction::StoreDeref(i) => {
615                let value = self.pop_value();
616                self.cells_frees[i.get(arg) as usize].set(Some(value));
617                Ok(None)
618            }
619            bytecode::Instruction::DeleteFast(idx) => {
620                let mut fastlocals = self.fastlocals.lock();
621                let idx = idx.get(arg) as usize;
622                if fastlocals[idx].is_none() {
623                    return Err(vm.new_exception_msg(
624                        vm.ctx.exceptions.unbound_local_error.to_owned(),
625                        format!(
626                            "local variable '{}' referenced before assignment",
627                            self.code.varnames[idx]
628                        ),
629                    ));
630                }
631                fastlocals[idx] = None;
632                Ok(None)
633            }
634            bytecode::Instruction::DeleteLocal(idx) => {
635                let name = self.code.names[idx.get(arg) as usize];
636                let res = self.locals.mapping().ass_subscript(name, None, vm);
637
638                match res {
639                    Ok(()) => {}
640                    Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {
641                        return Err(name_error(name, vm))
642                    }
643                    Err(e) => return Err(e),
644                }
645                Ok(None)
646            }
647            bytecode::Instruction::DeleteGlobal(idx) => {
648                let name = self.code.names[idx.get(arg) as usize];
649                match self.globals.del_item(name, vm) {
650                    Ok(()) => {}
651                    Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {
652                        return Err(name_error(name, vm))
653                    }
654                    Err(e) => return Err(e),
655                }
656                Ok(None)
657            }
658            bytecode::Instruction::DeleteDeref(i) => {
659                self.cells_frees[i.get(arg) as usize].set(None);
660                Ok(None)
661            }
662            bytecode::Instruction::LoadClosure(i) => {
663                let value = self.cells_frees[i.get(arg) as usize].clone();
664                self.push_value(value.into());
665                Ok(None)
666            }
667            bytecode::Instruction::Subscript => self.execute_subscript(vm),
668            bytecode::Instruction::StoreSubscript => self.execute_store_subscript(vm),
669            bytecode::Instruction::DeleteSubscript => self.execute_delete_subscript(vm),
670            bytecode::Instruction::Pop => {
671                // Pop value from stack and ignore.
672                self.pop_value();
673                Ok(None)
674            }
675            bytecode::Instruction::Duplicate => {
676                // Duplicate top of stack
677                let value = self.top_value();
678                self.push_value(value.to_owned());
679                Ok(None)
680            }
681            bytecode::Instruction::Duplicate2 => {
682                // Duplicate top 2 of stack
683                let len = self.state.stack.len();
684                self.push_value(self.state.stack[len - 2].clone());
685                self.push_value(self.state.stack[len - 1].clone());
686                Ok(None)
687            }
688            // splitting the instructions like this offloads the cost of "dynamic" dispatch (on the
689            // amount to rotate) to the opcode dispatcher, and generates optimized code for the
690            // concrete cases we actually have
691            bytecode::Instruction::Rotate2 => self.execute_rotate(2),
692            bytecode::Instruction::Rotate3 => self.execute_rotate(3),
693            bytecode::Instruction::BuildString { size } => {
694                let s = self
695                    .pop_multiple(size.get(arg) as usize)
696                    .as_slice()
697                    .iter()
698                    .map(|pyobj| pyobj.payload::<PyStr>().unwrap().as_ref())
699                    .collect::<String>();
700                let str_obj = vm.ctx.new_str(s);
701                self.push_value(str_obj.into());
702                Ok(None)
703            }
704            bytecode::Instruction::BuildList { size } => {
705                let elements = self.pop_multiple(size.get(arg) as usize).collect();
706                let list_obj = vm.ctx.new_list(elements);
707                self.push_value(list_obj.into());
708                Ok(None)
709            }
710            bytecode::Instruction::BuildListUnpack { size } => {
711                let elements = self.unpack_elements(vm, size.get(arg) as usize)?;
712                let list_obj = vm.ctx.new_list(elements);
713                self.push_value(list_obj.into());
714                Ok(None)
715            }
716            bytecode::Instruction::BuildSet { size } => {
717                let set = PySet::new_ref(&vm.ctx);
718                {
719                    for element in self.pop_multiple(size.get(arg) as usize) {
720                        set.add(element, vm)?;
721                    }
722                }
723                self.push_value(set.into());
724                Ok(None)
725            }
726            bytecode::Instruction::BuildSetUnpack { size } => {
727                let set = PySet::new_ref(&vm.ctx);
728                {
729                    for element in self.pop_multiple(size.get(arg) as usize) {
730                        vm.map_iterable_object(&element, |x| set.add(x, vm))??;
731                    }
732                }
733                self.push_value(set.into());
734                Ok(None)
735            }
736            bytecode::Instruction::BuildTuple { size } => {
737                let elements = self.pop_multiple(size.get(arg) as usize).collect();
738                let list_obj = vm.ctx.new_tuple(elements);
739                self.push_value(list_obj.into());
740                Ok(None)
741            }
742            bytecode::Instruction::BuildTupleUnpack { size } => {
743                let elements = self.unpack_elements(vm, size.get(arg) as usize)?;
744                let list_obj = vm.ctx.new_tuple(elements);
745                self.push_value(list_obj.into());
746                Ok(None)
747            }
748            bytecode::Instruction::BuildMap { size } => self.execute_build_map(vm, size.get(arg)),
749            bytecode::Instruction::BuildMapForCall { size } => {
750                self.execute_build_map_for_call(vm, size.get(arg))
751            }
752            bytecode::Instruction::DictUpdate => {
753                let other = self.pop_value();
754                let dict = self
755                    .top_value()
756                    .downcast_ref::<PyDict>()
757                    .expect("exact dict expected");
758                dict.merge_object(other, vm)?;
759                Ok(None)
760            }
761            bytecode::Instruction::BuildSlice { step } => {
762                self.execute_build_slice(vm, step.get(arg))
763            }
764            bytecode::Instruction::ListAppend { i } => {
765                let item = self.pop_value();
766                let obj = self.nth_value(i.get(arg));
767                let list: &Py<PyList> = unsafe {
768                    // SAFETY: trust compiler
769                    obj.downcast_unchecked_ref()
770                };
771                list.append(item);
772                Ok(None)
773            }
774            bytecode::Instruction::SetAdd { i } => {
775                let item = self.pop_value();
776                let obj = self.nth_value(i.get(arg));
777                let set: &Py<PySet> = unsafe {
778                    // SAFETY: trust compiler
779                    obj.downcast_unchecked_ref()
780                };
781                set.add(item, vm)?;
782                Ok(None)
783            }
784            bytecode::Instruction::MapAdd { i } => {
785                let value = self.pop_value();
786                let key = self.pop_value();
787                let obj = self.nth_value(i.get(arg));
788                let dict: &Py<PyDict> = unsafe {
789                    // SAFETY: trust compiler
790                    obj.downcast_unchecked_ref()
791                };
792                dict.set_item(&*key, value, vm)?;
793                Ok(None)
794            }
795            bytecode::Instruction::BinaryOperation { op } => self.execute_binop(vm, op.get(arg)),
796            bytecode::Instruction::BinaryOperationInplace { op } => {
797                self.execute_binop_inplace(vm, op.get(arg))
798            }
799            bytecode::Instruction::LoadAttr { idx } => self.load_attr(vm, idx.get(arg)),
800            bytecode::Instruction::StoreAttr { idx } => self.store_attr(vm, idx.get(arg)),
801            bytecode::Instruction::DeleteAttr { idx } => self.delete_attr(vm, idx.get(arg)),
802            bytecode::Instruction::UnaryOperation { op } => self.execute_unop(vm, op.get(arg)),
803            bytecode::Instruction::TestOperation { op } => self.execute_test(vm, op.get(arg)),
804            bytecode::Instruction::CompareOperation { op } => self.execute_compare(vm, op.get(arg)),
805            bytecode::Instruction::ReturnValue => {
806                let value = self.pop_value();
807                self.unwind_blocks(vm, UnwindReason::Returning { value })
808            }
809            bytecode::Instruction::ReturnConst { idx } => {
810                let value = self.code.constants[idx.get(arg) as usize].clone().into();
811                self.unwind_blocks(vm, UnwindReason::Returning { value })
812            }
813            bytecode::Instruction::YieldValue => {
814                let value = self.pop_value();
815                let value = if self.code.flags.contains(bytecode::CodeFlags::IS_COROUTINE) {
816                    PyAsyncGenWrappedValue(value).into_pyobject(vm)
817                } else {
818                    value
819                };
820                Ok(Some(ExecutionResult::Yield(value)))
821            }
822            bytecode::Instruction::YieldFrom => self.execute_yield_from(vm),
823            bytecode::Instruction::SetupAnnotation => self.setup_annotations(vm),
824            bytecode::Instruction::SetupLoop => {
825                self.push_block(BlockType::Loop);
826                Ok(None)
827            }
828            bytecode::Instruction::SetupExcept { handler } => {
829                self.push_block(BlockType::TryExcept {
830                    handler: handler.get(arg),
831                });
832                Ok(None)
833            }
834            bytecode::Instruction::SetupFinally { handler } => {
835                self.push_block(BlockType::Finally {
836                    handler: handler.get(arg),
837                });
838                Ok(None)
839            }
840            bytecode::Instruction::EnterFinally => {
841                self.push_block(BlockType::FinallyHandler {
842                    reason: None,
843                    prev_exc: vm.current_exception(),
844                });
845                Ok(None)
846            }
847            bytecode::Instruction::EndFinally => {
848                // Pop the finally handler from the stack, and recall
849                // what was the reason we were in this finally clause.
850                let block = self.pop_block();
851
852                if let BlockType::FinallyHandler { reason, prev_exc } = block.typ {
853                    vm.set_exception(prev_exc);
854                    if let Some(reason) = reason {
855                        self.unwind_blocks(vm, reason)
856                    } else {
857                        Ok(None)
858                    }
859                } else {
860                    self.fatal(
861                        "Block type must be finally handler when reaching EndFinally instruction!",
862                    );
863                }
864            }
865            bytecode::Instruction::SetupWith { end } => {
866                let context_manager = self.pop_value();
867                let error_string = || -> String {
868                    format!(
869                        "'{:.200}' object does not support the context manager protocol",
870                        context_manager.class().name(),
871                    )
872                };
873                let enter_res = vm
874                    .get_special_method(&context_manager, identifier!(vm, __enter__))?
875                    .ok_or_else(|| vm.new_type_error(error_string()))?
876                    .invoke((), vm)?;
877
878                let exit = context_manager
879                    .get_attr(identifier!(vm, __exit__), vm)
880                    .map_err(|_exc| {
881                        vm.new_type_error({
882                            format!("'{} (missed __exit__ method)", error_string())
883                        })
884                    })?;
885                self.push_value(exit);
886                self.push_block(BlockType::Finally {
887                    handler: end.get(arg),
888                });
889                self.push_value(enter_res);
890                Ok(None)
891            }
892            bytecode::Instruction::BeforeAsyncWith => {
893                let mgr = self.pop_value();
894                let error_string = || -> String {
895                    format!(
896                        "'{:.200}' object does not support the asynchronous context manager protocol",
897                        mgr.class().name(),
898                    )
899                };
900
901                let aenter_res = vm
902                    .get_special_method(&mgr, identifier!(vm, __aenter__))?
903                    .ok_or_else(|| vm.new_type_error(error_string()))?
904                    .invoke((), vm)?;
905                let aexit = mgr
906                    .get_attr(identifier!(vm, __aexit__), vm)
907                    .map_err(|_exc| {
908                        vm.new_type_error({
909                            format!("'{} (missed __aexit__ method)", error_string())
910                        })
911                    })?;
912                self.push_value(aexit);
913                self.push_value(aenter_res);
914
915                Ok(None)
916            }
917            bytecode::Instruction::SetupAsyncWith { end } => {
918                let enter_res = self.pop_value();
919                self.push_block(BlockType::Finally {
920                    handler: end.get(arg),
921                });
922                self.push_value(enter_res);
923                Ok(None)
924            }
925            bytecode::Instruction::WithCleanupStart => {
926                let block = self.current_block().unwrap();
927                let reason = match block.typ {
928                    BlockType::FinallyHandler { reason, .. } => reason,
929                    _ => self.fatal("WithCleanupStart expects a FinallyHandler block on stack"),
930                };
931                let exc = match reason {
932                    Some(UnwindReason::Raising { exception }) => Some(exception),
933                    _ => None,
934                };
935
936                let exit = self.top_value();
937
938                let args = if let Some(exc) = exc {
939                    vm.split_exception(exc)
940                } else {
941                    (vm.ctx.none(), vm.ctx.none(), vm.ctx.none())
942                };
943                let exit_res = exit.call(args, vm)?;
944                self.replace_top(exit_res);
945
946                Ok(None)
947            }
948            bytecode::Instruction::WithCleanupFinish => {
949                let block = self.pop_block();
950                let (reason, prev_exc) = match block.typ {
951                    BlockType::FinallyHandler { reason, prev_exc } => (reason, prev_exc),
952                    _ => self.fatal("WithCleanupFinish expects a FinallyHandler block on stack"),
953                };
954
955                vm.set_exception(prev_exc);
956
957                let suppress_exception = self.pop_value().try_to_bool(vm)?;
958
959                if suppress_exception {
960                    Ok(None)
961                } else if let Some(reason) = reason {
962                    self.unwind_blocks(vm, reason)
963                } else {
964                    Ok(None)
965                }
966            }
967            bytecode::Instruction::PopBlock => {
968                self.pop_block();
969                Ok(None)
970            }
971            bytecode::Instruction::GetIter => {
972                let iterated_obj = self.pop_value();
973                let iter_obj = iterated_obj.get_iter(vm)?;
974                self.push_value(iter_obj.into());
975                Ok(None)
976            }
977            bytecode::Instruction::GetAwaitable => {
978                let awaited_obj = self.pop_value();
979                let awaitable = if awaited_obj.payload_is::<PyCoroutine>() {
980                    awaited_obj
981                } else {
982                    let await_method = vm.get_method_or_type_error(
983                        awaited_obj.clone(),
984                        identifier!(vm, __await__),
985                        || {
986                            format!(
987                                "object {} can't be used in 'await' expression",
988                                awaited_obj.class().name(),
989                            )
990                        },
991                    )?;
992                    await_method.call((), vm)?
993                };
994                self.push_value(awaitable);
995                Ok(None)
996            }
997            bytecode::Instruction::GetAIter => {
998                let aiterable = self.pop_value();
999                let aiter = vm.call_special_method(&aiterable, identifier!(vm, __aiter__), ())?;
1000                self.push_value(aiter);
1001                Ok(None)
1002            }
1003            bytecode::Instruction::GetANext => {
1004                #[cfg(debug_assertions)] // remove when GetANext is fully implemented
1005                let orig_stack_len = self.state.stack.len();
1006
1007                let aiter = self.top_value();
1008                let awaitable = if aiter.class().is(vm.ctx.types.async_generator) {
1009                    vm.call_special_method(aiter, identifier!(vm, __anext__), ())?
1010                } else {
1011                    if !aiter.has_attr("__anext__", vm).unwrap_or(false) {
1012                        // TODO: __anext__ must be protocol
1013                        let msg = format!(
1014                            "'async for' requires an iterator with __anext__ method, got {:.100}",
1015                            aiter.class().name()
1016                        );
1017                        return Err(vm.new_type_error(msg));
1018                    }
1019                    let next_iter =
1020                        vm.call_special_method(aiter, identifier!(vm, __anext__), ())?;
1021
1022                    // _PyCoro_GetAwaitableIter in CPython
1023                    fn get_awaitable_iter(next_iter: &PyObject, vm: &VirtualMachine) -> PyResult {
1024                        let gen_is_coroutine = |_| {
1025                            // TODO: cpython gen_is_coroutine
1026                            true
1027                        };
1028                        if next_iter.class().is(vm.ctx.types.coroutine_type)
1029                            || gen_is_coroutine(next_iter)
1030                        {
1031                            return Ok(next_iter.to_owned());
1032                        }
1033                        // TODO: error handling
1034                        vm.call_special_method(next_iter, identifier!(vm, __await__), ())
1035                    }
1036                    get_awaitable_iter(&next_iter, vm).map_err(|_| {
1037                        vm.new_type_error(format!(
1038                            "'async for' received an invalid object from __anext__: {:.200}",
1039                            next_iter.class().name()
1040                        ))
1041                    })?
1042                };
1043                self.push_value(awaitable);
1044                #[cfg(debug_assertions)]
1045                debug_assert_eq!(orig_stack_len + 1, self.state.stack.len());
1046                Ok(None)
1047            }
1048            bytecode::Instruction::EndAsyncFor => {
1049                let exc = self.pop_value();
1050                let except_block = self.pop_block(); // pushed by TryExcept unwind
1051                debug_assert_eq!(except_block.level, self.state.stack.len());
1052                let _async_iterator = self.pop_value(); // __anext__ provider in the loop
1053                if exc.fast_isinstance(vm.ctx.exceptions.stop_async_iteration) {
1054                    vm.take_exception().expect("Should have exception in stack");
1055                    Ok(None)
1056                } else {
1057                    Err(exc.downcast().unwrap())
1058                }
1059            }
1060            bytecode::Instruction::ForIter { target } => self.execute_for_iter(vm, target.get(arg)),
1061            bytecode::Instruction::MakeFunction(flags) => {
1062                self.execute_make_function(vm, flags.get(arg))
1063            }
1064            bytecode::Instruction::CallFunctionPositional { nargs } => {
1065                let args = self.collect_positional_args(nargs.get(arg));
1066                self.execute_call(args, vm)
1067            }
1068            bytecode::Instruction::CallFunctionKeyword { nargs } => {
1069                let args = self.collect_keyword_args(nargs.get(arg));
1070                self.execute_call(args, vm)
1071            }
1072            bytecode::Instruction::CallFunctionEx { has_kwargs } => {
1073                let args = self.collect_ex_args(vm, has_kwargs.get(arg))?;
1074                self.execute_call(args, vm)
1075            }
1076            bytecode::Instruction::LoadMethod { idx } => {
1077                let obj = self.pop_value();
1078                let method_name = self.code.names[idx.get(arg) as usize];
1079                let method = PyMethod::get(obj, method_name, vm)?;
1080                let (target, is_method, func) = match method {
1081                    PyMethod::Function { target, func } => (target, true, func),
1082                    PyMethod::Attribute(val) => (vm.ctx.none(), false, val),
1083                };
1084                // TODO: figure out a better way to communicate PyMethod::Attribute - CPython uses
1085                // target==NULL, maybe we could use a sentinel value or something?
1086                self.push_value(target);
1087                self.push_value(vm.ctx.new_bool(is_method).into());
1088                self.push_value(func);
1089                Ok(None)
1090            }
1091            bytecode::Instruction::CallMethodPositional { nargs } => {
1092                let args = self.collect_positional_args(nargs.get(arg));
1093                self.execute_method_call(args, vm)
1094            }
1095            bytecode::Instruction::CallMethodKeyword { nargs } => {
1096                let args = self.collect_keyword_args(nargs.get(arg));
1097                self.execute_method_call(args, vm)
1098            }
1099            bytecode::Instruction::CallMethodEx { has_kwargs } => {
1100                let args = self.collect_ex_args(vm, has_kwargs.get(arg))?;
1101                self.execute_method_call(args, vm)
1102            }
1103            bytecode::Instruction::Jump { target } => {
1104                self.jump(target.get(arg));
1105                Ok(None)
1106            }
1107            bytecode::Instruction::JumpIfTrue { target } => self.jump_if(vm, target.get(arg), true),
1108            bytecode::Instruction::JumpIfFalse { target } => {
1109                self.jump_if(vm, target.get(arg), false)
1110            }
1111            bytecode::Instruction::JumpIfTrueOrPop { target } => {
1112                self.jump_if_or_pop(vm, target.get(arg), true)
1113            }
1114            bytecode::Instruction::JumpIfFalseOrPop { target } => {
1115                self.jump_if_or_pop(vm, target.get(arg), false)
1116            }
1117
1118            bytecode::Instruction::Raise { kind } => self.execute_raise(vm, kind.get(arg)),
1119
1120            bytecode::Instruction::Break { target } => self.unwind_blocks(
1121                vm,
1122                UnwindReason::Break {
1123                    target: target.get(arg),
1124                },
1125            ),
1126            bytecode::Instruction::Continue { target } => self.unwind_blocks(
1127                vm,
1128                UnwindReason::Continue {
1129                    target: target.get(arg),
1130                },
1131            ),
1132            bytecode::Instruction::PrintExpr => self.print_expr(vm),
1133            bytecode::Instruction::LoadBuildClass => {
1134                self.push_value(vm.builtins.get_attr(identifier!(vm, __build_class__), vm)?);
1135                Ok(None)
1136            }
1137            bytecode::Instruction::UnpackSequence { size } => {
1138                self.unpack_sequence(size.get(arg), vm)
1139            }
1140            bytecode::Instruction::UnpackEx { args } => {
1141                let args = args.get(arg);
1142                self.execute_unpack_ex(vm, args.before, args.after)
1143            }
1144            bytecode::Instruction::FormatValue { conversion } => {
1145                self.format_value(conversion.get(arg), vm)
1146            }
1147            bytecode::Instruction::PopException {} => {
1148                let block = self.pop_block();
1149                if let BlockType::ExceptHandler { prev_exc } = block.typ {
1150                    vm.set_exception(prev_exc);
1151                    Ok(None)
1152                } else {
1153                    self.fatal("block type must be ExceptHandler here.")
1154                }
1155            }
1156            bytecode::Instruction::Reverse { amount } => {
1157                let stack_len = self.state.stack.len();
1158                self.state.stack[stack_len - amount.get(arg) as usize..stack_len].reverse();
1159                Ok(None)
1160            }
1161            bytecode::Instruction::ExtendedArg => {
1162                *extend_arg = true;
1163                Ok(None)
1164            }
1165            bytecode::Instruction::TypeVar => {
1166                let type_name = self.pop_value();
1167                let type_var: PyObjectRef =
1168                    _typing::make_typevar(vm, type_name.clone(), vm.ctx.none(), vm.ctx.none())
1169                        .into_ref(&vm.ctx)
1170                        .into();
1171                self.push_value(type_var);
1172                Ok(None)
1173            }
1174            bytecode::Instruction::TypeVarWithBound => {
1175                let type_name = self.pop_value();
1176                let bound = self.pop_value();
1177                let type_var: PyObjectRef =
1178                    _typing::make_typevar(vm, type_name.clone(), bound, vm.ctx.none())
1179                        .into_ref(&vm.ctx)
1180                        .into();
1181                self.push_value(type_var);
1182                Ok(None)
1183            }
1184            bytecode::Instruction::TypeVarWithConstraint => {
1185                let type_name = self.pop_value();
1186                let constraint = self.pop_value();
1187                let type_var: PyObjectRef =
1188                    _typing::make_typevar(vm, type_name.clone(), vm.ctx.none(), constraint)
1189                        .into_ref(&vm.ctx)
1190                        .into();
1191                self.push_value(type_var);
1192                Ok(None)
1193            }
1194            bytecode::Instruction::TypeAlias => {
1195                let name = self.pop_value();
1196                let type_params: PyTupleRef = self
1197                    .pop_value()
1198                    .downcast()
1199                    .map_err(|_| vm.new_type_error("Type params must be a tuple.".to_owned()))?;
1200                let value = self.pop_value();
1201                let type_alias = _typing::TypeAliasType::new(name, type_params, value);
1202                self.push_value(type_alias.into_ref(&vm.ctx).into());
1203                Ok(None)
1204            }
1205        }
1206    }
1207
1208    #[inline]
1209    fn load_global_or_builtin(&self, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
1210        self.globals
1211            .get_chain(self.builtins, name, vm)?
1212            .ok_or_else(|| {
1213                vm.new_name_error(format!("name '{name}' is not defined"), name.to_owned())
1214            })
1215    }
1216
1217    #[cfg_attr(feature = "flame-it", flame("Frame"))]
1218    fn unpack_elements(&mut self, vm: &VirtualMachine, size: usize) -> PyResult<Vec<PyObjectRef>> {
1219        let mut result = Vec::<PyObjectRef>::new();
1220        for element in self.pop_multiple(size) {
1221            let items: Vec<_> = element.try_to_value(vm)?;
1222            result.extend(items);
1223        }
1224        Ok(result)
1225    }
1226
1227    #[cfg_attr(feature = "flame-it", flame("Frame"))]
1228    fn import(&mut self, vm: &VirtualMachine, module_name: Option<&Py<PyStr>>) -> PyResult<()> {
1229        let module_name = module_name.unwrap_or(vm.ctx.empty_str);
1230        let from_list = <Option<PyTupleTyped<PyStrRef>>>::try_from_object(vm, self.pop_value())?
1231            .unwrap_or_else(|| PyTupleTyped::empty(vm));
1232        let level = usize::try_from_object(vm, self.pop_value())?;
1233
1234        let module = vm.import_from(module_name, from_list, level)?;
1235
1236        self.push_value(module);
1237        Ok(())
1238    }
1239
1240    #[cfg_attr(feature = "flame-it", flame("Frame"))]
1241    fn import_from(&mut self, vm: &VirtualMachine, idx: bytecode::NameIdx) -> PyResult {
1242        let module = self.top_value();
1243        let name = self.code.names[idx as usize];
1244        let err = || vm.new_import_error(format!("cannot import name '{name}'"), name.to_owned());
1245        // Load attribute, and transform any error into import error.
1246        if let Some(obj) = vm.get_attribute_opt(module.to_owned(), name)? {
1247            return Ok(obj);
1248        }
1249        // fallback to importing '{module.__name__}.{name}' from sys.modules
1250        let mod_name = module
1251            .get_attr(identifier!(vm, __name__), vm)
1252            .map_err(|_| err())?;
1253        let mod_name = mod_name.downcast::<PyStr>().map_err(|_| err())?;
1254        let full_mod_name = format!("{mod_name}.{name}");
1255        let sys_modules = vm.sys_module.get_attr("modules", vm).map_err(|_| err())?;
1256        sys_modules.get_item(&full_mod_name, vm).map_err(|_| err())
1257    }
1258
1259    #[cfg_attr(feature = "flame-it", flame("Frame"))]
1260    fn import_star(&mut self, vm: &VirtualMachine) -> PyResult<()> {
1261        let module = self.pop_value();
1262
1263        // Grab all the names from the module and put them in the context
1264        if let Some(dict) = module.dict() {
1265            let filter_pred: Box<dyn Fn(&str) -> bool> =
1266                if let Ok(all) = dict.get_item(identifier!(vm, __all__), vm) {
1267                    let all: Vec<PyStrRef> = all.try_to_value(vm)?;
1268                    let all: Vec<String> = all
1269                        .into_iter()
1270                        .map(|name| name.as_str().to_owned())
1271                        .collect();
1272                    Box::new(move |name| all.contains(&name.to_owned()))
1273                } else {
1274                    Box::new(|name| !name.starts_with('_'))
1275                };
1276            for (k, v) in dict {
1277                let k = PyStrRef::try_from_object(vm, k)?;
1278                if filter_pred(k.as_str()) {
1279                    self.locals.mapping().ass_subscript(&k, Some(v), vm)?;
1280                }
1281            }
1282        }
1283        Ok(())
1284    }
1285
1286    /// Unwind blocks.
1287    /// The reason for unwinding gives a hint on what to do when
1288    /// unwinding a block.
1289    /// Optionally returns an exception.
1290    #[cfg_attr(feature = "flame-it", flame("Frame"))]
1291    fn unwind_blocks(&mut self, vm: &VirtualMachine, reason: UnwindReason) -> FrameResult {
1292        // First unwind all existing blocks on the block stack:
1293        while let Some(block) = self.current_block() {
1294            // eprintln!("unwinding block: {:.60?} {:.60?}", block.typ, reason);
1295            match block.typ {
1296                BlockType::Loop => match reason {
1297                    UnwindReason::Break { target } => {
1298                        self.pop_block();
1299                        self.jump(target);
1300                        return Ok(None);
1301                    }
1302                    UnwindReason::Continue { target } => {
1303                        self.jump(target);
1304                        return Ok(None);
1305                    }
1306                    _ => {
1307                        self.pop_block();
1308                    }
1309                },
1310                BlockType::Finally { handler } => {
1311                    self.pop_block();
1312                    let prev_exc = vm.current_exception();
1313                    if let UnwindReason::Raising { exception } = &reason {
1314                        vm.set_exception(Some(exception.clone()));
1315                    }
1316                    self.push_block(BlockType::FinallyHandler {
1317                        reason: Some(reason),
1318                        prev_exc,
1319                    });
1320                    self.jump(handler);
1321                    return Ok(None);
1322                }
1323                BlockType::TryExcept { handler } => {
1324                    self.pop_block();
1325                    if let UnwindReason::Raising { exception } = reason {
1326                        self.push_block(BlockType::ExceptHandler {
1327                            prev_exc: vm.current_exception(),
1328                        });
1329                        vm.contextualize_exception(&exception);
1330                        vm.set_exception(Some(exception.clone()));
1331                        self.push_value(exception.into());
1332                        self.jump(handler);
1333                        return Ok(None);
1334                    }
1335                }
1336                BlockType::FinallyHandler { prev_exc, .. }
1337                | BlockType::ExceptHandler { prev_exc } => {
1338                    self.pop_block();
1339                    vm.set_exception(prev_exc);
1340                }
1341            }
1342        }
1343
1344        // We do not have any more blocks to unwind. Inspect the reason we are here:
1345        match reason {
1346            UnwindReason::Raising { exception } => Err(exception),
1347            UnwindReason::Returning { value } => Ok(Some(ExecutionResult::Return(value))),
1348            UnwindReason::Break { .. } | UnwindReason::Continue { .. } => {
1349                self.fatal("break or continue must occur within a loop block.")
1350            } // UnwindReason::NoWorries => Ok(None),
1351        }
1352    }
1353
1354    #[inline(always)]
1355    fn execute_rotate(&mut self, amount: usize) -> FrameResult {
1356        let i = self.state.stack.len() - amount;
1357        self.state.stack[i..].rotate_right(1);
1358        Ok(None)
1359    }
1360
1361    fn execute_subscript(&mut self, vm: &VirtualMachine) -> FrameResult {
1362        let b_ref = self.pop_value();
1363        let a_ref = self.pop_value();
1364        let value = a_ref.get_item(&*b_ref, vm)?;
1365        self.push_value(value);
1366        Ok(None)
1367    }
1368
1369    fn execute_store_subscript(&mut self, vm: &VirtualMachine) -> FrameResult {
1370        let idx = self.pop_value();
1371        let obj = self.pop_value();
1372        let value = self.pop_value();
1373        obj.set_item(&*idx, value, vm)?;
1374        Ok(None)
1375    }
1376
1377    fn execute_delete_subscript(&mut self, vm: &VirtualMachine) -> FrameResult {
1378        let idx = self.pop_value();
1379        let obj = self.pop_value();
1380        obj.del_item(&*idx, vm)?;
1381        Ok(None)
1382    }
1383
1384    fn execute_build_map(&mut self, vm: &VirtualMachine, size: u32) -> FrameResult {
1385        let size = size as usize;
1386        let map_obj = vm.ctx.new_dict();
1387        for (key, value) in self.pop_multiple(2 * size).tuples() {
1388            map_obj.set_item(&*key, value, vm)?;
1389        }
1390
1391        self.push_value(map_obj.into());
1392        Ok(None)
1393    }
1394
1395    fn execute_build_map_for_call(&mut self, vm: &VirtualMachine, size: u32) -> FrameResult {
1396        let size = size as usize;
1397        let map_obj = vm.ctx.new_dict();
1398        for obj in self.pop_multiple(size) {
1399            // Take all key-value pairs from the dict:
1400            let dict: PyDictRef = obj.downcast().map_err(|obj| {
1401                vm.new_type_error(format!("'{}' object is not a mapping", obj.class().name()))
1402            })?;
1403            for (key, value) in dict {
1404                if map_obj.contains_key(&*key, vm) {
1405                    let key_repr = &key.repr(vm)?;
1406                    let msg = format!(
1407                        "got multiple values for keyword argument {}",
1408                        key_repr.as_str()
1409                    );
1410                    return Err(vm.new_type_error(msg));
1411                }
1412                map_obj.set_item(&*key, value, vm)?;
1413            }
1414        }
1415
1416        self.push_value(map_obj.into());
1417        Ok(None)
1418    }
1419
1420    fn execute_build_slice(&mut self, vm: &VirtualMachine, step: bool) -> FrameResult {
1421        let step = if step { Some(self.pop_value()) } else { None };
1422        let stop = self.pop_value();
1423        let start = self.pop_value();
1424
1425        let obj = PySlice {
1426            start: Some(start),
1427            stop,
1428            step,
1429        }
1430        .into_ref(&vm.ctx);
1431        self.push_value(obj.into());
1432        Ok(None)
1433    }
1434
1435    fn collect_positional_args(&mut self, nargs: u32) -> FuncArgs {
1436        FuncArgs {
1437            args: self.pop_multiple(nargs as usize).collect(),
1438            kwargs: IndexMap::new(),
1439        }
1440    }
1441
1442    fn collect_keyword_args(&mut self, nargs: u32) -> FuncArgs {
1443        let kwarg_names = self
1444            .pop_value()
1445            .downcast::<PyTuple>()
1446            .expect("kwarg names should be tuple of strings");
1447        let args = self.pop_multiple(nargs as usize);
1448
1449        let kwarg_names = kwarg_names
1450            .as_slice()
1451            .iter()
1452            .map(|pyobj| pyobj.payload::<PyStr>().unwrap().as_ref().to_owned());
1453        FuncArgs::with_kwargs_names(args, kwarg_names)
1454    }
1455
1456    fn collect_ex_args(&mut self, vm: &VirtualMachine, has_kwargs: bool) -> PyResult<FuncArgs> {
1457        let kwargs = if has_kwargs {
1458            let kw_dict: PyDictRef = self.pop_value().downcast().map_err(|_| {
1459                // TODO: check collections.abc.Mapping
1460                vm.new_type_error("Kwargs must be a dict.".to_owned())
1461            })?;
1462            let mut kwargs = IndexMap::new();
1463            for (key, value) in kw_dict.into_iter() {
1464                let key = key
1465                    .payload_if_subclass::<PyStr>(vm)
1466                    .ok_or_else(|| vm.new_type_error("keywords must be strings".to_owned()))?;
1467                kwargs.insert(key.as_str().to_owned(), value);
1468            }
1469            kwargs
1470        } else {
1471            IndexMap::new()
1472        };
1473        let args = self.pop_value();
1474        let args = args.try_to_value(vm)?;
1475        Ok(FuncArgs { args, kwargs })
1476    }
1477
1478    #[inline]
1479    fn execute_call(&mut self, args: FuncArgs, vm: &VirtualMachine) -> FrameResult {
1480        let func_ref = self.pop_value();
1481        let value = func_ref.call(args, vm)?;
1482        self.push_value(value);
1483        Ok(None)
1484    }
1485
1486    #[inline]
1487    fn execute_method_call(&mut self, args: FuncArgs, vm: &VirtualMachine) -> FrameResult {
1488        let func = self.pop_value();
1489        let is_method = self.pop_value().is(&vm.ctx.true_value);
1490        let target = self.pop_value();
1491
1492        // TODO: It was PyMethod before #4873. Check if it's correct.
1493        let func = if is_method {
1494            if let Some(descr_get) = func.class().mro_find_map(|cls| cls.slots.descr_get.load()) {
1495                let cls = target.class().to_owned().into();
1496                descr_get(func, Some(target), Some(cls), vm)?
1497            } else {
1498                func
1499            }
1500        } else {
1501            drop(target); // should be None
1502            func
1503        };
1504        let value = func.call(args, vm)?;
1505        self.push_value(value);
1506        Ok(None)
1507    }
1508
1509    fn execute_raise(&mut self, vm: &VirtualMachine, kind: bytecode::RaiseKind) -> FrameResult {
1510        let cause = match kind {
1511            bytecode::RaiseKind::RaiseCause => {
1512                let val = self.pop_value();
1513                Some(if vm.is_none(&val) {
1514                    // if the cause arg is none, we clear the cause
1515                    None
1516                } else {
1517                    // if the cause arg is an exception, we overwrite it
1518                    let ctor = ExceptionCtor::try_from_object(vm, val).map_err(|_| {
1519                        vm.new_type_error(
1520                            "exception causes must derive from BaseException".to_owned(),
1521                        )
1522                    })?;
1523                    Some(ctor.instantiate(vm)?)
1524                })
1525            }
1526            // if there's no cause arg, we keep the cause as is
1527            bytecode::RaiseKind::Raise | bytecode::RaiseKind::Reraise => None,
1528        };
1529        let exception = match kind {
1530            bytecode::RaiseKind::RaiseCause | bytecode::RaiseKind::Raise => {
1531                ExceptionCtor::try_from_object(vm, self.pop_value())?.instantiate(vm)?
1532            }
1533            bytecode::RaiseKind::Reraise => vm
1534                .topmost_exception()
1535                .ok_or_else(|| vm.new_runtime_error("No active exception to reraise".to_owned()))?,
1536        };
1537        info!("Exception raised: {:?} with cause: {:?}", exception, cause);
1538        if let Some(cause) = cause {
1539            exception.set_cause(cause);
1540        }
1541        Err(exception)
1542    }
1543
1544    fn builtin_coro<'a>(&self, coro: &'a PyObject) -> Option<&'a Coro> {
1545        match_class!(match coro {
1546            ref g @ PyGenerator => Some(g.as_coro()),
1547            ref c @ PyCoroutine => Some(c.as_coro()),
1548            _ => None,
1549        })
1550    }
1551
1552    fn _send(
1553        &self,
1554        gen: &PyObject,
1555        val: PyObjectRef,
1556        vm: &VirtualMachine,
1557    ) -> PyResult<PyIterReturn> {
1558        match self.builtin_coro(gen) {
1559            Some(coro) => coro.send(gen, val, vm),
1560            // FIXME: turn return type to PyResult<PyIterReturn> then ExecutionResult will be simplified
1561            None if vm.is_none(&val) => PyIter::new(gen).next(vm),
1562            None => {
1563                let meth = gen.get_attr("send", vm)?;
1564                PyIterReturn::from_pyresult(meth.call((val,), vm), vm)
1565            }
1566        }
1567    }
1568
1569    fn execute_yield_from(&mut self, vm: &VirtualMachine) -> FrameResult {
1570        // Value send into iterator:
1571        let val = self.pop_value();
1572        let coro = self.top_value();
1573        let result = self._send(coro, val, vm)?;
1574
1575        // PyIterReturn returned from e.g. gen.__next__() or gen.send()
1576        match result {
1577            PyIterReturn::Return(value) => {
1578                // Set back program counter:
1579                self.update_lasti(|i| *i -= 1);
1580                Ok(Some(ExecutionResult::Yield(value)))
1581            }
1582            PyIterReturn::StopIteration(value) => {
1583                let value = vm.unwrap_or_none(value);
1584                self.replace_top(value);
1585                Ok(None)
1586            }
1587        }
1588    }
1589
1590    fn execute_unpack_ex(&mut self, vm: &VirtualMachine, before: u8, after: u8) -> FrameResult {
1591        let (before, after) = (before as usize, after as usize);
1592        let value = self.pop_value();
1593        let elements: Vec<_> = value.try_to_value(vm)?;
1594        let min_expected = before + after;
1595
1596        let middle = elements.len().checked_sub(min_expected).ok_or_else(|| {
1597            vm.new_value_error(format!(
1598                "not enough values to unpack (expected at least {}, got {})",
1599                min_expected,
1600                elements.len()
1601            ))
1602        })?;
1603
1604        let mut elements = elements;
1605        // Elements on stack from right-to-left:
1606        self.state
1607            .stack
1608            .extend(elements.drain(before + middle..).rev());
1609
1610        let middle_elements = elements.drain(before..).collect();
1611        let t = vm.ctx.new_list(middle_elements);
1612        self.push_value(t.into());
1613
1614        // Lastly the first reversed values:
1615        self.state.stack.extend(elements.into_iter().rev());
1616
1617        Ok(None)
1618    }
1619
1620    #[inline]
1621    fn jump(&mut self, label: bytecode::Label) {
1622        let target_pc = label.0;
1623        vm_trace!("jump from {:?} to {:?}", self.lasti(), target_pc);
1624        self.update_lasti(|i| *i = target_pc);
1625    }
1626
1627    #[inline]
1628    fn jump_if(&mut self, vm: &VirtualMachine, target: bytecode::Label, flag: bool) -> FrameResult {
1629        let obj = self.pop_value();
1630        let value = obj.try_to_bool(vm)?;
1631        if value == flag {
1632            self.jump(target);
1633        }
1634        Ok(None)
1635    }
1636
1637    #[inline]
1638    fn jump_if_or_pop(
1639        &mut self,
1640        vm: &VirtualMachine,
1641        target: bytecode::Label,
1642        flag: bool,
1643    ) -> FrameResult {
1644        let obj = self.top_value();
1645        let value = obj.to_owned().try_to_bool(vm)?;
1646        if value == flag {
1647            self.jump(target);
1648        } else {
1649            self.pop_value();
1650        }
1651        Ok(None)
1652    }
1653
1654    /// The top of stack contains the iterator, lets push it forward
1655    fn execute_for_iter(&mut self, vm: &VirtualMachine, target: bytecode::Label) -> FrameResult {
1656        let top_of_stack = PyIter::new(self.top_value());
1657        let next_obj = top_of_stack.next(vm);
1658
1659        // Check the next object:
1660        match next_obj {
1661            Ok(PyIterReturn::Return(value)) => {
1662                self.push_value(value);
1663                Ok(None)
1664            }
1665            Ok(PyIterReturn::StopIteration(_)) => {
1666                // Pop iterator from stack:
1667                self.pop_value();
1668
1669                // End of for loop
1670                self.jump(target);
1671                Ok(None)
1672            }
1673            Err(next_error) => {
1674                // Pop iterator from stack:
1675                self.pop_value();
1676                Err(next_error)
1677            }
1678        }
1679    }
1680    fn execute_make_function(
1681        &mut self,
1682        vm: &VirtualMachine,
1683        flags: bytecode::MakeFunctionFlags,
1684    ) -> FrameResult {
1685        let qualified_name = self
1686            .pop_value()
1687            .downcast::<PyStr>()
1688            .expect("qualified name to be a string");
1689        let code_obj: PyRef<PyCode> = self
1690            .pop_value()
1691            .downcast()
1692            .expect("Second to top value on the stack must be a code object");
1693
1694        let closure = if flags.contains(bytecode::MakeFunctionFlags::CLOSURE) {
1695            Some(PyTupleTyped::try_from_object(vm, self.pop_value()).unwrap())
1696        } else {
1697            None
1698        };
1699
1700        let annotations = if flags.contains(bytecode::MakeFunctionFlags::ANNOTATIONS) {
1701            self.pop_value()
1702        } else {
1703            vm.ctx.new_dict().into()
1704        };
1705
1706        let type_params: PyTupleRef = if flags.contains(bytecode::MakeFunctionFlags::TYPE_PARAMS) {
1707            self.pop_value()
1708                .downcast()
1709                .map_err(|_| vm.new_type_error("Type params must be a tuple.".to_owned()))?
1710        } else {
1711            vm.ctx.empty_tuple.clone()
1712        };
1713
1714        let kw_only_defaults = if flags.contains(bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS) {
1715            Some(
1716                self.pop_value()
1717                    .downcast::<PyDict>()
1718                    .expect("Stack value for keyword only defaults expected to be a dict"),
1719            )
1720        } else {
1721            None
1722        };
1723
1724        let defaults = if flags.contains(bytecode::MakeFunctionFlags::DEFAULTS) {
1725            Some(
1726                self.pop_value()
1727                    .downcast::<PyTuple>()
1728                    .expect("Stack value for defaults expected to be a tuple"),
1729            )
1730        } else {
1731            None
1732        };
1733
1734        // pop argc arguments
1735        // argument: name, args, globals
1736        // let scope = self.scope.clone();
1737        let func_obj = PyFunction::new(
1738            code_obj,
1739            self.globals.clone(),
1740            closure,
1741            defaults,
1742            kw_only_defaults,
1743            qualified_name.clone(),
1744            type_params,
1745        )
1746        .into_pyobject(vm);
1747
1748        func_obj.set_attr(identifier!(vm, __doc__), vm.ctx.none(), vm)?;
1749
1750        let name = qualified_name.as_str().split('.').next_back().unwrap();
1751        func_obj.set_attr(identifier!(vm, __name__), vm.new_pyobj(name), vm)?;
1752        func_obj.set_attr(identifier!(vm, __qualname__), qualified_name, vm)?;
1753        let module = vm.unwrap_or_none(self.globals.get_item_opt(identifier!(vm, __name__), vm)?);
1754        func_obj.set_attr(identifier!(vm, __module__), module, vm)?;
1755        func_obj.set_attr(identifier!(vm, __annotations__), annotations, vm)?;
1756
1757        self.push_value(func_obj);
1758        Ok(None)
1759    }
1760
1761    #[cfg_attr(feature = "flame-it", flame("Frame"))]
1762    fn execute_binop(&mut self, vm: &VirtualMachine, op: bytecode::BinaryOperator) -> FrameResult {
1763        let b_ref = &self.pop_value();
1764        let a_ref = &self.pop_value();
1765        let value = match op {
1766            bytecode::BinaryOperator::Subtract => vm._sub(a_ref, b_ref),
1767            bytecode::BinaryOperator::Add => vm._add(a_ref, b_ref),
1768            bytecode::BinaryOperator::Multiply => vm._mul(a_ref, b_ref),
1769            bytecode::BinaryOperator::MatrixMultiply => vm._matmul(a_ref, b_ref),
1770            bytecode::BinaryOperator::Power => vm._pow(a_ref, b_ref, vm.ctx.none.as_object()),
1771            bytecode::BinaryOperator::Divide => vm._truediv(a_ref, b_ref),
1772            bytecode::BinaryOperator::FloorDivide => vm._floordiv(a_ref, b_ref),
1773            bytecode::BinaryOperator::Modulo => vm._mod(a_ref, b_ref),
1774            bytecode::BinaryOperator::Lshift => vm._lshift(a_ref, b_ref),
1775            bytecode::BinaryOperator::Rshift => vm._rshift(a_ref, b_ref),
1776            bytecode::BinaryOperator::Xor => vm._xor(a_ref, b_ref),
1777            bytecode::BinaryOperator::Or => vm._or(a_ref, b_ref),
1778            bytecode::BinaryOperator::And => vm._and(a_ref, b_ref),
1779        }?;
1780
1781        self.push_value(value);
1782        Ok(None)
1783    }
1784    fn execute_binop_inplace(
1785        &mut self,
1786        vm: &VirtualMachine,
1787        op: bytecode::BinaryOperator,
1788    ) -> FrameResult {
1789        let b_ref = &self.pop_value();
1790        let a_ref = &self.pop_value();
1791        let value = match op {
1792            bytecode::BinaryOperator::Subtract => vm._isub(a_ref, b_ref),
1793            bytecode::BinaryOperator::Add => vm._iadd(a_ref, b_ref),
1794            bytecode::BinaryOperator::Multiply => vm._imul(a_ref, b_ref),
1795            bytecode::BinaryOperator::MatrixMultiply => vm._imatmul(a_ref, b_ref),
1796            bytecode::BinaryOperator::Power => vm._ipow(a_ref, b_ref, vm.ctx.none.as_object()),
1797            bytecode::BinaryOperator::Divide => vm._itruediv(a_ref, b_ref),
1798            bytecode::BinaryOperator::FloorDivide => vm._ifloordiv(a_ref, b_ref),
1799            bytecode::BinaryOperator::Modulo => vm._imod(a_ref, b_ref),
1800            bytecode::BinaryOperator::Lshift => vm._ilshift(a_ref, b_ref),
1801            bytecode::BinaryOperator::Rshift => vm._irshift(a_ref, b_ref),
1802            bytecode::BinaryOperator::Xor => vm._ixor(a_ref, b_ref),
1803            bytecode::BinaryOperator::Or => vm._ior(a_ref, b_ref),
1804            bytecode::BinaryOperator::And => vm._iand(a_ref, b_ref),
1805        }?;
1806
1807        self.push_value(value);
1808        Ok(None)
1809    }
1810
1811    #[cfg_attr(feature = "flame-it", flame("Frame"))]
1812    fn execute_unop(&mut self, vm: &VirtualMachine, op: bytecode::UnaryOperator) -> FrameResult {
1813        let a = self.pop_value();
1814        let value = match op {
1815            bytecode::UnaryOperator::Minus => vm._neg(&a)?,
1816            bytecode::UnaryOperator::Plus => vm._pos(&a)?,
1817            bytecode::UnaryOperator::Invert => vm._invert(&a)?,
1818            bytecode::UnaryOperator::Not => {
1819                let value = a.try_to_bool(vm)?;
1820                vm.ctx.new_bool(!value).into()
1821            }
1822        };
1823        self.push_value(value);
1824        Ok(None)
1825    }
1826
1827    #[cold]
1828    fn setup_annotations(&mut self, vm: &VirtualMachine) -> FrameResult {
1829        let __annotations__ = identifier!(vm, __annotations__);
1830        // Try using locals as dict first, if not, fallback to generic method.
1831        let has_annotations = match self
1832            .locals
1833            .clone()
1834            .into_object()
1835            .downcast_exact::<PyDict>(vm)
1836        {
1837            Ok(d) => d.contains_key(__annotations__, vm),
1838            Err(o) => {
1839                let needle = __annotations__.as_object();
1840                self._in(vm, needle, &o)?
1841            }
1842        };
1843        if !has_annotations {
1844            self.locals
1845                .as_object()
1846                .set_item(__annotations__, vm.ctx.new_dict().into(), vm)?;
1847        }
1848        Ok(None)
1849    }
1850
1851    fn print_expr(&mut self, vm: &VirtualMachine) -> FrameResult {
1852        let expr = self.pop_value();
1853
1854        let displayhook = vm
1855            .sys_module
1856            .get_attr("displayhook", vm)
1857            .map_err(|_| vm.new_runtime_error("lost sys.displayhook".to_owned()))?;
1858        displayhook.call((expr,), vm)?;
1859
1860        Ok(None)
1861    }
1862
1863    fn unpack_sequence(&mut self, size: u32, vm: &VirtualMachine) -> FrameResult {
1864        let value = self.pop_value();
1865        let elements: Vec<_> = value.try_to_value(vm).map_err(|e| {
1866            if e.class().is(vm.ctx.exceptions.type_error) {
1867                vm.new_type_error(format!(
1868                    "cannot unpack non-iterable {} object",
1869                    value.class().name()
1870                ))
1871            } else {
1872                e
1873            }
1874        })?;
1875        let msg = match elements.len().cmp(&(size as usize)) {
1876            std::cmp::Ordering::Equal => {
1877                self.state.stack.extend(elements.into_iter().rev());
1878                return Ok(None);
1879            }
1880            std::cmp::Ordering::Greater => {
1881                format!("too many values to unpack (expected {size})")
1882            }
1883            std::cmp::Ordering::Less => format!(
1884                "not enough values to unpack (expected {}, got {})",
1885                size,
1886                elements.len()
1887            ),
1888        };
1889        Err(vm.new_value_error(msg))
1890    }
1891
1892    fn format_value(
1893        &mut self,
1894        conversion: bytecode::ConversionFlag,
1895        vm: &VirtualMachine,
1896    ) -> FrameResult {
1897        use bytecode::ConversionFlag;
1898        let value = self.pop_value();
1899        let value = match conversion {
1900            ConversionFlag::Str => value.str(vm)?.into(),
1901            ConversionFlag::Repr => value.repr(vm)?.into(),
1902            ConversionFlag::Ascii => vm.ctx.new_str(builtins::ascii(value, vm)?).into(),
1903            ConversionFlag::None => value,
1904        };
1905
1906        let spec = self.pop_value();
1907        let formatted = vm.format(&value, spec.downcast::<PyStr>().unwrap())?;
1908        self.push_value(formatted.into());
1909        Ok(None)
1910    }
1911
1912    fn _in(&self, vm: &VirtualMachine, needle: &PyObject, haystack: &PyObject) -> PyResult<bool> {
1913        let found = vm._contains(haystack, needle)?;
1914        Ok(found)
1915    }
1916
1917    #[inline(always)]
1918    fn _not_in(
1919        &self,
1920        vm: &VirtualMachine,
1921        needle: &PyObject,
1922        haystack: &PyObject,
1923    ) -> PyResult<bool> {
1924        Ok(!self._in(vm, needle, haystack)?)
1925    }
1926
1927    #[cfg_attr(feature = "flame-it", flame("Frame"))]
1928    fn execute_test(&mut self, vm: &VirtualMachine, op: bytecode::TestOperator) -> FrameResult {
1929        let b = self.pop_value();
1930        let a = self.pop_value();
1931        let value = match op {
1932            bytecode::TestOperator::Is => a.is(&b),
1933            bytecode::TestOperator::IsNot => !a.is(&b),
1934            bytecode::TestOperator::In => self._in(vm, &a, &b)?,
1935            bytecode::TestOperator::NotIn => self._not_in(vm, &a, &b)?,
1936            bytecode::TestOperator::ExceptionMatch => {
1937                if let Some(tuple_of_exceptions) = b.downcast_ref::<PyTuple>() {
1938                    for exception in tuple_of_exceptions.iter() {
1939                        if !exception
1940                            .is_subclass(vm.ctx.exceptions.base_exception_type.into(), vm)?
1941                        {
1942                            return Err(vm.new_type_error(
1943                                "catching classes that do not inherit from BaseException is not allowed"
1944                                    .to_owned(),
1945                            ));
1946                        }
1947                    }
1948                } else if !b.is_subclass(vm.ctx.exceptions.base_exception_type.into(), vm)? {
1949                    return Err(vm.new_type_error(
1950                        "catching classes that do not inherit from BaseException is not allowed"
1951                            .to_owned(),
1952                    ));
1953                }
1954
1955                a.is_instance(&b, vm)?
1956            }
1957        };
1958
1959        self.push_value(vm.ctx.new_bool(value).into());
1960        Ok(None)
1961    }
1962
1963    #[cfg_attr(feature = "flame-it", flame("Frame"))]
1964    fn execute_compare(
1965        &mut self,
1966        vm: &VirtualMachine,
1967        op: bytecode::ComparisonOperator,
1968    ) -> FrameResult {
1969        let b = self.pop_value();
1970        let a = self.pop_value();
1971        let value = a.rich_compare(b, op.into(), vm)?;
1972        self.push_value(value);
1973        Ok(None)
1974    }
1975
1976    fn load_attr(&mut self, vm: &VirtualMachine, attr: bytecode::NameIdx) -> FrameResult {
1977        let attr_name = self.code.names[attr as usize];
1978        let parent = self.pop_value();
1979        let obj = parent.get_attr(attr_name, vm)?;
1980        self.push_value(obj);
1981        Ok(None)
1982    }
1983
1984    fn store_attr(&mut self, vm: &VirtualMachine, attr: bytecode::NameIdx) -> FrameResult {
1985        let attr_name = self.code.names[attr as usize];
1986        let parent = self.pop_value();
1987        let value = self.pop_value();
1988        parent.set_attr(attr_name, value, vm)?;
1989        Ok(None)
1990    }
1991
1992    fn delete_attr(&mut self, vm: &VirtualMachine, attr: bytecode::NameIdx) -> FrameResult {
1993        let attr_name = self.code.names[attr as usize];
1994        let parent = self.pop_value();
1995        parent.del_attr(attr_name, vm)?;
1996        Ok(None)
1997    }
1998
1999    fn push_block(&mut self, typ: BlockType) {
2000        // eprintln!("block pushed: {:.60?} {}", typ, self.state.stack.len());
2001        self.state.blocks.push(Block {
2002            typ,
2003            level: self.state.stack.len(),
2004        });
2005    }
2006
2007    #[track_caller]
2008    fn pop_block(&mut self) -> Block {
2009        let block = self.state.blocks.pop().expect("No more blocks to pop!");
2010        // eprintln!(
2011        //     "block popped: {:.60?}  {} -> {} ",
2012        //     block.typ,
2013        //     self.state.stack.len(),
2014        //     block.level
2015        // );
2016        #[cfg(debug_assertions)]
2017        if self.state.stack.len() < block.level {
2018            dbg!(&self);
2019            panic!(
2020                "stack size reversion: current size({}) < truncates target({}).",
2021                self.state.stack.len(),
2022                block.level
2023            );
2024        }
2025        self.state.stack.truncate(block.level);
2026        block
2027    }
2028
2029    #[inline]
2030    fn current_block(&self) -> Option<Block> {
2031        self.state.blocks.last().cloned()
2032    }
2033
2034    #[inline]
2035    #[track_caller] // not a real track_caller but push_value is not very useful
2036    fn push_value(&mut self, obj: PyObjectRef) {
2037        // eprintln!(
2038        //     "push_value {} / len: {} +1",
2039        //     obj.class().name(),
2040        //     self.state.stack.len()
2041        // );
2042        match self.state.stack.try_push(obj) {
2043            Ok(()) => {}
2044            Err(_e) => self.fatal("tried to push value onto stack but overflowed max_stackdepth"),
2045        }
2046    }
2047
2048    #[inline]
2049    #[track_caller] // not a real track_caller but pop_value is not very useful
2050    fn pop_value(&mut self) -> PyObjectRef {
2051        match self.state.stack.pop() {
2052            Some(x) => {
2053                // eprintln!(
2054                //     "pop_value {} / len: {}",
2055                //     x.class().name(),
2056                //     self.state.stack.len()
2057                // );
2058                x
2059            }
2060            None => self.fatal("tried to pop value but there was nothing on the stack"),
2061        }
2062    }
2063
2064    fn pop_multiple(&mut self, count: usize) -> crate::common::boxvec::Drain<PyObjectRef> {
2065        let stack_len = self.state.stack.len();
2066        self.state.stack.drain(stack_len - count..)
2067    }
2068
2069    #[inline]
2070    fn replace_top(&mut self, mut top: PyObjectRef) -> PyObjectRef {
2071        let last = self.state.stack.last_mut().unwrap();
2072        std::mem::swap(&mut top, last);
2073        top
2074    }
2075
2076    #[inline]
2077    #[track_caller] // not a real track_caller but top_value is not very useful
2078    fn top_value(&self) -> &PyObject {
2079        match &*self.state.stack {
2080            [.., last] => last,
2081            [] => self.fatal("tried to get top of stack but stack is empty"),
2082        }
2083    }
2084
2085    #[inline]
2086    #[track_caller]
2087    fn nth_value(&self, depth: u32) -> &PyObject {
2088        let stack = &self.state.stack;
2089        &stack[stack.len() - depth as usize - 1]
2090    }
2091
2092    #[cold]
2093    #[inline(never)]
2094    #[track_caller]
2095    fn fatal(&self, msg: &'static str) -> ! {
2096        dbg!(self);
2097        panic!("{}", msg)
2098    }
2099}
2100
2101impl fmt::Debug for Frame {
2102    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2103        let state = self.state.lock();
2104        let stack_str = state.stack.iter().fold(String::new(), |mut s, elem| {
2105            if elem.payload_is::<Frame>() {
2106                s.push_str("\n  > {frame}");
2107            } else {
2108                std::fmt::write(&mut s, format_args!("\n  > {elem:?}")).unwrap();
2109            }
2110            s
2111        });
2112        let block_str = state.blocks.iter().fold(String::new(), |mut s, elem| {
2113            std::fmt::write(&mut s, format_args!("\n  > {elem:?}")).unwrap();
2114            s
2115        });
2116        // TODO: fix this up
2117        let locals = self.locals.clone();
2118        write!(
2119            f,
2120            "Frame Object {{ \n Stack:{}\n Blocks:{}\n Locals:{:?}\n}}",
2121            stack_str,
2122            block_str,
2123            locals.into_object()
2124        )
2125    }
2126}