Issue #22557: Now importing already imported modules is up to 2.5 times faster.
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 @@
                                  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 @@
         }
 
         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 @@
 }
 
 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 @@
 }
 
 
-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(parent);
+    PyObject *abs_name;
+    PyObject *package = NULL;
+    PyObject *spec;
+    PyInterpreterState *interp = PyThreadState_GET()->interp;
+    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__);
+
+    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 {
+        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);
+            }
+        }
+    }
+
+    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;
+        }
+    }
+
+    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);
-    _Py_IDENTIFIER(_lock_unlock_module);
     PyObject *abs_name = NULL;
-    PyObject *builtins_import = NULL;
     PyObject *final_mod = NULL;
     PyObject *mod = NULL;
     PyObject *package = NULL;
-    PyObject *spec = NULL;
-    PyObject *globals = NULL;
-    PyObject *fromlist = NULL;
     PyInterpreterState *interp = PyThreadState_GET()->interp;
     int has_from;
 
-    /* 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) {
-            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");
-            goto error;
-        }
-        globals = given_globals;
-        Py_INCREF(globals);
-    }
-
-    if (given_fromlist == NULL) {
-        fromlist = PyList_New(0);
-        if (fromlist == NULL) {
-            goto error;
-        }
-    }
-    else {
-        fromlist = given_fromlist;
-        Py_INCREF(fromlist);
-    }
     if (name == NULL) {
         PyErr_SetString(PyExc_ValueError, "Empty module name");
         goto error;
@@ -1403,170 +1512,28 @@
         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");
+    if (level > 0) {
+        abs_name = resolve_name(name, globals, level);
+        if (abs_name == NULL)
             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;
-        }
     }
     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 @@
             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 @@
             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 @@
                     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 @@
                 }
 
                 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 @@
     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 @@
     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 @@
         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 @@
     Py_CLEAR(interp->builtins);
     Py_CLEAR(interp->builtins_copy);
     Py_CLEAR(interp->importlib);
+    Py_CLEAR(interp->import_func);
 }