@@ -1984,15 +1984,114 @@ STATIC void emit_native_continue_loop(emit_t *emit, mp_uint_t label, mp_uint_t e
19841984}
19851985
19861986STATIC void emit_native_setup_with (emit_t * emit , mp_uint_t label ) {
1987- // not supported, or could be with runtime call
1988- (void )emit ;
1989- (void )label ;
1990- assert (0 );
1987+ // the context manager is on the top of the stack
1988+ // stack: (..., ctx_mgr)
1989+
1990+ // get __exit__ method
1991+ vtype_kind_t vtype ;
1992+ emit_access_stack (emit , 1 , & vtype , REG_ARG_1 ); // arg1 = ctx_mgr
1993+ assert (vtype == VTYPE_PYOBJ );
1994+ emit_get_stack_pointer_to_reg_for_push (emit , REG_ARG_3 , 2 ); // arg3 = dest ptr
1995+ emit_call_with_imm_arg (emit , MP_F_LOAD_METHOD , MP_QSTR___exit__ , REG_ARG_2 );
1996+ // stack: (..., ctx_mgr, __exit__, self)
1997+
1998+ emit_pre_pop_reg (emit , & vtype , REG_ARG_3 ); // self
1999+ emit_pre_pop_reg (emit , & vtype , REG_ARG_2 ); // __exit__
2000+ emit_pre_pop_reg (emit , & vtype , REG_ARG_1 ); // ctx_mgr
2001+ emit_post_push_reg (emit , vtype , REG_ARG_2 ); // __exit__
2002+ emit_post_push_reg (emit , vtype , REG_ARG_3 ); // self
2003+ // stack: (..., __exit__, self)
2004+ // REG_ARG_1=ctx_mgr
2005+
2006+ // get __enter__ method
2007+ emit_get_stack_pointer_to_reg_for_push (emit , REG_ARG_3 , 2 ); // arg3 = dest ptr
2008+ emit_call_with_imm_arg (emit , MP_F_LOAD_METHOD , MP_QSTR___enter__ , REG_ARG_2 ); // arg2 = method name
2009+ // stack: (..., __exit__, self, __enter__, self)
2010+
2011+ // call __enter__ method
2012+ emit_get_stack_pointer_to_reg_for_pop (emit , REG_ARG_3 , 2 ); // pointer to items, including meth and self
2013+ emit_call_with_2_imm_args (emit , MP_F_CALL_METHOD_N_KW , 0 , REG_ARG_1 , 0 , REG_ARG_2 );
2014+ emit_post_push_reg (emit , VTYPE_PYOBJ , REG_RET ); // push return value of __enter__
2015+ // stack: (..., __exit__, self, as_value)
2016+
2017+ // need to commit stack because we may jump elsewhere
2018+ need_stack_settled (emit );
2019+ emit_get_stack_pointer_to_reg_for_push (emit , REG_ARG_1 , sizeof (nlr_buf_t ) / sizeof (mp_uint_t )); // arg1 = pointer to nlr buf
2020+ emit_call (emit , MP_F_NLR_PUSH );
2021+ ASM_JUMP_IF_REG_NONZERO (emit -> as , REG_RET , label );
2022+
2023+ emit_access_stack (emit , sizeof (nlr_buf_t ) / sizeof (mp_uint_t ) + 1 , & vtype , REG_RET ); // access return value of __enter__
2024+ emit_post_push_reg (emit , VTYPE_PYOBJ , REG_RET ); // push return value of __enter__
2025+ // stack: (..., __exit__, self, as_value, nlr_buf, as_value)
19912026}
19922027
19932028STATIC void emit_native_with_cleanup (emit_t * emit , mp_uint_t label ) {
1994- (void )emit ;
1995- assert (0 );
2029+ // note: label+1 is available as an auxiliary label
2030+
2031+ // stack: (..., __exit__, self, as_value, nlr_buf)
2032+ emit_native_pre (emit );
2033+ emit_call (emit , MP_F_NLR_POP );
2034+ adjust_stack (emit , - (mp_int_t )(sizeof (nlr_buf_t ) / sizeof (mp_uint_t )) - 1 );
2035+ // stack: (..., __exit__, self)
2036+
2037+ // call __exit__
2038+ emit_post_push_imm (emit , VTYPE_PYOBJ , (mp_uint_t )mp_const_none );
2039+ emit_post_push_imm (emit , VTYPE_PYOBJ , (mp_uint_t )mp_const_none );
2040+ emit_post_push_imm (emit , VTYPE_PYOBJ , (mp_uint_t )mp_const_none );
2041+ emit_get_stack_pointer_to_reg_for_pop (emit , REG_ARG_3 , 5 );
2042+ emit_call_with_2_imm_args (emit , MP_F_CALL_METHOD_N_KW , 3 , REG_ARG_1 , 0 , REG_ARG_2 );
2043+
2044+ // jump to after with cleanup nlr_catch block
2045+ adjust_stack (emit , 1 ); // dummy nlr_buf.prev
2046+ emit_native_load_const_tok (emit , MP_TOKEN_KW_NONE ); // nlr_buf.ret_val = no exception
2047+ emit_native_jump (emit , label + 1 );
2048+
2049+ // nlr_catch
2050+ emit_native_label_assign (emit , label );
2051+
2052+ // adjust stack counter for: __exit__, self, as_value
2053+ adjust_stack (emit , 3 );
2054+ // stack: (..., __exit__, self, as_value, nlr_buf.prev, nlr_buf.ret_val)
2055+
2056+ vtype_kind_t vtype ;
2057+ emit_pre_pop_reg (emit , & vtype , REG_ARG_1 ); // get the thrown value (exc)
2058+ adjust_stack (emit , -2 ); // discard nlr_buf.prev and as_value
2059+ // stack: (..., __exit__, self)
2060+ // REG_ARG_1=exc
2061+
2062+ emit_pre_pop_reg (emit , & vtype , REG_ARG_2 ); // self
2063+ emit_pre_pop_reg (emit , & vtype , REG_ARG_3 ); // __exit__
2064+ adjust_stack (emit , 1 ); // dummy nlr_buf.prev
2065+ emit_post_push_reg (emit , vtype , REG_ARG_1 ); // push exc to save it for later
2066+ emit_post_push_reg (emit , vtype , REG_ARG_3 ); // __exit__
2067+ emit_post_push_reg (emit , vtype , REG_ARG_2 ); // self
2068+ // stack: (..., exc, __exit__, self)
2069+ // REG_ARG_1=exc
2070+
2071+ ASM_LOAD_REG_REG_OFFSET (emit -> as , REG_ARG_2 , REG_ARG_1 , 0 ); // get type(exc)
2072+ emit_post_push_reg (emit , VTYPE_PYOBJ , REG_ARG_2 ); // push type(exc)
2073+ emit_post_push_reg (emit , VTYPE_PYOBJ , REG_ARG_1 ); // push exc value
2074+ emit_post_push_imm (emit , VTYPE_PYOBJ , (mp_uint_t )mp_const_none ); // traceback info
2075+ // stack: (..., exc, __exit__, self, type(exc), exc, traceback)
2076+
2077+ // call __exit__ method
2078+ emit_get_stack_pointer_to_reg_for_pop (emit , REG_ARG_3 , 5 );
2079+ emit_call_with_2_imm_args (emit , MP_F_CALL_METHOD_N_KW , 3 , REG_ARG_1 , 0 , REG_ARG_2 );
2080+ // stack: (..., exc)
2081+
2082+ // if REG_RET is true then we need to replace top-of-stack with None (swallow exception)
2083+ if (REG_ARG_1 != REG_RET ) {
2084+ ASM_MOV_REG_REG (emit -> as , REG_ARG_1 , REG_RET );
2085+ }
2086+ emit_call (emit , MP_F_OBJ_IS_TRUE );
2087+ ASM_JUMP_IF_REG_ZERO (emit -> as , REG_RET , label + 1 );
2088+
2089+ // replace exc with None
2090+ emit_pre_pop_discard (emit );
2091+ emit_post_push_imm (emit , VTYPE_PYOBJ , (mp_uint_t )mp_const_none );
2092+
2093+ // end of with cleanup nlr_catch block
2094+ emit_native_label_assign (emit , label + 1 );
19962095}
19972096
19982097STATIC void emit_native_setup_except (emit_t * emit , mp_uint_t label ) {
@@ -2016,7 +2115,8 @@ STATIC void emit_native_end_finally(emit_t *emit) {
20162115 // else: raise exc
20172116 // the check if exc is None is done in the MP_F_NATIVE_RAISE stub
20182117 vtype_kind_t vtype ;
2019- emit_pre_pop_reg (emit , & vtype , REG_ARG_1 );
2118+ emit_pre_pop_reg (emit , & vtype , REG_ARG_1 ); // get nlr_buf.ret_val
2119+ emit_pre_pop_discard (emit ); // discard nlr_buf.prev
20202120 emit_call (emit , MP_F_NATIVE_RAISE );
20212121 emit_post (emit );
20222122}
@@ -2053,7 +2153,7 @@ STATIC void emit_native_for_iter_end(emit_t *emit) {
20532153STATIC void emit_native_pop_block (emit_t * emit ) {
20542154 emit_native_pre (emit );
20552155 emit_call (emit , MP_F_NLR_POP );
2056- adjust_stack (emit , - (mp_int_t )(sizeof (nlr_buf_t ) / sizeof (mp_uint_t )));
2156+ adjust_stack (emit , - (mp_int_t )(sizeof (nlr_buf_t ) / sizeof (mp_uint_t )) + 1 );
20572157 emit_post (emit );
20582158}
20592159
@@ -2495,15 +2595,15 @@ STATIC void emit_native_start_except_handler(emit_t *emit) {
24952595 // This instruction follows an nlr_pop, so the stack counter is back to zero, when really
24962596 // it should be up by a whole nlr_buf_t. We then want to pop the nlr_buf_t here, but save
24972597 // the first 2 elements, so we can get the thrown value.
2498- adjust_stack (emit , 2 );
2598+ adjust_stack (emit , 1 );
24992599 vtype_kind_t vtype_nlr ;
25002600 emit_pre_pop_reg (emit , & vtype_nlr , REG_ARG_1 ); // get the thrown value
25012601 emit_pre_pop_discard (emit ); // discard the linked-list pointer in the nlr_buf
25022602 emit_post_push_reg_reg_reg (emit , VTYPE_PYOBJ , REG_ARG_1 , VTYPE_PYOBJ , REG_ARG_1 , VTYPE_PYOBJ , REG_ARG_1 ); // push the 3 exception items
25032603}
25042604
25052605STATIC void emit_native_end_except_handler (emit_t * emit ) {
2506- adjust_stack (emit , -2 );
2606+ adjust_stack (emit , -1 );
25072607}
25082608
25092609const emit_method_table_t EXPORT_FUN (method_table ) = {
0 commit comments