Lots of progress.
[p5sagit/Devel-Size.git] / Size.xs
CommitLineData
fd495cc6 1/* -*- mode: C -*- */
2
c07e8ef8 3#undef NDEBUG /* XXX */
4#include <assert.h>
5
265a0548 6#define PERL_NO_GET_CONTEXT
7
e98cedbf 8#include "EXTERN.h"
9#include "perl.h"
10#include "XSUB.h"
2eb93d08 11#include "ppport.h"
e98cedbf 12
87372f42 13/* Not yet in ppport.h */
14#ifndef CvISXSUB
15# define CvISXSUB(cv) (CvXSUB(cv) ? TRUE : FALSE)
16#endif
0e1f978f 17#ifndef SvRV_const
18# define SvRV_const(rv) SvRV(rv)
19#endif
95dc1714 20#ifndef SvOOK_offset
21# define SvOOK_offset(sv, len) STMT_START { len = SvIVX(sv); } STMT_END
22#endif
924d9c4e 23#ifndef SvIsCOW
24# define SvIsCOW(sv) ((SvFLAGS(sv) & (SVf_FAKE | SVf_READONLY)) == \
25 (SVf_FAKE | SVf_READONLY))
26#endif
27#ifndef SvIsCOW_shared_hash
28# define SvIsCOW_shared_hash(sv) (SvIsCOW(sv) && SvLEN(sv) == 0)
29#endif
30#ifndef SvSHARED_HEK_FROM_PV
31# define SvSHARED_HEK_FROM_PV(pvx) \
32 ((struct hek*)(pvx - STRUCT_OFFSET(struct hek, hek_key)))
33#endif
87372f42 34
177ebd37 35#if PERL_VERSION < 6
36# define PL_opargs opargs
37# define PL_op_name op_name
38#endif
39
9fc9ab86 40#ifdef _MSC_VER
1a36ac09 41/* "structured exception" handling is a Microsoft extension to C and C++.
42 It's *not* C++ exception handling - C++ exception handling can't capture
43 SEGVs and suchlike, whereas this can. There's no known analagous
44 functionality on other platforms. */
45# include <excpt.h>
46# define TRY_TO_CATCH_SEGV __try
1c35d132 47# define CAUGHT_EXCEPTION __except(EXCEPTION_EXECUTE_HANDLER)
9fc9ab86 48#else
1a36ac09 49# define TRY_TO_CATCH_SEGV if(1)
50# define CAUGHT_EXCEPTION else
9fc9ab86 51#endif
52
53#ifdef __GNUC__
54# define __attribute__(x)
55#endif
56
b7621729 57#if 0 && defined(DEBUGGING)
58#define dbg_printf(x) printf x
59#else
60#define dbg_printf(x)
61#endif
98ecbbc6 62
0964064b 63#define TAG /* printf( "# %s(%d)\n", __FILE__, __LINE__ ) */
6a9ad7ec 64#define carp puts
9fc9ab86 65
30fe4f47 66/* The idea is to have a tree structure to store 1 bit per possible pointer
67 address. The lowest 16 bits are stored in a block of 8092 bytes.
68 The blocks are in a 256-way tree, indexed by the reset of the pointer.
69 This can cope with 32 and 64 bit pointers, and any address space layout,
70 without excessive memory needs. The assumption is that your CPU cache
71 works :-) (And that we're not going to bust it) */
72
30fe4f47 73#define BYTE_BITS 3
74#define LEAF_BITS (16 - BYTE_BITS)
75#define LEAF_MASK 0x1FFF
9fc9ab86 76
c07e8ef8 77typedef struct npath_node_st npath_node_t;
78struct npath_node_st {
79 npath_node_t *prev;
80 const void *id;
81 U8 type;
82 U8 flags;
83 UV seqn;
84 U16 depth;
85};
86
65db36c0 87struct state {
eee00145 88 UV total_size;
65db36c0 89 bool regex_whine;
90 bool fm_whine;
91 bool dangle_whine;
92 bool go_yell;
93 /* My hunch (not measured) is that for most architectures pointers will
94 start with 0 bits, hence the start of this array will be hot, and the
95 end unused. So put the flags next to the hot end. */
96 void *tracking[256];
c07e8ef8 97 /* callback hooks and data */
98 int (*add_attr_cb)(struct state *st, npath_node_t *npath_node, UV attr_type, const char *name, UV value);
99 void (*free_state_cb)(struct state *st);
100 UV seqn;
101 void *state_cb_data; /* free'd by free_state() after free_state_cb() call */
5e486cae 102 /* this stuff wil be moved to state_cb_data later */
103 FILE *node_stream;
65db36c0 104};
105
c07e8ef8 106#define ADD_SIZE(st, leafname, bytes) (NPathAddSizeCb(st, leafname, bytes) (st)->total_size += (bytes))
107
108#define PATH_TRACKING
109#ifdef PATH_TRACKING
110
c07e8ef8 111#define pPATH npath_node_t *NPathArg
112
012b5f33 113/* A subtle point here is that dNPathNodes and NPathPushNode leaves NP pointing
114 * to the next unused slot (though with prev already filled in)
c07e8ef8 115 * whereas NPathLink leaves NP unchanged, it just fills in the slot NP points
116 * to and passes that NP value to the function being called.
117 */
118#define dNPathNodes(nodes, prev_np) \
119 npath_node_t name_path_nodes[nodes+1]; /* +1 for NPathLink */ \
120 npath_node_t *NP = &name_path_nodes[0]; \
121 NP->seqn = 0; \
122 NP->type = 0; \
123 NP->id = "?0?"; /* DEBUG */ \
124 NP->prev = prev_np
012b5f33 125#define NPathPushNode(nodeid, nodetype) \
c07e8ef8 126 NP->id = nodeid; \
127 NP->type = nodetype; \
012b5f33 128 if(0)fprintf(stderr,"NPathPushNode (%p <-) %p <- [%d %s]\n", NP->prev, NP, nodetype,(char*)nodeid);\
c07e8ef8 129 NP++; \
130 NP->id="?+?"; /* DEBUG */ \
131 NP->seqn = 0; \
132 NP->prev = (NP-1)
012b5f33 133#define NPathSetNode(nodeid, nodetype) \
134 (NP-1)->id = nodeid; \
135 (NP-1)->type = nodetype; \
136 if(0)fprintf(stderr,"NPathSetNode (%p <-) %p <- [%d %s]\n", (NP-1)->prev, (NP-1), nodetype,(char*)nodeid);\
137 (NP-1)->seqn = 0;
c07e8ef8 138
139/* dNPathUseParent points NP directly the the parents' name_path_nodes array
140 * So the function can only safely call ADD_*() but not NPathLink, unless the
141 * caller has spare nodes in its name_path_nodes.
142 */
143#define dNPathUseParent(prev_np) npath_node_t *NP = (((prev_np+1)->prev = prev_np), prev_np+1)
144
145#define NPtype_NAME 0x01
146#define NPtype_LINK 0x02
147#define NPtype_SV 0x03
148#define NPtype_MAGIC 0x04
149#define NPtype_OP 0x05
150
e8f4c506 151#define NPattr_LEAFSIZE 0x00
152#define NPattr_NAME 0x01
153#define NPattr_PADFAKE 0x02
154#define NPattr_PADNAME 0x03
155#define NPattr_PADTMP 0x04
156
fc6614ee 157#define NPathLink(nodeid) ((NP->id = nodeid), (NP->type = NPtype_LINK), (NP->seqn = 0), NP)
c07e8ef8 158#define NPathOpLink (NPathArg)
e8f4c506 159#define NPathAddSizeCb(st, name, bytes) (st->add_attr_cb && st->add_attr_cb(st, NP-1, NPattr_LEAFSIZE, (name), (bytes))),
c07e8ef8 160#define ADD_ATTR(st, attr_type, attr_name, attr_value) (st->add_attr_cb && st->add_attr_cb(st, NP-1, attr_type, attr_name, attr_value))
161
162#else
163
164#define NPathAddSizeCb(st, name, bytes)
165#define pPATH void *npath_dummy /* XXX ideally remove */
166#define dNPathNodes(nodes, prev_np) dNOOP
167#define NPathLink(nodeid, nodetype) NULL
168#define NPathOpLink NULL
169#define ADD_ATTR(st, attr_type, attr_name, attr_value) NOOP
170
171#endif /* PATH_TRACKING */
172
173
174
175
176#ifdef PATH_TRACKING
177
178static const char *svtypenames[SVt_LAST] = {
179#if PERL_VERSION < 9
180 "NULL", "IV", "NV", "RV", "PV", "PVIV", "PVNV", "PVMG", "PVBM", "PVLV", "PVAV", "PVHV", "PVCV", "PVGV", "PVFM", "PVIO",
181#elif PERL_VERSION == 10 && PERL_SUBVERSION == 0
182 "NULL", "BIND", "IV", "NV", "RV", "PV", "PVIV", "PVNV", "PVMG", "PVGV", "PVLV", "PVAV", "PVHV", "PVCV", "PVFM", "PVIO",
183#elif PERL_VERSION == 10 && PERL_SUBVERSION == 1
184 "NULL", "BIND", "IV", "NV", "RV", "PV", "PVIV", "PVNV", "PVMG", "PVGV", "PVLV", "PVAV", "PVHV", "PVCV", "PVFM", "PVIO",
185#elif PERL_VERSION < 13
186 "NULL", "BIND", "IV", "NV", "PV", "PVIV", "PVNV", "PVMG", "REGEXP", "PVGV", "PVLV", "PVAV", "PVHV", "PVCV", "PVFM", "PVIO",
187#else
188 "NULL", "BIND", "IV", "NV", "PV", "PVIV", "PVNV", "PVMG", "REGEXP", "PVGV", "PVLV", "PVAV", "PVHV", "PVCV", "PVFM", "PVIO",
189#endif
190};
191
192int
5e486cae 193np_print_node_name(FILE *fp, npath_node_t *npath_node)
c07e8ef8 194{
195 char buf[1024]; /* XXX */
196
197 switch (npath_node->type) {
198 case NPtype_SV: { /* id is pointer to the SV sv_size was called on */
199 const SV *sv = (SV*)npath_node->id;
200 int type = SvTYPE(sv);
201 char *typename = (type == SVt_IV && SvROK(sv)) ? "RV" : svtypenames[type];
5e486cae 202 fprintf(fp, "SV(%s)", typename);
c07e8ef8 203 switch(type) { /* add some useful details */
5e486cae 204 case SVt_PVAV: fprintf(fp, " fill=%d/%ld", av_len((AV*)sv), AvMAX((AV*)sv)); break;
205 case SVt_PVHV: fprintf(fp, " fill=%ld/%ld", HvFILL((HV*)sv), HvMAX((HV*)sv)); break;
c07e8ef8 206 }
207 break;
208 }
209 case NPtype_OP: { /* id is pointer to the OP op_size was called on */
210 const OP *op = (OP*)npath_node->id;
5e486cae 211 fprintf(fp, "OP(%s)", OP_NAME(op));
c07e8ef8 212 break;
213 }
214 case NPtype_MAGIC: { /* id is pointer to the MAGIC struct */
215 MAGIC *magic_pointer = (MAGIC*)npath_node->id;
216 /* XXX it would be nice if we could reuse mg_names.c [sigh] */
5e486cae 217 fprintf(fp, "MAGIC(%c)", magic_pointer->mg_type ? magic_pointer->mg_type : '0');
c07e8ef8 218 break;
219 }
220 case NPtype_LINK:
5e486cae 221 fprintf(fp, "%s->", npath_node->id);
c07e8ef8 222 break;
223 case NPtype_NAME:
5e486cae 224 fprintf(fp, "%s", npath_node->id);
c07e8ef8 225 break;
226 default: /* assume id is a string pointer */
5e486cae 227 fprintf(fp, "UNKNOWN(%d,%p)", npath_node->type, npath_node->id);
c07e8ef8 228 break;
229 }
230 return 0;
231}
232
233void
5e486cae 234np_dump_indent(int depth) {
c07e8ef8 235 while (depth-- > 0)
236 fprintf(stderr, ": ");
237}
238
239int
fc6614ee 240np_walk_new_nodes(struct state *st,
241 npath_node_t *npath_node,
242 npath_node_t *npath_node_deeper,
243 int (*cb)(struct state *st, npath_node_t *npath_node, npath_node_t *npath_node_deeper))
c07e8ef8 244{
245 if (npath_node->seqn) /* node already output */
fc6614ee 246 return 0;
c07e8ef8 247
248 if (npath_node->prev) {
fc6614ee 249 np_walk_new_nodes(st, npath_node->prev, npath_node, cb); /* recurse */
c07e8ef8 250 npath_node->depth = npath_node->prev->depth + 1;
251 }
252 else npath_node->depth = 0;
253 npath_node->seqn = ++st->seqn;
254
fc6614ee 255 if (cb) {
256 if (cb(st, npath_node, npath_node_deeper)) {
257 /* ignore this node */
258 assert(npath_node->prev);
259 assert(npath_node->depth);
260 assert(npath_node_deeper);
261 npath_node->depth--;
262 npath_node->seqn = --st->seqn;
263 npath_node_deeper->prev = npath_node->prev;
264 }
265 }
c07e8ef8 266
fc6614ee 267 return 0;
268}
269
270int
271np_dump_formatted_node(struct state *st, npath_node_t *npath_node, npath_node_t *npath_node_deeper) {
272 if (0 && npath_node->type == NPtype_LINK)
273 return 1;
274 np_dump_indent(npath_node->depth);
275 np_print_node_name(stderr, npath_node);
276 fprintf(stderr, "\t\t[#%ld @%u] ", npath_node->seqn, npath_node->depth);
277 fprintf(stderr, "\n");
278 return 0;
c07e8ef8 279}
280
281int
5e486cae 282np_dump_node_path_info(struct state *st, npath_node_t *npath_node, UV attr_type, const char *attr_name, UV attr_value)
c07e8ef8 283{
284 if (!attr_type && !attr_value)
5e486cae 285 return 0; /* ignore zero sized leaf items */
fc6614ee 286 np_walk_new_nodes(st, npath_node, NULL, np_dump_formatted_node);
5e486cae 287 np_dump_indent(npath_node->depth+1);
c07e8ef8 288 if (attr_type) {
289 fprintf(stderr, "~NAMED('%s') %lu", attr_name, attr_value);
290 }
291 else {
292 fprintf(stderr, "+%ld ", attr_value);
293 fprintf(stderr, "%s ", attr_name);
294 fprintf(stderr, "=%ld ", attr_value+st->total_size);
295 }
296 fprintf(stderr, "\n");
297 return 0;
298}
299
5e486cae 300int
fc6614ee 301np_stream_formatted_node(struct state *st, npath_node_t *npath_node, npath_node_t *npath_node_deeper) {
5e486cae 302 fprintf(st->node_stream, "N %lu %u ", npath_node->seqn,
fc6614ee 303 (unsigned)npath_node->depth
5e486cae 304 );
305 np_print_node_name(st->node_stream, npath_node);
306 fprintf(st->node_stream, "\n");
307 return 0;
308}
309
310int
311np_stream_node_path_info(struct state *st, npath_node_t *npath_node, UV attr_type, const char *attr_name, UV attr_value)
312{
313 if (!attr_type && !attr_value)
314 return 0; /* ignore zero sized leaf items */
fc6614ee 315 np_walk_new_nodes(st, npath_node, NULL, np_stream_formatted_node);
e8f4c506 316 if (attr_type) { /* Attribute type, name and value */
317 fprintf(st->node_stream, "%lu %lu ", attr_type, npath_node->seqn);
5e486cae 318 }
e8f4c506 319 else { /* Leaf name and memory size */
320 fprintf(st->node_stream, "L %lu ", npath_node->seqn);
5e486cae 321 }
322 fprintf(st->node_stream, "%lu %s\n", attr_value, attr_name);
323 return 0;
324}
325
c07e8ef8 326#endif /* PATH_TRACKING */
327
328
9fc9ab86 329/*
330 Checks to see if thing is in the bitstring.
331 Returns true or false, and
332 notes thing in the segmented bitstring.
333 */
2eb93d08 334static bool
a4efdff3 335check_new(struct state *st, const void *const p) {
30fe4f47 336 unsigned int bits = 8 * sizeof(void*);
337 const size_t raw_p = PTR2nat(p);
338 /* This effectively rotates the value right by the number of low always-0
339 bits in an aligned pointer. The assmption is that most (if not all)
340 pointers are aligned, and these will be in the same chain of nodes
341 (and hence hot in the cache) but we can still deal with any unaligned
342 pointers. */
343 const size_t cooked_p
f404ed48 344 = (raw_p >> ALIGN_BITS) | (raw_p << (bits - ALIGN_BITS));
30fe4f47 345 const U8 this_bit = 1 << (cooked_p & 0x7);
346 U8 **leaf_p;
347 U8 *leaf;
348 unsigned int i;
302077b6 349 void **tv_p = (void **) (st->tracking);
30fe4f47 350
302077b6 351 if (NULL == p) return FALSE;
1a36ac09 352 TRY_TO_CATCH_SEGV {
2eb93d08 353 const char c = *(const char *)p;
9fc9ab86 354 }
1a36ac09 355 CAUGHT_EXCEPTION {
a4efdff3 356 if (st->dangle_whine)
9fc9ab86 357 warn( "Devel::Size: Encountered invalid pointer: %p\n", p );
358 return FALSE;
359 }
9fc9ab86 360 TAG;
30fe4f47 361
362 bits -= 8;
363 /* bits now 24 (32 bit pointers) or 56 (64 bit pointers) */
364
365 /* First level is always present. */
366 do {
367 i = (unsigned int)((cooked_p >> bits) & 0xFF);
368 if (!tv_p[i])
369 Newxz(tv_p[i], 256, void *);
370 tv_p = (void **)(tv_p[i]);
371 bits -= 8;
372 } while (bits > LEAF_BITS + BYTE_BITS);
373 /* bits now 16 always */
5f04c81d 374#if !defined(MULTIPLICITY) || PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8)
375 /* 5.8.8 and early have an assert() macro that uses Perl_croak, hence needs
376 a my_perl under multiplicity */
30fe4f47 377 assert(bits == 16);
5f04c81d 378#endif
30fe4f47 379 leaf_p = (U8 **)tv_p;
380 i = (unsigned int)((cooked_p >> bits) & 0xFF);
381 if (!leaf_p[i])
382 Newxz(leaf_p[i], 1 << LEAF_BITS, U8);
383 leaf = leaf_p[i];
384
9fc9ab86 385 TAG;
30fe4f47 386
387 i = (unsigned int)((cooked_p >> BYTE_BITS) & LEAF_MASK);
388
389 if(leaf[i] & this_bit)
390 return FALSE;
391
392 leaf[i] |= this_bit;
9fc9ab86 393 return TRUE;
394}
395
e9716740 396static void
30fe4f47 397free_tracking_at(void **tv, int level)
398{
399 int i = 255;
400
401 if (--level) {
402 /* Nodes */
403 do {
404 if (tv[i]) {
384ebd3f 405 free_tracking_at((void **) tv[i], level);
30fe4f47 406 Safefree(tv[i]);
407 }
408 } while (i--);
409 } else {
410 /* Leaves */
411 do {
412 if (tv[i])
413 Safefree(tv[i]);
414 } while (i--);
415 }
416}
417
418static void
a4efdff3 419free_state(struct state *st)
e9716740 420{
30fe4f47 421 const int top_level = (sizeof(void *) * 8 - LEAF_BITS - BYTE_BITS) / 8;
c07e8ef8 422 if (st->free_state_cb)
423 st->free_state_cb(st);
424 if (st->state_cb_data)
425 Safefree(st->state_cb_data);
a4efdff3 426 free_tracking_at((void **)st->tracking, top_level);
427 Safefree(st);
e9716740 428}
429
f3cf7e20 430/* For now, this is somewhat a compatibility bodge until the plan comes
431 together for fine grained recursion control. total_size() would recurse into
432 hash and array members, whereas sv_size() would not. However, sv_size() is
433 called with CvSTASH() of a CV, which means that if it (also) starts to
434 recurse fully, then the size of any CV now becomes the size of the entire
435 symbol table reachable from it, and potentially the entire symbol table, if
436 any subroutine makes a reference to a global (such as %SIG). The historical
437 implementation of total_size() didn't report "everything", and changing the
438 only available size to "everything" doesn't feel at all useful. */
439
440#define NO_RECURSION 0
441#define SOME_RECURSION 1
442#define TOTAL_SIZE_RECURSION 2
443
c07e8ef8 444static void sv_size(pTHX_ struct state *, pPATH, const SV *const, const int recurse);
db519f11 445
7ccc7d88 446typedef enum {
9fc9ab86 447 OPc_NULL, /* 0 */
448 OPc_BASEOP, /* 1 */
449 OPc_UNOP, /* 2 */
450 OPc_BINOP, /* 3 */
451 OPc_LOGOP, /* 4 */
452 OPc_LISTOP, /* 5 */
453 OPc_PMOP, /* 6 */
454 OPc_SVOP, /* 7 */
455 OPc_PADOP, /* 8 */
456 OPc_PVOP, /* 9 */
457 OPc_LOOP, /* 10 */
458 OPc_COP /* 11 */
177ebd37 459#ifdef OA_CONDOP
460 , OPc_CONDOP /* 12 */
461#endif
462#ifdef OA_GVOP
463 , OPc_GVOP /* 13 */
464#endif
465
7ccc7d88 466} opclass;
467
468static opclass
9fc9ab86 469cc_opclass(const OP * const o)
7ccc7d88 470{
471 if (!o)
9fc9ab86 472 return OPc_NULL;
1a36ac09 473 TRY_TO_CATCH_SEGV {
9fc9ab86 474 if (o->op_type == 0)
475 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
7ccc7d88 476
9fc9ab86 477 if (o->op_type == OP_SASSIGN)
478 return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
7ccc7d88 479
9fc9ab86 480 #ifdef USE_ITHREADS
481 if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
482 return OPc_PADOP;
483 #endif
7ccc7d88 484
9fc9ab86 485 if ((o->op_type == OP_TRANS)) {
486 return OPc_BASEOP;
487 }
7ccc7d88 488
9fc9ab86 489 switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
490 case OA_BASEOP: TAG;
491 return OPc_BASEOP;
492
493 case OA_UNOP: TAG;
494 return OPc_UNOP;
495
496 case OA_BINOP: TAG;
497 return OPc_BINOP;
62691e7c 498
9fc9ab86 499 case OA_LOGOP: TAG;
500 return OPc_LOGOP;
7ccc7d88 501
9fc9ab86 502 case OA_LISTOP: TAG;
503 return OPc_LISTOP;
7ccc7d88 504
9fc9ab86 505 case OA_PMOP: TAG;
506 return OPc_PMOP;
7ccc7d88 507
9fc9ab86 508 case OA_SVOP: TAG;
509 return OPc_SVOP;
7ccc7d88 510
177ebd37 511#ifdef OA_PADOP
9fc9ab86 512 case OA_PADOP: TAG;
513 return OPc_PADOP;
177ebd37 514#endif
515
516#ifdef OA_GVOP
517 case OA_GVOP: TAG;
518 return OPc_GVOP;
519#endif
7ccc7d88 520
177ebd37 521#ifdef OA_PVOP_OR_SVOP
9fc9ab86 522 case OA_PVOP_OR_SVOP: TAG;
523 /*
524 * Character translations (tr///) are usually a PVOP, keeping a
525 * pointer to a table of shorts used to look up translations.
526 * Under utf8, however, a simple table isn't practical; instead,
527 * the OP is an SVOP, and the SV is a reference to a swash
528 * (i.e., an RV pointing to an HV).
529 */
530 return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
531 ? OPc_SVOP : OPc_PVOP;
177ebd37 532#endif
7ccc7d88 533
9fc9ab86 534 case OA_LOOP: TAG;
535 return OPc_LOOP;
7ccc7d88 536
9fc9ab86 537 case OA_COP: TAG;
538 return OPc_COP;
7ccc7d88 539
9fc9ab86 540 case OA_BASEOP_OR_UNOP: TAG;
7ccc7d88 541 /*
9fc9ab86 542 * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on
543 * whether parens were seen. perly.y uses OPf_SPECIAL to
544 * signal whether a BASEOP had empty parens or none.
545 * Some other UNOPs are created later, though, so the best
546 * test is OPf_KIDS, which is set in newUNOP.
7ccc7d88 547 */
9fc9ab86 548 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
549
550 case OA_FILESTATOP: TAG;
551 /*
552 * The file stat OPs are created via UNI(OP_foo) in toke.c but use
553 * the OPf_REF flag to distinguish between OP types instead of the
554 * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we
555 * return OPc_UNOP so that walkoptree can find our children. If
556 * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set
557 * (no argument to the operator) it's an OP; with OPf_REF set it's
558 * an SVOP (and op_sv is the GV for the filehandle argument).
559 */
560 return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
561 #ifdef USE_ITHREADS
562 (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
563 #else
564 (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
565 #endif
566 case OA_LOOPEXOP: TAG;
567 /*
568 * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a
569 * label was omitted (in which case it's a BASEOP) or else a term was
570 * seen. In this last case, all except goto are definitely PVOP but
571 * goto is either a PVOP (with an ordinary constant label), an UNOP
572 * with OPf_STACKED (with a non-constant non-sub) or an UNOP for
573 * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to
574 * get set.
575 */
576 if (o->op_flags & OPf_STACKED)
577 return OPc_UNOP;
578 else if (o->op_flags & OPf_SPECIAL)
579 return OPc_BASEOP;
580 else
581 return OPc_PVOP;
177ebd37 582
583#ifdef OA_CONDOP
584 case OA_CONDOP: TAG;
585 return OPc_CONDOP;
586#endif
9fc9ab86 587 }
588 warn("Devel::Size: Can't determine class of operator %s, assuming BASEOP\n",
589 PL_op_name[o->op_type]);
590 }
1a36ac09 591 CAUGHT_EXCEPTION { }
7ccc7d88 592 return OPc_BASEOP;
593}
594
6a9ad7ec 595/* Figure out how much magic is attached to the SV and return the
596 size */
eee00145 597static void
c07e8ef8 598magic_size(pTHX_ const SV * const thing, struct state *st, pPATH) {
599 dNPathNodes(1, NPathArg);
980c6576 600 MAGIC *magic_pointer = SvMAGIC(thing);
6a9ad7ec 601
012b5f33 602 /* push a dummy node for NPathSetNode to update inside the while loop */
603 NPathPushNode("dummy", NPtype_NAME);
604
980c6576 605 /* Have we seen the magic pointer? (NULL has always been seen before) */
e5c69bdd 606 while (check_new(st, magic_pointer)) {
c07e8ef8 607
012b5f33 608 NPathSetNode(magic_pointer, NPtype_MAGIC);
c07e8ef8 609
610 ADD_SIZE(st, "mg", sizeof(MAGIC));
9847261d 611 /* magic vtables aren't freed when magic is freed, so don't count them.
612 (They are static structures. Anything that assumes otherwise is buggy.)
613 */
614
6a9ad7ec 615
1a36ac09 616 TRY_TO_CATCH_SEGV {
fc6614ee 617 sv_size(aTHX_ st, NPathLink("mg_obj"), magic_pointer->mg_obj, TOTAL_SIZE_RECURSION);
d1888d0b 618 if (magic_pointer->mg_len == HEf_SVKEY) {
fc6614ee 619 sv_size(aTHX_ st, NPathLink("mg_ptr"), (SV *)magic_pointer->mg_ptr, TOTAL_SIZE_RECURSION);
d1888d0b 620 }
621#if defined(PERL_MAGIC_utf8) && defined (PERL_MAGIC_UTF8_CACHESIZE)
622 else if (magic_pointer->mg_type == PERL_MAGIC_utf8) {
623 if (check_new(st, magic_pointer->mg_ptr)) {
c07e8ef8 624 ADD_SIZE(st, "PERL_MAGIC_utf8", PERL_MAGIC_UTF8_CACHESIZE * 2 * sizeof(STRLEN));
d1888d0b 625 }
626 }
627#endif
628 else if (magic_pointer->mg_len > 0) {
629 if (check_new(st, magic_pointer->mg_ptr)) {
c07e8ef8 630 ADD_SIZE(st, "mg_len", magic_pointer->mg_len);
d1888d0b 631 }
632 }
6a9ad7ec 633
0964064b 634 /* Get the next in the chain */
9fc9ab86 635 magic_pointer = magic_pointer->mg_moremagic;
636 }
1a36ac09 637 CAUGHT_EXCEPTION {
a4efdff3 638 if (st->dangle_whine)
9fc9ab86 639 warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
640 }
6a9ad7ec 641 }
6a9ad7ec 642}
643
eee00145 644static void
c07e8ef8 645check_new_and_strlen(struct state *st, const char *const p, pPATH) {
646 dNPathNodes(1, NPathArg->prev);
647 if(check_new(st, p)) {
012b5f33 648 NPathPushNode(NPathArg->id, NPtype_NAME);
c07e8ef8 649 ADD_SIZE(st, NPathArg->id, 1 + strlen(p));
650 }
99684fd4 651}
652
653static void
c07e8ef8 654regex_size(const REGEXP * const baseregex, struct state *st, pPATH) {
655 dNPathNodes(1, NPathArg);
c1bfd7da 656 if(!check_new(st, baseregex))
657 return;
012b5f33 658 NPathPushNode("regex_size", NPtype_NAME);
c07e8ef8 659 ADD_SIZE(st, "REGEXP", sizeof(REGEXP));
9fc9ab86 660#if (PERL_VERSION < 11)
6ea94d90 661 /* Note the size of the paren offset thing */
c07e8ef8 662 ADD_SIZE(st, "nparens", sizeof(I32) * baseregex->nparens * 2);
663 ADD_SIZE(st, "precomp", strlen(baseregex->precomp));
6ea94d90 664#else
c07e8ef8 665 ADD_SIZE(st, "regexp", sizeof(struct regexp));
666 ADD_SIZE(st, "nparens", sizeof(I32) * SvANY(baseregex)->nparens * 2);
667 /*ADD_SIZE(st, strlen(SvANY(baseregex)->subbeg));*/
6ea94d90 668#endif
a4efdff3 669 if (st->go_yell && !st->regex_whine) {
6ea94d90 670 carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
a4efdff3 671 st->regex_whine = 1;
98ecbbc6 672 }
7ccc7d88 673}
674
eee00145 675static void
c07e8ef8 676op_size(pTHX_ const OP * const baseop, struct state *st, pPATH)
1e5a8ad2 677{
c07e8ef8 678 /* op_size recurses to follow the chain of opcodes.
679 * For the 'path' we don't want the chain to be 'nested' in the path so we
680 * use ->prev in dNPathNodes.
681 */
682 dNPathUseParent(NPathArg);
683
1e5a8ad2 684 TRY_TO_CATCH_SEGV {
685 TAG;
686 if(!check_new(st, baseop))
687 return;
688 TAG;
c07e8ef8 689 op_size(aTHX_ baseop->op_next, st, NPathOpLink);
1e5a8ad2 690 TAG;
691 switch (cc_opclass(baseop)) {
692 case OPc_BASEOP: TAG;
c07e8ef8 693 ADD_SIZE(st, "op", sizeof(struct op));
1e5a8ad2 694 TAG;break;
695 case OPc_UNOP: TAG;
c07e8ef8 696 ADD_SIZE(st, "unop", sizeof(struct unop));
697 op_size(aTHX_ ((UNOP *)baseop)->op_first, st, NPathOpLink);
1e5a8ad2 698 TAG;break;
699 case OPc_BINOP: TAG;
c07e8ef8 700 ADD_SIZE(st, "binop", sizeof(struct binop));
701 op_size(aTHX_ ((BINOP *)baseop)->op_first, st, NPathOpLink);
702 op_size(aTHX_ ((BINOP *)baseop)->op_last, st, NPathOpLink);
1e5a8ad2 703 TAG;break;
704 case OPc_LOGOP: TAG;
c07e8ef8 705 ADD_SIZE(st, "logop", sizeof(struct logop));
706 op_size(aTHX_ ((BINOP *)baseop)->op_first, st, NPathOpLink);
707 op_size(aTHX_ ((LOGOP *)baseop)->op_other, st, NPathOpLink);
1e5a8ad2 708 TAG;break;
177ebd37 709#ifdef OA_CONDOP
710 case OPc_CONDOP: TAG;
c07e8ef8 711 ADD_SIZE(st, "condop", sizeof(struct condop));
712 op_size(aTHX_ ((BINOP *)baseop)->op_first, st, NPathOpLink);
713 op_size(aTHX_ ((CONDOP *)baseop)->op_true, st, NPathOpLink);
714 op_size(aTHX_ ((CONDOP *)baseop)->op_false, st, NPathOpLink);
177ebd37 715 TAG;break;
716#endif
1e5a8ad2 717 case OPc_LISTOP: TAG;
c07e8ef8 718 ADD_SIZE(st, "listop", sizeof(struct listop));
719 op_size(aTHX_ ((LISTOP *)baseop)->op_first, st, NPathOpLink);
720 op_size(aTHX_ ((LISTOP *)baseop)->op_last, st, NPathOpLink);
1e5a8ad2 721 TAG;break;
722 case OPc_PMOP: TAG;
c07e8ef8 723 ADD_SIZE(st, "pmop", sizeof(struct pmop));
724 op_size(aTHX_ ((PMOP *)baseop)->op_first, st, NPathOpLink);
725 op_size(aTHX_ ((PMOP *)baseop)->op_last, st, NPathOpLink);
5a83b7cf 726#if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
c07e8ef8 727 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplroot, st, NPathOpLink);
728 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplstart, st, NPathOpLink);
5a83b7cf 729#endif
c1bfd7da 730 /* This is defined away in perl 5.8.x, but it is in there for
731 5.6.x */
98ecbbc6 732#ifdef PM_GETRE
fc6614ee 733 regex_size(PM_GETRE((PMOP *)baseop), st, NPathLink("PM_GETRE"));
98ecbbc6 734#else
fc6614ee 735 regex_size(((PMOP *)baseop)->op_pmregexp, st, NPathLink("op_pmregexp"));
98ecbbc6 736#endif
c1bfd7da 737 TAG;break;
81f1c018 738 case OPc_SVOP: TAG;
c07e8ef8 739 ADD_SIZE(st, "svop", sizeof(struct svop));
574d9fd9 740 if (!(baseop->op_type == OP_AELEMFAST
741 && baseop->op_flags & OPf_SPECIAL)) {
742 /* not an OP_PADAV replacement */
fc6614ee 743 sv_size(aTHX_ st, NPathLink("SVOP"), ((SVOP *)baseop)->op_sv, SOME_RECURSION);
574d9fd9 744 }
81f1c018 745 TAG;break;
177ebd37 746#ifdef OA_PADOP
9fc9ab86 747 case OPc_PADOP: TAG;
c07e8ef8 748 ADD_SIZE(st, "padop", sizeof(struct padop));
99684fd4 749 TAG;break;
177ebd37 750#endif
751#ifdef OA_GVOP
752 case OPc_GVOP: TAG;
c07e8ef8 753 ADD_SIZE(st, "gvop", sizeof(struct gvop));
fc6614ee 754 sv_size(aTHX_ st, NPathLink("GVOP"), ((GVOP *)baseop)->op_gv, SOME_RECURSION);
177ebd37 755 TAG;break;
756#endif
99684fd4 757 case OPc_PVOP: TAG;
fc6614ee 758 check_new_and_strlen(st, ((PVOP *)baseop)->op_pv, NPathLink("op_pv"));
219b7d34 759 TAG;break;
1e5a8ad2 760 case OPc_LOOP: TAG;
c07e8ef8 761 ADD_SIZE(st, "loop", sizeof(struct loop));
762 op_size(aTHX_ ((LOOP *)baseop)->op_first, st, NPathOpLink);
763 op_size(aTHX_ ((LOOP *)baseop)->op_last, st, NPathOpLink);
764 op_size(aTHX_ ((LOOP *)baseop)->op_redoop, st, NPathOpLink);
765 op_size(aTHX_ ((LOOP *)baseop)->op_nextop, st, NPathOpLink);
766 op_size(aTHX_ ((LOOP *)baseop)->op_lastop, st, NPathOpLink);
1e5a8ad2 767 TAG;break;
768 case OPc_COP: TAG;
9fc9ab86 769 {
770 COP *basecop;
771 basecop = (COP *)baseop;
c07e8ef8 772 ADD_SIZE(st, "cop", sizeof(struct cop));
9fc9ab86 773
774 /* Change 33656 by nicholas@mouse-mill on 2008/04/07 11:29:51
775 Eliminate cop_label from struct cop by storing a label as the first
776 entry in the hints hash. Most statements don't have labels, so this
777 will save memory. Not sure how much.
778 The check below will be incorrect fail on bleadperls
779 before 5.11 @33656, but later than 5.10, producing slightly too
780 small memory sizes on these Perls. */
b7621729 781#if (PERL_VERSION < 11)
fc6614ee 782 check_new_and_strlen(st, basecop->cop_label, NPathLink("cop_label"));
b7621729 783#endif
7ccc7d88 784#ifdef USE_ITHREADS
fc6614ee 785 check_new_and_strlen(st, basecop->cop_file, NPathLink("cop_file"));
786 check_new_and_strlen(st, basecop->cop_stashpv, NPathLink("cop_stashpv"));
7ccc7d88 787#else
fc6614ee 788 sv_size(aTHX_ st, NPathLink("cop_stash"), (SV *)basecop->cop_stash, SOME_RECURSION);
789 sv_size(aTHX_ st, NPathLink("cop_filegv"), (SV *)basecop->cop_filegv, SOME_RECURSION);
7ccc7d88 790#endif
791
9fc9ab86 792 }
793 TAG;break;
794 default:
795 TAG;break;
796 }
797 }
1a36ac09 798 CAUGHT_EXCEPTION {
a4efdff3 799 if (st->dangle_whine)
9fc9ab86 800 warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
7ccc7d88 801 }
7ccc7d88 802}
6a9ad7ec 803
3d18ea10 804static void
c07e8ef8 805hek_size(pTHX_ struct state *st, HEK *hek, U32 shared, pPATH)
3d18ea10 806{
fc6614ee 807 dNPathNodes(1, NPathArg);
808
3d18ea10 809 /* Hash keys can be shared. Have we seen this before? */
810 if (!check_new(st, hek))
811 return;
fc6614ee 812 NPathPushNode("hek", NPtype_NAME);
c07e8ef8 813 ADD_SIZE(st, "hek_len", HEK_BASESIZE + hek->hek_len
3d18ea10 814#if PERL_VERSION < 8
815 + 1 /* No hash key flags prior to 5.8.0 */
816#else
817 + 2
818#endif
c07e8ef8 819 );
3d18ea10 820 if (shared) {
821#if PERL_VERSION < 10
c07e8ef8 822 ADD_SIZE(st, "he", sizeof(struct he));
3d18ea10 823#else
c07e8ef8 824 ADD_SIZE(st, "shared_he", STRUCT_OFFSET(struct shared_he, shared_he_hek));
3d18ea10 825#endif
826 }
827}
828
829
b6558d1d 830#if PERL_VERSION < 8 || PERL_SUBVERSION < 9
831# define SVt_LAST 16
24d37977 832#endif
833
f73dcfce 834#ifdef PURIFY
835# define MAYBE_PURIFY(normal, pure) (pure)
836# define MAYBE_OFFSET(struct_name, member) 0
837#else
838# define MAYBE_PURIFY(normal, pure) (normal)
839# define MAYBE_OFFSET(struct_name, member) STRUCT_OFFSET(struct_name, member)
840#endif
841
b6558d1d 842const U8 body_sizes[SVt_LAST] = {
843#if PERL_VERSION < 9
f73dcfce 844 0, /* SVt_NULL */
845 MAYBE_PURIFY(sizeof(IV), sizeof(XPVIV)), /* SVt_IV */
846 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
847 sizeof(XRV), /* SVt_RV */
848 sizeof(XPV), /* SVt_PV */
849 sizeof(XPVIV), /* SVt_PVIV */
850 sizeof(XPVNV), /* SVt_PVNV */
851 sizeof(XPVMG), /* SVt_PVMG */
852 sizeof(XPVBM), /* SVt_PVBM */
853 sizeof(XPVLV), /* SVt_PVLV */
854 sizeof(XPVAV), /* SVt_PVAV */
855 sizeof(XPVHV), /* SVt_PVHV */
856 sizeof(XPVCV), /* SVt_PVCV */
857 sizeof(XPVGV), /* SVt_PVGV */
858 sizeof(XPVFM), /* SVt_PVFM */
859 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 860#elif PERL_VERSION == 10 && PERL_SUBVERSION == 0
f73dcfce 861 0, /* SVt_NULL */
862 0, /* SVt_BIND */
863 0, /* SVt_IV */
864 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
865 0, /* SVt_RV */
866 MAYBE_PURIFY(sizeof(xpv_allocated), sizeof(XPV)), /* SVt_PV */
867 MAYBE_PURIFY(sizeof(xpviv_allocated), sizeof(XPVIV)),/* SVt_PVIV */
868 sizeof(XPVNV), /* SVt_PVNV */
869 sizeof(XPVMG), /* SVt_PVMG */
870 sizeof(XPVGV), /* SVt_PVGV */
871 sizeof(XPVLV), /* SVt_PVLV */
872 MAYBE_PURIFY(sizeof(xpvav_allocated), sizeof(XPVAV)),/* SVt_PVAV */
873 MAYBE_PURIFY(sizeof(xpvhv_allocated), sizeof(XPVHV)),/* SVt_PVHV */
874 MAYBE_PURIFY(sizeof(xpvcv_allocated), sizeof(XPVCV)),/* SVt_PVCV */
875 MAYBE_PURIFY(sizeof(xpvfm_allocated), sizeof(XPVFM)),/* SVt_PVFM */
876 sizeof(XPVIO), /* SVt_PVIO */
b6558d1d 877#elif PERL_VERSION == 10 && PERL_SUBVERSION == 1
f73dcfce 878 0, /* SVt_NULL */
879 0, /* SVt_BIND */
880 0, /* SVt_IV */
881 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
882 0, /* SVt_RV */
883 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
884 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
885 sizeof(XPVNV), /* SVt_PVNV */
886 sizeof(XPVMG), /* SVt_PVMG */
887 sizeof(XPVGV), /* SVt_PVGV */
888 sizeof(XPVLV), /* SVt_PVLV */
889 sizeof(XPVAV) - MAYBE_OFFSET(XPVAV, xav_fill), /* SVt_PVAV */
890 sizeof(XPVHV) - MAYBE_OFFSET(XPVHV, xhv_fill), /* SVt_PVHV */
891 sizeof(XPVCV) - MAYBE_OFFSET(XPVCV, xpv_cur), /* SVt_PVCV */
892 sizeof(XPVFM) - MAYBE_OFFSET(XPVFM, xpv_cur), /* SVt_PVFM */
893 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 894#elif PERL_VERSION < 13
f73dcfce 895 0, /* SVt_NULL */
896 0, /* SVt_BIND */
897 0, /* SVt_IV */
898 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
899 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
900 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
901 sizeof(XPVNV), /* SVt_PVNV */
902 sizeof(XPVMG), /* SVt_PVMG */
903 sizeof(regexp) - MAYBE_OFFSET(regexp, xpv_cur), /* SVt_REGEXP */
904 sizeof(XPVGV), /* SVt_PVGV */
905 sizeof(XPVLV), /* SVt_PVLV */
906 sizeof(XPVAV) - MAYBE_OFFSET(XPVAV, xav_fill), /* SVt_PVAV */
907 sizeof(XPVHV) - MAYBE_OFFSET(XPVHV, xhv_fill), /* SVt_PVHV */
908 sizeof(XPVCV) - MAYBE_OFFSET(XPVCV, xpv_cur), /* SVt_PVCV */
909 sizeof(XPVFM) - MAYBE_OFFSET(XPVFM, xpv_cur), /* SVt_PVFM */
910 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 911#else
f73dcfce 912 0, /* SVt_NULL */
913 0, /* SVt_BIND */
914 0, /* SVt_IV */
915 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
916 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
917 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
918 sizeof(XPVNV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVNV */
919 sizeof(XPVMG), /* SVt_PVMG */
920 sizeof(regexp), /* SVt_REGEXP */
921 sizeof(XPVGV), /* SVt_PVGV */
922 sizeof(XPVLV), /* SVt_PVLV */
923 sizeof(XPVAV), /* SVt_PVAV */
924 sizeof(XPVHV), /* SVt_PVHV */
925 sizeof(XPVCV), /* SVt_PVCV */
926 sizeof(XPVFM), /* SVt_PVFM */
927 sizeof(XPVIO) /* SVt_PVIO */
b6558d1d 928#endif
929};
930
c07e8ef8 931
932static void
933padlist_size(pTHX_ struct state *const st, pPATH, PADLIST *padlist,
934 const int recurse)
935{
936 dNPathUseParent(NPathArg);
937 /* based on Perl_do_dump_pad() */
938 const AV *pad_name;
939 SV **pname;
940 I32 ix;
941
942 if (!padlist) {
943 return;
944 }
945 pad_name = MUTABLE_AV(*av_fetch(MUTABLE_AV(padlist), 0, FALSE));
946 pname = AvARRAY(pad_name);
947
948 for (ix = 1; ix <= AvFILLp(pad_name); ix++) {
949 const SV *namesv = pname[ix];
950 if (namesv && namesv == &PL_sv_undef) {
951 namesv = NULL;
952 }
953 if (namesv) {
954 if (SvFAKE(namesv))
e8f4c506 955 ADD_ATTR(st, NPattr_PADFAKE, SvPVX_const(namesv), ix);
c07e8ef8 956 else
e8f4c506 957 ADD_ATTR(st, NPattr_PADNAME, SvPVX_const(namesv), ix);
c07e8ef8 958 }
959 else {
e8f4c506 960 ADD_ATTR(st, NPattr_PADTMP, "SVs_PADTMP", ix);
c07e8ef8 961 }
962
963 }
964 sv_size(aTHX_ st, NPathArg, (SV*)padlist, recurse);
965}
966
967
a5c6bdd7 968static void
c07e8ef8 969sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing,
f3cf7e20 970 const int recurse) {
9fc9ab86 971 const SV *thing = orig_thing;
c07e8ef8 972 dNPathNodes(3, NPathArg);
b6558d1d 973 U32 type;
eee00145 974
c07e8ef8 975 if(!check_new(st, orig_thing))
a5c6bdd7 976 return;
81f1c018 977
b6558d1d 978 type = SvTYPE(thing);
979 if (type > SVt_LAST) {
980 warn("Devel::Size: Unknown variable type: %d encountered\n", type);
a5c6bdd7 981 return;
b6558d1d 982 }
012b5f33 983 NPathPushNode(thing, NPtype_SV);
c07e8ef8 984 ADD_SIZE(st, "sv", sizeof(SV) + body_sizes[type]);
b1e5ad85 985
b6558d1d 986 if (type >= SVt_PVMG) {
fc6614ee 987 magic_size(aTHX_ thing, st, NPathLink("MG"));
696b99e2 988 }
989
b6558d1d 990 switch (type) {
991#if (PERL_VERSION < 11)
e98cedbf 992 /* Is it a reference? */
9fc9ab86 993 case SVt_RV: TAG;
b6558d1d 994#else
995 case SVt_IV: TAG;
24d37977 996#endif
81f1c018 997 if(recurse && SvROK(thing))
fc6614ee 998 sv_size(aTHX_ st, NPathLink("RV"), SvRV_const(thing), recurse);
9fc9ab86 999 TAG;break;
267703fd 1000
9fc9ab86 1001 case SVt_PVAV: TAG;
e98cedbf 1002 /* Is there anything in the array? */
1003 if (AvMAX(thing) != -1) {
c8db37d3 1004 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
c07e8ef8 1005 ADD_SIZE(st, "av_max", sizeof(SV *) * (AvMAX(thing) + 1));
eee00145 1006 dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
6c5ddc0d 1007
1008 if (recurse >= TOTAL_SIZE_RECURSION) {
1009 SSize_t i = AvFILLp(thing) + 1;
1010
1011 while (i--)
fc6614ee 1012 sv_size(aTHX_ st, NPathLink("AVelem"), AvARRAY(thing)[i], recurse);
6c5ddc0d 1013 }
e98cedbf 1014 }
1015 /* Add in the bits on the other side of the beginning */
0430b7f7 1016
b7621729 1017 dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
c07e8ef8 1018 st->total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
0430b7f7 1019
1020 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
b1e5ad85 1021 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
0430b7f7 1022 if (AvALLOC(thing) != 0) {
c07e8ef8 1023 ADD_SIZE(st, "AvALLOC", (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing))));
0430b7f7 1024 }
795fc84c 1025#if (PERL_VERSION < 9)
1026 /* Is there something hanging off the arylen element?
1027 Post 5.9.something this is stored in magic, so will be found there,
1028 and Perl_av_arylen_p() takes a non-const AV*, hence compilers rightly
1029 complain about AvARYLEN() passing thing to it. */
fc6614ee 1030 sv_size(aTHX_ st, NPathLink("ARYLEN"), AvARYLEN(thing), recurse);
795fc84c 1031#endif
9fc9ab86 1032 TAG;break;
1033 case SVt_PVHV: TAG;
a6ea0805 1034 /* Now the array of buckets */
c07e8ef8 1035 ADD_SIZE(st, "hv_max", (sizeof(HE *) * (HvMAX(thing) + 1)));
1036 if (HvENAME(thing)) {
e8f4c506 1037 ADD_ATTR(st, NPattr_NAME, HvENAME(thing), 0);
c07e8ef8 1038 }
a6ea0805 1039 /* Now walk the bucket chain */
6a9ad7ec 1040 if (HvARRAY(thing)) {
a6ea0805 1041 HE *cur_entry;
9fc9ab86 1042 UV cur_bucket = 0;
a6ea0805 1043 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
9fc9ab86 1044 cur_entry = *(HvARRAY(thing) + cur_bucket);
1045 while (cur_entry) {
c07e8ef8 1046 ADD_SIZE(st, "he", sizeof(HE));
fc6614ee 1047 hek_size(aTHX_ st, cur_entry->hent_hek, HvSHAREKEYS(thing), NPathLink("hent_hek"));
5e486cae 1048 if (recurse >= TOTAL_SIZE_RECURSION) {
2c631ee0 1049/* I've seen a PL_strtab HeVAL == 0xC and 0x40C etc
5e486cae 1050 * just running perl -Mblib -Mstrict -MDevel::Size=:all -MCarp -e 'warn perl_size()'
1051 * but it seemed like a corruption - it would change come and go with irrelevant code changes.
1052 * so we protect against that here, but I'd like to know the cause.
1053 */
2c631ee0 1054if (PTR2UV(HeVAL(cur_entry)) > 0xFFF)
fc6614ee 1055 sv_size(aTHX_ st, NPathLink("HeVAL"), HeVAL(cur_entry), recurse);
5e486cae 1056 }
9fc9ab86 1057 cur_entry = cur_entry->hent_next;
1058 }
a6ea0805 1059 }
1060 }
78037efb 1061#ifdef HvAUX
1062 if (SvOOK(thing)) {
1063 /* This direct access is arguably "naughty": */
1064 struct mro_meta *meta = HvAUX(thing)->xhv_mro_meta;
b3a37f1a 1065#if PERL_VERSION > 13 || PERL_SUBVERSION > 8
1066 /* As is this: */
1067 I32 count = HvAUX(thing)->xhv_name_count;
1068
1069 if (count) {
1070 HEK **names = HvAUX(thing)->xhv_name_u.xhvnameu_names;
1071 if (count < 0)
1072 count = -count;
1073 while (--count)
fc6614ee 1074 hek_size(aTHX_ st, names[count], 1, NPathLink("HvAUXelem"));
b3a37f1a 1075 }
1076 else
1077#endif
1078 {
fc6614ee 1079 hek_size(aTHX_ st, HvNAME_HEK(thing), 1, NPathLink("HvNAME_HEK"));
b3a37f1a 1080 }
1081
c07e8ef8 1082 ADD_SIZE(st, "xpvhv_aux", sizeof(struct xpvhv_aux));
78037efb 1083 if (meta) {
c07e8ef8 1084 ADD_SIZE(st, "mro_meta", sizeof(struct mro_meta));
fc6614ee 1085 sv_size(aTHX_ st, NPathLink("mro_nextmethod"), (SV *)meta->mro_nextmethod, TOTAL_SIZE_RECURSION);
78037efb 1086#if PERL_VERSION > 10 || (PERL_VERSION == 10 && PERL_SUBVERSION > 0)
fc6614ee 1087 sv_size(aTHX_ st, NPathLink("isa"), (SV *)meta->isa, TOTAL_SIZE_RECURSION);
78037efb 1088#endif
1089#if PERL_VERSION > 10
fc6614ee 1090 sv_size(aTHX_ st, NPathLink("mro_linear_all"), (SV *)meta->mro_linear_all, TOTAL_SIZE_RECURSION);
1091 sv_size(aTHX_ st, NPathLink("mro_linear_current"), meta->mro_linear_current, TOTAL_SIZE_RECURSION);
78037efb 1092#else
fc6614ee 1093 sv_size(aTHX_ st, NPathLink("mro_linear_dfs"), (SV *)meta->mro_linear_dfs, TOTAL_SIZE_RECURSION);
1094 sv_size(aTHX_ st, NPathLink("mro_linear_c3"), (SV *)meta->mro_linear_c3, TOTAL_SIZE_RECURSION);
78037efb 1095#endif
1096 }
1097 }
1098#else
fc6614ee 1099 check_new_and_strlen(st, HvNAME_get(thing), NPathLink("HvNAME"));
78037efb 1100#endif
9fc9ab86 1101 TAG;break;
267703fd 1102
1103
1104 case SVt_PVFM: TAG;
fc6614ee 1105 padlist_size(aTHX_ st, NPathLink("CvPADLIST"), CvPADLIST(thing), SOME_RECURSION);
1106 sv_size(aTHX_ st, NPathLink("CvOUTSIDE"), (SV *)CvOUTSIDE(thing), recurse);
267703fd 1107
1108 if (st->go_yell && !st->fm_whine) {
1109 carp("Devel::Size: Calculated sizes for FMs are incomplete");
1110 st->fm_whine = 1;
1111 }
1112 goto freescalar;
1113
9fc9ab86 1114 case SVt_PVCV: TAG;
fc6614ee 1115 sv_size(aTHX_ st, NPathLink("CvSTASH"), (SV *)CvSTASH(thing), SOME_RECURSION);
1116 sv_size(aTHX_ st, NPathLink("SvSTASH"), (SV *)SvSTASH(thing), SOME_RECURSION);
1117 sv_size(aTHX_ st, NPathLink("CvGV"), (SV *)CvGV(thing), SOME_RECURSION);
1118 padlist_size(aTHX_ st, NPathLink("CvPADLIST"), CvPADLIST(thing), SOME_RECURSION);
1119 sv_size(aTHX_ st, NPathLink("CvOUTSIDE"), (SV *)CvOUTSIDE(thing), recurse);
66f50dda 1120 if (CvISXSUB(thing)) {
fc6614ee 1121 sv_size(aTHX_ st, NPathLink("cv_const_sv"), cv_const_sv((CV *)thing), recurse);
66f50dda 1122 } else {
fc6614ee 1123 op_size(aTHX_ CvSTART(thing), st, NPathLink("CvSTART"));
1124 op_size(aTHX_ CvROOT(thing), st, NPathLink("CvROOT"));
7ccc7d88 1125 }
267703fd 1126 goto freescalar;
1127
1128 case SVt_PVIO: TAG;
267703fd 1129 /* Some embedded char pointers */
fc6614ee 1130 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_top_name, NPathLink("xio_top_name"));
1131 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_fmt_name, NPathLink("xio_fmt_name"));
1132 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_bottom_name, NPathLink("xio_bottom_name"));
267703fd 1133 /* Throw the GVs on the list to be walked if they're not-null */
fc6614ee 1134 sv_size(aTHX_ st, NPathLink("xio_top_gv"), (SV *)((XPVIO *) SvANY(thing))->xio_top_gv, recurse);
1135 sv_size(aTHX_ st, NPathLink("xio_bottom_gv"), (SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv, recurse);
1136 sv_size(aTHX_ st, NPathLink("xio_fmt_gv"), (SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv, recurse);
267703fd 1137
1138 /* Only go trotting through the IO structures if they're really
1139 trottable. If USE_PERLIO is defined we can do this. If
1140 not... we can't, so we don't even try */
1141#ifdef USE_PERLIO
1142 /* Dig into xio_ifp and xio_ofp here */
1143 warn("Devel::Size: Can't size up perlio layers yet\n");
1144#endif
1145 goto freescalar;
1146
267703fd 1147 case SVt_PVLV: TAG;
267703fd 1148#if (PERL_VERSION < 9)
1149 goto freescalar;
267703fd 1150#endif
7ccc7d88 1151
9fc9ab86 1152 case SVt_PVGV: TAG;
4a3d023d 1153 if(isGV_with_GP(thing)) {
638a265a 1154#ifdef GvNAME_HEK
fc6614ee 1155 hek_size(aTHX_ st, GvNAME_HEK(thing), 1, NPathLink("GvNAME_HEK"));
638a265a 1156#else
c07e8ef8 1157 ADD_SIZE(st, "GvNAMELEN", GvNAMELEN(thing));
638a265a 1158#endif
e8f4c506 1159 ADD_ATTR(st, NPattr_NAME, GvNAME_get(thing), 0);
15588e9c 1160#ifdef GvFILE_HEK
fc6614ee 1161 hek_size(aTHX_ st, GvFILE_HEK(thing), 1, NPathLink("GvFILE_HEK"));
15588e9c 1162#elif defined(GvFILE)
2b217e71 1163# if !defined(USE_ITHREADS) || (PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8))
1164 /* With itreads, before 5.8.9, this can end up pointing to freed memory
1165 if the GV was created in an eval, as GvFILE() points to CopFILE(),
1166 and the relevant COP has been freed on scope cleanup after the eval.
1167 5.8.9 adds a binary compatible fudge that catches the vast majority
1168 of cases. 5.9.something added a proper fix, by converting the GP to
1169 use a shared hash key (porperly reference counted), instead of a
1170 char * (owned by who knows? possibly no-one now) */
fc6614ee 1171 check_new_and_strlen(st, GvFILE(thing), NPathLink("GvFILE"));
2b217e71 1172# endif
78dfb4e7 1173#endif
4a3d023d 1174 /* Is there something hanging off the glob? */
1175 if (check_new(st, GvGP(thing))) {
c07e8ef8 1176 ADD_SIZE(st, "GP", sizeof(GP));
fc6614ee 1177 sv_size(aTHX_ st, NPathLink("gp_sv"), (SV *)(GvGP(thing)->gp_sv), recurse);
1178 sv_size(aTHX_ st, NPathLink("gp_form"), (SV *)(GvGP(thing)->gp_form), recurse);
1179 sv_size(aTHX_ st, NPathLink("gp_av"), (SV *)(GvGP(thing)->gp_av), recurse);
1180 sv_size(aTHX_ st, NPathLink("gp_hv"), (SV *)(GvGP(thing)->gp_hv), recurse);
1181 sv_size(aTHX_ st, NPathLink("gp_egv"), (SV *)(GvGP(thing)->gp_egv), recurse);
1182 sv_size(aTHX_ st, NPathLink("gp_cv"), (SV *)(GvGP(thing)->gp_cv), recurse);
4a3d023d 1183 }
267703fd 1184#if (PERL_VERSION >= 9)
1185 TAG; break;
1186#endif
5c2e1b12 1187 }
b6558d1d 1188#if PERL_VERSION <= 8
1189 case SVt_PVBM: TAG;
1190#endif
267703fd 1191 case SVt_PVMG: TAG;
267703fd 1192 case SVt_PVNV: TAG;
267703fd 1193 case SVt_PVIV: TAG;
267703fd 1194 case SVt_PV: TAG;
267703fd 1195 freescalar:
1196 if(recurse && SvROK(thing))
fc6614ee 1197 sv_size(aTHX_ st, NPathLink("RV"), SvRV_const(thing), recurse);
924d9c4e 1198 else if (SvIsCOW_shared_hash(thing))
fc6614ee 1199 hek_size(aTHX_ st, SvSHARED_HEK_FROM_PV(SvPVX(thing)), 1, NPathLink("SvSHARED_HEK_FROM_PV"));
267703fd 1200 else
c07e8ef8 1201 ADD_SIZE(st, "SvLEN", SvLEN(thing));
267703fd 1202
1203 if(SvOOK(thing)) {
95dc1714 1204 STRLEN len;
1205 SvOOK_offset(thing, len);
c07e8ef8 1206 ADD_SIZE(st, "SvOOK", len);
ebb2c5b9 1207 }
9fc9ab86 1208 TAG;break;
5073b933 1209
e98cedbf 1210 }
a5c6bdd7 1211 return;
e98cedbf 1212}
1213
a4efdff3 1214static struct state *
1215new_state(pTHX)
65db36c0 1216{
1217 SV *warn_flag;
a4efdff3 1218 struct state *st;
d9b022a1 1219
a4efdff3 1220 Newxz(st, 1, struct state);
1221 st->go_yell = TRUE;
65db36c0 1222 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
a4efdff3 1223 st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 1224 }
1225 if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
a4efdff3 1226 st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
65db36c0 1227 }
a52ceccd 1228 check_new(st, &PL_sv_undef);
1229 check_new(st, &PL_sv_no);
1230 check_new(st, &PL_sv_yes);
6389ea67 1231#if PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 0)
1232 check_new(st, &PL_sv_placeholder);
1233#endif
33f2f60c 1234#ifdef PATH_TRACKING
5e486cae 1235if (getenv("M"))
1236st->node_stream = stdout;
1237 if (st->node_stream)
1238 st->add_attr_cb = np_stream_node_path_info;
1239 else
1240 st->add_attr_cb = np_dump_node_path_info;
33f2f60c 1241#endif
a4efdff3 1242 return st;
65db36c0 1243}
1244
9fc9ab86 1245MODULE = Devel::Size PACKAGE = Devel::Size
e98cedbf 1246
fea63ffa 1247PROTOTYPES: DISABLE
1248
eee00145 1249UV
a6ea0805 1250size(orig_thing)
1251 SV *orig_thing
13683e3a 1252ALIAS:
1253 total_size = TOTAL_SIZE_RECURSION
e98cedbf 1254CODE:
1255{
6a9ad7ec 1256 SV *thing = orig_thing;
a4efdff3 1257 struct state *st = new_state(aTHX);
ebb2c5b9 1258
6a9ad7ec 1259 /* If they passed us a reference then dereference it. This is the
1260 only way we can check the sizes of arrays and hashes */
b7621729 1261 if (SvROK(thing)) {
1262 thing = SvRV(thing);
1263 }
33f2f60c 1264
c07e8ef8 1265 sv_size(aTHX_ st, NULL, thing, ix);
eee00145 1266 RETVAL = st->total_size;
a4efdff3 1267 free_state(st);
6a9ad7ec 1268}
1269OUTPUT:
1270 RETVAL
33f2f60c 1271
1272UV
1273perl_size()
1274CODE:
1275{
e8f4c506 1276 dNPathNodes(2, NULL);
33f2f60c 1277 struct state *st = new_state(aTHX);
012b5f33 1278 NPathPushNode("perl_size", NPtype_NAME); /* provide a root node */
33f2f60c 1279
1280 /* start with PL_defstash to get everything reachable from \%main::
1281 * this seems to include PL_defgv, PL_incgv etc but I've listed them anyway
1282 */
fc6614ee 1283 sv_size(aTHX_ st, NPathLink("PL_defstash"), (SV*)PL_defstash, TOTAL_SIZE_RECURSION);
e8f4c506 1284
1285 NPathPushNode("others", NPtype_NAME); /* group these (typically much smaller) items */
fc6614ee 1286 sv_size(aTHX_ st, NPathLink("PL_defgv"), (SV*)PL_defgv, TOTAL_SIZE_RECURSION);
1287 sv_size(aTHX_ st, NPathLink("PL_incgv"), (SV*)PL_incgv, TOTAL_SIZE_RECURSION);
1288 sv_size(aTHX_ st, NPathLink("PL_rs"), (SV*)PL_rs, TOTAL_SIZE_RECURSION);
1289 sv_size(aTHX_ st, NPathLink("PL_fdpid"), (SV*)PL_fdpid, TOTAL_SIZE_RECURSION);
1290 sv_size(aTHX_ st, NPathLink("PL_modglobal"), (SV*)PL_modglobal, TOTAL_SIZE_RECURSION);
1291 sv_size(aTHX_ st, NPathLink("PL_errors"), (SV*)PL_errors, TOTAL_SIZE_RECURSION);
1292 sv_size(aTHX_ st, NPathLink("PL_stashcache"), (SV*)PL_stashcache, TOTAL_SIZE_RECURSION);
1293 sv_size(aTHX_ st, NPathLink("PL_patchlevel"), (SV*)PL_patchlevel, TOTAL_SIZE_RECURSION);
1294 sv_size(aTHX_ st, NPathLink("PL_apiversion"), (SV*)PL_apiversion, TOTAL_SIZE_RECURSION);
1295 sv_size(aTHX_ st, NPathLink("PL_registered_mros"), (SV*)PL_registered_mros, TOTAL_SIZE_RECURSION);
33f2f60c 1296#ifdef USE_ITHREADS
fc6614ee 1297 sv_size(aTHX_ st, NPathLink("PL_regex_padav"), (SV*)PL_regex_padav, TOTAL_SIZE_RECURSION);
33f2f60c 1298#endif
1299 /* TODO PL_pidstatus */
1300 /* TODO PL_stashpad */
1301
1302 /* in theory we shouldn't have any elements in PL_strtab that haven't been seen yet */
fc6614ee 1303 sv_size(aTHX_ st, NPathLink("PL_strtab"), (SV*)PL_strtab, TOTAL_SIZE_RECURSION);
33f2f60c 1304
1305 /* TODO stacks: cur, main, tmps, mark, scope, save */
1306 /* TODO unused space in arenas */
1307 /* TODO unused space in malloc, for whichever mallocs support it */
5e486cae 1308 /* TODO threads? */
33f2f60c 1309 /* TODO anything missed? */
1310
1311 RETVAL = st->total_size;
1312 free_state(st);
1313}
1314OUTPUT:
1315 RETVAL