[Python-Dev] Why do we need Traceback Objects?

Vladimir Marangozov Vladimir.Marangozov@inrialpes.fr
Fri, 7 Apr 2000 13:47:07 +0200 (CEST)


Skip Montanaro wrote:
> 
> Whoops, wait a minute.  I just tried
> 
>     >>> def foo(): pass
>     ... 
>     >>> foo.func_code.co_lnotab 
> 
> with both "python" and "python -O".  co_lnotab is empty for python -O.  I
> thought it was supposed to always be generated?

It is always generated, but since co_lnotab contains only lineno
increments starting from co_firstlineno (i.e. only deltas) and your
function is a 1-liner (no lineno increments starting from the first
line of the function), the table is empty. Move 'pass' to the next line
and the table will contain 1-entry (of 2 bytes: delta_addr, delta_line).

Generally speaking, the problem really boils down to the callbacks
from C to Python when a tracefunc is set. My approach is not that bad
in this regard.

A decent processor nowadays has (an IRQ pin) a flag for generating
interrupts on every processor instruction (trace flag). In Python,
we have the same problem - we need to interrupt the (virtual) processor,
implemented in eval_code2() on regular intervals. Actually, what we
need (for pdb) is to interrupt the processor on every source line, but
one could easily imagine a per instruction interrupt (with a callback
installed with sys.settracei().

This is exactly what the patch does under the grounds. It interrupts
the processor on every new source line (but interrupting it on every
instruction would be a trivial extension -- all opcodes in the code
stream would be set to CALL_TRACE!) And this is exactly what LINENO
does (+ some processor state saving in the frame: f_lasti, f_lineno).

Clearly, there are 2 differences with the existing code:

a) The interrupting opcodes are installed dynamically, on demand, only
   when a trace function is set, for the current traced frame.
   Presently, these opcodes are SET_LINENO; I introduced a new one byte
   CALL_TRACE opcode which does the same thing (thus preserving backwards
   compatibility with old .pyc that contain SET_LINENO).

b) f_lasti and f_lineno aren't updated when the frame is not traced :-(
   I wonder whether we really care about them, though.

The other implementation details aren't so important. Yet, they look
scary, but no more than the co_lnotab business. The problem with my patch
is point b). I believe the approach is good, though -- if it weren't,
I woudn't have taken the care to talk about it detail. :-)

-- 
       Vladimir MARANGOZOV          | Vladimir.Marangozov@inrialpes.fr
http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252