summaryrefslogtreecommitdiff
path: root/py/emitbc.c
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2024-02-29 11:13:56 +1100
committerDamien George <damien@micropython.org>2024-06-21 16:21:33 +1000
commit038125be79569548f5ebc0a336bda587ea7d63ca (patch)
tree8d5228540cd0af8eb6b688ea3e83acdec0cd5161 /py/emitbc.c
parenta19214d897f7891d177dc22bb8fc555f7e6b65bb (diff)
py/emitnative: Fix native async with.
The code generating the entry to the finally handler of an async-with statement was simply wrong for the case of the native emitter. Among other things the layout of the stack was incorrect. This is fixed by this commit. The setup of the async-with finally handler is now put in a dedicated emit function, for both the bytecode and native emitters to implement in their own way (the bytecode emitter is unchanged, just factored to a function). With this fix all of the async-with tests now work when using the native emitter. Signed-off-by: Damien George <damien@micropython.org>
Diffstat (limited to 'py/emitbc.c')
-rw-r--r--py/emitbc.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/py/emitbc.c b/py/emitbc.c
index 05754cfab..f6bb229ba 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -666,6 +666,27 @@ void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) {
mp_emit_bc_adjust_stack_size(emit, -4);
}
+#if MICROPY_PY_ASYNC_AWAIT
+void mp_emit_bc_async_with_setup_finally(emit_t *emit, mp_uint_t label_aexit_no_exc, mp_uint_t label_finally_block, mp_uint_t label_ret_unwind_jump) {
+ // The async-with body has executed and no exception was raised, the execution fell through to this point.
+ // Stack: (..., ctx_mgr)
+
+ // Finish async-with body and prepare to enter "finally" block.
+ mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE); // to tell end_finally there's no exception
+ mp_emit_bc_rot_two(emit);
+ mp_emit_bc_jump(emit, label_aexit_no_exc); // jump to code to call __aexit__
+
+ // Start of "finally" block which is entered via one of: an exception propagating out, a return, an unwind jump.
+ mp_emit_bc_label_assign(emit, label_finally_block);
+
+ // Detect which case we have by the TOS being an exception or not.
+ mp_emit_bc_dup_top(emit);
+ mp_emit_bc_load_global(emit, MP_QSTR_BaseException, MP_EMIT_IDOP_GLOBAL_GLOBAL);
+ mp_emit_bc_binary_op(emit, MP_BINARY_OP_EXCEPTION_MATCH);
+ mp_emit_bc_pop_jump_if(emit, false, label_ret_unwind_jump); // if not an exception then we have return or unwind jump.
+}
+#endif
+
void mp_emit_bc_end_finally(emit_t *emit) {
emit_write_bytecode_byte(emit, -1, MP_BC_END_FINALLY);
}
@@ -862,6 +883,9 @@ const emit_method_table_t emit_bc_method_table = {
mp_emit_bc_unwind_jump,
mp_emit_bc_setup_block,
mp_emit_bc_with_cleanup,
+ #if MICROPY_PY_ASYNC_AWAIT
+ mp_emit_bc_async_with_setup_finally,
+ #endif
mp_emit_bc_end_finally,
mp_emit_bc_get_iter,
mp_emit_bc_for_iter,