@@ -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