Add tests for subroutines and subroutine references.
[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
81f1c018 163static bool sv_size(pTHX_ struct state *, const SV *const, bool recurse);
db519f11 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))
6ec51ae0 336 st->total_size += 1 + strlen(p);
99684fd4 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;
81f1c018 409 case OPc_SVOP: TAG;
410 st->total_size += sizeof(struct pmop);
db519f11 411 sv_size(aTHX_ st, cSVOPx(baseop)->op_sv, TRUE);
81f1c018 412 TAG;break;
9fc9ab86 413 case OPc_PADOP: TAG;
eee00145 414 st->total_size += sizeof(struct padop);
99684fd4 415 TAG;break;
416 case OPc_PVOP: TAG;
417 check_new_and_strlen(st, cPVOPx(baseop)->op_pv);
1e5a8ad2 418 case OPc_LOOP: TAG;
419 st->total_size += sizeof(struct loop);
420 op_size(aTHX_ cLOOPx(baseop)->op_first, st);
421 op_size(aTHX_ cLOOPx(baseop)->op_last, st);
422 op_size(aTHX_ cLOOPx(baseop)->op_redoop, st);
423 op_size(aTHX_ cLOOPx(baseop)->op_nextop, st);
424 op_size(aTHX_ cLOOPx(baseop)->op_lastop, st);
425 TAG;break;
426 case OPc_COP: TAG;
9fc9ab86 427 {
428 COP *basecop;
429 basecop = (COP *)baseop;
eee00145 430 st->total_size += sizeof(struct cop);
9fc9ab86 431
432 /* Change 33656 by nicholas@mouse-mill on 2008/04/07 11:29:51
433 Eliminate cop_label from struct cop by storing a label as the first
434 entry in the hints hash. Most statements don't have labels, so this
435 will save memory. Not sure how much.
436 The check below will be incorrect fail on bleadperls
437 before 5.11 @33656, but later than 5.10, producing slightly too
438 small memory sizes on these Perls. */
b7621729 439#if (PERL_VERSION < 11)
99684fd4 440 check_new_and_strlen(st, basecop->cop_label);
b7621729 441#endif
7ccc7d88 442#ifdef USE_ITHREADS
99684fd4 443 check_new_and_strlen(st, basecop->cop_file);
444 check_new_and_strlen(st, basecop->cop_stashpv);
7ccc7d88 445#else
81f1c018 446 sv_size(aTHX_ st, (SV *)basecop->cop_stash, TRUE);
447 sv_size(aTHX_ st, (SV *)basecop->cop_filegv, TRUE);
7ccc7d88 448#endif
449
9fc9ab86 450 }
451 TAG;break;
452 default:
453 TAG;break;
454 }
455 }
1a36ac09 456 CAUGHT_EXCEPTION {
a4efdff3 457 if (st->dangle_whine)
9fc9ab86 458 warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
7ccc7d88 459 }
7ccc7d88 460}
6a9ad7ec 461
24d37977 462#if PERL_VERSION > 9 || (PERL_VERSION == 9 && PERL_SUBVERSION > 2)
463# define NEW_HEAD_LAYOUT
464#endif
465
81f1c018 466static bool
db519f11 467sv_size(pTHX_ struct state *const st, const SV * const orig_thing,
468 const bool recurse) {
9fc9ab86 469 const SV *thing = orig_thing;
eee00145 470
81f1c018 471 if(!check_new(st, thing))
472 return FALSE;
473
eee00145 474 st->total_size += sizeof(SV);
b1e5ad85 475
e98cedbf 476 switch (SvTYPE(thing)) {
477 /* Is it undef? */
9fc9ab86 478 case SVt_NULL: TAG;
479 TAG;break;
e98cedbf 480 /* Just a plain integer. This will be differently sized depending
481 on whether purify's been compiled in */
9fc9ab86 482 case SVt_IV: TAG;
24d37977 483#ifndef NEW_HEAD_LAYOUT
484# ifdef PURIFY
eee00145 485 st->total_size += sizeof(sizeof(XPVIV));
24d37977 486# else
eee00145 487 st->total_size += sizeof(IV);
24d37977 488# endif
e98cedbf 489#endif
81f1c018 490 if(recurse && SvROK(thing))
491 sv_size(aTHX_ st, SvRV_const(thing), TRUE);
9fc9ab86 492 TAG;break;
e98cedbf 493 /* Is it a float? Like the int, it depends on purify */
9fc9ab86 494 case SVt_NV: TAG;
e98cedbf 495#ifdef PURIFY
eee00145 496 st->total_size += sizeof(sizeof(XPVNV));
e98cedbf 497#else
eee00145 498 st->total_size += sizeof(NV);
e98cedbf 499#endif
9fc9ab86 500 TAG;break;
501#if (PERL_VERSION < 11)
e98cedbf 502 /* Is it a reference? */
9fc9ab86 503 case SVt_RV: TAG;
24d37977 504#ifndef NEW_HEAD_LAYOUT
eee00145 505 st->total_size += sizeof(XRV);
24d37977 506#endif
81f1c018 507 if(recurse && SvROK(thing))
508 sv_size(aTHX_ st, SvRV_const(thing), TRUE);
9fc9ab86 509 TAG;break;
6ea94d90 510#endif
e98cedbf 511 /* How about a plain string? In which case we need to add in how
512 much has been allocated */
9fc9ab86 513 case SVt_PV: TAG;
eee00145 514 st->total_size += sizeof(XPV);
db519f11 515 if(recurse && SvROK(thing))
516 sv_size(aTHX_ st, SvRV_const(thing), TRUE);
eee00145 517 else
518 st->total_size += SvLEN(thing);
9fc9ab86 519 TAG;break;
e98cedbf 520 /* A string with an integer part? */
9fc9ab86 521 case SVt_PVIV: TAG;
eee00145 522 st->total_size += sizeof(XPVIV);
db519f11 523 if(recurse && SvROK(thing))
524 sv_size(aTHX_ st, SvRV_const(thing), TRUE);
eee00145 525 else
526 st->total_size += SvLEN(thing);
0430b7f7 527 if(SvOOK(thing)) {
eee00145 528 st->total_size += SvIVX(thing);
9fc9ab86 529 }
530 TAG;break;
c8db37d3 531 /* A scalar/string/reference with a float part? */
9fc9ab86 532 case SVt_PVNV: TAG;
eee00145 533 st->total_size += sizeof(XPVNV);
db519f11 534 if(recurse && SvROK(thing))
535 sv_size(aTHX_ st, SvRV_const(thing), TRUE);
eee00145 536 else
537 st->total_size += SvLEN(thing);
9fc9ab86 538 TAG;break;
539 case SVt_PVMG: TAG;
eee00145 540 st->total_size += sizeof(XPVMG);
db519f11 541 if(recurse && SvROK(thing))
542 sv_size(aTHX_ st, SvRV_const(thing), TRUE);
eee00145 543 else
544 st->total_size += SvLEN(thing);
545 magic_size(thing, st);
9fc9ab86 546 TAG;break;
0430b7f7 547#if PERL_VERSION <= 8
9fc9ab86 548 case SVt_PVBM: TAG;
eee00145 549 st->total_size += sizeof(XPVBM);
db519f11 550 if(recurse && SvROK(thing))
551 sv_size(aTHX_ st, SvRV_const(thing), TRUE);
eee00145 552 else
553 st->total_size += SvLEN(thing);
554 magic_size(thing, st);
9fc9ab86 555 TAG;break;
0430b7f7 556#endif
9fc9ab86 557 case SVt_PVLV: TAG;
eee00145 558 st->total_size += sizeof(XPVLV);
db519f11 559 if(recurse && SvROK(thing))
560 sv_size(aTHX_ st, SvRV_const(thing), TRUE);
eee00145 561 else
562 st->total_size += SvLEN(thing);
563 magic_size(thing, st);
9fc9ab86 564 TAG;break;
e98cedbf 565 /* How much space is dedicated to the array? Not counting the
566 elements in the array, mind, just the array itself */
9fc9ab86 567 case SVt_PVAV: TAG;
eee00145 568 st->total_size += sizeof(XPVAV);
e98cedbf 569 /* Is there anything in the array? */
570 if (AvMAX(thing) != -1) {
c8db37d3 571 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
eee00145 572 st->total_size += sizeof(SV *) * (AvMAX(thing) + 1);
573 dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
e98cedbf 574 }
575 /* Add in the bits on the other side of the beginning */
0430b7f7 576
b7621729 577 dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
eee00145 578 st->total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
0430b7f7 579
580 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
b1e5ad85 581 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
0430b7f7 582 if (AvALLOC(thing) != 0) {
eee00145 583 st->total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
0430b7f7 584 }
795fc84c 585#if (PERL_VERSION < 9)
586 /* Is there something hanging off the arylen element?
587 Post 5.9.something this is stored in magic, so will be found there,
588 and Perl_av_arylen_p() takes a non-const AV*, hence compilers rightly
589 complain about AvARYLEN() passing thing to it. */
81f1c018 590 sv_size(aTHX_ st, AvARYLEN(thing), TRUE);
795fc84c 591#endif
eee00145 592 magic_size(thing, st);
9fc9ab86 593 TAG;break;
594 case SVt_PVHV: TAG;
a6ea0805 595 /* First the base struct */
eee00145 596 st->total_size += sizeof(XPVHV);
a6ea0805 597 /* Now the array of buckets */
eee00145 598 st->total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
a6ea0805 599 /* Now walk the bucket chain */
6a9ad7ec 600 if (HvARRAY(thing)) {
a6ea0805 601 HE *cur_entry;
9fc9ab86 602 UV cur_bucket = 0;
a6ea0805 603 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
9fc9ab86 604 cur_entry = *(HvARRAY(thing) + cur_bucket);
605 while (cur_entry) {
eee00145 606 st->total_size += sizeof(HE);
9fc9ab86 607 if (cur_entry->hent_hek) {
608 /* Hash keys can be shared. Have we seen this before? */
a4efdff3 609 if (check_new(st, cur_entry->hent_hek)) {
eee00145 610 st->total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
9fc9ab86 611 }
612 }
613 cur_entry = cur_entry->hent_next;
614 }
a6ea0805 615 }
616 }
eee00145 617 magic_size(thing, st);
9fc9ab86 618 TAG;break;
619 case SVt_PVCV: TAG;
eee00145 620 st->total_size += sizeof(XPVCV);
621 magic_size(thing, st);
7ccc7d88 622
eee00145 623 st->total_size += ((XPVIO *) SvANY(thing))->xpv_len;
81f1c018 624 sv_size(aTHX_ st, (SV *)CvSTASH(thing), TRUE);
625 sv_size(aTHX_ st, (SV *)SvSTASH(thing), TRUE);
626 sv_size(aTHX_ st, (SV *)CvGV(thing), TRUE);
627 sv_size(aTHX_ st, (SV *)CvPADLIST(thing), TRUE);
628 sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), TRUE);
66f50dda 629 if (CvISXSUB(thing)) {
81f1c018 630 sv_size(aTHX_ st, cv_const_sv((CV *)thing), TRUE);
66f50dda 631 } else {
1e5a8ad2 632 op_size(aTHX_ CvSTART(thing), st);
633 op_size(aTHX_ CvROOT(thing), st);
7ccc7d88 634 }
635
9fc9ab86 636 TAG;break;
637 case SVt_PVGV: TAG;
eee00145 638 magic_size(thing, st);
639 st->total_size += sizeof(XPVGV);
640 st->total_size += GvNAMELEN(thing);
78dfb4e7 641#ifdef GvFILE
0bff12d8 642 /* Is there a file? */
99684fd4 643 check_new_and_strlen(st, GvFILE(thing));
78dfb4e7 644#endif
5c2e1b12 645 /* Is there something hanging off the glob? */
646 if (GvGP(thing)) {
a4efdff3 647 if (check_new(st, GvGP(thing))) {
81f1c018 648 st->total_size += sizeof(GP);
649 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_sv), TRUE);
650 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_form), TRUE);
651 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_av), TRUE);
652 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_hv), TRUE);
653 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_egv), TRUE);
654 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_cv), TRUE);
5c2e1b12 655 }
656 }
9fc9ab86 657 TAG;break;
658 case SVt_PVFM: TAG;
eee00145 659 st->total_size += sizeof(XPVFM);
660 magic_size(thing, st);
661 st->total_size += ((XPVIO *) SvANY(thing))->xpv_len;
81f1c018 662 sv_size(aTHX_ st, (SV *)CvPADLIST(thing), TRUE);
663 sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), TRUE);
7ccc7d88 664
a4efdff3 665 if (st->go_yell && !st->fm_whine) {
5073b933 666 carp("Devel::Size: Calculated sizes for FMs are incomplete");
a4efdff3 667 st->fm_whine = 1;
ebb2c5b9 668 }
9fc9ab86 669 TAG;break;
670 case SVt_PVIO: TAG;
eee00145 671 st->total_size += sizeof(XPVIO);
672 magic_size(thing, st);
a4efdff3 673 if (check_new(st, (SvPVX_const(thing)))) {
eee00145 674 st->total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
ebb2c5b9 675 }
5073b933 676 /* Some embedded char pointers */
99684fd4 677 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_top_name);
678 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_fmt_name);
679 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_bottom_name);
5073b933 680 /* Throw the GVs on the list to be walked if they're not-null */
81f1c018 681 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_top_gv, TRUE);
682 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv, TRUE);
683 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv, TRUE);
5073b933 684
685 /* Only go trotting through the IO structures if they're really
686 trottable. If USE_PERLIO is defined we can do this. If
687 not... we can't, so we don't even try */
688#ifdef USE_PERLIO
689 /* Dig into xio_ifp and xio_ofp here */
9fc9ab86 690 warn("Devel::Size: Can't size up perlio layers yet\n");
5073b933 691#endif
9fc9ab86 692 TAG;break;
e98cedbf 693 default:
9fc9ab86 694 warn("Devel::Size: Unknown variable type: %d encountered\n", SvTYPE(thing) );
e98cedbf 695 }
81f1c018 696 return TRUE;
e98cedbf 697}
698
a4efdff3 699static struct state *
700new_state(pTHX)
65db36c0 701{
702 SV *warn_flag;
a4efdff3 703 struct state *st;
704 Newxz(st, 1, struct state);
705 st->go_yell = TRUE;
65db36c0 706 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
a4efdff3 707 st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 708 }
709 if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
a4efdff3 710 st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 711 }
a52ceccd 712 check_new(st, &PL_sv_undef);
713 check_new(st, &PL_sv_no);
714 check_new(st, &PL_sv_yes);
a4efdff3 715 return st;
65db36c0 716}
717
9fc9ab86 718MODULE = Devel::Size PACKAGE = Devel::Size
e98cedbf 719
fea63ffa 720PROTOTYPES: DISABLE
721
eee00145 722UV
a6ea0805 723size(orig_thing)
724 SV *orig_thing
e98cedbf 725CODE:
726{
6a9ad7ec 727 SV *thing = orig_thing;
a4efdff3 728 struct state *st = new_state(aTHX);
ebb2c5b9 729
6a9ad7ec 730 /* If they passed us a reference then dereference it. This is the
731 only way we can check the sizes of arrays and hashes */
b7621729 732#if (PERL_VERSION < 11)
6a9ad7ec 733 if (SvOK(thing) && SvROK(thing)) {
734 thing = SvRV(thing);
735 }
b7621729 736#else
737 if (SvROK(thing)) {
738 thing = SvRV(thing);
739 }
740#endif
741
db519f11 742 sv_size(aTHX_ st, thing, FALSE);
eee00145 743 RETVAL = st->total_size;
a4efdff3 744 free_state(st);
6a9ad7ec 745}
746OUTPUT:
747 RETVAL
748
749
eee00145 750UV
6a9ad7ec 751total_size(orig_thing)
752 SV *orig_thing
753CODE:
754{
755 SV *thing = orig_thing;
b7621729 756 /* Array with things we still need to do */
757 AV *pending_array;
b98fcdb9 758 IV size = 0;
a4efdff3 759 struct state *st = new_state(aTHX);
b98fcdb9 760
6a9ad7ec 761 /* Size starts at zero */
762 RETVAL = 0;
763
b7621729 764 pending_array = newAV();
765
8c394e12 766 /* If they passed us a reference then dereference it.
b7621729 767 This is the only way we can check the sizes of arrays and hashes. */
768 if (SvROK(thing)) {
8c394e12 769 thing = SvRV(thing);
b7621729 770 }
6a9ad7ec 771
772 /* Put it on the pending array */
773 av_push(pending_array, thing);
774
775 /* Now just yank things off the end of the array until it's done */
e96acca9 776 while (av_len(pending_array) >= 0) {
777 thing = av_pop(pending_array);
6a9ad7ec 778 /* Process it if we've not seen it */
81f1c018 779 if (sv_size(aTHX_ st, thing, TRUE)) {
b7621729 780 dbg_printf(("# Found type %i at %p\n", SvTYPE(thing), thing));
9fc9ab86 781 switch (SvTYPE(thing)) {
782 /* fix for bug #24846 (Does not correctly recurse into references in a PVNV-type scalar) */
783 case SVt_PVNV: TAG;
784 if (SvROK(thing))
785 {
786 av_push(pending_array, SvRV(thing));
787 }
788 TAG;break;
b7621729 789#if (PERL_VERSION < 11)
9fc9ab86 790 case SVt_RV: TAG;
b7621729 791#else
9fc9ab86 792 case SVt_IV: TAG;
b7621729 793#endif
794 dbg_printf(("# Found RV\n"));
795 if (SvROK(thing)) {
796 dbg_printf(("# Found RV\n"));
797 av_push(pending_array, SvRV(thing));
798 }
9fc9ab86 799 TAG;break;
800
801 case SVt_PVAV: TAG;
802 {
803 AV *tempAV = (AV *)thing;
804 SV **tempSV;
805
806 dbg_printf(("# Found type AV\n"));
807 /* Quick alias to cut down on casting */
808
809 /* Any elements? */
810 if (av_len(tempAV) != -1) {
811 IV index;
812 /* Run through them all */
813 for (index = 0; index <= av_len(tempAV); index++) {
814 /* Did we get something? */
815 if ((tempSV = av_fetch(tempAV, index, 0))) {
816 /* Was it undef? */
817 if (*tempSV != &PL_sv_undef) {
818 /* Apparently not. Save it for later */
819 av_push(pending_array, *tempSV);
820 }
821 }
822 }
823 }
824 }
825 TAG;break;
826
827 case SVt_PVHV: TAG;
828 dbg_printf(("# Found type HV\n"));
829 /* Is there anything in here? */
830 if (hv_iterinit((HV *)thing)) {
831 HE *temp_he;
832 while ((temp_he = hv_iternext((HV *)thing))) {
833 av_push(pending_array, hv_iterval((HV *)thing, temp_he));
834 }
835 }
836 TAG;break;
837
838 case SVt_PVGV: TAG;
839 dbg_printf(("# Found type GV\n"));
840 /* Run through all the pieces and push the ones with bits */
841 if (GvSV(thing)) {
842 av_push(pending_array, (SV *)GvSV(thing));
843 }
844 if (GvFORM(thing)) {
845 av_push(pending_array, (SV *)GvFORM(thing));
846 }
847 if (GvAV(thing)) {
848 av_push(pending_array, (SV *)GvAV(thing));
849 }
850 if (GvHV(thing)) {
851 av_push(pending_array, (SV *)GvHV(thing));
852 }
853 if (GvCV(thing)) {
854 av_push(pending_array, (SV *)GvCV(thing));
855 }
856 TAG;break;
857 default:
858 TAG;break;
6a9ad7ec 859 }
b7621729 860 } else {
861 /* check_new() returned false: */
862#ifdef DEVEL_SIZE_DEBUGGING
863 if (SvOK(sv)) printf("# Ignore ref copy 0x%x\n", sv);
864 else printf("# Ignore non-sv 0x%x\n", sv);
865#endif
6a9ad7ec 866 }
b7621729 867 } /* end while */
e9716740 868
eee00145 869 RETVAL = st->total_size;
a4efdff3 870 free_state(st);
6a9ad7ec 871 SvREFCNT_dec(pending_array);
e98cedbf 872}
873OUTPUT:
874 RETVAL
6a9ad7ec 875