bpo-45256: Don't track the exact depth of each InterpreterFrame (GH-30372)

This commit is contained in:
Brandt Bucher 2022-01-05 03:30:26 -08:00 committed by GitHub
parent cae55542d2
commit 332e6b9725
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 16 additions and 17 deletions

View file

@ -4,6 +4,8 @@
extern "C" { extern "C" {
#endif #endif
#include <stdbool.h>
/* runtime lifecycle */ /* runtime lifecycle */
@ -44,7 +46,7 @@ typedef struct _interpreter_frame {
int f_lasti; /* Last instruction if called */ int f_lasti; /* Last instruction if called */
int stacktop; /* Offset of TOS from localsplus */ int stacktop; /* Offset of TOS from localsplus */
PyFrameState f_state; /* What state the frame is in */ PyFrameState f_state; /* What state the frame is in */
int depth; /* Depth of the frame in a ceval loop */ bool is_entry; // Whether this is the "root" frame for the current CFrame.
PyObject *localsplus[1]; PyObject *localsplus[1];
} InterpreterFrame; } InterpreterFrame;
@ -101,7 +103,7 @@ _PyFrame_InitializeSpecials(
frame->generator = NULL; frame->generator = NULL;
frame->f_lasti = -1; frame->f_lasti = -1;
frame->f_state = FRAME_CREATED; frame->f_state = FRAME_CREATED;
frame->depth = 0; frame->is_entry = false;
} }
/* Gets the pointer to the locals array /* Gets the pointer to the locals array

View file

@ -1323,7 +1323,7 @@ class SizeofTest(unittest.TestCase):
def func(): def func():
return sys._getframe() return sys._getframe()
x = func() x = func()
check(x, size('3Pi3c8P2iciP')) check(x, size('3Pi3c8P2ic?P'))
# function # function
def func(): pass def func(): pass
check(func, size('14Pi')) check(func, size('14Pi'))
@ -1340,7 +1340,7 @@ class SizeofTest(unittest.TestCase):
check(bar, size('PP')) check(bar, size('PP'))
# generator # generator
def get_gen(): yield 1 def get_gen(): yield 1
check(get_gen(), size('P2P4P4c8P2iciP')) check(get_gen(), size('P2P4P4c8P2ic?P'))
# iterator # iterator
check(iter('abc'), size('lP')) check(iter('abc'), size('lP'))
# callable-iterator # callable-iterator

View file

@ -1683,7 +1683,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
cframe.previous = prev_cframe; cframe.previous = prev_cframe;
tstate->cframe = &cframe; tstate->cframe = &cframe;
assert(frame->depth == 0); frame->is_entry = true;
/* Push frame */ /* Push frame */
frame->previous = prev_cframe->current_frame; frame->previous = prev_cframe->current_frame;
cframe.current_frame = frame; cframe.current_frame = frame;
@ -2310,7 +2310,6 @@ check_eval_breaker:
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
new_frame->previous = frame; new_frame->previous = frame;
frame = cframe.current_frame = new_frame; frame = cframe.current_frame = new_frame;
new_frame->depth = frame->depth + 1;
goto start_frame; goto start_frame;
} }
@ -2475,7 +2474,7 @@ check_eval_breaker:
TRACE_FUNCTION_EXIT(); TRACE_FUNCTION_EXIT();
DTRACE_FUNCTION_EXIT(); DTRACE_FUNCTION_EXIT();
_Py_LeaveRecursiveCall(tstate); _Py_LeaveRecursiveCall(tstate);
if (frame->depth) { if (!frame->is_entry) {
frame = cframe.current_frame = pop_frame(tstate, frame); frame = cframe.current_frame = pop_frame(tstate, frame);
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
goto resume_frame; goto resume_frame;
@ -2625,7 +2624,7 @@ check_eval_breaker:
} }
TARGET(SEND) { TARGET(SEND) {
assert(frame->depth == 0); assert(frame->is_entry);
assert(STACK_LEVEL() >= 2); assert(STACK_LEVEL() >= 2);
PyObject *v = POP(); PyObject *v = POP();
PyObject *receiver = TOP(); PyObject *receiver = TOP();
@ -2684,7 +2683,7 @@ check_eval_breaker:
} }
TARGET(YIELD_VALUE) { TARGET(YIELD_VALUE) {
assert(frame->depth == 0); assert(frame->is_entry);
PyObject *retval = POP(); PyObject *retval = POP();
if (frame->f_code->co_flags & CO_ASYNC_GENERATOR) { if (frame->f_code->co_flags & CO_ASYNC_GENERATOR) {
@ -4612,7 +4611,6 @@ check_eval_breaker:
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
new_frame->previous = frame; new_frame->previous = frame;
cframe.current_frame = frame = new_frame; cframe.current_frame = frame = new_frame;
new_frame->depth = frame->depth + 1;
goto start_frame; goto start_frame;
} }
} }
@ -4706,7 +4704,6 @@ check_eval_breaker:
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
new_frame->previous = frame; new_frame->previous = frame;
frame = cframe.current_frame = new_frame; frame = cframe.current_frame = new_frame;
new_frame->depth = frame->depth + 1;
goto start_frame; goto start_frame;
} }
@ -5382,7 +5379,7 @@ exception_unwind:
exit_unwind: exit_unwind:
assert(_PyErr_Occurred(tstate)); assert(_PyErr_Occurred(tstate));
_Py_LeaveRecursiveCall(tstate); _Py_LeaveRecursiveCall(tstate);
if (frame->depth == 0) { if (frame->is_entry) {
/* Restore previous cframe and exit */ /* Restore previous cframe and exit */
tstate->cframe = cframe.previous; tstate->cframe = cframe.previous;
tstate->cframe->use_tracing = cframe.use_tracing; tstate->cframe->use_tracing = cframe.use_tracing;

View file

@ -1044,8 +1044,8 @@ class PyFramePtr:
def _f_lasti(self): def _f_lasti(self):
return self._f_special("f_lasti", int_from_int) return self._f_special("f_lasti", int_from_int)
def depth(self): def is_entry(self):
return self._f_special("depth", int_from_int) return self._f_special("is_entry", bool)
def previous(self): def previous(self):
return self._f_special("previous", PyFramePtr) return self._f_special("previous", PyFramePtr)
@ -1860,7 +1860,7 @@ class Frame(object):
line = interp_frame.current_line() line = interp_frame.current_line()
if line is not None: if line is not None:
sys.stdout.write(' %s\n' % line.strip()) sys.stdout.write(' %s\n' % line.strip())
if interp_frame.depth() == 0: if interp_frame.is_entry():
break break
else: else:
sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index()) sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
@ -1883,7 +1883,7 @@ class Frame(object):
line = interp_frame.current_line() line = interp_frame.current_line()
if line is not None: if line is not None:
sys.stdout.write(' %s\n' % line.strip()) sys.stdout.write(' %s\n' % line.strip())
if interp_frame.depth() == 0: if interp_frame.is_entry():
break break
else: else:
sys.stdout.write(' (unable to read python frame information)\n') sys.stdout.write(' (unable to read python frame information)\n')
@ -2147,7 +2147,7 @@ class PyLocals(gdb.Command):
% (pyop_name.proxyval(set()), % (pyop_name.proxyval(set()),
pyop_value.get_truncated_repr(MAX_OUTPUT_LEN))) pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)))
if pyop_frame.depth() == 0: if pyop_frame.is_entry():
break break
pyop_frame = pyop_frame.previous() pyop_frame = pyop_frame.previous()