Add the size of mg_len if mg_ptr is non-NULL.
[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
b7130948 314magic_size(pTHX_ 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 }
b7130948 335 sv_size(aTHX_ st, magic_pointer->mg_obj, TOTAL_SIZE_RECURSION);
d1888d0b 336 if (magic_pointer->mg_len == HEf_SVKEY) {
337 sv_size(aTHX_ st, (SV *)magic_pointer->mg_ptr, TOTAL_SIZE_RECURSION);
338 }
339#if defined(PERL_MAGIC_utf8) && defined (PERL_MAGIC_UTF8_CACHESIZE)
340 else if (magic_pointer->mg_type == PERL_MAGIC_utf8) {
341 if (check_new(st, magic_pointer->mg_ptr)) {
342 st->total_size += PERL_MAGIC_UTF8_CACHESIZE * 2 * sizeof(STRLEN);
343 }
344 }
345#endif
346 else if (magic_pointer->mg_len > 0) {
347 if (check_new(st, magic_pointer->mg_ptr)) {
348 st->total_size += magic_pointer->mg_len;
349 }
350 }
6a9ad7ec 351
0964064b 352 /* Get the next in the chain */
9fc9ab86 353 magic_pointer = magic_pointer->mg_moremagic;
354 }
1a36ac09 355 CAUGHT_EXCEPTION {
a4efdff3 356 if (st->dangle_whine)
9fc9ab86 357 warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
358 }
6a9ad7ec 359 }
6a9ad7ec 360}
361
eee00145 362static void
99684fd4 363check_new_and_strlen(struct state *st, const char *const p) {
364 if(check_new(st, p))
6ec51ae0 365 st->total_size += 1 + strlen(p);
99684fd4 366}
367
368static void
eee00145 369regex_size(const REGEXP * const baseregex, struct state *st) {
c1bfd7da 370 if(!check_new(st, baseregex))
371 return;
eee00145 372 st->total_size += sizeof(REGEXP);
9fc9ab86 373#if (PERL_VERSION < 11)
6ea94d90 374 /* Note the size of the paren offset thing */
eee00145 375 st->total_size += sizeof(I32) * baseregex->nparens * 2;
376 st->total_size += strlen(baseregex->precomp);
6ea94d90 377#else
eee00145 378 st->total_size += sizeof(struct regexp);
379 st->total_size += sizeof(I32) * SvANY(baseregex)->nparens * 2;
380 /*st->total_size += strlen(SvANY(baseregex)->subbeg);*/
6ea94d90 381#endif
a4efdff3 382 if (st->go_yell && !st->regex_whine) {
6ea94d90 383 carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
a4efdff3 384 st->regex_whine = 1;
98ecbbc6 385 }
7ccc7d88 386}
387
eee00145 388static void
1e5a8ad2 389op_size(pTHX_ const OP * const baseop, struct state *st)
390{
391 TRY_TO_CATCH_SEGV {
392 TAG;
393 if(!check_new(st, baseop))
394 return;
395 TAG;
396 op_size(aTHX_ baseop->op_next, st);
397 TAG;
398 switch (cc_opclass(baseop)) {
399 case OPc_BASEOP: TAG;
400 st->total_size += sizeof(struct op);
401 TAG;break;
402 case OPc_UNOP: TAG;
403 st->total_size += sizeof(struct unop);
404 op_size(aTHX_ cUNOPx(baseop)->op_first, st);
405 TAG;break;
406 case OPc_BINOP: TAG;
407 st->total_size += sizeof(struct binop);
408 op_size(aTHX_ cBINOPx(baseop)->op_first, st);
409 op_size(aTHX_ cBINOPx(baseop)->op_last, st);
410 TAG;break;
411 case OPc_LOGOP: TAG;
412 st->total_size += sizeof(struct logop);
413 op_size(aTHX_ cBINOPx(baseop)->op_first, st);
414 op_size(aTHX_ cLOGOPx(baseop)->op_other, st);
415 TAG;break;
416 case OPc_LISTOP: TAG;
417 st->total_size += sizeof(struct listop);
418 op_size(aTHX_ cLISTOPx(baseop)->op_first, st);
419 op_size(aTHX_ cLISTOPx(baseop)->op_last, st);
420 TAG;break;
421 case OPc_PMOP: TAG;
422 st->total_size += sizeof(struct pmop);
423 op_size(aTHX_ cPMOPx(baseop)->op_first, st);
424 op_size(aTHX_ cPMOPx(baseop)->op_last, st);
5a83b7cf 425#if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
1e5a8ad2 426 op_size(aTHX_ cPMOPx(baseop)->op_pmreplroot, st);
427 op_size(aTHX_ cPMOPx(baseop)->op_pmreplstart, st);
428 op_size(aTHX_ (OP *)cPMOPx(baseop)->op_pmnext, st);
5a83b7cf 429#endif
c1bfd7da 430 /* This is defined away in perl 5.8.x, but it is in there for
431 5.6.x */
98ecbbc6 432#ifdef PM_GETRE
c1bfd7da 433 regex_size(PM_GETRE(cPMOPx(baseop)), st);
98ecbbc6 434#else
c1bfd7da 435 regex_size(cPMOPx(baseop)->op_pmregexp, st);
98ecbbc6 436#endif
c1bfd7da 437 TAG;break;
81f1c018 438 case OPc_SVOP: TAG;
439 st->total_size += sizeof(struct pmop);
574d9fd9 440 if (!(baseop->op_type == OP_AELEMFAST
441 && baseop->op_flags & OPf_SPECIAL)) {
442 /* not an OP_PADAV replacement */
f3cf7e20 443 sv_size(aTHX_ st, cSVOPx(baseop)->op_sv, SOME_RECURSION);
574d9fd9 444 }
81f1c018 445 TAG;break;
9fc9ab86 446 case OPc_PADOP: TAG;
eee00145 447 st->total_size += sizeof(struct padop);
99684fd4 448 TAG;break;
449 case OPc_PVOP: TAG;
450 check_new_and_strlen(st, cPVOPx(baseop)->op_pv);
219b7d34 451 TAG;break;
1e5a8ad2 452 case OPc_LOOP: TAG;
453 st->total_size += sizeof(struct loop);
454 op_size(aTHX_ cLOOPx(baseop)->op_first, st);
455 op_size(aTHX_ cLOOPx(baseop)->op_last, st);
456 op_size(aTHX_ cLOOPx(baseop)->op_redoop, st);
457 op_size(aTHX_ cLOOPx(baseop)->op_nextop, st);
458 op_size(aTHX_ cLOOPx(baseop)->op_lastop, st);
459 TAG;break;
460 case OPc_COP: TAG;
9fc9ab86 461 {
462 COP *basecop;
463 basecop = (COP *)baseop;
eee00145 464 st->total_size += sizeof(struct cop);
9fc9ab86 465
466 /* Change 33656 by nicholas@mouse-mill on 2008/04/07 11:29:51
467 Eliminate cop_label from struct cop by storing a label as the first
468 entry in the hints hash. Most statements don't have labels, so this
469 will save memory. Not sure how much.
470 The check below will be incorrect fail on bleadperls
471 before 5.11 @33656, but later than 5.10, producing slightly too
472 small memory sizes on these Perls. */
b7621729 473#if (PERL_VERSION < 11)
99684fd4 474 check_new_and_strlen(st, basecop->cop_label);
b7621729 475#endif
7ccc7d88 476#ifdef USE_ITHREADS
99684fd4 477 check_new_and_strlen(st, basecop->cop_file);
478 check_new_and_strlen(st, basecop->cop_stashpv);
7ccc7d88 479#else
f3cf7e20 480 sv_size(aTHX_ st, (SV *)basecop->cop_stash, SOME_RECURSION);
481 sv_size(aTHX_ st, (SV *)basecop->cop_filegv, SOME_RECURSION);
7ccc7d88 482#endif
483
9fc9ab86 484 }
485 TAG;break;
486 default:
487 TAG;break;
488 }
489 }
1a36ac09 490 CAUGHT_EXCEPTION {
a4efdff3 491 if (st->dangle_whine)
9fc9ab86 492 warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
7ccc7d88 493 }
7ccc7d88 494}
6a9ad7ec 495
24d37977 496#if PERL_VERSION > 9 || (PERL_VERSION == 9 && PERL_SUBVERSION > 2)
497# define NEW_HEAD_LAYOUT
498#endif
499
81f1c018 500static bool
db519f11 501sv_size(pTHX_ struct state *const st, const SV * const orig_thing,
f3cf7e20 502 const int recurse) {
9fc9ab86 503 const SV *thing = orig_thing;
eee00145 504
81f1c018 505 if(!check_new(st, thing))
506 return FALSE;
507
eee00145 508 st->total_size += sizeof(SV);
b1e5ad85 509
e98cedbf 510 switch (SvTYPE(thing)) {
511 /* Is it undef? */
9fc9ab86 512 case SVt_NULL: TAG;
513 TAG;break;
e98cedbf 514 /* Just a plain integer. This will be differently sized depending
515 on whether purify's been compiled in */
9fc9ab86 516 case SVt_IV: TAG;
24d37977 517#ifndef NEW_HEAD_LAYOUT
518# ifdef PURIFY
eee00145 519 st->total_size += sizeof(sizeof(XPVIV));
24d37977 520# else
eee00145 521 st->total_size += sizeof(IV);
24d37977 522# endif
e98cedbf 523#endif
81f1c018 524 if(recurse && SvROK(thing))
f3cf7e20 525 sv_size(aTHX_ st, SvRV_const(thing), recurse);
9fc9ab86 526 TAG;break;
e98cedbf 527 /* Is it a float? Like the int, it depends on purify */
9fc9ab86 528 case SVt_NV: TAG;
e98cedbf 529#ifdef PURIFY
eee00145 530 st->total_size += sizeof(sizeof(XPVNV));
e98cedbf 531#else
eee00145 532 st->total_size += sizeof(NV);
e98cedbf 533#endif
9fc9ab86 534 TAG;break;
535#if (PERL_VERSION < 11)
e98cedbf 536 /* Is it a reference? */
9fc9ab86 537 case SVt_RV: TAG;
24d37977 538#ifndef NEW_HEAD_LAYOUT
eee00145 539 st->total_size += sizeof(XRV);
24d37977 540#endif
81f1c018 541 if(recurse && SvROK(thing))
f3cf7e20 542 sv_size(aTHX_ st, SvRV_const(thing), recurse);
9fc9ab86 543 TAG;break;
6ea94d90 544#endif
e98cedbf 545 /* How about a plain string? In which case we need to add in how
546 much has been allocated */
9fc9ab86 547 case SVt_PV: TAG;
eee00145 548 st->total_size += sizeof(XPV);
db519f11 549 if(recurse && SvROK(thing))
f3cf7e20 550 sv_size(aTHX_ st, SvRV_const(thing), recurse);
eee00145 551 else
552 st->total_size += SvLEN(thing);
9fc9ab86 553 TAG;break;
e98cedbf 554 /* A string with an integer part? */
9fc9ab86 555 case SVt_PVIV: TAG;
eee00145 556 st->total_size += sizeof(XPVIV);
db519f11 557 if(recurse && SvROK(thing))
f3cf7e20 558 sv_size(aTHX_ st, SvRV_const(thing), recurse);
eee00145 559 else
560 st->total_size += SvLEN(thing);
0430b7f7 561 if(SvOOK(thing)) {
eee00145 562 st->total_size += SvIVX(thing);
9fc9ab86 563 }
564 TAG;break;
c8db37d3 565 /* A scalar/string/reference with a float part? */
9fc9ab86 566 case SVt_PVNV: TAG;
eee00145 567 st->total_size += sizeof(XPVNV);
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);
9fc9ab86 572 TAG;break;
573 case SVt_PVMG: TAG;
eee00145 574 st->total_size += sizeof(XPVMG);
db519f11 575 if(recurse && SvROK(thing))
f3cf7e20 576 sv_size(aTHX_ st, SvRV_const(thing), recurse);
eee00145 577 else
578 st->total_size += SvLEN(thing);
b7130948 579 magic_size(aTHX_ thing, st);
9fc9ab86 580 TAG;break;
0430b7f7 581#if PERL_VERSION <= 8
9fc9ab86 582 case SVt_PVBM: TAG;
eee00145 583 st->total_size += sizeof(XPVBM);
db519f11 584 if(recurse && SvROK(thing))
f3cf7e20 585 sv_size(aTHX_ st, SvRV_const(thing), recurse);
eee00145 586 else
587 st->total_size += SvLEN(thing);
b7130948 588 magic_size(aTHX_ thing, st);
9fc9ab86 589 TAG;break;
0430b7f7 590#endif
9fc9ab86 591 case SVt_PVLV: TAG;
eee00145 592 st->total_size += sizeof(XPVLV);
db519f11 593 if(recurse && SvROK(thing))
f3cf7e20 594 sv_size(aTHX_ st, SvRV_const(thing), recurse);
eee00145 595 else
596 st->total_size += SvLEN(thing);
b7130948 597 magic_size(aTHX_ thing, st);
9fc9ab86 598 TAG;break;
e98cedbf 599 /* How much space is dedicated to the array? Not counting the
600 elements in the array, mind, just the array itself */
9fc9ab86 601 case SVt_PVAV: TAG;
eee00145 602 st->total_size += sizeof(XPVAV);
e98cedbf 603 /* Is there anything in the array? */
604 if (AvMAX(thing) != -1) {
c8db37d3 605 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
eee00145 606 st->total_size += sizeof(SV *) * (AvMAX(thing) + 1);
607 dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
6c5ddc0d 608
609 if (recurse >= TOTAL_SIZE_RECURSION) {
610 SSize_t i = AvFILLp(thing) + 1;
611
612 while (i--)
613 sv_size(aTHX_ st, AvARRAY(thing)[i], recurse);
614 }
e98cedbf 615 }
616 /* Add in the bits on the other side of the beginning */
0430b7f7 617
b7621729 618 dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
eee00145 619 st->total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
0430b7f7 620
621 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
b1e5ad85 622 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
0430b7f7 623 if (AvALLOC(thing) != 0) {
eee00145 624 st->total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
0430b7f7 625 }
795fc84c 626#if (PERL_VERSION < 9)
627 /* Is there something hanging off the arylen element?
628 Post 5.9.something this is stored in magic, so will be found there,
629 and Perl_av_arylen_p() takes a non-const AV*, hence compilers rightly
630 complain about AvARYLEN() passing thing to it. */
f3cf7e20 631 sv_size(aTHX_ st, AvARYLEN(thing), recurse);
795fc84c 632#endif
b7130948 633 magic_size(aTHX_ thing, st);
9fc9ab86 634 TAG;break;
635 case SVt_PVHV: TAG;
a6ea0805 636 /* First the base struct */
eee00145 637 st->total_size += sizeof(XPVHV);
a6ea0805 638 /* Now the array of buckets */
eee00145 639 st->total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
a6ea0805 640 /* Now walk the bucket chain */
6a9ad7ec 641 if (HvARRAY(thing)) {
a6ea0805 642 HE *cur_entry;
9fc9ab86 643 UV cur_bucket = 0;
a6ea0805 644 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
9fc9ab86 645 cur_entry = *(HvARRAY(thing) + cur_bucket);
646 while (cur_entry) {
eee00145 647 st->total_size += sizeof(HE);
9fc9ab86 648 if (cur_entry->hent_hek) {
649 /* Hash keys can be shared. Have we seen this before? */
a4efdff3 650 if (check_new(st, cur_entry->hent_hek)) {
eee00145 651 st->total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
9fc9ab86 652 }
653 }
f3cf7e20 654 if (recurse >= TOTAL_SIZE_RECURSION)
655 sv_size(aTHX_ st, HeVAL(cur_entry), recurse);
9fc9ab86 656 cur_entry = cur_entry->hent_next;
657 }
a6ea0805 658 }
659 }
b7130948 660 magic_size(aTHX_ thing, st);
9fc9ab86 661 TAG;break;
662 case SVt_PVCV: TAG;
eee00145 663 st->total_size += sizeof(XPVCV);
b7130948 664 magic_size(aTHX_ thing, st);
7ccc7d88 665
eee00145 666 st->total_size += ((XPVIO *) SvANY(thing))->xpv_len;
f3cf7e20 667 sv_size(aTHX_ st, (SV *)CvSTASH(thing), SOME_RECURSION);
668 sv_size(aTHX_ st, (SV *)SvSTASH(thing), SOME_RECURSION);
669 sv_size(aTHX_ st, (SV *)CvGV(thing), SOME_RECURSION);
6c5ddc0d 670 sv_size(aTHX_ st, (SV *)CvPADLIST(thing), SOME_RECURSION);
f3cf7e20 671 sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), recurse);
66f50dda 672 if (CvISXSUB(thing)) {
f3cf7e20 673 sv_size(aTHX_ st, cv_const_sv((CV *)thing), recurse);
66f50dda 674 } else {
1e5a8ad2 675 op_size(aTHX_ CvSTART(thing), st);
676 op_size(aTHX_ CvROOT(thing), st);
7ccc7d88 677 }
678
9fc9ab86 679 TAG;break;
680 case SVt_PVGV: TAG;
b7130948 681 magic_size(aTHX_ thing, st);
eee00145 682 st->total_size += sizeof(XPVGV);
4a3d023d 683 if(isGV_with_GP(thing)) {
684 st->total_size += GvNAMELEN(thing);
78dfb4e7 685#ifdef GvFILE
2b217e71 686# if !defined(USE_ITHREADS) || (PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8))
687 /* With itreads, before 5.8.9, this can end up pointing to freed memory
688 if the GV was created in an eval, as GvFILE() points to CopFILE(),
689 and the relevant COP has been freed on scope cleanup after the eval.
690 5.8.9 adds a binary compatible fudge that catches the vast majority
691 of cases. 5.9.something added a proper fix, by converting the GP to
692 use a shared hash key (porperly reference counted), instead of a
693 char * (owned by who knows? possibly no-one now) */
4a3d023d 694 check_new_and_strlen(st, GvFILE(thing));
2b217e71 695# endif
78dfb4e7 696#endif
4a3d023d 697 /* Is there something hanging off the glob? */
698 if (check_new(st, GvGP(thing))) {
699 st->total_size += sizeof(GP);
f3cf7e20 700 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_sv), recurse);
701 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_form), recurse);
702 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_av), recurse);
703 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_hv), recurse);
704 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_egv), recurse);
705 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_cv), recurse);
4a3d023d 706 }
5c2e1b12 707 }
9fc9ab86 708 TAG;break;
709 case SVt_PVFM: TAG;
eee00145 710 st->total_size += sizeof(XPVFM);
b7130948 711 magic_size(aTHX_ thing, st);
eee00145 712 st->total_size += ((XPVIO *) SvANY(thing))->xpv_len;
6c5ddc0d 713 sv_size(aTHX_ st, (SV *)CvPADLIST(thing), SOME_RECURSION);
f3cf7e20 714 sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), recurse);
7ccc7d88 715
a4efdff3 716 if (st->go_yell && !st->fm_whine) {
5073b933 717 carp("Devel::Size: Calculated sizes for FMs are incomplete");
a4efdff3 718 st->fm_whine = 1;
ebb2c5b9 719 }
9fc9ab86 720 TAG;break;
721 case SVt_PVIO: TAG;
eee00145 722 st->total_size += sizeof(XPVIO);
b7130948 723 magic_size(aTHX_ thing, st);
a4efdff3 724 if (check_new(st, (SvPVX_const(thing)))) {
eee00145 725 st->total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
ebb2c5b9 726 }
5073b933 727 /* Some embedded char pointers */
99684fd4 728 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_top_name);
729 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_fmt_name);
730 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_bottom_name);
5073b933 731 /* Throw the GVs on the list to be walked if they're not-null */
f3cf7e20 732 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_top_gv, recurse);
733 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv, recurse);
734 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv, recurse);
5073b933 735
736 /* Only go trotting through the IO structures if they're really
737 trottable. If USE_PERLIO is defined we can do this. If
738 not... we can't, so we don't even try */
739#ifdef USE_PERLIO
740 /* Dig into xio_ifp and xio_ofp here */
9fc9ab86 741 warn("Devel::Size: Can't size up perlio layers yet\n");
5073b933 742#endif
9fc9ab86 743 TAG;break;
e98cedbf 744 default:
9fc9ab86 745 warn("Devel::Size: Unknown variable type: %d encountered\n", SvTYPE(thing) );
e98cedbf 746 }
81f1c018 747 return TRUE;
e98cedbf 748}
749
d9b022a1 750void *vtables[] = {
751#include "vtables.inc"
752 NULL
753};
754
a4efdff3 755static struct state *
756new_state(pTHX)
65db36c0 757{
758 SV *warn_flag;
a4efdff3 759 struct state *st;
d9b022a1 760 void **vt_p = vtables;
761
a4efdff3 762 Newxz(st, 1, struct state);
763 st->go_yell = TRUE;
65db36c0 764 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
a4efdff3 765 st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 766 }
767 if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
a4efdff3 768 st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 769 }
a52ceccd 770 check_new(st, &PL_sv_undef);
771 check_new(st, &PL_sv_no);
772 check_new(st, &PL_sv_yes);
d9b022a1 773 while(*vt_p)
774 check_new(st, *vt_p++);
a4efdff3 775 return st;
65db36c0 776}
777
9fc9ab86 778MODULE = Devel::Size PACKAGE = Devel::Size
e98cedbf 779
fea63ffa 780PROTOTYPES: DISABLE
781
eee00145 782UV
a6ea0805 783size(orig_thing)
784 SV *orig_thing
13683e3a 785ALIAS:
786 total_size = TOTAL_SIZE_RECURSION
e98cedbf 787CODE:
788{
6a9ad7ec 789 SV *thing = orig_thing;
a4efdff3 790 struct state *st = new_state(aTHX);
ebb2c5b9 791
6a9ad7ec 792 /* If they passed us a reference then dereference it. This is the
793 only way we can check the sizes of arrays and hashes */
b7621729 794 if (SvROK(thing)) {
795 thing = SvRV(thing);
796 }
b7621729 797
13683e3a 798 sv_size(aTHX_ st, thing, ix);
eee00145 799 RETVAL = st->total_size;
a4efdff3 800 free_state(st);
6a9ad7ec 801}
802OUTPUT:
803 RETVAL