Fix COPHH for PERL_BCDVERSION < 0x5013007
[p5sagit/Devel-Size.git] / SizeMe.xs
index 2b440b5..ddef672 100644 (file)
--- a/SizeMe.xs
+++ b/SizeMe.xs
@@ -3,15 +3,8 @@
 /* TODO
  *
  * Refactor this to split out D:M code from Devel::Size code.
- *
  * Start migrating Devel::Size's Size.xs towards the new code.
  *
- * ADD_PRE_ATTR for index should check if the ptr is new first. Currently we're
- * generating lots of ADD_PRE_ATTR's for SVs that we've already seen via other paths.
- * That's wasteful and likely to cause subtle bugs.
- *
- * Give HE's their own node so keys and values can be tied together
- *
  */
 
 #undef NDEBUG /* XXX */
@@ -22,6 +15,9 @@
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
+
+#define DPPP_PL_parser_NO_DUMMY
+#define NEED_PL_parser
 #include "ppport.h"
 
 #include "refcounted_he.h"
 #  define SvSHARED_HEK_FROM_PV(pvx) \
         ((struct hek*)(pvx - STRUCT_OFFSET(struct hek, hek_key)))
 #endif
+#ifndef MUTABLE_AV
+#define MUTABLE_AV(p) ((AV*)p)
+#endif
+#ifndef MUTABLE_SV
+#define MUTABLE_SV(p) ((SV*)p)
+#endif
 
 #if PERL_VERSION < 6
 #  define PL_opargs opargs
@@ -174,14 +176,13 @@ struct state {
 #define NPtype_MAGIC    0x04
 #define NPtype_OP       0x05
 
-/* XXX these should probably be generalizes into flag bits */
+/* XXX these should probably be generalized into flag bits */
 #define NPattr_LEAFSIZE 0x00
 #define NPattr_NAME     0x01
 #define NPattr_PADFAKE  0x02
 #define NPattr_PADNAME  0x03
 #define NPattr_PADTMP   0x04
 #define NPattr_NOTE     0x05
-#define NPattr_PRE_ATTR 0x06 /* deprecated */
 
 #define _ADD_ATTR_NP(st, attr_type, attr_name, attr_value, np) \
   STMT_START { \
@@ -190,17 +191,14 @@ struct state {
     } \
   } STMT_END
 
-#define ADD_ATTR(st, attr_type, attr_name, attr_value) _ADD_ATTR_NP(st, attr_type, attr_name, attr_value, NP-1)
+#define ADD_ATTR(st, attr_type, attr_name, attr_value) \
+    _ADD_ATTR_NP(st, attr_type, attr_name, attr_value, NP-1)
+
 #define ADD_LINK_ATTR(st, attr_type, attr_name, attr_value)            \
   STMT_START {                                                         \
-    assert(NP->seqn);                                                  \
+    if (st->add_attr_cb) assert(NP->seqn);                             \
     _ADD_ATTR_NP(st, attr_type, attr_name, attr_value, NP);            \
   } STMT_END;
-#define ADD_PRE_ATTR(st, attr_type, attr_name, attr_value)             \
-  STMT_START {                                                         \
-    assert(!attr_type);                                                        \
-    _ADD_ATTR_NP(st, NPattr_PRE_ATTR, attr_name, attr_value, NP-1);    \
-  } STMT_END;
 
 #define _NPathLink(np, nid, ntype)   (((np)->id=nid), ((np)->type=ntype), ((np)->seqn=0))
 #define NPathLink(nid)               (_NPathLink(NP, nid, NPtype_LINK), NP)
@@ -763,14 +761,14 @@ regex_size(pTHX_ const REGEXP * const baseregex, struct state *st, pPATH) {
   }
 }
 
-static void
+static int
 hek_size(pTHX_ struct state *st, HEK *hek, U32 shared, pPATH)
 {
     dNPathNodes(1, NPathArg);
 
     /* Hash keys can be shared. Have we seen this before? */
     if (!check_new(st, hek))
-       return;
+       return 0;
     NPathPushNode("hek", NPtype_NAME);
     ADD_SIZE(st, "hek_len", HEK_BASESIZE + hek->hek_len
 #if PERL_VERSION < 8
@@ -786,8 +784,10 @@ hek_size(pTHX_ struct state *st, HEK *hek, U32 shared, pPATH)
        ADD_SIZE(st, "shared_he", STRUCT_OFFSET(struct shared_he, shared_he_hek));
 #endif
     }
+    return 1;
 }
 
+#if (PERL_BCDVERSION >= 0x5009004)
 static void
 refcounted_he_size(pTHX_ struct state *st, struct refcounted_he *he, pPATH)
 {
@@ -806,6 +806,7 @@ refcounted_he_size(pTHX_ struct state *st, struct refcounted_he *he, pPATH)
   if (he->refcounted_he_next)
     refcounted_he_size(aTHX_ st, he->refcounted_he_next, NPathLink("refcounted_he_next"));
 }
+#endif
 
 static void op_size_class(pTHX_ const OP * const baseop, opclass op_class, bool skip_op_struct, struct state *st, pPATH);
 
@@ -926,7 +927,6 @@ op_size_class(pTHX_ const OP * const baseop, opclass op_class, bool skip_op_stru
        case OPc_COP: TAG;
         {
           COP *basecop;
-         COPHH *hh;
           basecop = (COP *)baseop;
          if (!skip_op_struct)
            ADD_SIZE(st, "cop", sizeof(struct cop));
@@ -943,15 +943,22 @@ op_size_class(pTHX_ const OP * const baseop, opclass op_class, bool skip_op_stru
 #endif
 #ifdef USE_ITHREADS
           check_new_and_strlen(st, basecop->cop_file, NPathLink("cop_file"));
-          check_new_and_strlen(st, basecop->cop_stashpv, NPathLink("cop_stashpv"));
+          /*check_new_and_strlen(st, basecop->cop_stashpv, NPathLink("cop_stashpv"));  XXX */
 #else
           if (SvREFCNT(basecop->cop_stash) == 1) /* XXX hack? */
             sv_size(aTHX_ st, NPathLink("cop_stash"), (SV *)basecop->cop_stash, SOME_RECURSION);
          sv_size(aTHX_ st, NPathLink("cop_filegv"), (SV *)basecop->cop_filegv, SOME_RECURSION);
 #endif
 
-         hh = CopHINTHASH_get(basecop);
-         refcounted_he_size(aTHX_ st, hh, NPathLink("cop_hints_hash"));
+#if (PERL_BCDVERSION >= 0x5009004)
+#  if (PERL_BCDVERSION < 0x5013007)
+#    define COPHH struct refcounted_he
+#  endif
+#  ifndef CopHINTHASH_get
+#    define CopHINTHASH_get(c)  ((COPHH*)((c)->cop_hints_hash))
+#  endif
+         refcounted_he_size(aTHX_ st, CopHINTHASH_get(basecop), NPathLink("cop_hints_hash"));
+#endif
         }
         TAG;break;
       default:
@@ -1118,7 +1125,7 @@ sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing,
   type = SvTYPE(thing);
   if (type > SVt_LAST) {
       warn("Devel::Size: Unknown variable type: %d encountered\n", type);
-      return 1;
+      return 0;
   }
   NPathPushNode(thing, NPtype_SV);
   ADD_SIZE(st, "sv_head", sizeof(SV));
@@ -1140,6 +1147,7 @@ sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing,
     if (AvMAX(thing) != -1) {
       /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
       ADD_SIZE(st, "av_max", sizeof(SV *) * (AvMAX(thing) + 1));
+      ADD_ATTR(st, NPattr_NOTE, "av_len", av_len((AV*)thing));
       dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
 
       if (recurse >= st->min_recurse_threshold) {
@@ -1172,9 +1180,11 @@ sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing,
 
   case SVt_PVHV: TAG;
     /* Now the array of buckets */
-    if (HvENAME(thing)) {
-        ADD_ATTR(st, NPattr_NAME, HvENAME(thing), 0);
-    }
+#ifdef HvENAME
+    if (HvENAME(thing)) { ADD_ATTR(st, NPattr_NAME, HvENAME(thing), 0); }
+#else
+    if (HvNAME(thing))  { ADD_ATTR(st, NPattr_NAME, HvNAME(thing), 0); }
+#endif
     ADD_SIZE(st, "hv_max", (sizeof(HE *) * (HvMAX(thing) + 1)));
     /* Now walk the bucket chain */
     if (HvARRAY(thing)) {
@@ -1313,7 +1323,11 @@ else warn("skipped suspect HeVAL %p", HeVAL(cur_entry));
 #ifdef GvFILE_HEK
        hek_size(aTHX_ st, GvFILE_HEK(thing), 1, NPathLink("GvFILE_HEK"));
 #elif defined(GvFILE)
-#  if !defined(USE_ITHREADS) || (PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8))
+/* XXX this coredumped for me in t/recurse.t with a non-threaded 5.8.9
+ * so I've changed the condition to be more restricive
+ *#  if !defined(USE_ITHREADS) || (PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8))
+ */
+#  if (PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 9))
        /* With itreads, before 5.8.9, this can end up pointing to freed memory
           if the GV was created in an eval, as GvFILE() points to CopFILE(),
           and the relevant COP has been freed on scope cleanup after the eval.
@@ -1365,7 +1379,8 @@ else warn("skipped suspect HeVAL %p", HeVAL(cur_entry));
   if (type >= SVt_PVMG) {
     if (SvMAGICAL(thing))
       magic_size(aTHX_ thing, st, NPathLink("MG"));
-    if (SvPAD_OUR(thing) && SvOURSTASH(thing))
+    /* SVpad_OUR shares same flag bit as SVpbm_VALID and others */
+    if (type == SVt_PVGV && SvPAD_OUR(thing) && SvOURSTASH(thing))
       sv_size(aTHX_ st, NPathLink("SvOURSTASH"), (SV *)SvOURSTASH(thing), SOME_RECURSION);
     if (SvSTASH(thing))
       sv_size(aTHX_ st, NPathLink("SvSTASH"), (SV *)SvSTASH(thing), SOME_RECURSION);
@@ -1401,10 +1416,10 @@ new_state(pTHX)
     Newxz(st, 1, struct state);
     st->go_yell = TRUE;
     st->min_recurse_threshold = TOTAL_SIZE_RECURSION;
-    if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
+    if (NULL != (warn_flag = get_sv("Devel::Size::warn", FALSE))) {
        st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
     }
-    if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
+    if (NULL != (warn_flag = get_sv("Devel::Size::dangle", FALSE))) {
        st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
     }
     st->start_time_nv = gettimeofday_nv();
@@ -1452,8 +1467,8 @@ unseen_sv_size(pTHX_ struct state *st, pPATH)
 
     /* by this point we should have visited all the SVs
      * so now we'll run through all the SVs via the arenas
-     * in order to find any thet we've missed for some reason.
-     * Once the rest of the code is finding all the SVs then any
+     * in order to find any that we've missed for some reason.
+     * Once the rest of the code is finding ALL the SVs then any
      * found here will be leaks.
      */
     for (sva = PL_sv_arenaroot; sva; sva = MUTABLE_SV(SvANY(sva))) {
@@ -1488,6 +1503,7 @@ madprop_size(pTHX_ struct state *const st, pPath, MADPROP *prop)
 }
 #endif
 
+#if (PERL_BCDVERSION >= 0x5009005)
 static void
 parser_size(pTHX_ struct state *const st, pPATH, yy_parser *parser)
 {
@@ -1499,12 +1515,17 @@ parser_size(pTHX_ struct state *const st, pPATH, yy_parser *parser)
 
   NPathPushNode("stack", NPtype_NAME);
   yy_stack_frame *ps;
-  //warn("total: %u", parser->stack_size);
-  //warn("foo: %u", parser->ps - parser->stack);
+  /*warn("total: %u", parser->stack_size); */
+  /*warn("foo: %u", parser->ps - parser->stack); */
   ADD_SIZE(st, "stack_frames", parser->stack_size * sizeof(yy_stack_frame));
   for (ps = parser->stack; ps <= parser->ps; ps++) {
-    ADD_PRE_ATTR(st, 0, "frame", ps - parser->ps);
-    sv_size(aTHX_ st, NPathLink("compcv"), (SV*)ps->compcv, TOTAL_SIZE_RECURSION);
+#if (PERL_BCDVERSION >= 0x5011001) /* roughly */
+    if (sv_size(aTHX_ st, NPathLink("compcv"), (SV*)ps->compcv, TOTAL_SIZE_RECURSION))
+        ADD_LINK_ATTR(st, NPattr_NOTE, "i", ps - parser->ps);
+#else /* prior to perl 8c63ea58  Dec 8 2009 */
+    if (sv_size(aTHX_ st, NPathLink("comppad"), (SV*)ps->comppad, TOTAL_SIZE_RECURSION))
+        ADD_LINK_ATTR(st, NPattr_NOTE, "i", ps - parser->ps);
+#endif
   }
   NPathPopNode;
 
@@ -1512,7 +1533,7 @@ parser_size(pTHX_ struct state *const st, pPATH, yy_parser *parser)
   sv_size(aTHX_ st, NPathLink("lex_stuff"), (SV*)parser->lex_stuff, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("linestr"), (SV*)parser->linestr, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("in_my_stash"), (SV*)parser->in_my_stash, TOTAL_SIZE_RECURSION);
-  //sv_size(aTHX_ st, NPathLink("rsfp"), parser->rsfp, TOTAL_SIZE_RECURSION);
+  /*sv_size(aTHX_ st, NPathLink("rsfp"), parser->rsfp, TOTAL_SIZE_RECURSION); */
   sv_size(aTHX_ st, NPathLink("rsfp_filters"), (SV*)parser->rsfp_filters, TOTAL_SIZE_RECURSION);
 #ifdef PERL_MAD
   sv_size(aTHX_ st, NPathLink("endwhite"), parser->endwhite, TOTAL_SIZE_RECURSION);
@@ -1531,6 +1552,7 @@ parser_size(pTHX_ struct state *const st, pPATH, yy_parser *parser)
   if (parser->old_parser)
     parser_size(aTHX_ st, NPathLink("old_parser"), parser->old_parser);
 }
+#endif
 
 static void
 perl_size(pTHX_ struct state *const st, pPATH)
@@ -1560,8 +1582,12 @@ perl_size(pTHX_ struct state *const st, pPATH)
   sv_size(aTHX_ st, NPathLink("PL_errors"), (SV*)PL_errors, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_stashcache"), (SV*)PL_stashcache, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_patchlevel"), (SV*)PL_patchlevel, TOTAL_SIZE_RECURSION);
+#ifdef PL_apiversion
   sv_size(aTHX_ st, NPathLink("PL_apiversion"), (SV*)PL_apiversion, TOTAL_SIZE_RECURSION);
+#endif
+#ifdef PL_registered_mros
   sv_size(aTHX_ st, NPathLink("PL_registered_mros"), (SV*)PL_registered_mros, TOTAL_SIZE_RECURSION);
+#endif
 #ifdef USE_ITHREADS
   sv_size(aTHX_ st, NPathLink("PL_regex_padav"), (SV*)PL_regex_padav, TOTAL_SIZE_RECURSION);
 #endif
@@ -1575,24 +1601,34 @@ perl_size(pTHX_ struct state *const st, pPATH)
   sv_size(aTHX_ st, NPathLink("PL_hintgv"), (SV*)PL_hintgv, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_e_script"), (SV*)PL_e_script, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_encoding"), (SV*)PL_encoding, TOTAL_SIZE_RECURSION);
+#ifdef PL_ofsgv
   sv_size(aTHX_ st, NPathLink("PL_ofsgv"), (SV*)PL_ofsgv, TOTAL_SIZE_RECURSION);
+#endif
   sv_size(aTHX_ st, NPathLink("PL_argvout_stack"), (SV*)PL_argvout_stack, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_beginav"), (SV*)PL_beginav, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_beginav_save"), (SV*)PL_beginav_save, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_checkav_save"), (SV*)PL_checkav_save, TOTAL_SIZE_RECURSION);
+#ifdef PL_unitcheckav
   sv_size(aTHX_ st, NPathLink("PL_unitcheckav"), (SV*)PL_unitcheckav, TOTAL_SIZE_RECURSION);
+#endif
+#ifdef PL_unitcheckav_save
   sv_size(aTHX_ st, NPathLink("PL_unitcheckav_save"), (SV*)PL_unitcheckav_save, TOTAL_SIZE_RECURSION);
+#endif
   sv_size(aTHX_ st, NPathLink("PL_endav"), (SV*)PL_endav, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_checkav"), (SV*)PL_checkav, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_initav"), (SV*)PL_initav, TOTAL_SIZE_RECURSION);
+#ifdef PL_isarev
   sv_size(aTHX_ st, NPathLink("PL_isarev"), (SV*)PL_isarev, TOTAL_SIZE_RECURSION);
+#endif
   sv_size(aTHX_ st, NPathLink("PL_fdpid"), (SV*)PL_fdpid, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_preambleav"), (SV*)PL_preambleav, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_ors_sv"), (SV*)PL_ors_sv, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_modglobal"), (SV*)PL_modglobal, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_custom_op_names"), (SV*)PL_custom_op_names, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_custom_op_descs"), (SV*)PL_custom_op_descs, TOTAL_SIZE_RECURSION);
+#ifdef PL_custom_ops
   sv_size(aTHX_ st, NPathLink("PL_custom_ops"), (SV*)PL_custom_ops, TOTAL_SIZE_RECURSION);
+#endif
   sv_size(aTHX_ st, NPathLink("PL_compcv"), (SV*)PL_compcv, TOTAL_SIZE_RECURSION);
   sv_size(aTHX_ st, NPathLink("PL_DBcv"), (SV*)PL_DBcv, TOTAL_SIZE_RECURSION);
 #ifdef PERL_USES_PL_PIDSTATUS
@@ -1626,7 +1662,10 @@ perl_size(pTHX_ struct state *const st, pPATH)
   op_size_class(aTHX_ (OP*)&PL_compiling, OPc_COP, 1, st, NPathLink("PL_compiling"));
   op_size_class(aTHX_ (OP*)PL_curcopdb, OPc_COP, 0, st, NPathLink("PL_curcopdb"));
 
+#if (PERL_BCDVERSION >= 0x5009005)
   parser_size(aTHX_ st, NPathLink("PL_parser"), PL_parser);
+#endif
+
   /* TODO stacks: cur, main, tmps, mark, scope, save */
   /* TODO PL_exitlist */
   /* TODO PL_reentrant_buffers etc */