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