Author: Armin Rigo <[email protected]>
Branch: reverse-debugger
Changeset: r86802:799bea7b4905
Date: 2016-09-01 00:31 +0100
http://bitbucket.org/pypy/pypy/changeset/799bea7b4905/
Log: fixes fixes fixes
now after "b FILENAME:LINENO", will break whenever we reach the
LINENO in a code object with co_filename == (optional
prefix/)FILENAME. Should all be done efficiently enough with
multiple levels of caching.
diff --git a/pypy/interpreter/reverse_debugging.py
b/pypy/interpreter/reverse_debugging.py
--- a/pypy/interpreter/reverse_debugging.py
+++ b/pypy/interpreter/reverse_debugging.py
@@ -1,5 +1,5 @@
import sys
-from rpython.rlib import revdb, rpath, rstring
+from rpython.rlib import revdb
from rpython.rlib.debug import make_sure_not_resized
from rpython.rlib.objectmodel import specialize, we_are_translated
from rpython.rtyper.annlowlevel import cast_gcref_to_instance
@@ -15,6 +15,7 @@
breakpoint_stack_id = 0
breakpoint_funcnames = None
breakpoint_filelines = None
+ breakpoint_by_file = None
breakpoint_version = 0
printed_objects = {}
metavars = []
@@ -131,7 +132,7 @@
call_stop_point_at_line = False
#
if call_stop_point_at_line:
- if dbstate.breakpoint_filelines is not None:
+ if dbstate.breakpoint_by_file is not None:
check_and_trigger_bkpt(frame.pycode, cur)
stop_point_activate()
cur += 1
@@ -214,6 +215,7 @@
lastlineno = lineno
addr += byte_incr
lineno += line_incr
+ p += 2
if lineno != lastlineno:
result.append((addr, lineno))
return result
@@ -545,6 +547,8 @@
# mapping {opindex: bkpt_num}. This cache is updated when the
# version in 'pycode.co_revdb_bkpt_version' does not match
# 'dbstate.breakpoint_version' any more.
+ #
+ # IMPORTANT: no object allocation here, outside update_bkpt_cache!
if pycode.co_revdb_bkpt_version != dbstate.breakpoint_version:
update_bkpt_cache(pycode)
cache = pycode.co_revdb_bkpt_cache
@@ -552,33 +556,46 @@
revdb.breakpoint(cache[opindex])
def update_bkpt_cache(pycode):
- # dbstate.breakpoint_filelines == {'normfilename': {lineno: bkpt_num}}
+ # initialized by command_breakpoints():
+ # dbstate.breakpoint_filelines == [('FILENAME', lineno, bkpt_num)]
+ # computed lazily (here, first half of the logic):
+ # dbstate.breakpoint_by_file == {'co_filename': {lineno: bkpt_num}}
+ # the goal is to set:
+ # pycode.co_revdb_bkpt_cache == {opindex: bkpt_num}
+ #
+ prev_state = revdb.watch_save_state(force=True)
+ # ^^^ the object allocations done in this function should not count!
+
co_filename = pycode.co_filename
try:
- linenos = dbstate.breakpoint_filelines[co_filename]
+ linenos = dbstate.breakpoint_by_file[co_filename]
except KeyError:
- # normalize co_filename, and assigns the {lineno: bkpt_num} dict
- # back over the original key, to avoid calling rabspath/rnormpath
- # again the next time
- co_filename = rstring.assert_str0(co_filename)
- normfilename = rpath.rabspath(co_filename)
- normfilename = rpath.rnormpath(normfilename)
- linenos = dbstate.breakpoint_filelines.get(normfilename, None)
- dbstate.breakpoint_filelines[co_filename] = linenos
- #
+ linenos = None
+ match = co_filename.upper() # ignore cAsE in filename matching
+ for filename, lineno, bkpt_num in dbstate.breakpoint_filelines:
+ if match.endswith(filename) and (
+ len(match) == len(filename) or
+ match[-len(filename)-1] in '/\\'): # a valid prefix
+ if linenos is None:
+ linenos = {}
+ linenos[lineno] = bkpt_num
+ dbstate.breakpoint_by_file[co_filename] = linenos
+
newcache = None
if linenos is not None:
# parse co_lnotab to figure out the opindexes that correspond
- # to the marked line numbers.
+ # to the marked line numbers. here, linenos == {lineno: bkpt_num}
for addr, lineno in find_line_starts(pycode):
if lineno in linenos:
if newcache is None:
newcache = {}
newcache[addr] = linenos[lineno]
- #
+
pycode.co_revdb_bkpt_cache = newcache
pycode.co_revdb_bkpt_version = dbstate.breakpoint_version
+ revdb.watch_restore_state(prev_state)
+
def valid_identifier(s):
if not s:
@@ -596,10 +613,14 @@
dbstate.breakpoint_funcnames[name] = i
def add_breakpoint_fileline(filename, lineno, i):
+ # dbstate.breakpoint_filelines is just a list of (FILENAME, lineno, i).
+ # dbstate.breakpoint_by_file is {co_filename: {lineno: i}}, but
+ # computed lazily when we encounter a code object with the given
+ # co_filename. Any suffix 'filename' matches 'co_filename'.
if dbstate.breakpoint_filelines is None:
- dbstate.breakpoint_filelines = {}
- linenos = dbstate.breakpoint_filelines.setdefault(filename, {})
- linenos[lineno] = i
+ dbstate.breakpoint_filelines = []
+ dbstate.breakpoint_by_file = {}
+ dbstate.breakpoint_filelines.append((filename.upper(), lineno, i))
def add_breakpoint(name, i):
# if it is empty, complain
@@ -654,10 +675,6 @@
revdb.send_output(
'Note: "%s" doesn''t look like a Python filename. '
'Setting breakpoint anyway\n' % (filename,))
- elif '\x00' not in filename:
- filename = rstring.assert_str0(filename)
- filename = rpath.rabspath(filename)
- filename = rpath.rnormpath(filename)
add_breakpoint_fileline(filename, lineno, i)
name = '%s:%d' % (filename, lineno)
@@ -670,6 +687,7 @@
revdb.set_thread_breakpoint(cmd.c_arg2)
dbstate.breakpoint_funcnames = None
dbstate.breakpoint_filelines = None
+ dbstate.breakpoint_by_file = None
dbstate.breakpoint_version += 1
watch_progs = []
with non_standard_code:
diff --git a/pypy/interpreter/test/test_reverse_debugging.py
b/pypy/interpreter/test/test_reverse_debugging.py
--- a/pypy/interpreter/test/test_reverse_debugging.py
+++ b/pypy/interpreter/test/test_reverse_debugging.py
@@ -1,7 +1,7 @@
import dis
from pypy.interpreter.reverse_debugging import *
from pypy.interpreter import reverse_debugging
-from rpython.rlib import revdb, rpath
+from rpython.rlib import revdb
from hypothesis import given, strategies, example
@@ -73,7 +73,7 @@
assert dbstate.breakpoint_filelines is None
else:
filename, lineno = expected_fileline
- assert dbstate.breakpoint_filelines == {filename: {lineno: 5}}
+ assert dbstate.breakpoint_filelines == [(filename.upper(), lineno, 5)]
got_output = None
got_chbkpt = None
@@ -89,9 +89,6 @@
assert got_output == expected_output
assert got_chbkpt == expected_chbkpt
-def fullpath(path):
- return rpath.rnormpath(rpath.rabspath(path))
-
def test_add_breakpoint():
check_add_breakpoint('', expected_output="Empty breakpoint name\n",
expected_chbkpt='')
@@ -109,12 +106,8 @@
check_add_breakpoint('abcd:42', expected_fileline=('abcd', 42),
expected_output='Note: "abcd" doesnt look like a Python filename.'
' Setting breakpoint anyway\n')
- full = fullpath('abcd.py')
check_add_breakpoint('abcd.py:42',
- expected_fileline=(full, 42),
- expected_chbkpt='%s:42' % full)
- check_add_breakpoint('%s:42' % full,
- expected_fileline=(full, 42))
+ expected_fileline=('abcd.py', 42))
check_add_breakpoint('42:abc',
expected_output='"42:abc": expected a line number after colon\n',
expected_chbkpt='')
diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -132,8 +132,8 @@
ll_callback = llhelper(_CALLBACK_GCREF_FNPTR, callback)
llop.revdb_track_object(lltype.Void, unique_id, ll_callback)
-def watch_save_state():
- return llop.revdb_watch_save_state(lltype.Bool)
+def watch_save_state(force=False):
+ return llop.revdb_watch_save_state(lltype.Bool, force)
def watch_restore_state(any_watch_point):
llop.revdb_watch_restore_state(lltype.Void, any_watch_point)
diff --git a/rpython/translator/revdb/interact.py
b/rpython/translator/revdb/interact.py
--- a/rpython/translator/revdb/interact.py
+++ b/rpython/translator/revdb/interact.py
@@ -51,6 +51,7 @@
print 'KeyboardInterrupt: restoring state at time %d...' % (
rtime,)
self.pgroup.recreate_subprocess(rtime)
+ print "(type 'q' or Ctrl-D to quit)"
self.last_command = ''
self.previous_thread = '?'
self.previous_time = '?'
diff --git a/rpython/translator/revdb/src-revdb/revdb_include.h
b/rpython/translator/revdb/src-revdb/revdb_include.h
--- a/rpython/translator/revdb/src-revdb/revdb_include.h
+++ b/rpython/translator/revdb/src-revdb/revdb_include.h
@@ -205,9 +205,9 @@
#define OP_REVDB_TRACK_OBJECT(uid, callback, r) \
rpy_reverse_db_track_object(uid, callback)
-#define OP_REVDB_WATCH_SAVE_STATE(r) do { \
+#define OP_REVDB_WATCH_SAVE_STATE(force, r) do { \
r = rpy_revdb.watch_enabled; \
- if (r) rpy_reverse_db_watch_save_state(); \
+ if ((force) || r) rpy_reverse_db_watch_save_state(); \
} while (0)
#define OP_REVDB_WATCH_RESTORE_STATE(any_watch_point, r) \
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit