diff --git a/py/mpconfig.h b/py/mpconfig.h index 292fafb52e..afef744ab5 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -845,7 +845,9 @@ typedef double mp_float_t; #define MICROPY_MODULE_ATTR_DELEGATION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif -// Whether to call __init__ when importing builtin modules for the first time +// Whether to call __init__ when importing builtin modules for the first time. +// Modules using this need to handle the possibility that __init__ might be +// called multiple times. #ifndef MICROPY_MODULE_BUILTIN_INIT #define MICROPY_MODULE_BUILTIN_INIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif diff --git a/py/objmodule.c b/py/objmodule.c index 6f061a9408..7326fbe2d1 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -40,10 +40,6 @@ #include "genhdr/moduledefs.h" #endif -#if MICROPY_MODULE_BUILTIN_INIT -STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj); -#endif - STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); @@ -176,9 +172,8 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table); -// Attempts to find (and initialise) a builtin, otherwise returns MP_OBJ_NULL. -// This must only be called after first checking the loaded modules, -// otherwise the module will be re-initialised. +// Attempts to find (and initialise) a builtin, otherwise returns +// MP_OBJ_NULL. mp_obj_t mp_module_get_builtin(qstr module_name) { mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); if (!elem) { @@ -186,34 +181,19 @@ mp_obj_t mp_module_get_builtin(qstr module_name) { } #if MICROPY_MODULE_BUILTIN_INIT - // If found, it's a newly loaded built-in, so init it. - mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value); + // If found, it's a newly loaded built-in, so init it. This can run + // multiple times, so the module must ensure that it handles being + // initialised multiple times. + mp_obj_t dest[2]; + mp_load_method_maybe(elem->value, MP_QSTR___init__, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, dest); + } #endif return elem->value; } -#if MICROPY_MODULE_BUILTIN_INIT -STATIC void mp_module_register(mp_obj_t module_name, mp_obj_t module) { - mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; - mp_map_lookup(mp_loaded_modules_map, module_name, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; -} - -STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj) { - // Look for __init__ and call it if it exists - mp_obj_t dest[2]; - mp_load_method_maybe(module_obj, MP_QSTR___init__, dest); - if (dest[0] != MP_OBJ_NULL) { - mp_call_method_n_kw(0, 0, dest); - // Register module so __init__ is not called again. - // If a module can be referenced by more than one name (eg due to weak links) - // then __init__ will still be called for each distinct import, and it's then - // up to the particular module to make sure it's __init__ code only runs once. - mp_module_register(module_name, module_obj); - } -} -#endif - void mp_module_generic_attr(qstr attr, mp_obj_t *dest, const uint16_t *keys, mp_obj_t *values) { for (size_t i = 0; keys[i] != MP_QSTRnull; ++i) { if (attr == keys[i]) {