summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2021-12-07 16:02:53 (GMT)
committerGitHub <noreply@github.com>2021-12-07 16:02:53 (GMT)
commit8319114feedd2a5b77378bba24eb9fb2689c5033 (patch)
treeb96bfa2c7b8d36124b713170f421f653360a4b5c /Objects
parentc7e7a4b969b5728d4b4f3c59bf98e1e830d5c6d6 (diff)
downloadcpython-8319114feedd2a5b77378bba24eb9fb2689c5033.zip
cpython-8319114feedd2a5b77378bba24eb9fb2689c5033.tar.gz
cpython-8319114feedd2a5b77378bba24eb9fb2689c5033.tar.bz2
bpo-45947: Place dict and values pointer at fixed (negative) offset just before GC header. (GH-29879)
* Place __dict__ immediately before GC header for plain Python objects. * Fix up lazy dict creation logic to use managed dict pointers. * Manage values pointer, placing them directly before managed dict pointers. * Convert hint-based load/store attr specialization target managed dict classes. * Specialize LOAD_METHOD for managed dict objects. * Remove unsafe _PyObject_GC_Calloc function. * Remove unsafe _PyObject_GC_Malloc() function. * Add comment explaning use of Py_TPFLAGS_MANAGED_DICT.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/dictobject.c86
-rw-r--r--Objects/exceptions.c5
-rw-r--r--Objects/object.c71
-rw-r--r--Objects/typeobject.c113
4 files changed, 131 insertions, 144 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 475d92d..7ce4b90 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -4961,8 +4961,8 @@ static int
init_inline_values(PyObject *obj, PyTypeObject *tp)
{
assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE);
- assert(tp->tp_dictoffset > 0);
- assert(tp->tp_inline_values_offset > 0);
+ // assert(type->tp_dictoffset > 0); -- TO DO Update this assert.
+ assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictKeysObject *keys = CACHED_KEYS(tp);
assert(keys != NULL);
if (keys->dk_usable > 1) {
@@ -4979,7 +4979,7 @@ init_inline_values(PyObject *obj, PyTypeObject *tp)
for (int i = 0; i < size; i++) {
values->values[i] = NULL;
}
- *((PyDictValues **)((char *)obj + tp->tp_inline_values_offset)) = values;
+ *_PyObject_ValuesPointer(obj) = values;
return 0;
}
@@ -4990,7 +4990,7 @@ _PyObject_InitializeDict(PyObject *obj)
if (tp->tp_dictoffset == 0) {
return 0;
}
- if (tp->tp_inline_values_offset) {
+ if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
return init_inline_values(obj, tp);
}
PyObject *dict;
@@ -5032,7 +5032,7 @@ make_dict_from_instance_attributes(PyDictKeysObject *keys, PyDictValues *values)
PyObject *
_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values)
{
- assert(Py_TYPE(obj)->tp_inline_values_offset != 0);
+ assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
return make_dict_from_instance_attributes(keys, values);
}
@@ -5042,10 +5042,10 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
PyObject *name, PyObject *value)
{
assert(PyUnicode_CheckExact(name));
- PyTypeObject *tp = Py_TYPE(obj);
PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
assert(keys != NULL);
assert(values != NULL);
+ assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
int ix = insert_into_dictkeys(keys, name);
if (ix == DKIX_EMPTY) {
if (value == NULL) {
@@ -5056,8 +5056,8 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
if (dict == NULL) {
return -1;
}
- *((PyDictValues **)((char *)obj + tp->tp_inline_values_offset)) = NULL;
- *((PyObject **) ((char *)obj + tp->tp_dictoffset)) = dict;
+ *_PyObject_ValuesPointer(obj) = NULL;
+ *_PyObject_ManagedDictPointer(obj) = dict;
return PyDict_SetItem(dict, name, value);
}
PyObject *old_value = values->values[ix];
@@ -5102,17 +5102,23 @@ _PyObject_IsInstanceDictEmpty(PyObject *obj)
if (tp->tp_dictoffset == 0) {
return 1;
}
- PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
- if (values_ptr && *values_ptr) {
- PyDictKeysObject *keys = CACHED_KEYS(tp);
- for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
- if ((*values_ptr)->values[i] != NULL) {
- return 0;
+ PyObject **dictptr;
+ if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
+ PyDictValues *values = *_PyObject_ValuesPointer(obj);
+ if (values) {
+ PyDictKeysObject *keys = CACHED_KEYS(tp);
+ for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
+ if (values->values[i] != NULL) {
+ return 0;
+ }
}
+ return 1;
}
- return 1;
+ dictptr = _PyObject_ManagedDictPointer(obj);
+ }
+ else {
+ dictptr = _PyObject_DictPointer(obj);
}
- PyObject **dictptr = _PyObject_DictPointer(obj);
PyObject *dict = *dictptr;
if (dict == NULL) {
return 1;
@@ -5125,7 +5131,7 @@ int
_PyObject_VisitInstanceAttributes(PyObject *self, visitproc visit, void *arg)
{
PyTypeObject *tp = Py_TYPE(self);
- assert(tp->tp_inline_values_offset);
+ assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictValues **values_ptr = _PyObject_ValuesPointer(self);
if (*values_ptr == NULL) {
return 0;
@@ -5141,7 +5147,7 @@ void
_PyObject_ClearInstanceAttributes(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
- assert(tp->tp_inline_values_offset);
+ assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictValues **values_ptr = _PyObject_ValuesPointer(self);
if (*values_ptr == NULL) {
return;
@@ -5156,7 +5162,7 @@ void
_PyObject_FreeInstanceAttributes(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
- assert(tp->tp_inline_values_offset);
+ assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictValues **values_ptr = _PyObject_ValuesPointer(self);
if (*values_ptr == NULL) {
return;
@@ -5171,28 +5177,42 @@ _PyObject_FreeInstanceAttributes(PyObject *self)
PyObject *
PyObject_GenericGetDict(PyObject *obj, void *context)
{
- PyObject **dictptr = _PyObject_DictPointer(obj);
- if (dictptr == NULL) {
- PyErr_SetString(PyExc_AttributeError,
- "This object has no __dict__");
- return NULL;
- }
- PyObject *dict = *dictptr;
- if (dict == NULL) {
- PyTypeObject *tp = Py_TYPE(obj);
+ PyObject *dict;
+ PyTypeObject *tp = Py_TYPE(obj);
+ if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) {
PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
- if (values_ptr && *values_ptr) {
+ PyObject **dictptr = _PyObject_ManagedDictPointer(obj);
+ if (*values_ptr) {
+ assert(*dictptr == NULL);
*dictptr = dict = make_dict_from_instance_attributes(CACHED_KEYS(tp), *values_ptr);
if (dict != NULL) {
*values_ptr = NULL;
}
}
- else if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
- dictkeys_incref(CACHED_KEYS(tp));
- *dictptr = dict = new_dict_with_shared_keys(CACHED_KEYS(tp));
+ else if (*dictptr == NULL) {
+ *dictptr = dict = PyDict_New();
}
else {
- *dictptr = dict = PyDict_New();
+ dict = *dictptr;
+ }
+ }
+ else {
+ PyObject **dictptr = _PyObject_DictPointer(obj);
+ if (dictptr == NULL) {
+ PyErr_SetString(PyExc_AttributeError,
+ "This object has no __dict__");
+ return NULL;
+ }
+ dict = *dictptr;
+ if (dict == NULL) {
+ PyTypeObject *tp = Py_TYPE(obj);
+ if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
+ dictkeys_incref(CACHED_KEYS(tp));
+ *dictptr = dict = new_dict_with_shared_keys(CACHED_KEYS(tp));
+ }
+ else {
+ *dictptr = dict = PyDict_New();
+ }
}
}
Py_XINCREF(dict);
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index c99f17a..e1a8c13 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -3484,7 +3484,6 @@ _PyErr_TrySetFromCause(const char *format, ...)
PyObject* msg_prefix;
PyObject *exc, *val, *tb;
PyTypeObject *caught_type;
- PyObject **dictptr;
PyObject *instance_args;
Py_ssize_t num_args, caught_type_size, base_exc_size;
PyObject *new_exc, *new_val, *new_tb;
@@ -3530,9 +3529,7 @@ _PyErr_TrySetFromCause(const char *format, ...)
}
/* Ensure the instance dict is also empty */
- dictptr = _PyObject_GetDictPtr(val);
- if (dictptr != NULL && *dictptr != NULL &&
- PyDict_GET_SIZE(*dictptr) > 0) {
+ if (!_PyObject_IsInstanceDictEmpty(val)) {
/* While we could potentially copy a non-empty instance dictionary
* to the replacement exception, for now we take the more
* conservative path of leaving exceptions with attributes set
diff --git a/Objects/object.c b/Objects/object.c
index 25f5a21..a1c2e16 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1073,6 +1073,9 @@ _PyObject_DictPointer(PyObject *obj)
Py_ssize_t dictoffset;
PyTypeObject *tp = Py_TYPE(obj);
+ if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
+ return _PyObject_ManagedDictPointer(obj);
+ }
dictoffset = tp->tp_dictoffset;
if (dictoffset == 0)
return NULL;
@@ -1096,24 +1099,20 @@ _PyObject_DictPointer(PyObject *obj)
PyObject **
_PyObject_GetDictPtr(PyObject *obj)
{
- PyObject **dict_ptr = _PyObject_DictPointer(obj);
- if (dict_ptr == NULL) {
- return NULL;
- }
- if (*dict_ptr != NULL) {
- return dict_ptr;
+ 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 || *values_ptr == NULL) {
+ if (*values_ptr == NULL) {
return dict_ptr;
}
+ assert(*dict_ptr == NULL);
PyObject *dict = _PyObject_MakeDictFromInstanceAttributes(obj, *values_ptr);
if (dict == NULL) {
PyErr_Clear();
return NULL;
}
- assert(*dict_ptr == NULL);
- assert(*values_ptr != NULL);
*values_ptr = NULL;
*dict_ptr = dict;
return dict_ptr;
@@ -1185,10 +1184,12 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
}
}
}
- PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
- if (values_ptr && *values_ptr) {
+ 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_ptr, name);
+ PyObject *attr = _PyObject_GetInstanceAttribute(obj, values, name);
if (attr != NULL) {
*method = attr;
Py_XDECREF(descr);
@@ -1240,17 +1241,6 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
return 0;
}
-PyDictValues **
-_PyObject_ValuesPointer(PyObject *obj)
-{
- PyTypeObject *tp = Py_TYPE(obj);
- Py_ssize_t offset = tp->tp_inline_values_offset;
- if (offset == 0) {
- return NULL;
- }
- return (PyDictValues **) ((char *)obj + offset);
-}
-
/* Generic GetAttr functions - put these in your tp_[gs]etattro slot. */
PyObject *
@@ -1267,7 +1257,6 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
PyObject *descr = NULL;
PyObject *res = NULL;
descrgetfunc f;
- Py_ssize_t dictoffset;
PyObject **dictptr;
if (!PyUnicode_Check(name)){
@@ -1299,8 +1288,10 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
}
}
if (dict == NULL) {
- PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
- if (values_ptr && *values_ptr) {
+ 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);
@@ -1320,22 +1311,8 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
}
}
else {
- /* Inline _PyObject_DictPointer */
- dictoffset = tp->tp_dictoffset;
- if (dictoffset != 0) {
- if (dictoffset < 0) {
- Py_ssize_t tsize = Py_SIZE(obj);
- if (tsize < 0) {
- tsize = -tsize;
- }
- size_t size = _PyObject_VAR_SIZE(tp, tsize);
- _PyObject_ASSERT(obj, size <= PY_SSIZE_T_MAX);
-
- dictoffset += (Py_ssize_t)size;
- _PyObject_ASSERT(obj, dictoffset > 0);
- _PyObject_ASSERT(obj, dictoffset % SIZEOF_VOID_P == 0);
- }
- dictptr = (PyObject **) ((char *)obj + dictoffset);
+ dictptr = _PyObject_DictPointer(obj);
+ if (dictptr) {
dict = *dictptr;
}
}
@@ -1426,9 +1403,8 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
}
if (dict == NULL) {
- PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
- if (values_ptr && *values_ptr) {
- res = _PyObject_StoreInstanceAttribute(obj, *values_ptr, name, value);
+ if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) && *_PyObject_ValuesPointer(obj)) {
+ res = _PyObject_StoreInstanceAttribute(obj, *_PyObject_ValuesPointer(obj), name, value);
}
else {
PyObject **dictptr = _PyObject_DictPointer(obj);
@@ -1478,8 +1454,9 @@ PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context)
{
PyObject **dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) {
- PyDictValues** values_ptr = _PyObject_ValuesPointer(obj);
- if (values_ptr != NULL && *values_ptr != NULL) {
+ if (_PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_MANAGED_DICT) &&
+ *_PyObject_ValuesPointer(obj) != NULL)
+ {
/* Was unable to convert to dict */
PyErr_NoMemory();
}
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 22e509b..2fd93b6 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -1146,17 +1146,17 @@ _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems)
const size_t size = _PyObject_VAR_SIZE(type, nitems+1);
/* note that we need to add one, for the sentinel */
- if (_PyType_IS_GC(type)) {
- obj = _PyObject_GC_Malloc(size);
- }
- else {
- obj = (PyObject *)PyObject_Malloc(size);
- }
-
- if (obj == NULL) {
+ const size_t presize = _PyType_PreHeaderSize(type);
+ char *alloc = PyObject_Malloc(size + presize);
+ if (alloc == NULL) {
return PyErr_NoMemory();
}
-
+ obj = (PyObject *)(alloc + presize);
+ if (presize) {
+ ((PyObject **)alloc)[0] = NULL;
+ ((PyObject **)alloc)[1] = NULL;
+ _PyObject_GC_Link(obj);
+ }
memset(obj, '\0', size);
if (type->tp_itemsize == 0) {
@@ -1232,7 +1232,7 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg)
assert(base);
}
- if (type->tp_inline_values_offset) {
+ if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
assert(type->tp_dictoffset);
int err = _PyObject_VisitInstanceAttributes(self, visit, arg);
if (err) {
@@ -1301,7 +1301,7 @@ 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_inline_values_offset) {
+ if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
_PyObject_ClearInstanceAttributes(self);
}
if (type->tp_dictoffset != base->tp_dictoffset) {
@@ -1360,6 +1360,8 @@ subtype_dealloc(PyObject *self)
int type_needs_decref = (type->tp_flags & Py_TPFLAGS_HEAPTYPE
&& !(base->tp_flags & Py_TPFLAGS_HEAPTYPE));
+ assert((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0);
+
/* Call the base tp_dealloc() */
assert(basedealloc);
basedealloc(self);
@@ -1445,10 +1447,18 @@ subtype_dealloc(PyObject *self)
}
/* If we added a dict, DECREF it, or free inline values. */
- if (type->tp_inline_values_offset) {
- _PyObject_FreeInstanceAttributes(self);
+ 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 {
+ _PyObject_FreeInstanceAttributes(self);
+ }
}
- if (type->tp_dictoffset && !base->tp_dictoffset) {
+ else if (type->tp_dictoffset && !base->tp_dictoffset) {
PyObject **dictptr = _PyObject_DictPointer(self);
if (dictptr != NULL) {
PyObject *dict = *dictptr;
@@ -2243,18 +2253,10 @@ extra_ivars(PyTypeObject *type, PyTypeObject *base)
return t_size != b_size ||
type->tp_itemsize != base->tp_itemsize;
}
- if (type->tp_inline_values_offset && base->tp_inline_values_offset == 0 &&
- type->tp_inline_values_offset + sizeof(PyDictValues *) == t_size &&
- type->tp_flags & Py_TPFLAGS_HEAPTYPE)
- t_size -= sizeof(PyDictValues *);
if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 &&
type->tp_weaklistoffset + sizeof(PyObject *) == t_size &&
type->tp_flags & Py_TPFLAGS_HEAPTYPE)
t_size -= sizeof(PyObject *);
- if (type->tp_dictoffset && base->tp_dictoffset == 0 &&
- type->tp_dictoffset + sizeof(PyObject *) == t_size &&
- type->tp_flags & Py_TPFLAGS_HEAPTYPE)
- t_size -= sizeof(PyObject *);
return t_size != b_size;
}
@@ -2982,13 +2984,8 @@ type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type)
}
}
- if (ctx->add_dict) {
- if (ctx->base->tp_itemsize) {
- type->tp_dictoffset = -(long)sizeof(PyObject *);
- }
- else {
- type->tp_dictoffset = slotoffset;
- }
+ if (ctx->add_dict && ctx->base->tp_itemsize) {
+ type->tp_dictoffset = -(long)sizeof(PyObject *);
slotoffset += sizeof(PyObject *);
}
@@ -2997,12 +2994,10 @@ type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type)
type->tp_weaklistoffset = slotoffset;
slotoffset += sizeof(PyObject *);
}
- if (type->tp_dictoffset > 0) {
- type->tp_inline_values_offset = slotoffset;
- slotoffset += sizeof(PyDictValues *);
- }
- else {
- type->tp_inline_values_offset = 0;
+ if (ctx->add_dict && ctx->base->tp_itemsize == 0) {
+ assert((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0);
+ type->tp_flags |= Py_TPFLAGS_MANAGED_DICT;
+ type->tp_dictoffset = -slotoffset - sizeof(PyObject *)*3;
}
type->tp_basicsize = slotoffset;
@@ -3206,8 +3201,7 @@ type_new_impl(type_new_ctx *ctx)
// Put the proper slots in place
fixup_slot_dispatchers(type);
- if (type->tp_inline_values_offset) {
- assert(type->tp_dictoffset > 0);
+ if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
PyHeapTypeObject *et = (PyHeapTypeObject*)type;
et->ht_cached_keys = _PyDict_NewKeysForClass();
}
@@ -3594,8 +3588,7 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
if (PyType_Ready(type) < 0)
goto fail;
- if (type->tp_inline_values_offset) {
- assert(type->tp_dictoffset > 0);
+ if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
res->ht_cached_keys = _PyDict_NewKeysForClass();
}
@@ -4658,7 +4651,6 @@ compatible_with_tp_base(PyTypeObject *child)
child->tp_itemsize == parent->tp_itemsize &&
child->tp_dictoffset == parent->tp_dictoffset &&
child->tp_weaklistoffset == parent->tp_weaklistoffset &&
- child->tp_inline_values_offset == parent->tp_inline_values_offset &&
((child->tp_flags & Py_TPFLAGS_HAVE_GC) ==
(parent->tp_flags & Py_TPFLAGS_HAVE_GC)) &&
(child->tp_dealloc == subtype_dealloc ||
@@ -4678,8 +4670,6 @@ same_slots_added(PyTypeObject *a, PyTypeObject *b)
size += sizeof(PyObject *);
if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size)
size += sizeof(PyObject *);
- if (a->tp_inline_values_offset == size && b->tp_inline_values_offset == size)
- size += sizeof(PyObject *);
/* Check slots compliance */
if (!(a->tp_flags & Py_TPFLAGS_HEAPTYPE) ||
@@ -4729,16 +4719,22 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char*
if (newbase != oldbase &&
(newbase->tp_base != oldbase->tp_base ||
!same_slots_added(newbase, oldbase))) {
- PyErr_Format(PyExc_TypeError,
- "%s assignment: "
- "'%s' object layout differs from '%s'",
- attr,
- newto->tp_name,
- oldto->tp_name);
- return 0;
+ goto differs;
}
-
- return 1;
+ /* The above does not check for managed __dicts__ */
+ if ((oldto->tp_flags & Py_TPFLAGS_MANAGED_DICT) ==
+ ((newto->tp_flags & Py_TPFLAGS_MANAGED_DICT)))
+ {
+ return 1;
+ }
+differs:
+ PyErr_Format(PyExc_TypeError,
+ "%s assignment: "
+ "'%s' object layout differs from '%s'",
+ attr,
+ newto->tp_name,
+ oldto->tp_name);
+ return 0;
}
static int
@@ -4826,15 +4822,13 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
if (compatible_for_assignment(oldto, newto, "__class__")) {
/* Changing the class will change the implicit dict keys,
* so we must materialize the dictionary first. */
- assert(oldto->tp_inline_values_offset == newto->tp_inline_values_offset);
+ assert((oldto->tp_flags & Py_TPFLAGS_MANAGED_DICT) == (newto->tp_flags & Py_TPFLAGS_MANAGED_DICT));
_PyObject_GetDictPtr(self);
- PyDictValues** values_ptr = _PyObject_ValuesPointer(self);
- if (values_ptr != NULL && *values_ptr != NULL) {
+ if (oldto->tp_flags & Py_TPFLAGS_MANAGED_DICT && *_PyObject_ValuesPointer(self)) {
/* Was unable to convert to dict */
PyErr_NoMemory();
return -1;
}
- assert(_PyObject_ValuesPointer(self) == NULL || *_PyObject_ValuesPointer(self) == NULL);
if (newto->tp_flags & Py_TPFLAGS_HEAPTYPE) {
Py_INCREF(newto);
}
@@ -4980,15 +4974,14 @@ _PyObject_GetState(PyObject *obj, int required)
assert(slotnames == Py_None || PyList_Check(slotnames));
if (required) {
Py_ssize_t basicsize = PyBaseObject_Type.tp_basicsize;
- if (Py_TYPE(obj)->tp_dictoffset) {
+ if (Py_TYPE(obj)->tp_dictoffset &&
+ (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0)
+ {
basicsize += sizeof(PyObject *);
}
if (Py_TYPE(obj)->tp_weaklistoffset) {
basicsize += sizeof(PyObject *);
}
- if (Py_TYPE(obj)->tp_inline_values_offset) {
- basicsize += sizeof(PyDictValues *);
- }
if (slotnames != Py_None) {
basicsize += sizeof(PyObject *) * PyList_GET_SIZE(slotnames);
}
@@ -5749,6 +5742,7 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
if (type->tp_clear == NULL)
type->tp_clear = base->tp_clear;
}
+ type->tp_flags |= (base->tp_flags & Py_TPFLAGS_MANAGED_DICT);
if (type->tp_basicsize == 0)
type->tp_basicsize = base->tp_basicsize;
@@ -5761,7 +5755,6 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
COPYVAL(tp_itemsize);
COPYVAL(tp_weaklistoffset);
COPYVAL(tp_dictoffset);
- COPYVAL(tp_inline_values_offset);
#undef COPYVAL
/* Setup fast subclass flags */