wrong test for magicalness
[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
218
7ccc7d88 219} opclass;
220
221static opclass
9fc9ab86 222cc_opclass(const OP * const o)
7ccc7d88 223{
224 if (!o)
9fc9ab86 225 return OPc_NULL;
1a36ac09 226 TRY_TO_CATCH_SEGV {
9fc9ab86 227 if (o->op_type == 0)
228 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
7ccc7d88 229
9fc9ab86 230 if (o->op_type == OP_SASSIGN)
231 return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
7ccc7d88 232
9fc9ab86 233 #ifdef USE_ITHREADS
234 if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
235 return OPc_PADOP;
236 #endif
7ccc7d88 237
9fc9ab86 238 if ((o->op_type == OP_TRANS)) {
239 return OPc_BASEOP;
240 }
7ccc7d88 241
9fc9ab86 242 switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
243 case OA_BASEOP: TAG;
244 return OPc_BASEOP;
245
246 case OA_UNOP: TAG;
247 return OPc_UNOP;
248
249 case OA_BINOP: TAG;
250 return OPc_BINOP;
62691e7c 251
9fc9ab86 252 case OA_LOGOP: TAG;
253 return OPc_LOGOP;
7ccc7d88 254
9fc9ab86 255 case OA_LISTOP: TAG;
256 return OPc_LISTOP;
7ccc7d88 257
9fc9ab86 258 case OA_PMOP: TAG;
259 return OPc_PMOP;
7ccc7d88 260
9fc9ab86 261 case OA_SVOP: TAG;
262 return OPc_SVOP;
7ccc7d88 263
177ebd37 264#ifdef OA_PADOP
9fc9ab86 265 case OA_PADOP: TAG;
266 return OPc_PADOP;
177ebd37 267#endif
268
269#ifdef OA_GVOP
270 case OA_GVOP: TAG;
271 return OPc_GVOP;
272#endif
7ccc7d88 273
177ebd37 274#ifdef OA_PVOP_OR_SVOP
9fc9ab86 275 case OA_PVOP_OR_SVOP: TAG;
276 /*
277 * Character translations (tr///) are usually a PVOP, keeping a
278 * pointer to a table of shorts used to look up translations.
279 * Under utf8, however, a simple table isn't practical; instead,
280 * the OP is an SVOP, and the SV is a reference to a swash
281 * (i.e., an RV pointing to an HV).
282 */
283 return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
284 ? OPc_SVOP : OPc_PVOP;
177ebd37 285#endif
7ccc7d88 286
9fc9ab86 287 case OA_LOOP: TAG;
288 return OPc_LOOP;
7ccc7d88 289
9fc9ab86 290 case OA_COP: TAG;
291 return OPc_COP;
7ccc7d88 292
9fc9ab86 293 case OA_BASEOP_OR_UNOP: TAG;
7ccc7d88 294 /*
9fc9ab86 295 * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on
296 * whether parens were seen. perly.y uses OPf_SPECIAL to
297 * signal whether a BASEOP had empty parens or none.
298 * Some other UNOPs are created later, though, so the best
299 * test is OPf_KIDS, which is set in newUNOP.
7ccc7d88 300 */
9fc9ab86 301 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
302
303 case OA_FILESTATOP: TAG;
304 /*
305 * The file stat OPs are created via UNI(OP_foo) in toke.c but use
306 * the OPf_REF flag to distinguish between OP types instead of the
307 * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we
308 * return OPc_UNOP so that walkoptree can find our children. If
309 * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set
310 * (no argument to the operator) it's an OP; with OPf_REF set it's
311 * an SVOP (and op_sv is the GV for the filehandle argument).
312 */
313 return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
314 #ifdef USE_ITHREADS
315 (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
316 #else
317 (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
318 #endif
319 case OA_LOOPEXOP: TAG;
320 /*
321 * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a
322 * label was omitted (in which case it's a BASEOP) or else a term was
323 * seen. In this last case, all except goto are definitely PVOP but
324 * goto is either a PVOP (with an ordinary constant label), an UNOP
325 * with OPf_STACKED (with a non-constant non-sub) or an UNOP for
326 * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to
327 * get set.
328 */
329 if (o->op_flags & OPf_STACKED)
330 return OPc_UNOP;
331 else if (o->op_flags & OPf_SPECIAL)
332 return OPc_BASEOP;
333 else
334 return OPc_PVOP;
177ebd37 335
336#ifdef OA_CONDOP
337 case OA_CONDOP: TAG;
338 return OPc_CONDOP;
339#endif
9fc9ab86 340 }
341 warn("Devel::Size: Can't determine class of operator %s, assuming BASEOP\n",
342 PL_op_name[o->op_type]);
343 }
1a36ac09 344 CAUGHT_EXCEPTION { }
7ccc7d88 345 return OPc_BASEOP;
346}
347
6a9ad7ec 348/* Figure out how much magic is attached to the SV and return the
349 size */
eee00145 350static void
b7130948 351magic_size(pTHX_ const SV * const thing, struct state *st) {
980c6576 352 MAGIC *magic_pointer = SvMAGIC(thing);
6a9ad7ec 353
980c6576 354 /* Have we seen the magic pointer? (NULL has always been seen before) */
e5c69bdd 355 while (check_new(st, magic_pointer)) {
eee00145 356 st->total_size += sizeof(MAGIC);
9847261d 357 /* magic vtables aren't freed when magic is freed, so don't count them.
358 (They are static structures. Anything that assumes otherwise is buggy.)
359 */
360
6a9ad7ec 361
1a36ac09 362 TRY_TO_CATCH_SEGV {
b7130948 363 sv_size(aTHX_ st, magic_pointer->mg_obj, TOTAL_SIZE_RECURSION);
d1888d0b 364 if (magic_pointer->mg_len == HEf_SVKEY) {
365 sv_size(aTHX_ st, (SV *)magic_pointer->mg_ptr, TOTAL_SIZE_RECURSION);
366 }
367#if defined(PERL_MAGIC_utf8) && defined (PERL_MAGIC_UTF8_CACHESIZE)
368 else if (magic_pointer->mg_type == PERL_MAGIC_utf8) {
369 if (check_new(st, magic_pointer->mg_ptr)) {
370 st->total_size += PERL_MAGIC_UTF8_CACHESIZE * 2 * sizeof(STRLEN);
371 }
372 }
373#endif
374 else if (magic_pointer->mg_len > 0) {
375 if (check_new(st, magic_pointer->mg_ptr)) {
376 st->total_size += magic_pointer->mg_len;
377 }
378 }
6a9ad7ec 379
0964064b 380 /* Get the next in the chain */
9fc9ab86 381 magic_pointer = magic_pointer->mg_moremagic;
382 }
1a36ac09 383 CAUGHT_EXCEPTION {
a4efdff3 384 if (st->dangle_whine)
9fc9ab86 385 warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
386 }
6a9ad7ec 387 }
6a9ad7ec 388}
389
eee00145 390static void
99684fd4 391check_new_and_strlen(struct state *st, const char *const p) {
392 if(check_new(st, p))
6ec51ae0 393 st->total_size += 1 + strlen(p);
99684fd4 394}
395
396static void
eee00145 397regex_size(const REGEXP * const baseregex, struct state *st) {
c1bfd7da 398 if(!check_new(st, baseregex))
399 return;
eee00145 400 st->total_size += sizeof(REGEXP);
9fc9ab86 401#if (PERL_VERSION < 11)
6ea94d90 402 /* Note the size of the paren offset thing */
eee00145 403 st->total_size += sizeof(I32) * baseregex->nparens * 2;
404 st->total_size += strlen(baseregex->precomp);
6ea94d90 405#else
eee00145 406 st->total_size += sizeof(struct regexp);
407 st->total_size += sizeof(I32) * SvANY(baseregex)->nparens * 2;
408 /*st->total_size += strlen(SvANY(baseregex)->subbeg);*/
6ea94d90 409#endif
a4efdff3 410 if (st->go_yell && !st->regex_whine) {
6ea94d90 411 carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
a4efdff3 412 st->regex_whine = 1;
98ecbbc6 413 }
7ccc7d88 414}
415
eee00145 416static void
1e5a8ad2 417op_size(pTHX_ const OP * const baseop, struct state *st)
418{
419 TRY_TO_CATCH_SEGV {
420 TAG;
421 if(!check_new(st, baseop))
422 return;
423 TAG;
424 op_size(aTHX_ baseop->op_next, st);
425 TAG;
426 switch (cc_opclass(baseop)) {
427 case OPc_BASEOP: TAG;
428 st->total_size += sizeof(struct op);
429 TAG;break;
430 case OPc_UNOP: TAG;
431 st->total_size += sizeof(struct unop);
a0a834e7 432 op_size(aTHX_ ((UNOP *)baseop)->op_first, st);
1e5a8ad2 433 TAG;break;
434 case OPc_BINOP: TAG;
435 st->total_size += sizeof(struct binop);
a0a834e7 436 op_size(aTHX_ ((BINOP *)baseop)->op_first, st);
437 op_size(aTHX_ ((BINOP *)baseop)->op_last, st);
1e5a8ad2 438 TAG;break;
439 case OPc_LOGOP: TAG;
440 st->total_size += sizeof(struct logop);
a0a834e7 441 op_size(aTHX_ ((BINOP *)baseop)->op_first, st);
442 op_size(aTHX_ ((LOGOP *)baseop)->op_other, st);
1e5a8ad2 443 TAG;break;
177ebd37 444#ifdef OA_CONDOP
445 case OPc_CONDOP: TAG;
446 st->total_size += sizeof(struct condop);
447 op_size(aTHX_ ((BINOP *)baseop)->op_first, st);
448 op_size(aTHX_ ((CONDOP *)baseop)->op_true, st);
449 op_size(aTHX_ ((CONDOP *)baseop)->op_false, st);
450 TAG;break;
451#endif
1e5a8ad2 452 case OPc_LISTOP: TAG;
453 st->total_size += sizeof(struct listop);
a0a834e7 454 op_size(aTHX_ ((LISTOP *)baseop)->op_first, st);
455 op_size(aTHX_ ((LISTOP *)baseop)->op_last, st);
1e5a8ad2 456 TAG;break;
457 case OPc_PMOP: TAG;
458 st->total_size += sizeof(struct pmop);
a0a834e7 459 op_size(aTHX_ ((PMOP *)baseop)->op_first, st);
460 op_size(aTHX_ ((PMOP *)baseop)->op_last, st);
5a83b7cf 461#if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
a0a834e7 462 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplroot, st);
463 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplstart, st);
5a83b7cf 464#endif
c1bfd7da 465 /* This is defined away in perl 5.8.x, but it is in there for
466 5.6.x */
98ecbbc6 467#ifdef PM_GETRE
a0a834e7 468 regex_size(PM_GETRE((PMOP *)baseop), st);
98ecbbc6 469#else
a0a834e7 470 regex_size(((PMOP *)baseop)->op_pmregexp, st);
98ecbbc6 471#endif
c1bfd7da 472 TAG;break;
81f1c018 473 case OPc_SVOP: TAG;
474 st->total_size += sizeof(struct pmop);
574d9fd9 475 if (!(baseop->op_type == OP_AELEMFAST
476 && baseop->op_flags & OPf_SPECIAL)) {
477 /* not an OP_PADAV replacement */
a0a834e7 478 sv_size(aTHX_ st, ((SVOP *)baseop)->op_sv, SOME_RECURSION);
574d9fd9 479 }
81f1c018 480 TAG;break;
177ebd37 481#ifdef OA_PADOP
9fc9ab86 482 case OPc_PADOP: TAG;
eee00145 483 st->total_size += sizeof(struct padop);
99684fd4 484 TAG;break;
177ebd37 485#endif
486#ifdef OA_GVOP
487 case OPc_GVOP: TAG;
488 st->total_size += sizeof(struct gvop);
489 sv_size(aTHX_ st, ((GVOP *)baseop)->op_gv, SOME_RECURSION);
490 TAG;break;
491#endif
99684fd4 492 case OPc_PVOP: TAG;
a0a834e7 493 check_new_and_strlen(st, ((PVOP *)baseop)->op_pv);
219b7d34 494 TAG;break;
1e5a8ad2 495 case OPc_LOOP: TAG;
496 st->total_size += sizeof(struct loop);
a0a834e7 497 op_size(aTHX_ ((LOOP *)baseop)->op_first, st);
498 op_size(aTHX_ ((LOOP *)baseop)->op_last, st);
499 op_size(aTHX_ ((LOOP *)baseop)->op_redoop, st);
500 op_size(aTHX_ ((LOOP *)baseop)->op_nextop, st);
501 op_size(aTHX_ ((LOOP *)baseop)->op_lastop, st);
1e5a8ad2 502 TAG;break;
503 case OPc_COP: TAG;
9fc9ab86 504 {
505 COP *basecop;
506 basecop = (COP *)baseop;
eee00145 507 st->total_size += sizeof(struct cop);
9fc9ab86 508
509 /* Change 33656 by nicholas@mouse-mill on 2008/04/07 11:29:51
510 Eliminate cop_label from struct cop by storing a label as the first
511 entry in the hints hash. Most statements don't have labels, so this
512 will save memory. Not sure how much.
513 The check below will be incorrect fail on bleadperls
514 before 5.11 @33656, but later than 5.10, producing slightly too
515 small memory sizes on these Perls. */
b7621729 516#if (PERL_VERSION < 11)
99684fd4 517 check_new_and_strlen(st, basecop->cop_label);
b7621729 518#endif
7ccc7d88 519#ifdef USE_ITHREADS
99684fd4 520 check_new_and_strlen(st, basecop->cop_file);
697012cd 521#if PERL_VERSION < 17 || (PERL_VERSION == 17 && PERL_SUBVERSION == 0)
27423777 522 /* This pointer is owned by the COP, and freed with it. */
99684fd4 523 check_new_and_strlen(st, basecop->cop_stashpv);
7ccc7d88 524#else
27423777 525 /* A per-interpreter pointer for this stash is allocated in
526 PL_stashpad. */
527 if (check_new(st, PL_stashpad + basecop->cop_stashoff))
528 st->total_size += sizeof(PL_stashpad[basecop->cop_stashoff]);
529#endif
530#else
f3cf7e20 531 sv_size(aTHX_ st, (SV *)basecop->cop_filegv, SOME_RECURSION);
7ccc7d88 532#endif
533
9fc9ab86 534 }
535 TAG;break;
536 default:
537 TAG;break;
538 }
539 }
1a36ac09 540 CAUGHT_EXCEPTION {
a4efdff3 541 if (st->dangle_whine)
9fc9ab86 542 warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
7ccc7d88 543 }
7ccc7d88 544}
6a9ad7ec 545
3d18ea10 546static void
547hek_size(pTHX_ struct state *st, HEK *hek, U32 shared)
548{
549 /* Hash keys can be shared. Have we seen this before? */
550 if (!check_new(st, hek))
551 return;
552 st->total_size += HEK_BASESIZE + hek->hek_len
553#if PERL_VERSION < 8
554 + 1 /* No hash key flags prior to 5.8.0 */
555#else
556 + 2
557#endif
558 ;
559 if (shared) {
560#if PERL_VERSION < 10
561 st->total_size += sizeof(struct he);
562#else
563 st->total_size += STRUCT_OFFSET(struct shared_he, shared_he_hek);
564#endif
565 }
566}
567
568
b6558d1d 569#if PERL_VERSION < 8 || PERL_SUBVERSION < 9
570# define SVt_LAST 16
24d37977 571#endif
572
f73dcfce 573#ifdef PURIFY
574# define MAYBE_PURIFY(normal, pure) (pure)
575# define MAYBE_OFFSET(struct_name, member) 0
576#else
577# define MAYBE_PURIFY(normal, pure) (normal)
578# define MAYBE_OFFSET(struct_name, member) STRUCT_OFFSET(struct_name, member)
579#endif
580
b6558d1d 581const U8 body_sizes[SVt_LAST] = {
582#if PERL_VERSION < 9
f73dcfce 583 0, /* SVt_NULL */
584 MAYBE_PURIFY(sizeof(IV), sizeof(XPVIV)), /* SVt_IV */
585 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
586 sizeof(XRV), /* SVt_RV */
587 sizeof(XPV), /* SVt_PV */
588 sizeof(XPVIV), /* SVt_PVIV */
589 sizeof(XPVNV), /* SVt_PVNV */
590 sizeof(XPVMG), /* SVt_PVMG */
591 sizeof(XPVBM), /* SVt_PVBM */
592 sizeof(XPVLV), /* SVt_PVLV */
593 sizeof(XPVAV), /* SVt_PVAV */
594 sizeof(XPVHV), /* SVt_PVHV */
595 sizeof(XPVCV), /* SVt_PVCV */
596 sizeof(XPVGV), /* SVt_PVGV */
597 sizeof(XPVFM), /* SVt_PVFM */
598 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 599#elif PERL_VERSION == 10 && PERL_SUBVERSION == 0
f73dcfce 600 0, /* SVt_NULL */
601 0, /* SVt_BIND */
602 0, /* SVt_IV */
603 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
604 0, /* SVt_RV */
605 MAYBE_PURIFY(sizeof(xpv_allocated), sizeof(XPV)), /* SVt_PV */
606 MAYBE_PURIFY(sizeof(xpviv_allocated), sizeof(XPVIV)),/* SVt_PVIV */
607 sizeof(XPVNV), /* SVt_PVNV */
608 sizeof(XPVMG), /* SVt_PVMG */
609 sizeof(XPVGV), /* SVt_PVGV */
610 sizeof(XPVLV), /* SVt_PVLV */
611 MAYBE_PURIFY(sizeof(xpvav_allocated), sizeof(XPVAV)),/* SVt_PVAV */
612 MAYBE_PURIFY(sizeof(xpvhv_allocated), sizeof(XPVHV)),/* SVt_PVHV */
613 MAYBE_PURIFY(sizeof(xpvcv_allocated), sizeof(XPVCV)),/* SVt_PVCV */
614 MAYBE_PURIFY(sizeof(xpvfm_allocated), sizeof(XPVFM)),/* SVt_PVFM */
615 sizeof(XPVIO), /* SVt_PVIO */
b6558d1d 616#elif PERL_VERSION == 10 && PERL_SUBVERSION == 1
f73dcfce 617 0, /* SVt_NULL */
618 0, /* SVt_BIND */
619 0, /* SVt_IV */
620 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
621 0, /* SVt_RV */
622 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
623 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
624 sizeof(XPVNV), /* SVt_PVNV */
625 sizeof(XPVMG), /* SVt_PVMG */
626 sizeof(XPVGV), /* SVt_PVGV */
627 sizeof(XPVLV), /* SVt_PVLV */
628 sizeof(XPVAV) - MAYBE_OFFSET(XPVAV, xav_fill), /* SVt_PVAV */
629 sizeof(XPVHV) - MAYBE_OFFSET(XPVHV, xhv_fill), /* SVt_PVHV */
630 sizeof(XPVCV) - MAYBE_OFFSET(XPVCV, xpv_cur), /* SVt_PVCV */
631 sizeof(XPVFM) - MAYBE_OFFSET(XPVFM, xpv_cur), /* SVt_PVFM */
632 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 633#elif PERL_VERSION < 13
f73dcfce 634 0, /* SVt_NULL */
635 0, /* SVt_BIND */
636 0, /* SVt_IV */
637 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
638 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
639 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
640 sizeof(XPVNV), /* SVt_PVNV */
641 sizeof(XPVMG), /* SVt_PVMG */
642 sizeof(regexp) - MAYBE_OFFSET(regexp, xpv_cur), /* SVt_REGEXP */
643 sizeof(XPVGV), /* SVt_PVGV */
644 sizeof(XPVLV), /* SVt_PVLV */
645 sizeof(XPVAV) - MAYBE_OFFSET(XPVAV, xav_fill), /* SVt_PVAV */
646 sizeof(XPVHV) - MAYBE_OFFSET(XPVHV, xhv_fill), /* SVt_PVHV */
647 sizeof(XPVCV) - MAYBE_OFFSET(XPVCV, xpv_cur), /* SVt_PVCV */
648 sizeof(XPVFM) - MAYBE_OFFSET(XPVFM, xpv_cur), /* SVt_PVFM */
649 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 650#else
f73dcfce 651 0, /* SVt_NULL */
652 0, /* SVt_BIND */
653 0, /* SVt_IV */
654 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
655 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
656 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
657 sizeof(XPVNV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVNV */
658 sizeof(XPVMG), /* SVt_PVMG */
659 sizeof(regexp), /* SVt_REGEXP */
660 sizeof(XPVGV), /* SVt_PVGV */
661 sizeof(XPVLV), /* SVt_PVLV */
662 sizeof(XPVAV), /* SVt_PVAV */
663 sizeof(XPVHV), /* SVt_PVHV */
664 sizeof(XPVCV), /* SVt_PVCV */
665 sizeof(XPVFM), /* SVt_PVFM */
666 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 667#endif
668};
669
e0d4117e 670#ifdef PadlistNAMES
671static void
672padlist_size(pTHX_ struct state *const st, const PADLIST * const padl,
673 const int recurse) {
674 SSize_t i;
675 if (!check_new(st, padl))
676 return;
677 /* This relies on PADNAMELIST and PAD being typedefed to AV. If that
678 ever changes, this code will need an update. */
679 st->total_size += sizeof(PADLIST);
680 sv_size(aTHX_ st, (SV*)PadlistNAMES(padl), recurse);
681 i = PadlistMAX(padl) + 1;
682 st->total_size += sizeof(PAD*) * i;
683 while (--i)
684 sv_size(aTHX_ st, (SV*)PadlistARRAY(padl)[i], recurse);
685}
686#else
687static void
688padlist_size(pTHX_ struct state *const st, const AV * const padl,
689 const int recurse) {
690 sv_size(aTHX_ st, (SV*)padl, recurse);
691}
692#endif
693
a5c6bdd7 694static void
db519f11 695sv_size(pTHX_ struct state *const st, const SV * const orig_thing,
f3cf7e20 696 const int recurse) {
9fc9ab86 697 const SV *thing = orig_thing;
b6558d1d 698 U32 type;
eee00145 699
81f1c018 700 if(!check_new(st, thing))
a5c6bdd7 701 return;
81f1c018 702
b6558d1d 703 type = SvTYPE(thing);
704 if (type > SVt_LAST) {
705 warn("Devel::Size: Unknown variable type: %d encountered\n", type);
a5c6bdd7 706 return;
b6558d1d 707 }
708 st->total_size += sizeof(SV) + body_sizes[type];
b1e5ad85 709
ad06a650 710 if (SvMAGICAL(thing)) {
696b99e2 711 magic_size(aTHX_ thing, st);
712 }
713
b6558d1d 714 switch (type) {
715#if (PERL_VERSION < 11)
e98cedbf 716 /* Is it a reference? */
9fc9ab86 717 case SVt_RV: TAG;
b6558d1d 718#else
719 case SVt_IV: TAG;
24d37977 720#endif
81f1c018 721 if(recurse && SvROK(thing))
f3cf7e20 722 sv_size(aTHX_ st, SvRV_const(thing), recurse);
9fc9ab86 723 TAG;break;
267703fd 724
9fc9ab86 725 case SVt_PVAV: TAG;
e98cedbf 726 /* Is there anything in the array? */
727 if (AvMAX(thing) != -1) {
c8db37d3 728 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
eee00145 729 st->total_size += sizeof(SV *) * (AvMAX(thing) + 1);
730 dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
6c5ddc0d 731
732 if (recurse >= TOTAL_SIZE_RECURSION) {
733 SSize_t i = AvFILLp(thing) + 1;
734
735 while (i--)
736 sv_size(aTHX_ st, AvARRAY(thing)[i], recurse);
737 }
e98cedbf 738 }
739 /* Add in the bits on the other side of the beginning */
0430b7f7 740
b7621729 741 dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
eee00145 742 st->total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
0430b7f7 743
744 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
b1e5ad85 745 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
0430b7f7 746 if (AvALLOC(thing) != 0) {
eee00145 747 st->total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
0430b7f7 748 }
795fc84c 749#if (PERL_VERSION < 9)
750 /* Is there something hanging off the arylen element?
751 Post 5.9.something this is stored in magic, so will be found there,
752 and Perl_av_arylen_p() takes a non-const AV*, hence compilers rightly
753 complain about AvARYLEN() passing thing to it. */
f3cf7e20 754 sv_size(aTHX_ st, AvARYLEN(thing), recurse);
795fc84c 755#endif
9fc9ab86 756 TAG;break;
757 case SVt_PVHV: TAG;
a6ea0805 758 /* Now the array of buckets */
eee00145 759 st->total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
a6ea0805 760 /* Now walk the bucket chain */
6a9ad7ec 761 if (HvARRAY(thing)) {
a6ea0805 762 HE *cur_entry;
9fc9ab86 763 UV cur_bucket = 0;
a6ea0805 764 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
9fc9ab86 765 cur_entry = *(HvARRAY(thing) + cur_bucket);
766 while (cur_entry) {
eee00145 767 st->total_size += sizeof(HE);
3d18ea10 768 hek_size(aTHX_ st, cur_entry->hent_hek, HvSHAREKEYS(thing));
f3cf7e20 769 if (recurse >= TOTAL_SIZE_RECURSION)
770 sv_size(aTHX_ st, HeVAL(cur_entry), recurse);
9fc9ab86 771 cur_entry = cur_entry->hent_next;
772 }
a6ea0805 773 }
774 }
78037efb 775#ifdef HvAUX
776 if (SvOOK(thing)) {
777 /* This direct access is arguably "naughty": */
778 struct mro_meta *meta = HvAUX(thing)->xhv_mro_meta;
b3a37f1a 779#if PERL_VERSION > 13 || PERL_SUBVERSION > 8
780 /* As is this: */
781 I32 count = HvAUX(thing)->xhv_name_count;
782
783 if (count) {
784 HEK **names = HvAUX(thing)->xhv_name_u.xhvnameu_names;
785 if (count < 0)
786 count = -count;
787 while (--count)
788 hek_size(aTHX_ st, names[count], 1);
789 }
790 else
791#endif
792 {
793 hek_size(aTHX_ st, HvNAME_HEK(thing), 1);
794 }
795
78037efb 796 st->total_size += sizeof(struct xpvhv_aux);
78037efb 797 if (meta) {
798 st->total_size += sizeof(struct mro_meta);
799 sv_size(aTHX_ st, (SV *)meta->mro_nextmethod, TOTAL_SIZE_RECURSION);
800#if PERL_VERSION > 10 || (PERL_VERSION == 10 && PERL_SUBVERSION > 0)
801 sv_size(aTHX_ st, (SV *)meta->isa, TOTAL_SIZE_RECURSION);
802#endif
803#if PERL_VERSION > 10
804 sv_size(aTHX_ st, (SV *)meta->mro_linear_all, TOTAL_SIZE_RECURSION);
805 sv_size(aTHX_ st, meta->mro_linear_current, TOTAL_SIZE_RECURSION);
806#else
807 sv_size(aTHX_ st, (SV *)meta->mro_linear_dfs, TOTAL_SIZE_RECURSION);
808 sv_size(aTHX_ st, (SV *)meta->mro_linear_c3, TOTAL_SIZE_RECURSION);
809#endif
810 }
811 }
812#else
813 check_new_and_strlen(st, HvNAME_get(thing));
814#endif
9fc9ab86 815 TAG;break;
267703fd 816
817
818 case SVt_PVFM: TAG;
e0d4117e 819 padlist_size(aTHX_ st, CvPADLIST(thing), SOME_RECURSION);
267703fd 820 sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), recurse);
821
822 if (st->go_yell && !st->fm_whine) {
823 carp("Devel::Size: Calculated sizes for FMs are incomplete");
824 st->fm_whine = 1;
825 }
826 goto freescalar;
827
9fc9ab86 828 case SVt_PVCV: TAG;
f3cf7e20 829 sv_size(aTHX_ st, (SV *)CvSTASH(thing), SOME_RECURSION);
830 sv_size(aTHX_ st, (SV *)SvSTASH(thing), SOME_RECURSION);
831 sv_size(aTHX_ st, (SV *)CvGV(thing), SOME_RECURSION);
e0d4117e 832 padlist_size(aTHX_ st, CvPADLIST(thing), SOME_RECURSION);
f3cf7e20 833 sv_size(aTHX_ st, (SV *)CvOUTSIDE(thing), recurse);
66f50dda 834 if (CvISXSUB(thing)) {
f3cf7e20 835 sv_size(aTHX_ st, cv_const_sv((CV *)thing), recurse);
cd50b0d7 836 } else if (CvROOT(thing)) {
1e5a8ad2 837 op_size(aTHX_ CvSTART(thing), st);
838 op_size(aTHX_ CvROOT(thing), st);
7ccc7d88 839 }
267703fd 840 goto freescalar;
841
842 case SVt_PVIO: TAG;
267703fd 843 /* Some embedded char pointers */
844 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_top_name);
845 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_fmt_name);
846 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_bottom_name);
847 /* Throw the GVs on the list to be walked if they're not-null */
848 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_top_gv, recurse);
849 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv, recurse);
850 sv_size(aTHX_ st, (SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv, recurse);
851
852 /* Only go trotting through the IO structures if they're really
853 trottable. If USE_PERLIO is defined we can do this. If
854 not... we can't, so we don't even try */
855#ifdef USE_PERLIO
856 /* Dig into xio_ifp and xio_ofp here */
857 warn("Devel::Size: Can't size up perlio layers yet\n");
858#endif
859 goto freescalar;
860
267703fd 861 case SVt_PVLV: TAG;
267703fd 862#if (PERL_VERSION < 9)
863 goto freescalar;
267703fd 864#endif
7ccc7d88 865
9fc9ab86 866 case SVt_PVGV: TAG;
4a3d023d 867 if(isGV_with_GP(thing)) {
638a265a 868#ifdef GvNAME_HEK
869 hek_size(aTHX_ st, GvNAME_HEK(thing), 1);
870#else
4a3d023d 871 st->total_size += GvNAMELEN(thing);
638a265a 872#endif
15588e9c 873#ifdef GvFILE_HEK
874 hek_size(aTHX_ st, GvFILE_HEK(thing), 1);
875#elif defined(GvFILE)
2b217e71 876# if !defined(USE_ITHREADS) || (PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8))
877 /* With itreads, before 5.8.9, this can end up pointing to freed memory
878 if the GV was created in an eval, as GvFILE() points to CopFILE(),
879 and the relevant COP has been freed on scope cleanup after the eval.
880 5.8.9 adds a binary compatible fudge that catches the vast majority
881 of cases. 5.9.something added a proper fix, by converting the GP to
882 use a shared hash key (porperly reference counted), instead of a
883 char * (owned by who knows? possibly no-one now) */
4a3d023d 884 check_new_and_strlen(st, GvFILE(thing));
2b217e71 885# endif
78dfb4e7 886#endif
4a3d023d 887 /* Is there something hanging off the glob? */
888 if (check_new(st, GvGP(thing))) {
889 st->total_size += sizeof(GP);
f3cf7e20 890 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_sv), recurse);
891 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_form), recurse);
892 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_av), recurse);
893 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_hv), recurse);
894 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_egv), recurse);
895 sv_size(aTHX_ st, (SV *)(GvGP(thing)->gp_cv), recurse);
4a3d023d 896 }
267703fd 897#if (PERL_VERSION >= 9)
898 TAG; break;
899#endif
5c2e1b12 900 }
b6558d1d 901#if PERL_VERSION <= 8
902 case SVt_PVBM: TAG;
903#endif
267703fd 904 case SVt_PVMG: TAG;
267703fd 905 case SVt_PVNV: TAG;
267703fd 906 case SVt_PVIV: TAG;
267703fd 907 case SVt_PV: TAG;
267703fd 908 freescalar:
909 if(recurse && SvROK(thing))
910 sv_size(aTHX_ st, SvRV_const(thing), recurse);
924d9c4e 911 else if (SvIsCOW_shared_hash(thing))
912 hek_size(aTHX_ st, SvSHARED_HEK_FROM_PV(SvPVX(thing)), 1);
267703fd 913 else
914 st->total_size += SvLEN(thing);
915
916 if(SvOOK(thing)) {
95dc1714 917 STRLEN len;
918 SvOOK_offset(thing, len);
919 st->total_size += len;
ebb2c5b9 920 }
9fc9ab86 921 TAG;break;
5073b933 922
e98cedbf 923 }
a5c6bdd7 924 return;
e98cedbf 925}
926
a4efdff3 927static struct state *
928new_state(pTHX)
65db36c0 929{
930 SV *warn_flag;
a4efdff3 931 struct state *st;
d9b022a1 932
a4efdff3 933 Newxz(st, 1, struct state);
934 st->go_yell = TRUE;
65db36c0 935 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
a4efdff3 936 st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 937 }
938 if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
a4efdff3 939 st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 940 }
a52ceccd 941 check_new(st, &PL_sv_undef);
942 check_new(st, &PL_sv_no);
943 check_new(st, &PL_sv_yes);
6389ea67 944#if PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 0)
945 check_new(st, &PL_sv_placeholder);
946#endif
a4efdff3 947 return st;
65db36c0 948}
949
9fc9ab86 950MODULE = Devel::Size PACKAGE = Devel::Size
e98cedbf 951
fea63ffa 952PROTOTYPES: DISABLE
953
eee00145 954UV
a6ea0805 955size(orig_thing)
956 SV *orig_thing
13683e3a 957ALIAS:
958 total_size = TOTAL_SIZE_RECURSION
e98cedbf 959CODE:
960{
6a9ad7ec 961 SV *thing = orig_thing;
a4efdff3 962 struct state *st = new_state(aTHX);
ebb2c5b9 963
6a9ad7ec 964 /* If they passed us a reference then dereference it. This is the
965 only way we can check the sizes of arrays and hashes */
b7621729 966 if (SvROK(thing)) {
967 thing = SvRV(thing);
968 }
b7621729 969
13683e3a 970 sv_size(aTHX_ st, thing, ix);
eee00145 971 RETVAL = st->total_size;
a4efdff3 972 free_state(st);
6a9ad7ec 973}
974OUTPUT:
975 RETVAL