bpo-44590: Lazily allocate frame objects (GH-27077)

* Convert "specials" array to InterpreterFrame struct, adding f_lasti, f_state and other non-debug FrameObject fields to it.

* Refactor, calls pushing the call to the interpreter upward toward _PyEval_Vector.

* Compute f_back when on thread stack, only filling in value when frame object outlives stack invocation.

* Move ownership of InterpreterFrame in generator from frame object to generator object.

* Do not create frame objects for Python calls.

* Do not create frame objects for generators.
This commit is contained in:
Mark Shannon 2021-07-26 11:22:16 +01:00 committed by GitHub
parent 0363a4014d
commit ae0a2b7562
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1037 additions and 619 deletions

View file

@ -240,7 +240,7 @@ _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame)
assert(tb_next == NULL || PyTraceBack_Check(tb_next));
assert(frame != NULL);
return tb_create_raw((PyTracebackObject *)tb_next, frame, frame->f_lasti*2,
return tb_create_raw((PyTracebackObject *)tb_next, frame, frame->f_frame->f_lasti*2,
PyFrame_GetLineNumber(frame));
}
@ -521,7 +521,7 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent, i
* When displaying a new traceback line, for certain syntactical constructs
* (e.g a subscript, an arithmetic operation) we try to create a representation
* that separates the primary source of error from the rest.
*
*
* Example specialization of BinOp nodes:
* Traceback (most recent call last):
* File "/home/isidentical/cpython/cpython/t.py", line 10, in <module>
@ -710,7 +710,7 @@ tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int linen
}
int code_offset = tb->tb_lasti;
PyCodeObject* code = _PyFrame_GetCode(frame);
PyCodeObject* code = frame->f_frame->f_code;
int start_line;
int end_line;
@ -1024,9 +1024,9 @@ _Py_DumpASCII(int fd, PyObject *text)
This function is signal safe. */
static void
dump_frame(int fd, PyFrameObject *frame)
dump_frame(int fd, InterpreterFrame *frame)
{
PyCodeObject *code = PyFrame_GetCode(frame);
PyCodeObject *code = frame->f_code;
PUTS(fd, " File ");
if (code->co_filename != NULL
&& PyUnicode_Check(code->co_filename))
@ -1038,7 +1038,7 @@ dump_frame(int fd, PyFrameObject *frame)
PUTS(fd, "???");
}
int lineno = PyFrame_GetLineNumber(frame);
int lineno = PyCode_Addr2Line(code, frame->f_lasti*2);
PUTS(fd, ", line ");
if (lineno >= 0) {
_Py_DumpDecimal(fd, (size_t)lineno);
@ -1057,20 +1057,19 @@ dump_frame(int fd, PyFrameObject *frame)
}
PUTS(fd, "\n");
Py_DECREF(code);
}
static void
dump_traceback(int fd, PyThreadState *tstate, int write_header)
{
PyFrameObject *frame;
InterpreterFrame *frame;
unsigned int depth;
if (write_header) {
PUTS(fd, "Stack (most recent call first):\n");
}
frame = PyThreadState_GetFrame(tstate);
frame = tstate->frame;
if (frame == NULL) {
PUTS(fd, "<no Python frame>\n");
return;
@ -1079,22 +1078,14 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
depth = 0;
while (1) {
if (MAX_FRAME_DEPTH <= depth) {
Py_DECREF(frame);
PUTS(fd, " ...\n");
break;
}
if (!PyFrame_Check(frame)) {
Py_DECREF(frame);
break;
}
dump_frame(fd, frame);
PyFrameObject *back = PyFrame_GetBack(frame);
Py_DECREF(frame);
if (back == NULL) {
frame = frame->previous;
if (frame == NULL) {
break;
}
frame = back;
depth++;
}
}