Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b6098ef

Browse files
Drop m_init and m_copy from PyModuleDef_Base.
1 parent efa17fc commit b6098ef

File tree

2 files changed

+49
-55
lines changed

2 files changed

+49
-55
lines changed

Include/moduleobject.h

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,30 +38,21 @@ PyAPI_DATA(PyTypeObject) PyModuleDef_Type;
3838

3939
typedef struct PyModuleDef_Base {
4040
PyObject_HEAD
41-
/* The function used to re-initialize the module.
42-
This is only set for legacy (single-phase init) extension modules
43-
and only used for those that support multiple initializations
44-
(m_size >= 0).
45-
It is set by _PyImport_LoadDynamicModuleWithSpec()
46-
and _imp.create_builtin(). */
47-
PyObject* (*m_init)(void);
41+
/* We keep the following fields, at the given size, for API compatibility. */
42+
Py_uintptr_t m_cache_has_m_init;
43+
Py_uintptr_t m_cache_has_m_dict;
4844
/* The module's index into its interpreter's modules_by_index cache.
4945
This is set for all extension modules but only used for legacy ones.
5046
(See PyInterpreterState.modules_by_index for more info.)
5147
It is set by PyModuleDef_Init(). */
5248
Py_ssize_t m_index;
53-
/* A copy of the module's __dict__ after the first time it was loaded.
54-
This is only set/used for legacy modules that do not support
55-
multiple initializations.
56-
It is set by fix_up_extension() in import.c. */
57-
PyObject* m_copy;
5849
} PyModuleDef_Base;
5950

6051
#define PyModuleDef_HEAD_INIT { \
6152
PyObject_HEAD_INIT(_Py_NULL) \
62-
_Py_NULL, /* m_init */ \
63-
0, /* m_index */ \
64-
_Py_NULL, /* m_copy */ \
53+
0, /* m_cache_has_m_init */ \
54+
0, /* m_cache_has_m_dict */ \
55+
0, /* m_index */ \
6556
}
6657

6758
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000

Python/import.c

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -580,19 +580,8 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
580580
return;
581581
}
582582

583-
Py_ssize_t i;
584-
for (i = 0; i < PyList_GET_SIZE(MODULES_BY_INDEX(interp)); i++) {
585-
PyObject *m = PyList_GET_ITEM(MODULES_BY_INDEX(interp), i);
586-
if (PyModule_Check(m)) {
587-
/* cleanup the saved copy of module dicts */
588-
PyModuleDef *md = PyModule_GetDef(m);
589-
if (md) {
590-
// XXX Do this more carefully. The dict might be owned
591-
// by another interpreter.
592-
Py_CLEAR(md->m_base.m_copy);
593-
}
594-
}
595-
}
583+
/* We clear out the cached module defs and copied module dicts
584+
* in _PyImport_Fini(). */
596585

597586
/* Setting modules_by_index to NULL could be dangerous, so we
598587
clear the list instead. */
@@ -652,7 +641,7 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
652641
O. import_run_extension(): set __file__
653642
P. import_run_extension() -> update_global_state_for_extension()
654643
Q. update_global_state_for_extension():
655-
copy __dict__ into def->m_base.m_copy
644+
copy __dict__ into the cached m_dict
656645
R. update_global_state_for_extension():
657646
add it to _PyRuntime.imports.extensions
658647
S. import_run_extension() -> finish_singlephase_extension()
@@ -672,7 +661,7 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
672661
F. else:
673662
1. import_add_module() -> PyModule_NewObject()
674663
2. import_add_module(): set it on sys.modules
675-
G. reload_singlephase_extension(): copy the "m_copy" dict into __dict__
664+
G. reload_singlephase_extension(): copy the "m_dict" dict into __dict__
676665
H. reload_singlephase_extension(): add to modules_by_index
677666
678667
(10). (every time):
@@ -854,19 +843,19 @@ We support a number of kinds of single-phase init builtin/extension modules:
854843
855844
* "basic"
856845
* no module state (PyModuleDef.m_size == -1)
857-
* does not support repeated init (we use PyModuleDef.m_base.m_copy)
846+
* does not support repeated init (we use the cached m_dict)
858847
* may have process-global state
859848
* the module's def is cached in _PyRuntime.imports.extensions,
860849
by (name, filename)
861850
* "reinit"
862851
* no module state (PyModuleDef.m_size == 0)
863-
* supports repeated init (m_copy is never used)
852+
* supports repeated init (m_dict is never used)
864853
* should not have any process-global state
865854
* its def is never cached in _PyRuntime.imports.extensions
866855
(except, currently, under the main interpreter, for some reason)
867856
* "with state" (almost the same as reinit)
868857
* has module state (PyModuleDef.m_size > 0)
869-
* supports repeated init (m_copy is never used)
858+
* supports repeated init (m_dict is never used)
870859
* should not have any process-global state
871860
* its def is never cached in _PyRuntime.imports.extensions
872861
(except, currently, under the main interpreter, for some reason)
@@ -892,7 +881,7 @@ notable weirdness happens:
892881
* (non-basic-only) its init func is used when re-loading any of them
893882
(via the def's m_init)
894883
* (basic-only) the copy of its __dict__ is used when re-loading any of them
895-
(via the def's m_copy)
884+
(via the def's cached m_dict)
896885
897886
However, the following happens as expected:
898887
@@ -905,7 +894,7 @@ However, the following happens as expected:
905894
For "basic" modules there are other quirks:
906895
907896
* (whether sharing a def or not) when loaded the first time,
908-
m_copy is set before _init_module_attrs() is called
897+
m_dict is set before _init_module_attrs() is called
909898
in importlib._bootstrap.module_from_spec(),
910899
so when the module is re-loaded, the previous value
911900
for __wpec__ (and others) is reset, possibly unexpectedly.
@@ -948,7 +937,7 @@ typedef PyDictObject *cached_m_dict_t;
948937
struct extensions_cache_value {
949938
PyModuleDef *def;
950939

951-
/* m_init and m_copy were formerly part of PyModuleDef_Base. */
940+
/* m_init and m_dict were formerly part of PyModuleDef_Base. */
952941

953942
/* The function used to re-initialize the module.
954943
This is only set for legacy (single-phase init) extension modules
@@ -1008,7 +997,7 @@ set_cached_m_dict(struct extensions_cache_value *value, PyObject *m_dict)
1008997
* isolated interpreter, but there are ways around that.
1009998
* Hence, heere be dragons! Ideally we would instead do
1010999
* something like make a read-only, immortal copy of the
1011-
* dict using PyMem_RawMalloc() and store *that* in m_copy.
1000+
* dict using PyMem_RawMalloc() and store *that* in m_dict.
10121001
* Then we'd need to make sure to clear that when the
10131002
* runtime is finalized, rather than in
10141003
* PyImport_ClearModulesByIndex(). */
@@ -1051,7 +1040,7 @@ update_extensions_cache_value(struct extensions_cache_value *value,
10511040
/* We expect the same symbol to be used and the shared object file
10521041
* to have remained loaded, so it must be the same pointer. */
10531042
assert(value->m_init == NULL || value->m_init == m_init);
1054-
/* For now we don't worry about comparing value->m_copy. */
1043+
/* For now we don't worry about comparing value->m_dict. */
10551044
assert(value->m_dict == NULL || m_dict != NULL);
10561045

10571046
/* We assume that all module defs are statically allocated
@@ -1067,6 +1056,13 @@ update_extensions_cache_value(struct extensions_cache_value *value,
10671056
return -1;
10681057
}
10691058

1059+
if (m_init != NULL) {
1060+
def->m_base.m_cache_has_m_init = 1;
1061+
}
1062+
if (temp.m_dict != NULL) {
1063+
def->m_base.m_cache_has_m_dict = 1;
1064+
}
1065+
10701066
*value = temp;
10711067
return 0;
10721068
}
@@ -1396,7 +1392,7 @@ _get_extension_kind(PyModuleDef *def, bool check_size)
13961392
enum _Py_ext_module_kind kind;
13971393
if (def == NULL) {
13981394
/* It must be a module created by reload_singlephase_extension()
1399-
* from m_copy. Ideally we'd do away with this case. */
1395+
* from m_dict. Ideally we'd do away with this case. */
14001396
kind = _Py_ext_module_kind_SINGLEPHASE;
14011397
}
14021398
else if (def->m_slots != NULL) {
@@ -1405,7 +1401,10 @@ _get_extension_kind(PyModuleDef *def, bool check_size)
14051401
else if (check_size && def->m_size == -1) {
14061402
kind = _Py_ext_module_kind_SINGLEPHASE;
14071403
}
1408-
else if (def->m_base.m_init != NULL) {
1404+
else if (def->m_base.m_cache_has_m_init) {
1405+
kind = _Py_ext_module_kind_SINGLEPHASE;
1406+
}
1407+
else if (def->m_base.m_cache_has_m_dict) {
14091408
kind = _Py_ext_module_kind_SINGLEPHASE;
14101409
}
14111410
else {
@@ -1451,8 +1450,9 @@ update_global_state_for_extension(PyThreadState *tstate,
14511450
PyModInitFunction m_init = NULL;
14521451
PyObject *m_dict = NULL;
14531452

1454-
assert(def->m_base.m_init == NULL);
1455-
assert(def->m_base.m_copy == NULL);
1453+
/* It shouldn't have been set yet. */
1454+
assert(!def->m_base.m_cache_has_m_init);
1455+
assert(!def->m_base.m_cache_has_m_dict);
14561456

14571457
/* Set up for _extensions_cache_set(). */
14581458
if (singlephase != NULL) {
@@ -1473,7 +1473,7 @@ update_global_state_for_extension(PyThreadState *tstate,
14731473
else {
14741474
assert(singlephase->m_dict != NULL
14751475
&& PyDict_Check(singlephase->m_dict));
1476-
// gh-88216: Extensions and def->m_base.m_copy can be updated
1476+
// gh-88216: Extensions and the cached m_dict can be updated
14771477
// when the extension module doesn't support sub-interpreters.
14781478
assert(def->m_size == -1);
14791479
assert(!is_core_module(tstate->interp, name, path));
@@ -1496,6 +1496,8 @@ update_global_state_for_extension(PyThreadState *tstate,
14961496
// mark the module as not loadable.
14971497
return -1;
14981498
}
1499+
assert(def->m_base.m_cache_has_m_init
1500+
|| def->m_base.m_cache_has_m_dict);
14991501
}
15001502

15011503
return 0;
@@ -1547,14 +1549,15 @@ reload_singlephase_extension(PyThreadState *tstate,
15471549
if (def->m_size == -1) {
15481550
/* Module does not support repeated initialization */
15491551
assert(cached->m_init == NULL);
1550-
assert(def->m_base.m_init == NULL);
1552+
assert(!def->m_base.m_cache_has_m_init);
1553+
assert(def->m_base.m_cache_has_m_dict);
15511554
// XXX Copying the cached dict may break interpreter isolation.
15521555
// We could solve this by temporarily acquiring the original
15531556
// interpreter's GIL.
15541557
PyObject *m_copy = get_cached_m_dict(cached);
15551558
if (m_copy == NULL) {
15561559
/* It might be a core module (e.g. sys & builtins),
1557-
for which we don't set m_copy. */
1560+
for which we don't cache m_dict. */
15581561
m_copy = get_core_module_dict(
15591562
tstate->interp, info->name, info->path);
15601563
if (m_copy == NULL) {
@@ -1589,7 +1592,8 @@ reload_singlephase_extension(PyThreadState *tstate,
15891592
}
15901593
else {
15911594
assert(cached->m_dict == NULL);
1592-
assert(def->m_base.m_copy == NULL);
1595+
assert(def->m_base.m_cache_has_m_init);
1596+
assert(!def->m_base.m_cache_has_m_dict);
15931597
PyModInitFunction p0 = cached->m_init;
15941598
if (p0 == NULL) {
15951599
assert(!PyErr_Occurred());
@@ -1714,18 +1718,16 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
17141718

17151719
/* Update global import state. */
17161720
struct singlephase_global_update singlephase = {0};
1717-
// gh-88216: Extensions and def->m_base.m_copy can be updated
1721+
// gh-88216: Extensions and def->m_base.m_dict can be updated
17181722
// when the extension module doesn't support sub-interpreters.
17191723
if (def->m_size == -1) {
1720-
/* We will reload from m_copy. */
1721-
assert(def->m_base.m_init == NULL);
1724+
/* We will reload from m_dict. */
17221725
singlephase.m_dict = PyModule_GetDict(mod);
17231726
assert(singlephase.m_dict != NULL);
17241727
}
17251728
else {
17261729
/* We will reload via the init function. */
17271730
assert(def->m_size >= 0);
1728-
assert(def->m_base.m_copy == NULL);
17291731
singlephase.m_init = p0;
17301732
}
17311733
if (update_global_state_for_extension(
@@ -1765,8 +1767,8 @@ clear_singlephase_extension(PyInterpreterState *interp,
17651767
PyModuleDef *def = value->def;
17661768

17671769
/* Clear data set when the module was initially loaded. */
1768-
def->m_base.m_init = NULL;
1769-
Py_CLEAR(def->m_base.m_copy);
1770+
def->m_base.m_cache_has_m_init = 0;
1771+
def->m_base.m_cache_has_m_dict = 0;
17701772
// We leave m_index alone since there's no reason to reset it.
17711773

17721774
/* Clear the PyState_*Module() cache entry. */
@@ -1808,22 +1810,23 @@ _PyImport_FixupBuiltin(PyThreadState *tstate, PyObject *mod, const char *name,
18081810

18091811
/* We only use _PyImport_FixupBuiltin() for the core builtin modules
18101812
* (sys and builtins). These modules are single-phase init with no
1811-
* module state, but we also don't populate def->m_base.m_copy
1813+
* module state, but we also don't populate the cached m_dict
18121814
* for them. */
18131815
assert(is_core_module(tstate->interp, nameobj, nameobj));
18141816
assert(check_singlephase(def));
18151817
assert(def->m_size == -1);
1816-
assert(def->m_base.m_copy == NULL);
18171818

18181819
struct singlephase_global_update singlephase = {
1819-
/* We don't want def->m_base.m_copy populated. */
1820+
/* We don't want the cached m_dict populated. */
18201821
.m_dict=NULL,
18211822
};
18221823
if (update_global_state_for_extension(
18231824
tstate, nameobj, nameobj, def, &singlephase) < 0)
18241825
{
18251826
goto finally;
18261827
}
1828+
assert(!def->m_base.m_cache_has_m_init);
1829+
assert(def->m_base.m_cache_has_m_dict);
18271830

18281831
if (finish_singlephase_extension(tstate, mod, def, nameobj, modules) < 0) {
18291832
goto finally;

0 commit comments

Comments
 (0)