Eliminate conditional 5.11/older conditional code that is actually unnecessary.
[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
87372f42 15
9fc9ab86 16#ifdef _MSC_VER
1a36ac09 17/* "structured exception" handling is a Microsoft extension to C and C++.
18 It's *not* C++ exception handling - C++ exception handling can't capture
19 SEGVs and suchlike, whereas this can. There's no known analagous
20 functionality on other platforms. */
21# include <excpt.h>
22# define TRY_TO_CATCH_SEGV __try
23# define CAUGHT_EXCEPTION __except(EXCEPTION EXCEPTION_EXECUTE_HANDLER)
9fc9ab86 24#else
1a36ac09 25# define TRY_TO_CATCH_SEGV if(1)
26# define CAUGHT_EXCEPTION else
9fc9ab86 27#endif
28
29#ifdef __GNUC__
30# define __attribute__(x)
31#endif
32
b7621729 33#if 0 && defined(DEBUGGING)
34#define dbg_printf(x) printf x
35#else
36#define dbg_printf(x)
37#endif
98ecbbc6 38
0964064b 39#define TAG /* printf( "# %s(%d)\n", __FILE__, __LINE__ ) */
6a9ad7ec 40#define carp puts
9fc9ab86 41
30fe4f47 42/* The idea is to have a tree structure to store 1 bit per possible pointer
43 address. The lowest 16 bits are stored in a block of 8092 bytes.
44 The blocks are in a 256-way tree, indexed by the reset of the pointer.
45 This can cope with 32 and 64 bit pointers, and any address space layout,
46 without excessive memory needs. The assumption is that your CPU cache
47 works :-) (And that we're not going to bust it) */
48
9fc9ab86 49#define ALIGN_BITS ( sizeof(void*) >> 1 )
30fe4f47 50#define BYTE_BITS 3
51#define LEAF_BITS (16 - BYTE_BITS)
52#define LEAF_MASK 0x1FFF
9fc9ab86 53
65db36c0 54struct state {
55 bool regex_whine;
56 bool fm_whine;
57 bool dangle_whine;
58 bool go_yell;
59 /* My hunch (not measured) is that for most architectures pointers will
60 start with 0 bits, hence the start of this array will be hot, and the
61 end unused. So put the flags next to the hot end. */
62 void *tracking[256];
63};
64
9fc9ab86 65/*
66 Checks to see if thing is in the bitstring.
67 Returns true or false, and
68 notes thing in the segmented bitstring.
69 */
2eb93d08 70static bool
a4efdff3 71check_new(struct state *st, const void *const p) {
30fe4f47 72 unsigned int bits = 8 * sizeof(void*);
73 const size_t raw_p = PTR2nat(p);
74 /* This effectively rotates the value right by the number of low always-0
75 bits in an aligned pointer. The assmption is that most (if not all)
76 pointers are aligned, and these will be in the same chain of nodes
77 (and hence hot in the cache) but we can still deal with any unaligned
78 pointers. */
79 const size_t cooked_p
80 = (raw_p >> ALIGN_BITS) | (raw_p << (bits - BYTE_BITS));
81 const U8 this_bit = 1 << (cooked_p & 0x7);
82 U8 **leaf_p;
83 U8 *leaf;
84 unsigned int i;
2640cff1 85 void **tv_p;
30fe4f47 86
2640cff1 87
88 if (NULL == p || NULL == st) return FALSE;
89 tv_p = (void **) (st->tracking);
1a36ac09 90 TRY_TO_CATCH_SEGV {
2eb93d08 91 const char c = *(const char *)p;
9fc9ab86 92 }
1a36ac09 93 CAUGHT_EXCEPTION {
a4efdff3 94 if (st->dangle_whine)
9fc9ab86 95 warn( "Devel::Size: Encountered invalid pointer: %p\n", p );
96 return FALSE;
97 }
9fc9ab86 98 TAG;
30fe4f47 99
100 bits -= 8;
101 /* bits now 24 (32 bit pointers) or 56 (64 bit pointers) */
102
103 /* First level is always present. */
104 do {
105 i = (unsigned int)((cooked_p >> bits) & 0xFF);
106 if (!tv_p[i])
107 Newxz(tv_p[i], 256, void *);
108 tv_p = (void **)(tv_p[i]);
109 bits -= 8;
110 } while (bits > LEAF_BITS + BYTE_BITS);
111 /* bits now 16 always */
5f04c81d 112#if !defined(MULTIPLICITY) || PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8)
113 /* 5.8.8 and early have an assert() macro that uses Perl_croak, hence needs
114 a my_perl under multiplicity */
30fe4f47 115 assert(bits == 16);
5f04c81d 116#endif
30fe4f47 117 leaf_p = (U8 **)tv_p;
118 i = (unsigned int)((cooked_p >> bits) & 0xFF);
119 if (!leaf_p[i])
120 Newxz(leaf_p[i], 1 << LEAF_BITS, U8);
121 leaf = leaf_p[i];
122
9fc9ab86 123 TAG;
30fe4f47 124
125 i = (unsigned int)((cooked_p >> BYTE_BITS) & LEAF_MASK);
126
127 if(leaf[i] & this_bit)
128 return FALSE;
129
130 leaf[i] |= this_bit;
9fc9ab86 131 return TRUE;
132}
133
e9716740 134static void
30fe4f47 135free_tracking_at(void **tv, int level)
136{
137 int i = 255;
138
139 if (--level) {
140 /* Nodes */
141 do {
142 if (tv[i]) {
143 free_tracking_at(tv[i], level);
144 Safefree(tv[i]);
145 }
146 } while (i--);
147 } else {
148 /* Leaves */
149 do {
150 if (tv[i])
151 Safefree(tv[i]);
152 } while (i--);
153 }
154}
155
156static void
a4efdff3 157free_state(struct state *st)
e9716740 158{
30fe4f47 159 const int top_level = (sizeof(void *) * 8 - LEAF_BITS - BYTE_BITS) / 8;
a4efdff3 160 free_tracking_at((void **)st->tracking, top_level);
161 Safefree(st);
e9716740 162}
163
a4efdff3 164static UV thing_size(pTHX_ const SV *const, struct state *);
7ccc7d88 165typedef enum {
9fc9ab86 166 OPc_NULL, /* 0 */
167 OPc_BASEOP, /* 1 */
168 OPc_UNOP, /* 2 */
169 OPc_BINOP, /* 3 */
170 OPc_LOGOP, /* 4 */
171 OPc_LISTOP, /* 5 */
172 OPc_PMOP, /* 6 */
173 OPc_SVOP, /* 7 */
174 OPc_PADOP, /* 8 */
175 OPc_PVOP, /* 9 */
176 OPc_LOOP, /* 10 */
177 OPc_COP /* 11 */
7ccc7d88 178} opclass;
179
180static opclass
9fc9ab86 181cc_opclass(const OP * const o)
7ccc7d88 182{
183 if (!o)
9fc9ab86 184 return OPc_NULL;
1a36ac09 185 TRY_TO_CATCH_SEGV {
9fc9ab86 186 if (o->op_type == 0)
187 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
7ccc7d88 188
9fc9ab86 189 if (o->op_type == OP_SASSIGN)
190 return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
7ccc7d88 191
9fc9ab86 192 #ifdef USE_ITHREADS
193 if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
194 return OPc_PADOP;
195 #endif
7ccc7d88 196
9fc9ab86 197 if ((o->op_type == OP_TRANS)) {
198 return OPc_BASEOP;
199 }
7ccc7d88 200
9fc9ab86 201 switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
202 case OA_BASEOP: TAG;
203 return OPc_BASEOP;
204
205 case OA_UNOP: TAG;
206 return OPc_UNOP;
207
208 case OA_BINOP: TAG;
209 return OPc_BINOP;
62691e7c 210
9fc9ab86 211 case OA_LOGOP: TAG;
212 return OPc_LOGOP;
7ccc7d88 213
9fc9ab86 214 case OA_LISTOP: TAG;
215 return OPc_LISTOP;
7ccc7d88 216
9fc9ab86 217 case OA_PMOP: TAG;
218 return OPc_PMOP;
7ccc7d88 219
9fc9ab86 220 case OA_SVOP: TAG;
221 return OPc_SVOP;
7ccc7d88 222
9fc9ab86 223 case OA_PADOP: TAG;
224 return OPc_PADOP;
7ccc7d88 225
9fc9ab86 226 case OA_PVOP_OR_SVOP: TAG;
227 /*
228 * Character translations (tr///) are usually a PVOP, keeping a
229 * pointer to a table of shorts used to look up translations.
230 * Under utf8, however, a simple table isn't practical; instead,
231 * the OP is an SVOP, and the SV is a reference to a swash
232 * (i.e., an RV pointing to an HV).
233 */
234 return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
235 ? OPc_SVOP : OPc_PVOP;
7ccc7d88 236
9fc9ab86 237 case OA_LOOP: TAG;
238 return OPc_LOOP;
7ccc7d88 239
9fc9ab86 240 case OA_COP: TAG;
241 return OPc_COP;
7ccc7d88 242
9fc9ab86 243 case OA_BASEOP_OR_UNOP: TAG;
7ccc7d88 244 /*
9fc9ab86 245 * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on
246 * whether parens were seen. perly.y uses OPf_SPECIAL to
247 * signal whether a BASEOP had empty parens or none.
248 * Some other UNOPs are created later, though, so the best
249 * test is OPf_KIDS, which is set in newUNOP.
7ccc7d88 250 */
9fc9ab86 251 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
252
253 case OA_FILESTATOP: TAG;
254 /*
255 * The file stat OPs are created via UNI(OP_foo) in toke.c but use
256 * the OPf_REF flag to distinguish between OP types instead of the
257 * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we
258 * return OPc_UNOP so that walkoptree can find our children. If
259 * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set
260 * (no argument to the operator) it's an OP; with OPf_REF set it's
261 * an SVOP (and op_sv is the GV for the filehandle argument).
262 */
263 return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
264 #ifdef USE_ITHREADS
265 (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
266 #else
267 (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
268 #endif
269 case OA_LOOPEXOP: TAG;
270 /*
271 * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a
272 * label was omitted (in which case it's a BASEOP) or else a term was
273 * seen. In this last case, all except goto are definitely PVOP but
274 * goto is either a PVOP (with an ordinary constant label), an UNOP
275 * with OPf_STACKED (with a non-constant non-sub) or an UNOP for
276 * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to
277 * get set.
278 */
279 if (o->op_flags & OPf_STACKED)
280 return OPc_UNOP;
281 else if (o->op_flags & OPf_SPECIAL)
282 return OPc_BASEOP;
283 else
284 return OPc_PVOP;
285 }
286 warn("Devel::Size: Can't determine class of operator %s, assuming BASEOP\n",
287 PL_op_name[o->op_type]);
288 }
1a36ac09 289 CAUGHT_EXCEPTION { }
7ccc7d88 290 return OPc_BASEOP;
291}
292
6a9ad7ec 293
a6ea0805 294#if !defined(NV)
295#define NV double
296#endif
297
6a9ad7ec 298/* Figure out how much magic is attached to the SV and return the
299 size */
a4efdff3 300IV magic_size(const SV * const thing, struct state *st) {
6a9ad7ec 301 IV total_size = 0;
302 MAGIC *magic_pointer;
303
304 /* Is there any? */
305 if (!SvMAGIC(thing)) {
306 /* No, bail */
307 return 0;
308 }
309
310 /* Get the base magic pointer */
311 magic_pointer = SvMAGIC(thing);
312
313 /* Have we seen the magic pointer? */
a4efdff3 314 while (magic_pointer && check_new(st, magic_pointer)) {
6a9ad7ec 315 total_size += sizeof(MAGIC);
316
1a36ac09 317 TRY_TO_CATCH_SEGV {
9fc9ab86 318 /* Have we seen the magic vtable? */
319 if (magic_pointer->mg_virtual &&
a4efdff3 320 check_new(st, magic_pointer->mg_virtual)) {
9fc9ab86 321 total_size += sizeof(MGVTBL);
322 }
6a9ad7ec 323
0964064b 324 /* Get the next in the chain */
9fc9ab86 325 magic_pointer = magic_pointer->mg_moremagic;
326 }
1a36ac09 327 CAUGHT_EXCEPTION {
a4efdff3 328 if (st->dangle_whine)
9fc9ab86 329 warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
330 }
6a9ad7ec 331 }
6a9ad7ec 332 return total_size;
333}
334
a4efdff3 335UV regex_size(const REGEXP * const baseregex, struct state *st) {
7ccc7d88 336 UV total_size = 0;
337
98ecbbc6 338 total_size += sizeof(REGEXP);
9fc9ab86 339#if (PERL_VERSION < 11)
6ea94d90 340 /* Note the size of the paren offset thing */
98ecbbc6 341 total_size += sizeof(I32) * baseregex->nparens * 2;
342 total_size += strlen(baseregex->precomp);
6ea94d90 343#else
344 total_size += sizeof(struct regexp);
345 total_size += sizeof(I32) * SvANY(baseregex)->nparens * 2;
346 /*total_size += strlen(SvANY(baseregex)->subbeg);*/
347#endif
a4efdff3 348 if (st->go_yell && !st->regex_whine) {
6ea94d90 349 carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
a4efdff3 350 st->regex_whine = 1;
98ecbbc6 351 }
352
7ccc7d88 353 return total_size;
354}
355
265a0548 356static UV
a4efdff3 357op_size(pTHX_ const OP * const baseop, struct state *st) {
7ccc7d88 358 UV total_size = 0;
1a36ac09 359 TRY_TO_CATCH_SEGV {
9fc9ab86 360 TAG;
a4efdff3 361 if (check_new(st, baseop->op_next)) {
362 total_size += op_size(aTHX_ baseop->op_next, st);
9fc9ab86 363 }
364 TAG;
365 switch (cc_opclass(baseop)) {
366 case OPc_BASEOP: TAG;
367 total_size += sizeof(struct op);
368 TAG;break;
369 case OPc_UNOP: TAG;
370 total_size += sizeof(struct unop);
a4efdff3 371 if (check_new(st, cUNOPx(baseop)->op_first)) {
372 total_size += op_size(aTHX_ cUNOPx(baseop)->op_first, st);
9fc9ab86 373 }
374 TAG;break;
375 case OPc_BINOP: TAG;
376 total_size += sizeof(struct binop);
a4efdff3 377 if (check_new(st, cBINOPx(baseop)->op_first)) {
378 total_size += op_size(aTHX_ cBINOPx(baseop)->op_first, st);
9fc9ab86 379 }
a4efdff3 380 if (check_new(st, cBINOPx(baseop)->op_last)) {
381 total_size += op_size(aTHX_ cBINOPx(baseop)->op_last, st);
9fc9ab86 382 }
383 TAG;break;
384 case OPc_LOGOP: TAG;
385 total_size += sizeof(struct logop);
a4efdff3 386 if (check_new(st, cLOGOPx(baseop)->op_first)) {
387 total_size += op_size(aTHX_ cBINOPx(baseop)->op_first, st);
9fc9ab86 388 }
a4efdff3 389 if (check_new(st, cLOGOPx(baseop)->op_other)) {
390 total_size += op_size(aTHX_ cLOGOPx(baseop)->op_other, st);
9fc9ab86 391 }
392 TAG;break;
393 case OPc_LISTOP: TAG;
394 total_size += sizeof(struct listop);
a4efdff3 395 if (check_new(st, cLISTOPx(baseop)->op_first)) {
396 total_size += op_size(aTHX_ cLISTOPx(baseop)->op_first, st);
9fc9ab86 397 }
a4efdff3 398 if (check_new(st, cLISTOPx(baseop)->op_last)) {
399 total_size += op_size(aTHX_ cLISTOPx(baseop)->op_last, st);
9fc9ab86 400 }
401 TAG;break;
402 case OPc_PMOP: TAG;
403 total_size += sizeof(struct pmop);
a4efdff3 404 if (check_new(st, cPMOPx(baseop)->op_first)) {
405 total_size += op_size(aTHX_ cPMOPx(baseop)->op_first, st);
9fc9ab86 406 }
a4efdff3 407 if (check_new(st, cPMOPx(baseop)->op_last)) {
408 total_size += op_size(aTHX_ cPMOPx(baseop)->op_last, st);
9fc9ab86 409 }
5a83b7cf 410#if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
a4efdff3 411 if (check_new(st, cPMOPx(baseop)->op_pmreplroot)) {
412 total_size += op_size(aTHX_ cPMOPx(baseop)->op_pmreplroot, st);
9fc9ab86 413 }
a4efdff3 414 if (check_new(st, cPMOPx(baseop)->op_pmreplstart)) {
415 total_size += op_size(aTHX_ cPMOPx(baseop)->op_pmreplstart, st);
9fc9ab86 416 }
a4efdff3 417 if (check_new(st, cPMOPx(baseop)->op_pmnext)) {
418 total_size += op_size(aTHX_ (OP *)cPMOPx(baseop)->op_pmnext, st);
9fc9ab86 419 }
5a83b7cf 420#endif
9fc9ab86 421 /* This is defined away in perl 5.8.x, but it is in there for
422 5.6.x */
98ecbbc6 423#ifdef PM_GETRE
a4efdff3 424 if (check_new(st, PM_GETRE((cPMOPx(baseop))))) {
425 total_size += regex_size(PM_GETRE(cPMOPx(baseop)), st);
9fc9ab86 426 }
98ecbbc6 427#else
a4efdff3 428 if (check_new(st, cPMOPx(baseop)->op_pmregexp)) {
429 total_size += regex_size(cPMOPx(baseop)->op_pmregexp, st);
9fc9ab86 430 }
98ecbbc6 431#endif
9fc9ab86 432 TAG;break;
433 case OPc_SVOP: TAG;
434 total_size += sizeof(struct pmop);
a4efdff3 435 if (check_new(st, cSVOPx(baseop)->op_sv)) {
436 total_size += thing_size(aTHX_ cSVOPx(baseop)->op_sv, st);
9fc9ab86 437 }
438 TAG;break;
439 case OPc_PADOP: TAG;
440 total_size += sizeof(struct padop);
441 TAG;break;
442 case OPc_PVOP: TAG;
a4efdff3 443 if (check_new(st, cPVOPx(baseop)->op_pv)) {
9fc9ab86 444 total_size += strlen(cPVOPx(baseop)->op_pv);
445 }
446 case OPc_LOOP: TAG;
447 total_size += sizeof(struct loop);
a4efdff3 448 if (check_new(st, cLOOPx(baseop)->op_first)) {
449 total_size += op_size(aTHX_ cLOOPx(baseop)->op_first, st);
9fc9ab86 450 }
a4efdff3 451 if (check_new(st, cLOOPx(baseop)->op_last)) {
452 total_size += op_size(aTHX_ cLOOPx(baseop)->op_last, st);
9fc9ab86 453 }
a4efdff3 454 if (check_new(st, cLOOPx(baseop)->op_redoop)) {
455 total_size += op_size(aTHX_ cLOOPx(baseop)->op_redoop, st);
9fc9ab86 456 }
a4efdff3 457 if (check_new(st, cLOOPx(baseop)->op_nextop)) {
458 total_size += op_size(aTHX_ cLOOPx(baseop)->op_nextop, st);
9fc9ab86 459 }
a4efdff3 460 if (check_new(st, cLOOPx(baseop)->op_lastop)) {
461 total_size += op_size(aTHX_ cLOOPx(baseop)->op_lastop, st);
9fc9ab86 462 }
463
464 TAG;break;
465 case OPc_COP: TAG;
466 {
467 COP *basecop;
468 basecop = (COP *)baseop;
469 total_size += sizeof(struct cop);
470
471 /* Change 33656 by nicholas@mouse-mill on 2008/04/07 11:29:51
472 Eliminate cop_label from struct cop by storing a label as the first
473 entry in the hints hash. Most statements don't have labels, so this
474 will save memory. Not sure how much.
475 The check below will be incorrect fail on bleadperls
476 before 5.11 @33656, but later than 5.10, producing slightly too
477 small memory sizes on these Perls. */
b7621729 478#if (PERL_VERSION < 11)
a4efdff3 479 if (check_new(st, basecop->cop_label)) {
9fc9ab86 480 total_size += strlen(basecop->cop_label);
481 }
b7621729 482#endif
7ccc7d88 483#ifdef USE_ITHREADS
a4efdff3 484 if (check_new(st, basecop->cop_file)) {
9fc9ab86 485 total_size += strlen(basecop->cop_file);
486 }
a4efdff3 487 if (check_new(st, basecop->cop_stashpv)) {
9fc9ab86 488 total_size += strlen(basecop->cop_stashpv);
489 }
7ccc7d88 490#else
a4efdff3 491 if (check_new(st, basecop->cop_stash)) {
492 total_size += thing_size(aTHX_ (SV *)basecop->cop_stash, st);
9fc9ab86 493 }
a4efdff3 494 if (check_new(st, basecop->cop_filegv)) {
495 total_size += thing_size(aTHX_ (SV *)basecop->cop_filegv, st);
9fc9ab86 496 }
7ccc7d88 497#endif
498
9fc9ab86 499 }
500 TAG;break;
501 default:
502 TAG;break;
503 }
504 }
1a36ac09 505 CAUGHT_EXCEPTION {
a4efdff3 506 if (st->dangle_whine)
9fc9ab86 507 warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
7ccc7d88 508 }
509 return total_size;
510}
6a9ad7ec 511
24d37977 512#if PERL_VERSION > 9 || (PERL_VERSION == 9 && PERL_SUBVERSION > 2)
513# define NEW_HEAD_LAYOUT
514#endif
515
265a0548 516static UV
a4efdff3 517thing_size(pTHX_ const SV * const orig_thing, struct state *st) {
9fc9ab86 518 const SV *thing = orig_thing;
e98cedbf 519 UV total_size = sizeof(SV);
b1e5ad85 520
e98cedbf 521 switch (SvTYPE(thing)) {
522 /* Is it undef? */
9fc9ab86 523 case SVt_NULL: TAG;
524 TAG;break;
e98cedbf 525 /* Just a plain integer. This will be differently sized depending
526 on whether purify's been compiled in */
9fc9ab86 527 case SVt_IV: TAG;
24d37977 528#ifndef NEW_HEAD_LAYOUT
529# ifdef PURIFY
e98cedbf 530 total_size += sizeof(sizeof(XPVIV));
24d37977 531# else
e98cedbf 532 total_size += sizeof(IV);
24d37977 533# endif
e98cedbf 534#endif
9fc9ab86 535 TAG;break;
e98cedbf 536 /* Is it a float? Like the int, it depends on purify */
9fc9ab86 537 case SVt_NV: TAG;
e98cedbf 538#ifdef PURIFY
539 total_size += sizeof(sizeof(XPVNV));
540#else
541 total_size += sizeof(NV);
542#endif
9fc9ab86 543 TAG;break;
544#if (PERL_VERSION < 11)
e98cedbf 545 /* Is it a reference? */
9fc9ab86 546 case SVt_RV: TAG;
24d37977 547#ifndef NEW_HEAD_LAYOUT
e98cedbf 548 total_size += sizeof(XRV);
24d37977 549#endif
9fc9ab86 550 TAG;break;
6ea94d90 551#endif
e98cedbf 552 /* How about a plain string? In which case we need to add in how
553 much has been allocated */
9fc9ab86 554 case SVt_PV: TAG;
e98cedbf 555 total_size += sizeof(XPV);
0e1f978f 556 total_size += SvROK(thing) ? thing_size(aTHX_ SvRV_const(thing), st) : SvLEN(thing);
9fc9ab86 557 TAG;break;
e98cedbf 558 /* A string with an integer part? */
9fc9ab86 559 case SVt_PVIV: TAG;
e98cedbf 560 total_size += sizeof(XPVIV);
0e1f978f 561 total_size += SvROK(thing) ? thing_size(aTHX_ SvRV_const(thing), st) : SvLEN(thing);
0430b7f7 562 if(SvOOK(thing)) {
563 total_size += SvIVX(thing);
9fc9ab86 564 }
565 TAG;break;
c8db37d3 566 /* A scalar/string/reference with a float part? */
9fc9ab86 567 case SVt_PVNV: TAG;
e98cedbf 568 total_size += sizeof(XPVNV);
0e1f978f 569 total_size += SvROK(thing) ? thing_size(aTHX_ SvRV_const(thing), st) : SvLEN(thing);
9fc9ab86 570 TAG;break;
571 case SVt_PVMG: TAG;
4ab42718 572 total_size += sizeof(XPVMG);
0e1f978f 573 total_size += SvROK(thing) ? thing_size(aTHX_ SvRV_const(thing), st) : SvLEN(thing);
a4efdff3 574 total_size += magic_size(thing, st);
9fc9ab86 575 TAG;break;
0430b7f7 576#if PERL_VERSION <= 8
9fc9ab86 577 case SVt_PVBM: TAG;
6a9ad7ec 578 total_size += sizeof(XPVBM);
0e1f978f 579 total_size += SvROK(thing) ? thing_size(aTHX_ SvRV_const(thing), st) : SvLEN(thing);
a4efdff3 580 total_size += magic_size(thing, st);
9fc9ab86 581 TAG;break;
0430b7f7 582#endif
9fc9ab86 583 case SVt_PVLV: TAG;
6a9ad7ec 584 total_size += sizeof(XPVLV);
0e1f978f 585 total_size += SvROK(thing) ? thing_size(aTHX_ SvRV_const(thing), st) : SvLEN(thing);
a4efdff3 586 total_size += magic_size(thing, st);
9fc9ab86 587 TAG;break;
e98cedbf 588 /* How much space is dedicated to the array? Not counting the
589 elements in the array, mind, just the array itself */
9fc9ab86 590 case SVt_PVAV: TAG;
e98cedbf 591 total_size += sizeof(XPVAV);
592 /* Is there anything in the array? */
593 if (AvMAX(thing) != -1) {
c8db37d3 594 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
595 total_size += sizeof(SV *) * (AvMAX(thing) + 1);
b7621729 596 dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", total_size, AvMAX(thing), av_len((AV*)thing)));
e98cedbf 597 }
598 /* Add in the bits on the other side of the beginning */
0430b7f7 599
b7621729 600 dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
9fc9ab86 601 total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
0430b7f7 602
603 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
b1e5ad85 604 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
0430b7f7 605 if (AvALLOC(thing) != 0) {
606 total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
607 }
795fc84c 608#if (PERL_VERSION < 9)
609 /* Is there something hanging off the arylen element?
610 Post 5.9.something this is stored in magic, so will be found there,
611 and Perl_av_arylen_p() takes a non-const AV*, hence compilers rightly
612 complain about AvARYLEN() passing thing to it. */
e98cedbf 613 if (AvARYLEN(thing)) {
a4efdff3 614 if (check_new(st, AvARYLEN(thing))) {
615 total_size += thing_size(aTHX_ AvARYLEN(thing), st);
6a9ad7ec 616 }
e98cedbf 617 }
795fc84c 618#endif
a4efdff3 619 total_size += magic_size(thing, st);
9fc9ab86 620 TAG;break;
621 case SVt_PVHV: TAG;
a6ea0805 622 /* First the base struct */
623 total_size += sizeof(XPVHV);
624 /* Now the array of buckets */
625 total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
626 /* Now walk the bucket chain */
6a9ad7ec 627 if (HvARRAY(thing)) {
a6ea0805 628 HE *cur_entry;
9fc9ab86 629 UV cur_bucket = 0;
a6ea0805 630 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
9fc9ab86 631 cur_entry = *(HvARRAY(thing) + cur_bucket);
632 while (cur_entry) {
633 total_size += sizeof(HE);
634 if (cur_entry->hent_hek) {
635 /* Hash keys can be shared. Have we seen this before? */
a4efdff3 636 if (check_new(st, cur_entry->hent_hek)) {
9fc9ab86 637 total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
638 }
639 }
640 cur_entry = cur_entry->hent_next;
641 }
a6ea0805 642 }
643 }
a4efdff3 644 total_size += magic_size(thing, st);
9fc9ab86 645 TAG;break;
646 case SVt_PVCV: TAG;
6a9ad7ec 647 total_size += sizeof(XPVCV);
a4efdff3 648 total_size += magic_size(thing, st);
7ccc7d88 649
650 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
a4efdff3 651 if (check_new(st, CvSTASH(thing))) {
652 total_size += thing_size(aTHX_ (SV *)CvSTASH(thing), st);
7ccc7d88 653 }
a4efdff3 654 if (check_new(st, SvSTASH(thing))) {
655 total_size += thing_size(aTHX_ (SV *)SvSTASH(thing), st);
7ccc7d88 656 }
a4efdff3 657 if (check_new(st, CvGV(thing))) {
658 total_size += thing_size(aTHX_ (SV *)CvGV(thing), st);
ebb2c5b9 659 }
a4efdff3 660 if (check_new(st, CvPADLIST(thing))) {
661 total_size += thing_size(aTHX_ (SV *)CvPADLIST(thing), st);
7ccc7d88 662 }
a4efdff3 663 if (check_new(st, CvOUTSIDE(thing))) {
664 total_size += thing_size(aTHX_ (SV *)CvOUTSIDE(thing), st);
7ccc7d88 665 }
66f50dda 666 if (CvISXSUB(thing)) {
667 SV *sv = cv_const_sv((CV *)thing);
668 if (sv) {
a4efdff3 669 total_size += thing_size(aTHX_ sv, st);
66f50dda 670 }
671 } else {
a4efdff3 672 if (check_new(st, CvSTART(thing))) {
673 total_size += op_size(aTHX_ CvSTART(thing), st);
87372f42 674 }
a4efdff3 675 if (check_new(st, CvROOT(thing))) {
676 total_size += op_size(aTHX_ CvROOT(thing), st);
87372f42 677 }
7ccc7d88 678 }
679
9fc9ab86 680 TAG;break;
681 case SVt_PVGV: TAG;
a4efdff3 682 total_size += magic_size(thing, st);
6a9ad7ec 683 total_size += sizeof(XPVGV);
5c2e1b12 684 total_size += GvNAMELEN(thing);
78dfb4e7 685#ifdef GvFILE
0bff12d8 686 /* Is there a file? */
687 if (GvFILE(thing)) {
a4efdff3 688 if (check_new(st, GvFILE(thing))) {
9fc9ab86 689 total_size += strlen(GvFILE(thing));
0bff12d8 690 }
691 }
78dfb4e7 692#endif
5c2e1b12 693 /* Is there something hanging off the glob? */
694 if (GvGP(thing)) {
a4efdff3 695 if (check_new(st, GvGP(thing))) {
9fc9ab86 696 total_size += sizeof(GP);
697 {
698 SV *generic_thing;
699 if ((generic_thing = (SV *)(GvGP(thing)->gp_sv))) {
a4efdff3 700 total_size += thing_size(aTHX_ generic_thing, st);
9fc9ab86 701 }
702 if ((generic_thing = (SV *)(GvGP(thing)->gp_form))) {
a4efdff3 703 total_size += thing_size(aTHX_ generic_thing, st);
9fc9ab86 704 }
705 if ((generic_thing = (SV *)(GvGP(thing)->gp_av))) {
a4efdff3 706 total_size += thing_size(aTHX_ generic_thing, st);
9fc9ab86 707 }
708 if ((generic_thing = (SV *)(GvGP(thing)->gp_hv))) {
a4efdff3 709 total_size += thing_size(aTHX_ generic_thing, st);
9fc9ab86 710 }
711 if ((generic_thing = (SV *)(GvGP(thing)->gp_egv))) {
a4efdff3 712 total_size += thing_size(aTHX_ generic_thing, st);
9fc9ab86 713 }
714 if ((generic_thing = (SV *)(GvGP(thing)->gp_cv))) {
a4efdff3 715 total_size += thing_size(aTHX_ generic_thing, st);
9fc9ab86 716 }
717 }
5c2e1b12 718 }
719 }
9fc9ab86 720 TAG;break;
721 case SVt_PVFM: TAG;
6a9ad7ec 722 total_size += sizeof(XPVFM);
a4efdff3 723 total_size += magic_size(thing, st);
7ccc7d88 724 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
a4efdff3 725 if (check_new(st, CvPADLIST(thing))) {
726 total_size += thing_size(aTHX_ (SV *)CvPADLIST(thing), st);
7ccc7d88 727 }
a4efdff3 728 if (check_new(st, CvOUTSIDE(thing))) {
729 total_size += thing_size(aTHX_ (SV *)CvOUTSIDE(thing), st);
7ccc7d88 730 }
731
a4efdff3 732 if (st->go_yell && !st->fm_whine) {
5073b933 733 carp("Devel::Size: Calculated sizes for FMs are incomplete");
a4efdff3 734 st->fm_whine = 1;
ebb2c5b9 735 }
9fc9ab86 736 TAG;break;
737 case SVt_PVIO: TAG;
6a9ad7ec 738 total_size += sizeof(XPVIO);
a4efdff3 739 total_size += magic_size(thing, st);
740 if (check_new(st, (SvPVX_const(thing)))) {
5073b933 741 total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
ebb2c5b9 742 }
5073b933 743 /* Some embedded char pointers */
a4efdff3 744 if (check_new(st, ((XPVIO *) SvANY(thing))->xio_top_name)) {
5073b933 745 total_size += strlen(((XPVIO *) SvANY(thing))->xio_top_name);
746 }
a4efdff3 747 if (check_new(st, ((XPVIO *) SvANY(thing))->xio_fmt_name)) {
5073b933 748 total_size += strlen(((XPVIO *) SvANY(thing))->xio_fmt_name);
749 }
a4efdff3 750 if (check_new(st, ((XPVIO *) SvANY(thing))->xio_bottom_name)) {
5073b933 751 total_size += strlen(((XPVIO *) SvANY(thing))->xio_bottom_name);
752 }
753 /* Throw the GVs on the list to be walked if they're not-null */
754 if (((XPVIO *) SvANY(thing))->xio_top_gv) {
265a0548 755 total_size += thing_size(aTHX_ (SV *)((XPVIO *) SvANY(thing))->xio_top_gv,
a4efdff3 756 st);
5073b933 757 }
758 if (((XPVIO *) SvANY(thing))->xio_bottom_gv) {
265a0548 759 total_size += thing_size(aTHX_ (SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv,
a4efdff3 760 st);
5073b933 761 }
762 if (((XPVIO *) SvANY(thing))->xio_fmt_gv) {
265a0548 763 total_size += thing_size(aTHX_ (SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv,
a4efdff3 764 st);
5073b933 765 }
766
767 /* Only go trotting through the IO structures if they're really
768 trottable. If USE_PERLIO is defined we can do this. If
769 not... we can't, so we don't even try */
770#ifdef USE_PERLIO
771 /* Dig into xio_ifp and xio_ofp here */
9fc9ab86 772 warn("Devel::Size: Can't size up perlio layers yet\n");
5073b933 773#endif
9fc9ab86 774 TAG;break;
e98cedbf 775 default:
9fc9ab86 776 warn("Devel::Size: Unknown variable type: %d encountered\n", SvTYPE(thing) );
e98cedbf 777 }
778 return total_size;
779}
780
a4efdff3 781static struct state *
782new_state(pTHX)
65db36c0 783{
784 SV *warn_flag;
a4efdff3 785 struct state *st;
786 Newxz(st, 1, struct state);
787 st->go_yell = TRUE;
65db36c0 788 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
a4efdff3 789 st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 790 }
791 if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
a4efdff3 792 st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 793 }
a4efdff3 794 return st;
65db36c0 795}
796
9fc9ab86 797MODULE = Devel::Size PACKAGE = Devel::Size
e98cedbf 798
fea63ffa 799PROTOTYPES: DISABLE
800
a6ea0805 801IV
802size(orig_thing)
803 SV *orig_thing
e98cedbf 804CODE:
805{
6a9ad7ec 806 SV *thing = orig_thing;
a4efdff3 807 struct state *st = new_state(aTHX);
ebb2c5b9 808
6a9ad7ec 809 /* If they passed us a reference then dereference it. This is the
810 only way we can check the sizes of arrays and hashes */
b7621729 811#if (PERL_VERSION < 11)
6a9ad7ec 812 if (SvOK(thing) && SvROK(thing)) {
813 thing = SvRV(thing);
814 }
b7621729 815#else
816 if (SvROK(thing)) {
817 thing = SvRV(thing);
818 }
819#endif
820
a4efdff3 821 RETVAL = thing_size(aTHX_ thing, st);
822 free_state(st);
6a9ad7ec 823}
824OUTPUT:
825 RETVAL
826
827
828IV
829total_size(orig_thing)
830 SV *orig_thing
831CODE:
832{
833 SV *thing = orig_thing;
b7621729 834 /* Array with things we still need to do */
835 AV *pending_array;
b98fcdb9 836 IV size = 0;
a4efdff3 837 struct state *st = new_state(aTHX);
b98fcdb9 838
6a9ad7ec 839 /* Size starts at zero */
840 RETVAL = 0;
841
b7621729 842 pending_array = newAV();
843
8c394e12 844 /* If they passed us a reference then dereference it.
b7621729 845 This is the only way we can check the sizes of arrays and hashes. */
846 if (SvROK(thing)) {
8c394e12 847 thing = SvRV(thing);
b7621729 848 }
6a9ad7ec 849
850 /* Put it on the pending array */
851 av_push(pending_array, thing);
852
853 /* Now just yank things off the end of the array until it's done */
e96acca9 854 while (av_len(pending_array) >= 0) {
855 thing = av_pop(pending_array);
6a9ad7ec 856 /* Process it if we've not seen it */
a4efdff3 857 if (check_new(st, thing)) {
b7621729 858 dbg_printf(("# Found type %i at %p\n", SvTYPE(thing), thing));
e96acca9 859 /* Is it valid? */
860 if (thing) {
9fc9ab86 861 /* Yes, it is. So let's check the type */
862 switch (SvTYPE(thing)) {
863 /* fix for bug #24846 (Does not correctly recurse into references in a PVNV-type scalar) */
864 case SVt_PVNV: TAG;
865 if (SvROK(thing))
866 {
867 av_push(pending_array, SvRV(thing));
868 }
869 TAG;break;
b7621729 870#if (PERL_VERSION < 11)
9fc9ab86 871 case SVt_RV: TAG;
b7621729 872#else
9fc9ab86 873 case SVt_IV: TAG;
b7621729 874#endif
875 dbg_printf(("# Found RV\n"));
876 if (SvROK(thing)) {
877 dbg_printf(("# Found RV\n"));
878 av_push(pending_array, SvRV(thing));
879 }
9fc9ab86 880 TAG;break;
881
882 case SVt_PVAV: TAG;
883 {
884 AV *tempAV = (AV *)thing;
885 SV **tempSV;
886
887 dbg_printf(("# Found type AV\n"));
888 /* Quick alias to cut down on casting */
889
890 /* Any elements? */
891 if (av_len(tempAV) != -1) {
892 IV index;
893 /* Run through them all */
894 for (index = 0; index <= av_len(tempAV); index++) {
895 /* Did we get something? */
896 if ((tempSV = av_fetch(tempAV, index, 0))) {
897 /* Was it undef? */
898 if (*tempSV != &PL_sv_undef) {
899 /* Apparently not. Save it for later */
900 av_push(pending_array, *tempSV);
901 }
902 }
903 }
904 }
905 }
906 TAG;break;
907
908 case SVt_PVHV: TAG;
909 dbg_printf(("# Found type HV\n"));
910 /* Is there anything in here? */
911 if (hv_iterinit((HV *)thing)) {
912 HE *temp_he;
913 while ((temp_he = hv_iternext((HV *)thing))) {
914 av_push(pending_array, hv_iterval((HV *)thing, temp_he));
915 }
916 }
917 TAG;break;
918
919 case SVt_PVGV: TAG;
920 dbg_printf(("# Found type GV\n"));
921 /* Run through all the pieces and push the ones with bits */
922 if (GvSV(thing)) {
923 av_push(pending_array, (SV *)GvSV(thing));
924 }
925 if (GvFORM(thing)) {
926 av_push(pending_array, (SV *)GvFORM(thing));
927 }
928 if (GvAV(thing)) {
929 av_push(pending_array, (SV *)GvAV(thing));
930 }
931 if (GvHV(thing)) {
932 av_push(pending_array, (SV *)GvHV(thing));
933 }
934 if (GvCV(thing)) {
935 av_push(pending_array, (SV *)GvCV(thing));
936 }
937 TAG;break;
938 default:
939 TAG;break;
940 }
6a9ad7ec 941 }
b98fcdb9 942
a4efdff3 943 size = thing_size(aTHX_ thing, st);
b98fcdb9 944 RETVAL += size;
b7621729 945 } else {
946 /* check_new() returned false: */
947#ifdef DEVEL_SIZE_DEBUGGING
948 if (SvOK(sv)) printf("# Ignore ref copy 0x%x\n", sv);
949 else printf("# Ignore non-sv 0x%x\n", sv);
950#endif
6a9ad7ec 951 }
b7621729 952 } /* end while */
e9716740 953
a4efdff3 954 free_state(st);
6a9ad7ec 955 SvREFCNT_dec(pending_array);
e98cedbf 956}
957OUTPUT:
958 RETVAL
6a9ad7ec 959