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