This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Silence a compilation warning
[perl5.git] / dump.c
diff --git a/dump.c b/dump.c
index 52a43a9..5f0bef2 100644 (file)
--- a/dump.c
+++ b/dump.c
@@ -1,7 +1,7 @@
 /*    dump.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
  * it has not been hard for me to read your mind and memory.'"
  */
 
+/* This file contains utility routines to dump the contents of SV and OP
+ * structures, as used by command-line options like -Dt and -Dx, and
+ * by Devel::Peek.
+ *
+ * It also holds the debugging version of the  runops function.
+ */
+
 #include "EXTERN.h"
 #define PERL_IN_DUMP_C
 #include "perl.h"
 #include "regcomp.h"
 
+static HV *Sequence;
+
 void
 Perl_dump_indent(pTHX_ I32 level, PerlIO *file, const char* pat, ...)
 {
@@ -116,19 +125,17 @@ Perl_pv_display(pTHX_ SV *dsv, char *pv, STRLEN cur, STRLEN len, STRLEN pvlim)
             truncated++;
            break;
         }
-        if (isPRINT(*pv)) {
-            switch (*pv) {
-           case '\t': sv_catpvn(dsv, "\\t", 2);  break;
-           case '\n': sv_catpvn(dsv, "\\n", 2);  break;
-           case '\r': sv_catpvn(dsv, "\\r", 2);  break;
-           case '\f': sv_catpvn(dsv, "\\f", 2);  break;
-           case '"':  sv_catpvn(dsv, "\\\"", 2); break;
-           case '\\': sv_catpvn(dsv, "\\\\", 2); break;
-           default:   sv_catpvn(dsv, pv, 1);     break;
-            }
-        }
-       else {
-           if (cur && isDIGIT(*(pv+1)))
+       switch (*pv) {
+       case '\t': sv_catpvn(dsv, "\\t", 2);  break;
+       case '\n': sv_catpvn(dsv, "\\n", 2);  break;
+       case '\r': sv_catpvn(dsv, "\\r", 2);  break;
+       case '\f': sv_catpvn(dsv, "\\f", 2);  break;
+       case '"':  sv_catpvn(dsv, "\\\"", 2); break;
+       case '\\': sv_catpvn(dsv, "\\\\", 2); break;
+       default:
+           if (isPRINT(*pv))
+               sv_catpvn(dsv, pv, 1);
+           else if (cur && isDIGIT(*(pv+1)))
                Perl_sv_catpvf(aTHX_ dsv, "\\%03o", (U8)*pv);
            else
                Perl_sv_catpvf(aTHX_ dsv, "\\%o", (U8)*pv);
@@ -392,24 +399,137 @@ Perl_pmop_dump(pTHX_ PMOP *pm)
     do_pmop_dump(0, Perl_debug_log, pm);
 }
 
+/* An op sequencer.  We visit the ops in the order they're to execute. */
+
+STATIC void
+sequence(pTHX_ register OP *o)
+{
+    SV      *op;
+    char    *key;
+    STRLEN   len;
+    static   UV seq;
+    OP      *oldop = 0,
+            *l;
+
+    if (!Sequence)
+       Sequence = newHV();
+
+    if (!o)
+       return;
+
+    op = newSVuv(PTR2UV(o));
+    key = SvPV(op, len);
+    if (hv_exists(Sequence, key, len))
+       return;
+
+    for (; o; o = o->op_next) {
+       op = newSVuv(PTR2UV(o));
+       key = SvPV(op, len);
+       if (hv_exists(Sequence, key, len))
+           break;
+
+       switch (o->op_type) {
+       case OP_STUB:
+           if ((o->op_flags & OPf_WANT) != OPf_WANT_LIST) {
+               hv_store(Sequence, key, len, newSVuv(++seq), 0);
+               break;
+           }
+           goto nothin;
+       case OP_NULL:
+           if (oldop && o->op_next)
+               continue;
+           break;
+       case OP_SCALAR:
+       case OP_LINESEQ:
+       case OP_SCOPE:
+         nothin:
+           if (oldop && o->op_next)
+               continue;
+           hv_store(Sequence, key, len, newSVuv(++seq), 0);
+           break;
+
+       case OP_MAPWHILE:
+       case OP_GREPWHILE:
+       case OP_AND:
+       case OP_OR:
+       case OP_DOR:
+       case OP_ANDASSIGN:
+       case OP_ORASSIGN:
+       case OP_DORASSIGN:
+       case OP_COND_EXPR:
+       case OP_RANGE:
+           hv_store(Sequence, key, len, newSVuv(++seq), 0);
+           for (l = cLOGOPo->op_other; l && l->op_type == OP_NULL; l = l->op_next)
+               ;
+           sequence(aTHX_ l);
+           break;
+
+       case OP_ENTERLOOP:
+       case OP_ENTERITER:
+           hv_store(Sequence, key, len, newSVuv(++seq), 0);
+           for (l = cLOOPo->op_redoop; l && l->op_type == OP_NULL; l = l->op_next)
+               ;
+           sequence(aTHX_ l);
+           for (l = cLOOPo->op_nextop; l && l->op_type == OP_NULL; l = l->op_next)
+               ;
+           sequence(aTHX_ l);
+           for (l = cLOOPo->op_lastop; l && l->op_type == OP_NULL; l = l->op_next)
+               ;
+           sequence(aTHX_ l);
+           break;
+
+       case OP_QR:
+       case OP_MATCH:
+       case OP_SUBST:
+           hv_store(Sequence, key, len, newSVuv(++seq), 0);
+           for (l = cPMOPo->op_pmreplstart; l && l->op_type == OP_NULL; l = l->op_next)
+               ;
+           sequence(aTHX_ l);
+           break;
+
+       case OP_HELEM:
+           break;
+
+       default:
+           hv_store(Sequence, key, len, newSVuv(++seq), 0);
+           break;
+       }
+       oldop = o;
+    }
+}
+
+STATIC UV
+sequence_num(pTHX_ OP *o)
+{
+    SV     *op,
+          **seq;
+    char   *key;
+    STRLEN  len;
+    if (!o) return 0;
+    op = newSVuv(PTR2UV(o));
+    key = SvPV(op, len);
+    seq = hv_fetch(Sequence, key, len, 0);
+    return seq ? SvUV(*seq): 0;
+}
+
 void
 Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, OP *o)
 {
+    UV      seq;
+    sequence(aTHX_ o);
     Perl_dump_indent(aTHX_ level, file, "{\n");
     level++;
-    if (o->op_seq)
-       PerlIO_printf(file, "%-4d", o->op_seq);
+    seq = sequence_num(aTHX_ o);
+    if (seq)
+       PerlIO_printf(file, "%-4"UVf, seq);
     else
        PerlIO_printf(file, "    ");
     PerlIO_printf(file,
                  "%*sTYPE = %s  ===> ",
                  (int)(PL_dumpindent*level-4), "", OP_NAME(o));
-    if (o->op_next) {
-       if (o->op_seq)
-           PerlIO_printf(file, "%d\n", o->op_next->op_seq);
-       else
-           PerlIO_printf(file, "(%d)\n", o->op_next->op_seq);
-    }
+    if (o->op_next)
+       PerlIO_printf(file, seq ? "%"UVf"\n" : "(%"UVf")\n",
+                               sequence_num(aTHX_ o->op_next));
     else
        PerlIO_printf(file, "DONE\n");
     if (o->op_targ) {
@@ -624,9 +744,11 @@ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, OP *o)
            if (o->op_private & OPpHUSH_VMSISH)
                sv_catpv(tmpsv, ",HUSH_VMSISH");
        }
-       else if (OP_IS_FILETEST_ACCESS(o)) {
-            if (o->op_private & OPpFT_ACCESS)
-                 sv_catpv(tmpsv, ",FT_ACCESS");
+       else if (PL_check[o->op_type] != MEMBER_TO_FPTR(Perl_ck_ftst)) {
+           if (OP_IS_FILETEST_ACCESS(o) && o->op_private & OPpFT_ACCESS)
+               sv_catpv(tmpsv, ",FT_ACCESS");
+           if (o->op_private & OPpFT_STACKED)
+               sv_catpv(tmpsv, ",FT_STACKED");
        }
        if (o->op_flags & OPf_MOD && o->op_private & OPpLVAL_INTRO)
            sv_catpv(tmpsv, ",INTRO");
@@ -642,22 +764,28 @@ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, OP *o)
 #ifdef USE_ITHREADS
        Perl_dump_indent(aTHX_ level, file, "PADIX = %" IVdf "\n", (IV)cPADOPo->op_padix);
 #else
-       if (cSVOPo->op_sv) {
-           SV *tmpsv = NEWSV(0,0);
-           STRLEN n_a;
-           ENTER;
-           SAVEFREESV(tmpsv);
-           gv_fullname3(tmpsv, (GV*)cSVOPo->op_sv, Nullch);
-           Perl_dump_indent(aTHX_ level, file, "GV = %s\n", SvPV(tmpsv, n_a));
-           LEAVE;
+       if ( ! PL_op->op_flags & OPf_SPECIAL) { /* not lexical */
+           if (cSVOPo->op_sv) {
+               SV *tmpsv = NEWSV(0,0);
+               STRLEN n_a;
+               ENTER;
+               SAVEFREESV(tmpsv);
+               gv_fullname3(tmpsv, (GV*)cSVOPo->op_sv, Nullch);
+               Perl_dump_indent(aTHX_ level, file, "GV = %s\n", SvPV(tmpsv, n_a));
+               LEAVE;
+           }
+           else
+               Perl_dump_indent(aTHX_ level, file, "GV = NULL\n");
        }
-       else
-           Perl_dump_indent(aTHX_ level, file, "GV = NULL\n");
 #endif
        break;
     case OP_CONST:
     case OP_METHOD_NAMED:
+#ifndef USE_ITHREADS
+       /* with ITHREADS, consts are stored in the pad, and the right pad
+        * may not be active here, so skip */
        Perl_dump_indent(aTHX_ level, file, "SV = %s\n", SvPEEK(cSVOPo_sv));
+#endif
        break;
     case OP_SETSTATE:
     case OP_NEXTSTATE:
@@ -675,17 +803,17 @@ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, OP *o)
     case OP_ENTERLOOP:
        Perl_dump_indent(aTHX_ level, file, "REDO ===> ");
        if (cLOOPo->op_redoop)
-           PerlIO_printf(file, "%d\n", cLOOPo->op_redoop->op_seq);
+           PerlIO_printf(file, "%"UVf"\n", sequence_num(aTHX_ cLOOPo->op_redoop));
        else
            PerlIO_printf(file, "DONE\n");
        Perl_dump_indent(aTHX_ level, file, "NEXT ===> ");
        if (cLOOPo->op_nextop)
-           PerlIO_printf(file, "%d\n", cLOOPo->op_nextop->op_seq);
+           PerlIO_printf(file, "%"UVf"\n", sequence_num(aTHX_ cLOOPo->op_nextop));
        else
            PerlIO_printf(file, "DONE\n");
        Perl_dump_indent(aTHX_ level, file, "LAST ===> ");
        if (cLOOPo->op_lastop)
-           PerlIO_printf(file, "%d\n", cLOOPo->op_lastop->op_seq);
+           PerlIO_printf(file, "%"UVf"\n", sequence_num(aTHX_ cLOOPo->op_lastop));
        else
            PerlIO_printf(file, "DONE\n");
        break;
@@ -697,7 +825,7 @@ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, OP *o)
     case OP_AND:
        Perl_dump_indent(aTHX_ level, file, "OTHER ===> ");
        if (cLOGOPo->op_other)
-           PerlIO_printf(file, "%d\n", cLOGOPo->op_other->op_seq);
+           PerlIO_printf(file, "%"UVf"\n", sequence_num(aTHX_ cLOGOPo->op_other));
        else
            PerlIO_printf(file, "DONE\n");
        break;
@@ -1003,7 +1131,8 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
     if (flags & SVf_FAKE)      sv_catpv(d, "FAKE,");
     if (flags & SVf_READONLY)  sv_catpv(d, "READONLY,");
 
-    if (flags & SVf_AMAGIC)    sv_catpv(d, "OVERLOAD,");
+    if (flags & SVf_AMAGIC && type != SVt_PVHV)
+                               sv_catpv(d, "OVERLOAD,");
     if (flags & SVp_IOK)       sv_catpv(d, "pIOK,");
     if (flags & SVp_NOK)       sv_catpv(d, "pNOK,");
     if (flags & SVp_POK)       sv_catpv(d, "pPOK,");
@@ -1029,8 +1158,9 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
        if (HvSHAREKEYS(sv))    sv_catpv(d, "SHAREKEYS,");
        if (HvLAZYDEL(sv))      sv_catpv(d, "LAZYDEL,");
        if (HvHASKFLAGS(sv))    sv_catpv(d, "HASKFLAGS,");
+       if (HvREHASH(sv))       sv_catpv(d, "REHASH,");
        break;
-    case SVt_PVGV:
+    case SVt_PVGV: case SVt_PVLV:
        if (GvINTRO(sv))        sv_catpv(d, "INTRO,");
        if (GvMULTI(sv))        sv_catpv(d, "MULTI,");
        if (GvUNIQUE(sv))       sv_catpv(d, "UNIQUE,");
@@ -1166,7 +1296,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
        SvREFCNT_dec(d);
        return;
     }
-    if (type <= SVt_PVLV) {
+    if (type <= SVt_PVLV && type != SVt_PVGV) {
        if (SvPVX(sv)) {
            Perl_dump_indent(aTHX_ level, file,"  PV = 0x%"UVxf" ", PTR2UV(SvPVX(sv)));
            if (SvOOK(sv))
@@ -1188,15 +1318,6 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
            do_hv_dump(level, file, "  STASH", SvSTASH(sv));
     }
     switch (type) {
-    case SVt_PVLV:
-       Perl_dump_indent(aTHX_ level, file, "  TYPE = %c\n", LvTYPE(sv));
-       Perl_dump_indent(aTHX_ level, file, "  TARGOFF = %"IVdf"\n", (IV)LvTARGOFF(sv));
-       Perl_dump_indent(aTHX_ level, file, "  TARGLEN = %"IVdf"\n", (IV)LvTARGLEN(sv));
-       Perl_dump_indent(aTHX_ level, file, "  TARG = 0x%"UVxf"\n", PTR2UV(LvTARG(sv)));
-       if (LvTYPE(sv) != 't' && LvTYPE(sv) != 'T')
-           do_sv_dump(level+1, file, LvTARG(sv), nest+1, maxnest,
-                   dumpops, pvlim);
-       break;
     case SVt_PVAV:
        Perl_dump_indent(aTHX_ level, file, "  ARRAY = 0x%"UVxf, PTR2UV(AvARRAY(sv)));
        if (AvARRAY(sv) != AvALLOC(sv)) {
@@ -1308,6 +1429,8 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
                Perl_dump_indent(aTHX_ level+1, file, "Elt %s ", pv_display(d, keypv, len, 0, pvlim));
                if (SvUTF8(keysv))
                    PerlIO_printf(file, "[UTF8 \"%s\"] ", sv_uni_display(d, keysv, 8 * sv_len_utf8(keysv), UNI_DISPLAY_QQ));
+               if (HeKREHASH(he))
+                   PerlIO_printf(file, "[REHASH] ");
                PerlIO_printf(file, "HASH = 0x%"UVxf"\n", (UV)hash);
                do_sv_dump(level+1, file, elt, nest+1, maxnest, dumpops, pvlim);
            }
@@ -1321,7 +1444,7 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
     case SVt_PVFM:
        do_hv_dump(level, file, "  COMP_STASH", CvSTASH(sv));
        if (CvSTART(sv))
-           Perl_dump_indent(aTHX_ level, file, "  START = 0x%"UVxf" ===> %"IVdf"\n", PTR2UV(CvSTART(sv)), (IV)CvSTART(sv)->op_seq);
+           Perl_dump_indent(aTHX_ level, file, "  START = 0x%"UVxf" ===> %"IVdf"\n", PTR2UV(CvSTART(sv)), (IV)sequence_num(aTHX_ CvSTART(sv)));
        Perl_dump_indent(aTHX_ level, file, "  ROOT = 0x%"UVxf"\n", PTR2UV(CvROOT(sv)));
         if (CvROOT(sv) && dumpops)
            do_op_dump(level+1, file, CvROOT(sv));
@@ -1351,7 +1474,16 @@ Perl_do_sv_dump(pTHX_ I32 level, PerlIO *file, SV *sv, I32 nest, I32 maxnest, bo
        if (nest < maxnest && (CvCLONE(sv) || CvCLONED(sv)))
            do_sv_dump(level+1, file, (SV*)CvOUTSIDE(sv), nest+1, maxnest, dumpops, pvlim);
        break;
-    case SVt_PVGV:
+    case SVt_PVGV: case SVt_PVLV:
+    if (type == SVt_PVLV) {
+        Perl_dump_indent(aTHX_ level, file, "  TYPE = %c\n", LvTYPE(sv));
+        Perl_dump_indent(aTHX_ level, file, "  TARGOFF = %"IVdf"\n", (IV)LvTARGOFF(sv));
+        Perl_dump_indent(aTHX_ level, file, "  TARGLEN = %"IVdf"\n", (IV)LvTARGLEN(sv));
+        Perl_dump_indent(aTHX_ level, file, "  TARG = 0x%"UVxf"\n", PTR2UV(LvTARG(sv)));
+        if (LvTYPE(sv) != 't' && LvTYPE(sv) != 'T')
+            do_sv_dump(level+1, file, LvTARG(sv), nest+1, maxnest,
+                dumpops, pvlim);
+    }
        Perl_dump_indent(aTHX_ level, file, "  NAME = \"%s\"\n", GvNAME(sv));
        Perl_dump_indent(aTHX_ level, file, "  NAMELEN = %"IVdf"\n", (IV)GvNAMELEN(sv));
        do_hv_dump (level, file, "  GvSTASH", GvSTASH(sv));
@@ -1415,6 +1547,7 @@ Perl_runops_debug(pTHX)
        return 0;
     }
 
+    DEBUG_l(Perl_deb(aTHX_ "Entering new RUNOPS level\n"));
     do {
        PERL_ASYNC_CHECK();
        if (PL_debug) {
@@ -1437,6 +1570,7 @@ Perl_runops_debug(pTHX)
            if (DEBUG_P_TEST_) debprof(PL_op);
        }
     } while ((PL_op = CALL_FPTR(PL_op->op_ppaddr)(aTHX)));
+    DEBUG_l(Perl_deb(aTHX_ "leaving RUNOPS level\n"));
 
     TAINT_NOT;
     return 0;