Skip to content

Commit dae2c7d

Browse files
authored
Merge pull request RustPython#3763 from youknowone/inc-lasti
split functions from execute_instructions
2 parents 551b873 + 2931395 commit dae2c7d

File tree

1 file changed

+136
-120
lines changed

1 file changed

+136
-120
lines changed

vm/src/frame.rs

Lines changed: 136 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -335,22 +335,30 @@ impl ExecutingFrame<'_> {
335335
}
336336
// Instruction raised an exception
337337
Err(exception) => {
338-
// 1. Extract traceback from exception's '__traceback__' attr.
339-
// 2. Add new entry with current execution position (filename, lineno, code_object) to traceback.
340-
// 3. Unwind block stack till appropriate handler is found.
338+
#[cold]
339+
fn handle_exception(
340+
frame: &mut ExecutingFrame,
341+
exception: PyBaseExceptionRef,
342+
idx: usize,
343+
vm: &VirtualMachine,
344+
) -> FrameResult {
345+
// 1. Extract traceback from exception's '__traceback__' attr.
346+
// 2. Add new entry with current execution position (filename, lineno, code_object) to traceback.
347+
// 3. Unwind block stack till appropriate handler is found.
348+
349+
let loc = frame.code.locations[idx];
350+
let next = exception.traceback();
351+
let new_traceback =
352+
PyTraceback::new(next, frame.object.clone(), frame.lasti(), loc.row());
353+
vm_trace!("Adding to traceback: {:?} {:?}", new_traceback, loc.row());
354+
exception.set_traceback(Some(new_traceback.into_ref(vm)));
341355

342-
let loc = self.code.locations[idx];
343-
344-
let next = exception.traceback();
345-
346-
let new_traceback =
347-
PyTraceback::new(next, self.object.clone(), self.lasti(), loc.row());
348-
vm_trace!("Adding to traceback: {:?} {:?}", new_traceback, loc.row());
349-
exception.set_traceback(Some(new_traceback.into_ref(vm)));
356+
vm.contextualize_exception(&exception);
350357

351-
vm.contextualize_exception(&exception);
358+
frame.unwind_blocks(vm, UnwindReason::Raising { exception })
359+
}
352360

353-
match self.unwind_blocks(vm, UnwindReason::Raising { exception }) {
361+
match handle_exception(self, exception, idx, vm) {
354362
Ok(None) => continue,
355363
Ok(Some(result)) => {
356364
break Ok(result);
@@ -465,6 +473,11 @@ impl ExecutingFrame<'_> {
465473
trace!("=======");
466474
}
467475

476+
#[cold]
477+
fn name_error(name: &'static PyStrInterned, vm: &VirtualMachine) -> PyBaseExceptionRef {
478+
vm.new_name_error(format!("name '{name}' is not defined"), name.to_owned())
479+
}
480+
468481
match instruction {
469482
bytecode::Instruction::LoadConst { idx } => {
470483
self.push_value(self.code.constants[*idx as usize].clone().into());
@@ -481,16 +494,20 @@ impl ExecutingFrame<'_> {
481494
Ok(None)
482495
}
483496
bytecode::Instruction::LoadFast(idx) => {
484-
let idx = *idx as usize;
485-
let x = self.fastlocals.lock()[idx].clone().ok_or_else(|| {
497+
#[cold]
498+
fn reference_error(
499+
varname: &'static PyStrInterned,
500+
vm: &VirtualMachine,
501+
) -> PyBaseExceptionRef {
486502
vm.new_exception_msg(
487503
vm.ctx.exceptions.unbound_local_error.to_owned(),
488-
format!(
489-
"local variable '{}' referenced before assignment",
490-
self.code.varnames[idx]
491-
),
504+
format!("local variable '{varname}' referenced before assignment",),
492505
)
493-
})?;
506+
}
507+
let idx = *idx as usize;
508+
let x = self.fastlocals.lock()[idx]
509+
.clone()
510+
.ok_or_else(|| reference_error(self.code.varnames[idx], vm))?;
494511
self.push_value(x);
495512
Ok(None)
496513
}
@@ -562,10 +579,7 @@ impl ExecutingFrame<'_> {
562579
match res {
563580
Ok(()) => {}
564581
Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {
565-
return Err(vm.new_name_error(
566-
format!("name '{}' is not defined", name),
567-
name.to_owned(),
568-
))
582+
return Err(name_error(name, vm))
569583
}
570584
Err(e) => return Err(e),
571585
}
@@ -576,10 +590,7 @@ impl ExecutingFrame<'_> {
576590
match self.globals.del_item(name, vm) {
577591
Ok(()) => {}
578592
Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {
579-
return Err(vm.new_name_error(
580-
format!("name '{}' is not defined", name),
581-
name.to_owned(),
582-
))
593+
return Err(name_error(name, vm))
583594
}
584595
Err(e) => return Err(e),
585596
}
@@ -610,10 +621,8 @@ impl ExecutingFrame<'_> {
610621
}
611622
bytecode::Instruction::Duplicate2 => {
612623
// Duplicate top 2 of stack
613-
let top = self.pop_value();
614-
let second_to_top = self.pop_value();
615-
self.push_value(second_to_top.clone());
616-
self.push_value(top.clone());
624+
let top = self.last_value();
625+
let second_to_top = self.nth_value(1).to_owned();
617626
self.push_value(second_to_top);
618627
self.push_value(top);
619628
Ok(None)
@@ -724,30 +733,7 @@ impl ExecutingFrame<'_> {
724733
Ok(Some(ExecutionResult::Yield(value)))
725734
}
726735
bytecode::Instruction::YieldFrom => self.execute_yield_from(vm),
727-
bytecode::Instruction::SetupAnnotation => {
728-
let __annotations__ = identifier!(vm, __annotations__);
729-
// Try using locals as dict first, if not, fallback to generic method.
730-
let has_annotations = match self
731-
.locals
732-
.clone()
733-
.into_object()
734-
.downcast_exact::<PyDict>(vm)
735-
{
736-
Ok(d) => d.contains_key(__annotations__, vm),
737-
Err(o) => {
738-
let needle = __annotations__.to_object();
739-
self._in(vm, needle, o)?
740-
}
741-
};
742-
if !has_annotations {
743-
self.locals.as_object().set_item(
744-
__annotations__,
745-
vm.ctx.new_dict().into(),
746-
vm,
747-
)?;
748-
}
749-
Ok(None)
750-
}
736+
bytecode::Instruction::SetupAnnotation => self.setup_annotations(vm),
751737
bytecode::Instruction::SetupLoop { break_target } => {
752738
self.push_block(BlockType::Loop {
753739
break_target: *break_target,
@@ -1003,77 +989,16 @@ impl ExecutingFrame<'_> {
1003989
bytecode::Instruction::Continue { target } => {
1004990
self.unwind_blocks(vm, UnwindReason::Continue { target: *target })
1005991
}
1006-
bytecode::Instruction::PrintExpr => {
1007-
let expr = self.pop_value();
1008-
1009-
let displayhook = vm
1010-
.sys_module
1011-
.clone()
1012-
.get_attr("displayhook", vm)
1013-
.map_err(|_| vm.new_runtime_error("lost sys.displayhook".to_owned()))?;
1014-
vm.invoke(&displayhook, (expr,))?;
1015-
1016-
Ok(None)
1017-
}
992+
bytecode::Instruction::PrintExpr => self.print_expr(vm),
1018993
bytecode::Instruction::LoadBuildClass => {
1019994
self.push_value(vm.builtins.get_attr(identifier!(vm, __build_class__), vm)?);
1020995
Ok(None)
1021996
}
1022-
bytecode::Instruction::UnpackSequence { size } => {
1023-
let value = self.pop_value();
1024-
let elements: Vec<_> = value.try_to_value(vm).map_err(|e| {
1025-
if e.class().is(vm.ctx.exceptions.type_error) {
1026-
vm.new_type_error(format!(
1027-
"cannot unpack non-iterable {} object",
1028-
value.class().name()
1029-
))
1030-
} else {
1031-
e
1032-
}
1033-
})?;
1034-
let msg = match elements.len().cmp(&(*size as usize)) {
1035-
std::cmp::Ordering::Equal => {
1036-
self.state.stack.extend(elements.into_iter().rev());
1037-
None
1038-
}
1039-
std::cmp::Ordering::Greater => {
1040-
Some(format!("too many values to unpack (expected {})", size))
1041-
}
1042-
std::cmp::Ordering::Less => Some(format!(
1043-
"not enough values to unpack (expected {}, got {})",
1044-
size,
1045-
elements.len()
1046-
)),
1047-
};
1048-
if let Some(msg) = msg {
1049-
Err(vm.new_value_error(msg))
1050-
} else {
1051-
Ok(None)
1052-
}
1053-
}
997+
bytecode::Instruction::UnpackSequence { size } => self.unpack_sequence(*size, vm),
1054998
bytecode::Instruction::UnpackEx { before, after } => {
1055999
self.execute_unpack_ex(vm, *before, *after)
10561000
}
1057-
bytecode::Instruction::FormatValue { conversion } => {
1058-
use bytecode::ConversionFlag;
1059-
let value = self.pop_value();
1060-
let value = match conversion {
1061-
ConversionFlag::Str => value.str(vm)?.into(),
1062-
ConversionFlag::Repr => value.repr(vm)?.into(),
1063-
ConversionFlag::Ascii => vm.ctx.new_str(builtins::ascii(value, vm)?).into(),
1064-
ConversionFlag::None => value,
1065-
};
1066-
1067-
let spec = self.pop_value();
1068-
let formatted = call_object_format(
1069-
vm,
1070-
value,
1071-
None,
1072-
spec.downcast_ref::<PyStr>().unwrap().as_str(),
1073-
)?;
1074-
self.push_value(formatted.into());
1075-
Ok(None)
1076-
}
1001+
bytecode::Instruction::FormatValue { conversion } => self.format_value(*conversion, vm),
10771002
bytecode::Instruction::PopException {} => {
10781003
let block = self.pop_block();
10791004
if let BlockType::ExceptHandler { prev_exc } = block.typ {
@@ -1683,6 +1608,97 @@ impl ExecutingFrame<'_> {
16831608
Ok(None)
16841609
}
16851610

1611+
#[cold]
1612+
fn setup_annotations(&mut self, vm: &VirtualMachine) -> FrameResult {
1613+
let __annotations__ = identifier!(vm, __annotations__);
1614+
// Try using locals as dict first, if not, fallback to generic method.
1615+
let has_annotations = match self
1616+
.locals
1617+
.clone()
1618+
.into_object()
1619+
.downcast_exact::<PyDict>(vm)
1620+
{
1621+
Ok(d) => d.contains_key(__annotations__, vm),
1622+
Err(o) => {
1623+
let needle = __annotations__.to_object();
1624+
self._in(vm, needle, o)?
1625+
}
1626+
};
1627+
if !has_annotations {
1628+
self.locals
1629+
.as_object()
1630+
.set_item(__annotations__, vm.ctx.new_dict().into(), vm)?;
1631+
}
1632+
Ok(None)
1633+
}
1634+
1635+
fn print_expr(&mut self, vm: &VirtualMachine) -> FrameResult {
1636+
let expr = self.pop_value();
1637+
1638+
let displayhook = vm
1639+
.sys_module
1640+
.clone()
1641+
.get_attr("displayhook", vm)
1642+
.map_err(|_| vm.new_runtime_error("lost sys.displayhook".to_owned()))?;
1643+
vm.invoke(&displayhook, (expr,))?;
1644+
1645+
Ok(None)
1646+
}
1647+
1648+
fn unpack_sequence(&mut self, size: u32, vm: &VirtualMachine) -> FrameResult {
1649+
let value = self.pop_value();
1650+
let elements: Vec<_> = value.try_to_value(vm).map_err(|e| {
1651+
if e.class().is(vm.ctx.exceptions.type_error) {
1652+
vm.new_type_error(format!(
1653+
"cannot unpack non-iterable {} object",
1654+
value.class().name()
1655+
))
1656+
} else {
1657+
e
1658+
}
1659+
})?;
1660+
let msg = match elements.len().cmp(&(size as usize)) {
1661+
std::cmp::Ordering::Equal => {
1662+
self.state.stack.extend(elements.into_iter().rev());
1663+
return Ok(None);
1664+
}
1665+
std::cmp::Ordering::Greater => {
1666+
format!("too many values to unpack (expected {})", size)
1667+
}
1668+
std::cmp::Ordering::Less => format!(
1669+
"not enough values to unpack (expected {}, got {})",
1670+
size,
1671+
elements.len()
1672+
),
1673+
};
1674+
Err(vm.new_value_error(msg))
1675+
}
1676+
1677+
fn format_value(
1678+
&mut self,
1679+
conversion: bytecode::ConversionFlag,
1680+
vm: &VirtualMachine,
1681+
) -> FrameResult {
1682+
use bytecode::ConversionFlag;
1683+
let value = self.pop_value();
1684+
let value = match conversion {
1685+
ConversionFlag::Str => value.str(vm)?.into(),
1686+
ConversionFlag::Repr => value.repr(vm)?.into(),
1687+
ConversionFlag::Ascii => vm.ctx.new_str(builtins::ascii(value, vm)?).into(),
1688+
ConversionFlag::None => value,
1689+
};
1690+
1691+
let spec = self.pop_value();
1692+
let formatted = call_object_format(
1693+
vm,
1694+
value,
1695+
None,
1696+
spec.downcast_ref::<PyStr>().unwrap().as_str(),
1697+
)?;
1698+
self.push_value(formatted.into());
1699+
Ok(None)
1700+
}
1701+
16861702
fn _in(
16871703
&self,
16881704
vm: &VirtualMachine,

0 commit comments

Comments
 (0)