2a210e398a5b62339712f323e3e94008c653be65
[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 += 1 + 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             if (!(baseop->op_type == OP_AELEMFAST
412                   && baseop->op_flags & OPf_SPECIAL)) {
413                 /* not an OP_PADAV replacement */
414                 sv_size(aTHX_ st, cSVOPx(baseop)->op_sv, TRUE);
415             }
416             TAG;break;
417       case OPc_PADOP: TAG;
418           st->total_size += sizeof(struct padop);
419           TAG;break;
420         case OPc_PVOP: TAG;
421             check_new_and_strlen(st, cPVOPx(baseop)->op_pv);
422         case OPc_LOOP: TAG;
423             st->total_size += sizeof(struct loop);
424             op_size(aTHX_ cLOOPx(baseop)->op_first, st);
425             op_size(aTHX_ cLOOPx(baseop)->op_last, st);
426             op_size(aTHX_ cLOOPx(baseop)->op_redoop, st);
427             op_size(aTHX_ cLOOPx(baseop)->op_nextop, st);
428             op_size(aTHX_ cLOOPx(baseop)->op_lastop, st);
429             TAG;break;
430         case OPc_COP: TAG;
431         {
432           COP *basecop;
433           basecop = (COP *)baseop;
434           st->total_size += sizeof(struct cop);
435
436           /* Change 33656 by nicholas@mouse-mill on 2008/04/07 11:29:51
437           Eliminate cop_label from struct cop by storing a label as the first
438           entry in the hints hash. Most statements don't have labels, so this
439           will save memory. Not sure how much. 
440           The check below will be incorrect fail on bleadperls
441           before 5.11 @33656, but later than 5.10, producing slightly too
442           small memory sizes on these Perls. */
443 #if (PERL_VERSION < 11)
444           check_new_and_strlen(st, basecop->cop_label);
445 #endif
446 #ifdef USE_ITHREADS
447           check_new_and_strlen(st, basecop->cop_file);
448           check_new_and_strlen(st, basecop->cop_stashpv);
449 #else
450           sv_size(aTHX_ st, (SV *)basecop->cop_stash, TRUE);
451           sv_size(aTHX_ st, (SV *)basecop->cop_filegv, TRUE);
452 #endif
453
454         }
455         TAG;break;
456       default:
457         TAG;break;
458       }
459   }
460   CAUGHT_EXCEPTION {
461       if (st->dangle_whine) 
462           warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
463   }
464 }
465
466 #if PERL_VERSION > 9 || (PERL_VERSION == 9 && PERL_SUBVERSION > 2)
467 #  define NEW_HEAD_LAYOUT
468 #endif
469
470 static bool
471 sv_size(pTHX_ struct state *const st, const SV * const orig_thing,
472         const bool recurse) {
473   const SV *thing = orig_thing;
474
475   if(!check_new(st, thing))
476       return FALSE;
477
478   st->total_size += sizeof(SV);
479
480   switch (SvTYPE(thing)) {
481     /* Is it undef? */
482   case SVt_NULL: TAG;
483     TAG;break;
484     /* Just a plain integer. This will be differently sized depending
485        on whether purify's been compiled in */
486   case SVt_IV: TAG;
487 #ifndef NEW_HEAD_LAYOUT
488 #  ifdef PURIFY
489     st->total_size += sizeof(sizeof(XPVIV));
490 #  else
491     st->total_size += sizeof(IV);
492 #  endif
493 #endif
494     if(recurse && SvROK(thing))
495         sv_size(aTHX_ st, SvRV_const(thing), TRUE);
496     TAG;break;
497     /* Is it a float? Like the int, it depends on purify */
498   case SVt_NV: TAG;
499 #ifdef PURIFY
500     st->total_size += sizeof(sizeof(XPVNV));
501 #else
502     st->total_size += sizeof(NV);
503 #endif
504     TAG;break;
505 #if (PERL_VERSION < 11)     
506     /* Is it a reference? */
507   case SVt_RV: TAG;
508 #ifndef NEW_HEAD_LAYOUT
509     st->total_size += sizeof(XRV);
510 #endif
511     if(recurse && SvROK(thing))
512         sv_size(aTHX_ st, SvRV_const(thing), TRUE);
513     TAG;break;
514 #endif
515     /* How about a plain string? In which case we need to add in how
516        much has been allocated */
517   case SVt_PV: TAG;
518     st->total_size += sizeof(XPV);
519     if(recurse && SvROK(thing))
520         sv_size(aTHX_ st, SvRV_const(thing), TRUE);
521     else
522         st->total_size += SvLEN(thing);
523     TAG;break;
524     /* A string with an integer part? */
525   case SVt_PVIV: TAG;
526     st->total_size += sizeof(XPVIV);
527     if(recurse && SvROK(thing))
528         sv_size(aTHX_ st, SvRV_const(thing), TRUE);
529     else
530         st->total_size += SvLEN(thing);
531     if(SvOOK(thing)) {
532         st->total_size += SvIVX(thing);
533     }
534     TAG;break;
535     /* A scalar/string/reference with a float part? */
536   case SVt_PVNV: TAG;
537     st->total_size += sizeof(XPVNV);
538     if(recurse && SvROK(thing))
539         sv_size(aTHX_ st, SvRV_const(thing), TRUE);
540     else
541         st->total_size += SvLEN(thing);
542     TAG;break;
543   case SVt_PVMG: TAG;
544     st->total_size += sizeof(XPVMG);
545     if(recurse && SvROK(thing))
546         sv_size(aTHX_ st, SvRV_const(thing), TRUE);
547     else
548         st->total_size += SvLEN(thing);
549     magic_size(thing, st);
550     TAG;break;
551 #if PERL_VERSION <= 8
552   case SVt_PVBM: TAG;
553     st->total_size += sizeof(XPVBM);
554     if(recurse && SvROK(thing))
555         sv_size(aTHX_ st, SvRV_const(thing), TRUE);
556     else
557         st->total_size += SvLEN(thing);
558     magic_size(thing, st);
559     TAG;break;
560 #endif
561   case SVt_PVLV: TAG;
562     st->total_size += sizeof(XPVLV);
563     if(recurse && SvROK(thing))
564         sv_size(aTHX_ st, SvRV_const(thing), TRUE);
565     else
566         st->total_size += SvLEN(thing);
567     magic_size(thing, st);
568     TAG;break;
569     /* How much space is dedicated to the array? Not counting the
570        elements in the array, mind, just the array itself */
571   case SVt_PVAV: TAG;
572     st->total_size += sizeof(XPVAV);
573     /* Is there anything in the array? */
574     if (AvMAX(thing) != -1) {
575       /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
576       st->total_size += sizeof(SV *) * (AvMAX(thing) + 1);
577       dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
578     }
579     /* Add in the bits on the other side of the beginning */
580
581     dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n", 
582     st->total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
583
584     /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
585        resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
586     if (AvALLOC(thing) != 0) {
587       st->total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
588       }
589 #if (PERL_VERSION < 9)
590     /* Is there something hanging off the arylen element?
591        Post 5.9.something this is stored in magic, so will be found there,
592        and Perl_av_arylen_p() takes a non-const AV*, hence compilers rightly
593        complain about AvARYLEN() passing thing to it.  */
594     sv_size(aTHX_ st, AvARYLEN(thing), TRUE);
595 #endif
596     magic_size(thing, st);
597     TAG;break;
598   case SVt_PVHV: TAG;
599     /* First the base struct */
600     st->total_size += sizeof(XPVHV);
601     /* Now the array of buckets */
602     st->total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
603     /* Now walk the bucket chain */
604     if (HvARRAY(thing)) {
605       HE *cur_entry;
606       UV cur_bucket = 0;
607       for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
608         cur_entry = *(HvARRAY(thing) + cur_bucket);
609         while (cur_entry) {
610           st->total_size += sizeof(HE);
611           if (cur_entry->hent_hek) {
612             /* Hash keys can be shared. Have we seen this before? */
613             if (check_new(st, cur_entry->hent_hek)) {
614               st->total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
615             }
616           }
617           cur_entry = cur_entry->hent_next;
618         }
619       }
620     }
621     magic_size(thing, st);
622     TAG;break;
623   case SVt_PVCV: TAG;
624     st->total_size += sizeof(XPVCV);
625     magic_size(thing, st);
626
627     st->total_size += ((XPVIO *) SvANY(thing))->xpv_len;
628     sv_size(aTHX_ st, (SV *)CvSTASH(thing), TRUE);
629     sv_size(aTHX_ st, (SV *)SvSTASH(thing), TRUE);
630     sv_size(aTHX_ st, (SV *)CvGV(thing), TRUE);
631     sv_size(aTHX_ st, (SV *)CvPADLIST(thing), TRUE);
632     sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), TRUE);
633     if (CvISXSUB(thing)) {
634         sv_size(aTHX_ st, cv_const_sv((CV *)thing), TRUE);
635     } else {
636         op_size(aTHX_ CvSTART(thing), st);
637         op_size(aTHX_ CvROOT(thing), st);
638     }
639
640     TAG;break;
641   case SVt_PVGV: TAG;
642     magic_size(thing, st);
643     st->total_size += sizeof(XPVGV);
644     st->total_size += GvNAMELEN(thing);
645 #ifdef GvFILE
646     /* Is there a file? */
647     check_new_and_strlen(st, GvFILE(thing));
648 #endif
649     /* Is there something hanging off the glob? */
650     if (GvGP(thing)) {
651       if (check_new(st, GvGP(thing))) {
652           st->total_size += sizeof(GP);
653           sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_sv), TRUE);
654           sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_form), TRUE);
655           sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_av), TRUE);
656           sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_hv), TRUE);
657           sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_egv), TRUE);
658           sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_cv), TRUE);
659       }
660     }
661     TAG;break;
662   case SVt_PVFM: TAG;
663     st->total_size += sizeof(XPVFM);
664     magic_size(thing, st);
665     st->total_size += ((XPVIO *) SvANY(thing))->xpv_len;
666     sv_size(aTHX_ st, (SV *)CvPADLIST(thing), TRUE);
667     sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), TRUE);
668
669     if (st->go_yell && !st->fm_whine) {
670       carp("Devel::Size: Calculated sizes for FMs are incomplete");
671       st->fm_whine = 1;
672     }
673     TAG;break;
674   case SVt_PVIO: TAG;
675     st->total_size += sizeof(XPVIO);
676     magic_size(thing, st);
677     if (check_new(st, (SvPVX_const(thing)))) {
678       st->total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
679     }
680     /* Some embedded char pointers */
681     check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_top_name);
682     check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_fmt_name);
683     check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_bottom_name);
684     /* Throw the GVs on the list to be walked if they're not-null */
685     sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_top_gv, TRUE);
686     sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv, TRUE);
687     sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv, TRUE);
688
689     /* Only go trotting through the IO structures if they're really
690        trottable. If USE_PERLIO is defined we can do this. If
691        not... we can't, so we don't even try */
692 #ifdef USE_PERLIO
693     /* Dig into xio_ifp and xio_ofp here */
694     warn("Devel::Size: Can't size up perlio layers yet\n");
695 #endif
696     TAG;break;
697   default:
698     warn("Devel::Size: Unknown variable type: %d encountered\n", SvTYPE(thing) );
699   }
700   return TRUE;
701 }
702
703 static struct state *
704 new_state(pTHX)
705 {
706     SV *warn_flag;
707     struct state *st;
708     Newxz(st, 1, struct state);
709     st->go_yell = TRUE;
710     if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
711         st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
712     }
713     if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
714         st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
715     }
716     check_new(st, &PL_sv_undef);
717     check_new(st, &PL_sv_no);
718     check_new(st, &PL_sv_yes);
719     return st;
720 }
721
722 MODULE = Devel::Size        PACKAGE = Devel::Size       
723
724 PROTOTYPES: DISABLE
725
726 UV
727 size(orig_thing)
728      SV *orig_thing
729 CODE:
730 {
731   SV *thing = orig_thing;
732   struct state *st = new_state(aTHX);
733   
734   /* If they passed us a reference then dereference it. This is the
735      only way we can check the sizes of arrays and hashes */
736 #if (PERL_VERSION < 11)
737   if (SvOK(thing) && SvROK(thing)) {
738     thing = SvRV(thing);
739   }
740 #else
741   if (SvROK(thing)) {
742     thing = SvRV(thing);
743   }
744 #endif
745
746   sv_size(aTHX_ st, thing, FALSE);
747   RETVAL = st->total_size;
748   free_state(st);
749 }
750 OUTPUT:
751   RETVAL
752
753
754 UV
755 total_size(orig_thing)
756        SV *orig_thing
757 CODE:
758 {
759   SV *thing = orig_thing;
760   /* Array with things we still need to do */
761   AV *pending_array;
762   IV size = 0;
763   struct state *st = new_state(aTHX);
764
765   /* Size starts at zero */
766   RETVAL = 0;
767
768   pending_array = newAV();
769
770   /* If they passed us a reference then dereference it.
771      This is the only way we can check the sizes of arrays and hashes. */
772   if (SvROK(thing)) {
773       thing = SvRV(thing);
774   } 
775
776   /* Put it on the pending array */
777   av_push(pending_array, thing);
778
779   /* Now just yank things off the end of the array until it's done */
780   while (av_len(pending_array) >= 0) {
781     thing = av_pop(pending_array);
782     /* Process it if we've not seen it */
783     if (sv_size(aTHX_ st, thing, TRUE)) {
784       dbg_printf(("# Found type %i at %p\n", SvTYPE(thing), thing));
785     switch (SvTYPE(thing)) {
786     /* fix for bug #24846 (Does not correctly recurse into references in a PVNV-type scalar) */
787     case SVt_PVNV: TAG;
788       if (SvROK(thing))
789         {
790         av_push(pending_array, SvRV(thing));
791         } 
792       TAG;break;
793 #if (PERL_VERSION < 11)
794         case SVt_RV: TAG;
795 #else
796         case SVt_IV: TAG;
797 #endif
798              dbg_printf(("# Found RV\n"));
799           if (SvROK(thing)) {
800              dbg_printf(("# Found RV\n"));
801              av_push(pending_array, SvRV(thing));
802           }
803           TAG;break;
804
805     case SVt_PVAV: TAG;
806       {
807         AV *tempAV = (AV *)thing;
808         SV **tempSV;
809
810         dbg_printf(("# Found type AV\n"));
811         /* Quick alias to cut down on casting */
812         
813         /* Any elements? */
814         if (av_len(tempAV) != -1) {
815           IV index;
816           /* Run through them all */
817           for (index = 0; index <= av_len(tempAV); index++) {
818         /* Did we get something? */
819         if ((tempSV = av_fetch(tempAV, index, 0))) {
820           /* Was it undef? */
821           if (*tempSV != &PL_sv_undef) {
822             /* Apparently not. Save it for later */
823             av_push(pending_array, *tempSV);
824           }
825         }
826           }
827         }
828       }
829       TAG;break;
830
831     case SVt_PVHV: TAG;
832       dbg_printf(("# Found type HV\n"));
833       /* Is there anything in here? */
834       if (hv_iterinit((HV *)thing)) {
835         HE *temp_he;
836         while ((temp_he = hv_iternext((HV *)thing))) {
837           av_push(pending_array, hv_iterval((HV *)thing, temp_he));
838         }
839       }
840       TAG;break;
841      
842     case SVt_PVGV: TAG;
843       dbg_printf(("# Found type GV\n"));
844       /* Run through all the pieces and push the ones with bits */
845       if (GvSV(thing)) {
846         av_push(pending_array, (SV *)GvSV(thing));
847       }
848       if (GvFORM(thing)) {
849         av_push(pending_array, (SV *)GvFORM(thing));
850       }
851       if (GvAV(thing)) {
852         av_push(pending_array, (SV *)GvAV(thing));
853       }
854       if (GvHV(thing)) {
855         av_push(pending_array, (SV *)GvHV(thing));
856       }
857       if (GvCV(thing)) {
858         av_push(pending_array, (SV *)GvCV(thing));
859       }
860       TAG;break;
861     default:
862       TAG;break;
863       }
864     } else {
865     /* check_new() returned false: */
866 #ifdef DEVEL_SIZE_DEBUGGING
867        if (SvOK(sv)) printf("# Ignore ref copy 0x%x\n", sv);
868        else printf("# Ignore non-sv 0x%x\n", sv);
869 #endif
870     }
871   } /* end while */
872
873   RETVAL = st->total_size;
874   free_state(st);
875   SvREFCNT_dec(pending_array);
876 }
877 OUTPUT:
878   RETVAL
879