@@ -5702,55 +5702,61 @@ PyObject_GetItemData(PyObject *obj)
57025702}
57035703
57045704/* Internal API to look for a name through the MRO, bypassing the method cache.
5705- This returns a borrowed reference, and might set an exception.
5706- 'error' is set to: -1: error with exception; 1: error without exception; 0: ok */
5707- static PyObject *
5708- find_name_in_mro(PyTypeObject *type, PyObject *name, int *error)
5705+ The result is stored as a _PyStackRef in `out`. It never set an exception.
5706+ Returns -1 if there was an error, 0 if the name was not found, and 1 if
5707+ the name was found. */
5708+ static int
5709+ find_name_in_mro(PyTypeObject *type, PyObject *name, _PyStackRef *out)
57095710{
57105711 ASSERT_TYPE_LOCK_HELD();
57115712
57125713 Py_hash_t hash = _PyObject_HashFast(name);
57135714 if (hash == -1) {
5714- *error = -1 ;
5715- return NULL ;
5715+ PyErr_Clear() ;
5716+ return -1 ;
57165717 }
57175718
57185719 /* Look in tp_dict of types in MRO */
57195720 PyObject *mro = lookup_tp_mro(type);
57205721 if (mro == NULL) {
57215722 if (!is_readying(type)) {
57225723 if (PyType_Ready(type) < 0) {
5723- *error = -1 ;
5724- return NULL ;
5724+ PyErr_Clear() ;
5725+ return -1 ;
57255726 }
57265727 mro = lookup_tp_mro(type);
57275728 }
57285729 if (mro == NULL) {
5729- *error = 1;
5730- return NULL;
5730+ return -1;
57315731 }
57325732 }
57335733
5734- PyObject *res = NULL;
5734+ int res = 0;
5735+ PyThreadState *tstate = _PyThreadState_GET();
57355736 /* Keep a strong reference to mro because type->tp_mro can be replaced
57365737 during dict lookup, e.g. when comparing to non-string keys. */
5737- Py_INCREF(mro);
5738+ _PyCStackRef mro_ref;
5739+ _PyThreadState_PushCStackRef(tstate, &mro_ref);
5740+ mro_ref.ref = PyStackRef_FromPyObjectNew(mro);
57385741 Py_ssize_t n = PyTuple_GET_SIZE(mro);
57395742 for (Py_ssize_t i = 0; i < n; i++) {
57405743 PyObject *base = PyTuple_GET_ITEM(mro, i);
57415744 PyObject *dict = lookup_tp_dict(_PyType_CAST(base));
57425745 assert(dict && PyDict_Check(dict));
5743- if (_PyDict_GetItemRef_KnownHash((PyDictObject *)dict, name, hash, &res) < 0) {
5744- *error = -1;
5746+ Py_ssize_t ix = _Py_dict_lookup_threadsafe_stackref(
5747+ (PyDictObject *)dict, name, hash, out);
5748+ if (ix == DKIX_ERROR) {
5749+ PyErr_Clear();
5750+ res = -1;
57455751 goto done;
57465752 }
5747- if (res != NULL) {
5753+ if (!PyStackRef_IsNull(*out)) {
5754+ res = 1;
57485755 break;
57495756 }
57505757 }
5751- *error = 0;
57525758done:
5753- Py_DECREF(mro );
5759+ _PyThreadState_PopCStackRef(tstate, &mro_ref );
57545760 return res;
57555761}
57565762
@@ -5905,11 +5911,11 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
59055911 // We need to atomically do the lookup and capture the version before
59065912 // anyone else can modify our mro or mutate the type.
59075913
5908- PyObject *res;
5909- int error;
5914+ int res;
59105915 PyInterpreterState *interp = _PyInterpreterState_GET();
59115916 int has_version = 0;
59125917 unsigned int assigned_version = 0;
5918+
59135919 BEGIN_TYPE_LOCK();
59145920 // We must assign the version before doing the lookup. If
59155921 // find_name_in_mro() blocks and releases the critical section
@@ -5918,35 +5924,24 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
59185924 has_version = assign_version_tag(interp, type);
59195925 assigned_version = type->tp_version_tag;
59205926 }
5921- res = find_name_in_mro(type, name, &error );
5927+ res = find_name_in_mro(type, name, out );
59225928 END_TYPE_LOCK();
59235929
59245930 /* Only put NULL results into cache if there was no error. */
5925- if (error) {
5926- /* It's not ideal to clear the error condition,
5927- but this function is documented as not setting
5928- an exception, and I don't want to change that.
5929- E.g., when PyType_Ready() can't proceed, it won't
5930- set the "ready" flag, so future attempts to ready
5931- the same type will call it again -- hopefully
5932- in a context that propagates the exception out.
5933- */
5934- if (error == -1) {
5935- PyErr_Clear();
5936- }
5931+ if (res < 0) {
59375932 *out = PyStackRef_NULL;
59385933 return 0;
59395934 }
59405935
59415936 if (has_version) {
5937+ PyObject *res_obj = PyStackRef_AsPyObjectBorrow(*out);
59425938#if Py_GIL_DISABLED
5943- update_cache_gil_disabled(entry, name, assigned_version, res );
5939+ update_cache_gil_disabled(entry, name, assigned_version, res_obj );
59445940#else
5945- PyObject *old_value = update_cache(entry, name, assigned_version, res );
5941+ PyObject *old_value = update_cache(entry, name, assigned_version, res_obj );
59465942 Py_DECREF(old_value);
59475943#endif
59485944 }
5949- *out = res ? PyStackRef_FromPyObjectSteal(res) : PyStackRef_NULL;
59505945 return has_version ? assigned_version : 0;
59515946}
59525947
@@ -11306,7 +11301,6 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p)
1130611301 int use_generic = 0;
1130711302
1130811303 int offset = p->offset;
11309- int error;
1131011304 void **ptr = slotptr(type, offset);
1131111305
1131211306 if (ptr == NULL) {
@@ -11319,19 +11313,15 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p)
1131911313 assert(!PyErr_Occurred());
1132011314 do {
1132111315 /* Use faster uncached lookup as we won't get any cache hits during type setup. */
11322- descr = find_name_in_mro(type, p->name_strobj, &error);
11323- if (descr == NULL) {
11324- if (error == -1) {
11325- /* It is unlikely but not impossible that there has been an exception
11326- during lookup. Since this function originally expected no errors,
11327- we ignore them here in order to keep up the interface. */
11328- PyErr_Clear();
11329- }
11316+ _PyStackRef descr_ref;
11317+ int res = find_name_in_mro(type, p->name_strobj, &descr_ref);
11318+ if (res <= 0) {
1133011319 if (ptr == (void**)&type->tp_iternext) {
1133111320 specific = (void *)_PyObject_NextNotImplemented;
1133211321 }
1133311322 continue;
1133411323 }
11324+ descr = PyStackRef_AsPyObjectBorrow(descr_ref);
1133511325 if (Py_IS_TYPE(descr, &PyWrapperDescr_Type) &&
1133611326 ((PyWrapperDescrObject *)descr)->d_base->name_strobj == p->name_strobj) {
1133711327 void **tptr = resolve_slotdups(type, p->name_strobj);
@@ -11399,7 +11389,7 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p)
1139911389 type_clear_flags(type, Py_TPFLAGS_HAVE_VECTORCALL);
1140011390 }
1140111391 }
11402- Py_DECREF(descr );
11392+ PyStackRef_CLOSE(descr_ref );
1140311393 } while ((++p)->offset == offset);
1140411394 if (specific && !use_generic)
1140511395 *ptr = specific;
0 commit comments