mirror of
https://github.com/python/cpython.git
synced 2025-08-24 02:35:59 +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
51
Python/executor_cases.c.h
generated
51
Python/executor_cases.c.h
generated
|
@ -1018,7 +1018,6 @@
|
|||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
STAT_INC(BINARY_SUBSCR, hit);
|
||||
Py_INCREF(getitem);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1031,7 +1030,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;
|
||||
|
@ -1852,8 +1851,9 @@
|
|||
oparg = CURRENT_OPARG();
|
||||
/* 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) {
|
||||
|
@ -2553,8 +2553,7 @@
|
|||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
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;
|
||||
stack_pointer[-1].bits = (uintptr_t)new_frame;
|
||||
break;
|
||||
|
@ -3603,7 +3602,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,
|
||||
|
@ -3833,11 +3832,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - 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++) {
|
||||
|
@ -3859,11 +3856,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - 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++) {
|
||||
|
@ -3885,11 +3880,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - 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++) {
|
||||
|
@ -3911,11 +3904,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - 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++) {
|
||||
|
@ -3937,11 +3928,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - 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++) {
|
||||
|
@ -3962,11 +3951,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - 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++) {
|
||||
|
@ -4145,10 +4132,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) {
|
||||
|
@ -4780,7 +4766,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);
|
||||
|
@ -5001,8 +4987,8 @@
|
|||
|
||||
case _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) {
|
||||
JUMP_TO_ERROR();
|
||||
|
@ -5376,8 +5362,9 @@
|
|||
|
||||
case _CHECK_FUNCTION: {
|
||||
uint32_t func_version = (uint32_t)CURRENT_OPERAND();
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
if (((PyFunctionObject *)frame->f_funcobj)->func_version != func_version) {
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
if (func->func_version != func_version) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue