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