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 typ: BlockType,
32 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 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#[derive(Clone, Debug)]
62enum UnwindReason {
63 Returning { value: PyObjectRef },
65
66 Raising { exception: PyBaseExceptionRef },
69
70 Break { target: bytecode::Label },
73
74 Continue { target: bytecode::Label },
76}
77
78#[derive(Debug)]
79struct FrameState {
80 stack: BoxVec<PyObjectRef>,
83 blocks: Vec<Block>,
85 #[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 pub lasti: Lasti,
109 pub trace: PyMutex<PyObjectRef>,
111 state: PyMutex<FrameState>,
112
113 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
124pub enum ExecutionResult {
126 Return(PyObjectRef),
127 Yield(PyObjectRef),
128}
129
130type 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 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
294struct 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("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 let instrs = &self.code.instructions;
351 let mut arg_state = bytecode::OpArgState::default();
352 loop {
353 let idx = self.lasti() as usize;
354 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 Err(exception) => {
370 #[cold]
371 fn handle_exception(
372 frame: &mut ExecutingFrame,
373 exception: PyBaseExceptionRef,
374 idx: usize,
375 vm: &VirtualMachine,
376 ) -> FrameResult {
377 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 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 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 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), 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 #[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 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 self.pop_value();
673 Ok(None)
674 }
675 bytecode::Instruction::Duplicate => {
676 let value = self.top_value();
678 self.push_value(value.to_owned());
679 Ok(None)
680 }
681 bytecode::Instruction::Duplicate2 => {
682 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 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 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 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 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 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)] 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 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 fn get_awaitable_iter(next_iter: &PyObject, vm: &VirtualMachine) -> PyResult {
1024 let gen_is_coroutine = |_| {
1025 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 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(); debug_assert_eq!(except_block.level, self.state.stack.len());
1052 let _async_iterator = self.pop_value(); 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 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 if let Some(obj) = vm.get_attribute_opt(module.to_owned(), name)? {
1247 return Ok(obj);
1248 }
1249 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 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 #[cfg_attr(feature = "flame-it", flame("Frame"))]
1291 fn unwind_blocks(&mut self, vm: &VirtualMachine, reason: UnwindReason) -> FrameResult {
1292 while let Some(block) = self.current_block() {
1294 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 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 } }
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 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 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 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); 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 None
1516 } else {
1517 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 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 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 let val = self.pop_value();
1572 let coro = self.top_value();
1573 let result = self._send(coro, val, vm)?;
1574
1575 match result {
1577 PyIterReturn::Return(value) => {
1578 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 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 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 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 match next_obj {
1661 Ok(PyIterReturn::Return(value)) => {
1662 self.push_value(value);
1663 Ok(None)
1664 }
1665 Ok(PyIterReturn::StopIteration(_)) => {
1666 self.pop_value();
1668
1669 self.jump(target);
1671 Ok(None)
1672 }
1673 Err(next_error) => {
1674 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 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 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 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 #[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] fn push_value(&mut self, obj: PyObjectRef) {
2037 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] fn pop_value(&mut self) -> PyObjectRef {
2051 match self.state.stack.pop() {
2052 Some(x) => {
2053 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] 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 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}