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