py/runtime: Remove nlr protection when calling __next__ in mp_resume.
And remove related comment about needing such protection when calling send. Reasoning for removal is as follows: - mp_resume is only called by the VM in YIELD_FROM opcode - if send_value != MP_OBJ_NULL then throw_value == MP_OBJ_NULL - so if __next__ or send are called then throw_value == MP_OBJ_NULL - if __next__ or send raise an exception without nlr protection then the exception will be handled by the global exception handler of the VM - this handler already has code to handle exceptions raised in YIELD_FROM, including correct handling of StopIteration - this handler doesn't handle the case of injection of GeneratorExit, but this won't be needed because throw_value == MP_OBJ_NULL Note that it's already possible for mp_resume() to raise an exception (including StopIteration) from the unprotected call to type->iternext(), so that's why the VM already has code to handle the case of exceptions coming out of mp_resume(). This commit reduces code size by a bit, and significantly reduces C stack usage when using yield-from, from 88 bytes down to 40 for Thumb2, and 152 down to 72 bytes for x86-64 (better than half). (Note that gcc doesn't seem to tail-call optimise the call from mp_resume() to mp_obj_gen_resume() so this saving in C stack usage helps all uses of yield-from.)
This commit is contained in:
parent
0c9d452370
commit
2c7a3061d5
15
py/runtime.c
15
py/runtime.c
|
@ -1248,15 +1248,8 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th
|
|||
if (send_value == mp_const_none) {
|
||||
mp_load_method_maybe(self_in, MP_QSTR___next__, dest);
|
||||
if (dest[0] != MP_OBJ_NULL) {
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
*ret_val = mp_call_method_n_kw(0, 0, dest);
|
||||
nlr_pop();
|
||||
return MP_VM_RETURN_YIELD;
|
||||
} else {
|
||||
*ret_val = MP_OBJ_FROM_PTR(nlr.ret_val);
|
||||
return MP_VM_RETURN_EXCEPTION;
|
||||
}
|
||||
*ret_val = mp_call_method_n_kw(0, 0, dest);
|
||||
return MP_VM_RETURN_YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1265,10 +1258,6 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th
|
|||
if (send_value != MP_OBJ_NULL) {
|
||||
mp_load_method(self_in, MP_QSTR_send, dest);
|
||||
dest[2] = send_value;
|
||||
// TODO: This should have exception wrapping like __next__ case
|
||||
// above. Not done right away to think how to optimize native
|
||||
// generators better, see:
|
||||
// https://github.com/micropython/micropython/issues/2628
|
||||
*ret_val = mp_call_method_n_kw(1, 0, dest);
|
||||
return MP_VM_RETURN_YIELD;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue