Author: jrieks
Date: Mon Apr 18 08:32:05 2005
New Revision: 7862

Modified:
   trunk/classes/continuation.pmc
   trunk/include/parrot/sub.h
   trunk/include/parrot/warnings.h
   trunk/src/debug.c
   trunk/src/exceptions.c
   trunk/src/sub.c
   trunk/src/warnings.c
   trunk/t/op/debuginfo.t
   trunk/t/pmc/perlarray.t
   trunk/t/pmc/perlundef.t
   trunk/t/pmc/sub.t
Log:
- improved PDB_backtrace
- added recursion detection ("... call repeated X times")
- removed src/warnings.c:find_line, print_pbc_location_stdio
- refactored pbc location printing/formating code, it is now in:
- added Parrot_Context_info and Parrot_Context_infostr,
  they encapuslate the "called from Sub '...' pc .. (file:line)"-logic
- show a backtrace if an exception was not caught (before parrot exits)
- if "debug 1" was executed, all (real_)exceptions are shown (including
  a backtrace), even if an exception handler was installed
- adjusted tests to reflect changed output



Modified: trunk/classes/continuation.pmc
==============================================================================
--- trunk/classes/continuation.pmc      (original)
+++ trunk/classes/continuation.pmc      Mon Apr 18 08:32:05 2005
@@ -230,20 +230,7 @@
 */
 
     STRING* get_string() {
-        struct Parrot_cont * cc = PMC_cont(SELF);
-        PMC *caller;
-        STRING *s;
-
-        caller = cc->ctx.current_sub;
-        s = NULL;
-        if (caller && PMC_sub(caller)->address) {
-            size_t offs = cc->ctx.current_pc -
-                PMC_sub(caller)->seg->base.data;
-            s = Parrot_sprintf_c(INTERP,
-                    "called from Sub '%Ss' pc %d\n",
-                    Parrot_full_sub_name(INTERP, caller), (int)offs);
-        }
-        return s;
+       return Parrot_Context_infostr(INTERP, &PMC_cont(SELF)->ctx);
     }
 
 /*

Modified: trunk/include/parrot/sub.h
==============================================================================
--- trunk/include/parrot/sub.h  (original)
+++ trunk/include/parrot/sub.h  Mon Apr 18 08:32:05 2005
@@ -84,6 +84,16 @@
 
 #define PMC_cont(pmc) LVALUE_CAST(parrot_cont_t, PMC_struct_val(pmc))
 
+struct Parrot_Context_info {
+    STRING* subname;
+    STRING* nsname;
+    STRING* fullname;
+    int pc;
+    const char *file;
+    int line;
+    opcode_t *address;
+};
+
 struct Parrot_sub * new_sub(Interp * interp);
 struct Parrot_sub * new_closure(Interp * interp);
 struct Parrot_coro * new_coroutine(Interp * interp);
@@ -104,6 +114,8 @@
 void add_to_retc_cache(Interp *interpreter, PMC *pmc);
 void mark_retc_cache(Interp *);
 STRING* Parrot_full_sub_name(Interp* interpreter, PMC* sub);
+int Parrot_Context_info(Interp *interpreter, struct Parrot_Context *, struct 
Parrot_Context_info *);
+STRING* Parrot_Context_infostr(Interp *interpreter, struct Parrot_Context *);
 
 #endif /* PARROT_SUB_H_GUARD */
 

Modified: trunk/include/parrot/warnings.h
==============================================================================
--- trunk/include/parrot/warnings.h     (original)
+++ trunk/include/parrot/warnings.h     Mon Apr 18 08:32:05 2005
@@ -46,7 +46,6 @@
 #include "parrot/parrot.h"
 
 void print_pbc_location(Parrot_Interp);
-void print_pbc_location_stdio(Parrot_Interp);
 
 INTVAL Parrot_warn(Parrot_Interp, INTVAL warnclass, const char *message, ...);
 

Modified: trunk/src/debug.c
==============================================================================
--- trunk/src/debug.c   (original)
+++ trunk/src/debug.c   Mon Apr 18 08:32:05 2005
@@ -2942,27 +2942,44 @@
 {
     STRING *str;
     PMC *sub;
-
+    PMC *old = PMCNULL;
+    int rec_level = 0;
+    
     /* information about the current sub */
     sub = interpinfo_p(interpreter, CURRENT_SUB);
     if (!PMC_IS_NULL(sub)) {
-       str = VTABLE_get_string(interpreter, sub);
-       PIO_eprintf(interpreter, "current instr.: '%Ss' pc %d\n",
-           str,
-           interpreter->ctx.current_pc - PMC_sub(sub)->address
-       );
+       str = Parrot_Context_infostr(interpreter, &interpreter->ctx);
+       if (str)
+           PIO_eprintf(interpreter, "%Ss", str);
     }
 
+    /* backtrace: follow the continuation chain */
     sub = interpinfo_p(interpreter, CURRENT_CONT);
-    while (!PMC_IS_NULL(sub) && sub->vtable->base_type == 
enum_class_Continuation) {
-       str = VTABLE_get_string(interpreter, sub);
-       if (!str)
-           break;
-       PIO_eprintf(interpreter, "%Ss",
-           str
-       );
+    while (!PMC_IS_NULL(sub) &&
+           sub->vtable->base_type == enum_class_Continuation &&
+           NULL != (str = Parrot_Context_infostr(interpreter,
+                   &PMC_cont(sub)->ctx)) ) {
+
+       /* recursion detection */
+       if (!PMC_IS_NULL(old) && PMC_cont(old) &&
+           PMC_cont(old)->ctx.current_pc == PMC_cont(sub)->ctx.current_pc &&
+           PMC_cont(old)->ctx.current_sub == PMC_cont(sub)->ctx.current_sub) {
+           ++rec_level;
+       } else if (rec_level != 0) {
+           PIO_eprintf(interpreter, "... call repeated %d times\n", rec_level);
+           rec_level = 0;
+       }
+
+       /* print the context description */
+       if (rec_level == 0)
+           PIO_eprintf(interpreter, "%Ss", str);
+
        /* get the next Continuation */
-        sub = PMC_cont(sub)->ctx.current_cont;
+       old = sub;
+       sub = PMC_cont(sub)->ctx.current_cont;
+    }
+    if (rec_level != 0) {
+        PIO_eprintf(interpreter, "... call repeated %d times\n", rec_level);
     }
 }
 

Modified: trunk/src/exceptions.c
==============================================================================
--- trunk/src/exceptions.c      (original)
+++ trunk/src/exceptions.c      Mon Apr 18 08:32:05 2005
@@ -270,7 +270,7 @@
     if (m)
         string_cstring_free(m);
     if (print_location)
-        print_pbc_location_stdio(interpreter);
+        PDB_backtrace(interpreter);
     /*
      * returning NULL from here returns resume address NULL to the
      * runloop, which will terminate the thread function finally

Modified: trunk/src/sub.c
==============================================================================
--- trunk/src/sub.c     (original)
+++ trunk/src/sub.c     Mon Apr 18 08:32:05 2005
@@ -539,12 +539,115 @@
     if (PMC_IS_NULL(s->name_space)) {
         return s->name;
     } else {
-        STRING* ns = VTABLE_get_string(interpreter, s->name_space);
-
-        ns = string_concat(interpreter, ns, string_from_cstring(interpreter, " 
:: ", 4), 0);
         if (s->name) {
-            return string_concat(interpreter, ns, s->name, 0);
-        }
+           STRING* ns = VTABLE_get_string(interpreter, s->name_space);
+
+           ns = string_concat(interpreter, ns,
+               string_from_cstring(interpreter, " :: ", 4), 0);
+           return string_concat(interpreter, ns, s->name, 0);
+        } else {
+           STRING* ns = string_from_cstring(interpreter, "??? :: ", 7);
+           return string_concat(interpreter, ns, s->name, 0);
+       }
+    }
+    return NULL;
+}
+
+int
+Parrot_Context_info(Interp *interpreter, struct Parrot_Context *ctx,
+       struct Parrot_Context_info *info)
+{
+    struct Parrot_sub *sub;
+
+    /* set file/line/pc defaults */
+    info->file = "(unknown file)";
+    info->line = -1;
+    info->pc = -1;
+        
+    /* is the current sub of the specified context valid? */
+    if (PMC_IS_NULL(ctx->current_sub)) {
+       info->subname = string_from_cstring(interpreter, "???", 3);
+       info->nsname = info->subname;
+       info->fullname = string_from_cstring(interpreter, "??? :: ???", 10);
+       info->pc = -1;
+       return 0;
+    }
+
+    /* make sure there is a sub (not always the case, e.g in pasm code) */
+    if (ctx->current_sub->vtable->base_type == enum_class_Undef ||
+           PMC_sub(ctx->current_sub)->address == 0) {
+       info->nsname = NULL;
+       info->subname = NULL;
+       info->fullname = NULL;
+       /* XXX: is this correct? (try with load_bytecode) */
+       /* use the current interpreter's bytecode as start address */
+       if (ctx->current_pc != NULL)
+           info->pc = ctx->current_pc - interpreter->code->byte_code;
+       return 1;
+    }
+
+    /* fetch struct Parrot_sub of the current sub in the given context */
+    sub = PMC_sub(ctx->current_sub);
+
+    /* set the sub name */
+    info->subname = sub->name;
+    
+    /* set the namespace name and fullname of the sub */
+    if (PMC_IS_NULL(sub->name_space)) {
+       info->nsname = string_from_cstring(interpreter, "", 0);
+       info->fullname = info->subname;
+    } else {
+       info->nsname = VTABLE_get_string(interpreter, sub->name_space);
+       info->fullname = string_concat(interpreter, info->nsname, 
+               string_from_cstring(interpreter, " :: ", 4), 0);
+       info->fullname = string_concat(interpreter, info->fullname,
+               info->subname, 1);
+    }
+
+    /* return here if there is no current pc */
+    if (ctx->current_pc == NULL)
+       return 1;
+
+    /* calculate the current pc */
+    info->pc = ctx->current_pc - sub->seg->base.data;
+
+    /* determine the current source file/line */
+    if (interpreter->ctx.current_pc) {
+       size_t offs = info->pc;
+       size_t i, n;
+       /* XXX: interpreter->code->cur_cs is not correct, is it? */
+       opcode_t *pc = interpreter->code->cur_cs->base.data;
+       struct PackFile_Debug *debug = interpreter->code->cur_cs->debugs;
+
+       /*assert(pc == sub->seg->base.data);*/
+       /* set source file */
+       info->file = debug->filename;
+       for (i = n = 0; n < interpreter->code->cur_cs->base.size; i++) {
+           op_info_t *op_info = &interpreter->op_info_table[*pc];
+           if (n >= offs) {
+               /* set source line */
+               info->line = debug->base.data[i];
+               break;
+           }
+           n += op_info->arg_count;
+           pc += op_info->arg_count;
+       }
+    }    
+    return 1;
+}
+
+STRING*
+Parrot_Context_infostr(Interp *interpreter, struct Parrot_Context *ctx)
+{
+    struct Parrot_Context_info info;
+    const char* msg = (&interpreter->ctx == ctx) ?
+       "current instr.:":
+       "called from Sub";
+
+    if (Parrot_Context_info(interpreter, ctx, &info)) {
+       return Parrot_sprintf_c(interpreter,
+               "%s '%Ss' pc %d (%s:%d)\n", msg,
+               info.fullname, info.pc, info.file, info.line);
     }
     return NULL;
 }

Modified: trunk/src/warnings.c
==============================================================================
--- trunk/src/warnings.c        (original)
+++ trunk/src/warnings.c        Mon Apr 18 08:32:05 2005
@@ -22,46 +22,6 @@
 
 /*
 
-=head2 Internal Functions
-
-=over 4
-
-=item C<static int
-find_line(Interp *interpreter, struct PackFile_Debug * debug)>
-
-Find the line number.
-
-Returns -2 if the interpreter has no current profile counter.
-
-I<What does returning -1 mean?>
-
-=cut
-
-*/
-
-static int
-find_line(Interp *interpreter, struct PackFile_Debug * debug)
-{
-    size_t offs, i, n;
-    op_info_t *op_info;
-    opcode_t *pc;
-
-    if (!interpreter->ctx.current_pc)
-        return -2;
-    pc = interpreter->code->cur_cs->base.data;
-    offs = interpreter->ctx.current_pc - pc;
-    for (i = n = 0; n < interpreter->code->cur_cs->base.size; i++) {
-        op_info = &interpreter->op_info_table[*pc];
-        if (n >= offs)
-            return (int) debug->base.data[i];
-        n += op_info->arg_count;
-        pc += op_info->arg_count;
-    }
-    return -1;
-}
-
-/*
-
 =item C<void
 print_pbc_location(Parrot_Interp interpreter)>
 
@@ -72,50 +32,9 @@
 */
 
 void
-print_pbc_location(Parrot_Interp interpreter)
-{
-    const char *file;
-    int line;
-    struct PackFile_Debug * debugs = interpreter->code->cur_cs->debugs;
-    if (debugs) {
-        file = debugs->filename;
-        line = find_line(interpreter, debugs);
-    }
-    else {
-        file = "(unknown file)";
-        line = -1;
-    }
-    PIO_eprintf(interpreter, "\tin file '%s' near line %d\n", file, line);
-}
-
-/*
-
-=item C<void
-print_pbc_location_stdio(Parrot_Interp interpreter)>
-
-Prints the bytecode location of the warning or error to C<stderr>.
-
-Uses C<fprintf()> only. This may be called from exceptions.
-
-=cut
-
-*/
-
-void
-print_pbc_location_stdio(Parrot_Interp interpreter)
+print_pbc_location(Parrot_Interp inter)
 {
-    const char *file;
-    int line;
-    struct PackFile_Debug * debugs = interpreter->code->cur_cs->debugs;
-    if (debugs) {
-        file = debugs->filename;
-        line = find_line(interpreter, debugs);
-    }
-    else {
-        file = "(unknown file)";
-        line = -1;
-    }
-    fprintf(stderr, "\tin file '%s' near line %d\n", file, line);
+    PIO_eprintf(inter, "%Ss", Parrot_Context_infostr(inter, &inter->ctx));
 }
 
 /*

Modified: trunk/t/op/debuginfo.t
==============================================================================
--- trunk/t/op/debuginfo.t      (original)
+++ trunk/t/op/debuginfo.t      Mon Apr 18 08:32:05 2005
@@ -17,7 +17,7 @@
 
 =cut
 
-use Parrot::Test tests => 6;
+use Parrot::Test tests => 8;
 
 SKIP:
 {
@@ -75,31 +75,29 @@
 pir_output_like( <<'CODE', <<'OUTPUT', "debug backtrace - Null PMC access" );
 .sub main
     print "ok 1\n"
-    debug 1
-    print "ok 2\n"
     a()
-    print "not ok 11\n"
+    print "not ok 10\n"
 .end
 .sub a
-    print "ok 3\n"
+    print "ok 2\n"
     b()
-    print "not ok 10\n"
+    print "not ok 9\n"
 .end
 .sub b
-    print "ok 4\n"
+    print "ok 3\n"
     c()
-    print "not ok 9\n"
+    print "not ok 8\n"
 .end
 .sub c
-    print "ok 5\n"
+    print "ok 4\n"
     d()
-    print "not ok 8\n"
+    print "not ok 7\n"
 .end
 .sub d
-    print "ok 6\n"
+    print "ok 5\n"
     $P0 = null
     $P0()
-    print "not ok 7\n"
+    print "not ok 6\n"
 .end
 CODE
 /^ok 1
@@ -107,20 +105,18 @@
 ok 3
 ok 4
 ok 5
-ok 6
 Null PMC access in invoke\(\)
-current instr\.: 'd' pc \d+
-called from Sub 'c' pc \d+
-called from Sub 'b' pc \d+
-called from Sub 'a' pc \d+
-called from Sub 'main' pc \d+
-\*\*\* Parrot VM: Dumping GC info \*\*\*/
+current instr\.: 'd' pc (\d+|-1) \(.*?:(\d+|-1)\)
+called from Sub 'c' pc (\d+|-1) \(.*?:(\d+|-1)\)
+called from Sub 'b' pc (\d+|-1) \(.*?:(\d+|-1)\)
+called from Sub 'a' pc (\d+|-1) \(.*?:(\d+|-1)\)
+called from Sub 'main' pc (\d+|-1) \(.*?:(\d+|-1)\)$/
 OUTPUT
 
 pir_output_like( <<'CODE', <<'OUTPUT', "debug backtrace - method not found" );
+.namespace ["Test1"]
 .sub main
     print "ok 1\n"
-    debug 1
     foo()
     print "not ok 5\n"
 .end
@@ -135,19 +131,16 @@
 /^ok 1
 ok 2
 ok 3
-real_exception \(severity:2 error:81\): Method 'nosuchmethod' not found
-current instr.: 'foo' pc \d+
-called from Sub 'main' pc \d+
 Method 'nosuchmethod' not found
-\s+in file '.*?' near line 11
-\*\*\* Parrot VM: Dumping GC info \*\*\*/
+current instr.: 'Test1 :: foo' pc (\d+|-1) \(.*?:(\d+|-1)\)
+called from Sub 'Test1 :: main' pc (\d+|-1) \(.*?:(\d+|-1)\)$/
 OUTPUT
 
 pir_output_like( <<'CODE', <<'OUTPUT', "debug backtrace - fetch of unknown 
lexical" );
+.namespace ["Test2"]
 .sub main
     new_pad 0
     print "ok 1\n"
-    debug 1
     foo()
     print "not ok 3\n"
 .end
@@ -159,10 +152,40 @@
 CODE
 /^ok 1
 ok 2
-real_exception \(severity:2 error:77\): Lexical 'nosuchlex' not found
-current instr.: 'foo' pc \d+
-called from Sub 'main' pc \d+
 Lexical 'nosuchlex' not found
-\s+in file '.*?' near line 10
-\*\*\* Parrot VM: Dumping GC info \*\*\*/
+current instr.: 'Test2 :: foo' pc (\d+|-1) \(.*?:(\d+|-1)\)
+called from Sub 'Test2 :: main' pc (\d+|-1) \(.*?:(\d+|-1)\)$/
+OUTPUT
+
+pir_output_like( <<'CODE', <<'OUTPUT', "debug backtrace - recursion 1" );
+.sub main
+    main()
+.end
+CODE
+/^maximum recursion depth exceeded
+current instr\.: 'main' pc (\d+|-1) \(.*?:(\d+|-1)\)
+called from Sub 'main' pc (\d+|-1) \(.*?:(\d+|-1)\)
+\.\.\. call repeated 999 times$/
+OUTPUT
+
+pir_output_like( <<'CODE', <<'OUTPUT', "debug backtrace - recursion 2" );
+.sub main
+    rec(91)
+.end
+.sub rec
+    .param int i
+    if i == 0 goto END
+    dec i
+    rec(i)
+    .return()
+END:
+    $P0 = null
+    $P0()
+.end
+CODE
+/^Null PMC access in invoke\(\)
+current instr\.: 'rec' pc (\d+|-1) \(.*?:(\d+|-1)\)
+called from Sub 'rec' pc (\d+|-1) \(.*?:(\d+|-1)\)
+\.\.\. call repeated 90 times
+called from Sub 'main' pc (\d+|-1) \(.*?:(\d+|-1)\)$/
 OUTPUT

Modified: trunk/t/pmc/perlarray.t
==============================================================================
--- trunk/t/pmc/perlarray.t     (original)
+++ trunk/t/pmc/perlarray.t     Mon Apr 18 08:32:05 2005
@@ -1377,23 +1377,22 @@
 OK4:  print "ok 4\\n"
       end
 CODE
-/Use of uninitialized value
-\s+in file.*
+/^Use of uninitialized value
+current instr\.: '\(null\)' pc (\d+|-1) .*?
 ok 1
 Use of uninitialized value
-\s+in file.*
+current instr\.: '\(null\)' pc (\d+|-1) .*?
 ok 2
 Use of uninitialized value
-\s+in file.*
+current instr\.: '\(null\)' pc (\d+|-1) .*?
 ok 3
 Use of uninitialized value
-\s+in file.*
+current instr\.: '\(null\)' pc (\d+|-1) .*?
 ok 4
-/
+$/
 OUTPUT
 
 pir_output_is(<< 'CODE', << 'OUTPUT', "check whether interface is done");
-
 .sub _main
     .local pmc pmc1
     pmc1 = new PerlArray

Modified: trunk/t/pmc/perlundef.t
==============================================================================
--- trunk/t/pmc/perlundef.t     (original)
+++ trunk/t/pmc/perlundef.t     Mon Apr 18 08:32:05 2005
@@ -326,8 +326,8 @@
        print P0
        end
 CODE
-/Use of uninitialized.*
-\s+in file .*pasm/i
+/^Use of uninitialized.*
+current instr\.: '\(null\)' pc (\d+|-1) /
 OUTPUT
 
 output_is(<<'CODE', <<'OUTPUT', "bor undef");

Modified: trunk/t/pmc/sub.t
==============================================================================
--- trunk/t/pmc/sub.t   (original)
+++ trunk/t/pmc/sub.t   Mon Apr 18 08:32:05 2005
@@ -379,7 +379,8 @@
     returncc
 CODE
 /^main:Use of uninitialized value in integer context
-\s+in file.*:back$/s
+current instr\.: '\(null\)' pc (\d+|-1) \(.*?:(\d+|-1)\)
+:back$/s
 OUTPUT
 
 output_like(<<'CODE', <<'OUTPUT', "interp - warnings 2");
@@ -402,7 +403,8 @@
     returncc
 CODE
 /^Use of uninitialized value in integer context
-\s+in file.*:main:back:Use of un.*$/sm
+current instr\.: '\(null\)' pc (\d+|-1) .*?
+:main:back:Use of un.*$/sm
 OUTPUT
 
 output_like(<<'CODE', <<'OUTPUT', "interp - warnings 2 - updatecc");
@@ -430,7 +432,8 @@
     returncc
 CODE
 /^Use of uninitialized value in integer context
-\s+in file.*:main:back:Use of un.*$/sm
+current instr\.: '\(null\)' pc (\d+|-1) .*?
+:main:back:Use of un.*$/sm
 OUTPUT
 
 output_is(<<'CODE', <<'OUTPUT', "pcc sub");
@@ -1070,7 +1073,6 @@
 
 
 pir_output_like(<<'CODE', <<'OUTPUT', "warn on in main");
-
 .sub _main @MAIN
 .include "warnings.pasm"
     warningson .PARROT_WARNINGS_UNDEF_FLAG
@@ -1085,7 +1087,6 @@
 OUTPUT
 
 pir_output_is(<<'CODE', <<'OUTPUT', "warn on in sub");
-
 .sub _main @MAIN
 .include "warnings.pasm"
     _f1()
@@ -1101,7 +1102,6 @@
 OUTPUT
 
 pir_output_like(<<'CODE', <<'OUTPUT', "warn on in sub, turn off in f2");
-
 .sub _main @MAIN
 .include "warnings.pasm"
     _f1()
@@ -1191,7 +1191,6 @@
 OUTPUT
 
 pir_output_is(<<'CODE', <<'OUTPUT', "sub names w newsub");
-
 .sub main @MAIN
     .include "interpinfo.pasm"
     $P0 = interpinfo .INTERPINFO_CURRENT_SUB
@@ -1215,7 +1214,6 @@
 OUTPUT
 
 pir_output_is(<<'CODE', <<'OUTPUT', "caller introspection");
-
 .sub main @MAIN
 .include "interpinfo.pasm"
     # this test will fail when run with -Oc
@@ -1290,7 +1288,7 @@
 main
 OUTPUT
     my $descr = '@IMMEDIATE, @POSTCOMP';
-    if ( $ENV{TEST_PROG_ARGS} =~ m/-r / )
+    if ( exists $ENV{TEST_PROG_ARGS} and $ENV{TEST_PROG_ARGS} =~ m/-r / )
     {
         TODO: 
         {

Reply via email to