mirror of https://github.com/python/cpython
GH-95245: Store object values and dict pointers in single tagged pointer. (GH-95278)
This commit is contained in:
parent
fb75d015f4
commit
de388c0a7b
|
@ -83,6 +83,3 @@ typedef struct {
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *) _PyDictView_New(PyObject *, PyTypeObject *);
|
PyAPI_FUNC(PyObject *) _PyDictView_New(PyObject *, PyTypeObject *);
|
||||||
PyAPI_FUNC(PyObject *) _PyDictView_Intersect(PyObject* self, PyObject *other);
|
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);
|
|
||||||
|
|
|
@ -510,3 +510,7 @@ Py_DEPRECATED(3.11) typedef int UsingDeprecatedTrashcanMacro;
|
||||||
#define Py_TRASHCAN_SAFE_END(op) \
|
#define Py_TRASHCAN_SAFE_END(op) \
|
||||||
Py_TRASHCAN_END; \
|
Py_TRASHCAN_END; \
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
|
|
||||||
|
PyAPI_FUNC(int) _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
|
||||||
|
PyAPI_FUNC(void) _PyObject_ClearManagedDict(PyObject *obj);
|
||||||
|
|
|
@ -274,24 +274,49 @@ extern int _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
|
||||||
PyObject * _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
|
PyObject * _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
|
||||||
PyObject *name);
|
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);
|
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 ((uintptr_t)dorv.values) & 1;
|
||||||
return ((PyObject **)obj)-3;
|
}
|
||||||
|
|
||||||
|
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)
|
#define MANAGED_DICT_OFFSET (((int)sizeof(PyObject *))*-3)
|
||||||
|
|
||||||
extern PyObject ** _PyObject_DictPointer(PyObject *);
|
extern PyObject ** _PyObject_ComputedDictPointer(PyObject *);
|
||||||
extern int _PyObject_VisitInstanceAttributes(PyObject *self, visitproc visit, void *arg);
|
extern void _PyObject_FreeInstanceAttributes(PyObject *obj);
|
||||||
extern void _PyObject_ClearInstanceAttributes(PyObject *self);
|
|
||||||
extern void _PyObject_FreeInstanceAttributes(PyObject *self);
|
|
||||||
extern int _PyObject_IsInstanceDictEmpty(PyObject *);
|
extern int _PyObject_IsInstanceDictEmpty(PyObject *);
|
||||||
extern PyObject* _PyType_GetSubclasses(PyTypeObject *);
|
extern PyObject* _PyType_GetSubclasses(PyTypeObject *);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Merge managed dict and values pointer into a single tagged pointer to save
|
||||||
|
one word in the pre-header.
|
|
@ -5368,7 +5368,7 @@ init_inline_values(PyObject *obj, PyTypeObject *tp)
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
values->values[i] = NULL;
|
values->values[i] = NULL;
|
||||||
}
|
}
|
||||||
*_PyObject_ValuesPointer(obj) = values;
|
_PyDictOrValues_SetValues(_PyObject_DictOrValuesPointer(obj), values);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5394,7 +5394,7 @@ _PyObject_InitializeDict(PyObject *obj)
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
PyObject **dictptr = _PyObject_DictPointer(obj);
|
PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
|
||||||
*dictptr = dict;
|
*dictptr = dict;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -5422,7 +5422,6 @@ make_dict_from_instance_attributes(PyDictKeysObject *keys, PyDictValues *values)
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values)
|
_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values)
|
||||||
{
|
{
|
||||||
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
|
||||||
PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
|
PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
|
||||||
OBJECT_STAT_INC(dict_materialized_on_request);
|
OBJECT_STAT_INC(dict_materialized_on_request);
|
||||||
return make_dict_from_instance_attributes(keys, values);
|
return make_dict_from_instance_attributes(keys, values);
|
||||||
|
@ -5458,8 +5457,7 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*_PyObject_ValuesPointer(obj) = NULL;
|
_PyObject_DictOrValuesPointer(obj)->dict = dict;
|
||||||
*_PyObject_ManagedDictPointer(obj) = dict;
|
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
return PyDict_DelItem(dict, name);
|
return PyDict_DelItem(dict, name);
|
||||||
}
|
}
|
||||||
|
@ -5488,6 +5486,37 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
|
||||||
return 0;
|
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 *
|
||||||
_PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
|
_PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
|
||||||
PyObject *name)
|
PyObject *name)
|
||||||
|
@ -5511,105 +5540,94 @@ _PyObject_IsInstanceDictEmpty(PyObject *obj)
|
||||||
if (tp->tp_dictoffset == 0) {
|
if (tp->tp_dictoffset == 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
PyObject **dictptr;
|
PyObject *dict;
|
||||||
if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
||||||
PyDictValues *values = *_PyObject_ValuesPointer(obj);
|
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj);
|
||||||
if (values) {
|
if (_PyDictOrValues_IsValues(dorv)) {
|
||||||
PyDictKeysObject *keys = CACHED_KEYS(tp);
|
PyDictKeysObject *keys = CACHED_KEYS(tp);
|
||||||
for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
|
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 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
dictptr = _PyObject_ManagedDictPointer(obj);
|
dict = _PyDictOrValues_GetDict(dorv);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dictptr = _PyObject_DictPointer(obj);
|
PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
|
||||||
|
dict = *dictptr;
|
||||||
}
|
}
|
||||||
PyObject *dict = *dictptr;
|
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return ((PyDictObject *)dict)->ma_used == 0;
|
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
|
void
|
||||||
_PyObject_FreeInstanceAttributes(PyObject *self)
|
_PyObject_FreeInstanceAttributes(PyObject *self)
|
||||||
{
|
{
|
||||||
PyTypeObject *tp = Py_TYPE(self);
|
PyTypeObject *tp = Py_TYPE(self);
|
||||||
assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
||||||
PyDictValues **values_ptr = _PyObject_ValuesPointer(self);
|
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
|
||||||
if (*values_ptr == NULL) {
|
if (!_PyDictOrValues_IsValues(dorv)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
PyDictValues *values = _PyDictOrValues_GetValues(dorv);
|
||||||
PyDictKeysObject *keys = CACHED_KEYS(tp);
|
PyDictKeysObject *keys = CACHED_KEYS(tp);
|
||||||
for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
|
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
|
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) {
|
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
assert(tp->tp_dictoffset);
|
assert(tp->tp_dictoffset);
|
||||||
int err = _PyObject_VisitInstanceAttributes(self, visit, arg);
|
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj);
|
||||||
if (err) {
|
if (_PyDictOrValues_IsValues(dorv)) {
|
||||||
return err;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
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) {
|
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_PyObject_FreeInstanceAttributes(self);
|
PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
|
||||||
*_PyObject_ValuesPointer(self) = NULL;
|
if (_PyDictOrValues_IsValues(*dorv_ptr)) {
|
||||||
Py_CLEAR(*_PyObject_ManagedDictPointer(self));
|
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 *
|
PyObject *
|
||||||
|
@ -5618,25 +5636,26 @@ PyObject_GenericGetDict(PyObject *obj, void *context)
|
||||||
PyObject *dict;
|
PyObject *dict;
|
||||||
PyTypeObject *tp = Py_TYPE(obj);
|
PyTypeObject *tp = Py_TYPE(obj);
|
||||||
if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) {
|
if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) {
|
||||||
PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
|
PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
|
||||||
PyObject **dictptr = _PyObject_ManagedDictPointer(obj);
|
if (_PyDictOrValues_IsValues(*dorv_ptr)) {
|
||||||
if (*values_ptr) {
|
PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
|
||||||
assert(*dictptr == NULL);
|
|
||||||
OBJECT_STAT_INC(dict_materialized_on_request);
|
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) {
|
if (dict != NULL) {
|
||||||
*values_ptr = NULL;
|
dorv_ptr->dict = dict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (*dictptr == NULL) {
|
|
||||||
*dictptr = dict = PyDict_New();
|
|
||||||
}
|
|
||||||
else {
|
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 {
|
else {
|
||||||
PyObject **dictptr = _PyObject_DictPointer(obj);
|
PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
|
||||||
if (dictptr == NULL) {
|
if (dictptr == NULL) {
|
||||||
PyErr_SetString(PyExc_AttributeError,
|
PyErr_SetString(PyExc_AttributeError,
|
||||||
"This object has no __dict__");
|
"This object has no __dict__");
|
||||||
|
|
170
Objects/object.c
170
Objects/object.c
|
@ -1054,14 +1054,12 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject **
|
PyObject **
|
||||||
_PyObject_DictPointer(PyObject *obj)
|
_PyObject_ComputedDictPointer(PyObject *obj)
|
||||||
{
|
{
|
||||||
Py_ssize_t dictoffset;
|
Py_ssize_t dictoffset;
|
||||||
PyTypeObject *tp = Py_TYPE(obj);
|
PyTypeObject *tp = Py_TYPE(obj);
|
||||||
|
|
||||||
if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
assert((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0);
|
||||||
return _PyObject_ManagedDictPointer(obj);
|
|
||||||
}
|
|
||||||
dictoffset = tp->tp_dictoffset;
|
dictoffset = tp->tp_dictoffset;
|
||||||
if (dictoffset == 0)
|
if (dictoffset == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1086,22 +1084,18 @@ PyObject **
|
||||||
_PyObject_GetDictPtr(PyObject *obj)
|
_PyObject_GetDictPtr(PyObject *obj)
|
||||||
{
|
{
|
||||||
if ((Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
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);
|
PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
|
||||||
PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
|
if (_PyDictOrValues_IsValues(*dorv_ptr)) {
|
||||||
if (*values_ptr == NULL) {
|
PyObject *dict = _PyObject_MakeDictFromInstanceAttributes(obj, _PyDictOrValues_GetValues(*dorv_ptr));
|
||||||
return dict_ptr;
|
if (dict == NULL) {
|
||||||
|
PyErr_Clear();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
dorv_ptr->dict = dict;
|
||||||
}
|
}
|
||||||
assert(*dict_ptr == NULL);
|
return &dorv_ptr->dict;
|
||||||
PyObject *dict = _PyObject_MakeDictFromInstanceAttributes(obj, *values_ptr);
|
|
||||||
if (dict == NULL) {
|
|
||||||
PyErr_Clear();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*values_ptr = NULL;
|
|
||||||
*dict_ptr = dict;
|
|
||||||
return dict_ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -1170,36 +1164,46 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyDictValues *values;
|
PyObject *dict;
|
||||||
if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) &&
|
if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT)) {
|
||||||
(values = *_PyObject_ValuesPointer(obj)))
|
PyDictOrValues* dorv_ptr = _PyObject_DictOrValuesPointer(obj);
|
||||||
{
|
if (_PyDictOrValues_IsValues(*dorv_ptr)) {
|
||||||
assert(*_PyObject_DictPointer(obj) == NULL);
|
PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
|
||||||
PyObject *attr = _PyObject_GetInstanceAttribute(obj, values, name);
|
PyObject *attr = _PyObject_GetInstanceAttribute(obj, values, name);
|
||||||
if (attr != NULL) {
|
if (attr != NULL) {
|
||||||
*method = attr;
|
*method = attr;
|
||||||
Py_XDECREF(descr);
|
Py_XDECREF(descr);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
dict = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dict = dorv_ptr->dict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyObject **dictptr = _PyObject_DictPointer(obj);
|
PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
|
||||||
PyObject *dict;
|
if (dictptr != NULL) {
|
||||||
if (dictptr != NULL && (dict = *dictptr) != NULL) {
|
dict = *dictptr;
|
||||||
Py_INCREF(dict);
|
}
|
||||||
PyObject *attr = PyDict_GetItemWithError(dict, name);
|
else {
|
||||||
if (attr != NULL) {
|
dict = NULL;
|
||||||
*method = Py_NewRef(attr);
|
}
|
||||||
Py_DECREF(dict);
|
}
|
||||||
Py_XDECREF(descr);
|
if (dict != NULL) {
|
||||||
return 0;
|
Py_INCREF(dict);
|
||||||
}
|
PyObject *attr = PyDict_GetItemWithError(dict, name);
|
||||||
|
if (attr != NULL) {
|
||||||
|
*method = Py_NewRef(attr);
|
||||||
Py_DECREF(dict);
|
Py_DECREF(dict);
|
||||||
|
Py_XDECREF(descr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Py_DECREF(dict);
|
||||||
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
Py_XDECREF(descr);
|
Py_XDECREF(descr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1243,7 +1247,6 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
|
||||||
PyObject *descr = NULL;
|
PyObject *descr = NULL;
|
||||||
PyObject *res = NULL;
|
PyObject *res = NULL;
|
||||||
descrgetfunc f;
|
descrgetfunc f;
|
||||||
PyObject **dictptr;
|
|
||||||
|
|
||||||
if (!PyUnicode_Check(name)){
|
if (!PyUnicode_Check(name)){
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
@ -1274,30 +1277,31 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) &&
|
if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT)) {
|
||||||
*_PyObject_ValuesPointer(obj))
|
PyDictOrValues* dorv_ptr = _PyObject_DictOrValuesPointer(obj);
|
||||||
{
|
if (_PyDictOrValues_IsValues(*dorv_ptr)) {
|
||||||
PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
|
PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
|
||||||
if (PyUnicode_CheckExact(name)) {
|
if (PyUnicode_CheckExact(name)) {
|
||||||
assert(*_PyObject_DictPointer(obj) == NULL);
|
res = _PyObject_GetInstanceAttribute(obj, values, name);
|
||||||
res = _PyObject_GetInstanceAttribute(obj, *values_ptr, name);
|
if (res != NULL) {
|
||||||
if (res != NULL) {
|
goto done;
|
||||||
goto done;
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dict = _PyObject_MakeDictFromInstanceAttributes(obj, values);
|
||||||
|
if (dict == NULL) {
|
||||||
|
res = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
dorv_ptr->dict = dict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dictptr = _PyObject_DictPointer(obj);
|
dict = _PyDictOrValues_GetDict(*dorv_ptr);
|
||||||
assert(dictptr != NULL && *dictptr == NULL);
|
|
||||||
*dictptr = dict = _PyObject_MakeDictFromInstanceAttributes(obj, *values_ptr);
|
|
||||||
if (dict == NULL) {
|
|
||||||
res = NULL;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
*values_ptr = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dictptr = _PyObject_DictPointer(obj);
|
PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
|
||||||
if (dictptr) {
|
if (dictptr) {
|
||||||
dict = *dictptr;
|
dict = *dictptr;
|
||||||
}
|
}
|
||||||
|
@ -1389,27 +1393,34 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) && *_PyObject_ValuesPointer(obj)) {
|
PyObject **dictptr;
|
||||||
res = _PyObject_StoreInstanceAttribute(obj, *_PyObject_ValuesPointer(obj), name, value);
|
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 {
|
else {
|
||||||
PyObject **dictptr = _PyObject_DictPointer(obj);
|
dictptr = _PyObject_ComputedDictPointer(obj);
|
||||||
if (dictptr == NULL) {
|
}
|
||||||
if (descr == NULL) {
|
if (dictptr == NULL) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
if (descr == NULL) {
|
||||||
"'%.100s' object has no attribute '%U'",
|
PyErr_Format(PyExc_AttributeError,
|
||||||
tp->tp_name, name);
|
"'%.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;
|
|
||||||
}
|
}
|
||||||
else {
|
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 {
|
else {
|
||||||
|
@ -1420,6 +1431,7 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
|
||||||
res = PyDict_SetItem(dict, name, value);
|
res = PyDict_SetItem(dict, name, value);
|
||||||
Py_DECREF(dict);
|
Py_DECREF(dict);
|
||||||
}
|
}
|
||||||
|
error_check:
|
||||||
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) {
|
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) {
|
||||||
if (PyType_IsSubtype(tp, &PyType_Type)) {
|
if (PyType_IsSubtype(tp, &PyType_Type)) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
|
@ -1451,7 +1463,7 @@ PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context)
|
||||||
PyObject **dictptr = _PyObject_GetDictPtr(obj);
|
PyObject **dictptr = _PyObject_GetDictPtr(obj);
|
||||||
if (dictptr == NULL) {
|
if (dictptr == NULL) {
|
||||||
if (_PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_MANAGED_DICT) &&
|
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 */
|
/* Was unable to convert to dict */
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
|
|
|
@ -1310,15 +1310,13 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
||||||
assert(type->tp_dictoffset);
|
int err = _PyObject_VisitManagedDict(self, visit, arg);
|
||||||
int err = _PyObject_VisitInstanceAttributes(self, visit, arg);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (type->tp_dictoffset != base->tp_dictoffset) {
|
||||||
if (type->tp_dictoffset != base->tp_dictoffset) {
|
PyObject **dictptr = _PyObject_ComputedDictPointer(self);
|
||||||
PyObject **dictptr = _PyObject_DictPointer(self);
|
|
||||||
if (dictptr && *dictptr)
|
if (dictptr && *dictptr)
|
||||||
Py_VISIT(*dictptr);
|
Py_VISIT(*dictptr);
|
||||||
}
|
}
|
||||||
|
@ -1379,10 +1377,10 @@ subtype_clear(PyObject *self)
|
||||||
/* Clear the instance dict (if any), to break cycles involving only
|
/* Clear the instance dict (if any), to break cycles involving only
|
||||||
__dict__ slots (as in the case 'self.__dict__ is self'). */
|
__dict__ slots (as in the case 'self.__dict__ is self'). */
|
||||||
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
||||||
_PyObject_ClearInstanceAttributes(self);
|
_PyObject_ClearManagedDict(self);
|
||||||
}
|
}
|
||||||
if (type->tp_dictoffset != base->tp_dictoffset) {
|
else if (type->tp_dictoffset != base->tp_dictoffset) {
|
||||||
PyObject **dictptr = _PyObject_DictPointer(self);
|
PyObject **dictptr = _PyObject_ComputedDictPointer(self);
|
||||||
if (dictptr && *dictptr)
|
if (dictptr && *dictptr)
|
||||||
Py_CLEAR(*dictptr);
|
Py_CLEAR(*dictptr);
|
||||||
}
|
}
|
||||||
|
@ -1526,18 +1524,17 @@ subtype_dealloc(PyObject *self)
|
||||||
|
|
||||||
/* If we added a dict, DECREF it, or free inline values. */
|
/* If we added a dict, DECREF it, or free inline values. */
|
||||||
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
||||||
PyObject **dictptr = _PyObject_ManagedDictPointer(self);
|
PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(self);
|
||||||
if (*dictptr != NULL) {
|
if (_PyDictOrValues_IsValues(*dorv_ptr)) {
|
||||||
assert(*_PyObject_ValuesPointer(self) == NULL);
|
|
||||||
Py_DECREF(*dictptr);
|
|
||||||
*dictptr = NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_PyObject_FreeInstanceAttributes(self);
|
_PyObject_FreeInstanceAttributes(self);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Py_XDECREF(_PyDictOrValues_GetDict(*dorv_ptr));
|
||||||
|
}
|
||||||
|
dorv_ptr->values = NULL;
|
||||||
}
|
}
|
||||||
else if (type->tp_dictoffset && !base->tp_dictoffset) {
|
else if (type->tp_dictoffset && !base->tp_dictoffset) {
|
||||||
PyObject **dictptr = _PyObject_DictPointer(self);
|
PyObject **dictptr = _PyObject_ComputedDictPointer(self);
|
||||||
if (dictptr != NULL) {
|
if (dictptr != NULL) {
|
||||||
PyObject *dict = *dictptr;
|
PyObject *dict = *dictptr;
|
||||||
if (dict != NULL) {
|
if (dict != NULL) {
|
||||||
|
@ -5137,7 +5134,9 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
|
||||||
* so we must materialize the dictionary first. */
|
* so we must materialize the dictionary first. */
|
||||||
assert((oldto->tp_flags & Py_TPFLAGS_MANAGED_DICT) == (newto->tp_flags & Py_TPFLAGS_MANAGED_DICT));
|
assert((oldto->tp_flags & Py_TPFLAGS_MANAGED_DICT) == (newto->tp_flags & Py_TPFLAGS_MANAGED_DICT));
|
||||||
_PyObject_GetDictPtr(self);
|
_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 */
|
/* Was unable to convert to dict */
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -3564,9 +3564,9 @@ handle_eval_breaker:
|
||||||
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
|
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
|
||||||
assert(tp->tp_dictoffset < 0);
|
assert(tp->tp_dictoffset < 0);
|
||||||
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
||||||
PyDictValues *values = *_PyObject_ValuesPointer(owner);
|
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
|
||||||
DEOPT_IF(values == NULL, LOAD_ATTR);
|
DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
|
||||||
res = values->values[cache->index];
|
res = _PyDictOrValues_GetValues(dorv)->values[cache->index];
|
||||||
DEOPT_IF(res == NULL, LOAD_ATTR);
|
DEOPT_IF(res == NULL, LOAD_ATTR);
|
||||||
STAT_INC(LOAD_ATTR, hit);
|
STAT_INC(LOAD_ATTR, hit);
|
||||||
Py_INCREF(res);
|
Py_INCREF(res);
|
||||||
|
@ -3613,7 +3613,9 @@ handle_eval_breaker:
|
||||||
assert(type_version != 0);
|
assert(type_version != 0);
|
||||||
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
|
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
|
||||||
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
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);
|
DEOPT_IF(dict == NULL, LOAD_ATTR);
|
||||||
assert(PyDict_CheckExact((PyObject *)dict));
|
assert(PyDict_CheckExact((PyObject *)dict));
|
||||||
PyObject *name = GETITEM(names, oparg>>1);
|
PyObject *name = GETITEM(names, oparg>>1);
|
||||||
|
@ -3750,12 +3752,13 @@ handle_eval_breaker:
|
||||||
assert(type_version != 0);
|
assert(type_version != 0);
|
||||||
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
|
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
|
||||||
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
||||||
PyDictValues *values = *_PyObject_ValuesPointer(owner);
|
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
|
||||||
DEOPT_IF(values == NULL, STORE_ATTR);
|
DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR);
|
||||||
STAT_INC(STORE_ATTR, hit);
|
STAT_INC(STORE_ATTR, hit);
|
||||||
Py_ssize_t index = cache->index;
|
Py_ssize_t index = cache->index;
|
||||||
STACK_SHRINK(1);
|
STACK_SHRINK(1);
|
||||||
PyObject *value = POP();
|
PyObject *value = POP();
|
||||||
|
PyDictValues *values = _PyDictOrValues_GetValues(dorv);
|
||||||
PyObject *old_value = values->values[index];
|
PyObject *old_value = values->values[index];
|
||||||
values->values[index] = value;
|
values->values[index] = value;
|
||||||
if (old_value == NULL) {
|
if (old_value == NULL) {
|
||||||
|
@ -3778,7 +3781,9 @@ handle_eval_breaker:
|
||||||
assert(type_version != 0);
|
assert(type_version != 0);
|
||||||
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
|
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
|
||||||
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
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);
|
DEOPT_IF(dict == NULL, STORE_ATTR);
|
||||||
assert(PyDict_CheckExact((PyObject *)dict));
|
assert(PyDict_CheckExact((PyObject *)dict));
|
||||||
PyObject *name = GETITEM(names, oparg);
|
PyObject *name = GETITEM(names, oparg);
|
||||||
|
@ -4680,8 +4685,8 @@ handle_eval_breaker:
|
||||||
assert(type_version != 0);
|
assert(type_version != 0);
|
||||||
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
|
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
|
||||||
assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
||||||
PyDictObject *dict = *(PyDictObject**)_PyObject_ManagedDictPointer(self);
|
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
|
||||||
DEOPT_IF(dict != NULL, LOAD_ATTR);
|
DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
|
||||||
PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls;
|
PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls;
|
||||||
DEOPT_IF(self_heap_type->ht_cached_keys->dk_version !=
|
DEOPT_IF(self_heap_type->ht_cached_keys->dk_version !=
|
||||||
read_u32(cache->keys_version), LOAD_ATTR);
|
read_u32(cache->keys_version), LOAD_ATTR);
|
||||||
|
|
|
@ -635,9 +635,8 @@ specialize_dict_access(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
|
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
|
||||||
PyObject **dictptr = _PyObject_ManagedDictPointer(owner);
|
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
|
||||||
PyDictObject *dict = (PyDictObject *)*dictptr;
|
if (_PyDictOrValues_IsValues(dorv)) {
|
||||||
if (dict == NULL) {
|
|
||||||
// Virtual dictionary
|
// Virtual dictionary
|
||||||
PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys;
|
PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys;
|
||||||
assert(PyUnicode_CheckExact(name));
|
assert(PyUnicode_CheckExact(name));
|
||||||
|
@ -652,7 +651,8 @@ specialize_dict_access(
|
||||||
_Py_SET_OPCODE(*instr, values_op);
|
_Py_SET_OPCODE(*instr, values_op);
|
||||||
}
|
}
|
||||||
else {
|
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);
|
SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -995,9 +995,9 @@ PyObject *descr, DescriptorClassification kind)
|
||||||
ObjectDictKind dictkind;
|
ObjectDictKind dictkind;
|
||||||
PyDictKeysObject *keys;
|
PyDictKeysObject *keys;
|
||||||
if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
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;
|
keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
|
||||||
if (dict == NULL) {
|
if (_PyDictOrValues_IsValues(dorv)) {
|
||||||
dictkind = MANAGED_VALUES;
|
dictkind = MANAGED_VALUES;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -489,6 +489,8 @@ class HeapTypeObjectPtr(PyObjectPtr):
|
||||||
dictptr = self._gdbval.cast(_type_char_ptr()) + dictoffset
|
dictptr = self._gdbval.cast(_type_char_ptr()) + dictoffset
|
||||||
PyObjectPtrPtr = PyObjectPtr.get_gdb_type().pointer()
|
PyObjectPtrPtr = PyObjectPtr.get_gdb_type().pointer()
|
||||||
dictptr = dictptr.cast(PyObjectPtrPtr)
|
dictptr = dictptr.cast(PyObjectPtrPtr)
|
||||||
|
if int(dictptr.dereference()) & 1:
|
||||||
|
return None
|
||||||
return PyObjectPtr.from_pyobject_ptr(dictptr.dereference())
|
return PyObjectPtr.from_pyobject_ptr(dictptr.dereference())
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
# Corrupt data somewhere; fail safe
|
# 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
|
has_values = int_from_int(typeobj.field('tp_flags')) & Py_TPFLAGS_MANAGED_DICT
|
||||||
if not has_values:
|
if not has_values:
|
||||||
return None
|
return None
|
||||||
PyDictValuesPtrPtr = gdb.lookup_type("PyDictValues").pointer().pointer()
|
charptrptr_t = _type_char_ptr().pointer()
|
||||||
valuesptr = self._gdbval.cast(PyDictValuesPtrPtr) - 4
|
ptr = self._gdbval.cast(charptrptr_t) - 3
|
||||||
values = valuesptr.dereference()
|
char_ptr = ptr.dereference()
|
||||||
if int(values) == 0:
|
if (int(char_ptr) & 1) == 0:
|
||||||
return None
|
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)
|
return PyKeysValuesPair(self.get_cached_keys(), values)
|
||||||
|
|
||||||
def get_cached_keys(self):
|
def get_cached_keys(self):
|
||||||
|
@ -527,14 +531,15 @@ class HeapTypeObjectPtr(PyObjectPtr):
|
||||||
return ProxyAlreadyVisited('<...>')
|
return ProxyAlreadyVisited('<...>')
|
||||||
visited.add(self.as_address())
|
visited.add(self.as_address())
|
||||||
|
|
||||||
pyop_attr_dict = self.get_attr_dict()
|
|
||||||
keys_values = self.get_keys_values()
|
keys_values = self.get_keys_values()
|
||||||
if keys_values:
|
if keys_values:
|
||||||
attr_dict = keys_values.proxyval(visited)
|
attr_dict = keys_values.proxyval(visited)
|
||||||
elif pyop_attr_dict:
|
|
||||||
attr_dict = pyop_attr_dict.proxyval(visited)
|
|
||||||
else:
|
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()
|
tp_name = self.safe_tp_name()
|
||||||
|
|
||||||
# Class:
|
# Class:
|
||||||
|
|
Loading…
Reference in New Issue