@@ -381,6 +381,73 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i
381381 break;
382382 */
383383
384+ case MP_BC_SETUP_WITH : {
385+ obj1 = TOP ();
386+ SET_TOP (rt_load_attr (obj1 , MP_QSTR___exit__ ));
387+ mp_obj_t dest [2 ];
388+ rt_load_method (obj1 , MP_QSTR___enter__ , dest );
389+ obj2 = rt_call_method_n_kw (0 , 0 , dest );
390+ SETUP_BLOCK ();
391+ PUSH (obj2 );
392+ break ;
393+ }
394+
395+ case MP_BC_WITH_CLEANUP : {
396+ static const mp_obj_t no_exc [] = {mp_const_none , mp_const_none , mp_const_none };
397+ if (TOP () == mp_const_none ) {
398+ sp -- ;
399+ obj1 = TOP ();
400+ SET_TOP (mp_const_none );
401+ obj2 = rt_call_function_n_kw (obj1 , 3 , 0 , no_exc );
402+ } else if (MP_OBJ_IS_SMALL_INT (TOP ())) {
403+ mp_obj_t cause = POP ();
404+ switch (MP_OBJ_SMALL_INT_VALUE (cause )) {
405+ case UNWIND_RETURN : {
406+ mp_obj_t retval = POP ();
407+ obj2 = rt_call_function_n_kw (TOP (), 3 , 0 , no_exc );
408+ SET_TOP (retval );
409+ PUSH (cause );
410+ break ;
411+ }
412+ case UNWIND_JUMP : {
413+ obj2 = rt_call_function_n_kw (sp [-2 ], 3 , 0 , no_exc );
414+ // Pop __exit__ boundmethod at sp[-2]
415+ sp [-2 ] = sp [-1 ];
416+ sp [-1 ] = sp [0 ];
417+ SET_TOP (cause );
418+ break ;
419+ }
420+ default :
421+ assert (0 );
422+ }
423+ } else if (mp_obj_is_exception_type (TOP ())) {
424+ mp_obj_t args [3 ] = {sp [0 ], sp [-1 ], sp [-2 ]};
425+ obj2 = rt_call_function_n_kw (sp [-3 ], 3 , 0 , args );
426+ // Pop __exit__ boundmethod at sp[-3]
427+ // TODO: Once semantics is proven, optimize for case when obj2 == True
428+ sp [-3 ] = sp [-2 ];
429+ sp [-2 ] = sp [-1 ];
430+ sp [-1 ] = sp [0 ];
431+ sp -- ;
432+ if (rt_is_true (obj2 )) {
433+ // This is what CPython does
434+ //PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_SILENCED));
435+ // But what we need to do is - pop exception from value stack...
436+ sp -= 3 ;
437+ // ... pop with exception handler, and signal END_FINALLY
438+ // to just execute finally handler normally (signalled by None
439+ // on value stack)
440+ assert (exc_sp >= exc_stack );
441+ assert (exc_sp -> opcode == MP_BC_SETUP_WITH );
442+ exc_sp -- ;
443+ PUSH (mp_const_none );
444+ }
445+ } else {
446+ assert (0 );
447+ }
448+ break ;
449+ }
450+
384451 case MP_BC_UNWIND_JUMP :
385452 DECODE_SLABEL ;
386453 PUSH ((void * )(ip + unum )); // push destination ip for jump
@@ -390,7 +457,7 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i
390457 while (unum > 0 ) {
391458 unum -= 1 ;
392459 assert (exc_sp >= exc_stack );
393- if (exc_sp -> opcode == MP_BC_SETUP_FINALLY ) {
460+ if (exc_sp -> opcode == MP_BC_SETUP_FINALLY || exc_sp -> opcode == MP_BC_SETUP_WITH ) {
394461 // We're going to run "finally" code as a coroutine
395462 // (not calling it recursively). Set up a sentinel
396463 // on a stack so it can return back to us when it is
@@ -604,7 +671,7 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i
604671 case MP_BC_RETURN_VALUE :
605672unwind_return :
606673 while (exc_sp >= exc_stack ) {
607- if (exc_sp -> opcode == MP_BC_SETUP_FINALLY ) {
674+ if (exc_sp -> opcode == MP_BC_SETUP_FINALLY || exc_sp -> opcode == MP_BC_SETUP_WITH ) {
608675 // We're going to run "finally" code as a coroutine
609676 // (not calling it recursively). Set up a sentinel
610677 // on a stack so it can return back to us when it is
0 commit comments