summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2017-04-06 12:09:01 +1000
committerDamien George <damien.p.george@gmail.com>2017-04-12 13:22:21 +1000
commit816413e4b20ccd463321558458bb63c310712bca (patch)
treed5c367a053af11fd76c1801023b67ae7d2a082a0 /py
parentfc710169b7fd8738b285c141f1850b262b26c622 (diff)
downloadmicropython-816413e4b20ccd463321558458bb63c310712bca.tar.gz
micropython-816413e4b20ccd463321558458bb63c310712bca.zip
py: Optimise types for common case where type has a single parent type.
The common cases for inheritance are 0 or 1 parent types, for both built-in types (eg built-in exceptions) as well as user defined types. So it makes sense to optimise the case of 1 parent type by storing just the type and not a tuple of 1 value (that value being the single parent type). This patch makes such an optimisation. Even though there is a bit more code to handle the two cases (either a single type or a tuple with 2 or more values) it helps reduce overall code size because it eliminates the need to create a static tuple to hold single parents (eg for the built-in exceptions). It also helps reduce RAM usage for user defined types that only derive from a single parent. Changes in code size (in bytes) due to this patch: bare-arm: -16 minimal (x86): -176 unix (x86-64): -320 unix nanbox: -384 stmhal: -64 cc3200: -32 esp8266: -108
Diffstat (limited to 'py')
-rw-r--r--py/obj.h7
-rw-r--r--py/objdict.c4
-rw-r--r--py/objexcept.c17
-rw-r--r--py/objnamedtuple.c4
-rw-r--r--py/objtype.c166
5 files changed, 102 insertions, 96 deletions
diff --git a/py/obj.h b/py/obj.h
index 45579ce8fa..597c7c8d97 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -525,8 +525,11 @@ struct _mp_obj_type_t {
// One of disjoint protocols (interfaces), like mp_stream_p_t, etc.
const void *protocol;
- // A tuple containing all the base types of this type.
- struct _mp_obj_tuple_t *bases_tuple;
+ // A pointer to the parents of this type:
+ // - 0 parents: pointer is NULL (object is implicitly the single parent)
+ // - 1 parent: a pointer to the type of that parent
+ // - 2 or more parents: pointer to a tuple object containing the parent types
+ const void *parent;
// A dict mapping qstrs to objects local methods/constants/etc.
struct _mp_obj_dict_t *locals_dict;
diff --git a/py/objdict.c b/py/objdict.c
index f6929d23fd..12ba61b2e9 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -577,8 +577,6 @@ const mp_obj_type_t mp_type_dict = {
};
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
-STATIC const mp_rom_obj_tuple_t ordereddict_base_tuple = {{&mp_type_tuple}, 1, {MP_ROM_PTR(&mp_type_dict)}};
-
const mp_obj_type_t mp_type_ordereddict = {
{ &mp_type_type },
.name = MP_QSTR_OrderedDict,
@@ -588,7 +586,7 @@ const mp_obj_type_t mp_type_ordereddict = {
.binary_op = dict_binary_op,
.subscr = dict_subscr,
.getiter = dict_getiter,
- .bases_tuple = (mp_obj_tuple_t*)(mp_rom_obj_tuple_t*)&ordereddict_base_tuple,
+ .parent = &mp_type_dict,
.locals_dict = (mp_obj_dict_t*)&dict_locals_dict,
};
#endif
diff --git a/py/objexcept.c b/py/objexcept.c
index dcc7800dca..4722aca914 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -197,9 +197,6 @@ const mp_obj_type_t mp_type_BaseException = {
.locals_dict = (mp_obj_dict_t*)&exc_locals_dict,
};
-#define MP_DEFINE_EXCEPTION_BASE(base_name) \
-STATIC const mp_rom_obj_tuple_t mp_type_ ## base_name ## _base_tuple = {{&mp_type_tuple}, 1, {MP_ROM_PTR(&mp_type_ ## base_name)}};\
-
#define MP_DEFINE_EXCEPTION(exc_name, base_name) \
const mp_obj_type_t mp_type_ ## exc_name = { \
{ &mp_type_type }, \
@@ -207,23 +204,20 @@ const mp_obj_type_t mp_type_ ## exc_name = { \
.print = mp_obj_exception_print, \
.make_new = mp_obj_exception_make_new, \
.attr = exception_attr, \
- .bases_tuple = (mp_obj_tuple_t*)(mp_rom_obj_tuple_t*)&mp_type_ ## base_name ## _base_tuple, \
+ .parent = &mp_type_ ## base_name, \
};
// List of all exceptions, arranged as in the table at:
// http://docs.python.org/3/library/exceptions.html
-MP_DEFINE_EXCEPTION_BASE(BaseException)
MP_DEFINE_EXCEPTION(SystemExit, BaseException)
MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
MP_DEFINE_EXCEPTION(GeneratorExit, BaseException)
MP_DEFINE_EXCEPTION(Exception, BaseException)
- MP_DEFINE_EXCEPTION_BASE(Exception)
#if MICROPY_PY_ASYNC_AWAIT
MP_DEFINE_EXCEPTION(StopAsyncIteration, Exception)
#endif
MP_DEFINE_EXCEPTION(StopIteration, Exception)
MP_DEFINE_EXCEPTION(ArithmeticError, Exception)
- MP_DEFINE_EXCEPTION_BASE(ArithmeticError)
//MP_DEFINE_EXCEPTION(FloatingPointError, ArithmeticError)
MP_DEFINE_EXCEPTION(OverflowError, ArithmeticError)
MP_DEFINE_EXCEPTION(ZeroDivisionError, ArithmeticError)
@@ -235,18 +229,15 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION(ImportError, Exception)
//MP_DEFINE_EXCEPTION(IOError, Exception) use OSError instead
MP_DEFINE_EXCEPTION(LookupError, Exception)
- MP_DEFINE_EXCEPTION_BASE(LookupError)
MP_DEFINE_EXCEPTION(IndexError, LookupError)
MP_DEFINE_EXCEPTION(KeyError, LookupError)
MP_DEFINE_EXCEPTION(MemoryError, Exception)
MP_DEFINE_EXCEPTION(NameError, Exception)
/*
- MP_DEFINE_EXCEPTION_BASE(NameError)
MP_DEFINE_EXCEPTION(UnboundLocalError, NameError)
*/
MP_DEFINE_EXCEPTION(OSError, Exception)
#if MICROPY_PY_BUILTINS_TIMEOUTERROR
- MP_DEFINE_EXCEPTION_BASE(OSError)
MP_DEFINE_EXCEPTION(TimeoutError, OSError)
#endif
/*
@@ -267,30 +258,24 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION(ReferenceError, Exception)
*/
MP_DEFINE_EXCEPTION(RuntimeError, Exception)
- MP_DEFINE_EXCEPTION_BASE(RuntimeError)
MP_DEFINE_EXCEPTION(NotImplementedError, RuntimeError)
MP_DEFINE_EXCEPTION(SyntaxError, Exception)
- MP_DEFINE_EXCEPTION_BASE(SyntaxError)
MP_DEFINE_EXCEPTION(IndentationError, SyntaxError)
/*
- MP_DEFINE_EXCEPTION_BASE(IndentationError)
MP_DEFINE_EXCEPTION(TabError, IndentationError)
*/
//MP_DEFINE_EXCEPTION(SystemError, Exception)
MP_DEFINE_EXCEPTION(TypeError, Exception)
#if MICROPY_EMIT_NATIVE
- MP_DEFINE_EXCEPTION_BASE(TypeError)
MP_DEFINE_EXCEPTION(ViperTypeError, TypeError)
#endif
MP_DEFINE_EXCEPTION(ValueError, Exception)
#if MICROPY_PY_BUILTINS_STR_UNICODE
- MP_DEFINE_EXCEPTION_BASE(ValueError)
MP_DEFINE_EXCEPTION(UnicodeError, ValueError)
//TODO: Implement more UnicodeError subclasses which take arguments
#endif
/*
MP_DEFINE_EXCEPTION(Warning, Exception)
- MP_DEFINE_EXCEPTION_BASE(Warning)
MP_DEFINE_EXCEPTION(DeprecationWarning, Warning)
MP_DEFINE_EXCEPTION(PendingDeprecationWarning, Warning)
MP_DEFINE_EXCEPTION(RuntimeWarning, Warning)
diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c
index 52468747bf..cbd845dce8 100644
--- a/py/objnamedtuple.c
+++ b/py/objnamedtuple.c
@@ -134,8 +134,6 @@ STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args,
return MP_OBJ_FROM_PTR(tuple);
}
-STATIC const mp_rom_obj_tuple_t namedtuple_base_tuple = {{&mp_type_tuple}, 1, {MP_ROM_PTR(&mp_type_tuple)}};
-
STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) {
mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, qstr, n_fields);
memset(&o->base, 0, sizeof(o->base));
@@ -148,7 +146,7 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t
o->base.attr = namedtuple_attr;
o->base.subscr = mp_obj_tuple_subscr;
o->base.getiter = mp_obj_tuple_getiter;
- o->base.bases_tuple = (mp_obj_tuple_t*)(mp_rom_obj_tuple_t*)&namedtuple_base_tuple;
+ o->base.parent = &mp_type_tuple;
o->n_fields = n_fields;
for (size_t i = 0; i < n_fields; i++) {
o->fields[i] = mp_obj_str_get_qstr(fields[i]);
diff --git a/py/objtype.c b/py/objtype.c
index dd170b4c65..5e522bed23 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -57,26 +57,34 @@ STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, size_t subobjs)
}
STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) {
- size_t len = type->bases_tuple->len;
- mp_obj_t *items = type->bases_tuple->items;
-
int count = 0;
- for (size_t i = 0; i < len; i++) {
- assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
- const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(items[i]);
- if (bt == &mp_type_object) {
- // Not a "real" type
- continue;
- }
- if (mp_obj_is_native_type(bt)) {
- *last_native_base = bt;
- count++;
+ for (;;) {
+ if (type == &mp_type_object) {
+ // Not a "real" type, end search here.
+ return count;
+ } else if (mp_obj_is_native_type(type)) {
+ // Native types don't have parents (at least not from our perspective) so end.
+ *last_native_base = type;
+ return count + 1;
+ } else if (type->parent == NULL) {
+ // No parents so end search here.
+ return count;
+ } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
+ // Multiple parents, search through them all recursively.
+ const mp_obj_tuple_t *parent_tuple = type->parent;
+ const mp_obj_t *item = parent_tuple->items;
+ const mp_obj_t *top = item + parent_tuple->len;
+ for (; item < top; ++item) {
+ assert(MP_OBJ_IS_TYPE(*item, &mp_type_type));
+ const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(*item);
+ count += instance_count_native_bases(bt, last_native_base);
+ }
+ return count;
} else {
- count += instance_count_native_bases(bt, last_native_base);
+ // A single parent, use iteration to continue the search.
+ type = type->parent;
}
}
-
- return count;
}
// TODO
@@ -160,32 +168,31 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_
// attribute not found, keep searching base classes
- // for a const struct, this entry might be NULL
- if (type->bases_tuple == NULL) {
- return;
- }
-
- size_t len = type->bases_tuple->len;
- mp_obj_t *items = type->bases_tuple->items;
- if (len == 0) {
+ if (type->parent == NULL) {
return;
- }
- for (size_t i = 0; i < len - 1; i++) {
- assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
- mp_obj_type_t *bt = (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i]);
- if (bt == &mp_type_object) {
- // Not a "real" type
- continue;
- }
- mp_obj_class_lookup(lookup, bt);
- if (lookup->dest[0] != MP_OBJ_NULL) {
- return;
+ } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
+ const mp_obj_tuple_t *parent_tuple = type->parent;
+ const mp_obj_t *item = parent_tuple->items;
+ const mp_obj_t *top = item + parent_tuple->len - 1;
+ for (; item < top; ++item) {
+ assert(MP_OBJ_IS_TYPE(*item, &mp_type_type));
+ mp_obj_type_t *bt = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item);
+ if (bt == &mp_type_object) {
+ // Not a "real" type
+ continue;
+ }
+ mp_obj_class_lookup(lookup, bt);
+ if (lookup->dest[0] != MP_OBJ_NULL) {
+ return;
+ }
}
- }
- // search last base (simple tail recursion elimination)
- assert(MP_OBJ_IS_TYPE(items[len - 1], &mp_type_type));
- type = (mp_obj_type_t*)MP_OBJ_TO_PTR(items[len - 1]);
+ // search last base (simple tail recursion elimination)
+ assert(MP_OBJ_IS_TYPE(*item, &mp_type_type));
+ type = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item);
+ } else {
+ type = type->parent;
+ }
if (type == &mp_type_object) {
// Not a "real" type
return;
@@ -946,14 +953,21 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
o->getiter = instance_getiter;
//o->iternext = ; not implemented
o->buffer_p.get_buffer = instance_get_buffer;
- // Inherit protocol from a base class. This allows to define an
- // abstract base class which would translate C-level protocol to
- // Python method calls, and any subclass inheriting from it will
- // support this feature.
+
if (len > 0) {
+ // Inherit protocol from a base class. This allows to define an
+ // abstract base class which would translate C-level protocol to
+ // Python method calls, and any subclass inheriting from it will
+ // support this feature.
o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(items[0]))->protocol;
+
+ if (len >= 2) {
+ o->parent = MP_OBJ_TO_PTR(bases_tuple);
+ } else {
+ o->parent = MP_OBJ_TO_PTR(items[0]);
+ }
}
- o->bases_tuple = MP_OBJ_TO_PTR(bases_tuple);
+
o->locals_dict = MP_OBJ_TO_PTR(locals_dict);
const mp_obj_type_t *native_base;
@@ -1015,13 +1029,6 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_type_t *type = MP_OBJ_TO_PTR(self->type);
- // for a const struct, this entry might be NULL
- if (type->bases_tuple == NULL) {
- return;
- }
-
- size_t len = type->bases_tuple->len;
- mp_obj_t *items = type->bases_tuple->items;
struct class_lookup_data lookup = {
.obj = MP_OBJ_TO_PTR(self->obj),
.attr = attr,
@@ -1029,13 +1036,27 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
.dest = dest,
.is_type = false,
};
- for (size_t i = 0; i < len; i++) {
- assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
- mp_obj_class_lookup(&lookup, (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i]));
+
+ if (type->parent == NULL) {
+ // no parents, do nothing
+ } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
+ const mp_obj_tuple_t *parent_tuple = type->parent;
+ size_t len = parent_tuple->len;
+ const mp_obj_t *items = parent_tuple->items;
+ for (size_t i = 0; i < len; i++) {
+ assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
+ mp_obj_class_lookup(&lookup, (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i]));
+ if (dest[0] != MP_OBJ_NULL) {
+ return;
+ }
+ }
+ } else {
+ mp_obj_class_lookup(&lookup, type->parent);
if (dest[0] != MP_OBJ_NULL) {
return;
}
}
+
mp_obj_class_lookup(&lookup, &mp_type_object);
}
@@ -1073,27 +1094,28 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
const mp_obj_type_t *self = MP_OBJ_TO_PTR(object);
- // for a const struct, this entry might be NULL
- if (self->bases_tuple == NULL) {
- return false;
- }
-
- // get the base objects (they should be type objects)
- size_t len = self->bases_tuple->len;
- mp_obj_t *items = self->bases_tuple->items;
- if (len == 0) {
+ if (self->parent == NULL) {
+ // type has no parents
return false;
- }
-
- // iterate through the base objects
- for (size_t i = 0; i < len - 1; i++) {
- if (mp_obj_is_subclass_fast(items[i], classinfo)) {
- return true;
+ } else if (((mp_obj_base_t*)self->parent)->type == &mp_type_tuple) {
+ // get the base objects (they should be type objects)
+ const mp_obj_tuple_t *parent_tuple = self->parent;
+ const mp_obj_t *item = parent_tuple->items;
+ const mp_obj_t *top = item + parent_tuple->len - 1;
+
+ // iterate through the base objects
+ for (; item < top; ++item) {
+ if (mp_obj_is_subclass_fast(*item, classinfo)) {
+ return true;
+ }
}
- }
- // search last base (simple tail recursion elimination)
- object = items[len - 1];
+ // search last base (simple tail recursion elimination)
+ object = *item;
+ } else {
+ // type has 1 parent
+ object = MP_OBJ_FROM_PTR(self->parent);
+ }
}
}