Include the size of constants in constant subs (resolves CPAN #58485)
[p5sagit/Devel-Size.git] / Size.xs
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4 #include "ppport.h"
5
6 /* Not yet in ppport.h */
7 #ifndef CvISXSUB
8 #  define CvISXSUB(cv)  (CvXSUB(cv) ? TRUE : FALSE)
9 #endif
10
11 #ifdef _MSC_VER 
12 /* "structured exception" handling is a Microsoft extension to C and C++.
13    It's *not* C++ exception handling - C++ exception handling can't capture
14    SEGVs and suchlike, whereas this can. There's no known analagous
15     functionality on other platforms.  */
16 #  include <excpt.h>
17 #  define TRY_TO_CATCH_SEGV __try
18 #  define CAUGHT_EXCEPTION __except(EXCEPTION EXCEPTION_EXECUTE_HANDLER)
19 #else
20 #  define TRY_TO_CATCH_SEGV if(1)
21 #  define CAUGHT_EXCEPTION else
22 #endif
23
24 #ifdef __GNUC__
25 # define __attribute__(x)
26 #endif
27
28 static int regex_whine;
29 static int fm_whine;
30 static int dangle_whine = 0;
31
32 #if 0 && defined(DEBUGGING)
33 #define dbg_printf(x) printf x
34 #else
35 #define dbg_printf(x)
36 #endif
37
38 #define TAG //printf( "# %s(%d)\n", __FILE__, __LINE__ )
39 #define carp puts
40
41 /* The idea is to have a tree structure to store 1 bit per possible pointer
42    address. The lowest 16 bits are stored in a block of 8092 bytes.
43    The blocks are in a 256-way tree, indexed by the reset of the pointer.
44    This can cope with 32 and 64 bit pointers, and any address space layout,
45    without excessive memory needs. The assumption is that your CPU cache
46    works :-) (And that we're not going to bust it)  */
47
48 #define ALIGN_BITS  ( sizeof(void*) >> 1 )
49 #define BYTE_BITS    3
50 #define LEAF_BITS   (16 - BYTE_BITS)
51 #define LEAF_MASK   0x1FFF
52
53 typedef void * TRACKING[256];
54
55 /* 
56     Checks to see if thing is in the bitstring. 
57     Returns true or false, and
58     notes thing in the segmented bitstring.
59  */
60 static bool
61 check_new(TRACKING *tv, const void *const p) {
62     unsigned int bits = 8 * sizeof(void*);
63     const size_t raw_p = PTR2nat(p);
64     /* This effectively rotates the value right by the number of low always-0
65        bits in an aligned pointer. The assmption is that most (if not all)
66        pointers are aligned, and these will be in the same chain of nodes
67        (and hence hot in the cache) but we can still deal with any unaligned
68        pointers.  */
69     const size_t cooked_p
70         = (raw_p >> ALIGN_BITS) | (raw_p << (bits - BYTE_BITS));
71     const U8 this_bit = 1 << (cooked_p & 0x7);
72     U8 **leaf_p;
73     U8 *leaf;
74     unsigned int i;
75     void **tv_p = (void **) tv;
76
77     assert(tv);
78     if (NULL == p) return FALSE;
79     TRY_TO_CATCH_SEGV { 
80         const char c = *(const char *)p;
81     }
82     CAUGHT_EXCEPTION {
83         if( dangle_whine ) 
84             warn( "Devel::Size: Encountered invalid pointer: %p\n", p );
85         return FALSE;
86     }
87     TAG;    
88
89     bits -= 8;
90     /* bits now 24 (32 bit pointers) or 56 (64 bit pointers) */
91
92     /* First level is always present.  */
93     do {
94         i = (unsigned int)((cooked_p >> bits) & 0xFF);
95         if (!tv_p[i])
96             Newxz(tv_p[i], 256, void *);
97         tv_p = (void **)(tv_p[i]);
98         bits -= 8;
99     } while (bits > LEAF_BITS + BYTE_BITS);
100     /* bits now 16 always */
101     assert(bits == 16);
102     leaf_p = (U8 **)tv_p;
103     i = (unsigned int)((cooked_p >> bits) & 0xFF);
104     if (!leaf_p[i])
105         Newxz(leaf_p[i], 1 << LEAF_BITS, U8);
106     leaf = leaf_p[i];
107
108     TAG;    
109
110     i = (unsigned int)((cooked_p >> BYTE_BITS) & LEAF_MASK);
111
112     if(leaf[i] & this_bit)
113         return FALSE;
114
115     leaf[i] |= this_bit;
116     return TRUE;
117 }
118
119 static void
120 free_tracking_at(void **tv, int level)
121 {
122     int i = 255;
123
124     if (--level) {
125         /* Nodes */
126         do {
127             if (tv[i]) {
128                 free_tracking_at(tv[i], level);
129                 Safefree(tv[i]);
130             }
131         } while (i--);
132     } else {
133         /* Leaves */
134         do {
135             if (tv[i])
136                 Safefree(tv[i]);
137         } while (i--);
138     }
139 }
140
141 static void
142 free_tracking(TRACKING *tv)
143 {
144     const int top_level = (sizeof(void *) * 8 - LEAF_BITS - BYTE_BITS) / 8;
145     free_tracking_at((void **)tv, top_level);
146     Safefree(tv);
147 }
148
149 UV thing_size(const SV *const, TRACKING *);
150 typedef enum {
151     OPc_NULL,   /* 0 */
152     OPc_BASEOP, /* 1 */
153     OPc_UNOP,   /* 2 */
154     OPc_BINOP,  /* 3 */
155     OPc_LOGOP,  /* 4 */
156     OPc_LISTOP, /* 5 */
157     OPc_PMOP,   /* 6 */
158     OPc_SVOP,   /* 7 */
159     OPc_PADOP,  /* 8 */
160     OPc_PVOP,   /* 9 */
161     OPc_LOOP,   /* 10 */
162     OPc_COP /* 11 */
163 } opclass;
164
165 static opclass
166 cc_opclass(const OP * const o)
167 {
168     if (!o)
169     return OPc_NULL;
170     TRY_TO_CATCH_SEGV {
171         if (o->op_type == 0)
172         return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
173
174         if (o->op_type == OP_SASSIGN)
175         return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
176
177     #ifdef USE_ITHREADS
178         if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
179         return OPc_PADOP;
180     #endif
181
182         if ((o->op_type == OP_TRANS)) {
183           return OPc_BASEOP;
184         }
185
186         switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
187         case OA_BASEOP: TAG;
188         return OPc_BASEOP;
189
190         case OA_UNOP: TAG;
191         return OPc_UNOP;
192
193         case OA_BINOP: TAG;
194         return OPc_BINOP;
195
196         case OA_LOGOP: TAG;
197         return OPc_LOGOP;
198
199         case OA_LISTOP: TAG;
200         return OPc_LISTOP;
201
202         case OA_PMOP: TAG;
203         return OPc_PMOP;
204
205         case OA_SVOP: TAG;
206         return OPc_SVOP;
207
208         case OA_PADOP: TAG;
209         return OPc_PADOP;
210
211         case OA_PVOP_OR_SVOP: TAG;
212             /*
213              * Character translations (tr///) are usually a PVOP, keeping a 
214              * pointer to a table of shorts used to look up translations.
215              * Under utf8, however, a simple table isn't practical; instead,
216              * the OP is an SVOP, and the SV is a reference to a swash
217              * (i.e., an RV pointing to an HV).
218              */
219         return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
220             ? OPc_SVOP : OPc_PVOP;
221
222         case OA_LOOP: TAG;
223         return OPc_LOOP;
224
225         case OA_COP: TAG;
226         return OPc_COP;
227
228         case OA_BASEOP_OR_UNOP: TAG;
229         /*
230          * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on
231          * whether parens were seen. perly.y uses OPf_SPECIAL to
232          * signal whether a BASEOP had empty parens or none.
233          * Some other UNOPs are created later, though, so the best
234          * test is OPf_KIDS, which is set in newUNOP.
235          */
236         return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
237
238         case OA_FILESTATOP: TAG;
239         /*
240          * The file stat OPs are created via UNI(OP_foo) in toke.c but use
241          * the OPf_REF flag to distinguish between OP types instead of the
242          * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we
243          * return OPc_UNOP so that walkoptree can find our children. If
244          * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set
245          * (no argument to the operator) it's an OP; with OPf_REF set it's
246          * an SVOP (and op_sv is the GV for the filehandle argument).
247          */
248         return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
249     #ifdef USE_ITHREADS
250             (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
251     #else
252             (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
253     #endif
254         case OA_LOOPEXOP: TAG;
255         /*
256          * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a
257          * label was omitted (in which case it's a BASEOP) or else a term was
258          * seen. In this last case, all except goto are definitely PVOP but
259          * goto is either a PVOP (with an ordinary constant label), an UNOP
260          * with OPf_STACKED (with a non-constant non-sub) or an UNOP for
261          * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to
262          * get set.
263          */
264         if (o->op_flags & OPf_STACKED)
265             return OPc_UNOP;
266         else if (o->op_flags & OPf_SPECIAL)
267             return OPc_BASEOP;
268         else
269             return OPc_PVOP;
270         }
271         warn("Devel::Size: Can't determine class of operator %s, assuming BASEOP\n",
272          PL_op_name[o->op_type]);
273     }
274     CAUGHT_EXCEPTION { }
275     return OPc_BASEOP;
276 }
277
278
279 #if !defined(NV)
280 #define NV double
281 #endif
282
283 static int go_yell = 1;
284
285 /* Figure out how much magic is attached to the SV and return the
286    size */
287 IV magic_size(const SV * const thing, TRACKING *tv) {
288   IV total_size = 0;
289   MAGIC *magic_pointer;
290
291   /* Is there any? */
292   if (!SvMAGIC(thing)) {
293     /* No, bail */
294     return 0;
295   }
296
297   /* Get the base magic pointer */
298   magic_pointer = SvMAGIC(thing);
299
300   /* Have we seen the magic pointer? */
301   while (magic_pointer && check_new(tv, magic_pointer)) {
302     total_size += sizeof(MAGIC);
303
304     TRY_TO_CATCH_SEGV {
305         /* Have we seen the magic vtable? */
306         if (magic_pointer->mg_virtual &&
307         check_new(tv, magic_pointer->mg_virtual)) {
308           total_size += sizeof(MGVTBL);
309         }
310
311         /* Get the next in the chain */ // ?try
312         magic_pointer = magic_pointer->mg_moremagic;
313     }
314     CAUGHT_EXCEPTION { 
315         if( dangle_whine ) 
316             warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
317     }
318   }
319   return total_size;
320 }
321
322 UV regex_size(const REGEXP * const baseregex, TRACKING *tv) {
323   UV total_size = 0;
324
325   total_size += sizeof(REGEXP);
326 #if (PERL_VERSION < 11)     
327   /* Note the size of the paren offset thing */
328   total_size += sizeof(I32) * baseregex->nparens * 2;
329   total_size += strlen(baseregex->precomp);
330 #else
331   total_size += sizeof(struct regexp);
332   total_size += sizeof(I32) * SvANY(baseregex)->nparens * 2;
333   /*total_size += strlen(SvANY(baseregex)->subbeg);*/
334 #endif
335   if (go_yell && !regex_whine) {
336     carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
337     regex_whine = 1;
338   }
339
340   return total_size;
341 }
342
343 UV op_size(const OP * const baseop, TRACKING *tv) {
344   UV total_size = 0;
345   TRY_TO_CATCH_SEGV {
346       TAG;
347       if (check_new(tv, baseop->op_next)) {
348            total_size += op_size(baseop->op_next, tv);
349       }
350       TAG;
351       switch (cc_opclass(baseop)) {
352       case OPc_BASEOP: TAG;
353         total_size += sizeof(struct op);
354         TAG;break;
355       case OPc_UNOP: TAG;
356         total_size += sizeof(struct unop);
357         if (check_new(tv, cUNOPx(baseop)->op_first)) {
358           total_size += op_size(cUNOPx(baseop)->op_first, tv);
359         }
360         TAG;break;
361       case OPc_BINOP: TAG;
362         total_size += sizeof(struct binop);
363         if (check_new(tv, cBINOPx(baseop)->op_first)) {
364           total_size += op_size(cBINOPx(baseop)->op_first, tv);
365         }  
366         if (check_new(tv, cBINOPx(baseop)->op_last)) {
367           total_size += op_size(cBINOPx(baseop)->op_last, tv);
368         }
369         TAG;break;
370       case OPc_LOGOP: TAG;
371         total_size += sizeof(struct logop);
372         if (check_new(tv, cLOGOPx(baseop)->op_first)) {
373           total_size += op_size(cBINOPx(baseop)->op_first, tv);
374         }  
375         if (check_new(tv, cLOGOPx(baseop)->op_other)) {
376           total_size += op_size(cLOGOPx(baseop)->op_other, tv);
377         }
378         TAG;break;
379       case OPc_LISTOP: TAG;
380         total_size += sizeof(struct listop);
381         if (check_new(tv, cLISTOPx(baseop)->op_first)) {
382           total_size += op_size(cLISTOPx(baseop)->op_first, tv);
383         }  
384         if (check_new(tv, cLISTOPx(baseop)->op_last)) {
385           total_size += op_size(cLISTOPx(baseop)->op_last, tv);
386         }
387         TAG;break;
388       case OPc_PMOP: TAG;
389         total_size += sizeof(struct pmop);
390         if (check_new(tv, cPMOPx(baseop)->op_first)) {
391           total_size += op_size(cPMOPx(baseop)->op_first, tv);
392         }  
393         if (check_new(tv, cPMOPx(baseop)->op_last)) {
394           total_size += op_size(cPMOPx(baseop)->op_last, tv);
395         }
396 #if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
397         if (check_new(tv, cPMOPx(baseop)->op_pmreplroot)) {
398           total_size += op_size(cPMOPx(baseop)->op_pmreplroot, tv);
399         }
400         if (check_new(tv, cPMOPx(baseop)->op_pmreplstart)) {
401           total_size += op_size(cPMOPx(baseop)->op_pmreplstart, tv);
402         }
403         if (check_new(tv, cPMOPx(baseop)->op_pmnext)) {
404           total_size += op_size((OP *)cPMOPx(baseop)->op_pmnext, tv);
405         }
406 #endif
407         /* This is defined away in perl 5.8.x, but it is in there for
408            5.6.x */
409 #ifdef PM_GETRE
410         if (check_new(tv, PM_GETRE((cPMOPx(baseop))))) {
411           total_size += regex_size(PM_GETRE(cPMOPx(baseop)), tv);
412         }
413 #else
414         if (check_new(tv, cPMOPx(baseop)->op_pmregexp)) {
415           total_size += regex_size(cPMOPx(baseop)->op_pmregexp, tv);
416         }
417 #endif
418         TAG;break;
419       case OPc_SVOP: TAG;
420         total_size += sizeof(struct pmop);
421         if (check_new(tv, cSVOPx(baseop)->op_sv)) {
422           total_size += thing_size(cSVOPx(baseop)->op_sv, tv);
423         }
424         TAG;break;
425       case OPc_PADOP: TAG;
426         total_size += sizeof(struct padop);
427         TAG;break;
428       case OPc_PVOP: TAG;
429         if (check_new(tv, cPVOPx(baseop)->op_pv)) {
430           total_size += strlen(cPVOPx(baseop)->op_pv);
431         }
432       case OPc_LOOP: TAG;
433         total_size += sizeof(struct loop);
434         if (check_new(tv, cLOOPx(baseop)->op_first)) {
435           total_size += op_size(cLOOPx(baseop)->op_first, tv);
436         }  
437         if (check_new(tv, cLOOPx(baseop)->op_last)) {
438           total_size += op_size(cLOOPx(baseop)->op_last, tv);
439         }
440         if (check_new(tv, cLOOPx(baseop)->op_redoop)) {
441           total_size += op_size(cLOOPx(baseop)->op_redoop, tv);
442         }  
443         if (check_new(tv, cLOOPx(baseop)->op_nextop)) {
444           total_size += op_size(cLOOPx(baseop)->op_nextop, tv);
445         }
446         if (check_new(tv, cLOOPx(baseop)->op_lastop)) {
447           total_size += op_size(cLOOPx(baseop)->op_lastop, tv);
448         }  
449
450         TAG;break;
451       case OPc_COP: TAG;
452         {
453           COP *basecop;
454           basecop = (COP *)baseop;
455           total_size += sizeof(struct cop);
456
457           /* Change 33656 by nicholas@mouse-mill on 2008/04/07 11:29:51
458           Eliminate cop_label from struct cop by storing a label as the first
459           entry in the hints hash. Most statements don't have labels, so this
460           will save memory. Not sure how much. 
461           The check below will be incorrect fail on bleadperls
462           before 5.11 @33656, but later than 5.10, producing slightly too
463           small memory sizes on these Perls. */
464 #if (PERL_VERSION < 11)
465           if (check_new(tv, basecop->cop_label)) {
466         total_size += strlen(basecop->cop_label);
467           }
468 #endif
469 #ifdef USE_ITHREADS
470           if (check_new(tv, basecop->cop_file)) {
471         total_size += strlen(basecop->cop_file);
472           }
473           if (check_new(tv, basecop->cop_stashpv)) {
474         total_size += strlen(basecop->cop_stashpv);
475           }
476 #else
477           if (check_new(tv, basecop->cop_stash)) {
478         total_size += thing_size((SV *)basecop->cop_stash, tv);
479           }
480           if (check_new(tv, basecop->cop_filegv)) {
481         total_size += thing_size((SV *)basecop->cop_filegv, tv);
482           }
483 #endif
484
485         }
486         TAG;break;
487       default:
488         TAG;break;
489       }
490   }
491   CAUGHT_EXCEPTION {
492       if( dangle_whine ) 
493           warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
494   }
495   return total_size;
496 }
497
498 #if PERL_VERSION > 9 || (PERL_VERSION == 9 && PERL_SUBVERSION > 2)
499 #  define NEW_HEAD_LAYOUT
500 #endif
501
502 UV thing_size(const SV * const orig_thing, TRACKING *tv) {
503   const SV *thing = orig_thing;
504   UV total_size = sizeof(SV);
505
506   switch (SvTYPE(thing)) {
507     /* Is it undef? */
508   case SVt_NULL: TAG;
509     TAG;break;
510     /* Just a plain integer. This will be differently sized depending
511        on whether purify's been compiled in */
512   case SVt_IV: TAG;
513 #ifndef NEW_HEAD_LAYOUT
514 #  ifdef PURIFY
515     total_size += sizeof(sizeof(XPVIV));
516 #  else
517     total_size += sizeof(IV);
518 #  endif
519 #endif
520     TAG;break;
521     /* Is it a float? Like the int, it depends on purify */
522   case SVt_NV: TAG;
523 #ifdef PURIFY
524     total_size += sizeof(sizeof(XPVNV));
525 #else
526     total_size += sizeof(NV);
527 #endif
528     TAG;break;
529 #if (PERL_VERSION < 11)     
530     /* Is it a reference? */
531   case SVt_RV: TAG;
532 #ifndef NEW_HEAD_LAYOUT
533     total_size += sizeof(XRV);
534 #endif
535     TAG;break;
536 #endif
537     /* How about a plain string? In which case we need to add in how
538        much has been allocated */
539   case SVt_PV: TAG;
540     total_size += sizeof(XPV);
541 #if (PERL_VERSION < 11)
542     total_size += SvROK(thing) ? thing_size( SvRV(thing), tv) : SvLEN(thing);
543 #else
544     total_size += SvLEN(thing);
545 #endif
546     TAG;break;
547     /* A string with an integer part? */
548   case SVt_PVIV: TAG;
549     total_size += sizeof(XPVIV);
550 #if (PERL_VERSION < 11)
551     total_size += SvROK(thing) ? thing_size( SvRV(thing), tv) : SvLEN(thing);
552 #else
553     total_size += SvLEN(thing);
554 #endif
555     if(SvOOK(thing)) {
556         total_size += SvIVX(thing);
557     }
558     TAG;break;
559     /* A scalar/string/reference with a float part? */
560   case SVt_PVNV: TAG;
561     total_size += sizeof(XPVNV);
562 #if (PERL_VERSION < 11)
563     total_size += SvROK(thing) ? thing_size( SvRV(thing), tv) : SvLEN(thing);
564 #else
565     total_size += SvLEN(thing);
566 #endif
567     TAG;break;
568   case SVt_PVMG: TAG;
569     total_size += sizeof(XPVMG);
570 #if (PERL_VERSION < 11)
571     total_size += SvROK(thing) ? thing_size( SvRV(thing), tv) : SvLEN(thing);
572 #else
573     total_size += SvLEN(thing);
574 #endif
575     total_size += magic_size(thing, tv);
576     TAG;break;
577 #if PERL_VERSION <= 8
578   case SVt_PVBM: TAG;
579     total_size += sizeof(XPVBM);
580 #if (PERL_VERSION < 11)
581     total_size += SvROK(thing) ? thing_size( SvRV(thing), tv) : SvLEN(thing);
582 #else
583     total_size += SvLEN(thing);
584 #endif
585     total_size += magic_size(thing, tv);
586     TAG;break;
587 #endif
588   case SVt_PVLV: TAG;
589     total_size += sizeof(XPVLV);
590 #if (PERL_VERSION < 11)
591     total_size += SvROK(thing) ? thing_size( SvRV(thing), tv) : SvLEN(thing);
592 #else
593     total_size += SvLEN(thing);
594 #endif
595     total_size += magic_size(thing, tv);
596     TAG;break;
597     /* How much space is dedicated to the array? Not counting the
598        elements in the array, mind, just the array itself */
599   case SVt_PVAV: TAG;
600     total_size += sizeof(XPVAV);
601     /* Is there anything in the array? */
602     if (AvMAX(thing) != -1) {
603       /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
604       total_size += sizeof(SV *) * (AvMAX(thing) + 1);
605       dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", total_size, AvMAX(thing), av_len((AV*)thing)));
606     }
607     /* Add in the bits on the other side of the beginning */
608
609     dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n", 
610     total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
611
612     /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
613        resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
614     if (AvALLOC(thing) != 0) {
615       total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
616       }
617 #if (PERL_VERSION < 9)
618     /* Is there something hanging off the arylen element?
619        Post 5.9.something this is stored in magic, so will be found there,
620        and Perl_av_arylen_p() takes a non-const AV*, hence compilers rightly
621        complain about AvARYLEN() passing thing to it.  */
622     if (AvARYLEN(thing)) {
623       if (check_new(tv, AvARYLEN(thing))) {
624     total_size += thing_size(AvARYLEN(thing), tv);
625       }
626     }
627 #endif
628     total_size += magic_size(thing, tv);
629     TAG;break;
630   case SVt_PVHV: TAG;
631     /* First the base struct */
632     total_size += sizeof(XPVHV);
633     /* Now the array of buckets */
634     total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
635     /* Now walk the bucket chain */
636     if (HvARRAY(thing)) {
637       HE *cur_entry;
638       UV cur_bucket = 0;
639       for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
640         cur_entry = *(HvARRAY(thing) + cur_bucket);
641         while (cur_entry) {
642           total_size += sizeof(HE);
643           if (cur_entry->hent_hek) {
644             /* Hash keys can be shared. Have we seen this before? */
645             if (check_new(tv, cur_entry->hent_hek)) {
646               total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
647             }
648           }
649           cur_entry = cur_entry->hent_next;
650         }
651       }
652     }
653     total_size += magic_size(thing, tv);
654     TAG;break;
655   case SVt_PVCV: TAG;
656     total_size += sizeof(XPVCV);
657     total_size += magic_size(thing, tv);
658
659     total_size += ((XPVIO *) SvANY(thing))->xpv_len;
660     if (check_new(tv, CvSTASH(thing))) {
661       total_size += thing_size((SV *)CvSTASH(thing), tv);
662     }
663     if (check_new(tv, SvSTASH(thing))) {
664       total_size += thing_size( (SV *)SvSTASH(thing), tv);
665     }
666     if (check_new(tv, CvGV(thing))) {
667       total_size += thing_size((SV *)CvGV(thing), tv);
668     }
669     if (check_new(tv, CvPADLIST(thing))) {
670       total_size += thing_size((SV *)CvPADLIST(thing), tv);
671     }
672     if (check_new(tv, CvOUTSIDE(thing))) {
673       total_size += thing_size((SV *)CvOUTSIDE(thing), tv);
674     }
675     if (CvISXSUB(thing)) {
676         SV *sv = cv_const_sv((CV *)thing);
677         if (sv) {
678             total_size += thing_size(sv, tv);
679         }
680     } else {
681         if (check_new(tv, CvSTART(thing))) {
682             total_size += op_size(CvSTART(thing), tv);
683         }
684         if (check_new(tv, CvROOT(thing))) {
685             total_size += op_size(CvROOT(thing), tv);
686         }
687     }
688
689     TAG;break;
690   case SVt_PVGV: TAG;
691     total_size += magic_size(thing, tv);
692     total_size += sizeof(XPVGV);
693     total_size += GvNAMELEN(thing);
694 #ifdef GvFILE
695     /* Is there a file? */
696     if (GvFILE(thing)) {
697       if (check_new(tv, GvFILE(thing))) {
698     total_size += strlen(GvFILE(thing));
699       }
700     }
701 #endif
702     /* Is there something hanging off the glob? */
703     if (GvGP(thing)) {
704       if (check_new(tv, GvGP(thing))) {
705     total_size += sizeof(GP);
706     {
707       SV *generic_thing;
708       if ((generic_thing = (SV *)(GvGP(thing)->gp_sv))) {
709         total_size += thing_size(generic_thing, tv);
710       }
711       if ((generic_thing = (SV *)(GvGP(thing)->gp_form))) {
712         total_size += thing_size(generic_thing, tv);
713       }
714       if ((generic_thing = (SV *)(GvGP(thing)->gp_av))) {
715         total_size += thing_size(generic_thing, tv);
716       }
717       if ((generic_thing = (SV *)(GvGP(thing)->gp_hv))) {
718         total_size += thing_size(generic_thing, tv);
719       }
720       if ((generic_thing = (SV *)(GvGP(thing)->gp_egv))) {
721         total_size += thing_size(generic_thing, tv);
722       }
723       if ((generic_thing = (SV *)(GvGP(thing)->gp_cv))) {
724         total_size += thing_size(generic_thing, tv);
725       }
726     }
727       }
728     }
729     TAG;break;
730   case SVt_PVFM: TAG;
731     total_size += sizeof(XPVFM);
732     total_size += magic_size(thing, tv);
733     total_size += ((XPVIO *) SvANY(thing))->xpv_len;
734     if (check_new(tv, CvPADLIST(thing))) {
735       total_size += thing_size((SV *)CvPADLIST(thing), tv);
736     }
737     if (check_new(tv, CvOUTSIDE(thing))) {
738       total_size += thing_size((SV *)CvOUTSIDE(thing), tv);
739     }
740
741     if (go_yell && !fm_whine) {
742       carp("Devel::Size: Calculated sizes for FMs are incomplete");
743       fm_whine = 1;
744     }
745     TAG;break;
746   case SVt_PVIO: TAG;
747     total_size += sizeof(XPVIO);
748     total_size += magic_size(thing, tv);
749     if (check_new(tv, (SvPVX_const(thing)))) {
750       total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
751     }
752     /* Some embedded char pointers */
753     if (check_new(tv, ((XPVIO *) SvANY(thing))->xio_top_name)) {
754       total_size += strlen(((XPVIO *) SvANY(thing))->xio_top_name);
755     }
756     if (check_new(tv, ((XPVIO *) SvANY(thing))->xio_fmt_name)) {
757       total_size += strlen(((XPVIO *) SvANY(thing))->xio_fmt_name);
758     }
759     if (check_new(tv, ((XPVIO *) SvANY(thing))->xio_bottom_name)) {
760       total_size += strlen(((XPVIO *) SvANY(thing))->xio_bottom_name);
761     }
762     /* Throw the GVs on the list to be walked if they're not-null */
763     if (((XPVIO *) SvANY(thing))->xio_top_gv) {
764       total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_top_gv, 
765                    tv);
766     }
767     if (((XPVIO *) SvANY(thing))->xio_bottom_gv) {
768       total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv, 
769                    tv);
770     }
771     if (((XPVIO *) SvANY(thing))->xio_fmt_gv) {
772       total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv, 
773                    tv);
774     }
775
776     /* Only go trotting through the IO structures if they're really
777        trottable. If USE_PERLIO is defined we can do this. If
778        not... we can't, so we don't even try */
779 #ifdef USE_PERLIO
780     /* Dig into xio_ifp and xio_ofp here */
781     warn("Devel::Size: Can't size up perlio layers yet\n");
782 #endif
783     TAG;break;
784   default:
785     warn("Devel::Size: Unknown variable type: %d encountered\n", SvTYPE(thing) );
786   }
787   return total_size;
788 }
789
790 MODULE = Devel::Size        PACKAGE = Devel::Size       
791
792 PROTOTYPES: DISABLE
793
794 IV
795 size(orig_thing)
796      SV *orig_thing
797 CODE:
798 {
799   SV *thing = orig_thing;
800   /* Hash to track our seen pointers */
801   //HV *tracking_hash = newHV();
802   SV *warn_flag;
803   TRACKING *tv;
804   Newz( 0xfc0ff, tv, 1, TRACKING );
805
806   /* Check warning status */
807   go_yell = 0;
808   regex_whine = 0;
809   fm_whine = 0;
810
811   if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
812     dangle_whine = go_yell = SvIV(warn_flag);
813   }
814   if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
815     dangle_whine = SvIV(warn_flag);
816   }
817   
818   /* If they passed us a reference then dereference it. This is the
819      only way we can check the sizes of arrays and hashes */
820 #if (PERL_VERSION < 11)
821   if (SvOK(thing) && SvROK(thing)) {
822     thing = SvRV(thing);
823   }
824 #else
825   if (SvROK(thing)) {
826     thing = SvRV(thing);
827   }
828 #endif
829
830   RETVAL = thing_size(thing, tv);
831   free_tracking(tv);
832 }
833 OUTPUT:
834   RETVAL
835
836
837 IV
838 total_size(orig_thing)
839        SV *orig_thing
840 CODE:
841 {
842   SV *thing = orig_thing;
843   /* Hash to track our seen pointers */
844   //HV *tracking_hash;
845   TRACKING *tv;
846   /* Array with things we still need to do */
847   AV *pending_array;
848   IV size = 0;
849   SV *warn_flag;
850
851   /* Size starts at zero */
852   RETVAL = 0;
853
854   /* Check warning status */
855   go_yell = 0;
856   regex_whine = 0;
857   fm_whine = 0;
858
859   if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
860     dangle_whine = go_yell = SvIV(warn_flag);
861   }
862   if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
863     dangle_whine = SvIV(warn_flag);
864   }
865
866   /* init these after the go_yell above */
867   //tracking_hash = newHV();
868   Newz( 0xfc0ff, tv, 1, TRACKING );
869   pending_array = newAV();
870
871   /* We cannot push HV/AV directly, only the RV. So deref it
872      later (see below for "*** dereference later") and adjust here for
873      the miscalculation.
874      This is the only way we can check the sizes of arrays and hashes. */
875   if (SvROK(thing)) {
876       RETVAL -= thing_size(thing, NULL);
877   } 
878
879   /* Put it on the pending array */
880   av_push(pending_array, thing);
881
882   /* Now just yank things off the end of the array until it's done */
883   while (av_len(pending_array) >= 0) {
884     thing = av_pop(pending_array);
885     /* Process it if we've not seen it */
886     if (check_new(tv, thing)) {
887       dbg_printf(("# Found type %i at %p\n", SvTYPE(thing), thing));
888       /* Is it valid? */
889       if (thing) {
890     /* Yes, it is. So let's check the type */
891     switch (SvTYPE(thing)) {
892     /* fix for bug #24846 (Does not correctly recurse into references in a PVNV-type scalar) */
893     case SVt_PVNV: TAG;
894       if (SvROK(thing))
895         {
896         av_push(pending_array, SvRV(thing));
897         } 
898       TAG;break;
899
900     /* this is the "*** dereference later" part - see above */
901 #if (PERL_VERSION < 11)
902         case SVt_RV: TAG;
903 #else
904         case SVt_IV: TAG;
905 #endif
906              dbg_printf(("# Found RV\n"));
907           if (SvROK(thing)) {
908              dbg_printf(("# Found RV\n"));
909              av_push(pending_array, SvRV(thing));
910           }
911           TAG;break;
912
913     case SVt_PVAV: TAG;
914       {
915         AV *tempAV = (AV *)thing;
916         SV **tempSV;
917
918         dbg_printf(("# Found type AV\n"));
919         /* Quick alias to cut down on casting */
920         
921         /* Any elements? */
922         if (av_len(tempAV) != -1) {
923           IV index;
924           /* Run through them all */
925           for (index = 0; index <= av_len(tempAV); index++) {
926         /* Did we get something? */
927         if ((tempSV = av_fetch(tempAV, index, 0))) {
928           /* Was it undef? */
929           if (*tempSV != &PL_sv_undef) {
930             /* Apparently not. Save it for later */
931             av_push(pending_array, *tempSV);
932           }
933         }
934           }
935         }
936       }
937       TAG;break;
938
939     case SVt_PVHV: TAG;
940       dbg_printf(("# Found type HV\n"));
941       /* Is there anything in here? */
942       if (hv_iterinit((HV *)thing)) {
943         HE *temp_he;
944         while ((temp_he = hv_iternext((HV *)thing))) {
945           av_push(pending_array, hv_iterval((HV *)thing, temp_he));
946         }
947       }
948       TAG;break;
949      
950     case SVt_PVGV: TAG;
951       dbg_printf(("# Found type GV\n"));
952       /* Run through all the pieces and push the ones with bits */
953       if (GvSV(thing)) {
954         av_push(pending_array, (SV *)GvSV(thing));
955       }
956       if (GvFORM(thing)) {
957         av_push(pending_array, (SV *)GvFORM(thing));
958       }
959       if (GvAV(thing)) {
960         av_push(pending_array, (SV *)GvAV(thing));
961       }
962       if (GvHV(thing)) {
963         av_push(pending_array, (SV *)GvHV(thing));
964       }
965       if (GvCV(thing)) {
966         av_push(pending_array, (SV *)GvCV(thing));
967       }
968       TAG;break;
969     default:
970       TAG;break;
971     }
972       }
973       
974       size = thing_size(thing, tv);
975       RETVAL += size;
976     } else {
977     /* check_new() returned false: */
978 #ifdef DEVEL_SIZE_DEBUGGING
979        if (SvOK(sv)) printf("# Ignore ref copy 0x%x\n", sv);
980        else printf("# Ignore non-sv 0x%x\n", sv);
981 #endif
982     }
983   } /* end while */
984
985   free_tracking(tv);
986   SvREFCNT_dec(pending_array);
987 }
988 OUTPUT:
989   RETVAL
990