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__`.
This commit is contained in:
Sam Gross 2025-04-21 15:54:25 -04:00 committed by GitHub
parent 8dfa840773
commit da53660f35
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 247 additions and 207 deletions

View file

@ -4407,43 +4407,42 @@
break;
}
case _LOAD_SPECIAL: {
_PyStackRef owner;
_PyStackRef attr;
_PyStackRef self_or_null;
oparg = CURRENT_OPARG();
owner = stack_pointer[-1];
assert(oparg <= SPECIAL_MAX);
PyObject *owner_o = PyStackRef_AsPyObjectSteal(owner);
PyObject *name = _Py_SpecialMethods[oparg].name;
PyObject *self_or_null_o;
stack_pointer += -1;
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 *method_and_self;
oparg = CURRENT_OPARG();
method_and_self = &stack_pointer[-2];
PyObject *name = _Py_SpecialMethods[oparg].name;
_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;
}