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