Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add ht_module to classes
Also adds PyType_FromModuleAndSpec constructor
  • Loading branch information
Marcel Plch authored and encukou committed May 5, 2020
commit 0741598ebc32334a2aa91ef8f7ae9c9a12df053d
1 change: 1 addition & 0 deletions Include/cpython/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ typedef struct _heaptypeobject {
PyBufferProcs as_buffer;
PyObject *ht_name, *ht_slots, *ht_qualname;
struct _dictkeysobject *ht_cached_keys;
PyObject *ht_module;
/* here are optional user slots, followed by the members. */
} PyHeapTypeObject;

Expand Down
3 changes: 3 additions & 0 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ PyAPI_FUNC(PyObject*) PyType_FromSpecWithBases(PyType_Spec*, PyObject*);
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000
PyAPI_FUNC(void*) PyType_GetSlot(PyTypeObject*, int);
#endif
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000
PyAPI_FUNC(PyObject*) PyType_FromModuleAndSpec(PyObject *, PyType_Spec *, PyObject *);
#endif

/* Generic type check */
PyAPI_FUNC(int) PyType_IsSubtype(PyTypeObject *, PyTypeObject *);
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -1322,7 +1322,7 @@ def delx(self): del self.__x
'3P' # PyMappingMethods
'10P' # PySequenceMethods
'2P' # PyBufferProcs
'4P')
'5P')
class newstyleclass(object): pass
# Separate block for PyDictKeysObject with 8 keys and 5 entries
check(newstyleclass, s + calcsize("2nP2n0P") + 8 + 5*calcsize("n2P"))
Expand Down
29 changes: 25 additions & 4 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2690,6 +2690,9 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
if (qualname != NULL && _PyDict_DelItemId(dict, &PyId___qualname__) < 0)
goto error;

/* Set ht_module */
et->ht_module = NULL;

/* Set tp_doc to a copy of dict['__doc__'], if the latter is there
and is a string. The __doc__ accessor will first look for tp_doc;
if that fails, it will still look into __dict__.
Expand Down Expand Up @@ -2921,6 +2924,12 @@ PyType_FromSpec_tp_traverse(PyObject *self, visitproc visit, void *arg)

PyObject *
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
{
return PyType_FromModuleAndSpec(NULL, spec, bases);
}

PyObject *
PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
{
PyHeapTypeObject *res;
PyObject *modname;
Expand Down Expand Up @@ -2980,6 +2989,9 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
Py_INCREF(res->ht_qualname);
type->tp_name = spec->name;

Py_XINCREF(module);
res->ht_module = module;

/* Adjust for empty tuple bases */
if (!bases) {
base = &PyBaseObject_Type;
Expand Down Expand Up @@ -3480,8 +3492,10 @@ type_dealloc(PyTypeObject *type)
Py_XDECREF(et->ht_name);
Py_XDECREF(et->ht_qualname);
Py_XDECREF(et->ht_slots);
if (et->ht_cached_keys)
if (et->ht_cached_keys) {
_PyDictKeys_DecRef(et->ht_cached_keys);
}
Py_XDECREF(et->ht_module);
Py_TYPE(type)->tp_free((PyObject *)type);
}

Expand Down Expand Up @@ -3671,6 +3685,7 @@ type_traverse(PyTypeObject *type, visitproc visit, void *arg)
Py_VISIT(type->tp_mro);
Py_VISIT(type->tp_bases);
Py_VISIT(type->tp_base);
Py_VISIT(((PyHeapTypeObject *)type)->ht_module);

/* There's no need to visit type->tp_subclasses or
((PyHeapTypeObject *)type)->ht_slots, because they can't be involved
Expand All @@ -3692,10 +3707,13 @@ type_clear(PyTypeObject *type)
the dict, so that other objects caught in a reference cycle
don't start calling destroyed methods.

Otherwise, the only field we need to clear is tp_mro, which is
Otherwise, the we need to clear tp_mro, which is
part of a hard cycle (its first element is the class itself) that
won't be broken otherwise (it's a tuple and tuples don't have a
tp_clear handler). None of the other fields need to be
tp_clear handler).
We also need to clear ht_module, if present: the module usually holds a
reference to its class. None of the other fields need to be

cleared, and here's why:

tp_cache:
Expand All @@ -3720,8 +3738,11 @@ type_clear(PyTypeObject *type)
((PyHeapTypeObject *)type)->ht_cached_keys = NULL;
_PyDictKeys_DecRef(cached_keys);
}
if (type->tp_dict)
if (type->tp_dict) {
PyDict_Clear(type->tp_dict);
}
Py_CLEAR(((PyHeapTypeObject *)type)->ht_module);

Py_CLEAR(type->tp_mro);

return 0;
Expand Down