[Patches] [ python-Patches-617312 ] debugger-controlled jumps (Psyco #3)

noreply@sourceforge.net noreply@sourceforge.net
Tue, 17 Dec 2002 09:47:52 -0800


Patches item #617312, was opened at 2002-10-01 23:26
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=617312&group_id=5470

Category: Core (C code)
Group: Python 2.3
Status: Closed
Resolution: Accepted
Priority: 5
Submitted By: Armin Rigo (arigo)
Assigned to: Michael Hudson (mwh)
Summary: debugger-controlled jumps (Psyco #3)

Initial Comment:
Psyco-friendly patch #3.

Allows the C profile and trace functions (called upon
function entry, line tracing, function exit, and
exception) to alter some fields of the current
PyFrameObject to influence the execution of the main
loop.  This is currently impossible because all the
relevant fields are copied into local variables of
eval_frame(), shadowing any subsequence change in the
frame object.

This is designed for what I plan to do with Psyco, but
could also be used by advanced debuggers to allow the
execution point to be modified by the user.  Besides,
the patch is just a matter of swapping a few lines in
eval_frame(), introducing almost no extra complexity.


In ceval.c:eval_frame():

The calls to call_trace(...PyTrace_CALL...) at the
beginning of the code have been moved above the
initialization of the local variables, allowing the
trace functions to fiddle with the frame object before
the main loop sees it.

There is also a bug fix here: if the profile or trace
functions raise an error at this point, eval_frame()
used to quit without restoring tstate->frame and
tstate->recursion_depth. [XXX should have been a bug
report on its own]

Finally, the call_trace() on SET_LINENO has been
slightly modified to allow the trace function to move
the execution point elsewhere.  This is done by saving
a few local variables are saved to and restored from
the frame object around the call_trace().  The
variables are the current instruction pointer (which
was already saved in f->f_lasti, but is now restored
from f->f_lasti too), and the current stack_pointer.

Compatibility: f->f_stacktop normally remains NULL for
the whole execution of the frame.  This patch sets it
to a non-NULL value for the duration of the call to the
line-by-line trace function.  I expect this not to
cause any incompatibility because f->f_stacktop is not
visible from Python code.  I do not expect extension
modules to rely on this detail.  Note however that this
has an influence on the GC, which only visits the stack
if f->f_stacktop is set.  Again, I assume this is not
an issue -- it cannot even cause dead cycles to be
detected earlier by the GC because as long as we are in
the call_trace() call, we have a live reference to f.

Performance: when tracing is on, SET_LINENO is now
marginally slower.  I guess this is not considered as
an issue given the debugging nature of tracing.  In
Python 2.3, line tracing is currently *much* heavier
and nobody seems to complain ;-)


----------------------------------------------------------------------

Comment By: Richie Hindle (richiehindle)
Date: 2002-12-17 17:47

Message:
Logged In: YES 
user_id=85414

Armin said: "This [...] could also be used by advanced
debuggers to allow the execution point to be modified
by the user."

I've implemented an extension of this idea as patch
643835, just checked in by mwh.  Debuggers (including
those written in pure Python) can now write to f_lineno
to modify the exeuction point.  pdb now has a 'jump'
command that does this.


----------------------------------------------------------------------

Comment By: Michael Hudson (mwh)
Date: 2002-11-08 12:56

Message:
Logged In: YES 
user_id=6656

I got lazy and checked in all the psyco patches at once:

Include/pystate.h revision 2.21
Modules/pyexpat.c revision 2.76
Python/ceval.c revision 2.340
Python/pystate.c revision 2.22


----------------------------------------------------------------------

Comment By: Armin Rigo (arigo)
Date: 2002-10-07 15:35

Message:
Logged In: YES 
user_id=4771

Uploaded patch for 2.3.  I had to change the order of some 
things in the main loop -- namely, call maybe_call_trace_line
() before the next opcode/oparg is loaded.  To do so I had to 
simplify the signature of maybe_call_trace_line():  I removed 
its first argument, 'opcode', which wasn't used any more 
anyway.

I carefully checked that I didn't broke anything, 
and 'test_trace' says so, but you may as well double-check 
the patch.

----------------------------------------------------------------------

Comment By: Michael Hudson (mwh)
Date: 2002-10-07 09:38

Message:
Logged In: YES 
user_id=6656

OK done, in ceval.c revision 2.301.4.6.

----------------------------------------------------------------------

Comment By: Armin Rigo (arigo)
Date: 2002-10-07 00:28

Message:
Logged In: YES 
user_id=4771

Here you are!

----------------------------------------------------------------------

Comment By: Guido van Rossum (gvanrossum)
Date: 2002-10-06 20:44

Message:
Logged In: YES 
user_id=6380

I'd like to get this into 2.2.2, but the patch doesn't apply
cleanly (courtesy of MWH fixing the beg reported herein :-).
Armin, can you upload a fixed patch? Or if MWH reads this,
can you check this and the other two in?

----------------------------------------------------------------------

Comment By: Michael Hudson (mwh)
Date: 2002-10-03 08:50

Message:
Logged In: YES 
user_id=6656

Fair enough.  Let's see what Guido thinks.

----------------------------------------------------------------------

Comment By: Armin Rigo (arigo)
Date: 2002-10-02 20:33

Message:
Logged In: YES 
user_id=4771

The trace function can change f_lasti if it knows what it
does and if it accordingly changes all other fields too,
like f_stacktop, f_blockstack and f_iblock.  In fact,
f_lasti and f_stacktop are the only fields of the frame
objects that are currently cached in local variables (with
the exception of what concerns the f_code object itself) so
that this patch is enough to let the trace function actually
move the execution point elsewhere.

This would be quite useful in Psyco, if the rest of the
function has been emulated and we then want the main loop to
exit with the proper value: just move f_lasti just before
the RETURN_VALUE opcode, clean up the stack and block stack,
and push the already-computed result value where
RETURN_VALUE will find it.  Psyco could also execute just a
part of the function and give it back to Python at some
later position.  A "clean hack".

----------------------------------------------------------------------

Comment By: Michael Hudson (mwh)
Date: 2002-10-02 13:14

Message:
Logged In: YES 
user_id=6656

Never mind, the bug offended me so much that I fixed it both
on the trunk and the 22-maint branch.

Python/ceval.c revisions 2.337 and 2.301.4.5
Lib/test/test_trace.py revisions 1.4 and 1.4.2.1

(probably a 2.1 bugix candidate, if any cares...)

----------------------------------------------------------------------

Comment By: Michael Hudson (mwh)
Date: 2002-10-02 12:23

Message:
Logged In: YES 
user_id=6656

What about the blockstack?  Are you just relying on trace
functions not moving f_lasti unwisely?

Agree about the bug.  Do you have a test case for it? 
Otherwise I'll cook one up.

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=617312&group_id=5470