]> granicus.if.org Git - python/commitdiff
A slight change to SET_LINENO-less tracing.
authorMichael W. Hudson <mwh@python.net>
Wed, 11 Sep 2002 15:36:32 +0000 (15:36 +0000)
committerMichael W. Hudson <mwh@python.net>
Wed, 11 Sep 2002 15:36:32 +0000 (15:36 +0000)
This makes things a touch more like 2.2.  Read the comments in
Python/ceval.c for more details.

Include/frameobject.h
Lib/test/test_trace.py
Modules/_hotshot.c
Objects/frameobject.c
Python/ceval.c

index 958b952fa53e12a1cdd7ea791dbd7a4c9670681c..2820e88bb0e4f0712d2eb65e440dd6b1d5e1953f 100644 (file)
@@ -29,6 +29,8 @@ typedef struct _frame {
     PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
     PyThreadState *f_tstate;
     int f_lasti;               /* Last instruction if called */
+    /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
+       f_trace is set) -- at other times use PyCode_Addr2Line instead. */
     int f_lineno;              /* Current line number */
     int f_restricted;          /* Flag set if restricted operations
                                   in this scope */
index eca8c16c967238b19d83679f42b75e6c90404ab5..314801d8bd17be6f7f671f205d08bacea2663776 100644 (file)
@@ -57,7 +57,7 @@ no_pop_tops.events = [(0, 'call'),
                       (3, 'line'),
                       (4, 'line'),
                       (2, 'line'),
-                      (6, 'return')]
+                      (2, 'return')]
 
 def no_pop_blocks():
     while 0:
index 2ca448620ee5be376faba1c62e9c84c76ece0e87..e12e5e5bf874de9cccddea95cf6df4616e20e1f1 100644 (file)
@@ -888,12 +888,10 @@ tracer_callback(ProfilerObject *self, PyFrameObject *frame, int what,
 
     case PyTrace_LINE:
         if (self->linetimings)
-            return pack_lineno_tdelta(self, PyCode_Addr2Line(frame->f_code, 
-                                                            frame->f_lasti),
+            return pack_lineno_tdelta(self, frame->f_lineno),
                                      get_tdelta(self));
         else
-            return pack_lineno(self, PyCode_Addr2Line(frame->f_code,
-                                                     frame->f_lasti));
+            return pack_lineno(self, frame->f_lineno);
 
     default:
         /* ignore PyTrace_EXCEPTION */
index c65ca40a7711ef8dee2ae82bc15f370c4d9ca079..3036ab684d939ba68d28a4f33691869430f90a18 100644 (file)
@@ -17,7 +17,6 @@ static PyMemberDef frame_memberlist[] = {
        {"f_globals",   T_OBJECT,       OFF(f_globals), RO},
        {"f_lasti",     T_INT,          OFF(f_lasti),   RO},
        {"f_restricted",T_INT,          OFF(f_restricted),RO},
-       {"f_trace",     T_OBJECT,       OFF(f_trace)},
        {"f_exc_type",  T_OBJECT,       OFF(f_exc_type)},
        {"f_exc_value", T_OBJECT,       OFF(f_exc_value)},
        {"f_exc_traceback", T_OBJECT,   OFF(f_exc_traceback)},
@@ -37,14 +36,49 @@ frame_getlineno(PyFrameObject *f, void *closure)
 {
        int lineno;
 
-       lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+       if (f->f_trace)
+               lineno = f->f_lineno;
+       else
+               lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
 
        return PyInt_FromLong(lineno);
 }
 
+static PyObject *
+frame_gettrace(PyFrameObject *f, void *closure)
+{
+       PyObject* trace = f->f_trace;
+
+       if (trace == NULL)
+               trace = Py_None;
+
+       Py_INCREF(trace);
+
+       return trace;
+}
+
+static int
+frame_settrace(PyFrameObject *f, PyObject* v, void *closure)
+{
+       /* We rely on f_lineno being accurate when f_trace is set. */
+
+       PyObject* old_value = f->f_trace;
+
+       Py_XINCREF(v);
+       f->f_trace = v;
+       
+       if (v != NULL)
+               f->f_lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+
+       Py_XDECREF(old_value);
+
+       return 0;
+}
+
 static PyGetSetDef frame_getsetlist[] = {
        {"f_locals",    (getter)frame_getlocals, NULL, NULL},
        {"f_lineno",    (getter)frame_getlineno, NULL, NULL},
+       {"f_trace",     (getter)frame_gettrace, (setter)frame_settrace, NULL},
        {0}
 };
 
index 6364c3f681dfa760fbb2f8cd3eab7d131124f850..362cd0bce706ee96b5ed924777ff58ffc84b0b3c 100644 (file)
@@ -2909,7 +2909,7 @@ maybe_call_line_trace(int opcode, Py_tracefunc func, PyObject *obj,
                 >>   21 LOAD_CONST               0 (None)
                      24 RETURN_VALUE
 
-          If a is false, execution will jump to instruction at offset
+          If 'a' is false, execution will jump to instruction at offset
           15 and the co_lnotab will claim that execution has moved to
           line 3.  This is at best misleading.  In this case we could
           associate the POP_TOP with line 4, but that doesn't make
@@ -2920,21 +2920,32 @@ maybe_call_line_trace(int opcode, Py_tracefunc func, PyObject *obj,
           current instruction offset matches the offset given for the
           start of a line by the co_lnotab.
 
-          This also takes care of the situation where a is true.
+          This also takes care of the situation where 'a' is true.
           Execution will jump from instruction offset 12 to offset 21.
           Then the co_lnotab would imply that execution has moved to line
           5, which is again misleading.
+
+          Why do we set f_lineno when tracing?  Well, consider the code
+          above when 'a' is true.  If stepping through this with 'n' in
+          pdb, you would stop at line 1 with a "call" type event, then
+          line events on lines 2 and 3, then a "return" type event -- but
+          you would be shown line 5 during this event.  This is a change
+          from the behaviour in 2.2 and before, and I've found it
+          confusing in practice.  By setting and using f_lineno when
+          tracing, one can report a line number different from that
+          suggested by f_lasti on this one occasion where it's desirable.
        */
 
        if ((frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub)) {
                PyCodeObject* co = frame->f_code;
-               int size, addr;
+               int size, addr, line;
                unsigned char* p;
 
                size = PyString_GET_SIZE(co->co_lnotab) / 2;
                p = (unsigned char*)PyString_AS_STRING(co->co_lnotab);
 
                addr = 0;
+               line = co->co_firstlineno;
 
                /* possible optimization: if f->f_lasti == instr_ub
                   (likely to be a common case) then we already know
@@ -2951,12 +2962,14 @@ maybe_call_line_trace(int opcode, Py_tracefunc func, PyObject *obj,
                        if (addr + *p > frame->f_lasti)
                                break;
                        addr += *p++;
-                       p++;
+                       line += *p++;
                        --size;
                }
-               if (addr == frame->f_lasti)
+               if (addr == frame->f_lasti) {
+                       frame->f_lineno = line;
                        call_trace(func, obj, frame, 
                                   PyTrace_LINE, Py_None);
+               }
                *instr_lb = addr;
                if (size > 0) {
                        while (--size >= 0) {