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