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