e89a33cb98d950029eaac137eecbc5777adcf5c1
[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 BYTE_BITS    3
50 #define LEAF_BITS   (16 - BYTE_BITS)
51 #define LEAF_MASK   0x1FFF
52
53 struct state {
54     UV total_size;
55     bool regex_whine;
56     bool fm_whine;
57     bool dangle_whine;
58     bool go_yell;
59     /* My hunch (not measured) is that for most architectures pointers will
60        start with 0 bits, hence the start of this array will be hot, and the
61        end unused. So put the flags next to the hot end.  */
62     void *tracking[256];
63 };
64
65 /* 
66     Checks to see if thing is in the bitstring. 
67     Returns true or false, and
68     notes thing in the segmented bitstring.
69  */
70 static bool
71 check_new(struct state *st, const void *const p) {
72     unsigned int bits = 8 * sizeof(void*);
73     const size_t raw_p = PTR2nat(p);
74     /* This effectively rotates the value right by the number of low always-0
75        bits in an aligned pointer. The assmption is that most (if not all)
76        pointers are aligned, and these will be in the same chain of nodes
77        (and hence hot in the cache) but we can still deal with any unaligned
78        pointers.  */
79     const size_t cooked_p
80         = (raw_p >> ALIGN_BITS) | (raw_p << (bits - ALIGN_BITS));
81     const U8 this_bit = 1 << (cooked_p & 0x7);
82     U8 **leaf_p;
83     U8 *leaf;
84     unsigned int i;
85     void **tv_p = (void **) (st->tracking);
86
87     if (NULL == p) return FALSE;
88     TRY_TO_CATCH_SEGV { 
89         const char c = *(const char *)p;
90     }
91     CAUGHT_EXCEPTION {
92         if (st->dangle_whine) 
93             warn( "Devel::Size: Encountered invalid pointer: %p\n", p );
94         return FALSE;
95     }
96     TAG;    
97
98     bits -= 8;
99     /* bits now 24 (32 bit pointers) or 56 (64 bit pointers) */
100
101     /* First level is always present.  */
102     do {
103         i = (unsigned int)((cooked_p >> bits) & 0xFF);
104         if (!tv_p[i])
105             Newxz(tv_p[i], 256, void *);
106         tv_p = (void **)(tv_p[i]);
107         bits -= 8;
108     } while (bits > LEAF_BITS + BYTE_BITS);
109     /* bits now 16 always */
110 #if !defined(MULTIPLICITY) || PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8)
111     /* 5.8.8 and early have an assert() macro that uses Perl_croak, hence needs
112        a my_perl under multiplicity  */
113     assert(bits == 16);
114 #endif
115     leaf_p = (U8 **)tv_p;
116     i = (unsigned int)((cooked_p >> bits) & 0xFF);
117     if (!leaf_p[i])
118         Newxz(leaf_p[i], 1 << LEAF_BITS, U8);
119     leaf = leaf_p[i];
120
121     TAG;    
122
123     i = (unsigned int)((cooked_p >> BYTE_BITS) & LEAF_MASK);
124
125     if(leaf[i] & this_bit)
126         return FALSE;
127
128     leaf[i] |= this_bit;
129     return TRUE;
130 }
131
132 static void
133 free_tracking_at(void **tv, int level)
134 {
135     int i = 255;
136
137     if (--level) {
138         /* Nodes */
139         do {
140             if (tv[i]) {
141                 free_tracking_at(tv[i], level);
142                 Safefree(tv[i]);
143             }
144         } while (i--);
145     } else {
146         /* Leaves */
147         do {
148             if (tv[i])
149                 Safefree(tv[i]);
150         } while (i--);
151     }
152 }
153
154 static void
155 free_state(struct state *st)
156 {
157     const int top_level = (sizeof(void *) * 8 - LEAF_BITS - BYTE_BITS) / 8;
158     free_tracking_at((void **)st->tracking, top_level);
159     Safefree(st);
160 }
161
162 /* For now, this is somewhat a compatibility bodge until the plan comes
163    together for fine grained recursion control. total_size() would recurse into
164    hash and array members, whereas sv_size() would not. However, sv_size() is
165    called with CvSTASH() of a CV, which means that if it (also) starts to
166    recurse fully, then the size of any CV now becomes the size of the entire
167    symbol table reachable from it, and potentially the entire symbol table, if
168    any subroutine makes a reference to a global (such as %SIG). The historical
169    implementation of total_size() didn't report "everything", and changing the
170    only available size to "everything" doesn't feel at all useful.  */
171
172 #define NO_RECURSION 0
173 #define SOME_RECURSION 1
174 #define TOTAL_SIZE_RECURSION 2
175
176 static bool sv_size(pTHX_ struct state *, const SV *const, const int recurse);
177
178 typedef enum {
179     OPc_NULL,   /* 0 */
180     OPc_BASEOP, /* 1 */
181     OPc_UNOP,   /* 2 */
182     OPc_BINOP,  /* 3 */
183     OPc_LOGOP,  /* 4 */
184     OPc_LISTOP, /* 5 */
185     OPc_PMOP,   /* 6 */
186     OPc_SVOP,   /* 7 */
187     OPc_PADOP,  /* 8 */
188     OPc_PVOP,   /* 9 */
189     OPc_LOOP,   /* 10 */
190     OPc_COP /* 11 */
191 } opclass;
192
193 static opclass
194 cc_opclass(const OP * const o)
195 {
196     if (!o)
197     return OPc_NULL;
198     TRY_TO_CATCH_SEGV {
199         if (o->op_type == 0)
200         return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
201
202         if (o->op_type == OP_SASSIGN)
203         return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
204
205     #ifdef USE_ITHREADS
206         if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
207         return OPc_PADOP;
208     #endif
209
210         if ((o->op_type == OP_TRANS)) {
211           return OPc_BASEOP;
212         }
213
214         switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
215         case OA_BASEOP: TAG;
216         return OPc_BASEOP;
217
218         case OA_UNOP: TAG;
219         return OPc_UNOP;
220
221         case OA_BINOP: TAG;
222         return OPc_BINOP;
223
224         case OA_LOGOP: TAG;
225         return OPc_LOGOP;
226
227         case OA_LISTOP: TAG;
228         return OPc_LISTOP;
229
230         case OA_PMOP: TAG;
231         return OPc_PMOP;
232
233         case OA_SVOP: TAG;
234         return OPc_SVOP;
235
236         case OA_PADOP: TAG;
237         return OPc_PADOP;
238
239         case OA_PVOP_OR_SVOP: TAG;
240             /*
241              * Character translations (tr///) are usually a PVOP, keeping a 
242              * pointer to a table of shorts used to look up translations.
243              * Under utf8, however, a simple table isn't practical; instead,
244              * the OP is an SVOP, and the SV is a reference to a swash
245              * (i.e., an RV pointing to an HV).
246              */
247         return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
248             ? OPc_SVOP : OPc_PVOP;
249
250         case OA_LOOP: TAG;
251         return OPc_LOOP;
252
253         case OA_COP: TAG;
254         return OPc_COP;
255
256         case OA_BASEOP_OR_UNOP: TAG;
257         /*
258          * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on
259          * whether parens were seen. perly.y uses OPf_SPECIAL to
260          * signal whether a BASEOP had empty parens or none.
261          * Some other UNOPs are created later, though, so the best
262          * test is OPf_KIDS, which is set in newUNOP.
263          */
264         return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
265
266         case OA_FILESTATOP: TAG;
267         /*
268          * The file stat OPs are created via UNI(OP_foo) in toke.c but use
269          * the OPf_REF flag to distinguish between OP types instead of the
270          * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we
271          * return OPc_UNOP so that walkoptree can find our children. If
272          * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set
273          * (no argument to the operator) it's an OP; with OPf_REF set it's
274          * an SVOP (and op_sv is the GV for the filehandle argument).
275          */
276         return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
277     #ifdef USE_ITHREADS
278             (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
279     #else
280             (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
281     #endif
282         case OA_LOOPEXOP: TAG;
283         /*
284          * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a
285          * label was omitted (in which case it's a BASEOP) or else a term was
286          * seen. In this last case, all except goto are definitely PVOP but
287          * goto is either a PVOP (with an ordinary constant label), an UNOP
288          * with OPf_STACKED (with a non-constant non-sub) or an UNOP for
289          * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to
290          * get set.
291          */
292         if (o->op_flags & OPf_STACKED)
293             return OPc_UNOP;
294         else if (o->op_flags & OPf_SPECIAL)
295             return OPc_BASEOP;
296         else
297             return OPc_PVOP;
298         }
299         warn("Devel::Size: Can't determine class of operator %s, assuming BASEOP\n",
300          PL_op_name[o->op_type]);
301     }
302     CAUGHT_EXCEPTION { }
303     return OPc_BASEOP;
304 }
305
306
307 #if !defined(NV)
308 #define NV double
309 #endif
310
311 /* Figure out how much magic is attached to the SV and return the
312    size */
313 static void
314 magic_size(pTHX_ const SV * const thing, struct state *st) {
315   MAGIC *magic_pointer = SvMAGIC(thing);
316
317   /* Have we seen the magic pointer?  (NULL has always been seen before)  */
318   while (check_new(st, magic_pointer)) {
319     st->total_size += sizeof(MAGIC);
320
321     TRY_TO_CATCH_SEGV {
322         /* Have we seen the magic vtable? */
323         if (check_new(st, magic_pointer->mg_virtual)) {
324           st->total_size += sizeof(MGVTBL);
325         }
326         sv_size(aTHX_ st, magic_pointer->mg_obj, TOTAL_SIZE_RECURSION);
327         if (magic_pointer->mg_len == HEf_SVKEY) {
328             sv_size(aTHX_ st, (SV *)magic_pointer->mg_ptr, TOTAL_SIZE_RECURSION);
329         }
330 #if defined(PERL_MAGIC_utf8) && defined (PERL_MAGIC_UTF8_CACHESIZE)
331         else if (magic_pointer->mg_type == PERL_MAGIC_utf8) {
332             if (check_new(st, magic_pointer->mg_ptr)) {
333                 st->total_size += PERL_MAGIC_UTF8_CACHESIZE * 2 * sizeof(STRLEN);
334             }
335         }
336 #endif
337         else if (magic_pointer->mg_len > 0) {
338             if (check_new(st, magic_pointer->mg_ptr)) {
339                 st->total_size += magic_pointer->mg_len;
340             }
341         }
342
343         /* Get the next in the chain */
344         magic_pointer = magic_pointer->mg_moremagic;
345     }
346     CAUGHT_EXCEPTION { 
347         if (st->dangle_whine) 
348             warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
349     }
350   }
351 }
352
353 static void
354 check_new_and_strlen(struct state *st, const char *const p) {
355     if(check_new(st, p))
356         st->total_size += 1 + strlen(p);
357 }
358
359 static void
360 regex_size(const REGEXP * const baseregex, struct state *st) {
361     if(!check_new(st, baseregex))
362         return;
363   st->total_size += sizeof(REGEXP);
364 #if (PERL_VERSION < 11)     
365   /* Note the size of the paren offset thing */
366   st->total_size += sizeof(I32) * baseregex->nparens * 2;
367   st->total_size += strlen(baseregex->precomp);
368 #else
369   st->total_size += sizeof(struct regexp);
370   st->total_size += sizeof(I32) * SvANY(baseregex)->nparens * 2;
371   /*st->total_size += strlen(SvANY(baseregex)->subbeg);*/
372 #endif
373   if (st->go_yell && !st->regex_whine) {
374     carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
375     st->regex_whine = 1;
376   }
377 }
378
379 static void
380 op_size(pTHX_ const OP * const baseop, struct state *st)
381 {
382     TRY_TO_CATCH_SEGV {
383         TAG;
384         if(!check_new(st, baseop))
385             return;
386         TAG;
387         op_size(aTHX_ baseop->op_next, st);
388         TAG;
389         switch (cc_opclass(baseop)) {
390         case OPc_BASEOP: TAG;
391             st->total_size += sizeof(struct op);
392             TAG;break;
393         case OPc_UNOP: TAG;
394             st->total_size += sizeof(struct unop);
395             op_size(aTHX_ cUNOPx(baseop)->op_first, st);
396             TAG;break;
397         case OPc_BINOP: TAG;
398             st->total_size += sizeof(struct binop);
399             op_size(aTHX_ cBINOPx(baseop)->op_first, st);
400             op_size(aTHX_ cBINOPx(baseop)->op_last, st);
401             TAG;break;
402         case OPc_LOGOP: TAG;
403             st->total_size += sizeof(struct logop);
404             op_size(aTHX_ cBINOPx(baseop)->op_first, st);
405             op_size(aTHX_ cLOGOPx(baseop)->op_other, st);
406             TAG;break;
407         case OPc_LISTOP: TAG;
408             st->total_size += sizeof(struct listop);
409             op_size(aTHX_ cLISTOPx(baseop)->op_first, st);
410             op_size(aTHX_ cLISTOPx(baseop)->op_last, st);
411             TAG;break;
412         case OPc_PMOP: TAG;
413             st->total_size += sizeof(struct pmop);
414             op_size(aTHX_ cPMOPx(baseop)->op_first, st);
415             op_size(aTHX_ cPMOPx(baseop)->op_last, st);
416 #if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
417             op_size(aTHX_ cPMOPx(baseop)->op_pmreplroot, st);
418             op_size(aTHX_ cPMOPx(baseop)->op_pmreplstart, st);
419             op_size(aTHX_ (OP *)cPMOPx(baseop)->op_pmnext, st);
420 #endif
421             /* This is defined away in perl 5.8.x, but it is in there for
422                5.6.x */
423 #ifdef PM_GETRE
424             regex_size(PM_GETRE(cPMOPx(baseop)), st);
425 #else
426             regex_size(cPMOPx(baseop)->op_pmregexp, st);
427 #endif
428             TAG;break;
429         case OPc_SVOP: TAG;
430             st->total_size += sizeof(struct pmop);
431             if (!(baseop->op_type == OP_AELEMFAST
432                   && baseop->op_flags & OPf_SPECIAL)) {
433                 /* not an OP_PADAV replacement */
434                 sv_size(aTHX_ st, cSVOPx(baseop)->op_sv, SOME_RECURSION);
435             }
436             TAG;break;
437       case OPc_PADOP: TAG;
438           st->total_size += sizeof(struct padop);
439           TAG;break;
440         case OPc_PVOP: TAG;
441             check_new_and_strlen(st, cPVOPx(baseop)->op_pv);
442             TAG;break;
443         case OPc_LOOP: TAG;
444             st->total_size += sizeof(struct loop);
445             op_size(aTHX_ cLOOPx(baseop)->op_first, st);
446             op_size(aTHX_ cLOOPx(baseop)->op_last, st);
447             op_size(aTHX_ cLOOPx(baseop)->op_redoop, st);
448             op_size(aTHX_ cLOOPx(baseop)->op_nextop, st);
449             op_size(aTHX_ cLOOPx(baseop)->op_lastop, st);
450             TAG;break;
451         case OPc_COP: TAG;
452         {
453           COP *basecop;
454           basecop = (COP *)baseop;
455           st->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           check_new_and_strlen(st, basecop->cop_label);
466 #endif
467 #ifdef USE_ITHREADS
468           check_new_and_strlen(st, basecop->cop_file);
469           check_new_and_strlen(st, basecop->cop_stashpv);
470 #else
471           sv_size(aTHX_ st, (SV *)basecop->cop_stash, SOME_RECURSION);
472           sv_size(aTHX_ st, (SV *)basecop->cop_filegv, SOME_RECURSION);
473 #endif
474
475         }
476         TAG;break;
477       default:
478         TAG;break;
479       }
480   }
481   CAUGHT_EXCEPTION {
482       if (st->dangle_whine) 
483           warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
484   }
485 }
486
487 #if PERL_VERSION < 8 || PERL_SUBVERSION < 9
488 #  define SVt_LAST 16
489 #endif
490
491 #ifdef PURIFY
492 #  define MAYBE_PURIFY(normal, pure) (pure)
493 #  define MAYBE_OFFSET(struct_name, member) 0
494 #else
495 #  define MAYBE_PURIFY(normal, pure) (normal)
496 #  define MAYBE_OFFSET(struct_name, member) STRUCT_OFFSET(struct_name, member)
497 #endif
498
499 const U8 body_sizes[SVt_LAST] = {
500 #if PERL_VERSION < 9
501      0,                                                       /* SVt_NULL */
502      MAYBE_PURIFY(sizeof(IV), sizeof(XPVIV)),                 /* SVt_IV */
503      MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)),                 /* SVt_NV */
504      sizeof(XRV),                                             /* SVt_RV */
505      sizeof(XPV),                                             /* SVt_PV */
506      sizeof(XPVIV),                                           /* SVt_PVIV */
507      sizeof(XPVNV),                                           /* SVt_PVNV */
508      sizeof(XPVMG),                                           /* SVt_PVMG */
509      sizeof(XPVBM),                                           /* SVt_PVBM */
510      sizeof(XPVLV),                                           /* SVt_PVLV */
511      sizeof(XPVAV),                                           /* SVt_PVAV */
512      sizeof(XPVHV),                                           /* SVt_PVHV */
513      sizeof(XPVCV),                                           /* SVt_PVCV */
514      sizeof(XPVGV),                                           /* SVt_PVGV */
515      sizeof(XPVFM),                                           /* SVt_PVFM */
516      sizeof(XPVIO)                                            /* SVt_PVIO */
517 #elif PERL_VERSION == 10 && PERL_SUBVERSION == 0
518      0,                                                       /* SVt_NULL */
519      0,                                                       /* SVt_BIND */
520      0,                                                       /* SVt_IV */
521      MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)),                 /* SVt_NV */
522      0,                                                       /* SVt_RV */
523      MAYBE_PURIFY(sizeof(xpv_allocated), sizeof(XPV)),        /* SVt_PV */
524      MAYBE_PURIFY(sizeof(xpviv_allocated), sizeof(XPVIV)),/* SVt_PVIV */
525      sizeof(XPVNV),                                           /* SVt_PVNV */
526      sizeof(XPVMG),                                           /* SVt_PVMG */
527      sizeof(XPVGV),                                           /* SVt_PVGV */
528      sizeof(XPVLV),                                           /* SVt_PVLV */
529      MAYBE_PURIFY(sizeof(xpvav_allocated), sizeof(XPVAV)),/* SVt_PVAV */
530      MAYBE_PURIFY(sizeof(xpvhv_allocated), sizeof(XPVHV)),/* SVt_PVHV */
531      MAYBE_PURIFY(sizeof(xpvcv_allocated), sizeof(XPVCV)),/* SVt_PVCV */
532      MAYBE_PURIFY(sizeof(xpvfm_allocated), sizeof(XPVFM)),/* SVt_PVFM */
533      sizeof(XPVIO),                                           /* SVt_PVIO */
534 #elif PERL_VERSION == 10 && PERL_SUBVERSION == 1
535      0,                                                       /* SVt_NULL */
536      0,                                                       /* SVt_BIND */
537      0,                                                       /* SVt_IV */
538      MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)),                 /* SVt_NV */
539      0,                                                       /* SVt_RV */
540      sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur),                /* SVt_PV */
541      sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur),              /* SVt_PVIV */
542      sizeof(XPVNV),                                           /* SVt_PVNV */
543      sizeof(XPVMG),                                           /* SVt_PVMG */
544      sizeof(XPVGV),                                           /* SVt_PVGV */
545      sizeof(XPVLV),                                           /* SVt_PVLV */
546      sizeof(XPVAV) - MAYBE_OFFSET(XPVAV, xav_fill),           /* SVt_PVAV */
547      sizeof(XPVHV) - MAYBE_OFFSET(XPVHV, xhv_fill),           /* SVt_PVHV */
548      sizeof(XPVCV) - MAYBE_OFFSET(XPVCV, xpv_cur),            /* SVt_PVCV */
549      sizeof(XPVFM) - MAYBE_OFFSET(XPVFM, xpv_cur),            /* SVt_PVFM */
550      sizeof(XPVIO)                                            /* SVt_PVIO */
551 #elif PERL_VERSION < 13
552      0,                                                       /* SVt_NULL */
553      0,                                                       /* SVt_BIND */
554      0,                                                       /* SVt_IV */
555      MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)),                 /* SVt_NV */
556      sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur),                /* SVt_PV */
557      sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur),              /* SVt_PVIV */
558      sizeof(XPVNV),                                           /* SVt_PVNV */
559      sizeof(XPVMG),                                           /* SVt_PVMG */
560      sizeof(regexp) - MAYBE_OFFSET(regexp, xpv_cur),          /* SVt_REGEXP */
561      sizeof(XPVGV),                                           /* SVt_PVGV */
562      sizeof(XPVLV),                                           /* SVt_PVLV */
563      sizeof(XPVAV) - MAYBE_OFFSET(XPVAV, xav_fill),           /* SVt_PVAV */
564      sizeof(XPVHV) - MAYBE_OFFSET(XPVHV, xhv_fill),           /* SVt_PVHV */
565      sizeof(XPVCV) - MAYBE_OFFSET(XPVCV, xpv_cur),            /* SVt_PVCV */
566      sizeof(XPVFM) - MAYBE_OFFSET(XPVFM, xpv_cur),            /* SVt_PVFM */
567      sizeof(XPVIO)                                            /* SVt_PVIO */
568 #else
569      0,                                                       /* SVt_NULL */
570      0,                                                       /* SVt_BIND */
571      0,                                                       /* SVt_IV */
572      MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)),                 /* SVt_NV */
573      sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur),                /* SVt_PV */
574      sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur),              /* SVt_PVIV */
575      sizeof(XPVNV) - MAYBE_OFFSET(XPV, xpv_cur),              /* SVt_PVNV */
576      sizeof(XPVMG),                                           /* SVt_PVMG */
577      sizeof(regexp),                                          /* SVt_REGEXP */
578      sizeof(XPVGV),                                           /* SVt_PVGV */
579      sizeof(XPVLV),                                           /* SVt_PVLV */
580      sizeof(XPVAV),                                           /* SVt_PVAV */
581      sizeof(XPVHV),                                           /* SVt_PVHV */
582      sizeof(XPVCV),                                           /* SVt_PVCV */
583      sizeof(XPVFM),                                           /* SVt_PVFM */
584      sizeof(XPVIO)                                            /* SVt_PVIO */
585 #endif
586 };
587
588 static bool
589 sv_size(pTHX_ struct state *const st, const SV * const orig_thing,
590         const int recurse) {
591   const SV *thing = orig_thing;
592   U32 type;
593
594   if(!check_new(st, thing))
595       return FALSE;
596
597   type = SvTYPE(thing);
598   if (type > SVt_LAST) {
599       warn("Devel::Size: Unknown variable type: %d encountered\n", type);
600       return TRUE;
601   }
602   st->total_size += sizeof(SV) + body_sizes[type];
603
604   if (type >= SVt_PVMG) {
605       magic_size(aTHX_ thing, st);
606   }
607
608   switch (type) {
609 #if (PERL_VERSION < 11)
610     /* Is it a reference? */
611   case SVt_RV: TAG;
612 #else
613   case SVt_IV: TAG;
614 #endif
615     if(recurse && SvROK(thing))
616         sv_size(aTHX_ st, SvRV_const(thing), recurse);
617     TAG;break;
618
619   case SVt_PVAV: TAG;
620     /* Is there anything in the array? */
621     if (AvMAX(thing) != -1) {
622       /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
623       st->total_size += sizeof(SV *) * (AvMAX(thing) + 1);
624       dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
625
626       if (recurse >= TOTAL_SIZE_RECURSION) {
627           SSize_t i = AvFILLp(thing) + 1;
628
629           while (i--)
630               sv_size(aTHX_ st, AvARRAY(thing)[i], recurse);
631       }
632     }
633     /* Add in the bits on the other side of the beginning */
634
635     dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n", 
636     st->total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
637
638     /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
639        resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
640     if (AvALLOC(thing) != 0) {
641       st->total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
642       }
643 #if (PERL_VERSION < 9)
644     /* Is there something hanging off the arylen element?
645        Post 5.9.something this is stored in magic, so will be found there,
646        and Perl_av_arylen_p() takes a non-const AV*, hence compilers rightly
647        complain about AvARYLEN() passing thing to it.  */
648     sv_size(aTHX_ st, AvARYLEN(thing), recurse);
649 #endif
650     TAG;break;
651   case SVt_PVHV: TAG;
652     /* Now the array of buckets */
653     st->total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
654     /* Now walk the bucket chain */
655     if (HvARRAY(thing)) {
656       HE *cur_entry;
657       UV cur_bucket = 0;
658       for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
659         cur_entry = *(HvARRAY(thing) + cur_bucket);
660         while (cur_entry) {
661           st->total_size += sizeof(HE);
662           if (cur_entry->hent_hek) {
663             /* Hash keys can be shared. Have we seen this before? */
664             if (check_new(st, cur_entry->hent_hek)) {
665               st->total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
666             }
667           }
668           if (recurse >= TOTAL_SIZE_RECURSION)
669               sv_size(aTHX_ st, HeVAL(cur_entry), recurse);
670           cur_entry = cur_entry->hent_next;
671         }
672       }
673     }
674     TAG;break;
675
676
677   case SVt_PVFM: TAG;
678     sv_size(aTHX_ st, (SV *)CvPADLIST(thing), SOME_RECURSION);
679     sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), recurse);
680
681     if (st->go_yell && !st->fm_whine) {
682       carp("Devel::Size: Calculated sizes for FMs are incomplete");
683       st->fm_whine = 1;
684     }
685     goto freescalar;
686
687   case SVt_PVCV: TAG;
688     sv_size(aTHX_ st, (SV *)CvSTASH(thing), SOME_RECURSION);
689     sv_size(aTHX_ st, (SV *)SvSTASH(thing), SOME_RECURSION);
690     sv_size(aTHX_ st, (SV *)CvGV(thing), SOME_RECURSION);
691     sv_size(aTHX_ st, (SV *)CvPADLIST(thing), SOME_RECURSION);
692     sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), recurse);
693     if (CvISXSUB(thing)) {
694         sv_size(aTHX_ st, cv_const_sv((CV *)thing), recurse);
695     } else {
696         op_size(aTHX_ CvSTART(thing), st);
697         op_size(aTHX_ CvROOT(thing), st);
698     }
699     goto freescalar;
700
701   case SVt_PVIO: TAG;
702     /* Some embedded char pointers */
703     check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_top_name);
704     check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_fmt_name);
705     check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_bottom_name);
706     /* Throw the GVs on the list to be walked if they're not-null */
707     sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_top_gv, recurse);
708     sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv, recurse);
709     sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv, recurse);
710
711     /* Only go trotting through the IO structures if they're really
712        trottable. If USE_PERLIO is defined we can do this. If
713        not... we can't, so we don't even try */
714 #ifdef USE_PERLIO
715     /* Dig into xio_ifp and xio_ofp here */
716     warn("Devel::Size: Can't size up perlio layers yet\n");
717 #endif
718     goto freescalar;
719
720   case SVt_PVLV: TAG;
721 #if (PERL_VERSION < 9)
722     goto freescalar;
723 #endif
724
725   case SVt_PVGV: TAG;
726     if(isGV_with_GP(thing)) {
727         st->total_size += GvNAMELEN(thing);
728 #ifdef GvFILE
729 #  if !defined(USE_ITHREADS) || (PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8))
730         /* With itreads, before 5.8.9, this can end up pointing to freed memory
731            if the GV was created in an eval, as GvFILE() points to CopFILE(),
732            and the relevant COP has been freed on scope cleanup after the eval.
733            5.8.9 adds a binary compatible fudge that catches the vast majority
734            of cases. 5.9.something added a proper fix, by converting the GP to
735            use a shared hash key (porperly reference counted), instead of a
736            char * (owned by who knows? possibly no-one now) */
737         check_new_and_strlen(st, GvFILE(thing));
738 #  endif
739 #endif
740         /* Is there something hanging off the glob? */
741         if (check_new(st, GvGP(thing))) {
742             st->total_size += sizeof(GP);
743             sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_sv), recurse);
744             sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_form), recurse);
745             sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_av), recurse);
746             sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_hv), recurse);
747             sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_egv), recurse);
748             sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_cv), recurse);
749         }
750 #if (PERL_VERSION >= 9)
751         TAG; break;
752 #endif
753     }
754 #if PERL_VERSION <= 8
755   case SVt_PVBM: TAG;
756 #endif
757   case SVt_PVMG: TAG;
758   case SVt_PVNV: TAG;
759   case SVt_PVIV: TAG;
760   case SVt_PV: TAG;
761   freescalar:
762     if(recurse && SvROK(thing))
763         sv_size(aTHX_ st, SvRV_const(thing), recurse);
764     else
765         st->total_size += SvLEN(thing);
766
767     if(SvOOK(thing)) {
768         st->total_size += SvIVX(thing);
769     }
770     TAG;break;
771
772   }
773   return TRUE;
774 }
775
776 /* Frustratingly, the vtables aren't const in perl.h
777    gcc is happy enough to have non-const initialisers in a static array.
778    VC seems not to be. (Is it actually treating the file as C++?)
779    So do the maximally portable thing, unless we know it's gcc, in which case
780    we can do the more space efficient version.  */
781
782 #if __GNUC__
783 void *vtables[] = {
784 #include "vtables.inc"
785     NULL
786 };
787 #endif
788
789 static struct state *
790 new_state(pTHX)
791 {
792     SV *warn_flag;
793     struct state *st;
794 #if __GNUC__
795     void **vt_p = vtables;
796 #endif
797
798     Newxz(st, 1, struct state);
799     st->go_yell = TRUE;
800     if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
801         st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
802     }
803     if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
804         st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
805     }
806     check_new(st, &PL_sv_undef);
807     check_new(st, &PL_sv_no);
808     check_new(st, &PL_sv_yes);
809 #if __GNUC__
810     while(*vt_p)
811         check_new(st, *vt_p++);
812 #else
813 #include "vtables.inc"
814 #endif
815     return st;
816 }
817
818 MODULE = Devel::Size        PACKAGE = Devel::Size       
819
820 PROTOTYPES: DISABLE
821
822 UV
823 size(orig_thing)
824      SV *orig_thing
825 ALIAS:
826     total_size = TOTAL_SIZE_RECURSION
827 CODE:
828 {
829   SV *thing = orig_thing;
830   struct state *st = new_state(aTHX);
831   
832   /* If they passed us a reference then dereference it. This is the
833      only way we can check the sizes of arrays and hashes */
834   if (SvROK(thing)) {
835     thing = SvRV(thing);
836   }
837
838   sv_size(aTHX_ st, thing, ix);
839   RETVAL = st->total_size;
840   free_state(st);
841 }
842 OUTPUT:
843   RETVAL