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