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