mirror of https://github.com/python/cpython
gh-94673: Recover Weaklist Lookup Performance (gh-95544)
gh-95302 seems to have introduced a small performance regression. Here we make some minor changes to recover that lost performance.
This commit is contained in:
parent
60f54d9485
commit
bdbadb905a
|
@ -217,6 +217,16 @@ extern void _Py_PrintReferences(FILE *);
|
|||
extern void _Py_PrintReferenceAddresses(FILE *);
|
||||
#endif
|
||||
|
||||
|
||||
/* Return the *address* of the object's weaklist. The address may be
|
||||
* dereferenced to get the current head of the weaklist. This is useful
|
||||
* for iterating over the linked list of weakrefs, especially when the
|
||||
* list is being modified externally (e.g. refs getting removed).
|
||||
*
|
||||
* The returned pointer should not be used to change the head of the list
|
||||
* nor should it be used to add, remove, or swap any refs in the list.
|
||||
* That is the sole responsibility of the code in weakrefobject.c.
|
||||
*/
|
||||
static inline PyObject **
|
||||
_PyObject_GET_WEAKREFS_LISTPTR(PyObject *op)
|
||||
{
|
||||
|
@ -226,10 +236,33 @@ _PyObject_GET_WEAKREFS_LISTPTR(PyObject *op)
|
|||
(PyTypeObject *)op);
|
||||
return _PyStaticType_GET_WEAKREFS_LISTPTR(state);
|
||||
}
|
||||
// Essentially _PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET():
|
||||
Py_ssize_t offset = Py_TYPE(op)->tp_weaklistoffset;
|
||||
return (PyObject **)((char *)op + offset);
|
||||
}
|
||||
|
||||
/* This is a special case of _PyObject_GET_WEAKREFS_LISTPTR().
|
||||
* Only the most fundamental lookup path is used.
|
||||
* Consequently, static types should not be used.
|
||||
*
|
||||
* For static builtin types the returned pointer will always point
|
||||
* to a NULL tp_weaklist. This is fine for any deallocation cases,
|
||||
* since static types are never deallocated and static builtin types
|
||||
* are only finalized at the end of runtime finalization.
|
||||
*
|
||||
* If the weaklist for static types is actually needed then use
|
||||
* _PyObject_GET_WEAKREFS_LISTPTR().
|
||||
*/
|
||||
static inline PyWeakReference **
|
||||
_PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET(PyObject *op)
|
||||
{
|
||||
assert(!PyType_Check(op) ||
|
||||
((PyTypeObject *)op)->tp_flags & Py_TPFLAGS_HEAPTYPE);
|
||||
Py_ssize_t offset = Py_TYPE(op)->tp_weaklistoffset;
|
||||
return (PyWeakReference **)((char *)op + offset);
|
||||
}
|
||||
|
||||
|
||||
// Fast inlined version of PyObject_IS_GC()
|
||||
static inline int
|
||||
_PyObject_IS_GC(PyObject *obj)
|
||||
|
|
|
@ -794,9 +794,12 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
|
|||
if (! _PyType_SUPPORTS_WEAKREFS(Py_TYPE(op)))
|
||||
continue;
|
||||
|
||||
/* It supports weakrefs. Does it have any? */
|
||||
wrlist = (PyWeakReference **)
|
||||
_PyObject_GET_WEAKREFS_LISTPTR(op);
|
||||
/* It supports weakrefs. Does it have any?
|
||||
*
|
||||
* This is never triggered for static types so we can avoid the
|
||||
* (slightly) more costly _PyObject_GET_WEAKREFS_LISTPTR().
|
||||
*/
|
||||
wrlist = _PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET(op);
|
||||
|
||||
/* `op` may have some weakrefs. March over the list, clear
|
||||
* all the weakrefs, and move the weakrefs with callbacks
|
||||
|
|
|
@ -1505,11 +1505,15 @@ subtype_dealloc(PyObject *self)
|
|||
finalizers since they might rely on part of the object
|
||||
being finalized that has already been destroyed. */
|
||||
if (type->tp_weaklistoffset && !base->tp_weaklistoffset) {
|
||||
/* Modeled after GET_WEAKREFS_LISTPTR() */
|
||||
PyWeakReference **list = (PyWeakReference **) \
|
||||
_PyObject_GET_WEAKREFS_LISTPTR(self);
|
||||
while (*list)
|
||||
/* Modeled after GET_WEAKREFS_LISTPTR().
|
||||
|
||||
This is never triggered for static types so we can avoid the
|
||||
(slightly) more costly _PyObject_GET_WEAKREFS_LISTPTR(). */
|
||||
PyWeakReference **list = \
|
||||
_PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET(self);
|
||||
while (*list) {
|
||||
_PyWeakref_ClearRef(*list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue