mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
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
3 changed files with 47 additions and 7 deletions
|
@ -217,6 +217,16 @@ extern void _Py_PrintReferences(FILE *);
|
||||||
extern void _Py_PrintReferenceAddresses(FILE *);
|
extern void _Py_PrintReferenceAddresses(FILE *);
|
||||||
#endif
|
#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 **
|
static inline PyObject **
|
||||||
_PyObject_GET_WEAKREFS_LISTPTR(PyObject *op)
|
_PyObject_GET_WEAKREFS_LISTPTR(PyObject *op)
|
||||||
{
|
{
|
||||||
|
@ -226,10 +236,33 @@ _PyObject_GET_WEAKREFS_LISTPTR(PyObject *op)
|
||||||
(PyTypeObject *)op);
|
(PyTypeObject *)op);
|
||||||
return _PyStaticType_GET_WEAKREFS_LISTPTR(state);
|
return _PyStaticType_GET_WEAKREFS_LISTPTR(state);
|
||||||
}
|
}
|
||||||
|
// Essentially _PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET():
|
||||||
Py_ssize_t offset = Py_TYPE(op)->tp_weaklistoffset;
|
Py_ssize_t offset = Py_TYPE(op)->tp_weaklistoffset;
|
||||||
return (PyObject **)((char *)op + offset);
|
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()
|
// Fast inlined version of PyObject_IS_GC()
|
||||||
static inline int
|
static inline int
|
||||||
_PyObject_IS_GC(PyObject *obj)
|
_PyObject_IS_GC(PyObject *obj)
|
||||||
|
|
|
@ -794,9 +794,12 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
|
||||||
if (! _PyType_SUPPORTS_WEAKREFS(Py_TYPE(op)))
|
if (! _PyType_SUPPORTS_WEAKREFS(Py_TYPE(op)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* It supports weakrefs. Does it have any? */
|
/* It supports weakrefs. Does it have any?
|
||||||
wrlist = (PyWeakReference **)
|
*
|
||||||
_PyObject_GET_WEAKREFS_LISTPTR(op);
|
* 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
|
/* `op` may have some weakrefs. March over the list, clear
|
||||||
* all the weakrefs, and move the weakrefs with callbacks
|
* all the weakrefs, and move the weakrefs with callbacks
|
||||||
|
|
|
@ -1505,13 +1505,17 @@ subtype_dealloc(PyObject *self)
|
||||||
finalizers since they might rely on part of the object
|
finalizers since they might rely on part of the object
|
||||||
being finalized that has already been destroyed. */
|
being finalized that has already been destroyed. */
|
||||||
if (type->tp_weaklistoffset && !base->tp_weaklistoffset) {
|
if (type->tp_weaklistoffset && !base->tp_weaklistoffset) {
|
||||||
/* Modeled after GET_WEAKREFS_LISTPTR() */
|
/* Modeled after GET_WEAKREFS_LISTPTR().
|
||||||
PyWeakReference **list = (PyWeakReference **) \
|
|
||||||
_PyObject_GET_WEAKREFS_LISTPTR(self);
|
This is never triggered for static types so we can avoid the
|
||||||
while (*list)
|
(slightly) more costly _PyObject_GET_WEAKREFS_LISTPTR(). */
|
||||||
|
PyWeakReference **list = \
|
||||||
|
_PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET(self);
|
||||||
|
while (*list) {
|
||||||
_PyWeakref_ClearRef(*list);
|
_PyWeakref_ClearRef(*list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear slots up to the nearest base with a different tp_dealloc */
|
/* Clear slots up to the nearest base with a different tp_dealloc */
|
||||||
base = type;
|
base = type;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue