summaryrefslogtreecommitdiffstats
path: root/Objects/typeobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/typeobject.c')
-rw-r--r--Objects/typeobject.c84
1 files changed, 50 insertions, 34 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 2ef79fb..6df9986 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -1861,7 +1861,7 @@ type_call(PyObject *self, PyObject *args, PyObject *kwds)
PyObject *
_PyType_NewManagedObject(PyTypeObject *type)
{
- assert(type->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+ assert(type->tp_flags & Py_TPFLAGS_INLINE_VALUES);
assert(_PyType_IS_GC(type));
assert(type->tp_new == PyBaseObject_Type.tp_new);
assert(type->tp_alloc == PyType_GenericAlloc);
@@ -1870,11 +1870,6 @@ _PyType_NewManagedObject(PyTypeObject *type)
if (obj == NULL) {
return PyErr_NoMemory();
}
- _PyObject_DictOrValuesPointer(obj)->dict = NULL;
- if (_PyObject_InitInlineValues(obj, type)) {
- Py_DECREF(obj);
- return NULL;
- }
return obj;
}
@@ -1888,9 +1883,13 @@ _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems)
* flag to indicate when that is safe) it does not seem worth the memory
* savings. An example type that doesn't need the +1 is a subclass of
* tuple. See GH-100659 and GH-81381. */
- const size_t size = _PyObject_VAR_SIZE(type, nitems+1);
+ size_t size = _PyObject_VAR_SIZE(type, nitems+1);
const size_t presize = _PyType_PreHeaderSize(type);
+ if (type->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
+ assert(type->tp_itemsize == 0);
+ size += _PyInlineValuesSize(type);
+ }
char *alloc = _PyObject_MallocWithType(type, size + presize);
if (alloc == NULL) {
return PyErr_NoMemory();
@@ -1911,6 +1910,9 @@ _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems)
else {
_PyObject_InitVar((PyVarObject *)obj, type, nitems);
}
+ if (type->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
+ _PyObject_InitInlineValues(obj, type);
+ }
return obj;
}
@@ -2060,6 +2062,10 @@ subtype_clear(PyObject *self)
if ((base->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
PyObject_ClearManagedDict(self);
}
+ else {
+ assert((base->tp_flags & Py_TPFLAGS_INLINE_VALUES) ==
+ (type->tp_flags & Py_TPFLAGS_INLINE_VALUES));
+ }
}
else if (type->tp_dictoffset != base->tp_dictoffset) {
PyObject **dictptr = _PyObject_ComputedDictPointer(self);
@@ -2210,14 +2216,7 @@ subtype_dealloc(PyObject *self)
/* If we added a dict, DECREF it, or free inline values. */
if (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- 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;
+ PyObject_ClearManagedDict(self);
}
else if (type->tp_dictoffset && !base->tp_dictoffset) {
PyObject **dictptr = _PyObject_ComputedDictPointer(self);
@@ -3161,19 +3160,26 @@ subtype_setdict(PyObject *obj, PyObject *value, void *context)
return func(descr, obj, value);
}
/* Almost like PyObject_GenericSetDict, but allow __dict__ to be deleted. */
- dictptr = _PyObject_GetDictPtr(obj);
- if (dictptr == NULL) {
- PyErr_SetString(PyExc_AttributeError,
- "This object has no __dict__");
- return -1;
- }
if (value != NULL && !PyDict_Check(value)) {
PyErr_Format(PyExc_TypeError,
"__dict__ must be set to a dictionary, "
"not a '%.200s'", Py_TYPE(value)->tp_name);
return -1;
}
- Py_XSETREF(*dictptr, Py_XNewRef(value));
+ if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
+ PyObject_ClearManagedDict(obj);
+ _PyObject_ManagedDictPointer(obj)->dict = (PyDictObject *)Py_XNewRef(value);
+ }
+ else {
+ dictptr = _PyObject_ComputedDictPointer(obj);
+ if (dictptr == NULL) {
+ PyErr_SetString(PyExc_AttributeError,
+ "This object has no __dict__");
+ return -1;
+ }
+ Py_CLEAR(*dictptr);
+ *dictptr = Py_XNewRef(value);
+ }
return 0;
}
@@ -5849,10 +5855,6 @@ object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (obj == NULL) {
return NULL;
}
- if (_PyObject_InitializeDict(obj)) {
- Py_DECREF(obj);
- return NULL;
- }
return obj;
}
@@ -6036,6 +6038,11 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char*
!same_slots_added(newbase, oldbase))) {
goto differs;
}
+ if ((oldto->tp_flags & Py_TPFLAGS_INLINE_VALUES) !=
+ ((newto->tp_flags & Py_TPFLAGS_INLINE_VALUES)))
+ {
+ goto differs;
+ }
/* The above does not check for the preheader */
if ((oldto->tp_flags & Py_TPFLAGS_PREHEADER) ==
((newto->tp_flags & Py_TPFLAGS_PREHEADER)))
@@ -6137,14 +6144,18 @@ 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_flags & Py_TPFLAGS_PREHEADER) == (newto->tp_flags & Py_TPFLAGS_PREHEADER));
- _PyObject_GetDictPtr(self);
- if (oldto->tp_flags & Py_TPFLAGS_MANAGED_DICT &&
- _PyDictOrValues_IsValues(*_PyObject_DictOrValuesPointer(self)))
- {
- /* Was unable to convert to dict */
- PyErr_NoMemory();
- return -1;
+ if (oldto->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
+ PyDictObject *dict = _PyObject_ManagedDictPointer(self)->dict;
+ if (dict == NULL) {
+ dict = (PyDictObject *)_PyObject_MakeDictFromInstanceAttributes(self);
+ if (dict == NULL) {
+ return -1;
+ }
+ _PyObject_ManagedDictPointer(self)->dict = dict;
+ }
+ if (_PyDict_DetachFromObject(dict, self)) {
+ return -1;
+ }
}
if (newto->tp_flags & Py_TPFLAGS_HEAPTYPE) {
Py_INCREF(newto);
@@ -7774,6 +7785,9 @@ type_ready_managed_dict(PyTypeObject *type)
return -1;
}
}
+ if (type->tp_itemsize == 0 && type->tp_basicsize == sizeof(PyObject)) {
+ type->tp_flags |= Py_TPFLAGS_INLINE_VALUES;
+ }
return 0;
}
@@ -7901,6 +7915,8 @@ PyType_Ready(PyTypeObject *type)
/* Historically, all static types were immutable. See bpo-43908 */
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
type->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
+ /* Static types must be immortal */
+ _Py_SetImmortalUntracked((PyObject *)type);
}
int res;