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