GH-95245: Store object values and dict pointers in single tagged pointer. (GH-95278)

This commit is contained in:
Mark Shannon 2022-08-01 14:34:54 +01:00 committed by GitHub
parent fb75d015f4
commit de388c0a7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 271 additions and 203 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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 *);

View File

@ -0,0 +1,2 @@
Merge managed dict and values pointer into a single tagged pointer to save
one word in the pre-header.

View File

@ -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__");

View File

@ -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);
return _PyObject_ComputedDictPointer(obj);
}
PyObject **dict_ptr = _PyObject_ManagedDictPointer(obj);
PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
if (*values_ptr == NULL) {
return dict_ptr;
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;
}
assert(*dict_ptr == NULL);
PyObject *dict = _PyObject_MakeDictFromInstanceAttributes(obj, *values_ptr);
if (dict == NULL) {
PyErr_Clear();
return NULL;
}
*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;
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 = attr;
Py_XDECREF(descr);
return 0;
}
dict = NULL;
}
else {
dict = dorv_ptr->dict;
}
}
else {
PyObject **dictptr = _PyObject_DictPointer(obj);
PyObject *dict;
if (dictptr != NULL && (dict = *dictptr) != 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;
}
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();

View File

@ -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;
}
else {
PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(self);
if (_PyDictOrValues_IsValues(*dorv_ptr)) {
_PyObject_FreeInstanceAttributes(self);
}
else {
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;

View File

@ -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);

View File

@ -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 {

View File

@ -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: