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