@@ -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