diff options
| author | Damien George <damien.p.george@gmail.com> | 2018-09-28 22:16:56 +1000 |
|---|---|---|
| committer | Damien George <damien.p.george@gmail.com> | 2018-09-28 22:16:56 +1000 |
| commit | 2c7a3061d519de269815663458d82e053978d835 (patch) | |
| tree | 6acf4de800eefb685b26294045f48f9ed94f6dc1 /py/runtime.c | |
| parent | 0c9d4523705c0b7f156e92611001dfb3ea26424a (diff) | |
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.)
Diffstat (limited to 'py/runtime.c')
| -rw-r--r-- | py/runtime.c | 15 |
1 files changed, 2 insertions, 13 deletions
diff --git a/py/runtime.c b/py/runtime.c index f987fc5d5..c933a8007 100644 --- a/py/runtime.c +++ b/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; } |
