Replace c*OPx macros with their expansions.
[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
95dc1714 15#ifndef SvOOK_offset
16# define SvOOK_offset(sv, len) STMT_START { len = SvIVX(sv); } STMT_END
17#endif
87372f42 18
9fc9ab86 19#ifdef _MSC_VER
1a36ac09 20/* "structured exception" handling is a Microsoft extension to C and C++.
21 It's *not* C++ exception handling - C++ exception handling can't capture
22 SEGVs and suchlike, whereas this can. There's no known analagous
23 functionality on other platforms. */
24# include <excpt.h>
25# define TRY_TO_CATCH_SEGV __try
26# define CAUGHT_EXCEPTION __except(EXCEPTION EXCEPTION_EXECUTE_HANDLER)
9fc9ab86 27#else
1a36ac09 28# define TRY_TO_CATCH_SEGV if(1)
29# define CAUGHT_EXCEPTION else
9fc9ab86 30#endif
31
32#ifdef __GNUC__
33# define __attribute__(x)
34#endif
35
b7621729 36#if 0 && defined(DEBUGGING)
37#define dbg_printf(x) printf x
38#else
39#define dbg_printf(x)
40#endif
98ecbbc6 41
0964064b 42#define TAG /* printf( "# %s(%d)\n", __FILE__, __LINE__ ) */
6a9ad7ec 43#define carp puts
9fc9ab86 44
30fe4f47 45/* The idea is to have a tree structure to store 1 bit per possible pointer
46 address. The lowest 16 bits are stored in a block of 8092 bytes.
47 The blocks are in a 256-way tree, indexed by the reset of the pointer.
48 This can cope with 32 and 64 bit pointers, and any address space layout,
49 without excessive memory needs. The assumption is that your CPU cache
50 works :-) (And that we're not going to bust it) */
51
30fe4f47 52#define BYTE_BITS 3
53#define LEAF_BITS (16 - BYTE_BITS)
54#define LEAF_MASK 0x1FFF
9fc9ab86 55
65db36c0 56struct state {
eee00145 57 UV total_size;
65db36c0 58 bool regex_whine;
59 bool fm_whine;
60 bool dangle_whine;
61 bool go_yell;
62 /* My hunch (not measured) is that for most architectures pointers will
63 start with 0 bits, hence the start of this array will be hot, and the
64 end unused. So put the flags next to the hot end. */
65 void *tracking[256];
66};
67
9fc9ab86 68/*
69 Checks to see if thing is in the bitstring.
70 Returns true or false, and
71 notes thing in the segmented bitstring.
72 */
2eb93d08 73static bool
a4efdff3 74check_new(struct state *st, const void *const p) {
30fe4f47 75 unsigned int bits = 8 * sizeof(void*);
76 const size_t raw_p = PTR2nat(p);
77 /* This effectively rotates the value right by the number of low always-0
78 bits in an aligned pointer. The assmption is that most (if not all)
79 pointers are aligned, and these will be in the same chain of nodes
80 (and hence hot in the cache) but we can still deal with any unaligned
81 pointers. */
82 const size_t cooked_p
f404ed48 83 = (raw_p >> ALIGN_BITS) | (raw_p << (bits - ALIGN_BITS));
30fe4f47 84 const U8 this_bit = 1 << (cooked_p & 0x7);
85 U8 **leaf_p;
86 U8 *leaf;
87 unsigned int i;
302077b6 88 void **tv_p = (void **) (st->tracking);
30fe4f47 89
302077b6 90 if (NULL == p) return FALSE;
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
f3cf7e20 165/* For now, this is somewhat a compatibility bodge until the plan comes
166 together for fine grained recursion control. total_size() would recurse into
167 hash and array members, whereas sv_size() would not. However, sv_size() is
168 called with CvSTASH() of a CV, which means that if it (also) starts to
169 recurse fully, then the size of any CV now becomes the size of the entire
170 symbol table reachable from it, and potentially the entire symbol table, if
171 any subroutine makes a reference to a global (such as %SIG). The historical
172 implementation of total_size() didn't report "everything", and changing the
173 only available size to "everything" doesn't feel at all useful. */
174
175#define NO_RECURSION 0
176#define SOME_RECURSION 1
177#define TOTAL_SIZE_RECURSION 2
178
179static bool sv_size(pTHX_ struct state *, const SV *const, const int recurse);
db519f11 180
7ccc7d88 181typedef enum {
9fc9ab86 182 OPc_NULL, /* 0 */
183 OPc_BASEOP, /* 1 */
184 OPc_UNOP, /* 2 */
185 OPc_BINOP, /* 3 */
186 OPc_LOGOP, /* 4 */
187 OPc_LISTOP, /* 5 */
188 OPc_PMOP, /* 6 */
189 OPc_SVOP, /* 7 */
190 OPc_PADOP, /* 8 */
191 OPc_PVOP, /* 9 */
192 OPc_LOOP, /* 10 */
193 OPc_COP /* 11 */
7ccc7d88 194} opclass;
195
196static opclass
9fc9ab86 197cc_opclass(const OP * const o)
7ccc7d88 198{
199 if (!o)
9fc9ab86 200 return OPc_NULL;
1a36ac09 201 TRY_TO_CATCH_SEGV {
9fc9ab86 202 if (o->op_type == 0)
203 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
7ccc7d88 204
9fc9ab86 205 if (o->op_type == OP_SASSIGN)
206 return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
7ccc7d88 207
9fc9ab86 208 #ifdef USE_ITHREADS
209 if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
210 return OPc_PADOP;
211 #endif
7ccc7d88 212
9fc9ab86 213 if ((o->op_type == OP_TRANS)) {
214 return OPc_BASEOP;
215 }
7ccc7d88 216
9fc9ab86 217 switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
218 case OA_BASEOP: TAG;
219 return OPc_BASEOP;
220
221 case OA_UNOP: TAG;
222 return OPc_UNOP;
223
224 case OA_BINOP: TAG;
225 return OPc_BINOP;
62691e7c 226
9fc9ab86 227 case OA_LOGOP: TAG;
228 return OPc_LOGOP;
7ccc7d88 229
9fc9ab86 230 case OA_LISTOP: TAG;
231 return OPc_LISTOP;
7ccc7d88 232
9fc9ab86 233 case OA_PMOP: TAG;
234 return OPc_PMOP;
7ccc7d88 235
9fc9ab86 236 case OA_SVOP: TAG;
237 return OPc_SVOP;
7ccc7d88 238
9fc9ab86 239 case OA_PADOP: TAG;
240 return OPc_PADOP;
7ccc7d88 241
9fc9ab86 242 case OA_PVOP_OR_SVOP: TAG;
243 /*
244 * Character translations (tr///) are usually a PVOP, keeping a
245 * pointer to a table of shorts used to look up translations.
246 * Under utf8, however, a simple table isn't practical; instead,
247 * the OP is an SVOP, and the SV is a reference to a swash
248 * (i.e., an RV pointing to an HV).
249 */
250 return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
251 ? OPc_SVOP : OPc_PVOP;
7ccc7d88 252
9fc9ab86 253 case OA_LOOP: TAG;
254 return OPc_LOOP;
7ccc7d88 255
9fc9ab86 256 case OA_COP: TAG;
257 return OPc_COP;
7ccc7d88 258
9fc9ab86 259 case OA_BASEOP_OR_UNOP: TAG;
7ccc7d88 260 /*
9fc9ab86 261 * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on
262 * whether parens were seen. perly.y uses OPf_SPECIAL to
263 * signal whether a BASEOP had empty parens or none.
264 * Some other UNOPs are created later, though, so the best
265 * test is OPf_KIDS, which is set in newUNOP.
7ccc7d88 266 */
9fc9ab86 267 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
268
269 case OA_FILESTATOP: TAG;
270 /*
271 * The file stat OPs are created via UNI(OP_foo) in toke.c but use
272 * the OPf_REF flag to distinguish between OP types instead of the
273 * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we
274 * return OPc_UNOP so that walkoptree can find our children. If
275 * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set
276 * (no argument to the operator) it's an OP; with OPf_REF set it's
277 * an SVOP (and op_sv is the GV for the filehandle argument).
278 */
279 return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
280 #ifdef USE_ITHREADS
281 (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
282 #else
283 (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
284 #endif
285 case OA_LOOPEXOP: TAG;
286 /*
287 * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a
288 * label was omitted (in which case it's a BASEOP) or else a term was
289 * seen. In this last case, all except goto are definitely PVOP but
290 * goto is either a PVOP (with an ordinary constant label), an UNOP
291 * with OPf_STACKED (with a non-constant non-sub) or an UNOP for
292 * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to
293 * get set.
294 */
295 if (o->op_flags & OPf_STACKED)
296 return OPc_UNOP;
297 else if (o->op_flags & OPf_SPECIAL)
298 return OPc_BASEOP;
299 else
300 return OPc_PVOP;
301 }
302 warn("Devel::Size: Can't determine class of operator %s, assuming BASEOP\n",
303 PL_op_name[o->op_type]);
304 }
1a36ac09 305 CAUGHT_EXCEPTION { }
7ccc7d88 306 return OPc_BASEOP;
307}
308
6a9ad7ec 309/* Figure out how much magic is attached to the SV and return the
310 size */
eee00145 311static void
b7130948 312magic_size(pTHX_ const SV * const thing, struct state *st) {
980c6576 313 MAGIC *magic_pointer = SvMAGIC(thing);
6a9ad7ec 314
980c6576 315 /* Have we seen the magic pointer? (NULL has always been seen before) */
e5c69bdd 316 while (check_new(st, magic_pointer)) {
eee00145 317 st->total_size += sizeof(MAGIC);
9847261d 318 /* magic vtables aren't freed when magic is freed, so don't count them.
319 (They are static structures. Anything that assumes otherwise is buggy.)
320 */
321
6a9ad7ec 322
1a36ac09 323 TRY_TO_CATCH_SEGV {
b7130948 324 sv_size(aTHX_ st, magic_pointer->mg_obj, TOTAL_SIZE_RECURSION);
d1888d0b 325 if (magic_pointer->mg_len == HEf_SVKEY) {
326 sv_size(aTHX_ st, (SV *)magic_pointer->mg_ptr, TOTAL_SIZE_RECURSION);
327 }
328#if defined(PERL_MAGIC_utf8) && defined (PERL_MAGIC_UTF8_CACHESIZE)
329 else if (magic_pointer->mg_type == PERL_MAGIC_utf8) {
330 if (check_new(st, magic_pointer->mg_ptr)) {
331 st->total_size += PERL_MAGIC_UTF8_CACHESIZE * 2 * sizeof(STRLEN);
332 }
333 }
334#endif
335 else if (magic_pointer->mg_len > 0) {
336 if (check_new(st, magic_pointer->mg_ptr)) {
337 st->total_size += magic_pointer->mg_len;
338 }
339 }
6a9ad7ec 340
0964064b 341 /* Get the next in the chain */
9fc9ab86 342 magic_pointer = magic_pointer->mg_moremagic;
343 }
1a36ac09 344 CAUGHT_EXCEPTION {
a4efdff3 345 if (st->dangle_whine)
9fc9ab86 346 warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
347 }
6a9ad7ec 348 }
6a9ad7ec 349}
350
eee00145 351static void
99684fd4 352check_new_and_strlen(struct state *st, const char *const p) {
353 if(check_new(st, p))
6ec51ae0 354 st->total_size += 1 + strlen(p);
99684fd4 355}
356
357static void
eee00145 358regex_size(const REGEXP * const baseregex, struct state *st) {
c1bfd7da 359 if(!check_new(st, baseregex))
360 return;
eee00145 361 st->total_size += sizeof(REGEXP);
9fc9ab86 362#if (PERL_VERSION < 11)
6ea94d90 363 /* Note the size of the paren offset thing */
eee00145 364 st->total_size += sizeof(I32) * baseregex->nparens * 2;
365 st->total_size += strlen(baseregex->precomp);
6ea94d90 366#else
eee00145 367 st->total_size += sizeof(struct regexp);
368 st->total_size += sizeof(I32) * SvANY(baseregex)->nparens * 2;
369 /*st->total_size += strlen(SvANY(baseregex)->subbeg);*/
6ea94d90 370#endif
a4efdff3 371 if (st->go_yell && !st->regex_whine) {
6ea94d90 372 carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
a4efdff3 373 st->regex_whine = 1;
98ecbbc6 374 }
7ccc7d88 375}
376
eee00145 377static void
1e5a8ad2 378op_size(pTHX_ const OP * const baseop, struct state *st)
379{
380 TRY_TO_CATCH_SEGV {
381 TAG;
382 if(!check_new(st, baseop))
383 return;
384 TAG;
385 op_size(aTHX_ baseop->op_next, st);
386 TAG;
387 switch (cc_opclass(baseop)) {
388 case OPc_BASEOP: TAG;
389 st->total_size += sizeof(struct op);
390 TAG;break;
391 case OPc_UNOP: TAG;
392 st->total_size += sizeof(struct unop);
a0a834e7 393 op_size(aTHX_ ((UNOP *)baseop)->op_first, st);
1e5a8ad2 394 TAG;break;
395 case OPc_BINOP: TAG;
396 st->total_size += sizeof(struct binop);
a0a834e7 397 op_size(aTHX_ ((BINOP *)baseop)->op_first, st);
398 op_size(aTHX_ ((BINOP *)baseop)->op_last, st);
1e5a8ad2 399 TAG;break;
400 case OPc_LOGOP: TAG;
401 st->total_size += sizeof(struct logop);
a0a834e7 402 op_size(aTHX_ ((BINOP *)baseop)->op_first, st);
403 op_size(aTHX_ ((LOGOP *)baseop)->op_other, st);
1e5a8ad2 404 TAG;break;
405 case OPc_LISTOP: TAG;
406 st->total_size += sizeof(struct listop);
a0a834e7 407 op_size(aTHX_ ((LISTOP *)baseop)->op_first, st);
408 op_size(aTHX_ ((LISTOP *)baseop)->op_last, st);
1e5a8ad2 409 TAG;break;
410 case OPc_PMOP: TAG;
411 st->total_size += sizeof(struct pmop);
a0a834e7 412 op_size(aTHX_ ((PMOP *)baseop)->op_first, st);
413 op_size(aTHX_ ((PMOP *)baseop)->op_last, st);
5a83b7cf 414#if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
a0a834e7 415 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplroot, st);
416 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplstart, st);
5a83b7cf 417#endif
c1bfd7da 418 /* This is defined away in perl 5.8.x, but it is in there for
419 5.6.x */
98ecbbc6 420#ifdef PM_GETRE
a0a834e7 421 regex_size(PM_GETRE((PMOP *)baseop), st);
98ecbbc6 422#else
a0a834e7 423 regex_size(((PMOP *)baseop)->op_pmregexp, st);
98ecbbc6 424#endif
c1bfd7da 425 TAG;break;
81f1c018 426 case OPc_SVOP: TAG;
427 st->total_size += sizeof(struct pmop);
574d9fd9 428 if (!(baseop->op_type == OP_AELEMFAST
429 && baseop->op_flags & OPf_SPECIAL)) {
430 /* not an OP_PADAV replacement */
a0a834e7 431 sv_size(aTHX_ st, ((SVOP *)baseop)->op_sv, SOME_RECURSION);
574d9fd9 432 }
81f1c018 433 TAG;break;
9fc9ab86 434 case OPc_PADOP: TAG;
eee00145 435 st->total_size += sizeof(struct padop);
99684fd4 436 TAG;break;
437 case OPc_PVOP: TAG;
a0a834e7 438 check_new_and_strlen(st, ((PVOP *)baseop)->op_pv);
219b7d34 439 TAG;break;
1e5a8ad2 440 case OPc_LOOP: TAG;
441 st->total_size += sizeof(struct loop);
a0a834e7 442 op_size(aTHX_ ((LOOP *)baseop)->op_first, st);
443 op_size(aTHX_ ((LOOP *)baseop)->op_last, st);
444 op_size(aTHX_ ((LOOP *)baseop)->op_redoop, st);
445 op_size(aTHX_ ((LOOP *)baseop)->op_nextop, st);
446 op_size(aTHX_ ((LOOP *)baseop)->op_lastop, st);
1e5a8ad2 447 TAG;break;
448 case OPc_COP: TAG;
9fc9ab86 449 {
450 COP *basecop;
451 basecop = (COP *)baseop;
eee00145 452 st->total_size += sizeof(struct cop);
9fc9ab86 453
454 /* Change 33656 by nicholas@mouse-mill on 2008/04/07 11:29:51
455 Eliminate cop_label from struct cop by storing a label as the first
456 entry in the hints hash. Most statements don't have labels, so this
457 will save memory. Not sure how much.
458 The check below will be incorrect fail on bleadperls
459 before 5.11 @33656, but later than 5.10, producing slightly too
460 small memory sizes on these Perls. */
b7621729 461#if (PERL_VERSION < 11)
99684fd4 462 check_new_and_strlen(st, basecop->cop_label);
b7621729 463#endif
7ccc7d88 464#ifdef USE_ITHREADS
99684fd4 465 check_new_and_strlen(st, basecop->cop_file);
466 check_new_and_strlen(st, basecop->cop_stashpv);
7ccc7d88 467#else
f3cf7e20 468 sv_size(aTHX_ st, (SV *)basecop->cop_stash, SOME_RECURSION);
469 sv_size(aTHX_ st, (SV *)basecop->cop_filegv, SOME_RECURSION);
7ccc7d88 470#endif
471
9fc9ab86 472 }
473 TAG;break;
474 default:
475 TAG;break;
476 }
477 }
1a36ac09 478 CAUGHT_EXCEPTION {
a4efdff3 479 if (st->dangle_whine)
9fc9ab86 480 warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
7ccc7d88 481 }
7ccc7d88 482}
6a9ad7ec 483
b6558d1d 484#if PERL_VERSION < 8 || PERL_SUBVERSION < 9
485# define SVt_LAST 16
24d37977 486#endif
487
f73dcfce 488#ifdef PURIFY
489# define MAYBE_PURIFY(normal, pure) (pure)
490# define MAYBE_OFFSET(struct_name, member) 0
491#else
492# define MAYBE_PURIFY(normal, pure) (normal)
493# define MAYBE_OFFSET(struct_name, member) STRUCT_OFFSET(struct_name, member)
494#endif
495
b6558d1d 496const U8 body_sizes[SVt_LAST] = {
497#if PERL_VERSION < 9
f73dcfce 498 0, /* SVt_NULL */
499 MAYBE_PURIFY(sizeof(IV), sizeof(XPVIV)), /* SVt_IV */
500 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
501 sizeof(XRV), /* SVt_RV */
502 sizeof(XPV), /* SVt_PV */
503 sizeof(XPVIV), /* SVt_PVIV */
504 sizeof(XPVNV), /* SVt_PVNV */
505 sizeof(XPVMG), /* SVt_PVMG */
506 sizeof(XPVBM), /* SVt_PVBM */
507 sizeof(XPVLV), /* SVt_PVLV */
508 sizeof(XPVAV), /* SVt_PVAV */
509 sizeof(XPVHV), /* SVt_PVHV */
510 sizeof(XPVCV), /* SVt_PVCV */
511 sizeof(XPVGV), /* SVt_PVGV */
512 sizeof(XPVFM), /* SVt_PVFM */
513 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 514#elif PERL_VERSION == 10 && PERL_SUBVERSION == 0
f73dcfce 515 0, /* SVt_NULL */
516 0, /* SVt_BIND */
517 0, /* SVt_IV */
518 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
519 0, /* SVt_RV */
520 MAYBE_PURIFY(sizeof(xpv_allocated), sizeof(XPV)), /* SVt_PV */
521 MAYBE_PURIFY(sizeof(xpviv_allocated), sizeof(XPVIV)),/* SVt_PVIV */
522 sizeof(XPVNV), /* SVt_PVNV */
523 sizeof(XPVMG), /* SVt_PVMG */
524 sizeof(XPVGV), /* SVt_PVGV */
525 sizeof(XPVLV), /* SVt_PVLV */
526 MAYBE_PURIFY(sizeof(xpvav_allocated), sizeof(XPVAV)),/* SVt_PVAV */
527 MAYBE_PURIFY(sizeof(xpvhv_allocated), sizeof(XPVHV)),/* SVt_PVHV */
528 MAYBE_PURIFY(sizeof(xpvcv_allocated), sizeof(XPVCV)),/* SVt_PVCV */
529 MAYBE_PURIFY(sizeof(xpvfm_allocated), sizeof(XPVFM)),/* SVt_PVFM */
530 sizeof(XPVIO), /* SVt_PVIO */
b6558d1d 531#elif PERL_VERSION == 10 && PERL_SUBVERSION == 1
f73dcfce 532 0, /* SVt_NULL */
533 0, /* SVt_BIND */
534 0, /* SVt_IV */
535 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
536 0, /* SVt_RV */
537 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
538 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
539 sizeof(XPVNV), /* SVt_PVNV */
540 sizeof(XPVMG), /* SVt_PVMG */
541 sizeof(XPVGV), /* SVt_PVGV */
542 sizeof(XPVLV), /* SVt_PVLV */
543 sizeof(XPVAV) - MAYBE_OFFSET(XPVAV, xav_fill), /* SVt_PVAV */
544 sizeof(XPVHV) - MAYBE_OFFSET(XPVHV, xhv_fill), /* SVt_PVHV */
545 sizeof(XPVCV) - MAYBE_OFFSET(XPVCV, xpv_cur), /* SVt_PVCV */
546 sizeof(XPVFM) - MAYBE_OFFSET(XPVFM, xpv_cur), /* SVt_PVFM */
547 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 548#elif PERL_VERSION < 13
f73dcfce 549 0, /* SVt_NULL */
550 0, /* SVt_BIND */
551 0, /* SVt_IV */
552 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
553 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
554 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
555 sizeof(XPVNV), /* SVt_PVNV */
556 sizeof(XPVMG), /* SVt_PVMG */
557 sizeof(regexp) - MAYBE_OFFSET(regexp, xpv_cur), /* SVt_REGEXP */
558 sizeof(XPVGV), /* SVt_PVGV */
559 sizeof(XPVLV), /* SVt_PVLV */
560 sizeof(XPVAV) - MAYBE_OFFSET(XPVAV, xav_fill), /* SVt_PVAV */
561 sizeof(XPVHV) - MAYBE_OFFSET(XPVHV, xhv_fill), /* SVt_PVHV */
562 sizeof(XPVCV) - MAYBE_OFFSET(XPVCV, xpv_cur), /* SVt_PVCV */
563 sizeof(XPVFM) - MAYBE_OFFSET(XPVFM, xpv_cur), /* SVt_PVFM */
564 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 565#else
f73dcfce 566 0, /* SVt_NULL */
567 0, /* SVt_BIND */
568 0, /* SVt_IV */
569 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
570 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
571 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
572 sizeof(XPVNV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVNV */
573 sizeof(XPVMG), /* SVt_PVMG */
574 sizeof(regexp), /* SVt_REGEXP */
575 sizeof(XPVGV), /* SVt_PVGV */
576 sizeof(XPVLV), /* SVt_PVLV */
577 sizeof(XPVAV), /* SVt_PVAV */
578 sizeof(XPVHV), /* SVt_PVHV */
579 sizeof(XPVCV), /* SVt_PVCV */
580 sizeof(XPVFM), /* SVt_PVFM */
581 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 582#endif
583};
584
81f1c018 585static bool
db519f11 586sv_size(pTHX_ struct state *const st, const SV * const orig_thing,
f3cf7e20 587 const int recurse) {
9fc9ab86 588 const SV *thing = orig_thing;
b6558d1d 589 U32 type;
eee00145 590
81f1c018 591 if(!check_new(st, thing))
592 return FALSE;
593
b6558d1d 594 type = SvTYPE(thing);
595 if (type > SVt_LAST) {
596 warn("Devel::Size: Unknown variable type: %d encountered\n", type);
597 return TRUE;
598 }
599 st->total_size += sizeof(SV) + body_sizes[type];
b1e5ad85 600
b6558d1d 601 if (type >= SVt_PVMG) {
696b99e2 602 magic_size(aTHX_ thing, st);
603 }
604
b6558d1d 605 switch (type) {
606#if (PERL_VERSION < 11)
e98cedbf 607 /* Is it a reference? */
9fc9ab86 608 case SVt_RV: TAG;
b6558d1d 609#else
610 case SVt_IV: TAG;
24d37977 611#endif
81f1c018 612 if(recurse && SvROK(thing))
f3cf7e20 613 sv_size(aTHX_ st, SvRV_const(thing), recurse);
9fc9ab86 614 TAG;break;
267703fd 615
9fc9ab86 616 case SVt_PVAV: TAG;
e98cedbf 617 /* Is there anything in the array? */
618 if (AvMAX(thing) != -1) {
c8db37d3 619 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
eee00145 620 st->total_size += sizeof(SV *) * (AvMAX(thing) + 1);
621 dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
6c5ddc0d 622
623 if (recurse >= TOTAL_SIZE_RECURSION) {
624 SSize_t i = AvFILLp(thing) + 1;
625
626 while (i--)
627 sv_size(aTHX_ st, AvARRAY(thing)[i], recurse);
628 }
e98cedbf 629 }
630 /* Add in the bits on the other side of the beginning */
0430b7f7 631
b7621729 632 dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
eee00145 633 st->total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
0430b7f7 634
635 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
b1e5ad85 636 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
0430b7f7 637 if (AvALLOC(thing) != 0) {
eee00145 638 st->total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
0430b7f7 639 }
795fc84c 640#if (PERL_VERSION < 9)
641 /* Is there something hanging off the arylen element?
642 Post 5.9.something this is stored in magic, so will be found there,
643 and Perl_av_arylen_p() takes a non-const AV*, hence compilers rightly
644 complain about AvARYLEN() passing thing to it. */
f3cf7e20 645 sv_size(aTHX_ st, AvARYLEN(thing), recurse);
795fc84c 646#endif
9fc9ab86 647 TAG;break;
648 case SVt_PVHV: TAG;
a6ea0805 649 /* Now the array of buckets */
eee00145 650 st->total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
a6ea0805 651 /* Now walk the bucket chain */
6a9ad7ec 652 if (HvARRAY(thing)) {
a6ea0805 653 HE *cur_entry;
9fc9ab86 654 UV cur_bucket = 0;
a6ea0805 655 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
9fc9ab86 656 cur_entry = *(HvARRAY(thing) + cur_bucket);
657 while (cur_entry) {
eee00145 658 st->total_size += sizeof(HE);
9fc9ab86 659 if (cur_entry->hent_hek) {
660 /* Hash keys can be shared. Have we seen this before? */
a4efdff3 661 if (check_new(st, cur_entry->hent_hek)) {
eee00145 662 st->total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
9fc9ab86 663 }
664 }
f3cf7e20 665 if (recurse >= TOTAL_SIZE_RECURSION)
666 sv_size(aTHX_ st, HeVAL(cur_entry), recurse);
9fc9ab86 667 cur_entry = cur_entry->hent_next;
668 }
a6ea0805 669 }
670 }
9fc9ab86 671 TAG;break;
267703fd 672
673
674 case SVt_PVFM: TAG;
267703fd 675 sv_size(aTHX_ st, (SV *)CvPADLIST(thing), SOME_RECURSION);
676 sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), recurse);
677
678 if (st->go_yell && !st->fm_whine) {
679 carp("Devel::Size: Calculated sizes for FMs are incomplete");
680 st->fm_whine = 1;
681 }
682 goto freescalar;
683
9fc9ab86 684 case SVt_PVCV: TAG;
f3cf7e20 685 sv_size(aTHX_ st, (SV *)CvSTASH(thing), SOME_RECURSION);
686 sv_size(aTHX_ st, (SV *)SvSTASH(thing), SOME_RECURSION);
687 sv_size(aTHX_ st, (SV *)CvGV(thing), SOME_RECURSION);
6c5ddc0d 688 sv_size(aTHX_ st, (SV *)CvPADLIST(thing), SOME_RECURSION);
f3cf7e20 689 sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), recurse);
66f50dda 690 if (CvISXSUB(thing)) {
f3cf7e20 691 sv_size(aTHX_ st, cv_const_sv((CV *)thing), recurse);
66f50dda 692 } else {
1e5a8ad2 693 op_size(aTHX_ CvSTART(thing), st);
694 op_size(aTHX_ CvROOT(thing), st);
7ccc7d88 695 }
267703fd 696 goto freescalar;
697
698 case SVt_PVIO: TAG;
267703fd 699 /* Some embedded char pointers */
700 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_top_name);
701 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_fmt_name);
702 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_bottom_name);
703 /* Throw the GVs on the list to be walked if they're not-null */
704 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_top_gv, recurse);
705 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv, recurse);
706 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv, recurse);
707
708 /* Only go trotting through the IO structures if they're really
709 trottable. If USE_PERLIO is defined we can do this. If
710 not... we can't, so we don't even try */
711#ifdef USE_PERLIO
712 /* Dig into xio_ifp and xio_ofp here */
713 warn("Devel::Size: Can't size up perlio layers yet\n");
714#endif
715 goto freescalar;
716
267703fd 717 case SVt_PVLV: TAG;
267703fd 718#if (PERL_VERSION < 9)
719 goto freescalar;
267703fd 720#endif
7ccc7d88 721
9fc9ab86 722 case SVt_PVGV: TAG;
4a3d023d 723 if(isGV_with_GP(thing)) {
724 st->total_size += GvNAMELEN(thing);
78dfb4e7 725#ifdef GvFILE
2b217e71 726# if !defined(USE_ITHREADS) || (PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8))
727 /* With itreads, before 5.8.9, this can end up pointing to freed memory
728 if the GV was created in an eval, as GvFILE() points to CopFILE(),
729 and the relevant COP has been freed on scope cleanup after the eval.
730 5.8.9 adds a binary compatible fudge that catches the vast majority
731 of cases. 5.9.something added a proper fix, by converting the GP to
732 use a shared hash key (porperly reference counted), instead of a
733 char * (owned by who knows? possibly no-one now) */
4a3d023d 734 check_new_and_strlen(st, GvFILE(thing));
2b217e71 735# endif
78dfb4e7 736#endif
4a3d023d 737 /* Is there something hanging off the glob? */
738 if (check_new(st, GvGP(thing))) {
739 st->total_size += sizeof(GP);
f3cf7e20 740 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_sv), recurse);
741 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_form), recurse);
742 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_av), recurse);
743 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_hv), recurse);
744 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_egv), recurse);
745 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_cv), recurse);
4a3d023d 746 }
267703fd 747#if (PERL_VERSION >= 9)
748 TAG; break;
749#endif
5c2e1b12 750 }
b6558d1d 751#if PERL_VERSION <= 8
752 case SVt_PVBM: TAG;
753#endif
267703fd 754 case SVt_PVMG: TAG;
267703fd 755 case SVt_PVNV: TAG;
267703fd 756 case SVt_PVIV: TAG;
267703fd 757 case SVt_PV: TAG;
267703fd 758 freescalar:
759 if(recurse && SvROK(thing))
760 sv_size(aTHX_ st, SvRV_const(thing), recurse);
761 else
762 st->total_size += SvLEN(thing);
763
764 if(SvOOK(thing)) {
95dc1714 765 STRLEN len;
766 SvOOK_offset(thing, len);
767 st->total_size += len;
ebb2c5b9 768 }
9fc9ab86 769 TAG;break;
5073b933 770
e98cedbf 771 }
81f1c018 772 return TRUE;
e98cedbf 773}
774
a4efdff3 775static struct state *
776new_state(pTHX)
65db36c0 777{
778 SV *warn_flag;
a4efdff3 779 struct state *st;
d9b022a1 780
a4efdff3 781 Newxz(st, 1, struct state);
782 st->go_yell = TRUE;
65db36c0 783 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
a4efdff3 784 st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 785 }
786 if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
a4efdff3 787 st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 788 }
a52ceccd 789 check_new(st, &PL_sv_undef);
790 check_new(st, &PL_sv_no);
791 check_new(st, &PL_sv_yes);
a4efdff3 792 return st;
65db36c0 793}
794
9fc9ab86 795MODULE = Devel::Size PACKAGE = Devel::Size
e98cedbf 796
fea63ffa 797PROTOTYPES: DISABLE
798
eee00145 799UV
a6ea0805 800size(orig_thing)
801 SV *orig_thing
13683e3a 802ALIAS:
803 total_size = TOTAL_SIZE_RECURSION
e98cedbf 804CODE:
805{
6a9ad7ec 806 SV *thing = orig_thing;
a4efdff3 807 struct state *st = new_state(aTHX);
ebb2c5b9 808
6a9ad7ec 809 /* If they passed us a reference then dereference it. This is the
810 only way we can check the sizes of arrays and hashes */
b7621729 811 if (SvROK(thing)) {
812 thing = SvRV(thing);
813 }
b7621729 814
13683e3a 815 sv_size(aTHX_ st, thing, ix);
eee00145 816 RETVAL = st->total_size;
a4efdff3 817 free_state(st);
6a9ad7ec 818}
819OUTPUT:
820 RETVAL