diff options
author | Sam Gross <colesbury@gmail.com> | 2025-04-21 15:54:25 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-21 15:54:25 -0400 |
commit | da53660f35db2dfb1e6181e603468dfe5758f3b8 (patch) | |
tree | cf641cfff0634552f7d84ae9b246fa17d5e04166 /Python/executor_cases.c.h | |
parent | 8dfa840773d1d6bae1bf6e0dfa07618ea10c9d71 (diff) | |
download | cpython-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.h | 41 |
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; } |