summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2022-08-01 13:34:54 (GMT)
committerGitHub <noreply@github.com>2022-08-01 13:34:54 (GMT)
commitde388c0a7b71c094d36ce40fecef87bdbb8a87d3 (patch)
treeb2318318e6c9a80bc9f45ecf5fc05aa66efb7825 /Objects
parentfb75d015f487e50079e8d2ea7859750684b124e4 (diff)
downloadcpython-de388c0a7b71c094d36ce40fecef87bdbb8a87d3.zip
cpython-de388c0a7b71c094d36ce40fecef87bdbb8a87d3.tar.gz
cpython-de388c0a7b71c094d36ce40fecef87bdbb8a87d3.tar.bz2
GH-95245: Store object values and dict pointers in single tagged pointer. (GH-95278)
Diffstat (limited to 'Objects')
-rw-r--r--Objects/dictobject.c161
-rw-r--r--Objects/object.c168
-rw-r--r--Objects/typeobject.c31
3 files changed, 195 insertions, 165 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 25e191f..d820348 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -5368,7 +5368,7 @@ init_inline_values(PyObject *obj, PyTypeObject *tp)
for (int i = 0; i < size; i++) {
values->values[i] = NULL;
}
- *_PyObject_ValuesPointer(obj) = values;
+ _PyDictOrValues_SetValues(_PyObject_DictOrValuesPointer(obj), values);
return 0;
}
@@ -5394,7 +5394,7 @@ _PyObject_InitializeDict(PyObject *obj)
if (dict == NULL) {
return -1;
}
- PyObject **dictptr = _PyObject_DictPointer(obj);
+ PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
*dictptr = dict;
return 0;
}
@@ -5422,7 +5422,6 @@ make_dict_from_instance_attributes(PyDictKeysObject *keys, PyDictValues *values)
PyObject *
_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values)
{
- assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
OBJECT_STAT_INC(dict_materialized_on_request);
return make_dict_from_instance_attributes(keys, values);
@@ -5458,8 +5457,7 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
if (dict == NULL) {
return -1;
}
- *_PyObject_ValuesPointer(obj) = NULL;
- *_PyObject_ManagedDictPointer(obj) = dict;
+ _PyObject_DictOrValuesPointer(obj)->dict = dict;
if (value == NULL) {
return PyDict_DelItem(dict, name);
}
@@ -5488,6 +5486,37 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
return 0;
}
+/* Sanity check for managed dicts */
+#if 0
+#define CHECK(val) assert(val); if (!(val)) { return 0; }
+
+int
+_PyObject_ManagedDictValidityCheck(PyObject *obj)
+{
+ PyTypeObject *tp = Py_TYPE(obj);
+ CHECK(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+ PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
+ int size = ((uint8_t *)values)[-2];
+ int count = 0;
+ PyDictKeysObject *keys = CACHED_KEYS(tp);
+ for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
+ if (values->values[i] != NULL) {
+ count++;
+ }
+ }
+ CHECK(size == count);
+ }
+ else {
+ if (dorv_ptr->dict != NULL) {
+ CHECK(PyDict_Check(dorv_ptr->dict));
+ }
+ }
+ return 1;
+}
+#endif
+
PyObject *
_PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
PyObject *name)
@@ -5511,105 +5540,94 @@ _PyObject_IsInstanceDictEmpty(PyObject *obj)
if (tp->tp_dictoffset == 0) {
return 1;
}
- PyObject **dictptr;
+ PyObject *dict;
if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- PyDictValues *values = *_PyObject_ValuesPointer(obj);
- if (values) {
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(dorv)) {
PyDictKeysObject *keys = CACHED_KEYS(tp);
for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
- if (values->values[i] != NULL) {
+ if (_PyDictOrValues_GetValues(dorv)->values[i] != NULL) {
return 0;
}
}
return 1;
}
- dictptr = _PyObject_ManagedDictPointer(obj);
+ dict = _PyDictOrValues_GetDict(dorv);
}
else {
- dictptr = _PyObject_DictPointer(obj);
+ PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
+ dict = *dictptr;
}
- PyObject *dict = *dictptr;
if (dict == NULL) {
return 1;
}
return ((PyDictObject *)dict)->ma_used == 0;
}
-
-int
-_PyObject_VisitInstanceAttributes(PyObject *self, visitproc visit, void *arg)
-{
- PyTypeObject *tp = Py_TYPE(self);
- assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictValues **values_ptr = _PyObject_ValuesPointer(self);
- if (*values_ptr == NULL) {
- return 0;
- }
- PyDictKeysObject *keys = CACHED_KEYS(tp);
- for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
- Py_VISIT((*values_ptr)->values[i]);
- }
- return 0;
-}
-
-void
-_PyObject_ClearInstanceAttributes(PyObject *self)
-{
- PyTypeObject *tp = Py_TYPE(self);
- assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictValues **values_ptr = _PyObject_ValuesPointer(self);
- if (*values_ptr == NULL) {
- return;
- }
- PyDictKeysObject *keys = CACHED_KEYS(tp);
- for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
- Py_CLEAR((*values_ptr)->values[i]);
- }
-}
-
void
_PyObject_FreeInstanceAttributes(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictValues **values_ptr = _PyObject_ValuesPointer(self);
- if (*values_ptr == NULL) {
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
+ if (!_PyDictOrValues_IsValues(dorv)) {
return;
}
+ PyDictValues *values = _PyDictOrValues_GetValues(dorv);
PyDictKeysObject *keys = CACHED_KEYS(tp);
for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
- Py_XDECREF((*values_ptr)->values[i]);
+ Py_XDECREF(values->values[i]);
}
- free_values(*values_ptr);
+ free_values(values);
}
int
-_PyObject_VisitManagedDict(PyObject *self, visitproc visit, void *arg)
+_PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
{
- PyTypeObject *tp = Py_TYPE(self);
+ PyTypeObject *tp = Py_TYPE(obj);
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
return 0;
}
assert(tp->tp_dictoffset);
- int err = _PyObject_VisitInstanceAttributes(self, visit, arg);
- if (err) {
- return err;
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(dorv)) {
+ PyDictValues *values = _PyDictOrValues_GetValues(dorv);
+ PyDictKeysObject *keys = CACHED_KEYS(tp);
+ for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
+ Py_VISIT(values->values[i]);
+ }
+ }
+ else {
+ PyObject *dict = _PyDictOrValues_GetDict(dorv);
+ Py_VISIT(dict);
}
- Py_VISIT(*_PyObject_ManagedDictPointer(self));
return 0;
}
-
void
-_PyObject_ClearManagedDict(PyObject *self)
+_PyObject_ClearManagedDict(PyObject *obj)
{
- PyTypeObject *tp = Py_TYPE(self);
+ PyTypeObject *tp = Py_TYPE(obj);
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
return;
}
- _PyObject_FreeInstanceAttributes(self);
- *_PyObject_ValuesPointer(self) = NULL;
- Py_CLEAR(*_PyObject_ManagedDictPointer(self));
+ PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
+ PyDictKeysObject *keys = CACHED_KEYS(tp);
+ for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
+ Py_CLEAR(values->values[i]);
+ }
+ dorv_ptr->dict = NULL;
+ free_values(values);
+ }
+ else {
+ PyObject *dict = dorv_ptr->dict;
+ if (dict) {
+ dorv_ptr->dict = NULL;
+ Py_DECREF(dict);
+ }
+ }
}
PyObject *
@@ -5618,25 +5636,26 @@ PyObject_GenericGetDict(PyObject *obj, void *context)
PyObject *dict;
PyTypeObject *tp = Py_TYPE(obj);
if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) {
- PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
- PyObject **dictptr = _PyObject_ManagedDictPointer(obj);
- if (*values_ptr) {
- assert(*dictptr == NULL);
+ PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
OBJECT_STAT_INC(dict_materialized_on_request);
- *dictptr = dict = make_dict_from_instance_attributes(CACHED_KEYS(tp), *values_ptr);
+ dict = make_dict_from_instance_attributes(CACHED_KEYS(tp), values);
if (dict != NULL) {
- *values_ptr = NULL;
+ dorv_ptr->dict = dict;
}
}
- else if (*dictptr == NULL) {
- *dictptr = dict = PyDict_New();
- }
else {
- dict = *dictptr;
+ dict = _PyDictOrValues_GetDict(*dorv_ptr);
+ if (dict == NULL) {
+ dictkeys_incref(CACHED_KEYS(tp));
+ dict = new_dict_with_shared_keys(CACHED_KEYS(tp));
+ dorv_ptr->dict = dict;
+ }
}
}
else {
- PyObject **dictptr = _PyObject_DictPointer(obj);
+ PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
if (dictptr == NULL) {
PyErr_SetString(PyExc_AttributeError,
"This object has no __dict__");
diff --git a/Objects/object.c b/Objects/object.c
index 758b79e..f0c0434 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1054,14 +1054,12 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
}
PyObject **
-_PyObject_DictPointer(PyObject *obj)
+_PyObject_ComputedDictPointer(PyObject *obj)
{
Py_ssize_t dictoffset;
PyTypeObject *tp = Py_TYPE(obj);
- if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- return _PyObject_ManagedDictPointer(obj);
- }
+ assert((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0);
dictoffset = tp->tp_dictoffset;
if (dictoffset == 0)
return NULL;
@@ -1086,22 +1084,18 @@ PyObject **
_PyObject_GetDictPtr(PyObject *obj)
{
if ((Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
- return _PyObject_DictPointer(obj);
- }
- PyObject **dict_ptr = _PyObject_ManagedDictPointer(obj);
- PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
- if (*values_ptr == NULL) {
- return dict_ptr;
+ return _PyObject_ComputedDictPointer(obj);
}
- assert(*dict_ptr == NULL);
- PyObject *dict = _PyObject_MakeDictFromInstanceAttributes(obj, *values_ptr);
- if (dict == NULL) {
- PyErr_Clear();
- return NULL;
+ PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ PyObject *dict = _PyObject_MakeDictFromInstanceAttributes(obj, _PyDictOrValues_GetValues(*dorv_ptr));
+ if (dict == NULL) {
+ PyErr_Clear();
+ return NULL;
+ }
+ dorv_ptr->dict = dict;
}
- *values_ptr = NULL;
- *dict_ptr = dict;
- return dict_ptr;
+ return &dorv_ptr->dict;
}
PyObject *
@@ -1170,36 +1164,46 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
}
}
}
- PyDictValues *values;
- if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) &&
- (values = *_PyObject_ValuesPointer(obj)))
- {
- assert(*_PyObject_DictPointer(obj) == NULL);
- PyObject *attr = _PyObject_GetInstanceAttribute(obj, values, name);
- if (attr != NULL) {
- *method = attr;
- Py_XDECREF(descr);
- return 0;
- }
- }
- else {
- PyObject **dictptr = _PyObject_DictPointer(obj);
- PyObject *dict;
- if (dictptr != NULL && (dict = *dictptr) != NULL) {
- Py_INCREF(dict);
- PyObject *attr = PyDict_GetItemWithError(dict, name);
+ PyObject *dict;
+ if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT)) {
+ PyDictOrValues* dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
+ PyObject *attr = _PyObject_GetInstanceAttribute(obj, values, name);
if (attr != NULL) {
- *method = Py_NewRef(attr);
- Py_DECREF(dict);
+ *method = attr;
Py_XDECREF(descr);
return 0;
}
+ dict = NULL;
+ }
+ else {
+ dict = dorv_ptr->dict;
+ }
+ }
+ else {
+ PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
+ if (dictptr != NULL) {
+ dict = *dictptr;
+ }
+ else {
+ dict = NULL;
+ }
+ }
+ if (dict != NULL) {
+ Py_INCREF(dict);
+ PyObject *attr = PyDict_GetItemWithError(dict, name);
+ if (attr != NULL) {
+ *method = Py_NewRef(attr);
Py_DECREF(dict);
+ Py_XDECREF(descr);
+ return 0;
+ }
+ Py_DECREF(dict);
- if (PyErr_Occurred()) {
- Py_XDECREF(descr);
- return 0;
- }
+ if (PyErr_Occurred()) {
+ Py_XDECREF(descr);
+ return 0;
}
}
@@ -1243,7 +1247,6 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
PyObject *descr = NULL;
PyObject *res = NULL;
descrgetfunc f;
- PyObject **dictptr;
if (!PyUnicode_Check(name)){
PyErr_Format(PyExc_TypeError,
@@ -1274,30 +1277,31 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
}
}
if (dict == NULL) {
- if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) &&
- *_PyObject_ValuesPointer(obj))
- {
- PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
- if (PyUnicode_CheckExact(name)) {
- assert(*_PyObject_DictPointer(obj) == NULL);
- res = _PyObject_GetInstanceAttribute(obj, *values_ptr, name);
- if (res != NULL) {
- goto done;
+ if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT)) {
+ PyDictOrValues* dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
+ if (PyUnicode_CheckExact(name)) {
+ res = _PyObject_GetInstanceAttribute(obj, values, name);
+ if (res != NULL) {
+ goto done;
+ }
+ }
+ else {
+ dict = _PyObject_MakeDictFromInstanceAttributes(obj, values);
+ if (dict == NULL) {
+ res = NULL;
+ goto done;
+ }
+ dorv_ptr->dict = dict;
}
}
else {
- dictptr = _PyObject_DictPointer(obj);
- assert(dictptr != NULL && *dictptr == NULL);
- *dictptr = dict = _PyObject_MakeDictFromInstanceAttributes(obj, *values_ptr);
- if (dict == NULL) {
- res = NULL;
- goto done;
- }
- *values_ptr = NULL;
+ dict = _PyDictOrValues_GetDict(*dorv_ptr);
}
}
else {
- dictptr = _PyObject_DictPointer(obj);
+ PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
if (dictptr) {
dict = *dictptr;
}
@@ -1389,27 +1393,34 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
}
if (dict == NULL) {
- if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) && *_PyObject_ValuesPointer(obj)) {
- res = _PyObject_StoreInstanceAttribute(obj, *_PyObject_ValuesPointer(obj), name, value);
+ PyObject **dictptr;
+ if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT)) {
+ PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ res = _PyObject_StoreInstanceAttribute(
+ obj, _PyDictOrValues_GetValues(*dorv_ptr), name, value);
+ goto error_check;
+ }
+ dictptr = &dorv_ptr->dict;
}
else {
- PyObject **dictptr = _PyObject_DictPointer(obj);
- if (dictptr == NULL) {
- if (descr == NULL) {
- PyErr_Format(PyExc_AttributeError,
- "'%.100s' object has no attribute '%U'",
- tp->tp_name, name);
- }
- else {
- PyErr_Format(PyExc_AttributeError,
- "'%.50s' object attribute '%U' is read-only",
- tp->tp_name, name);
- }
- goto done;
+ dictptr = _PyObject_ComputedDictPointer(obj);
+ }
+ if (dictptr == NULL) {
+ if (descr == NULL) {
+ PyErr_Format(PyExc_AttributeError,
+ "'%.100s' object has no attribute '%U'",
+ tp->tp_name, name);
}
else {
- res = _PyObjectDict_SetItem(tp, dictptr, name, value);
+ PyErr_Format(PyExc_AttributeError,
+ "'%.50s' object attribute '%U' is read-only",
+ tp->tp_name, name);
}
+ goto done;
+ }
+ else {
+ res = _PyObjectDict_SetItem(tp, dictptr, name, value);
}
}
else {
@@ -1420,6 +1431,7 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
res = PyDict_SetItem(dict, name, value);
Py_DECREF(dict);
}
+ error_check:
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) {
if (PyType_IsSubtype(tp, &PyType_Type)) {
PyErr_Format(PyExc_AttributeError,
@@ -1451,7 +1463,7 @@ PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context)
PyObject **dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) {
if (_PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_MANAGED_DICT) &&
- *_PyObject_ValuesPointer(obj) != NULL)
+ _PyDictOrValues_IsValues(*_PyObject_DictOrValuesPointer(obj)))
{
/* Was unable to convert to dict */
PyErr_NoMemory();
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index e4adf1c..d33befc0 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -1310,15 +1310,13 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg)
}
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- assert(type->tp_dictoffset);
- int err = _PyObject_VisitInstanceAttributes(self, visit, arg);
+ int err = _PyObject_VisitManagedDict(self, visit, arg);
if (err) {
return err;
}
}
-
- if (type->tp_dictoffset != base->tp_dictoffset) {
- PyObject **dictptr = _PyObject_DictPointer(self);
+ else if (type->tp_dictoffset != base->tp_dictoffset) {
+ PyObject **dictptr = _PyObject_ComputedDictPointer(self);
if (dictptr && *dictptr)
Py_VISIT(*dictptr);
}
@@ -1379,10 +1377,10 @@ subtype_clear(PyObject *self)
/* Clear the instance dict (if any), to break cycles involving only
__dict__ slots (as in the case 'self.__dict__ is self'). */
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- _PyObject_ClearInstanceAttributes(self);
+ _PyObject_ClearManagedDict(self);
}
- if (type->tp_dictoffset != base->tp_dictoffset) {
- PyObject **dictptr = _PyObject_DictPointer(self);
+ else if (type->tp_dictoffset != base->tp_dictoffset) {
+ PyObject **dictptr = _PyObject_ComputedDictPointer(self);
if (dictptr && *dictptr)
Py_CLEAR(*dictptr);
}
@@ -1526,18 +1524,17 @@ subtype_dealloc(PyObject *self)
/* If we added a dict, DECREF it, or free inline values. */
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- PyObject **dictptr = _PyObject_ManagedDictPointer(self);
- if (*dictptr != NULL) {
- assert(*_PyObject_ValuesPointer(self) == NULL);
- Py_DECREF(*dictptr);
- *dictptr = NULL;
+ PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(self);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ _PyObject_FreeInstanceAttributes(self);
}
else {
- _PyObject_FreeInstanceAttributes(self);
+ Py_XDECREF(_PyDictOrValues_GetDict(*dorv_ptr));
}
+ dorv_ptr->values = NULL;
}
else if (type->tp_dictoffset && !base->tp_dictoffset) {
- PyObject **dictptr = _PyObject_DictPointer(self);
+ PyObject **dictptr = _PyObject_ComputedDictPointer(self);
if (dictptr != NULL) {
PyObject *dict = *dictptr;
if (dict != NULL) {
@@ -5137,7 +5134,9 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
* so we must materialize the dictionary first. */
assert((oldto->tp_flags & Py_TPFLAGS_MANAGED_DICT) == (newto->tp_flags & Py_TPFLAGS_MANAGED_DICT));
_PyObject_GetDictPtr(self);
- if (oldto->tp_flags & Py_TPFLAGS_MANAGED_DICT && *_PyObject_ValuesPointer(self)) {
+ if (oldto->tp_flags & Py_TPFLAGS_MANAGED_DICT &&
+ _PyDictOrValues_IsValues(*_PyObject_DictOrValuesPointer(self)))
+ {
/* Was unable to convert to dict */
PyErr_NoMemory();
return -1;