aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Python/executor_cases.c.h
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2025-04-21 15:54:25 -0400
committerGitHub <noreply@github.com>2025-04-21 15:54:25 -0400
commitda53660f35db2dfb1e6181e603468dfe5758f3b8 (patch)
treecf641cfff0634552f7d84ae9b246fa17d5e04166 /Python/executor_cases.c.h
parent8dfa840773d1d6bae1bf6e0dfa07618ea10c9d71 (diff)
downloadcpython-da53660f35db2dfb1e6181e603468dfe5758f3b8.tar.gz
cpython-da53660f35db2dfb1e6181e603468dfe5758f3b8.zip
gh-131586: Avoid refcount contention in context managers (gh-131851)
This avoid reference count contention in the free threading build when calling special methods like `__enter__` and `__exit__`.
Diffstat (limited to 'Python/executor_cases.c.h')
-rw-r--r--Python/executor_cases.c.h41
1 files changed, 20 insertions, 21 deletions
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index cd265c383bd..c65cc9efa5e 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -4407,43 +4407,42 @@
break;
}
+ case _INSERT_NULL: {
+ _PyStackRef self;
+ _PyStackRef *method_and_self;
+ self = stack_pointer[-1];
+ method_and_self = &stack_pointer[-1];
+ method_and_self[1] = self;
+ method_and_self[0] = PyStackRef_NULL;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
case _LOAD_SPECIAL: {
- _PyStackRef owner;
- _PyStackRef attr;
- _PyStackRef self_or_null;
+ _PyStackRef *method_and_self;
oparg = CURRENT_OPARG();
- owner = stack_pointer[-1];
- assert(oparg <= SPECIAL_MAX);
- PyObject *owner_o = PyStackRef_AsPyObjectSteal(owner);
+ method_and_self = &stack_pointer[-2];
PyObject *name = _Py_SpecialMethods[oparg].name;
- PyObject *self_or_null_o;
- stack_pointer += -1;
- assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer);
- PyObject *attr_o = _PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o);
+ int err = _PyObject_LookupSpecialMethod(name, method_and_self);
stack_pointer = _PyFrame_GetStackPointer(frame);
- if (attr_o == NULL) {
- if (!_PyErr_Occurred(tstate)) {
+ if (err <= 0) {
+ if (err == 0) {
+ PyObject *owner = PyStackRef_AsPyObjectBorrow(method_and_self[1]);
_PyFrame_SetStackPointer(frame, stack_pointer);
- const char *errfmt = _PyEval_SpecialMethodCanSuggest(owner_o, oparg)
+ const char *errfmt = _PyEval_SpecialMethodCanSuggest(owner, oparg)
? _Py_SpecialMethods[oparg].error_suggestion
: _Py_SpecialMethods[oparg].error;
stack_pointer = _PyFrame_GetStackPointer(frame);
assert(!_PyErr_Occurred(tstate));
assert(errfmt != NULL);
_PyFrame_SetStackPointer(frame, stack_pointer);
- _PyErr_Format(tstate, PyExc_TypeError, errfmt, owner_o);
+ _PyErr_Format(tstate, PyExc_TypeError, errfmt, owner);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
JUMP_TO_ERROR();
}
- attr = PyStackRef_FromPyObjectSteal(attr_o);
- self_or_null = self_or_null_o == NULL ?
- PyStackRef_NULL : PyStackRef_FromPyObjectSteal(self_or_null_o);
- stack_pointer[0] = attr;
- stack_pointer[1] = self_or_null;
- stack_pointer += 2;
- assert(WITHIN_STACK_BOUNDS());
break;
}