summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-09-24 20:08:18 (GMT)
committerGitHub <noreply@github.com>2024-09-24 20:08:18 (GMT)
commitf4997bb3ac961d6aaf07ce650cd074e28ce6ccd0 (patch)
tree6c82b0fadd282e74c8f81de4a3966666fd210196 /Objects
parentd3c76dff444046504754a437dceebc9a9c87ef18 (diff)
downloadcpython-f4997bb3ac961d6aaf07ce650cd074e28ce6ccd0.zip
cpython-f4997bb3ac961d6aaf07ce650cd074e28ce6ccd0.tar.gz
cpython-f4997bb3ac961d6aaf07ce650cd074e28ce6ccd0.tar.bz2
gh-123923: Defer refcounting for `f_funcobj` in `_PyInterpreterFrame` (#124026)
Use a `_PyStackRef` and defer the reference to `f_funcobj` 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 'Objects')
-rw-r--r--Objects/frameobject.c9
-rw-r--r--Objects/genobject.c5
-rw-r--r--Objects/typevarobject.c4
3 files changed, 8 insertions, 10 deletions
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index b567327..9f1c031 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -1634,7 +1634,7 @@ frame_dealloc(PyFrameObject *f)
/* Kill all local variables including specials, if we own them */
if (f->f_frame == frame && frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) {
PyStackRef_CLEAR(frame->f_executable);
- Py_CLEAR(frame->f_funcobj);
+ PyStackRef_CLEAR(frame->f_funcobj);
Py_CLEAR(frame->f_locals);
_PyStackRef *locals = _PyFrame_GetLocalsArray(frame);
_PyStackRef *sp = frame->stackpointer;
@@ -1790,7 +1790,7 @@ static void
init_frame(_PyInterpreterFrame *frame, PyFunctionObject *func, PyObject *locals)
{
PyCodeObject *code = (PyCodeObject *)func->func_code;
- _PyFrame_Initialize(frame, (PyFunctionObject*)Py_NewRef(func),
+ _PyFrame_Initialize(frame, PyStackRef_FromPyObjectNew(func),
Py_XNewRef(locals), code, 0, NULL);
}
@@ -1861,14 +1861,15 @@ frame_init_get_vars(_PyInterpreterFrame *frame)
PyCodeObject *co = _PyFrame_GetCode(frame);
int lasti = _PyInterpreterFrame_LASTI(frame);
if (!(lasti < 0 && _PyCode_CODE(co)->op.code == COPY_FREE_VARS
- && PyFunction_Check(frame->f_funcobj)))
+ && PyStackRef_FunctionCheck(frame->f_funcobj)))
{
/* Free vars are initialized */
return;
}
/* Free vars have not been initialized -- Do that */
- PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
+ PyFunctionObject *func = _PyFrame_GetFunction(frame);
+ PyObject *closure = func->func_closure;
int offset = PyUnstable_Code_GetFirstFree(co);
for (int i = 0; i < co->co_nfreevars; ++i) {
PyObject *o = PyTuple_GET_ITEM(closure, i);
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 5dc8f92..41cf8fd 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -58,10 +58,7 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
else {
// We still need to visit the code object when the frame is cleared to
// ensure that it's kept alive if the reference is deferred.
- int err = _PyGC_VisitStackRef(&gen->gi_iframe.f_executable, visit, arg);
- if (err) {
- return err;
- }
+ _Py_VISIT_STACKREF(gen->gi_iframe.f_executable);
}
/* No need to visit cr_origin, because it's just tuples/str/int, so can't
participate in a reference cycle. */
diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c
index 3c96850..d365615 100644
--- a/Objects/typevarobject.c
+++ b/Objects/typevarobject.c
@@ -372,10 +372,10 @@ caller(void)
if (f == NULL) {
Py_RETURN_NONE;
}
- if (f == NULL || f->f_funcobj == NULL) {
+ if (f == NULL || PyStackRef_IsNull(f->f_funcobj)) {
Py_RETURN_NONE;
}
- PyObject *r = PyFunction_GetModule(f->f_funcobj);
+ PyObject *r = PyFunction_GetModule(PyStackRef_AsPyObjectBorrow(f->f_funcobj));
if (!r) {
PyErr_Clear();
Py_RETURN_NONE;