From d367d4c14597f28118008bda8289f625b09b6a86 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Nov 2026 15:45:29 +0100 Subject: [PATCH] gh-160147: Inline PyObject_IS_GC() in _PyObject_GC_MAY_BE_TRACKED() Move _PyType_IS_GC() and _PyObject_IS_GC() from pycore_object.h to pycore_gc.h. Replace PyObject_IS_GC() call with _PyObject_IS_GC() in _PyObject_GC_MAY_BE_TRACKED(). Help the compiler to inline _PyObject_IS_GC() code in _PyObject_GC_MAY_BE_TRACKED(), especially when LTO is not used. --- Include/internal/pycore_gc.h | 18 +++++++++++++++++- Include/internal/pycore_object.h | 12 ------------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 84cbb56a919215..33f94c0a0ad0b0 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -80,10 +80,26 @@ static inline int _PyObject_GC_IS_TRACKED(PyObject *op) { } #define _PyObject_GC_IS_TRACKED(op) _PyObject_GC_IS_TRACKED(_Py_CAST(PyObject*, op)) +// Fast inlined version of PyType_IS_GC() +static inline int +_PyType_IS_GC(PyTypeObject *type) +{ + return (type->tp_flags & Py_TPFLAGS_HAVE_GC) != 0; +} + +// Fast inlined version of PyObject_IS_GC() +static inline int +_PyObject_IS_GC(PyObject *obj) +{ + PyTypeObject *type = Py_TYPE(obj); + return (_PyType_IS_GC(type) + && (type->tp_is_gc == NULL || type->tp_is_gc(obj))); +} + /* True if the object may be tracked by the GC in the future, or already is. This can be useful to implement some optimizations. */ static inline int _PyObject_GC_MAY_BE_TRACKED(PyObject *obj) { - if (!PyObject_IS_GC(obj)) { + if (!_PyObject_IS_GC(obj)) { return 0; } if (PyTuple_CheckExact(obj)) { diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index dbc0ebf994fd1e..f6a71fe0417601 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -816,18 +816,6 @@ _PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET(PyObject *op) return (PyWeakReference **)((char *)op + offset); } -// Fast inlined version of PyType_IS_GC() -#define _PyType_IS_GC(t) _PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) - -// Fast inlined version of PyObject_IS_GC() -static inline int -_PyObject_IS_GC(PyObject *obj) -{ - PyTypeObject *type = Py_TYPE(obj); - return (_PyType_IS_GC(type) - && (type->tp_is_gc == NULL || type->tp_is_gc(obj))); -} - // Fast inlined version of PyObject_Hash(). Dictionaries are very // likely to include string keys (class and instance attributes, // json, ...) so we include a fast path for strings.