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