diff options
author | Sam Gross <colesbury@gmail.com> | 2024-09-12 16:37:06 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-12 16:37:06 (GMT) |
commit | b2afe2aae487ebf89897e22c01d9095944fd334f (patch) | |
tree | 3ffa3ebfe3c69cd21968ce76d8d7cb2f325ff6d3 /Include | |
parent | 4ed7d1d6acc22807bfb5983c98fd59f7cb5061db (diff) | |
download | cpython-b2afe2aae487ebf89897e22c01d9095944fd334f.zip cpython-b2afe2aae487ebf89897e22c01d9095944fd334f.tar.gz cpython-b2afe2aae487ebf89897e22c01d9095944fd334f.tar.bz2 |
gh-123923: Defer refcounting for `f_executable` in `_PyInterpreterFrame` (#123924)
Use a `_PyStackRef` and defer the reference to `f_executable` when
possible. This avoids some reference count contention in the common case
of executing the same code object from multiple threads concurrently in
the free-threaded build.
Diffstat (limited to 'Include')
-rw-r--r-- | Include/internal/pycore_frame.h | 13 | ||||
-rw-r--r-- | Include/internal/pycore_gc.h | 3 | ||||
-rw-r--r-- | Include/internal/pycore_stackref.h | 12 |
3 files changed, 22 insertions, 6 deletions
diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index a6f7c17..a776581 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -60,7 +60,7 @@ enum _frameowner { }; typedef struct _PyInterpreterFrame { - PyObject *f_executable; /* Strong reference (code object or None) */ + _PyStackRef f_executable; /* Deferred or strong reference (code object or None) */ struct _PyInterpreterFrame *previous; PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */ PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */ @@ -79,8 +79,9 @@ typedef struct _PyInterpreterFrame { ((int)((IF)->instr_ptr - _PyCode_CODE(_PyFrame_GetCode(IF)))) static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { - assert(PyCode_Check(f->f_executable)); - return (PyCodeObject *)f->f_executable; + PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); + assert(PyCode_Check(executable)); + return (PyCodeObject *)executable; } static inline _PyStackRef *_PyFrame_Stackbase(_PyInterpreterFrame *f) { @@ -130,7 +131,7 @@ static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame * dest->previous = NULL; #ifdef Py_GIL_DISABLED - PyCodeObject *co = (PyCodeObject *)dest->f_executable; + PyCodeObject *co = _PyFrame_GetCode(dest); for (int i = stacktop; i < co->co_nlocalsplus + co->co_stacksize; i++) { dest->localsplus[i] = PyStackRef_NULL; } @@ -148,7 +149,7 @@ _PyFrame_Initialize( { frame->previous = previous; frame->f_funcobj = (PyObject *)func; - frame->f_executable = Py_NewRef(code); + frame->f_executable = PyStackRef_FromPyObjectNew(code); frame->f_builtins = func->func_builtins; frame->f_globals = func->func_globals; frame->f_locals = locals; @@ -321,7 +322,7 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int assert(tstate->datastack_top < tstate->datastack_limit); frame->previous = previous; frame->f_funcobj = Py_None; - frame->f_executable = Py_NewRef(code); + frame->f_executable = PyStackRef_FromPyObjectNew(code); #ifdef Py_DEBUG frame->f_builtins = NULL; frame->f_globals = NULL; diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 89f6017..b674313 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -381,8 +381,11 @@ extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp); extern void _Py_ScheduleGC(PyThreadState *tstate); extern void _Py_RunGC(PyThreadState *tstate); +union _PyStackRef; + // GC visit callback for tracked interpreter frames extern int _PyGC_VisitFrameStack(struct _PyInterpreterFrame *frame, visitproc visit, void *arg); +extern int _PyGC_VisitStackRef(union _PyStackRef *ref, visitproc visit, void *arg); #ifdef __cplusplus } diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index 7c10657..f23f641 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -227,6 +227,13 @@ PyStackRef_DUP(_PyStackRef stackref) # define PyStackRef_DUP(stackref) PyStackRef_FromPyObjectSteal(Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref))) #endif +// Convert a possibly deferred reference to a strong reference. +static inline _PyStackRef +PyStackRef_AsStrongReference(_PyStackRef stackref) +{ + return PyStackRef_FromPyObjectSteal(PyStackRef_AsPyObjectSteal(stackref)); +} + static inline void _PyObjectStack_FromStackRefStack(PyObject **dst, const _PyStackRef *src, size_t length) { @@ -261,6 +268,11 @@ PyStackRef_ExceptionInstanceCheck(_PyStackRef stackref) return PyExceptionInstance_Check(PyStackRef_AsPyObjectBorrow(stackref)); } +static inline bool +PyStackRef_CodeCheck(_PyStackRef stackref) +{ + return PyCode_Check(PyStackRef_AsPyObjectBorrow(stackref)); +} static inline bool PyStackRef_FunctionCheck(_PyStackRef stackref) |