py/objexcept: Allow clearing traceback with 'exc.__traceback__ = None'.

We allow 'exc.__traceback__ = None' assignment as a low-level optimization
of pre-allocating exception instance and raising it repeatedly - this
avoids memory allocation during raise. However, uPy will keep adding
traceback entries to such exception instance, so before throwing it,
traceback should be cleared like above.

'exc.__traceback__ = None' syntax is CPython compatible. However, unlike
it, reading that attribute or setting it to any other value is not
supported (and not intended to be supported, again, the only reason for
adding this feature is to allow zero-memalloc exception raising).
This commit is contained in:
Paul Sokolovsky 2016-11-14 02:23:30 +03:00
parent bf318801d2
commit c3d96d387c

View File

@ -152,11 +152,21 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) {
}
STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);
if (dest[0] != MP_OBJ_NULL) {
// not load attribute
// store/delete attribute
if (attr == MP_QSTR___traceback__ && dest[1] == mp_const_none) {
// We allow 'exc.__traceback__ = None' assignment as low-level
// optimization of pre-allocating exception instance and raising
// it repeatedly - this avoids memory allocation during raise.
// However, uPy will keep adding traceback entries to such
// exception instance, so before throwing it, traceback should
// be cleared like above.
self->traceback_len = 0;
dest[0] = MP_OBJ_NULL; // indicate success
}
return;
}
mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);
if (attr == MP_QSTR_args) {
dest[0] = MP_OBJ_FROM_PTR(self->args);
} else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) {