[pypy-commit] pypy reverse-debugger: bug fixes, there is more
arigo
pypy.commits at gmail.com
Thu Jun 30 06:35:12 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r85468:550befa14f60
Date: 2016-06-30 12:36 +0200
http://bitbucket.org/pypy/pypy/changeset/550befa14f60/
Log: bug fixes, there is more
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
@@ -140,10 +140,13 @@
def stop_point_at_start_of_line():
if revdb.watch_save_state():
any_watch_point = False
+ space = dbstate.space
for prog, watch_id, expected in dbstate.watch_progs:
any_watch_point = True
- got = _run_watch(prog)
- if got != expected:
+ try:
+ if _run_watch(space, prog) != expected:
+ break
+ except OperationError:
break
else:
watch_id = -1
@@ -466,19 +469,15 @@
space = dbstate.space
try:
code = interp_marshal.loads(space, space.wrap(marshalled_code))
- w_res = code.exec_code(space, space.builtin, space.builtin)
- text = space.str_w(space.repr(w_res))
+ text = _run_watch(space, code)
except OperationError as e:
revdb.send_watch(e.errorstr(space), ok_flag=0)
else:
revdb.send_watch(text, ok_flag=1)
lambda_checkwatch = lambda: command_checkwatch
-def _run_watch(code):
- space = dbstate.space
- try:
- w_res = code.exec_code(space, space.builtin, space.builtin)
- text = space.str_w(space.repr(w_res))
- except OperationError as e:
- return e.errorstr(space)
- return text
+
+def _run_watch(space, prog):
+ w_dict = space.builtin.w_dict
+ w_res = prog.exec_code(space, w_dict, w_dict)
+ return space.str_w(space.repr(w_res))
diff --git a/rpython/memory/gctransform/boehm.py b/rpython/memory/gctransform/boehm.py
--- a/rpython/memory/gctransform/boehm.py
+++ b/rpython/memory/gctransform/boehm.py
@@ -29,7 +29,7 @@
ll_malloc_varsize = mh.ll_malloc_varsize
fields = [("hash", lltype.Signed)]
- if translator.config.translation.reverse_debugger:
+ if translator and translator.config.translation.reverse_debugger:
fields.append(("uid", lltype.SignedLongLong))
self.HDR = lltype.Struct("header", *fields)
HDRPTR = lltype.Ptr(self.HDR)
@@ -74,11 +74,21 @@
# XXX same behavior for zero=True: in theory that's wrong
if TYPE._is_atomic():
funcptr = self.malloc_fixedsize_atomic_ptr
+ opname = 'boehm_malloc_atomic'
else:
funcptr = self.malloc_fixedsize_ptr
- v_raw = hop.genop("direct_call",
- [funcptr, c_size],
- resulttype=llmemory.GCREF)
+ opname = 'boehm_malloc'
+ tr = self.translator
+ if tr and tr.config.translation.reverse_debugger:
+ # Don't check for NULLs after the operation (it crashes anyway
+ # with an explicit error message in case of out-of-memory).
+ # Avoiding a direct_call lets _RPY_REVDB_PRUID() prints the
+ # right file/line, at least for fixed-size mallocs.
+ v_raw = hop.genop(opname, [c_size], resulttype=llmemory.GCREF)
+ else:
+ v_raw = hop.genop("direct_call",
+ [funcptr, c_size],
+ resulttype=llmemory.GCREF)
finalizer_ptr = self.finalizer_funcptr_for_type(TYPE)
if finalizer_ptr:
c_finalizer_ptr = Constant(finalizer_ptr, self.FINALIZER_PTR)
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
@@ -279,20 +279,13 @@
{
/* Boehm only */
if (obj->h_hash == 0) {
- Signed h;
- if (flag_io_disabled != FID_REGULAR_MODE) {
- /* This is when running debug commands. Don't cache the
- hash on the object at all. */
- return ~((Signed)obj);
- }
- /* When recording, we get the hash the normal way from the
- pointer casted to an int, and record that. When replaying,
- we read it from the record. In both cases, we cache the
- hash in the object, so that we record/replay only once per
- object. */
- RPY_REVDB_EMIT(h = ~((Signed)obj);, Signed _e, h);
- assert(h != 0);
- obj->h_hash = h;
+ /* We never need to record anything: if h_hash is zero (which
+ is the case for all newly allocated objects), then we just
+ copy h_uid. This gives a stable answer. This would give
+ 0 for all prebuilt objects, but these should not have a
+ null h_hash anyway.
+ */
+ obj->h_hash = obj->h_uid;
}
return obj->h_hash;
}
@@ -853,6 +846,13 @@
static void check_at_end(uint64_t stop_points)
{
char dummy[1];
+ if (rpy_revdb.buf_p != rpy_revdb.buf_limit - 1 ||
+ read(rpy_rev_fileno, dummy, 1) > 0) {
+ fprintf(stderr, "RevDB file error: corrupted file (too much data or, "
+ "more likely, non-deterministic run, e.g. a "
+ "watchpoint with side effects)\n");
+ exit(1);
+ }
if (stop_points != rpy_revdb.stop_point_seen) {
fprintf(stderr, "Bad number of stop points "
"(seen %lld, recorded %lld)\n",
@@ -860,11 +860,6 @@
(long long)stop_points);
exit(1);
}
- if (rpy_revdb.buf_p != rpy_revdb.buf_limit - 1 ||
- read(rpy_rev_fileno, dummy, 1) > 0) {
- fprintf(stderr, "RevDB file error: corrupted file (too much data?)\n");
- exit(1);
- }
if (stop_points != total_stop_points) {
fprintf(stderr, "RevDB file modified while reading?\n");
exit(1);
@@ -971,6 +966,7 @@
memcpy(future_ids, extra, cmd->extra_size);
future_ids[cmd->extra_size / sizeof(uint64_t)] = 0;
uid_break = *future_ids;
+ attach_gdb();
}
future_next_id = future_ids;
}
@@ -1168,10 +1164,17 @@
return uid;
}
+struct destructor_s {
+ void *d_obj;
+ void (*d_callback)(void *);
+};
+
static int _ftree_compare(const void *obj1, const void *obj2)
{
- const struct pypy_header0 *h1 = obj1;
- const struct pypy_header0 *h2 = obj2;
+ const struct destructor_s *d1 = obj1;
+ const struct destructor_s *d2 = obj2;
+ struct pypy_header0 *h1 = d1->d_obj;
+ struct pypy_header0 *h2 = d2->d_obj;
if (h1->h_uid < h2->h_uid)
return -1;
if (h1->h_uid == h2->h_uid)
@@ -1180,26 +1183,60 @@
return 1;
}
+static void _ftree_add(void **tree, void *obj, void (*callback)(void *))
+{
+ /* Note: we always allocate an indirection through a
+ struct destructor_s, so that Boehm knows that 'obj' must be
+ kept alive. */
+ struct destructor_s *node, **item;
+ node = GC_MALLOC_UNCOLLECTABLE(sizeof(struct destructor_s));
+ node->d_obj = obj;
+ node->d_callback = callback;
+ item = tsearch(node, tree, _ftree_compare);
+ if (item == NULL) {
+ fprintf(stderr, "_ftree_add: out of memory\n");
+ exit(1);
+ }
+ if (*item != node) {
+ fprintf(stderr, "_ftree_add: duplicate object\n");
+ exit(1);
+ }
+}
+
+static struct pypy_header0 *_ftree_pop(void **tree, uint64_t uid,
+ void (**callback_out)(void *))
+{
+ struct destructor_s d_dummy, *entry, **item;
+ struct pypy_header0 o_dummy, *result;
+
+ d_dummy.d_obj = &o_dummy;
+ o_dummy.h_uid = uid;
+ item = tfind(&d_dummy, tree, _ftree_compare);
+ if (item == NULL) {
+ fprintf(stderr, "_ftree_pop: object not found\n");
+ exit(1);
+ }
+ entry = *item;
+ result = entry->d_obj;
+ if (callback_out)
+ *callback_out = entry->d_callback;
+ assert(result->h_uid == uid);
+ tdelete(entry, tree, _ftree_compare);
+ GC_FREE(entry);
+ return result;
+}
+
RPY_EXTERN
int rpy_reverse_db_fq_register(void *obj)
{
- /*fprintf(stderr, "FINALIZER_TREE: %lld -> %p\n",
+ fprintf(stderr, "FINALIZER_TREE: %lld -> %p\n",
((struct pypy_header0 *)obj)->h_uid, obj);
- */
if (!RPY_RDB_REPLAY) {
return 0; /* recording */
}
else {
- /* add the object into the finalizer_tree, keyed by the h_uid */
- void **item = tsearch(obj, &finalizer_tree, _ftree_compare);
- if (item == NULL) {
- fprintf(stderr, "fq_register: out of memory\n");
- exit(1);
- }
- if (*item != obj) {
- fprintf(stderr, "fq_register: duplicate object\n");
- exit(1);
- }
+ /* add the object into the finalizer_tree, keyed by the h_uid. */
+ _ftree_add(&finalizer_tree, obj, NULL);
return 1; /* replaying */
}
}
@@ -1210,47 +1247,19 @@
int64_t uid;
RPY_REVDB_EMIT(uid = result ? ((struct pypy_header0 *)result)->h_uid : -1;,
int64_t _e, uid);
+ fprintf(stderr, "next_dead: object %lld\n", uid);
if (RPY_RDB_REPLAY) {
if (uid == -1) {
result = NULL;
}
else {
/* fetch and remove the object from the finalizer_tree */
- void **item;
- struct pypy_header0 dummy;
- dummy.h_uid = uid;
- item = tfind(&dummy, &finalizer_tree, _ftree_compare);
- if (item == NULL) {
- fprintf(stderr, "next_dead: object not found\n");
- exit(1);
- }
- result = *item;
- assert(((struct pypy_header0 *)result)->h_uid == uid);
- tdelete(result, &finalizer_tree, _ftree_compare);
+ result = _ftree_pop(&finalizer_tree, uid, NULL);
}
}
return result;
}
-struct destructor_s {
- void *obj;
- void (*callback)(void *);
-};
-
- static int _dtree_compare(const void *obj1, const void *obj2)
-{
- const struct destructor_s *d1 = obj1;
- const struct destructor_s *d2 = obj2;
- const struct pypy_header0 *h1 = d1->obj;
- const struct pypy_header0 *h2 = d2->obj;
- if (h1->h_uid < h2->h_uid)
- return -1;
- if (h1->h_uid == h2->h_uid)
- return 0;
- else
- return 1;
-}
-
RPY_EXTERN
void rpy_reverse_db_register_destructor(void *obj, void (*callback)(void *))
{
@@ -1259,23 +1268,7 @@
NULL, NULL, NULL);
}
else {
- struct destructor_s **item;
- struct destructor_s *node = malloc(sizeof(struct destructor_s));
- if (!node) {
- fprintf(stderr, "register_destructor: malloc: out of memory\n");
- exit(1);
- }
- node->obj = obj;
- node->callback = callback;
- item = tsearch(node, &destructor_tree, _dtree_compare);
- if (item == NULL) {
- fprintf(stderr, "register_destructor: tsearch: out of memory\n");
- exit(1);
- }
- if (*item != node) {
- fprintf(stderr, "register_destructor: duplicate object\n");
- exit(1);
- }
+ _ftree_add(&destructor_tree, obj, callback);
}
}
@@ -1292,26 +1285,15 @@
while (1) {
int64_t uid;
- struct destructor_s d_dummy, *entry, **item;
- struct pypy_header0 o_dummy;
+ struct pypy_header0 *obj;
+ void (*callback)(void *);
RPY_REVDB_EMIT(abort();, int64_t _e, uid);
if (uid == -1)
break;
- d_dummy.obj = &o_dummy;
- o_dummy.h_uid = uid;
- item = tfind(&d_dummy, &destructor_tree, _dtree_compare);
- if (item == NULL) {
- fprintf(stderr, "replay_call_destructors: object not found\n");
- exit(1);
- }
- entry = *item;
- assert(((struct pypy_header0 *)entry->obj)->h_uid == uid);
- tdelete(entry, &destructor_tree, _dtree_compare);
-
- entry->callback(entry->obj);
- free(entry);
+ obj = _ftree_pop(&destructor_tree, uid, &callback);
+ callback(obj);
}
}
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
@@ -35,12 +35,19 @@
"%s:%d: %0*llx\n", \
__FILE__, __LINE__, 2 * sizeof(_e), \
((unsigned long long)_e) & ((2ULL << (8*sizeof(_e)-1)) - 1))
+#endif
+
+#if 1 /* enable to print all allocs to stderr */
# define _RPY_REVDB_PRUID() \
fprintf(stderr, \
"%s:%d: obj %llu\n", \
__FILE__, __LINE__, (unsigned long long) uid)
-#else
+#endif
+
+#ifndef _RPY_REVDB_PRINT
# define _RPY_REVDB_PRINT(mode) /* nothing */
+#endif
+#ifndef _RPY_REVDB_PRUID
# define _RPY_REVDB_PRUID() /* nothing */
#endif
diff --git a/rpython/translator/revdb/test/test_basic.py b/rpython/translator/revdb/test/test_basic.py
--- a/rpython/translator/revdb/test/test_basic.py
+++ b/rpython/translator/revdb/test/test_basic.py
@@ -150,8 +150,7 @@
assert match
hash_value = int(match.group(1))
rdb = self.fetch_rdb([self.exename, 'Xx'])
- # compute_identity_hash() call, but only the first one
- x = rdb.next(); assert intmask(x) == intmask(hash_value)
+ # compute_identity_hash() doesn't record anything
# write() call
x = rdb.next(); assert x == len(out)
x = rdb.next('i'); assert x == 0 # errno
More information about the pypy-commit
mailing list