@@ -6369,28 +6369,11 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char*
63696369 return 0 ;
63706370}
63716371
6372- static int
6373- object_set_class (PyObject * self , PyObject * value , void * closure )
6374- {
6375-
6376- if (value == NULL ) {
6377- PyErr_SetString (PyExc_TypeError ,
6378- "can't delete __class__ attribute" );
6379- return -1 ;
6380- }
6381- if (!PyType_Check (value )) {
6382- PyErr_Format (PyExc_TypeError ,
6383- "__class__ must be set to a class, not '%s' object" ,
6384- Py_TYPE (value )-> tp_name );
6385- return -1 ;
6386- }
6387- PyTypeObject * newto = (PyTypeObject * )value ;
63886372
6389- if (PySys_Audit ("object.__setattr__" , "OsO" ,
6390- self , "__class__" , value ) < 0 ) {
6391- return -1 ;
6392- }
63936373
6374+ static int
6375+ object_set_class_world_stopped (PyObject * self , PyTypeObject * newto )
6376+ {
63946377 PyTypeObject * oldto = Py_TYPE (self );
63956378
63966379 /* In versions of CPython prior to 3.5, the code in
@@ -6456,49 +6439,74 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
64566439 /* Changing the class will change the implicit dict keys,
64576440 * so we must materialize the dictionary first. */
64586441 if (oldto -> tp_flags & Py_TPFLAGS_INLINE_VALUES ) {
6459- PyDictObject * dict = _PyObject_MaterializeManagedDict (self );
6442+ PyDictObject * dict = _PyObject_GetManagedDict (self );
64606443 if (dict == NULL ) {
6461- return -1 ;
6444+ dict = _PyObject_MaterializeManagedDict_LockHeld (self );
6445+ if (dict == NULL ) {
6446+ return -1 ;
6447+ }
64626448 }
64636449
6464- bool error = false;
6465-
6466- Py_BEGIN_CRITICAL_SECTION2 (self , dict );
6467-
6468- // If we raced after materialization and replaced the dict
6469- // then the materialized dict should no longer have the
6470- // inline values in which case detach is a nop.
6471- assert (_PyObject_GetManagedDict (self ) == dict ||
6472- dict -> ma_values != _PyObject_InlineValues (self ));
6450+ assert (_PyObject_GetManagedDict (self ) == dict );
64736451
64746452 if (_PyDict_DetachFromObject (dict , self ) < 0 ) {
6475- error = true;
6476- }
6477-
6478- Py_END_CRITICAL_SECTION2 ();
6479- if (error ) {
64806453 return -1 ;
64816454 }
6455+
64826456 }
64836457 if (newto -> tp_flags & Py_TPFLAGS_HEAPTYPE ) {
64846458 Py_INCREF (newto );
64856459 }
6486- Py_BEGIN_CRITICAL_SECTION (self );
6487- // The real Py_TYPE(self) (`oldto`) may have changed from
6488- // underneath us in another thread, so we re-fetch it here.
6489- oldto = Py_TYPE (self );
6460+
64906461 Py_SET_TYPE (self , newto );
6491- Py_END_CRITICAL_SECTION ();
6462+
6463+ return 0 ;
6464+ }
6465+ else {
6466+ return -1 ;
6467+ }
6468+ }
6469+
6470+ static int
6471+ object_set_class (PyObject * self , PyObject * value , void * closure )
6472+ {
6473+
6474+ if (value == NULL ) {
6475+ PyErr_SetString (PyExc_TypeError ,
6476+ "can't delete __class__ attribute" );
6477+ return -1 ;
6478+ }
6479+ if (!PyType_Check (value )) {
6480+ PyErr_Format (PyExc_TypeError ,
6481+ "__class__ must be set to a class, not '%s' object" ,
6482+ Py_TYPE (value )-> tp_name );
6483+ return -1 ;
6484+ }
6485+ PyTypeObject * newto = (PyTypeObject * )value ;
6486+
6487+ if (PySys_Audit ("object.__setattr__" , "OsO" ,
6488+ self , "__class__" , value ) < 0 ) {
6489+ return -1 ;
6490+ }
6491+
6492+ #ifdef Py_GIL_DISABLED
6493+ PyInterpreterState * interp = _PyInterpreterState_GET ();
6494+ _PyEval_StopTheWorld (interp );
6495+ #endif
6496+ PyTypeObject * oldto = Py_TYPE (self );
6497+ int res = object_set_class_world_stopped (self , newto );
6498+ #ifdef Py_GIL_DISABLED
6499+ _PyEval_StartTheWorld (interp );
6500+ #endif
6501+ if (res == 0 ) {
64926502 if (oldto -> tp_flags & Py_TPFLAGS_HEAPTYPE ) {
64936503 Py_DECREF (oldto );
64946504 }
64956505
64966506 RARE_EVENT_INC (set_class );
64976507 return 0 ;
64986508 }
6499- else {
6500- return -1 ;
6501- }
6509+ return res ;
65026510}
65036511
65046512static PyGetSetDef object_getsets [] = {
0 commit comments