gh-144549: Fix tail calling interpreter on Windows for FT (GH-144550)

This commit is contained in:
Ken Jin 2026-02-07 03:20:28 +08:00 committed by GitHub
parent 28fb13cb33
commit 895e83727d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 62 additions and 86 deletions

View file

@ -2364,31 +2364,9 @@ dummy_func(
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
if (oparg & 1) {
/* Designed to work in tandem with CALL, pushes two values. */
_PyCStackRef method;
_PyThreadState_PushCStackRef(tstate, &method);
int is_meth = _PyObject_GetMethodStackRef(tstate, PyStackRef_AsPyObjectBorrow(owner), name, &method.ref);
if (is_meth) {
/* We can bypass temporary bound method object.
meth is unbound method and obj is self.
meth | self | arg1 | ... | argN
*/
assert(!PyStackRef_IsNull(method.ref)); // No errors on this branch
self_or_null[0] = owner; // Transfer ownership
DEAD(owner);
attr = _PyThreadState_PopCStackRefSteal(tstate, &method);
}
else {
/* meth is not an unbound method (but a regular attr, or
something was returned by a descriptor protocol). Set
the second element of the stack to NULL, to signal
CALL that it's not a method call.
meth | NULL | arg1 | ... | argN
*/
PyStackRef_CLOSE(owner);
self_or_null[0] = PyStackRef_NULL;
attr = _PyThreadState_PopCStackRefSteal(tstate, &method);
ERROR_IF(PyStackRef_IsNull(attr));
}
attr = _Py_LoadAttr_StackRefSteal(tstate, owner, name, self_or_null);
DEAD(owner);
ERROR_IF(PyStackRef_IsNull(attr));
}
else {
/* Classic, pushes one value. */

View file

@ -1007,6 +1007,34 @@ _Py_BuildMap_StackRefSteal(
return res;
}
_PyStackRef
_Py_LoadAttr_StackRefSteal(
PyThreadState *tstate, _PyStackRef owner,
PyObject *name, _PyStackRef *self_or_null)
{
_PyCStackRef method;
_PyThreadState_PushCStackRef(tstate, &method);
int is_meth = _PyObject_GetMethodStackRef(tstate, PyStackRef_AsPyObjectBorrow(owner), name, &method.ref);
if (is_meth) {
/* We can bypass temporary bound method object.
meth is unbound method and obj is self.
meth | self | arg1 | ... | argN
*/
assert(!PyStackRef_IsNull(method.ref)); // No errors on this branch
self_or_null[0] = owner; // Transfer ownership
return _PyThreadState_PopCStackRefSteal(tstate, &method);
}
/* meth is not an unbound method (but a regular attr, or
something was returned by a descriptor protocol). Set
the second element of the stack to NULL, to signal
CALL that it's not a method call.
meth | NULL | arg1 | ... | argN
*/
PyStackRef_CLOSE(owner);
self_or_null[0] = PyStackRef_NULL;
return _PyThreadState_PopCStackRefSteal(tstate, &method);
}
#ifdef Py_DEBUG
void
_Py_assert_within_stack_bounds(

View file

@ -8670,32 +8670,18 @@
self_or_null = &stack_pointer[1];
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
if (oparg & 1) {
_PyCStackRef method;
stack_pointer[0] = owner;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyThreadState_PushCStackRef(tstate, &method);
int is_meth = _PyObject_GetMethodStackRef(tstate, PyStackRef_AsPyObjectBorrow(owner), name, &method.ref);
attr = _Py_LoadAttr_StackRefSteal(tstate, owner, name, self_or_null);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (is_meth) {
assert(!PyStackRef_IsNull(method.ref));
self_or_null[0] = owner;
attr = _PyThreadState_PopCStackRefSteal(tstate, &method);
}
else {
stack_pointer += -1;
if (PyStackRef_IsNull(attr)) {
stack_pointer[-1] = attr;
stack_pointer += (oparg&1);
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(owner);
stack_pointer = _PyFrame_GetStackPointer(frame);
self_or_null[0] = PyStackRef_NULL;
attr = _PyThreadState_PopCStackRefSteal(tstate, &method);
if (PyStackRef_IsNull(attr)) {
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
stack_pointer += 1;
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
}
else {

View file

@ -7898,28 +7898,11 @@
self_or_null = &stack_pointer[0];
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
if (oparg & 1) {
_PyCStackRef method;
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyThreadState_PushCStackRef(tstate, &method);
int is_meth = _PyObject_GetMethodStackRef(tstate, PyStackRef_AsPyObjectBorrow(owner), name, &method.ref);
attr = _Py_LoadAttr_StackRefSteal(tstate, owner, name, self_or_null);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (is_meth) {
assert(!PyStackRef_IsNull(method.ref));
self_or_null[0] = owner;
attr = _PyThreadState_PopCStackRefSteal(tstate, &method);
}
else {
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(owner);
stack_pointer = _PyFrame_GetStackPointer(frame);
self_or_null[0] = PyStackRef_NULL;
attr = _PyThreadState_PopCStackRefSteal(tstate, &method);
if (PyStackRef_IsNull(attr)) {
JUMP_TO_LABEL(error);
}
stack_pointer += 1;
if (PyStackRef_IsNull(attr)) {
JUMP_TO_LABEL(pop_1_error);
}
}
else {