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