-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-124218: Use per-thread refcounts for code objects #125216
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,7 @@ extern "C" { | |
#include "pycore_interp.h" // PyInterpreterState.gc | ||
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_PTR_RELAXED | ||
#include "pycore_pystate.h" // _PyInterpreterState_GET() | ||
#include "pycore_uniqueid.h" // _PyType_IncrefSlow | ||
#include "pycore_uniqueid.h" // _PyObject_ThreadIncrefSlow() | ||
|
||
|
||
#define _Py_IMMORTAL_REFCNT_LOOSE ((_Py_IMMORTAL_REFCNT >> 1) + 1) | ||
|
@@ -311,7 +311,31 @@ extern bool _PyRefchain_IsTraced(PyInterpreterState *interp, PyObject *obj); | |
#ifndef Py_GIL_DISABLED | ||
# define _Py_INCREF_TYPE Py_INCREF | ||
# define _Py_DECREF_TYPE Py_DECREF | ||
# define _Py_INCREF_CODE Py_INCREF | ||
# define _Py_DECREF_CODE Py_DECREF | ||
#else | ||
static inline void | ||
_Py_THREAD_INCREF_OBJECT(PyObject *obj, Py_ssize_t unique_id) | ||
{ | ||
_PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); | ||
|
||
// Unsigned comparison so that `unique_id=-1`, which indicates that | ||
// per-thread refcounting has been disabled on this object, is handled by | ||
// the "else". | ||
if ((size_t)unique_id < (size_t)tstate->refcounts.size) { | ||
# ifdef Py_REF_DEBUG | ||
_Py_INCREF_IncRefTotal(); | ||
# endif | ||
_Py_INCREF_STAT_INC(); | ||
tstate->refcounts.values[unique_id]++; | ||
} | ||
else { | ||
// The slow path resizes the per-thread refcount array if necessary. | ||
// It handles the unique_id=-1 case to keep the inlinable function smaller. | ||
_PyObject_ThreadIncrefSlow(obj, unique_id); | ||
} | ||
} | ||
|
||
static inline void | ||
_Py_INCREF_TYPE(PyTypeObject *type) | ||
{ | ||
|
@@ -328,29 +352,38 @@ _Py_INCREF_TYPE(PyTypeObject *type) | |
# pragma GCC diagnostic push | ||
# pragma GCC diagnostic ignored "-Warray-bounds" | ||
#endif | ||
_Py_THREAD_INCREF_OBJECT((PyObject *)type, ((PyHeapTypeObject *)type)->unique_id); | ||
#if defined(__GNUC__) && __GNUC__ >= 11 | ||
# pragma GCC diagnostic pop | ||
#endif | ||
} | ||
|
||
static inline void | ||
_Py_INCREF_CODE(PyCodeObject *co) | ||
{ | ||
_Py_THREAD_INCREF_OBJECT((PyObject *)co, co->_co_unique_id); | ||
} | ||
|
||
static inline void | ||
_Py_THREAD_DECREF_OBJECT(PyObject *obj, Py_ssize_t unique_id) | ||
{ | ||
_PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); | ||
PyHeapTypeObject *ht = (PyHeapTypeObject *)type; | ||
|
||
// Unsigned comparison so that `unique_id=-1`, which indicates that | ||
// per-thread refcounting has been disabled on this type, is handled by | ||
// per-thread refcounting has been disabled on this object, is handled by | ||
// the "else". | ||
if ((size_t)ht->unique_id < (size_t)tstate->refcounts.size) { | ||
if ((size_t)unique_id < (size_t)tstate->refcounts.size) { | ||
# ifdef Py_REF_DEBUG | ||
_Py_INCREF_IncRefTotal(); | ||
_Py_DECREF_DecRefTotal(); | ||
# endif | ||
_Py_INCREF_STAT_INC(); | ||
tstate->refcounts.values[ht->unique_id]++; | ||
_Py_DECREF_STAT_INC(); | ||
tstate->refcounts.values[unique_id]--; | ||
} | ||
else { | ||
// The slow path resizes the thread-local refcount array if necessary. | ||
// It handles the unique_id=-1 case to keep the inlinable function smaller. | ||
_PyType_IncrefSlow(ht); | ||
// Directly decref the object if the id is not assigned or if | ||
// per-thread refcounting has been disabled on this object. | ||
Py_DECREF(obj); | ||
} | ||
|
||
#if defined(__GNUC__) && __GNUC__ >= 11 | ||
# pragma GCC diagnostic pop | ||
#endif | ||
} | ||
|
||
static inline void | ||
|
@@ -361,25 +394,14 @@ _Py_DECREF_TYPE(PyTypeObject *type) | |
_Py_DECREF_IMMORTAL_STAT_INC(); | ||
return; | ||
} | ||
|
||
_PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); | ||
PyHeapTypeObject *ht = (PyHeapTypeObject *)type; | ||
_Py_THREAD_DECREF_OBJECT((PyObject *)type, ht->unique_id); | ||
} | ||
|
||
// Unsigned comparison so that `unique_id=-1`, which indicates that | ||
// per-thread refcounting has been disabled on this type, is handled by | ||
// the "else". | ||
if ((size_t)ht->unique_id < (size_t)tstate->refcounts.size) { | ||
# ifdef Py_REF_DEBUG | ||
_Py_DECREF_DecRefTotal(); | ||
# endif | ||
_Py_DECREF_STAT_INC(); | ||
tstate->refcounts.values[ht->unique_id]--; | ||
} | ||
else { | ||
// Directly decref the type if the type id is not assigned or if | ||
// per-thread refcounting has been disabled on this type. | ||
Py_DECREF(type); | ||
} | ||
static inline void | ||
_Py_DECREF_CODE(PyCodeObject *co) | ||
{ | ||
_Py_THREAD_DECREF_OBJECT((PyObject *)co, co->_co_unique_id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. assert that co is a code object. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant it to be protect against incorrect casts, anyways it's minor. |
||
} | ||
#endif | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same add assert to check it is codeobject