Author: Armin Rigo <ar...@tunes.org> Branch: reverse-debugger Changeset: r86781:99b8ccb0e43a Date: 2016-08-31 16:53 +0200 http://bitbucket.org/pypy/pypy/changeset/99b8ccb0e43a/
Log: in-progress: activate breakpoints based on line number 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 @@ -15,6 +15,7 @@ breakpoint_stack_id = 0 breakpoint_funcnames = None breakpoint_filelines = None + breakpoint_version = 0 printed_objects = {} metavars = [] watch_progs = [] @@ -24,6 +25,8 @@ pycode.PyCode.co_revdb_linestarts = None # or a string: see below +pycode.PyCode.co_revdb_bkpt_version = 0 # see check_and_trigger_bkpt() +pycode.PyCode.co_revdb_bkpt_cache = None # see check_and_trigger_bkpt() # invariant: "f_revdb_nextline_instr" is the bytecode offset of # the start of the line that follows "last_instr". @@ -128,6 +131,8 @@ call_stop_point_at_line = False # if call_stop_point_at_line: + if dbstate.breakpoint_filelines is not None: + check_and_trigger_bkpt(frame.pycode, cur) stop_point_activate() cur += 1 ch = ord(co_revdb_linestarts[cur]) @@ -192,6 +197,25 @@ p += 2 return lineno +def find_line_starts(code): + # RPython version of dis.findlinestarts() + lnotab = code.co_lnotab + lastlineno = -1 + lineno = code.co_firstlineno + addr = 0 + p = 0 + result = [] + while p < len(lnotab) - 1: + byte_incr = ord(lnotab[p]) + if byte_incr: + if lineno != lastlineno: + result.append((addr, lineno)) + lastlineno = lineno + addr += byte_incr + lineno += line_incr + if lineno != lastlineno: + result.append((addr, lineno)) + return result class NonStandardCode(object): def __enter__(self): @@ -512,6 +536,47 @@ revdb.send_output('%s\n' % e.errorstr(space, use_repr=True)) lambda_locals = lambda: command_locals +# ____________________________________________________________ + + +def check_and_trigger_bkpt(pycode, opindex): + # We cache on 'pycode.co_revdb_bkpt_cache' either None or a dict + # 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. + if pycode.co_revdb_bkpt_version != dbstate.breakpoint_version: + update_bkpt_cache(pycode) + cache = pycode.co_revdb_bkpt_cache + if cache is not None and opindex in cache: + revdb.breakpoint(cache[opindex]) + +def update_bkpt_cache(pycode): + # dbstate.breakpoint_filelines == {'normfilename': {lineno: bkpt_num}} + co_filename = pycode.co_filename + try: + linenos = dbstate.breakpoint_filelines[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 + normfilename = rpath.rabspath(co_filename) + normfilename = rpath.rnormpath(normfilename) + linenos = dbstate.breakpoint_filelines.get(normfilename, None) + dbstate.breakpoint_filelines[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. + 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 + def valid_identifier(s): if not s: @@ -600,6 +665,7 @@ revdb.set_thread_breakpoint(cmd.c_arg2) dbstate.breakpoint_funcnames = None dbstate.breakpoint_filelines = None + dbstate.breakpoint_version += 1 watch_progs = [] with non_standard_code: for i, kind, name in revdb.split_breakpoints_arg(extra): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit