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