[pypy-svn] r70543 - 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
Tue Jan 12 19:02:21 CET 2010


Author: arigo
Date: Tue Jan 12 19:02:21 2010
New Revision: 70543

Added:
   pypy/branch/c-traceback/pypy/translator/c/src/debug_traceback.h   (contents, props changed)
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/genc.py
   pypy/branch/c-traceback/pypy/translator/c/src/g_include.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:
Pass the first 2 tests.


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	Tue Jan 12 19:02:21 2010
@@ -87,6 +87,7 @@
     def is_pure(self, args_v):
         return (self.canfold or                # canfold => pure operation
                 self is llop.debug_assert or   # debug_assert is pure enough
+                self is llop.debug_assert_with_tb or
                                                # reading from immutable
                 (self in (llop.getfield, llop.getarrayitem) and
                  args_v[0].concretetype.TO._hints.get('immutable')) or
@@ -536,6 +537,8 @@
     '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_catch_exception':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	Tue Jan 12 19:02:21 2010
@@ -817,5 +817,19 @@
             self.expr(op.args[1]),
             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
+
+    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),))
+
 
 assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)

Modified: pypy/branch/c-traceback/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/c-traceback/pypy/translator/c/genc.py	(original)
+++ pypy/branch/c-traceback/pypy/translator/c/genc.py	Tue Jan 12 19:02:21 2010
@@ -715,6 +715,7 @@
             print >> fc, '/***  Implementations                                    ***/'
             print >> fc
             print >> fc, '#define PYPY_NOT_MAIN_FILE'
+            print >> fc, '#define PYPY_FILE_NAME "%s"' % name
             print >> fc, '#include "common_header.h"'
             print >> fc, '#include "structdef.h"'
             print >> fc, '#include "forwarddecl.h"'
@@ -787,6 +788,7 @@
     print >> f, '/***********************************************************/'
     print >> f, '/***  Implementations                                    ***/'
     print >> f
+    print >> f, '#define PYPY_FILE_NAME "%s"' % os.path.basename(f.name)
     for line in preimplementationlines:
         print >> f, line
     print >> f, '#include "src/g_include.h"'

Added: pypy/branch/c-traceback/pypy/translator/c/src/debug_traceback.h
==============================================================================
--- (empty file)
+++ pypy/branch/c-traceback/pypy/translator/c/src/debug_traceback.h	Tue Jan 12 19:02:21 2010
@@ -0,0 +1,66 @@
+/**************************************************************/
+ /***  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
+
+#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;         \
+  }
+
+/* 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 {
+  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];
+
+void pypy_debug_catch_exception(void);
+
+
+/************************************************************/
+
+
+#ifndef PYPY_NOT_MAIN_FILE
+
+int pypy_debug_traceback_count = PYPY_DEBUG_TRACEBACK_DEPTH;
+struct pydtentry_s *pypy_debug_tracebacks[PYPY_DEBUG_TRACEBACK_DEPTH];
+
+void pypy_debug_traceback_print(void)
+{
+  int i, lineno;
+  const char *filename;
+  const char *funcname;
+
+  fprintf(stderr, "RPython traceback:\n");
+  for (i=PYPY_DEBUG_TRACEBACK_DEPTH-1; i>=0; i--)
+    {
+      if (i < pypy_debug_traceback_count)
+        break;
+      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);
+    }
+}
+
+void pypy_debug_catch_exception(void)
+{
+  pypy_debug_traceback_print();
+  fprintf(stderr, "Fatal RPython error: %s\n",
+          RPyFetchExceptionType()->ov_name->items);
+  abort();
+}
+
+#endif /* PYPY_NOT_MAIN_FILE */

Modified: pypy/branch/c-traceback/pypy/translator/c/src/g_include.h
==============================================================================
--- pypy/branch/c-traceback/pypy/translator/c/src/g_include.h	(original)
+++ pypy/branch/c-traceback/pypy/translator/c/src/g_include.h	Tue Jan 12 19:02:21 2010
@@ -52,6 +52,7 @@
 #ifdef HAVE_RTYPER      /* only if we have an RTyper */
 #  include "src/rtyper.h"
 #  include "src/debug_print.h"
+#  include "src/debug_traceback.h"
 #ifndef AVR
 #  include "src/ll_os.h"
 #  include "src/ll_strtod.h"

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	Tue Jan 12 19:02:21 2010
@@ -37,11 +37,7 @@
     exitcode = STANDALONE_ENTRY_POINT(list);
     if (RPyExceptionOccurred()) {
         /* fish for the exception type, at least */
-#ifndef AVR
-        fprintf(stderr, "Fatal RPython error: %s\n",
-                RPyFetchExceptionType()->ov_name->items);
-#endif
-        abort();
+        pypy_debug_catch_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	Tue Jan 12 19:02:21 2010
@@ -396,8 +396,8 @@
         assert len(lines) >= 4
         l0, l1, l2 = lines[-4:-1]
         assert l0 == 'RPython traceback:'
-        assert re.match(r'  File "\w+.c", line \d+, in g', l1)
-        assert re.match(r'  File "\w+.c", line \d+, in entry_point', l2)
+        assert re.match(r'  File "\w+.c", line \d+, in pypy_g_g', l1)
+        assert re.match(r'  File "\w+.c", line \d+, in pypy_g_entry_point', l2)
         #
         out2, err2 = cbuilder.cmdexec("x", expect_crash=True)
         assert out2.strip() == ''
@@ -405,10 +405,10 @@
         assert lines2[-1] == 'Fatal RPython error: KeyError'
         l0, l1, l2 = lines2[-4:-1]
         assert l0 == 'RPython traceback:'
-        assert re.match(r'  File "\w+.c", line \d+, in g', l1)
-        assert re.match(r'  File "\w+.c", line \d+, in entry_point', l2)
-        assert lines2[-3] != lines[-3]
-        assert lines2[-2] == lines[-2]
+        assert re.match(r'  File "\w+.c", line \d+, in pypy_g_g', l1)
+        assert re.match(r'  File "\w+.c", line \d+, in pypy_g_entry_point', l2)
+        assert lines2[-3] != lines[-3]    # different line number
+        assert lines2[-2] == lines[-2]    # same line number
 
     def test_assertion_error(self):
         def g(x):
@@ -429,8 +429,8 @@
         assert len(lines) >= 4
         l0, l1, l2 = lines[-4:-1]
         assert l0 == 'RPython traceback:'
-        assert re.match(r'  File "\w+.c", line \d+, in g', l1)
-        assert re.match(r'  File "\w+.c", line \d+, in f', l2)
+        assert re.match(r'  File "\w+.c", line \d+, in pypy_g_g', l1)
+        assert re.match(r'  File "\w+.c", line \d+, in pypy_g_f', l2)
         # The traceback stops at f() because it's the first function that
         # captures the AssertionError, which makes the program abort.
 

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	Tue Jan 12 19:02:21 2010
@@ -16,6 +16,7 @@
 from pypy.rlib.debug import ll_assert
 from pypy.annotation import model as annmodel
 from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
+from pypy.tool.sourcetools import func_with_new_name
 
 PrimitiveErrorValue = {lltype.Signed: -1,
                        lltype.Unsigned: r_uint(-1),
@@ -45,6 +46,9 @@
 def error_constant(T):
     return Constant(error_value(T), T)
 
+def constant_value(llvalue):
+    return Constant(llvalue, lltype.typeOf(llvalue))
+
 class BaseExceptionTransformer(object):
 
     def __init__(self, translator):
@@ -64,6 +68,10 @@
         (n_i_error_ll_exc_type,
          n_i_error_ll_exc) = self.get_builtin_exception(NotImplementedError)
 
+        self.c_assertion_error_ll_exc_type = constant_value(
+            assertion_error_ll_exc_type)
+        self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type)
+
         def rpyexc_occured():
             exc_type = exc_data.exc_type
             return bool(exc_type)
@@ -82,6 +90,7 @@
             # assert(!RPyExceptionOccurred());
             exc_data.exc_type = etype
             exc_data.exc_value = evalue
+            lloperation.llop.debug_start_traceback(lltype.Void)
 
         def rpyexc_fetch_exception():
             evalue = rpyexc_fetch_value()
@@ -90,7 +99,8 @@
         
         def rpyexc_restore_exception(evalue):
             if evalue:
-                rpyexc_raise(rclass.ll_inst_type(evalue), evalue)
+                exc_data.exc_type = rclass.ll_inst_type(evalue)
+                exc_data.exc_value = evalue
 
         def rpyexc_raise_runtime_error():
             rpyexc_raise(runtime_error_ll_exc_type, runtime_error_ll_exc)
@@ -117,14 +127,14 @@
 
         self.rpyexc_raise_ptr = self.build_func(
             "RPyRaiseException",
-            rpyexc_raise,
+            self.noinline(rpyexc_raise),
             [self.lltype_of_exception_type, self.lltype_of_exception_value],
             lltype.Void,
             jitcallkind='rpyexc_raise') # for the JIT
 
         self.rpyexc_raise_runtime_error_ptr = self.build_func(
             "RPyRaiseRuntimeError",
-            rpyexc_raise_runtime_error,
+            self.noinline(rpyexc_raise_runtime_error),
             [], lltype.Void)
 
         self.rpyexc_fetch_exception_ptr = self.build_func(
@@ -134,7 +144,7 @@
 
         self.rpyexc_restore_exception_ptr = self.build_func(
             "RPyRestoreException",
-            rpyexc_restore_exception,
+            self.noinline(rpyexc_restore_exception),
             [self.lltype_of_exception_value], lltype.Void)
 
         self.build_extra_funcs()
@@ -142,6 +152,11 @@
         self.mixlevelannotator.finish()
         self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()
 
+    def noinline(self, fn):
+        fn = func_with_new_name(fn, fn.__name__ + '_noinline')
+        fn._dont_inline_ = True
+        return fn
+
     def build_func(self, name, fn, inputtypes, rettype, **kwds):
         l2a = annmodel.lltype_to_annotation
         graph = self.mixlevelannotator.getgraph(fn, map(l2a, inputtypes), l2a(rettype))
@@ -185,10 +200,10 @@
         for block in list(graph.iterblocks()):
             self.replace_stack_unwind(block)
             self.replace_fetch_restore_operations(block)
+            self.transform_jump_to_except_block(graph, block.exits)
             need_exc_matching, gen_exc_checks = self.transform_block(graph, block)
             n_need_exc_matching_blocks += need_exc_matching
             n_gen_exc_checks           += gen_exc_checks
-        self.transform_except_block(graph, graph.exceptblock)
         cleanup_graph(graph)
         removenoops.remove_superfluous_keep_alive(graph)
         return n_need_exc_matching_blocks, n_gen_exc_checks
@@ -266,19 +281,23 @@
                 self.insert_matching(lastblock, graph)
         return need_exc_matching, n_gen_exc_checks
 
-    def transform_except_block(self, graph, block):
-        # attach an except block -- let's hope that nobody uses it
-        graph.exceptblock = Block([Variable('etype'),   # exception class
-                                   Variable('evalue')])  # exception value
-        graph.exceptblock.operations = ()
-        graph.exceptblock.closeblock()
-        
-        result = Variable()
-        result.concretetype = lltype.Void
-        block.operations = [SpaceOperation(
-           "direct_call", [self.rpyexc_raise_ptr] + block.inputargs, result)]
-        l = Link([error_constant(graph.returnblock.inputargs[0].concretetype)], graph.returnblock)
-        block.recloseblock(l)
+    def transform_jump_to_except_block(self, graph, exits):
+        for link in exits:
+            if link.target is graph.exceptblock:
+                result = Variable()
+                result.concretetype = lltype.Void
+                block = Block([copyvar(None, v)
+                               for v in graph.exceptblock.inputargs])
+                block.operations = [
+                    SpaceOperation("direct_call",
+                                   [self.rpyexc_raise_ptr] + block.inputargs,
+                                   result),
+                    SpaceOperation('debug_record_traceback', [],
+                                   varoftype(lltype.Void))]
+                link.target = block
+                RETTYPE = graph.returnblock.inputargs[0].concretetype
+                l = Link([error_constant(RETTYPE)], graph.returnblock)
+                block.recloseblock(l)
 
     def insert_matching(self, block, graph):
         proxygraph, op = self.create_proxy_graph(block.operations[-1])
@@ -326,6 +345,11 @@
         llops = rtyper.LowLevelOpList(None)
         var_value = self.gen_getfield('exc_value', llops)
         var_type  = self.gen_getfield('exc_type' , llops)
+        #
+        c_check1 = self.c_assertion_error_ll_exc_type
+        c_check2 = self.c_n_i_error_ll_exc_type
+        llops.genop('debug_catch_exception', [var_type, c_check1, c_check2])
+        #
         self.gen_setfield('exc_value', self.c_null_evalue, llops)
         self.gen_setfield('exc_type',  self.c_null_etype,  llops)
         excblock.operations[:] = llops
@@ -359,7 +383,12 @@
         
         block.exitswitch = var_no_exc
         #exception occurred case
+        b = Block([])
+        b.operations = [SpaceOperation('debug_record_traceback', [],
+                                       varoftype(lltype.Void))]
         l = Link([error_constant(returnblock.inputargs[0].concretetype)], returnblock)
+        b.closeblock(l)
+        l = Link([], b)
         l.exitcase = l.llexitcase = False
 
         #non-exception case



More information about the Pypy-commit mailing list