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>
This commit is contained in:
parent
093c4b6b26
commit
d84220b8c6
30
py/vm.c
30
py/vm.c
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user