diff options
author | Damien George <damien@micropython.org> | 2022-06-21 18:11:19 +1000 |
---|---|---|
committer | Damien George <damien@micropython.org> | 2022-07-12 18:17:44 +1000 |
commit | d84220b8c62003b4714e0fa514a46ff5139148dc (patch) | |
tree | 45a8fd995ec210c98f84144db2138e2a65b7a9fd | |
parent | 093c4b6b2681951a277c71453598a9e0e2a82f52 (diff) | |
download | micropython-d84220b8c62003b4714e0fa514a46ff5139148dc.tar.gz micropython-d84220b8c62003b4714e0fa514a46ff5139148dc.zip |
py/vm: Remove check for ip being NULL when handling StopIteration.
This check for code_state->ip being NULL was added in
a7c02c4538bb2b986efb1999e00da4d76345767d with a commit message that "When
generator raises exception, it is automatically terminated (by setting its
code_state.ip to 0)". It was also added without any tests to test for this
particular case. (The commit did mention that CPython's test_pep380.py
triggered a bug, but upon re-running this test it did not show any need for
this NULL check of code_state->ip.)
It is true that generators that have completed (either by running to their
end or raising an exception) set "code_state.ip = 0". But there is an
explicit check at the start of mp_obj_gen_resume() to return immediately
for any attempt to resume an already-stopped generator. So the VM can
never execute a generator with NULL ip (and this was true at the time of
the above-referenced commit).
Furthermore, the other parts of the VM just before and after this piece
of code do require (or at least assume) code_state->ip is non-NULL.
Signed-off-by: Damien George <damien@micropython.org>
-rw-r--r-- | py/vm.c | 30 |
1 files changed, 14 insertions, 16 deletions
@@ -1375,22 +1375,20 @@ exception_handler: #endif if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { - if (code_state->ip) { - // check if it's a StopIteration within a for block - if (*code_state->ip == MP_BC_FOR_ITER) { - const byte *ip = code_state->ip + 1; - DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward - code_state->ip = ip + ulab; // jump to after for-block - code_state->sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator - goto outer_dispatch_loop; // continue with dispatch loop - } else if (*code_state->ip == MP_BC_YIELD_FROM) { - // StopIteration inside yield from call means return a value of - // yield from, so inject exception's value as yield from's result - // (Instead of stack pop then push we just replace exhausted gen with value) - *code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); - code_state->ip++; // yield from is over, move to next instruction - goto outer_dispatch_loop; // continue with dispatch loop - } + // check if it's a StopIteration within a for block + if (*code_state->ip == MP_BC_FOR_ITER) { + const byte *ip = code_state->ip + 1; + DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward + code_state->ip = ip + ulab; // jump to after for-block + code_state->sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator + goto outer_dispatch_loop; // continue with dispatch loop + } else if (*code_state->ip == MP_BC_YIELD_FROM) { + // StopIteration inside yield from call means return a value of + // yield from, so inject exception's value as yield from's result + // (Instead of stack pop then push we just replace exhausted gen with value) + *code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); + code_state->ip++; // yield from is over, move to next instruction + goto outer_dispatch_loop; // continue with dispatch loop } } |