@@ -548,68 +548,82 @@ run_code_state: ;
548548
549549 ENTRY (MP_BC_SETUP_WITH ): {
550550 MARK_EXC_IP_SELECTIVE ();
551+ // stack: (..., ctx_mgr)
551552 mp_obj_t obj = TOP ();
552- SET_TOP (mp_load_attr (obj , MP_QSTR___exit__ ));
553- mp_load_method (obj , MP_QSTR___enter__ , sp + 1 );
554- mp_obj_t ret = mp_call_method_n_kw (0 , 0 , sp + 1 );
553+ mp_load_method (obj , MP_QSTR___exit__ , sp );
554+ mp_load_method (obj , MP_QSTR___enter__ , sp + 2 );
555+ mp_obj_t ret = mp_call_method_n_kw (0 , 0 , sp + 2 );
556+ sp += 1 ;
555557 PUSH_EXC_BLOCK (1 );
556558 PUSH (ret );
559+ // stack: (..., __exit__, ctx_mgr, as_value)
557560 DISPATCH ();
558561 }
559562
560563 ENTRY (MP_BC_WITH_CLEANUP ): {
561564 MARK_EXC_IP_SELECTIVE ();
562565 // Arriving here, there's "exception control block" on top of stack,
563- // and __exit__ bound method underneath it. Bytecode calls __exit__,
566+ // and __exit__ method (with self) underneath it. Bytecode calls __exit__,
564567 // and "deletes" it off stack, shifting "exception control block"
565568 // to its place.
566- static const mp_obj_t no_exc [] = {mp_const_none , mp_const_none , mp_const_none };
567569 if (TOP () == mp_const_none ) {
568- sp -- ;
569- mp_obj_t obj = TOP ();
570+ // stack: (..., __exit__, ctx_mgr, None)
571+ sp [1 ] = mp_const_none ;
572+ sp [2 ] = mp_const_none ;
573+ sp -= 2 ;
574+ mp_call_method_n_kw (3 , 0 , sp );
570575 SET_TOP (mp_const_none );
571- mp_call_function_n_kw (obj , 3 , 0 , no_exc );
572576 } else if (MP_OBJ_IS_SMALL_INT (TOP ())) {
573577 mp_int_t cause_val = MP_OBJ_SMALL_INT_VALUE (TOP ());
574578 if (cause_val == UNWIND_RETURN ) {
575- mp_call_function_n_kw (sp [-2 ], 3 , 0 , no_exc );
579+ // stack: (..., __exit__, ctx_mgr, ret_val, UNWIND_RETURN)
580+ mp_obj_t ret_val = sp [-1 ];
581+ sp [-1 ] = mp_const_none ;
582+ sp [0 ] = mp_const_none ;
583+ sp [1 ] = mp_const_none ;
584+ mp_call_method_n_kw (3 , 0 , sp - 3 );
585+ sp [-3 ] = ret_val ;
586+ sp [-2 ] = MP_OBJ_NEW_SMALL_INT (UNWIND_RETURN );
576587 } else {
577588 assert (cause_val == UNWIND_JUMP );
578- mp_call_function_n_kw (sp [-3 ], 3 , 0 , no_exc );
579- // Pop __exit__ boundmethod at sp[-3]
580- sp [-3 ] = sp [-2 ];
589+ // stack: (..., __exit__, ctx_mgr, dest_ip, num_exc, UNWIND_JUMP)
590+ mp_obj_t dest_ip = sp [-2 ];
591+ mp_obj_t num_exc = sp [-1 ];
592+ sp [-2 ] = mp_const_none ;
593+ sp [-1 ] = mp_const_none ;
594+ sp [0 ] = mp_const_none ;
595+ mp_call_method_n_kw (3 , 0 , sp - 4 );
596+ sp [-4 ] = dest_ip ;
597+ sp [-3 ] = num_exc ;
598+ sp [-2 ] = MP_OBJ_NEW_SMALL_INT (UNWIND_JUMP );
581599 }
582- sp [-2 ] = sp [-1 ]; // copy retval down
583- sp [-1 ] = sp [0 ]; // copy cause down
584- sp -- ; // discard top value (was cause)
600+ sp -= 2 ; // we removed (__exit__, ctx_mgr)
585601 } else {
586602 assert (mp_obj_is_exception_type (TOP ()));
603+ // stack: (..., __exit__, ctx_mgr, traceback, exc_val, exc_type)
587604 // Need to pass (sp[0], sp[-1], sp[-2]) as arguments so must reverse the
588605 // order of these on the value stack (don't want to create a temporary
589606 // array because it increases stack footprint of the VM).
590607 mp_obj_t obj = sp [-2 ];
591608 sp [-2 ] = sp [0 ];
592609 sp [0 ] = obj ;
593- mp_obj_t ret_value = mp_call_function_n_kw ( sp [ -3 ], 3 , 0 , & sp [ -2 ] );
610+ mp_obj_t ret_value = mp_call_method_n_kw ( 3 , 0 , sp - 4 );
594611 if (mp_obj_is_true (ret_value )) {
595- // This is what CPython does
596- //PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_SILENCED));
597- // But what we need to do is - pop exception from value stack...
612+ // We need to silence/swallow the exception. This is done
613+ // by popping the exception and the __exit__ handler and
614+ // replacing it with None, which signals END_FINALLY to just
615+ // execute the finally handler normally.
598616 sp -= 4 ;
599- // ... pop "with" exception handler, and signal END_FINALLY
600- // to just execute finally handler normally (by pushing None
601- // on value stack)
617+ SET_TOP (mp_const_none );
602618 assert (exc_sp >= exc_stack );
603619 POP_EXC_BLOCK ();
604- PUSH (mp_const_none );
605620 } else {
606- // Pop __exit__ boundmethod at sp[-3], remembering that top 3 values
607- // are reversed.
608- sp [-3 ] = sp [0 ];
609- obj = sp [-2 ];
610- sp [-2 ] = sp [-1 ];
611- sp [-1 ] = obj ;
612- sp -- ;
621+ // We need to re-raise the exception. We pop __exit__ handler
622+ // and copy the 3 exception values down (remembering that they
623+ // are reversed due to above code).
624+ sp [-4 ] = sp [0 ];
625+ sp [-3 ] = sp [-1 ];
626+ sp -= 2 ;
613627 }
614628 }
615629 DISPATCH ();
0 commit comments