mirror of
https://github.com/python/cpython.git
synced 2026-01-06 07:22:09 +00:00
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.
This commit is contained in:
parent
d3c76dff44
commit
f4997bb3ac
17 changed files with 143 additions and 137 deletions
52
Python/generated_cases.c.h
generated
52
Python/generated_cases.c.h
generated
|
|
@ -506,7 +506,6 @@
|
|||
assert(code->co_argcount == 2);
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR);
|
||||
STAT_INC(BINARY_SUBSCR, hit);
|
||||
Py_INCREF(getitem);
|
||||
}
|
||||
// _BINARY_SUBSCR_INIT_CALL
|
||||
sub = stack_pointer[-1];
|
||||
|
|
@ -514,7 +513,7 @@
|
|||
PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container));
|
||||
PyHeapTypeObject *ht = (PyHeapTypeObject *)tp;
|
||||
PyObject *getitem = ht->_spec_cache.getitem;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, (PyFunctionObject *)getitem, 2, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame);
|
||||
stack_pointer += -2;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
new_frame->localsplus[0] = container;
|
||||
|
|
@ -892,7 +891,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// Manipulate stack directly since we leave using DISPATCH_INLINED().
|
||||
|
|
@ -1021,10 +1020,9 @@
|
|||
assert(_PyCode_CODE(_PyFrame_GetCode(shim))[0].op.code == EXIT_INIT_CHECK);
|
||||
/* Push self onto stack of shim */
|
||||
shim->localsplus[0] = PyStackRef_DUP(self);
|
||||
PyFunctionObject *init_func = (PyFunctionObject *)PyStackRef_AsPyObjectSteal(init);
|
||||
args[-1] = self;
|
||||
init_frame = _PyEvalFramePushAndInit(
|
||||
tstate, init_func, NULL, args-1, oparg+1, NULL, shim);
|
||||
tstate, init, NULL, args-1, oparg+1, NULL, shim);
|
||||
stack_pointer += -2 - oparg;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
if (init_frame == NULL) {
|
||||
|
|
@ -1119,11 +1117,9 @@
|
|||
// _INIT_CALL_PY_EXACT_ARGS
|
||||
args = &stack_pointer[-oparg];
|
||||
{
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
|
@ -1216,7 +1212,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// The frame has stolen all the arguments from the stack,
|
||||
|
|
@ -1616,8 +1612,8 @@
|
|||
Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
|
||||
int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(tstate,
|
||||
(PyFunctionObject *)PyStackRef_AsPyObjectSteal(func_st), locals,
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(
|
||||
tstate, func_st, locals,
|
||||
nargs, callargs, kwargs, frame);
|
||||
// Need to manually shrink the stack since we exit with DISPATCH_INLINED.
|
||||
STACK_SHRINK(oparg + 3);
|
||||
|
|
@ -1802,7 +1798,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, positional_args, kwnames_o, frame
|
||||
);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
|
|
@ -1936,7 +1932,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, positional_args, kwnames_o, frame
|
||||
);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
|
|
@ -2104,7 +2100,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, positional_args, kwnames_o, frame
|
||||
);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
|
|
@ -2649,11 +2645,9 @@
|
|||
// _INIT_CALL_PY_EXACT_ARGS
|
||||
args = &stack_pointer[-oparg];
|
||||
{
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
|
@ -2726,7 +2720,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// The frame has stolen all the arguments from the stack,
|
||||
|
|
@ -3274,8 +3268,9 @@
|
|||
INSTRUCTION_STATS(COPY_FREE_VARS);
|
||||
/* Copy closure variables to free variables */
|
||||
PyCodeObject *co = _PyFrame_GetCode(frame);
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
PyObject *closure = func->func_closure;
|
||||
assert(oparg == co->co_nfreevars);
|
||||
int offset = co->co_nlocalsplus - oparg;
|
||||
for (int i = 0; i < oparg; ++i) {
|
||||
|
|
@ -4102,7 +4097,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// Manipulate stack directly since we leave using DISPATCH_INLINED().
|
||||
|
|
@ -4997,8 +4992,8 @@
|
|||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR);
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
|
||||
Py_INCREF(f);
|
||||
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2, frame);
|
||||
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(
|
||||
tstate, PyStackRef_FromPyObjectNew(f), 2, frame);
|
||||
// Manipulate stack directly because we exit with DISPATCH_INLINED().
|
||||
STACK_SHRINK(1);
|
||||
new_frame->localsplus[0] = owner;
|
||||
|
|
@ -5328,8 +5323,7 @@
|
|||
DEOPT_IF(code->co_argcount != 1, LOAD_ATTR);
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR);
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
Py_INCREF(fget);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, f, 1, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(fget), 1, frame);
|
||||
new_frame->localsplus[0] = owner;
|
||||
}
|
||||
// _SAVE_RETURN_OFFSET
|
||||
|
|
@ -6504,8 +6498,8 @@
|
|||
next_instr += 1;
|
||||
INSTRUCTION_STATS(RETURN_GENERATOR);
|
||||
_PyStackRef res;
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
|
||||
if (gen == NULL) {
|
||||
goto error;
|
||||
|
|
@ -7718,8 +7712,8 @@
|
|||
Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
|
||||
int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(tstate,
|
||||
(PyFunctionObject *)PyStackRef_AsPyObjectSteal(func_st), locals,
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(
|
||||
tstate, func_st, locals,
|
||||
nargs, callargs, kwargs, frame);
|
||||
// Need to manually shrink the stack since we exit with DISPATCH_INLINED.
|
||||
STACK_SHRINK(oparg + 3);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue