@@ -6540,28 +6540,11 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char*
65406540 return 0 ;
65416541}
65426542
6543- static int
6544- object_set_class (PyObject * self , PyObject * value , void * closure )
6545- {
6546-
6547- if (value == NULL ) {
6548- PyErr_SetString (PyExc_TypeError ,
6549- "can't delete __class__ attribute" );
6550- return -1 ;
6551- }
6552- if (!PyType_Check (value )) {
6553- PyErr_Format (PyExc_TypeError ,
6554- "__class__ must be set to a class, not '%s' object" ,
6555- Py_TYPE (value )-> tp_name );
6556- return -1 ;
6557- }
6558- PyTypeObject * newto = (PyTypeObject * )value ;
65596543
6560- if (PySys_Audit ("object.__setattr__" , "OsO" ,
6561- self , "__class__" , value ) < 0 ) {
6562- return -1 ;
6563- }
65646544
6545+ static int
6546+ object_set_class_world_stopped (PyObject * self , PyTypeObject * newto )
6547+ {
65656548 PyTypeObject * oldto = Py_TYPE (self );
65666549
65676550 /* In versions of CPython prior to 3.5, the code in
@@ -6627,49 +6610,74 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
66276610 /* Changing the class will change the implicit dict keys,
66286611 * so we must materialize the dictionary first. */
66296612 if (oldto -> tp_flags & Py_TPFLAGS_INLINE_VALUES ) {
6630- PyDictObject * dict = _PyObject_MaterializeManagedDict (self );
6613+ PyDictObject * dict = _PyObject_GetManagedDict (self );
66316614 if (dict == NULL ) {
6632- return -1 ;
6615+ dict = _PyObject_MaterializeManagedDict_LockHeld (self );
6616+ if (dict == NULL ) {
6617+ return -1 ;
6618+ }
66336619 }
66346620
6635- bool error = false;
6636-
6637- Py_BEGIN_CRITICAL_SECTION2 (self , dict );
6638-
6639- // If we raced after materialization and replaced the dict
6640- // then the materialized dict should no longer have the
6641- // inline values in which case detach is a nop.
6642- assert (_PyObject_GetManagedDict (self ) == dict ||
6643- dict -> ma_values != _PyObject_InlineValues (self ));
6621+ assert (_PyObject_GetManagedDict (self ) == dict );
66446622
66456623 if (_PyDict_DetachFromObject (dict , self ) < 0 ) {
6646- error = true;
6647- }
6648-
6649- Py_END_CRITICAL_SECTION2 ();
6650- if (error ) {
66516624 return -1 ;
66526625 }
6626+
66536627 }
66546628 if (newto -> tp_flags & Py_TPFLAGS_HEAPTYPE ) {
66556629 Py_INCREF (newto );
66566630 }
6657- Py_BEGIN_CRITICAL_SECTION (self );
6658- // The real Py_TYPE(self) (`oldto`) may have changed from
6659- // underneath us in another thread, so we re-fetch it here.
6660- oldto = Py_TYPE (self );
6631+
66616632 Py_SET_TYPE (self , newto );
6662- Py_END_CRITICAL_SECTION ();
6633+
6634+ return 0 ;
6635+ }
6636+ else {
6637+ return -1 ;
6638+ }
6639+ }
6640+
6641+ static int
6642+ object_set_class (PyObject * self , PyObject * value , void * closure )
6643+ {
6644+
6645+ if (value == NULL ) {
6646+ PyErr_SetString (PyExc_TypeError ,
6647+ "can't delete __class__ attribute" );
6648+ return -1 ;
6649+ }
6650+ if (!PyType_Check (value )) {
6651+ PyErr_Format (PyExc_TypeError ,
6652+ "__class__ must be set to a class, not '%s' object" ,
6653+ Py_TYPE (value )-> tp_name );
6654+ return -1 ;
6655+ }
6656+ PyTypeObject * newto = (PyTypeObject * )value ;
6657+
6658+ if (PySys_Audit ("object.__setattr__" , "OsO" ,
6659+ self , "__class__" , value ) < 0 ) {
6660+ return -1 ;
6661+ }
6662+
6663+ #ifdef Py_GIL_DISABLED
6664+ PyInterpreterState * interp = _PyInterpreterState_GET ();
6665+ _PyEval_StopTheWorld (interp );
6666+ #endif
6667+ PyTypeObject * oldto = Py_TYPE (self );
6668+ int res = object_set_class_world_stopped (self , newto );
6669+ #ifdef Py_GIL_DISABLED
6670+ _PyEval_StartTheWorld (interp );
6671+ #endif
6672+ if (res == 0 ) {
66636673 if (oldto -> tp_flags & Py_TPFLAGS_HEAPTYPE ) {
66646674 Py_DECREF (oldto );
66656675 }
66666676
66676677 RARE_EVENT_INC (set_class );
66686678 return 0 ;
66696679 }
6670- else {
6671- return -1 ;
6672- }
6680+ return res ;
66736681}
66746682
66756683static PyGetSetDef object_getsets [] = {
0 commit comments