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