bpo-35444: Unify and optimize the helper for getting a builtin object. (GH-11047)

This speeds up pickling of some iterators.

This fixes also error handling in pickling methods when fail to
look up builtin "getattr".
diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c
index 1442653..3926095 100644
--- a/Objects/bytearrayobject.c
+++ b/Objects/bytearrayobject.c
@@ -2358,11 +2358,12 @@
 static PyObject *
 bytearrayiter_reduce(bytesiterobject *it, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     if (it->it_seq != NULL) {
-        return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+        return Py_BuildValue("N(O)n", _PyEval_GetBuiltinId(&PyId_iter),
                              it->it_seq, it->it_index);
     } else {
-        return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
+        return Py_BuildValue("N(())", _PyEval_GetBuiltinId(&PyId_iter));
     }
 }
 
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index e4a4973..adf0cff 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -3089,11 +3089,12 @@
 static PyObject *
 striter_reduce(striterobject *it, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     if (it->it_seq != NULL) {
-        return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+        return Py_BuildValue("N(O)n", _PyEval_GetBuiltinId(&PyId_iter),
                              it->it_seq, it->it_index);
     } else {
-        return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
+        return Py_BuildValue("N(())", _PyEval_GetBuiltinId(&PyId_iter));
     }
 }
 
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 1eed5d3..0d1cf7a 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -78,8 +78,6 @@
 {
     PyObject *self = PyMethod_GET_SELF(im);
     PyObject *func = PyMethod_GET_FUNCTION(im);
-    PyObject *builtins;
-    PyObject *getattr;
     PyObject *funcname;
     _Py_IDENTIFIER(getattr);
 
@@ -87,9 +85,8 @@
     if (funcname == NULL) {
         return NULL;
     }
-    builtins = PyEval_GetBuiltins();
-    getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
-    return Py_BuildValue("O(ON)", getattr, self, funcname);
+    return Py_BuildValue("N(ON)", _PyEval_GetBuiltinId(&PyId_getattr),
+                         self, funcname);
 }
 
 static PyMethodDef method_methods[] = {
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index e129d0c..22546a5 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -452,14 +452,9 @@
 static PyObject *
 descr_reduce(PyDescrObject *descr, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *builtins;
-    PyObject *getattr;
     _Py_IDENTIFIER(getattr);
-
-    builtins = PyEval_GetBuiltins();
-    getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
-    return Py_BuildValue("O(OO)", getattr, PyDescr_TYPE(descr),
-                         PyDescr_NAME(descr));
+    return Py_BuildValue("N(OO)", _PyEval_GetBuiltinId(&PyId_getattr),
+                         PyDescr_TYPE(descr), PyDescr_NAME(descr));
 }
 
 static PyMethodDef descr_methods[] = {
@@ -1087,13 +1082,9 @@
 static PyObject *
 wrapper_reduce(wrapperobject *wp, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *builtins;
-    PyObject *getattr;
     _Py_IDENTIFIER(getattr);
-
-    builtins = PyEval_GetBuiltins();
-    getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
-    return Py_BuildValue("O(OO)", getattr, wp->self, PyDescr_NAME(wp->descr));
+    return Py_BuildValue("N(OO)", _PyEval_GetBuiltinId(&PyId_getattr),
+                         wp->self, PyDescr_NAME(wp->descr));
 }
 
 static PyMethodDef wrapper_methods[] = {
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 72cb4c5..a871636 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -3810,6 +3810,7 @@
 static PyObject *
 dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     /* copy the iterator state */
     dictiterobject tmp = *di;
     Py_XINCREF(tmp.di_dict);
@@ -3819,7 +3820,7 @@
     if (list == NULL) {
         return NULL;
     }
-    return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), list);
+    return Py_BuildValue("N(N)", _PyEval_GetBuiltinId(&PyId_iter), list);
 }
 
 PyTypeObject PyDictRevIterItem_Type = {
diff --git a/Objects/iterobject.c b/Objects/iterobject.c
index ada1bdc..5bee1e2 100644
--- a/Objects/iterobject.c
+++ b/Objects/iterobject.c
@@ -104,11 +104,12 @@
 static PyObject *
 iter_reduce(seqiterobject *it, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     if (it->it_seq != NULL)
-        return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+        return Py_BuildValue("N(O)n", _PyEval_GetBuiltinId(&PyId_iter),
                              it->it_seq, it->it_index);
     else
-        return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
+        return Py_BuildValue("N(())", _PyEval_GetBuiltinId(&PyId_iter));
 }
 
 PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
@@ -243,11 +244,12 @@
 static PyObject *
 calliter_reduce(calliterobject *it, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     if (it->it_callable != NULL && it->it_sentinel != NULL)
-        return Py_BuildValue("N(OO)", _PyObject_GetBuiltin("iter"),
+        return Py_BuildValue("N(OO)", _PyEval_GetBuiltinId(&PyId_iter),
                              it->it_callable, it->it_sentinel);
     else
-        return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
+        return Py_BuildValue("N(())", _PyEval_GetBuiltinId(&PyId_iter));
 }
 
 static PyMethodDef calliter_methods[] = {
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 6da8391..b1f2b59 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -3356,23 +3356,25 @@
 static PyObject *
 listiter_reduce_general(void *_it, int forward)
 {
+    _Py_IDENTIFIER(iter);
+    _Py_IDENTIFIER(reversed);
     PyObject *list;
 
     /* the objects are not the same, index is of different types! */
     if (forward) {
         listiterobject *it = (listiterobject *)_it;
         if (it->it_seq)
-            return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+            return Py_BuildValue("N(O)n", _PyEval_GetBuiltinId(&PyId_iter),
                                  it->it_seq, it->it_index);
     } else {
         listreviterobject *it = (listreviterobject *)_it;
         if (it->it_seq)
-            return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("reversed"),
+            return Py_BuildValue("N(O)n", _PyEval_GetBuiltinId(&PyId_reversed),
                                  it->it_seq, it->it_index);
     }
     /* empty iterator, create an empty list */
     list = PyList_New(0);
     if (list == NULL)
         return NULL;
-    return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), list);
+    return Py_BuildValue("N(N)", _PyEval_GetBuiltinId(&PyId_iter), list);
 }
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 6dec642..9fed3fc 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -104,16 +104,13 @@
 static PyObject *
 meth_reduce(PyCFunctionObject *m, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *builtins;
-    PyObject *getattr;
     _Py_IDENTIFIER(getattr);
 
     if (m->m_self == NULL || PyModule_Check(m->m_self))
         return PyUnicode_FromString(m->m_ml->ml_name);
 
-    builtins = PyEval_GetBuiltins();
-    getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
-    return Py_BuildValue("O(Os)", getattr, m->m_self, m->m_ml->ml_name);
+    return Py_BuildValue("N(Os)", _PyEval_GetBuiltinId(&PyId_getattr),
+                         m->m_self, m->m_ml->ml_name);
 }
 
 static PyMethodDef meth_methods[] = {
diff --git a/Objects/object.c b/Objects/object.c
index c2d78aa..993342e 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1080,23 +1080,6 @@
     return obj;
 }
 
-/* Convenience function to get a builtin from its name */
-PyObject *
-_PyObject_GetBuiltin(const char *name)
-{
-    PyObject *mod_name, *mod, *attr;
-
-    mod_name = _PyUnicode_FromId(&PyId_builtins);   /* borrowed */
-    if (mod_name == NULL)
-        return NULL;
-    mod = PyImport_Import(mod_name);
-    if (mod == NULL)
-        return NULL;
-    attr = PyObject_GetAttrString(mod, name);
-    Py_DECREF(mod);
-    return attr;
-}
-
 /* Helper used when the __next__ method is removed from a type:
    tp_iternext is never NULL and can be safely called without checking
    on every iteration.
diff --git a/Objects/odictobject.c b/Objects/odictobject.c
index 689062c..767eb5f 100644
--- a/Objects/odictobject.c
+++ b/Objects/odictobject.c
@@ -1806,6 +1806,7 @@
 static PyObject *
 odictiter_reduce(odictiterobject *di, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     /* copy the iterator state */
     odictiterobject tmp = *di;
     Py_XINCREF(tmp.di_odict);
@@ -1818,7 +1819,7 @@
     if (list == NULL) {
         return NULL;
     }
-    return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), list);
+    return Py_BuildValue("N(N)", _PyEval_GetBuiltinId(&PyId_iter), list);
 }
 
 static PyMethodDef odictiter_methods[] = {
diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c
index e7b47bd..4b8e5ed 100644
--- a/Objects/rangeobject.c
+++ b/Objects/rangeobject.c
@@ -742,6 +742,7 @@
 static PyObject *
 rangeiter_reduce(rangeiterobject *r, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     PyObject *start=NULL, *stop=NULL, *step=NULL;
     PyObject *range;
 
@@ -760,7 +761,8 @@
     if (range == NULL)
         goto err;
     /* return the result */
-    return Py_BuildValue("N(N)i", _PyObject_GetBuiltin("iter"), range, r->index);
+    return Py_BuildValue("N(N)i", _PyEval_GetBuiltinId(&PyId_iter),
+                         range, r->index);
 err:
     Py_XDECREF(start);
     Py_XDECREF(stop);
@@ -898,6 +900,7 @@
 static PyObject *
 longrangeiter_reduce(longrangeiterobject *r, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     PyObject *product, *stop=NULL;
     PyObject *range;
 
@@ -921,7 +924,8 @@
     }
 
     /* return the result */
-    return Py_BuildValue("N(N)O", _PyObject_GetBuiltin("iter"), range, r->index);
+    return Py_BuildValue("N(N)O", _PyEval_GetBuiltinId(&PyId_iter),
+                         range, r->index);
 }
 
 static PyObject *
diff --git a/Objects/setobject.c b/Objects/setobject.c
index c2a1467..a43ecd5 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -842,6 +842,7 @@
 static PyObject *
 setiter_reduce(setiterobject *si, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     /* copy the iterator state */
     setiterobject tmp = *si;
     Py_XINCREF(tmp.si_set);
@@ -852,7 +853,7 @@
     if (list == NULL) {
         return NULL;
     }
-    return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), list);
+    return Py_BuildValue("N(N)", _PyEval_GetBuiltinId(&PyId_iter), list);
 }
 
 PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 83c63e0..9cf3f3d 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -1024,11 +1024,12 @@
 static PyObject *
 tupleiter_reduce(tupleiterobject *it, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     if (it->it_seq)
-        return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+        return Py_BuildValue("N(O)n", _PyEval_GetBuiltinId(&PyId_iter),
                              it->it_seq, it->it_index);
     else
-        return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
+        return Py_BuildValue("N(())", _PyEval_GetBuiltinId(&PyId_iter));
 }
 
 static PyObject *
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index d0f0358..06338fa 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -15444,14 +15444,15 @@
 static PyObject *
 unicodeiter_reduce(unicodeiterobject *it, PyObject *Py_UNUSED(ignored))
 {
+    _Py_IDENTIFIER(iter);
     if (it->it_seq != NULL) {
-        return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
+        return Py_BuildValue("N(O)n", _PyEval_GetBuiltinId(&PyId_iter),
                              it->it_seq, it->it_index);
     } else {
         PyObject *u = (PyObject *)_PyUnicode_New(0);
         if (u == NULL)
             return NULL;
-        return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), u);
+        return Py_BuildValue("N(N)", _PyEval_GetBuiltinId(&PyId_iter), u);
     }
 }