py: Add config option to disable multiple inheritance.
This patch introduces a new compile-time config option to disable multiple inheritance at the Python level: MICROPY_MULTIPLE_INHERITANCE. It is enabled by default. Disabling multiple inheritance eliminates a lot of recursion in the call graph (which is important for some embedded systems), and can be used to reduce code size for ports that are really constrained (by around 200 bytes for Thumb2 archs). With multiple inheritance disabled all tests in the test-suite pass except those that explicitly test for multiple inheritance.
This commit is contained in:
parent
811ddcc65f
commit
da154fdaf9
@ -666,6 +666,13 @@ typedef double mp_float_t;
|
||||
/*****************************************************************************/
|
||||
/* Fine control over Python builtins, classes, modules, etc */
|
||||
|
||||
// Whether to support multiple inheritance of Python classes. Multiple
|
||||
// inheritance makes some C functions inherently recursive, and adds a bit of
|
||||
// code overhead.
|
||||
#ifndef MICROPY_MULTIPLE_INHERITANCE
|
||||
#define MICROPY_MULTIPLE_INHERITANCE (1)
|
||||
#endif
|
||||
|
||||
// Whether to implement attributes on functions
|
||||
#ifndef MICROPY_PY_FUNCTION_ATTRS
|
||||
#define MICROPY_PY_FUNCTION_ATTRS (0)
|
||||
|
14
py/objtype.c
14
py/objtype.c
@ -67,6 +67,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
|
||||
} else if (type->parent == NULL) {
|
||||
// No parents so end search here.
|
||||
return count;
|
||||
#if MICROPY_MULTIPLE_INHERITANCE
|
||||
} 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;
|
||||
@ -78,6 +79,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
|
||||
count += instance_count_native_bases(bt, last_native_base);
|
||||
}
|
||||
return count;
|
||||
#endif
|
||||
} else {
|
||||
// A single parent, use iteration to continue the search.
|
||||
type = type->parent;
|
||||
@ -172,6 +174,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_
|
||||
if (type->parent == NULL) {
|
||||
DEBUG_printf("mp_obj_class_lookup: No more parents\n");
|
||||
return;
|
||||
#if MICROPY_MULTIPLE_INHERITANCE
|
||||
} 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;
|
||||
@ -192,6 +195,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_
|
||||
// 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);
|
||||
#endif
|
||||
} else {
|
||||
type = type->parent;
|
||||
}
|
||||
@ -247,7 +251,7 @@ STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
|
||||
mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
assert(mp_obj_is_instance_type(self));
|
||||
|
||||
const mp_obj_type_t *native_base;
|
||||
const mp_obj_type_t *native_base = NULL;
|
||||
size_t num_native_bases = instance_count_native_bases(self, &native_base);
|
||||
assert(num_native_bases < 2);
|
||||
|
||||
@ -1022,7 +1026,11 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
|
||||
o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(bases_items[0]))->protocol;
|
||||
|
||||
if (bases_len >= 2) {
|
||||
#if MICROPY_MULTIPLE_INHERITANCE
|
||||
o->parent = MP_OBJ_TO_PTR(bases_tuple);
|
||||
#else
|
||||
mp_raise_NotImplementedError("multiple inheritance not supported");
|
||||
#endif
|
||||
} else {
|
||||
o->parent = MP_OBJ_TO_PTR(bases_items[0]);
|
||||
}
|
||||
@ -1101,6 +1109,7 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
|
||||
if (type->parent == NULL) {
|
||||
// no parents, do nothing
|
||||
#if MICROPY_MULTIPLE_INHERITANCE
|
||||
} 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;
|
||||
@ -1112,6 +1121,7 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
mp_obj_class_lookup(&lookup, type->parent);
|
||||
if (dest[0] != MP_OBJ_NULL) {
|
||||
@ -1158,6 +1168,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
|
||||
if (self->parent == NULL) {
|
||||
// type has no parents
|
||||
return false;
|
||||
#if MICROPY_MULTIPLE_INHERITANCE
|
||||
} 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;
|
||||
@ -1173,6 +1184,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
|
||||
|
||||
// search last base (simple tail recursion elimination)
|
||||
object = *item;
|
||||
#endif
|
||||
} else {
|
||||
// type has 1 parent
|
||||
object = MP_OBJ_FROM_PTR(self->parent);
|
||||
|
Loading…
Reference in New Issue
Block a user