gh-101758: Clean Up Uses of Import State (gh-101919)

This change is almost entirely moving code around and hiding import state behind internal API.  We introduce no changes to behavior, nor to non-internal API.  (Since there was already going to be a lot of churn, I took this as an opportunity to re-organize import.c into topically-grouped sections of code.)  The motivation is to simplify a number of upcoming changes.

Specific changes:

* move existing import-related code to import.c, wherever possible
* add internal API for interacting with import state (both global and per-interpreter)
* use only API outside of import.c (to limit churn there when changing the location, etc.)
* consolidate the import-related state of PyInterpreterState into a single struct field (this changes layout slightly)
* add macros for import state in import.c (to simplify changing the location)
* group code in import.c into sections
*remove _PyState_AddModule()

https://github.com/python/cpython/issues/101758
This commit is contained in:
Eric Snow 2023-02-15 15:32:31 -07:00 committed by GitHub
parent c1ce0d178f
commit b2fc549278
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 1496 additions and 1092 deletions

View file

@ -772,11 +772,13 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
Py_CLEAR(interp->codec_search_path);
Py_CLEAR(interp->codec_search_cache);
Py_CLEAR(interp->codec_error_registry);
Py_CLEAR(interp->modules);
Py_CLEAR(interp->modules_by_index);
assert(interp->imports.modules == NULL);
assert(interp->imports.modules_by_index == NULL);
assert(interp->imports.importlib == NULL);
assert(interp->imports.import_func == NULL);
Py_CLEAR(interp->builtins_copy);
Py_CLEAR(interp->importlib);
Py_CLEAR(interp->import_func);
Py_CLEAR(interp->dict);
#ifdef HAVE_FORK
Py_CLEAR(interp->before_forkers);
@ -836,6 +838,7 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
// garbage. It can be different than the current Python thread state
// of 'interp'.
PyThreadState *current_tstate = current_fast_get(interp->runtime);
_PyImport_ClearCore(interp);
interpreter_clear(interp, current_tstate);
}
@ -843,6 +846,7 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
void
_PyInterpreterState_Clear(PyThreadState *tstate)
{
_PyImport_ClearCore(tstate->interp);
interpreter_clear(tstate->interp, tstate);
}
@ -945,36 +949,6 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
#endif
// Used by finalize_modules()
void
_PyInterpreterState_ClearModules(PyInterpreterState *interp)
{
if (!interp->modules_by_index) {
return;
}
Py_ssize_t i;
for (i = 0; i < PyList_GET_SIZE(interp->modules_by_index); i++) {
PyObject *m = PyList_GET_ITEM(interp->modules_by_index, i);
if (PyModule_Check(m)) {
/* cleanup the saved copy of module dicts */
PyModuleDef *md = PyModule_GetDef(m);
if (md) {
Py_CLEAR(md->m_base.m_copy);
}
}
}
/* Setting modules_by_index to NULL could be dangerous, so we
clear the list instead. */
if (PyList_SetSlice(interp->modules_by_index,
0, PyList_GET_SIZE(interp->modules_by_index),
NULL)) {
PyErr_WriteUnraisable(interp->modules_by_index);
}
}
//----------
// accessors
//----------
@ -1058,11 +1032,12 @@ _PyInterpreterState_RequireIDRef(PyInterpreterState *interp, int required)
PyObject *
_PyInterpreterState_GetMainModule(PyInterpreterState *interp)
{
if (interp->modules == NULL) {
PyObject *modules = _PyImport_GetModules(interp);
if (modules == NULL) {
PyErr_SetString(PyExc_RuntimeError, "interpreter not initialized");
return NULL;
}
return PyMapping_GetItemString(interp->modules, "__main__");
return PyMapping_GetItemString(modules, "__main__");
}
PyObject *
@ -1922,110 +1897,6 @@ done:
}
/****************/
/* module state */
/****************/
PyObject*
PyState_FindModule(PyModuleDef* module)
{
Py_ssize_t index = module->m_base.m_index;
PyInterpreterState *state = _PyInterpreterState_GET();
PyObject *res;
if (module->m_slots) {
return NULL;
}
if (index == 0)
return NULL;
if (state->modules_by_index == NULL)
return NULL;
if (index >= PyList_GET_SIZE(state->modules_by_index))
return NULL;
res = PyList_GET_ITEM(state->modules_by_index, index);
return res==Py_None ? NULL : res;
}
int
_PyState_AddModule(PyThreadState *tstate, PyObject* module, PyModuleDef* def)
{
if (!def) {
assert(_PyErr_Occurred(tstate));
return -1;
}
if (def->m_slots) {
_PyErr_SetString(tstate,
PyExc_SystemError,
"PyState_AddModule called on module with slots");
return -1;
}
PyInterpreterState *interp = tstate->interp;
if (!interp->modules_by_index) {
interp->modules_by_index = PyList_New(0);
if (!interp->modules_by_index) {
return -1;
}
}
while (PyList_GET_SIZE(interp->modules_by_index) <= def->m_base.m_index) {
if (PyList_Append(interp->modules_by_index, Py_None) < 0) {
return -1;
}
}
return PyList_SetItem(interp->modules_by_index,
def->m_base.m_index, Py_NewRef(module));
}
int
PyState_AddModule(PyObject* module, PyModuleDef* def)
{
if (!def) {
Py_FatalError("module definition is NULL");
return -1;
}
PyThreadState *tstate = current_fast_get(&_PyRuntime);
PyInterpreterState *interp = tstate->interp;
Py_ssize_t index = def->m_base.m_index;
if (interp->modules_by_index &&
index < PyList_GET_SIZE(interp->modules_by_index) &&
module == PyList_GET_ITEM(interp->modules_by_index, index))
{
_Py_FatalErrorFormat(__func__, "module %p already added", module);
return -1;
}
return _PyState_AddModule(tstate, module, def);
}
int
PyState_RemoveModule(PyModuleDef* def)
{
PyThreadState *tstate = current_fast_get(&_PyRuntime);
PyInterpreterState *interp = tstate->interp;
if (def->m_slots) {
_PyErr_SetString(tstate,
PyExc_SystemError,
"PyState_RemoveModule called on module with slots");
return -1;
}
Py_ssize_t index = def->m_base.m_index;
if (index == 0) {
Py_FatalError("invalid module index");
}
if (interp->modules_by_index == NULL) {
Py_FatalError("Interpreters module-list not accessible.");
}
if (index > PyList_GET_SIZE(interp->modules_by_index)) {
Py_FatalError("Module index out of bounds.");
}
return PyList_SetItem(interp->modules_by_index, index, Py_NewRef(Py_None));
}
/***********************************/
/* Python "auto thread state" API. */
/***********************************/