diff --git a/examples/natmod/btree/btree_c.c b/examples/natmod/btree/btree_c.c index 5e8a34ac40..e342b7d903 100644 --- a/examples/natmod/btree/btree_c.c +++ b/examples/natmod/btree/btree_c.c @@ -94,7 +94,7 @@ int mp_stream_posix_fsync(void *stream) { return res; } -mp_obj_type_t btree_type; +mp_obj_full_type_t btree_type; #include "extmod/modbtree.c" diff --git a/examples/natmod/framebuf/framebuf.c b/examples/natmod/framebuf/framebuf.c index 2eff61c817..98b44987b3 100644 --- a/examples/natmod/framebuf/framebuf.c +++ b/examples/natmod/framebuf/framebuf.c @@ -8,7 +8,7 @@ void *memset(void *s, int c, size_t n) { } #endif -mp_obj_type_t mp_type_framebuf; +mp_obj_full_type_t mp_type_framebuf; #include "extmod/modframebuf.c" diff --git a/examples/natmod/ure/ure.c b/examples/natmod/ure/ure.c index 175b93e395..d9e11760a7 100644 --- a/examples/natmod/ure/ure.c +++ b/examples/natmod/ure/ure.c @@ -32,8 +32,8 @@ void *memmove(void *dest, const void *src, size_t n) { return mp_fun_table.memmove_(dest, src, n); } -mp_obj_type_t match_type; -mp_obj_type_t re_type; +mp_obj_full_type_t match_type; +mp_obj_full_type_t re_type; #include "extmod/modure.c" diff --git a/examples/natmod/uzlib/uzlib.c b/examples/natmod/uzlib/uzlib.c index 99b3691761..24ab15d6f1 100644 --- a/examples/natmod/uzlib/uzlib.c +++ b/examples/natmod/uzlib/uzlib.c @@ -8,7 +8,7 @@ void *memset(void *s, int c, size_t n) { } #endif -mp_obj_type_t decompio_type; +mp_obj_full_type_t decompio_type; #include "extmod/moduzlib.c" diff --git a/extmod/modbtree.c b/extmod/modbtree.c index 15cb634163..60c6885e6b 100644 --- a/extmod/modbtree.c +++ b/extmod/modbtree.c @@ -67,7 +67,7 @@ void __dbpanic(DB *db) { } STATIC mp_obj_btree_t *btree_new(DB *db, mp_obj_t stream) { - mp_obj_btree_t *o = mp_obj_malloc(mp_obj_btree_t, &btree_type); + mp_obj_btree_t *o = mp_obj_malloc(mp_obj_btree_t, (mp_obj_type_t *)&btree_type); o->stream = stream; o->db = db; o->start_key = mp_const_none; diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index f29eab272f..5347be5643 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -841,7 +841,7 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE( // this factory function is provided for backwards compatibility with old FrameBuffer1 class STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args_in) { - mp_obj_framebuf_t *o = mp_obj_malloc(mp_obj_framebuf_t, &mp_type_framebuf); + mp_obj_framebuf_t *o = mp_obj_malloc(mp_obj_framebuf_t, (mp_obj_type_t *)&mp_type_framebuf); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args_in[0], &bufinfo, MP_BUFFER_WRITE); diff --git a/extmod/modnetwork.h b/extmod/modnetwork.h index 3481cc6dcc..55ee4eb4d3 100644 --- a/extmod/modnetwork.h +++ b/extmod/modnetwork.h @@ -62,7 +62,8 @@ mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_o struct _mod_network_socket_obj_t; typedef struct _mod_network_nic_type_t { - mp_obj_type_t base; + // Ensure that this struct is big enough to hold any type size. + mp_obj_full_type_t base; // API for non-socket operations int (*gethostbyname)(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *ip_out); diff --git a/extmod/modure.c b/extmod/modure.c index 4395992405..c0114c14fd 100644 --- a/extmod/modure.c +++ b/extmod/modure.c @@ -198,7 +198,7 @@ STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t STATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) { (void)n_args; mp_obj_re_t *self; - if (mp_obj_is_type(args[0], &re_type)) { + if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) { self = MP_OBJ_TO_PTR(args[0]); } else { self = MP_OBJ_TO_PTR(mod_re_compile(1, args)); @@ -217,7 +217,7 @@ STATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) { return mp_const_none; } - match->base.type = &match_type; + match->base.type = (mp_obj_type_t *)&match_type; match->num_matches = caps_num / 2; // caps_num counts start and end pointers match->str = args[1]; return MP_OBJ_FROM_PTR(match); @@ -282,7 +282,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_split_obj, 2, 3, re_split); STATIC mp_obj_t re_sub_helper(size_t n_args, const mp_obj_t *args) { mp_obj_re_t *self; - if (mp_obj_is_type(args[0], &re_type)) { + if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) { self = MP_OBJ_TO_PTR(args[0]); } else { self = MP_OBJ_TO_PTR(mod_re_compile(1, args)); @@ -305,7 +305,7 @@ STATIC mp_obj_t re_sub_helper(size_t n_args, const mp_obj_t *args) { vstr_t vstr_return; vstr_return.buf = NULL; // We'll init the vstr after the first match mp_obj_match_t *match = mp_local_alloc(sizeof(mp_obj_match_t) + caps_num * sizeof(char *)); - match->base.type = &match_type; + match->base.type = (mp_obj_type_t *)&match_type; match->num_matches = caps_num / 2; // caps_num counts start and end pointers match->str = where; @@ -430,7 +430,7 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { if (size == -1) { goto error; } - mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, char, size, &re_type); + mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, char, size, (mp_obj_type_t *)&re_type); #if MICROPY_PY_URE_DEBUG int flags = 0; if (n_args > 1) { diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c index 0906176d20..806819648d 100644 --- a/extmod/network_ninaw10.c +++ b/extmod/network_ninaw10.c @@ -774,7 +774,7 @@ static const mp_rom_map_elem_t nina_locals_dict_table[] = { static MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table); -STATIC MP_DEFINE_CONST_OBJ_TYPE( +STATIC MP_DEFINE_CONST_OBJ_FULL_TYPE( mod_network_nic_type_nina_base, MP_QSTR_nina, MP_TYPE_FLAG_NONE, diff --git a/extmod/network_wiznet5k.c b/extmod/network_wiznet5k.c index 951a2966c9..1d7318827c 100644 --- a/extmod/network_wiznet5k.c +++ b/extmod/network_wiznet5k.c @@ -1024,7 +1024,7 @@ MP_DEFINE_CONST_OBJ_TYPE( locals_dict, &wiznet5k_locals_dict ); #else // WIZNET5K_PROVIDED_STACK -STATIC MP_DEFINE_CONST_OBJ_TYPE( +STATIC MP_DEFINE_CONST_OBJ_FULL_TYPE( mod_network_nic_type_wiznet5k_base, MP_QSTR_WIZNET5K, MP_TYPE_FLAG_NONE, diff --git a/ports/cc3200/mods/modnetwork.h b/ports/cc3200/mods/modnetwork.h index 6ec90a2bac..c15a6467f2 100644 --- a/ports/cc3200/mods/modnetwork.h +++ b/ports/cc3200/mods/modnetwork.h @@ -36,7 +36,8 @@ DEFINE TYPES ******************************************************************************/ typedef struct _mod_network_nic_type_t { - mp_obj_type_t base; + // Ensure that this struct is big enough to hold any type size. + mp_obj_full_type_t base; } mod_network_nic_type_t; typedef struct _mod_network_socket_base_t { diff --git a/ports/cc3200/mods/modwlan.c b/ports/cc3200/mods/modwlan.c index 1c99f075e9..1e82b07e08 100644 --- a/ports/cc3200/mods/modwlan.c +++ b/ports/cc3200/mods/modwlan.c @@ -1285,7 +1285,7 @@ STATIC const mp_rom_map_elem_t wlan_locals_dict_table[] = { }; STATIC MP_DEFINE_CONST_DICT(wlan_locals_dict, wlan_locals_dict_table); -STATIC MP_DEFINE_CONST_OBJ_TYPE( +STATIC MP_DEFINE_CONST_OBJ_FULL_TYPE( mod_network_nic_type_wlan_base, MP_QSTR_WLAN, MP_TYPE_FLAG_NONE, diff --git a/py/obj.h b/py/obj.h index 4ab7e0dc09..9c0f41dc3d 100644 --- a/py/obj.h +++ b/py/obj.h @@ -562,6 +562,9 @@ typedef mp_int_t (*mp_buffer_fun_t)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); +// This struct will be updated to become a variable sized struct. In order to +// use this as a member, or allocate dynamically, use the mp_obj_empty_type_t +// or mp_obj_full_type_t structs below (which must be kept in sync). struct _mp_obj_type_t { // A type is an object so must start with this entry, which points to mp_type_type. mp_obj_base_t base; @@ -632,6 +635,13 @@ struct _mp_obj_type_t { struct _mp_obj_dict_t *locals_dict; }; +// Non-variable sized versions of mp_obj_type_t to be used as a member +// in other structs or for dynamic allocation. The fields are exactly +// as in mp_obj_type_t, but with a fixed size for the flexible array +// members. +typedef mp_obj_type_t mp_obj_empty_type_t; +typedef mp_obj_type_t mp_obj_full_type_t; + #define MP_TYPE_NULL_MAKE_NEW (NULL) // Implementation of MP_DEFINE_CONST_OBJ_TYPE for each number of arguments. @@ -657,14 +667,15 @@ struct _mp_obj_type_t { // of the 30th argument (30 is 13*2 + 4). #define MP_DEFINE_CONST_OBJ_TYPE_NARGS(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, N, ...) MP_DEFINE_CONST_OBJ_TYPE_NARGS_##N -// This macro is used to define a object type in ROM. +// These macros are used to define a object type in ROM. // Invoke as MP_DEFINE_CONST_OBJ_TYPE(_typename, _name, _flags, _make_new [, slot, func]*) -// It uses the number of arguments to select which MP_DEFINE_CONST_OBJ_TYPE_* +// They use the number of arguments to select which MP_DEFINE_CONST_OBJ_TYPE_* // macro to use based on the number of arguments. It works by shifting the // numeric values 12, 11, ... 0 by the number of arguments, such that the // 30th argument ends up being the number to use. The _INV values are // placeholders because the slot arguments come in pairs. #define MP_DEFINE_CONST_OBJ_TYPE(...) MP_DEFINE_CONST_OBJ_TYPE_EXPAND(MP_DEFINE_CONST_OBJ_TYPE_NARGS(__VA_ARGS__, _INV, 12, _INV, 11, _INV, 10, _INV, 9, _INV, 8, _INV, 7, _INV, 6, _INV, 5, _INV, 4, _INV, 3, _INV, 2, _INV, 1, _INV, 0)(mp_obj_type_t, __VA_ARGS__)) +#define MP_DEFINE_CONST_OBJ_FULL_TYPE(...) MP_DEFINE_CONST_OBJ_TYPE_EXPAND(MP_DEFINE_CONST_OBJ_TYPE_NARGS(__VA_ARGS__, _INV, 12, _INV, 11, _INV, 10, _INV, 9, _INV, 8, _INV, 7, _INV, 6, _INV, 5, _INV, 4, _INV, 3, _INV, 2, _INV, 1, _INV, 0)(mp_obj_full_type_t, __VA_ARGS__)) // Constant types, globally accessible extern const mp_obj_type_t mp_type_type; diff --git a/py/objnamedtuple.h b/py/objnamedtuple.h index d32af35afe..9f23351d5a 100644 --- a/py/objnamedtuple.h +++ b/py/objnamedtuple.h @@ -29,7 +29,10 @@ #include "py/objtuple.h" typedef struct _mp_obj_namedtuple_type_t { - mp_obj_type_t base; + // Must use the full-size version to avoid this being a variable sized member. + // This means that named tuples use slightly more RAM than necessary, but + // no worse than if we didn't have slots/split representation. + mp_obj_full_type_t base; size_t n_fields; qstr fields[]; } mp_obj_namedtuple_type_t; diff --git a/py/objtype.c b/py/objtype.c index 77fe8e22e3..cc5a5e5802 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -1148,7 +1148,10 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) #endif } - mp_obj_type_t *o = m_new0(mp_obj_type_t, 1); + // Allocate a full-sized mp_obj_full_type_t instance (i.e. all slots / extended fields). + // Given that Python types use almost all the slots anyway, this doesn't cost anything + // extra. + mp_obj_type_t *o = (mp_obj_type_t *)m_new0(mp_obj_full_type_t, 1); o->base.type = &mp_type_type; o->flags = base_flags; o->name = name;