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