summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/cpython/dictobject.h3
-rw-r--r--Include/cpython/object.h4
-rw-r--r--Include/internal/pycore_object.h43
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2022-07-26-12-59-03.gh-issue-95245.GHWczn.rst2
-rw-r--r--Objects/dictobject.c161
-rw-r--r--Objects/object.c168
-rw-r--r--Objects/typeobject.c31
-rw-r--r--Python/ceval.c23
-rw-r--r--Python/specialize.c12
-rwxr-xr-xTools/gdb/libpython.py23
10 files changed, 269 insertions, 201 deletions
diff --git a/Include/cpython/dictobject.h b/Include/cpython/dictobject.h
index c2e4a46..565ad791 100644
--- a/Include/cpython/dictobject.h
+++ b/Include/cpython/dictobject.h
@@ -83,6 +83,3 @@ typedef struct {
PyAPI_FUNC(PyObject *) _PyDictView_New(PyObject *, PyTypeObject *);
PyAPI_FUNC(PyObject *) _PyDictView_Intersect(PyObject* self, PyObject *other);
-
-PyAPI_FUNC(int) _PyObject_VisitManagedDict(PyObject *self, visitproc visit, void *arg);
-PyAPI_FUNC(void) _PyObject_ClearManagedDict(PyObject *self);
diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index 0268033..60c7c3e 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -510,3 +510,7 @@ Py_DEPRECATED(3.11) typedef int UsingDeprecatedTrashcanMacro;
#define Py_TRASHCAN_SAFE_END(op) \
Py_TRASHCAN_END; \
} while(0);
+
+
+PyAPI_FUNC(int) _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
+PyAPI_FUNC(void) _PyObject_ClearManagedDict(PyObject *obj);
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 9f061d8..173d367 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -274,24 +274,49 @@ extern int _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
PyObject * _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
PyObject *name);
-static inline PyDictValues **_PyObject_ValuesPointer(PyObject *obj)
+typedef union {
+ PyObject *dict;
+ /* Use a char* to generate a warning if directly assigning a PyDictValues */
+ char *values;
+} PyDictOrValues;
+
+static inline PyDictOrValues *
+_PyObject_DictOrValuesPointer(PyObject *obj)
{
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- return ((PyDictValues **)obj)-4;
+ return ((PyDictOrValues *)obj)-3;
}
-static inline PyObject **_PyObject_ManagedDictPointer(PyObject *obj)
+static inline int
+_PyDictOrValues_IsValues(PyDictOrValues dorv)
{
- assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- return ((PyObject **)obj)-3;
+ return ((uintptr_t)dorv.values) & 1;
+}
+
+static inline PyDictValues *
+_PyDictOrValues_GetValues(PyDictOrValues dorv)
+{
+ assert(_PyDictOrValues_IsValues(dorv));
+ return (PyDictValues *)(dorv.values + 1);
+}
+
+static inline PyObject *
+_PyDictOrValues_GetDict(PyDictOrValues dorv)
+{
+ assert(!_PyDictOrValues_IsValues(dorv));
+ return dorv.dict;
+}
+
+static inline void
+_PyDictOrValues_SetValues(PyDictOrValues *ptr, PyDictValues *values)
+{
+ ptr->values = ((char *)values) - 1;
}
#define MANAGED_DICT_OFFSET (((int)sizeof(PyObject *))*-3)
-extern PyObject ** _PyObject_DictPointer(PyObject *);
-extern int _PyObject_VisitInstanceAttributes(PyObject *self, visitproc visit, void *arg);
-extern void _PyObject_ClearInstanceAttributes(PyObject *self);
-extern void _PyObject_FreeInstanceAttributes(PyObject *self);
+extern PyObject ** _PyObject_ComputedDictPointer(PyObject *);
+extern void _PyObject_FreeInstanceAttributes(PyObject *obj);
extern int _PyObject_IsInstanceDictEmpty(PyObject *);
extern PyObject* _PyType_GetSubclasses(PyTypeObject *);
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-26-12-59-03.gh-issue-95245.GHWczn.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-26-12-59-03.gh-issue-95245.GHWczn.rst
new file mode 100644
index 0000000..d6dccc8
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-07-26-12-59-03.gh-issue-95245.GHWczn.rst
@@ -0,0 +1,2 @@
+Merge managed dict and values pointer into a single tagged pointer to save
+one word in the pre-header.
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;
diff --git a/Python/ceval.c b/Python/ceval.c
index 7ad26a7..abb934d 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3564,9 +3564,9 @@ handle_eval_breaker:
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
assert(tp->tp_dictoffset < 0);
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictValues *values = *_PyObject_ValuesPointer(owner);
- DEOPT_IF(values == NULL, LOAD_ATTR);
- res = values->values[cache->index];
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
+ res = _PyDictOrValues_GetValues(dorv)->values[cache->index];
DEOPT_IF(res == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
Py_INCREF(res);
@@ -3613,7 +3613,9 @@ handle_eval_breaker:
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictObject *dict = *(PyDictObject **)_PyObject_ManagedDictPointer(owner);
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
+ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv);
DEOPT_IF(dict == NULL, LOAD_ATTR);
assert(PyDict_CheckExact((PyObject *)dict));
PyObject *name = GETITEM(names, oparg>>1);
@@ -3750,12 +3752,13 @@ handle_eval_breaker:
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictValues *values = *_PyObject_ValuesPointer(owner);
- DEOPT_IF(values == NULL, STORE_ATTR);
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR);
STAT_INC(STORE_ATTR, hit);
Py_ssize_t index = cache->index;
STACK_SHRINK(1);
PyObject *value = POP();
+ PyDictValues *values = _PyDictOrValues_GetValues(dorv);
PyObject *old_value = values->values[index];
values->values[index] = value;
if (old_value == NULL) {
@@ -3778,7 +3781,9 @@ handle_eval_breaker:
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictObject *dict = *(PyDictObject **)_PyObject_ManagedDictPointer(owner);
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
+ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv);
DEOPT_IF(dict == NULL, STORE_ATTR);
assert(PyDict_CheckExact((PyObject *)dict));
PyObject *name = GETITEM(names, oparg);
@@ -4680,8 +4685,8 @@ handle_eval_breaker:
assert(type_version != 0);
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictObject *dict = *(PyDictObject**)_PyObject_ManagedDictPointer(self);
- DEOPT_IF(dict != NULL, LOAD_ATTR);
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
+ DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls;
DEOPT_IF(self_heap_type->ht_cached_keys->dk_version !=
read_u32(cache->keys_version), LOAD_ATTR);
diff --git a/Python/specialize.c b/Python/specialize.c
index 53b2ae8..d5877a1 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -635,9 +635,8 @@ specialize_dict_access(
return 0;
}
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
- PyObject **dictptr = _PyObject_ManagedDictPointer(owner);
- PyDictObject *dict = (PyDictObject *)*dictptr;
- if (dict == NULL) {
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+ if (_PyDictOrValues_IsValues(dorv)) {
// Virtual dictionary
PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys;
assert(PyUnicode_CheckExact(name));
@@ -652,7 +651,8 @@ specialize_dict_access(
_Py_SET_OPCODE(*instr, values_op);
}
else {
- if (!PyDict_CheckExact(dict)) {
+ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv);
+ if (dict == NULL || !PyDict_CheckExact(dict)) {
SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT);
return 0;
}
@@ -995,9 +995,9 @@ PyObject *descr, DescriptorClassification kind)
ObjectDictKind dictkind;
PyDictKeysObject *keys;
if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- PyObject *dict = *_PyObject_ManagedDictPointer(owner);
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
- if (dict == NULL) {
+ if (_PyDictOrValues_IsValues(dorv)) {
dictkind = MANAGED_VALUES;
}
else {
diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py
index 80563ea..d03c637 100755
--- a/Tools/gdb/libpython.py
+++ b/Tools/gdb/libpython.py
@@ -489,6 +489,8 @@ class HeapTypeObjectPtr(PyObjectPtr):
dictptr = self._gdbval.cast(_type_char_ptr()) + dictoffset
PyObjectPtrPtr = PyObjectPtr.get_gdb_type().pointer()
dictptr = dictptr.cast(PyObjectPtrPtr)
+ if int(dictptr.dereference()) & 1:
+ return None
return PyObjectPtr.from_pyobject_ptr(dictptr.dereference())
except RuntimeError:
# Corrupt data somewhere; fail safe
@@ -502,12 +504,14 @@ class HeapTypeObjectPtr(PyObjectPtr):
has_values = int_from_int(typeobj.field('tp_flags')) & Py_TPFLAGS_MANAGED_DICT
if not has_values:
return None
- PyDictValuesPtrPtr = gdb.lookup_type("PyDictValues").pointer().pointer()
- valuesptr = self._gdbval.cast(PyDictValuesPtrPtr) - 4
- values = valuesptr.dereference()
- if int(values) == 0:
+ charptrptr_t = _type_char_ptr().pointer()
+ ptr = self._gdbval.cast(charptrptr_t) - 3
+ char_ptr = ptr.dereference()
+ if (int(char_ptr) & 1) == 0:
return None
- values = values['values']
+ char_ptr += 1
+ values_ptr = char_ptr.cast(gdb.lookup_type("PyDictValues").pointer())
+ values = values_ptr['values']
return PyKeysValuesPair(self.get_cached_keys(), values)
def get_cached_keys(self):
@@ -527,14 +531,15 @@ class HeapTypeObjectPtr(PyObjectPtr):
return ProxyAlreadyVisited('<...>')
visited.add(self.as_address())
- pyop_attr_dict = self.get_attr_dict()
keys_values = self.get_keys_values()
if keys_values:
attr_dict = keys_values.proxyval(visited)
- elif pyop_attr_dict:
- attr_dict = pyop_attr_dict.proxyval(visited)
else:
- attr_dict = {}
+ pyop_attr_dict = self.get_attr_dict()
+ if pyop_attr_dict:
+ attr_dict = pyop_attr_dict.proxyval(visited)
+ else:
+ attr_dict = {}
tp_name = self.safe_tp_name()
# Class: