]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] gh-109181: Speed up Traceback object creation by lazily compute the line numbe...
authorPablo Galindo Salgado <Pablogsal@gmail.com>
Tue, 31 Oct 2023 15:59:31 +0000 (15:59 +0000)
committerGitHub <noreply@github.com>
Tue, 31 Oct 2023 15:59:31 +0000 (15:59 +0000)
.
(cherry picked from commit abb15420c11d9dda9c89f74eac8417240b321109)

Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst [new file with mode: 0644]
Python/traceback.c

diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst
new file mode 100644 (file)
index 0000000..61a15b4
--- /dev/null
@@ -0,0 +1,2 @@
+Speed up :obj:`Traceback` object creation by lazily compute the line number.
+Patch by Pablo Galindo
index 130f945c29023432db2b5762623740698ac0d9ce..664a73fdfbaa31a5c121fa142830c0db8ae44cdc 100644 (file)
@@ -111,6 +111,26 @@ tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_))
     return ret;
 }
 
+static int
+tb_get_lineno(PyTracebackObject* tb) {
+    PyFrameObject* frame = tb->tb_frame;
+    assert(frame != NULL);
+    return PyCode_Addr2Line(PyFrame_GetCode(frame), tb->tb_lasti);
+}
+
+static PyObject *
+tb_lineno_get(PyTracebackObject *self, void *Py_UNUSED(_))
+{
+    int lineno = self->tb_lineno;
+    if (lineno == -1) {
+        lineno = tb_get_lineno(self);
+        if (lineno < 0) {
+            Py_RETURN_NONE;
+        }
+    }
+    return PyLong_FromLong(lineno);
+}
+
 static int
 tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_))
 {
@@ -157,12 +177,12 @@ static PyMethodDef tb_methods[] = {
 static PyMemberDef tb_memberlist[] = {
     {"tb_frame",        T_OBJECT,       OFF(tb_frame),  READONLY|PY_AUDIT_READ},
     {"tb_lasti",        T_INT,          OFF(tb_lasti),  READONLY},
-    {"tb_lineno",       T_INT,          OFF(tb_lineno), READONLY},
     {NULL}      /* Sentinel */
 };
 
 static PyGetSetDef tb_getsetters[] = {
     {"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL},
+    {"tb_lineno", (getter)tb_lineno_get, NULL, NULL, NULL},
     {NULL}      /* Sentinel */
 };
 
@@ -241,8 +261,7 @@ _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame)
     assert(tb_next == NULL || PyTraceBack_Check(tb_next));
     assert(frame != NULL);
     int addr = _PyInterpreterFrame_LASTI(frame->f_frame) * sizeof(_Py_CODEUNIT);
-    return tb_create_raw((PyTracebackObject *)tb_next, frame, addr,
-                         PyFrame_GetLineNumber(frame));
+    return tb_create_raw((PyTracebackObject *)tb_next, frame, addr, -1);
 }
 
 
@@ -990,9 +1009,13 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit,
     }
     while (tb != NULL) {
         code = PyFrame_GetCode(tb->tb_frame);
+        int tb_lineno = tb->tb_lineno;
+        if (tb_lineno == -1) {
+            tb_lineno = tb_get_lineno(tb);
+        }
         if (last_file == NULL ||
             code->co_filename != last_file ||
-            last_line == -1 || tb->tb_lineno != last_line ||
+            last_line == -1 || tb_lineno != last_line ||
             last_name == NULL || code->co_name != last_name) {
             if (cnt > TB_RECURSIVE_CUTOFF) {
                 if (tb_print_line_repeated(f, cnt) < 0) {
@@ -1000,13 +1023,13 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit,
                 }
             }
             last_file = code->co_filename;
-            last_line = tb->tb_lineno;
+            last_line = tb_lineno;
             last_name = code->co_name;
             cnt = 0;
         }
         cnt++;
         if (cnt <= TB_RECURSIVE_CUTOFF) {
-            if (tb_displayline(tb, f, code->co_filename, tb->tb_lineno,
+            if (tb_displayline(tb, f, code->co_filename, tb_lineno,
                                tb->tb_frame, code->co_name, indent, margin) < 0) {
                 goto error;
             }