[pypy-svn] r70742 - in pypy/branch/c-traceback/pypy: rpython/lltypesystem translator translator/c translator/c/src translator/c/test
arigo at codespeak.net
arigo at codespeak.net
Thu Jan 21 13:31:35 CET 2010
Author: arigo
Date: Thu Jan 21 13:31:34 2010
New Revision: 70742
Modified:
pypy/branch/c-traceback/pypy/rpython/lltypesystem/lloperation.py
pypy/branch/c-traceback/pypy/translator/c/funcgen.py
pypy/branch/c-traceback/pypy/translator/c/src/debug_traceback.h
pypy/branch/c-traceback/pypy/translator/c/src/main.h
pypy/branch/c-traceback/pypy/translator/c/test/test_standalone.py
pypy/branch/c-traceback/pypy/translator/exceptiontransform.py
Log:
Change the implementation to make it more or less
work with nested tracebacks.
Modified: pypy/branch/c-traceback/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/c-traceback/pypy/rpython/lltypesystem/lloperation.py (original)
+++ pypy/branch/c-traceback/pypy/rpython/lltypesystem/lloperation.py Thu Jan 21 13:31:34 2010
@@ -536,10 +536,11 @@
'debug_fatalerror': LLOp(),
'debug_llinterpcall': LLOp(), # Python func call 'res=arg[0](*arg[1:])'
# in backends, abort() or whatever is fine
- 'debug_start_traceback':LLOp(),
- 'debug_record_traceback':LLOp(),
- 'debug_catch_exception':LLOp(),
- 'debug_print_traceback':LLOp(),
+ 'debug_start_traceback': LLOp(),
+ 'debug_record_traceback': LLOp(),
+ 'debug_catch_exception': LLOp(),
+ 'debug_reraise_traceback': LLOp(),
+ 'debug_print_traceback': LLOp(),
# __________ instrumentation _________
'instrument_count': LLOp(),
Modified: pypy/branch/c-traceback/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/branch/c-traceback/pypy/translator/c/funcgen.py (original)
+++ pypy/branch/c-traceback/pypy/translator/c/funcgen.py Thu Jan 21 13:31:34 2010
@@ -818,18 +818,17 @@
self.expr(op.args[2]))
def OP_DEBUG_RECORD_TRACEBACK(self, op):
- if self.functionname is None:
- return '/* debug_record_traceback skipped: no functionname */'
- return 'PYPY_DEBUG_RECORD_TRACEBACK("%s");' % self.functionname
+ #if self.functionname is None, we print "?" as the argument */
+ return 'PYPY_DEBUG_RECORD_TRACEBACK("%s");' % (
+ self.functionname or "?",)
def OP_DEBUG_CATCH_EXCEPTION(self, op):
gottype = self.expr(op.args[0])
exprs = []
for c_limited_type in op.args[1:]:
exprs.append('%s == %s' % (gottype, self.expr(c_limited_type)))
- return (self.OP_DEBUG_RECORD_TRACEBACK(None) +
- ' if (%s) { pypy_debug_catch_exception(); }' % (
- ' || '.join(exprs),))
+ return 'PYPY_DEBUG_CATCH_EXCEPTION("%s", %s, %s);' % (
+ self.functionname or "?", gottype, ' || '.join(exprs))
assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)
Modified: pypy/branch/c-traceback/pypy/translator/c/src/debug_traceback.h
==============================================================================
--- pypy/branch/c-traceback/pypy/translator/c/src/debug_traceback.h (original)
+++ pypy/branch/c-traceback/pypy/translator/c/src/debug_traceback.h Thu Jan 21 13:31:34 2010
@@ -2,34 +2,65 @@
/*** C header subsection: RPython tracebacks for debugging ***/
-#define PYPY_DEBUG_TRACEBACK_DEPTH 8
-
-#define OP_DEBUG_START_TRACEBACK() \
- pypy_debug_traceback_count = PYPY_DEBUG_TRACEBACK_DEPTH
+/* We store a list of (location, exctype) in a circular buffer that
+ we hope is large enough. Example of how to interpret the content
+ of the buffer:
+
+ location exctype meaning
+
+ NULL &KeyError a KeyError was raised
+ h:5 NULL it was raised at h:5
+ g:12 NULL which itself was called from g:12
+ f:17 &KeyError called from f:17, where a finally block starts
+ ... ...more exceptions can occur...
+ RERAISE &KeyError eventually the KeyError is re-raised by f
+ entry:25 NULL which itself was called from entry:25
+
+ Note that decoding the buffer assumes that when exctype matches, it was
+ really the same exception, for the purpose of going back from the RERAISE
+ line to the f:17/KeyError line.
+*/
-#define OP_DEBUG_PRINT_TRACEBACK() \
- pypy_debug_traceback_print()
+#define PYPY_DEBUG_TRACEBACK_DEPTH 128 /* a power of two */
-#define PYPY_DEBUG_RECORD_TRACEBACK(funcname) \
- if ((--pypy_debug_traceback_count) >= 0) { \
- static struct pydtentry_s entry = { PYPY_FILE_NAME, funcname, __LINE__ }; \
- pypy_debug_tracebacks[pypy_debug_traceback_count] = &entry; \
+#define PYPYDTPOS_RERAISE ((struct pypydtpos_s *) -1)
+#define PYPYDTSTORE(loc, etype) \
+ pypy_debug_tracebacks[pypydtcount].location = loc; \
+ pypy_debug_tracebacks[pypydtcount].exctype = etype; \
+ pypydtcount = (pypydtcount + 1) & (PYPY_DEBUG_TRACEBACK_DEPTH-1)
+
+#define OP_DEBUG_START_TRACEBACK(etype, _) PYPYDTSTORE(NULL, etype)
+#define OP_DEBUG_RERAISE_TRACEBACK(etp, _) PYPYDTSTORE(PYPYDTPOS_RERAISE, etp)
+#define OP_DEBUG_PRINT_TRACEBACK() pypy_debug_traceback_print()
+
+#define PYPY_DEBUG_RECORD_TRACEBACK(funcname) { \
+ static struct pypydtpos_s loc = { \
+ PYPY_FILE_NAME, funcname, __LINE__ }; \
+ PYPYDTSTORE(&loc, NULL); \
+ }
+#define PYPY_DEBUG_CATCH_EXCEPTION(funcname, etype, is_fatal) { \
+ static struct pypydtpos_s loc = { \
+ PYPY_FILE_NAME, funcname, __LINE__ }; \
+ PYPYDTSTORE(&loc, etype); \
+ if (is_fatal) pypy_debug_catch_fatal_exception(); \
}
-/* Format of the data: to represent a location in the source code, we
- use for now just a pointer to a 'pypy_debug_traceback_entry_s'.
-*/
-struct pydtentry_s {
+struct pypydtpos_s {
const char *filename;
const char *funcname;
int lineno;
};
-extern int pypy_debug_traceback_count;
-extern struct pydtentry_s *pypy_debug_tracebacks[PYPY_DEBUG_TRACEBACK_DEPTH];
+struct pypydtentry_s {
+ struct pypydtpos_s *location;
+ void *exctype;
+};
+
+extern int pypydtcount;
+extern struct pypydtentry_s pypy_debug_tracebacks[PYPY_DEBUG_TRACEBACK_DEPTH];
void pypy_debug_traceback_print(void);
-void pypy_debug_catch_exception(void);
+void pypy_debug_catch_fatal_exception(void);
/************************************************************/
@@ -37,29 +68,56 @@
#ifndef PYPY_NOT_MAIN_FILE
-int pypy_debug_traceback_count = PYPY_DEBUG_TRACEBACK_DEPTH;
-struct pydtentry_s *pypy_debug_tracebacks[PYPY_DEBUG_TRACEBACK_DEPTH];
+int pypydtcount = 0;
+struct pypydtentry_s pypy_debug_tracebacks[PYPY_DEBUG_TRACEBACK_DEPTH];
void pypy_debug_traceback_print(void)
{
- int i, lineno;
- const char *filename;
- const char *funcname;
+ int i;
+ int skipping;
+ void *my_etype = RPyFetchExceptionType();
+ struct pypydtpos_s *location;
+ void *etype;
+ int has_loc;
+ /* This code parses the pypy_debug_tracebacks array. See example
+ at the start of the file. */
fprintf(stderr, "RPython traceback:\n");
- for (i = 0; i < PYPY_DEBUG_TRACEBACK_DEPTH; i++)
+ skipping = 0;
+ i = (pypydtcount - 1) & (PYPY_DEBUG_TRACEBACK_DEPTH-1);
+ while (i != pypydtcount)
{
- if (i < pypy_debug_traceback_count)
- continue;
- filename = pypy_debug_tracebacks[i]->filename;
- funcname = pypy_debug_tracebacks[i]->funcname;
- lineno = pypy_debug_tracebacks[i]->lineno;
- fprintf(stderr, " File \"%s\", line %d, in %s\n",
- filename, lineno, funcname);
+ location = pypy_debug_tracebacks[i].location;
+ etype = pypy_debug_tracebacks[i].exctype;
+ has_loc = location != NULL && location != PYPYDTPOS_RERAISE;
+
+ if (skipping && has_loc && etype == my_etype)
+ skipping = 0; /* found the matching "f:17, &KeyError */
+
+ if (!skipping)
+ {
+ if (has_loc)
+ fprintf(stderr, " File \"%s\", line %d, in %s\n",
+ location->filename, location->lineno, location->funcname);
+ else
+ {
+ /* line "NULL, &KeyError" or "RERAISE, &KeyError" */
+ if (etype != my_etype)
+ {
+ fprintf(stderr, " Note: this traceback is "
+ "incomplete or corrupted!\n");
+ break;
+ }
+ if (location == NULL) /* found the place that raised the exc */
+ break;
+ skipping = 1; /* RERAISE: skip until "f:17, &KeyError" */
+ }
+ }
+ i = (i - 1) & (PYPY_DEBUG_TRACEBACK_DEPTH-1);
}
}
-void pypy_debug_catch_exception(void)
+void pypy_debug_catch_fatal_exception(void)
{
pypy_debug_traceback_print();
fprintf(stderr, "Fatal RPython error: %s\n",
Modified: pypy/branch/c-traceback/pypy/translator/c/src/main.h
==============================================================================
--- pypy/branch/c-traceback/pypy/translator/c/src/main.h (original)
+++ pypy/branch/c-traceback/pypy/translator/c/src/main.h Thu Jan 21 13:31:34 2010
@@ -36,8 +36,8 @@
exitcode = STANDALONE_ENTRY_POINT(list);
if (RPyExceptionOccurred()) {
- /* fish for the exception type, at least */
- pypy_debug_catch_exception();
+ /* print the RPython traceback */
+ pypy_debug_catch_fatal_exception();
}
return exitcode;
Modified: pypy/branch/c-traceback/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/branch/c-traceback/pypy/translator/c/test/test_standalone.py (original)
+++ pypy/branch/c-traceback/pypy/translator/c/test/test_standalone.py Thu Jan 21 13:31:34 2010
@@ -413,7 +413,8 @@
assert lines2[-2] != lines[-2] # different line number
assert lines2[-3] == lines[-3] # same line number
- def test_fatal_error_finally(self):
+ def test_fatal_error_finally_1(self):
+ # a simple case of try:finally:
def g(x):
if x == 1:
raise KeyError
@@ -439,6 +440,77 @@
assert re.match(r' File "\w+.c", line \d+, in pypy_g_h', l2)
assert re.match(r' File "\w+.c", line \d+, in pypy_g_g', l3)
+ def test_fatal_error_finally_2(self):
+ # a try:finally: in which we raise and catch another exception
+ def raiseme(x):
+ if x == 1:
+ raise ValueError
+ def raise_and_catch(x):
+ try:
+ raiseme(x)
+ except ValueError:
+ pass
+ def g(x):
+ if x == 1:
+ raise KeyError
+ def h(x):
+ try:
+ g(x)
+ finally:
+ raise_and_catch(x)
+ os.write(1, 'done.\n')
+ def entry_point(argv):
+ if len(argv) < 3:
+ h(len(argv))
+ return 0
+ t, cbuilder = self.compile(entry_point)
+ #
+ out, err = cbuilder.cmdexec("", expect_crash=True)
+ assert out.strip() == 'done.'
+ lines = err.strip().splitlines()
+ assert lines[-1] == 'Fatal RPython error: KeyError'
+ assert len(lines) >= 5
+ l0, l1, l2, l3 = lines[-5:-1]
+ assert l0 == 'RPython traceback:'
+ assert re.match(r' File "\w+.c", line \d+, in pypy_g_entry_point', l1)
+ assert re.match(r' File "\w+.c", line \d+, in pypy_g_h', l2)
+ assert re.match(r' File "\w+.c", line \d+, in pypy_g_g', l3)
+
+ def test_fatal_error_finally_3(self):
+ py.test.skip("not implemented: "
+ "a try:finally: in which we raise the *same* exception")
+
+ def test_fatal_error_finally_4(self):
+ # a try:finally: in which we raise (and don't catch) an exception
+ def raiseme(x):
+ if x == 1:
+ raise ValueError
+ def g(x):
+ if x == 1:
+ raise KeyError
+ def h(x):
+ try:
+ g(x)
+ finally:
+ raiseme(x)
+ os.write(1, 'done.\n')
+ def entry_point(argv):
+ if len(argv) < 3:
+ h(len(argv))
+ return 0
+ t, cbuilder = self.compile(entry_point)
+ #
+ out, err = cbuilder.cmdexec("", expect_crash=True)
+ assert out.strip() == ''
+ lines = err.strip().splitlines()
+ assert lines[-1] == 'Fatal RPython error: ValueError'
+ assert len(lines) >= 5
+ l0, l1, l2, l3 = lines[-5:-1]
+ assert l0 == 'RPython traceback:'
+ assert re.match(r' File "\w+.c", line \d+, in pypy_g_entry_point', l1)
+ assert re.match(r' File "\w+.c", line \d+, in pypy_g_h', l2)
+ assert re.match(r' File "\w+.c", line \d+, in pypy_g_raiseme', l3)
+
def test_assertion_error(self):
def g(x):
assert x != 1
Modified: pypy/branch/c-traceback/pypy/translator/exceptiontransform.py
==============================================================================
--- pypy/branch/c-traceback/pypy/translator/exceptiontransform.py (original)
+++ pypy/branch/c-traceback/pypy/translator/exceptiontransform.py Thu Jan 21 13:31:34 2010
@@ -89,11 +89,12 @@
# assert(!RPyExceptionOccurred());
exc_data.exc_type = etype
exc_data.exc_value = evalue
- lloperation.llop.debug_start_traceback(lltype.Void)
+ lloperation.llop.debug_start_traceback(lltype.Void, etype)
def rpyexc_reraise(etype, evalue):
exc_data.exc_type = etype
exc_data.exc_value = evalue
+ lloperation.llop.debug_reraise_traceback(lltype.Void, etype)
def rpyexc_fetch_exception():
evalue = rpyexc_fetch_value()
@@ -325,22 +326,24 @@
def transform_jump_to_except_block(self, graph, entrymap, link):
reraise = self.comes_from_last_exception(entrymap, link)
- if reraise:
- fnptr = self.rpyexc_reraise_ptr
- else:
- fnptr = self.rpyexc_raise_ptr
result = Variable()
result.concretetype = lltype.Void
block = Block([copyvar(None, v)
for v in graph.exceptblock.inputargs])
- block.operations = [
- SpaceOperation("direct_call",
- [fnptr] + block.inputargs,
- result)]
- if not reraise:
- block.operations.append(
+ if reraise:
+ block.operations = [
+ SpaceOperation("direct_call",
+ [self.rpyexc_reraise_ptr] + block.inputargs,
+ result),
+ ]
+ else:
+ block.operations = [
+ SpaceOperation("direct_call",
+ [self.rpyexc_raise_ptr] + block.inputargs,
+ result),
SpaceOperation('debug_record_traceback', [],
- varoftype(lltype.Void)))
+ varoftype(lltype.Void)),
+ ]
link.target = block
RETTYPE = graph.returnblock.inputargs[0].concretetype
l = Link([error_constant(RETTYPE)], graph.returnblock)
More information about the Pypy-commit
mailing list