summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/pystate.h1
-rw-r--r--Misc/NEWS2
-rw-r--r--Python/ceval.c79
-rw-r--r--Python/import.c395
-rw-r--r--Python/pylifecycle.c5
-rw-r--r--Python/pystate.c2
6 files changed, 238 insertions, 246 deletions
diff --git a/Include/pystate.h b/Include/pystate.h
index d69d4c9..f08618c 100644
--- a/Include/pystate.h
+++ b/Include/pystate.h
@@ -41,6 +41,7 @@ typedef struct _is {
#endif
PyObject *builtins_copy;
+ PyObject *import_func;
} PyInterpreterState;
#endif
diff --git a/Misc/NEWS b/Misc/NEWS
index d265038..cd73ecd 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,8 @@ What's New in Python 3.6.0 alpha 4
Core and Builtins
-----------------
+- Issue #22557: Now importing already imported modules is up to 2.5 times faster.
+
- Issue #17596: Include <wincrypt.h> to help with Min GW building.
- Issue #27507: Add integer overflow check in bytearray.extend(). Patch by
diff --git a/Python/ceval.c b/Python/ceval.c
index 7c664ad..7ca3ad2 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -139,6 +139,7 @@ static int maybe_call_line_trace(Py_tracefunc, PyObject *,
PyThreadState *, PyFrameObject *, int *, int *, int *);
static PyObject * cmp_outcome(int, PyObject *, PyObject *);
+static PyObject * import_name(PyFrameObject *, PyObject *, PyObject *, PyObject *);
static PyObject * import_from(PyObject *, PyObject *);
static int import_all_from(PyObject *, PyObject *);
static void format_exc_check_arg(PyObject *, const char *, PyObject *);
@@ -2808,37 +2809,15 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
TARGET(IMPORT_NAME) {
- _Py_IDENTIFIER(__import__);
PyObject *name = GETITEM(names, oparg);
- PyObject *func = _PyDict_GetItemId(f->f_builtins, &PyId___import__);
- PyObject *from, *level, *args, *res;
- if (func == NULL) {
- PyErr_SetString(PyExc_ImportError,
- "__import__ not found");
- goto error;
- }
- Py_INCREF(func);
- from = POP();
- level = TOP();
- args = PyTuple_Pack(5,
- name,
- f->f_globals,
- f->f_locals == NULL ?
- Py_None : f->f_locals,
- from,
- level);
- Py_DECREF(level);
- Py_DECREF(from);
- if (args == NULL) {
- Py_DECREF(func);
- STACKADJ(-1);
- goto error;
- }
+ PyObject *fromlist = POP();
+ PyObject *level = TOP();
+ PyObject *res;
READ_TIMESTAMP(intr0);
- res = PyEval_CallObject(func, args);
+ res = import_name(f, name, fromlist, level);
+ Py_DECREF(level);
+ Py_DECREF(fromlist);
READ_TIMESTAMP(intr1);
- Py_DECREF(args);
- Py_DECREF(func);
SET_TOP(res);
if (res == NULL)
goto error;
@@ -5159,6 +5138,50 @@ cmp_outcome(int op, PyObject *v, PyObject *w)
}
static PyObject *
+import_name(PyFrameObject *f, PyObject *name, PyObject *fromlist, PyObject *level)
+{
+ _Py_IDENTIFIER(__import__);
+ PyObject *import_func, *args, *res;
+
+ import_func = _PyDict_GetItemId(f->f_builtins, &PyId___import__);
+ if (import_func == NULL) {
+ PyErr_SetString(PyExc_ImportError, "__import__ not found");
+ return NULL;
+ }
+
+ /* Fast path for not overloaded __import__. */
+ if (import_func == PyThreadState_GET()->interp->import_func) {
+ int ilevel = _PyLong_AsInt(level);
+ if (ilevel == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ res = PyImport_ImportModuleLevelObject(
+ name,
+ f->f_globals,
+ f->f_locals == NULL ? Py_None : f->f_locals,
+ fromlist,
+ ilevel);
+ return res;
+ }
+
+ Py_INCREF(import_func);
+ args = PyTuple_Pack(5,
+ name,
+ f->f_globals,
+ f->f_locals == NULL ? Py_None : f->f_locals,
+ fromlist,
+ level);
+ if (args == NULL) {
+ Py_DECREF(import_func);
+ return NULL;
+ }
+ res = PyEval_CallObject(import_func, args);
+ Py_DECREF(args);
+ Py_DECREF(import_func);
+ return res;
+}
+
+static PyObject *
import_from(PyObject *v, PyObject *name)
{
PyObject *x;
diff --git a/Python/import.c b/Python/import.c
index ebad07b..f3aa9d4 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -1336,61 +1336,170 @@ done:
}
-PyObject *
-PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
- PyObject *locals, PyObject *given_fromlist,
- int level)
+static PyObject *
+resolve_name(PyObject *name, PyObject *globals, int level)
{
- _Py_IDENTIFIER(__import__);
_Py_IDENTIFIER(__spec__);
- _Py_IDENTIFIER(_initializing);
_Py_IDENTIFIER(__package__);
_Py_IDENTIFIER(__path__);
_Py_IDENTIFIER(__name__);
- _Py_IDENTIFIER(_find_and_load);
- _Py_IDENTIFIER(_handle_fromlist);
- _Py_IDENTIFIER(_lock_unlock_module);
- PyObject *abs_name = NULL;
- PyObject *builtins_import = NULL;
- PyObject *final_mod = NULL;
- PyObject *mod = NULL;
+ _Py_IDENTIFIER(parent);
+ PyObject *abs_name;
PyObject *package = NULL;
- PyObject *spec = NULL;
- PyObject *globals = NULL;
- PyObject *fromlist = NULL;
+ PyObject *spec;
PyInterpreterState *interp = PyThreadState_GET()->interp;
- int has_from;
+ Py_ssize_t last_dot;
+ PyObject *base;
+ int level_up;
+
+ if (globals == NULL) {
+ PyErr_SetString(PyExc_KeyError, "'__name__' not in globals");
+ goto error;
+ }
+ if (!PyDict_Check(globals)) {
+ PyErr_SetString(PyExc_TypeError, "globals must be a dict");
+ goto error;
+ }
+ package = _PyDict_GetItemId(globals, &PyId___package__);
+ if (package == Py_None) {
+ package = NULL;
+ }
+ spec = _PyDict_GetItemId(globals, &PyId___spec__);
- /* Make sure to use default values so as to not have
- PyObject_CallMethodObjArgs() truncate the parameter list because of a
- NULL argument. */
- if (given_globals == NULL) {
- globals = PyDict_New();
- if (globals == NULL) {
+ if (package != NULL) {
+ Py_INCREF(package);
+ if (!PyUnicode_Check(package)) {
+ PyErr_SetString(PyExc_TypeError, "package must be a string");
+ goto error;
+ }
+ else if (spec != NULL && spec != Py_None) {
+ int equal;
+ PyObject *parent = _PyObject_GetAttrId(spec, &PyId_parent);
+ if (parent == NULL) {
+ goto error;
+ }
+
+ equal = PyObject_RichCompareBool(package, parent, Py_EQ);
+ Py_DECREF(parent);
+ if (equal < 0) {
+ goto error;
+ }
+ else if (equal == 0) {
+ if (PyErr_WarnEx(PyExc_ImportWarning,
+ "__package__ != __spec__.parent", 1) < 0) {
+ goto error;
+ }
+ }
+ }
+ }
+ else if (spec != NULL && spec != Py_None) {
+ package = _PyObject_GetAttrId(spec, &PyId_parent);
+ if (package == NULL) {
+ goto error;
+ }
+ else if (!PyUnicode_Check(package)) {
+ PyErr_SetString(PyExc_TypeError,
+ "__spec__.parent must be a string");
goto error;
}
}
else {
- /* Only have to care what given_globals is if it will be used
- for something. */
- if (level > 0 && !PyDict_Check(given_globals)) {
- PyErr_SetString(PyExc_TypeError, "globals must be a dict");
+ if (PyErr_WarnEx(PyExc_ImportWarning,
+ "can't resolve package from __spec__ or __package__, "
+ "falling back on __name__ and __path__", 1) < 0) {
goto error;
}
- globals = given_globals;
- Py_INCREF(globals);
+
+ package = _PyDict_GetItemId(globals, &PyId___name__);
+ if (package == NULL) {
+ PyErr_SetString(PyExc_KeyError, "'__name__' not in globals");
+ goto error;
+ }
+
+ Py_INCREF(package);
+ if (!PyUnicode_Check(package)) {
+ PyErr_SetString(PyExc_TypeError, "__name__ must be a string");
+ goto error;
+ }
+
+ if (_PyDict_GetItemId(globals, &PyId___path__) == NULL) {
+ Py_ssize_t dot;
+
+ if (PyUnicode_READY(package) < 0) {
+ goto error;
+ }
+
+ dot = PyUnicode_FindChar(package, '.',
+ 0, PyUnicode_GET_LENGTH(package), -1);
+ if (dot == -2) {
+ goto error;
+ }
+
+ if (dot >= 0) {
+ PyObject *substr = PyUnicode_Substring(package, 0, dot);
+ if (substr == NULL) {
+ goto error;
+ }
+ Py_SETREF(package, substr);
+ }
+ }
}
- if (given_fromlist == NULL) {
- fromlist = PyList_New(0);
- if (fromlist == NULL) {
+ last_dot = PyUnicode_GET_LENGTH(package);
+ if (last_dot == 0) {
+ PyErr_SetString(PyExc_ImportError,
+ "attempted relative import with no known parent package");
+ goto error;
+ }
+ else if (PyDict_GetItem(interp->modules, package) == NULL) {
+ PyErr_Format(PyExc_SystemError,
+ "Parent module %R not loaded, cannot perform relative "
+ "import", package);
+ goto error;
+ }
+
+ for (level_up = 1; level_up < level; level_up += 1) {
+ last_dot = PyUnicode_FindChar(package, '.', 0, last_dot, -1);
+ if (last_dot == -2) {
+ goto error;
+ }
+ else if (last_dot == -1) {
+ PyErr_SetString(PyExc_ValueError,
+ "attempted relative import beyond top-level "
+ "package");
goto error;
}
}
- else {
- fromlist = given_fromlist;
- Py_INCREF(fromlist);
+
+ base = PyUnicode_Substring(package, 0, last_dot);
+ Py_DECREF(package);
+ if (base == NULL || PyUnicode_GET_LENGTH(name) == 0) {
+ return base;
}
+
+ abs_name = PyUnicode_FromFormat("%U.%U", base, name);
+ Py_DECREF(base);
+ return abs_name;
+
+ error:
+ Py_XDECREF(package);
+ return NULL;
+}
+
+PyObject *
+PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
+ PyObject *locals, PyObject *fromlist,
+ int level)
+{
+ _Py_IDENTIFIER(_find_and_load);
+ _Py_IDENTIFIER(_handle_fromlist);
+ PyObject *abs_name = NULL;
+ PyObject *final_mod = NULL;
+ PyObject *mod = NULL;
+ PyObject *package = NULL;
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ int has_from;
+
if (name == NULL) {
PyErr_SetString(PyExc_ValueError, "Empty module name");
goto error;
@@ -1403,170 +1512,28 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
PyErr_SetString(PyExc_TypeError, "module name must be a string");
goto error;
}
- else if (PyUnicode_READY(name) < 0) {
+ if (PyUnicode_READY(name) < 0) {
goto error;
}
if (level < 0) {
PyErr_SetString(PyExc_ValueError, "level must be >= 0");
goto error;
}
- else if (level > 0) {
- package = _PyDict_GetItemId(globals, &PyId___package__);
- spec = _PyDict_GetItemId(globals, &PyId___spec__);
-
- if (package != NULL && package != Py_None) {
- Py_INCREF(package);
- if (!PyUnicode_Check(package)) {
- PyErr_SetString(PyExc_TypeError, "package must be a string");
- goto error;
- }
- else if (spec != NULL && spec != Py_None) {
- int equal;
- PyObject *parent = PyObject_GetAttrString(spec, "parent");
- if (parent == NULL) {
- goto error;
- }
-
- equal = PyObject_RichCompareBool(package, parent, Py_EQ);
- Py_DECREF(parent);
- if (equal < 0) {
- goto error;
- }
- else if (equal == 0) {
- if (PyErr_WarnEx(PyExc_ImportWarning,
- "__package__ != __spec__.parent", 1) < 0) {
- goto error;
- }
- }
- }
- }
- else if (spec != NULL && spec != Py_None) {
- package = PyObject_GetAttrString(spec, "parent");
- if (package == NULL) {
- goto error;
- }
- else if (!PyUnicode_Check(package)) {
- PyErr_SetString(PyExc_TypeError,
- "__spec__.parent must be a string");
- goto error;
- }
- }
- else {
- package = NULL;
- if (PyErr_WarnEx(PyExc_ImportWarning,
- "can't resolve package from __spec__ or __package__, "
- "falling back on __name__ and __path__", 1) < 0) {
- goto error;
- }
-
- package = _PyDict_GetItemId(globals, &PyId___name__);
- if (package == NULL) {
- PyErr_SetString(PyExc_KeyError, "'__name__' not in globals");
- goto error;
- }
-
- Py_INCREF(package);
- if (!PyUnicode_Check(package)) {
- PyErr_SetString(PyExc_TypeError, "__name__ must be a string");
- goto error;
- }
- if (_PyDict_GetItemId(globals, &PyId___path__) == NULL) {
- Py_ssize_t dot;
-
- if (PyUnicode_READY(package) < 0) {
- goto error;
- }
-
- dot = PyUnicode_FindChar(package, '.',
- 0, PyUnicode_GET_LENGTH(package), -1);
- if (dot == -2) {
- goto error;
- }
-
- if (dot >= 0) {
- PyObject *substr = PyUnicode_Substring(package, 0, dot);
- if (substr == NULL) {
- goto error;
- }
- Py_SETREF(package, substr);
- }
- }
- }
-
- if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
- PyErr_SetString(PyExc_ImportError,
- "attempted relative import with no known parent package");
- goto error;
- }
- else if (PyDict_GetItem(interp->modules, package) == NULL) {
- PyErr_Format(PyExc_SystemError,
- "Parent module %R not loaded, cannot perform relative "
- "import", package);
+ if (level > 0) {
+ abs_name = resolve_name(name, globals, level);
+ if (abs_name == NULL)
goto error;
- }
}
else { /* level == 0 */
if (PyUnicode_GET_LENGTH(name) == 0) {
PyErr_SetString(PyExc_ValueError, "Empty module name");
goto error;
}
- package = Py_None;
- Py_INCREF(package);
- }
-
- if (level > 0) {
- Py_ssize_t last_dot = PyUnicode_GET_LENGTH(package);
- PyObject *base = NULL;
- int level_up = 1;
-
- for (level_up = 1; level_up < level; level_up += 1) {
- last_dot = PyUnicode_FindChar(package, '.', 0, last_dot, -1);
- if (last_dot == -2) {
- goto error;
- }
- else if (last_dot == -1) {
- PyErr_SetString(PyExc_ValueError,
- "attempted relative import beyond top-level "
- "package");
- goto error;
- }
- }
-
- base = PyUnicode_Substring(package, 0, last_dot);
- if (base == NULL)
- goto error;
-
- if (PyUnicode_GET_LENGTH(name) > 0) {
- abs_name = PyUnicode_FromFormat("%U.%U", base, name);
- Py_DECREF(base);
- if (abs_name == NULL) {
- goto error;
- }
- }
- else {
- abs_name = base;
- }
- }
- else {
abs_name = name;
Py_INCREF(abs_name);
}
-#ifdef WITH_THREAD
- _PyImport_AcquireLock();
-#endif
- /* From this point forward, goto error_with_unlock! */
- /* XXX interp->builtins_copy is NULL in subinterpreter! */
- builtins_import = _PyDict_GetItemId(interp->builtins_copy ?
- interp->builtins_copy :
- interp->builtins, &PyId___import__);
- if (builtins_import == NULL) {
- PyErr_SetString(PyExc_ImportError, "__import__ not found");
- goto error_with_unlock;
- }
- Py_INCREF(builtins_import);
-
mod = PyDict_GetItem(interp->modules, abs_name);
if (mod == Py_None) {
PyObject *msg = PyUnicode_FromFormat("import of %R halted; "
@@ -1576,9 +1543,12 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
Py_DECREF(msg);
}
mod = NULL;
- goto error_with_unlock;
+ goto error;
}
else if (mod != NULL) {
+ _Py_IDENTIFIER(__spec__);
+ _Py_IDENTIFIER(_initializing);
+ _Py_IDENTIFIER(_lock_unlock_module);
PyObject *value = NULL;
PyObject *spec;
int initializing = 0;
@@ -1601,39 +1571,39 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
Py_DECREF(value);
if (initializing == -1)
PyErr_Clear();
- }
- if (initializing > 0) {
- /* _bootstrap._lock_unlock_module() releases the import lock */
- value = _PyObject_CallMethodIdObjArgs(interp->importlib,
- &PyId__lock_unlock_module, abs_name,
- NULL);
- if (value == NULL)
- goto error;
- Py_DECREF(value);
- }
- else {
+ if (initializing > 0) {
#ifdef WITH_THREAD
- if (_PyImport_ReleaseLock() < 0) {
- PyErr_SetString(PyExc_RuntimeError, "not holding the import lock");
- goto error;
- }
+ _PyImport_AcquireLock();
#endif
+ /* _bootstrap._lock_unlock_module() releases the import lock */
+ value = _PyObject_CallMethodIdObjArgs(interp->importlib,
+ &PyId__lock_unlock_module, abs_name,
+ NULL);
+ if (value == NULL)
+ goto error;
+ Py_DECREF(value);
+ }
}
}
else {
+#ifdef WITH_THREAD
+ _PyImport_AcquireLock();
+#endif
/* _bootstrap._find_and_load() releases the import lock */
mod = _PyObject_CallMethodIdObjArgs(interp->importlib,
&PyId__find_and_load, abs_name,
- builtins_import, NULL);
+ interp->import_func, NULL);
if (mod == NULL) {
goto error;
}
}
- /* From now on we don't hold the import lock anymore. */
- has_from = PyObject_IsTrue(fromlist);
- if (has_from < 0)
- goto error;
+ has_from = 0;
+ if (fromlist != NULL && fromlist != Py_None) {
+ has_from = PyObject_IsTrue(fromlist);
+ if (has_from < 0)
+ goto error;
+ }
if (!has_from) {
Py_ssize_t len = PyUnicode_GET_LENGTH(name);
if (level == 0 || len > 0) {
@@ -1657,7 +1627,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
goto error;
}
- final_mod = PyObject_CallFunctionObjArgs(builtins_import, front, NULL);
+ final_mod = PyImport_ImportModuleLevelObject(front, NULL, NULL, NULL, 0);
Py_DECREF(front);
}
else {
@@ -1670,15 +1640,14 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
}
final_mod = PyDict_GetItem(interp->modules, to_return);
+ Py_DECREF(to_return);
if (final_mod == NULL) {
PyErr_Format(PyExc_KeyError,
"%R not in sys.modules as expected",
to_return);
+ goto error;
}
- else {
- Py_INCREF(final_mod);
- }
- Py_DECREF(to_return);
+ Py_INCREF(final_mod);
}
}
else {
@@ -1689,24 +1658,14 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
else {
final_mod = _PyObject_CallMethodIdObjArgs(interp->importlib,
&PyId__handle_fromlist, mod,
- fromlist, builtins_import,
+ fromlist, interp->import_func,
NULL);
}
- goto error;
- error_with_unlock:
-#ifdef WITH_THREAD
- if (_PyImport_ReleaseLock() < 0) {
- PyErr_SetString(PyExc_RuntimeError, "not holding the import lock");
- }
-#endif
error:
Py_XDECREF(abs_name);
- Py_XDECREF(builtins_import);
Py_XDECREF(mod);
Py_XDECREF(package);
- Py_XDECREF(globals);
- Py_XDECREF(fromlist);
if (final_mod == NULL)
remove_importlib_frames();
return final_mod;
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 2d2dcba..dc85551 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -254,6 +254,11 @@ import_init(PyInterpreterState *interp, PyObject *sysmod)
interp->importlib = importlib;
Py_INCREF(interp->importlib);
+ interp->import_func = PyDict_GetItemString(interp->builtins, "__import__");
+ if (interp->import_func == NULL)
+ Py_FatalError("Py_Initialize: __import__ not found");
+ Py_INCREF(interp->import_func);
+
/* Import the _imp module */
impmod = PyInit_imp();
if (impmod == NULL) {
diff --git a/Python/pystate.c b/Python/pystate.c
index ba4dd4c..b1aecec 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -90,6 +90,7 @@ PyInterpreterState_New(void)
interp->codecs_initialized = 0;
interp->fscodec_initialized = 0;
interp->importlib = NULL;
+ interp->import_func = NULL;
#ifdef HAVE_DLOPEN
#if HAVE_DECL_RTLD_NOW
interp->dlopenflags = RTLD_NOW;
@@ -128,6 +129,7 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
Py_CLEAR(interp->builtins);
Py_CLEAR(interp->builtins_copy);
Py_CLEAR(interp->importlib);
+ Py_CLEAR(interp->import_func);
}