From 709e8328d9812a2e02da6fba65a03f9a873d60a2 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 22 Apr 2022 15:32:22 +1000 Subject: [PATCH] py/obj: Introduce mp_obj_malloc macro to allocate, and set object type. This is to replace the following: mp_foo_obj_t *self = m_new_obj(mp_foo_obj_t); self->base.type = &mp_type_foo; with: mp_foo_obj_t *self = mp_obj_malloc(mp_foo_obj_t, &mp_type_foo); Calling the function is less code than inlining setting the type everywhere, adds up to ~100 bytes on PYBV11. It also helps to avoid an easy mistake of forgetting to set the type. Signed-off-by: Jim Mussared --- py/dynruntime.h | 8 ++++++++ py/obj.c | 7 +++++++ py/obj.h | 6 ++++++ 3 files changed, 21 insertions(+) diff --git a/py/dynruntime.h b/py/dynruntime.h index b9dca60d13..32ca708b95 100644 --- a/py/dynruntime.h +++ b/py/dynruntime.h @@ -126,6 +126,8 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) { #define mp_obj_get_array(o, len, items) (mp_obj_get_array_dyn((o), (len), (items))) #define mp_obj_list_append(list, item) (mp_fun_table.list_append((list), (item))) +#define mp_obj_malloc_helper(n, t) (mp_obj_malloc_helper_dyn(n, t)) + static inline mp_obj_t mp_obj_new_str_of_type_dyn(const mp_obj_type_t *type, const byte *data, size_t len) { if (type == &mp_type_str) { return mp_obj_new_str((const char *)data, len); @@ -163,6 +165,12 @@ static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) { return mp_fun_table.call_function_n_kw(mp_fun_table.load_name(MP_QSTR_len), 1, &o); } +static inline void *mp_obj_malloc_helper_dyn(size_t num_bytes, const mp_obj_type_t *type) { + mp_obj_base_t *base = (mp_obj_base_t *)m_malloc(num_bytes); + base->type = type; + return base; +} + /******************************************************************************/ // General runtime functions diff --git a/py/obj.c b/py/obj.c index 5255e96553..024de3c96c 100644 --- a/py/obj.c +++ b/py/obj.c @@ -37,6 +37,13 @@ #include "py/stackctrl.h" #include "py/stream.h" // for mp_obj_print +// Allocates an object and also sets type, for mp_obj_malloc{,_var} macros. +void *mp_obj_malloc_helper(size_t num_bytes, const mp_obj_type_t *type) { + mp_obj_base_t *base = (mp_obj_base_t *)m_malloc(num_bytes); + base->type = type; + return base; +} + const mp_obj_type_t *MICROPY_WRAP_MP_OBJ_GET_TYPE(mp_obj_get_type)(mp_const_obj_t o_in) { #if MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A diff --git a/py/obj.h b/py/obj.h index 08a35ee6f8..ead3ce8649 100644 --- a/py/obj.h +++ b/py/obj.h @@ -732,6 +732,12 @@ extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; // General API for objects +// Helper versions of m_new_obj when you need to immediately set base.type. +// Implementing this as a call rather than inline saves 8 bytes per usage. +#define mp_obj_malloc(struct_type, obj_type) ((struct_type *)mp_obj_malloc_helper(sizeof(struct_type), obj_type)) +#define mp_obj_malloc_var(struct_type, var_type, var_num, obj_type) ((struct_type *)mp_obj_malloc_helper(sizeof(struct_type) + sizeof(var_type) * (var_num), obj_type)) +void *mp_obj_malloc_helper(size_t num_bytes, const mp_obj_type_t *type); + // These macros are derived from more primitive ones and are used to // check for more specific object types. // Note: these are kept as macros because inline functions sometimes use much