Skip to content

Commit 2931395

Browse files
committed
optimize instructions
1 parent 2ec7085 commit 2931395

File tree

1 file changed

+121
-108
lines changed

1 file changed

+121
-108
lines changed

vm/src/frame.rs

Lines changed: 121 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,12 @@ impl ExecutingFrame<'_> {
336336
// Instruction raised an exception
337337
Err(exception) => {
338338
#[cold]
339-
fn handle_exception(frame: &mut ExecutingFrame, exception: PyBaseExceptionRef, idx: usize, vm: &VirtualMachine) -> FrameResult {
339+
fn handle_exception(
340+
frame: &mut ExecutingFrame,
341+
exception: PyBaseExceptionRef,
342+
idx: usize,
343+
vm: &VirtualMachine,
344+
) -> FrameResult {
340345
// 1. Extract traceback from exception's '__traceback__' attr.
341346
// 2. Add new entry with current execution position (filename, lineno, code_object) to traceback.
342347
// 3. Unwind block stack till appropriate handler is found.
@@ -468,6 +473,11 @@ impl ExecutingFrame<'_> {
468473
trace!("=======");
469474
}
470475

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+
471481
match instruction {
472482
bytecode::Instruction::LoadConst { idx } => {
473483
self.push_value(self.code.constants[*idx as usize].clone().into());
@@ -484,16 +494,20 @@ impl ExecutingFrame<'_> {
484494
Ok(None)
485495
}
486496
bytecode::Instruction::LoadFast(idx) => {
487-
let idx = *idx as usize;
488-
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 {
489502
vm.new_exception_msg(
490503
vm.ctx.exceptions.unbound_local_error.to_owned(),
491-
format!(
492-
"local variable '{}' referenced before assignment",
493-
self.code.varnames[idx]
494-
),
504+
format!("local variable '{varname}' referenced before assignment",),
495505
)
496-
})?;
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))?;
497511
self.push_value(x);
498512
Ok(None)
499513
}
@@ -565,10 +579,7 @@ impl ExecutingFrame<'_> {
565579
match res {
566580
Ok(()) => {}
567581
Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {
568-
return Err(vm.new_name_error(
569-
format!("name '{}' is not defined", name),
570-
name.to_owned(),
571-
))
582+
return Err(name_error(name, vm))
572583
}
573584
Err(e) => return Err(e),
574585
}
@@ -579,10 +590,7 @@ impl ExecutingFrame<'_> {
579590
match self.globals.del_item(name, vm) {
580591
Ok(()) => {}
581592
Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {
582-
return Err(vm.new_name_error(
583-
format!("name '{}' is not defined", name),
584-
name.to_owned(),
585-
))
593+
return Err(name_error(name, vm))
586594
}
587595
Err(e) => return Err(e),
588596
}
@@ -613,10 +621,8 @@ impl ExecutingFrame<'_> {
613621
}
614622
bytecode::Instruction::Duplicate2 => {
615623
// Duplicate top 2 of stack
616-
let top = self.pop_value();
617-
let second_to_top = self.pop_value();
618-
self.push_value(second_to_top.clone());
619-
self.push_value(top.clone());
624+
let top = self.last_value();
625+
let second_to_top = self.nth_value(1).to_owned();
620626
self.push_value(second_to_top);
621627
self.push_value(top);
622628
Ok(None)
@@ -727,30 +733,7 @@ impl ExecutingFrame<'_> {
727733
Ok(Some(ExecutionResult::Yield(value)))
728734
}
729735
bytecode::Instruction::YieldFrom => self.execute_yield_from(vm),
730-
bytecode::Instruction::SetupAnnotation => {
731-
let __annotations__ = identifier!(vm, __annotations__);
732-
// Try using locals as dict first, if not, fallback to generic method.
733-
let has_annotations = match self
734-
.locals
735-
.clone()
736-
.into_object()
737-
.downcast_exact::<PyDict>(vm)
738-
{
739-
Ok(d) => d.contains_key(__annotations__, vm),
740-
Err(o) => {
741-
let needle = __annotations__.to_object();
742-
self._in(vm, needle, o)?
743-
}
744-
};
745-
if !has_annotations {
746-
self.locals.as_object().set_item(
747-
__annotations__,
748-
vm.ctx.new_dict().into(),
749-
vm,
750-
)?;
751-
}
752-
Ok(None)
753-
}
736+
bytecode::Instruction::SetupAnnotation => self.setup_annotations(vm),
754737
bytecode::Instruction::SetupLoop { break_target } => {
755738
self.push_block(BlockType::Loop {
756739
break_target: *break_target,
@@ -1006,77 +989,16 @@ impl ExecutingFrame<'_> {
1006989
bytecode::Instruction::Continue { target } => {
1007990
self.unwind_blocks(vm, UnwindReason::Continue { target: *target })
1008991
}
1009-
bytecode::Instruction::PrintExpr => {
1010-
let expr = self.pop_value();
1011-
1012-
let displayhook = vm
1013-
.sys_module
1014-
.clone()
1015-
.get_attr("displayhook", vm)
1016-
.map_err(|_| vm.new_runtime_error("lost sys.displayhook".to_owned()))?;
1017-
vm.invoke(&displayhook, (expr,))?;
1018-
1019-
Ok(None)
1020-
}
992+
bytecode::Instruction::PrintExpr => self.print_expr(vm),
1021993
bytecode::Instruction::LoadBuildClass => {
1022994
self.push_value(vm.builtins.get_attr(identifier!(vm, __build_class__), vm)?);
1023995
Ok(None)
1024996
}
1025-
bytecode::Instruction::UnpackSequence { size } => {
1026-
let value = self.pop_value();
1027-
let elements: Vec<_> = value.try_to_value(vm).map_err(|e| {
1028-
if e.class().is(vm.ctx.exceptions.type_error) {
1029-
vm.new_type_error(format!(
1030-
"cannot unpack non-iterable {} object",
1031-
value.class().name()
1032-
))
1033-
} else {
1034-
e
1035-
}
1036-
})?;
1037-
let msg = match elements.len().cmp(&(*size as usize)) {
1038-
std::cmp::Ordering::Equal => {
1039-
self.state.stack.extend(elements.into_iter().rev());
1040-
None
1041-
}
1042-
std::cmp::Ordering::Greater => {
1043-
Some(format!("too many values to unpack (expected {})", size))
1044-
}
1045-
std::cmp::Ordering::Less => Some(format!(
1046-
"not enough values to unpack (expected {}, got {})",
1047-
size,
1048-
elements.len()
1049-
)),
1050-
};
1051-
if let Some(msg) = msg {
1052-
Err(vm.new_value_error(msg))
1053-
} else {
1054-
Ok(None)
1055-
}
1056-
}
997+
bytecode::Instruction::UnpackSequence { size } => self.unpack_sequence(*size, vm),
1057998
bytecode::Instruction::UnpackEx { before, after } => {
1058999
self.execute_unpack_ex(vm, *before, *after)
10591000
}
1060-
bytecode::Instruction::FormatValue { conversion } => {
1061-
use bytecode::ConversionFlag;
1062-
let value = self.pop_value();
1063-
let value = match conversion {
1064-
ConversionFlag::Str => value.str(vm)?.into(),
1065-
ConversionFlag::Repr => value.repr(vm)?.into(),
1066-
ConversionFlag::Ascii => vm.ctx.new_str(builtins::ascii(value, vm)?).into(),
1067-
ConversionFlag::None => value,
1068-
};
1069-
1070-
let spec = self.pop_value();
1071-
let formatted = call_object_format(
1072-
vm,
1073-
value,
1074-
None,
1075-
spec.downcast_ref::<PyStr>().unwrap().as_str(),
1076-
)?;
1077-
self.push_value(formatted.into());
1078-
Ok(None)
1079-
}
1001+
bytecode::Instruction::FormatValue { conversion } => self.format_value(*conversion, vm),
10801002
bytecode::Instruction::PopException {} => {
10811003
let block = self.pop_block();
10821004
if let BlockType::ExceptHandler { prev_exc } = block.typ {
@@ -1686,6 +1608,97 @@ impl ExecutingFrame<'_> {
16861608
Ok(None)
16871609
}
16881610

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+
16891702
fn _in(
16901703
&self,
16911704
vm: &VirtualMachine,

0 commit comments

Comments
 (0)