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