Skip to content

Commit da154fd

Browse files
committed
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.
1 parent 811ddcc commit da154fd

2 files changed

Lines changed: 20 additions & 1 deletion

File tree

py/mpconfig.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,13 @@ typedef double mp_float_t;
666666
/*****************************************************************************/
667667
/* Fine control over Python builtins, classes, modules, etc */
668668

669+
// Whether to support multiple inheritance of Python classes. Multiple
670+
// inheritance makes some C functions inherently recursive, and adds a bit of
671+
// code overhead.
672+
#ifndef MICROPY_MULTIPLE_INHERITANCE
673+
#define MICROPY_MULTIPLE_INHERITANCE (1)
674+
#endif
675+
669676
// Whether to implement attributes on functions
670677
#ifndef MICROPY_PY_FUNCTION_ATTRS
671678
#define MICROPY_PY_FUNCTION_ATTRS (0)

py/objtype.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
6767
} else if (type->parent == NULL) {
6868
// No parents so end search here.
6969
return count;
70+
#if MICROPY_MULTIPLE_INHERITANCE
7071
} else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
7172
// Multiple parents, search through them all recursively.
7273
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
7879
count += instance_count_native_bases(bt, last_native_base);
7980
}
8081
return count;
82+
#endif
8183
} else {
8284
// A single parent, use iteration to continue the search.
8385
type = type->parent;
@@ -172,6 +174,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_
172174
if (type->parent == NULL) {
173175
DEBUG_printf("mp_obj_class_lookup: No more parents\n");
174176
return;
177+
#if MICROPY_MULTIPLE_INHERITANCE
175178
} else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
176179
const mp_obj_tuple_t *parent_tuple = type->parent;
177180
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_
192195
// search last base (simple tail recursion elimination)
193196
assert(MP_OBJ_IS_TYPE(*item, &mp_type_type));
194197
type = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item);
198+
#endif
195199
} else {
196200
type = type->parent;
197201
}
@@ -247,7 +251,7 @@ STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
247251
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) {
248252
assert(mp_obj_is_instance_type(self));
249253

250-
const mp_obj_type_t *native_base;
254+
const mp_obj_type_t *native_base = NULL;
251255
size_t num_native_bases = instance_count_native_bases(self, &native_base);
252256
assert(num_native_bases < 2);
253257

@@ -1022,7 +1026,11 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
10221026
o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(bases_items[0]))->protocol;
10231027

10241028
if (bases_len >= 2) {
1029+
#if MICROPY_MULTIPLE_INHERITANCE
10251030
o->parent = MP_OBJ_TO_PTR(bases_tuple);
1031+
#else
1032+
mp_raise_NotImplementedError("multiple inheritance not supported");
1033+
#endif
10261034
} else {
10271035
o->parent = MP_OBJ_TO_PTR(bases_items[0]);
10281036
}
@@ -1101,6 +1109,7 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
11011109

11021110
if (type->parent == NULL) {
11031111
// no parents, do nothing
1112+
#if MICROPY_MULTIPLE_INHERITANCE
11041113
} else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
11051114
const mp_obj_tuple_t *parent_tuple = type->parent;
11061115
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) {
11121121
return;
11131122
}
11141123
}
1124+
#endif
11151125
} else {
11161126
mp_obj_class_lookup(&lookup, type->parent);
11171127
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) {
11581168
if (self->parent == NULL) {
11591169
// type has no parents
11601170
return false;
1171+
#if MICROPY_MULTIPLE_INHERITANCE
11611172
} else if (((mp_obj_base_t*)self->parent)->type == &mp_type_tuple) {
11621173
// get the base objects (they should be type objects)
11631174
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) {
11731184

11741185
// search last base (simple tail recursion elimination)
11751186
object = *item;
1187+
#endif
11761188
} else {
11771189
// type has 1 parent
11781190
object = MP_OBJ_FROM_PTR(self->parent);

0 commit comments

Comments
 (0)