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