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