[pypy-commit] pypy reverse-debugger: in-progress: tracking live objects

arigo pypy.commits at gmail.com
Tue Jun 21 10:53:41 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r85306:1c3f6914ae95
Date: 2016-06-21 16:54 +0200
http://bitbucket.org/pypy/pypy/changeset/1c3f6914ae95/

Log:	in-progress: tracking live objects

diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -17,6 +17,7 @@
 CMD_MOREINFO    = 5
 ANSWER_TEXT     = 20
 ANSWER_MOREINFO = 21
+ANSWER_NEXTNID  = 22
 
 
 def stop_point():
@@ -31,6 +32,9 @@
 def register_debug_command(command, lambda_func):
     """Register the extra RPython-implemented debug command."""
 
+def register_allocation_command(lambda_func):
+    """Register the extra RPython-implemented callback for allocation."""
+
 def send_answer(cmd, arg1=0, arg2=0, arg3=0, extra=""):
     """For RPython debug commands: writes an answer block to stdout"""
     llop.revdb_send_answer(lltype.Void, cmd, arg1, arg2, arg3, extra)
@@ -38,6 +42,9 @@
 def send_output(text):
     send_answer(ANSWER_TEXT, extra=text)
 
+def send_nextnid(unique_id):
+    send_answer(ANSWER_NEXTNID, unique_id)
+
 def current_time():
     """For RPython debug commands: returns the current time."""
     return llop.revdb_get_value(lltype.SignedLongLong, 'c')
@@ -131,7 +138,12 @@
                 cmds = t.revdb_commands
             except AttributeError:
                 cmds = t.revdb_commands = []
-            cmds.append((command_num, func))
+            for old_num, old_func in cmds:
+                if old_num == command_num:
+                    assert old_func is func
+                    break
+            else:
+                cmds.append((command_num, func))
             s_func = self.bookkeeper.immutablevalue(func)
             s_ptr1 = llannotation.SomePtr(ll_ptrtype=_CMDPTR)
             s_str2 = annmodel.SomeString()
@@ -140,3 +152,28 @@
 
     def specialize_call(self, hop):
         hop.exception_cannot_occur()
+
+
+class RegisterAllocationCommand(ExtRegistryEntry):
+    _about_ = register_allocation_command
+
+    def compute_result_annotation(self, s_lambda_func):
+        from rpython.annotator import model as annmodel
+        from rpython.rtyper import llannotation
+
+        lambda_func = s_lambda_func.const
+        t = self.bookkeeper.annotator.translator
+        if t.config.translation.reverse_debugger:
+            func = lambda_func()
+            try:
+                assert t.revdb_allocation_cmd is func
+            except AttributeError:
+                t.revdb_allocation_cmd = func
+            s_func = self.bookkeeper.immutablevalue(func)
+            s_int1 = annmodel.SomeInteger(knowntype=r_longlong)
+            s_ref2 = llannotation.lltype_to_annotation(llmemory.GCREF)
+            self.bookkeeper.emulate_pbc_call(self.bookkeeper.position_key,
+                                             s_func, [s_int1, s_ref2])
+
+    def specialize_call(self, hop):
+        hop.exception_cannot_occur()
diff --git a/rpython/translator/revdb/gencsupp.py b/rpython/translator/revdb/gencsupp.py
--- a/rpython/translator/revdb/gencsupp.py
+++ b/rpython/translator/revdb/gencsupp.py
@@ -1,5 +1,5 @@
 import py
-from rpython.rtyper.lltypesystem import lltype, rffi, rstr
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr
 from rpython.translator.c.support import cdecl
 from rpython.rlib import exports, revdb
 
@@ -23,25 +23,31 @@
 
 
 def prepare_database(db):
-    FUNCPTR = lltype.Ptr(lltype.FuncType([revdb._CMDPTR,
-                                          lltype.Ptr(rstr.STR)], lltype.Void))
+    FUNCPTR = lltype.Ptr(lltype.FuncType([revdb._CMDPTR, lltype.Ptr(rstr.STR)],
+                                         lltype.Void))
+    ALLOCFUNCPTR = lltype.Ptr(lltype.FuncType([rffi.LONGLONG, llmemory.GCREF],
+                                              lltype.Void))
 
     bk = db.translator.annotator.bookkeeper
     cmds = getattr(db.translator, 'revdb_commands', [])
 
-    array_names = lltype.malloc(rffi.CArray(rffi.INT), len(cmds) + 1,
-                                flavor='raw', immortal=True, zero=True)
-    array_funcs = lltype.malloc(rffi.CArray(FUNCPTR), len(cmds),
-                                flavor='raw', immortal=True, zero=True)
+    S = lltype.Struct('RPY_REVDB_COMMANDS',
+                      ('names', lltype.FixedSizeArray(rffi.INT, len(cmds) + 1)),
+                      ('funcs', lltype.FixedSizeArray(FUNCPTR, len(cmds))),
+                      ('alloc', ALLOCFUNCPTR))
+    s = lltype.malloc(S, flavor='raw', immortal=True, zero=True)
 
     for i, (name, func) in enumerate(cmds):
         fnptr = lltype.getfunctionptr(bk.getdesc(func).getuniquegraph())
         assert lltype.typeOf(fnptr) == FUNCPTR
         assert isinstance(name, int) and name != 0
-        array_names[i] = rffi.cast(rffi.INT, name)
-        array_funcs[i] = fnptr
+        s.names[i] = rffi.cast(rffi.INT, name)
+        s.funcs[i] = fnptr
 
-    exports.EXPORTS_obj2name[array_names._as_obj()] = 'rpy_revdb_command_names'
-    exports.EXPORTS_obj2name[array_funcs._as_obj()] = 'rpy_revdb_command_funcs'
-    db.get(array_names)
-    db.get(array_funcs)
+    allocation_cmd = getattr(db.translator, 'revdb_allocation_cmd', None)
+    if allocation_cmd is not None:
+        s.alloc = lltype.getfunctionptr(
+            bk.getdesc(allocation_cmd).getuniquegraph())
+
+    exports.EXPORTS_obj2name[s._as_obj()] = 'rpy_revdb_commands'
+    db.get(s)
diff --git a/rpython/translator/revdb/message.py b/rpython/translator/revdb/message.py
--- a/rpython/translator/revdb/message.py
+++ b/rpython/translator/revdb/message.py
@@ -4,9 +4,11 @@
 
 # See the corresponding answers for details about messages.
 
-CMD_FORK     = -1      # Message(CMD_FORK)
-CMD_QUIT     = -2      # Message(CMD_QUIT)
-CMD_FORWARD  = -3      # Message(CMD_FORWARD, steps, breakpoint_mode)
+CMD_FORK      = -1     # Message(CMD_FORK)
+CMD_QUIT      = -2     # Message(CMD_QUIT)
+CMD_FORWARD   = -3     # Message(CMD_FORWARD, steps, breakpoint_mode)
+CMD_FUTUREIDS = -4     # Message(CMD_FUTUREIDS, extra=list-of-8bytes-uids)
+CMD_ALLOCATING= -5     # Message(CMD_CREATING, uid, addr)
 # extra commands which are not handled by revdb.c, but
 # by revdb.register_debug_command()
 CMD_PRINT       = 1    # Message(CMD_PRINT, extra=expression)
@@ -50,6 +52,10 @@
 #    Message(ANSWER_MOREINFO, stack_depth)
 ANSWER_MOREINFO   = 21
 
+# sent from CMD_PRINT to record the existence of a recallable object
+#    Message(ANSWER_NEXTNID, unique-id)
+ANSWER_NEXTNID    = 22
+
 
 # ____________________________________________________________
 
diff --git a/rpython/translator/revdb/process.py b/rpython/translator/revdb/process.py
--- a/rpython/translator/revdb/process.py
+++ b/rpython/translator/revdb/process.py
@@ -172,6 +172,7 @@
         self.active = child
         self.paused = {1: child.clone()}     # {time: subprocess}
         self.all_breakpoints = AllBreakpoints()
+        self.all_printed_objects = []
 
     def get_current_time(self):
         return self.active.current_time
@@ -313,7 +314,8 @@
         """Print an expression.
         """
         self.active.tainted = True
-        self.active.send(Message(CMD_PRINT, extra=expression))
+        next_nid = len(self.all_printed_objects)
+        self.active.send(Message(CMD_PRINT, next_nid, extra=expression))
         self.active.print_text_answer()
 
     def show_backtrace(self):
diff --git a/rpython/translator/revdb/src-revdb/revdb.c b/rpython/translator/revdb/src-revdb/revdb.c
--- a/rpython/translator/revdb/src-revdb/revdb.c
+++ b/rpython/translator/revdb/src-revdb/revdb.c
@@ -192,9 +192,10 @@
 
 #define INIT_VERSION_NUMBER   0xd80100
 
-#define CMD_FORK     (-1)
-#define CMD_QUIT     (-2)
-#define CMD_FORWARD  (-3)
+#define CMD_FORK      (-1)
+#define CMD_QUIT      (-2)
+#define CMD_FORWARD   (-3)
+#define CMD_FUTUREIDS (-4)
 
 #define ANSWER_INIT       (-20)
 #define ANSWER_READY      (-21)
@@ -215,6 +216,7 @@
 static uint64_t last_recorded_breakpoint_loc;
 static int last_recorded_breakpoint_num;
 static char breakpoint_mode;
+static uint64_t *future_ids, *future_next_id;
 
 static void attach_gdb(void)
 {
@@ -540,12 +542,33 @@
     }
 }
 
+static void command_future_ids(rpy_revdb_command_t *cmd, char *extra)
+{
+    free(future_ids);
+    if (cmd->extra_size == 0) {
+        future_ids = NULL;
+        rpy_revdb.unique_id_break = 0;
+    }
+    else {
+        assert(cmd->extra_size % sizeof(uint64_t) == 0);
+        future_ids = malloc(cmd->extra_size + sizeof(uint64_t));
+        if (future_ids == NULL) {
+            fprintf(stderr, "out of memory for a buffer of %llu chars\n",
+                    (unsigned long long)cmd->extra_size);
+            exit(1);
+        }
+        memcpy(future_ids, extra, cmd->extra_size);
+        future_ids[cmd->extra_size / sizeof(uint64_t)] = 0;
+    }
+    future_next_id = future_ids;
+}
+
 static void command_default(rpy_revdb_command_t *cmd, char *extra)
 {
     RPyString *s;
     int i;
-    for (i = 0; rpy_revdb_command_names[i] != cmd->cmd; i++) {
-        if (rpy_revdb_command_names[i] == 0) {
+    for (i = 0; rpy_revdb_commands.rp_names[i] != cmd->cmd; i++) {
+        if (rpy_revdb_commands.rp_names[i] == 0) {
             fprintf(stderr, "unknown command %d\n", cmd->cmd);
             exit(1);
         }
@@ -558,16 +581,29 @@
         s = make_rpy_string(cmd->extra_size);
         memcpy(_RPyString_AsString(s), extra, cmd->extra_size);
     }
-    execute_rpy_function(rpy_revdb_command_funcs[i], cmd, s);
+    execute_rpy_function(rpy_revdb_commands.rp_funcs[i], cmd, s);
+}
+
+static void save_state(void)
+{
+    stopped_time = rpy_revdb.stop_point_seen;
+    stopped_uid = rpy_revdb.unique_id_seen;
+    rpy_revdb.unique_id_seen = (-1ULL) << 63;
+}
+
+static void restore_state(void)
+{
+    rpy_revdb.stop_point_seen = stopped_time;
+    rpy_revdb.unique_id_seen = stopped_uid;
+    stopped_time = 0;
+    stopped_uid = 0;
 }
 
 RPY_EXTERN
 void rpy_reverse_db_stop_point(void)
 {
     while (rpy_revdb.stop_point_break == rpy_revdb.stop_point_seen) {
-        stopped_time = rpy_revdb.stop_point_seen;
-        stopped_uid = rpy_revdb.unique_id_seen;
-        rpy_revdb.unique_id_seen = (-1ULL) << 63;
+        save_state();
         breakpoint_mode = 0;
 
         if (pending_after_forward) {
@@ -599,15 +635,16 @@
                 command_forward(&cmd);
                 break;
 
+            case CMD_FUTUREIDS:
+                command_future_ids(&cmd, extra);
+                break;
+
             default:
                 command_default(&cmd, extra);
                 break;
             }
         }
-        rpy_revdb.stop_point_seen = stopped_time;
-        rpy_revdb.unique_id_seen = stopped_uid;
-        stopped_time = 0;
-        stopped_uid = 0;
+        restore_state();
     }
 }
 
@@ -696,39 +733,21 @@
     }
 }
 
-static void (*unique_id_callback)(void *);
-
 RPY_EXTERN
 uint64_t rpy_reverse_db_unique_id_break(void *new_object)
 {
-    rpy_revdb_t dinfo;
-    rpy_revdb.unique_id_break = 0;
-    disable_io(&dinfo);
-    if (setjmp(jmp_buf_cancel_execution) == 0)
-        unique_id_callback(new_object);
-    enable_io(&dinfo);
+    if (!new_object) {
+        fprintf(stderr, "out of memory: allocation failed, cannot continue\n");
+        exit(1);
+    }
+    if (rpy_revdb_commands.rp_alloc) {
+        save_state();
+        rpy_revdb_commands.rp_alloc(rpy_revdb.unique_id_seen, new_object);
+        restore_state();
+    }
+    rpy_revdb.unique_id_break = *future_next_id++;
     return rpy_revdb.unique_id_seen;
 }
 
-RPY_EXTERN
-void rpy_reverse_db_track_object(long long unique_id, void callback(void *))
-{
-    if (stopped_uid <= 0) {
-        fprintf(stderr, "stopped_uid should not be <= 0\n");
-        return;
-    }
-    if (unique_id <= 0) {
-        fprintf(stderr, "cannot track a prebuilt or debugger-created object\n");
-        return;
-    }
-    if (unique_id < stopped_uid) {
-        fprintf(stderr, "cannot track the creation of an object already created\n");
-        return;
-    }
-    assert(callback != NULL);
-    unique_id_callback = callback;
-    rpy_revdb.unique_id_break = unique_id;
-}
-
 
 /* ------------------------------------------------------------ */
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
@@ -114,8 +114,5 @@
 RPY_EXTERN void rpy_reverse_db_breakpoint(int64_t num);
 RPY_EXTERN long long rpy_reverse_db_get_value(char value_id);
 RPY_EXTERN uint64_t rpy_reverse_db_unique_id_break(void *new_object);
-RPY_EXTERN void rpy_reverse_db_track_object(long long unique_id,
-                                            void callback(void *));
-
 
 /* ------------------------------------------------------------ */


More information about the pypy-commit mailing list