]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-109181: Speed up Traceback object creation by lazily compute the line number ...
authorPablo Galindo Salgado <Pablogsal@gmail.com>
Tue, 31 Oct 2023 15:02:31 +0000 (15:02 +0000)
committerGitHub <noreply@github.com>
Tue, 31 Oct 2023 15:02:31 +0000 (15:02 +0000)
Signed-off-by: Pablo Galindo <pablogsal@gmail.com>
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 05d841e56ad7bd6462dcbebb74e36e0748a110b1..8aba802ae3678426d27d3717d456425cbe277e00 100644 (file)
@@ -109,6 +109,26 @@ tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_))
     return Py_NewRef(ret);
 }
 
+static int
+tb_get_lineno(PyTracebackObject* tb) {
+    _PyInterpreterFrame* frame = tb->tb_frame->f_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(_))
 {
@@ -152,12 +172,12 @@ static PyMethodDef tb_methods[] = {
 static PyMemberDef tb_memberlist[] = {
     {"tb_frame",        _Py_T_OBJECT,       OFF(tb_frame),  Py_READONLY|Py_AUDIT_READ},
     {"tb_lasti",        Py_T_INT,          OFF(tb_lasti),  Py_READONLY},
-    {"tb_lineno",       Py_T_INT,          OFF(tb_lineno), Py_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 */
 };
 
@@ -236,8 +256,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);
 }
 
 
@@ -681,9 +700,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) {
@@ -691,13 +714,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) < 0) {
                 goto error;
             }