@@ -5978,53 +5978,59 @@ PyObject_GetItemData(PyObject *obj)
59785978}
59795979
59805980/* Internal API to look for a name through the MRO, bypassing the method cache.
5981- This returns a borrowed reference, and might set an exception.
5982- 'error' is set to: -1: error with exception; 1: error without exception; 0: ok */
5983- static PyObject *
5984- find_name_in_mro (PyTypeObject * type , PyObject * name , int * error )
5981+ The result is stored as a _PyStackRef in `out`. It never set an exception.
5982+ Returns -1 if there was an error, 0 if the name was not found, and 1 if
5983+ the name was found. */
5984+ static int
5985+ find_name_in_mro (PyTypeObject * type , PyObject * name , _PyStackRef * out )
59855986{
59865987 Py_hash_t hash = _PyObject_HashFast (name );
59875988 if (hash == -1 ) {
5988- * error = -1 ;
5989- return NULL ;
5989+ PyErr_Clear () ;
5990+ return -1 ;
59905991 }
59915992
59925993 /* Look in tp_dict of types in MRO */
59935994 PyObject * mro = lookup_tp_mro (type );
59945995 if (mro == NULL ) {
59955996 if (!is_readying (type )) {
59965997 if (PyType_Ready (type ) < 0 ) {
5997- * error = -1 ;
5998- return NULL ;
5998+ PyErr_Clear () ;
5999+ return -1 ;
59996000 }
60006001 mro = lookup_tp_mro (type );
60016002 }
60026003 if (mro == NULL ) {
6003- * error = 1 ;
6004- return NULL ;
6004+ return -1 ;
60056005 }
60066006 }
60076007
6008- PyObject * res = NULL ;
6008+ int res = 0 ;
6009+ PyThreadState * tstate = _PyThreadState_GET ();
60096010 /* Keep a strong reference to mro because type->tp_mro can be replaced
60106011 during dict lookup, e.g. when comparing to non-string keys. */
6011- Py_INCREF (mro );
6012+ _PyCStackRef mro_ref ;
6013+ _PyThreadState_PushCStackRef (tstate , & mro_ref );
6014+ mro_ref .ref = PyStackRef_FromPyObjectNew (mro );
60126015 Py_ssize_t n = PyTuple_GET_SIZE (mro );
60136016 for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
60146017 PyObject * base = PyTuple_GET_ITEM (mro , i );
60156018 PyObject * dict = lookup_tp_dict (_PyType_CAST (base ));
60166019 assert (dict && PyDict_Check (dict ));
6017- if (_PyDict_GetItemRef_KnownHash ((PyDictObject * )dict , name , hash , & res ) < 0 ) {
6018- * error = -1 ;
6020+ Py_ssize_t ix = _Py_dict_lookup_threadsafe_stackref (
6021+ (PyDictObject * )dict , name , hash , out );
6022+ if (ix == DKIX_ERROR ) {
6023+ PyErr_Clear ();
6024+ res = -1 ;
60196025 goto done ;
60206026 }
6021- if (res != NULL ) {
6027+ if (!PyStackRef_IsNull (* out )) {
6028+ res = 1 ;
60226029 break ;
60236030 }
60246031 }
6025- * error = 0 ;
60266032done :
6027- Py_DECREF ( mro );
6033+ _PyThreadState_PopCStackRef ( tstate , & mro_ref );
60286034 return res ;
60296035}
60306036
@@ -6179,11 +6185,11 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
61796185 // We need to atomically do the lookup and capture the version before
61806186 // anyone else can modify our mro or mutate the type.
61816187
6182- PyObject * res ;
6183- int error ;
6188+ int res ;
61846189 PyInterpreterState * interp = _PyInterpreterState_GET ();
61856190 int has_version = 0 ;
61866191 unsigned int assigned_version = 0 ;
6192+
61876193 BEGIN_TYPE_LOCK ();
61886194 // We must assign the version before doing the lookup. If
61896195 // find_name_in_mro() blocks and releases the critical section
@@ -6192,35 +6198,24 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
61926198 has_version = assign_version_tag (interp , type );
61936199 assigned_version = type -> tp_version_tag ;
61946200 }
6195- res = find_name_in_mro (type , name , & error );
6201+ res = find_name_in_mro (type , name , out );
61966202 END_TYPE_LOCK ();
61976203
61986204 /* Only put NULL results into cache if there was no error. */
6199- if (error ) {
6200- /* It's not ideal to clear the error condition,
6201- but this function is documented as not setting
6202- an exception, and I don't want to change that.
6203- E.g., when PyType_Ready() can't proceed, it won't
6204- set the "ready" flag, so future attempts to ready
6205- the same type will call it again -- hopefully
6206- in a context that propagates the exception out.
6207- */
6208- if (error == -1 ) {
6209- PyErr_Clear ();
6210- }
6205+ if (res < 0 ) {
62116206 * out = PyStackRef_NULL ;
62126207 return 0 ;
62136208 }
62146209
62156210 if (has_version ) {
6211+ PyObject * res_obj = PyStackRef_AsPyObjectBorrow (* out );
62166212#if Py_GIL_DISABLED
6217- update_cache_gil_disabled (entry , name , assigned_version , res );
6213+ update_cache_gil_disabled (entry , name , assigned_version , res_obj );
62186214#else
6219- PyObject * old_value = update_cache (entry , name , assigned_version , res );
6215+ PyObject * old_value = update_cache (entry , name , assigned_version , res_obj );
62206216 Py_DECREF (old_value );
62216217#endif
62226218 }
6223- * out = res ? PyStackRef_FromPyObjectSteal (res ) : PyStackRef_NULL ;
62246219 return has_version ? assigned_version : 0 ;
62256220}
62266221
@@ -11709,7 +11704,6 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p, pytype_slotdef **next_p,
1170911704 int use_generic = 0 ;
1171011705
1171111706 int offset = p -> offset ;
11712- int error ;
1171311707 void * * ptr = slotptr (type , offset );
1171411708
1171511709 if (ptr == NULL ) {
@@ -11725,19 +11719,15 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p, pytype_slotdef **next_p,
1172511719 assert (!PyErr_Occurred ());
1172611720 do {
1172711721 /* Use faster uncached lookup as we won't get any cache hits during type setup. */
11728- descr = find_name_in_mro (type , p -> name_strobj , & error );
11729- if (descr == NULL ) {
11730- if (error == -1 ) {
11731- /* It is unlikely but not impossible that there has been an exception
11732- during lookup. Since this function originally expected no errors,
11733- we ignore them here in order to keep up the interface. */
11734- PyErr_Clear ();
11735- }
11722+ _PyStackRef descr_ref ;
11723+ int res = find_name_in_mro (type , p -> name_strobj , & descr_ref );
11724+ if (res <= 0 ) {
1173611725 if (ptr == (void * * )& type -> tp_iternext ) {
1173711726 specific = (void * )_PyObject_NextNotImplemented ;
1173811727 }
1173911728 continue ;
1174011729 }
11730+ descr = PyStackRef_AsPyObjectBorrow (descr_ref );
1174111731 if (Py_IS_TYPE (descr , & PyWrapperDescr_Type ) &&
1174211732 ((PyWrapperDescrObject * )descr )-> d_base -> name_strobj == p -> name_strobj ) {
1174311733 void * * tptr ;
@@ -11815,7 +11805,7 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p, pytype_slotdef **next_p,
1181511805 }
1181611806 }
1181711807 }
11818- Py_DECREF ( descr );
11808+ PyStackRef_CLOSE ( descr_ref );
1181911809 } while ((++ p )-> offset == offset );
1182011810
1182111811 void * slot_value ;
0 commit comments