3 #undef NDEBUG /* XXX */
6 #define PERL_NO_GET_CONTEXT
13 /* Not yet in ppport.h */
15 # define CvISXSUB(cv) (CvXSUB(cv) ? TRUE : FALSE)
18 # define SvRV_const(rv) SvRV(rv)
21 # define SvOOK_offset(sv, len) STMT_START { len = SvIVX(sv); } STMT_END
24 # define SvIsCOW(sv) ((SvFLAGS(sv) & (SVf_FAKE | SVf_READONLY)) == \
25 (SVf_FAKE | SVf_READONLY))
27 #ifndef SvIsCOW_shared_hash
28 # define SvIsCOW_shared_hash(sv) (SvIsCOW(sv) && SvLEN(sv) == 0)
30 #ifndef SvSHARED_HEK_FROM_PV
31 # define SvSHARED_HEK_FROM_PV(pvx) \
32 ((struct hek*)(pvx - STRUCT_OFFSET(struct hek, hek_key)))
36 # define PL_opargs opargs
37 # define PL_op_name op_name
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. */
46 # define TRY_TO_CATCH_SEGV __try
47 # define CAUGHT_EXCEPTION __except(EXCEPTION_EXECUTE_HANDLER)
49 # define TRY_TO_CATCH_SEGV if(1)
50 # define CAUGHT_EXCEPTION else
54 # define __attribute__(x)
57 #if 0 && defined(DEBUGGING)
58 #define dbg_printf(x) printf x
63 #define TAG /* printf( "# %s(%d)\n", __FILE__, __LINE__ ) */
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) */
74 #define LEAF_BITS (16 - BYTE_BITS)
75 #define LEAF_MASK 0x1FFF
77 typedef struct npath_node_st npath_node_t;
78 struct npath_node_st {
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. */
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);
101 void *state_cb_data; /* free'd by free_state() after free_state_cb() call */
102 /* this stuff wil be moved to state_cb_data later */
106 #define ADD_SIZE(st, leafname, bytes) (NPathAddSizeCb(st, leafname, bytes) (st)->total_size += (bytes))
108 #define PATH_TRACKING
111 #define pPATH npath_node_t *NPathArg
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)
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.
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]; \
123 NP->id = "?0?"; /* DEBUG */ \
125 #define NPathPushNode(nodeid, nodetype) \
127 NP->type = nodetype; \
128 if(0)fprintf(stderr,"NPathPushNode (%p <-) %p <- [%d %s]\n", NP->prev, NP, nodetype,(char*)nodeid);\
130 NP->id="?+?"; /* DEBUG */ \
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);\
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.
143 #define dNPathUseParent(prev_np) npath_node_t *NP = (((prev_np+1)->prev = prev_np), prev_np+1)
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
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
157 #define NPathLink(nodeid) ((NP->id = nodeid), (NP->type = NPtype_LINK), (NP->seqn = 0), NP)
158 #define NPathOpLink (NPathArg)
159 #define NPathAddSizeCb(st, name, bytes) (st->add_attr_cb && st->add_attr_cb(st, NP-1, NPattr_LEAFSIZE, (name), (bytes))),
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))
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
171 #endif /* PATH_TRACKING */
178 static const char *svtypenames[SVt_LAST] = {
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",
188 "NULL", "BIND", "IV", "NV", "PV", "PVIV", "PVNV", "PVMG", "REGEXP", "PVGV", "PVLV", "PVAV", "PVHV", "PVCV", "PVFM", "PVIO",
193 np_print_node_name(FILE *fp, npath_node_t *npath_node)
195 char buf[1024]; /* XXX */
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];
202 fprintf(fp, "SV(%s)", typename);
203 switch(type) { /* add some useful details */
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;
209 case NPtype_OP: { /* id is pointer to the OP op_size was called on */
210 const OP *op = (OP*)npath_node->id;
211 fprintf(fp, "OP(%s)", OP_NAME(op));
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] */
217 fprintf(fp, "MAGIC(%c)", magic_pointer->mg_type ? magic_pointer->mg_type : '0');
221 fprintf(fp, "%s->", npath_node->id);
224 fprintf(fp, "%s", npath_node->id);
226 default: /* assume id is a string pointer */
227 fprintf(fp, "UNKNOWN(%d,%p)", npath_node->type, npath_node->id);
234 np_dump_indent(int depth) {
236 fprintf(stderr, ": ");
240 np_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))
245 if (npath_node->seqn) /* node already output */
248 if (npath_node->prev) {
249 np_walk_new_nodes(st, npath_node->prev, npath_node, cb); /* recurse */
250 npath_node->depth = npath_node->prev->depth + 1;
252 else npath_node->depth = 0;
253 npath_node->seqn = ++st->seqn;
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);
262 npath_node->seqn = --st->seqn;
263 npath_node_deeper->prev = npath_node->prev;
271 np_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)
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");
282 np_dump_node_path_info(struct state *st, npath_node_t *npath_node, UV attr_type, const char *attr_name, UV attr_value)
284 if (!attr_type && !attr_value)
285 return 0; /* ignore zero sized leaf items */
286 np_walk_new_nodes(st, npath_node, NULL, np_dump_formatted_node);
287 np_dump_indent(npath_node->depth+1);
289 fprintf(stderr, "~NAMED('%s') %lu", attr_name, attr_value);
292 fprintf(stderr, "+%ld ", attr_value);
293 fprintf(stderr, "%s ", attr_name);
294 fprintf(stderr, "=%ld ", attr_value+st->total_size);
296 fprintf(stderr, "\n");
301 np_stream_formatted_node(struct state *st, npath_node_t *npath_node, npath_node_t *npath_node_deeper) {
302 fprintf(st->node_stream, "N %lu %u ", npath_node->seqn,
303 (unsigned)npath_node->depth
305 np_print_node_name(st->node_stream, npath_node);
306 fprintf(st->node_stream, "\n");
311 np_stream_node_path_info(struct state *st, npath_node_t *npath_node, UV attr_type, const char *attr_name, UV attr_value)
313 if (!attr_type && !attr_value)
314 return 0; /* ignore zero sized leaf items */
315 np_walk_new_nodes(st, npath_node, NULL, np_stream_formatted_node);
316 if (attr_type) { /* Attribute type, name and value */
317 fprintf(st->node_stream, "%lu %lu ", attr_type, npath_node->seqn);
319 else { /* Leaf name and memory size */
320 fprintf(st->node_stream, "L %lu ", npath_node->seqn);
322 fprintf(st->node_stream, "%lu %s\n", attr_value, attr_name);
326 #endif /* PATH_TRACKING */
330 Checks to see if thing is in the bitstring.
331 Returns true or false, and
332 notes thing in the segmented bitstring.
335 check_new(struct state *st, const void *const p) {
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
343 const size_t cooked_p
344 = (raw_p >> ALIGN_BITS) | (raw_p << (bits - ALIGN_BITS));
345 const U8 this_bit = 1 << (cooked_p & 0x7);
349 void **tv_p = (void **) (st->tracking);
351 if (NULL == p) return FALSE;
353 const char c = *(const char *)p;
356 if (st->dangle_whine)
357 warn( "Devel::Size: Encountered invalid pointer: %p\n", p );
363 /* bits now 24 (32 bit pointers) or 56 (64 bit pointers) */
365 /* First level is always present. */
367 i = (unsigned int)((cooked_p >> bits) & 0xFF);
369 Newxz(tv_p[i], 256, void *);
370 tv_p = (void **)(tv_p[i]);
372 } while (bits > LEAF_BITS + BYTE_BITS);
373 /* bits now 16 always */
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 */
379 leaf_p = (U8 **)tv_p;
380 i = (unsigned int)((cooked_p >> bits) & 0xFF);
382 Newxz(leaf_p[i], 1 << LEAF_BITS, U8);
387 i = (unsigned int)((cooked_p >> BYTE_BITS) & LEAF_MASK);
389 if(leaf[i] & this_bit)
397 free_tracking_at(void **tv, int level)
405 free_tracking_at((void **) tv[i], level);
419 free_state(struct state *st)
421 const int top_level = (sizeof(void *) * 8 - LEAF_BITS - BYTE_BITS) / 8;
422 if (st->free_state_cb)
423 st->free_state_cb(st);
424 if (st->state_cb_data)
425 Safefree(st->state_cb_data);
426 free_tracking_at((void **)st->tracking, top_level);
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. */
440 #define NO_RECURSION 0
441 #define SOME_RECURSION 1
442 #define TOTAL_SIZE_RECURSION 2
444 static void sv_size(pTHX_ struct state *, pPATH, const SV *const, const int recurse);
460 , OPc_CONDOP /* 12 */
469 cc_opclass(const OP * const o)
475 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
477 if (o->op_type == OP_SASSIGN)
478 return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
481 if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
485 if ((o->op_type == OP_TRANS)) {
489 switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
521 #ifdef OA_PVOP_OR_SVOP
522 case OA_PVOP_OR_SVOP: TAG;
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).
530 return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
531 ? OPc_SVOP : OPc_PVOP;
540 case OA_BASEOP_OR_UNOP: TAG;
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.
548 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
550 case OA_FILESTATOP: TAG;
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).
560 return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
562 (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
564 (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
566 case OA_LOOPEXOP: TAG;
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
576 if (o->op_flags & OPf_STACKED)
578 else if (o->op_flags & OPf_SPECIAL)
588 warn("Devel::Size: Can't determine class of operator %s, assuming BASEOP\n",
589 PL_op_name[o->op_type]);
595 /* Figure out how much magic is attached to the SV and return the
598 magic_size(pTHX_ const SV * const thing, struct state *st, pPATH) {
599 dNPathNodes(1, NPathArg);
600 MAGIC *magic_pointer = SvMAGIC(thing);
602 /* push a dummy node for NPathSetNode to update inside the while loop */
603 NPathPushNode("dummy", NPtype_NAME);
605 /* Have we seen the magic pointer? (NULL has always been seen before) */
606 while (check_new(st, magic_pointer)) {
608 NPathSetNode(magic_pointer, NPtype_MAGIC);
610 ADD_SIZE(st, "mg", sizeof(MAGIC));
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.)
617 sv_size(aTHX_ st, NPathLink("mg_obj"), magic_pointer->mg_obj, TOTAL_SIZE_RECURSION);
618 if (magic_pointer->mg_len == HEf_SVKEY) {
619 sv_size(aTHX_ st, NPathLink("mg_ptr"), (SV *)magic_pointer->mg_ptr, TOTAL_SIZE_RECURSION);
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)) {
624 ADD_SIZE(st, "PERL_MAGIC_utf8", PERL_MAGIC_UTF8_CACHESIZE * 2 * sizeof(STRLEN));
628 else if (magic_pointer->mg_len > 0) {
629 if (check_new(st, magic_pointer->mg_ptr)) {
630 ADD_SIZE(st, "mg_len", magic_pointer->mg_len);
634 /* Get the next in the chain */
635 magic_pointer = magic_pointer->mg_moremagic;
638 if (st->dangle_whine)
639 warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
645 check_new_and_strlen(struct state *st, const char *const p, pPATH) {
646 dNPathNodes(1, NPathArg->prev);
647 if(check_new(st, p)) {
648 NPathPushNode(NPathArg->id, NPtype_NAME);
649 ADD_SIZE(st, NPathArg->id, 1 + strlen(p));
654 regex_size(const REGEXP * const baseregex, struct state *st, pPATH) {
655 dNPathNodes(1, NPathArg);
656 if(!check_new(st, baseregex))
658 NPathPushNode("regex_size", NPtype_NAME);
659 ADD_SIZE(st, "REGEXP", sizeof(REGEXP));
660 #if (PERL_VERSION < 11)
661 /* Note the size of the paren offset thing */
662 ADD_SIZE(st, "nparens", sizeof(I32) * baseregex->nparens * 2);
663 ADD_SIZE(st, "precomp", strlen(baseregex->precomp));
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));*/
669 if (st->go_yell && !st->regex_whine) {
670 carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
676 op_size(pTHX_ const OP * const baseop, struct state *st, pPATH)
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.
682 dNPathUseParent(NPathArg);
686 if(!check_new(st, baseop))
689 op_size(aTHX_ baseop->op_next, st, NPathOpLink);
691 switch (cc_opclass(baseop)) {
692 case OPc_BASEOP: TAG;
693 ADD_SIZE(st, "op", sizeof(struct op));
696 ADD_SIZE(st, "unop", sizeof(struct unop));
697 op_size(aTHX_ ((UNOP *)baseop)->op_first, st, NPathOpLink);
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);
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);
710 case OPc_CONDOP: TAG;
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);
717 case OPc_LISTOP: TAG;
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);
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);
726 #if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
727 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplroot, st, NPathOpLink);
728 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplstart, st, NPathOpLink);
730 /* This is defined away in perl 5.8.x, but it is in there for
733 regex_size(PM_GETRE((PMOP *)baseop), st, NPathLink("PM_GETRE"));
735 regex_size(((PMOP *)baseop)->op_pmregexp, st, NPathLink("op_pmregexp"));
739 ADD_SIZE(st, "svop", sizeof(struct svop));
740 if (!(baseop->op_type == OP_AELEMFAST
741 && baseop->op_flags & OPf_SPECIAL)) {
742 /* not an OP_PADAV replacement */
743 sv_size(aTHX_ st, NPathLink("SVOP"), ((SVOP *)baseop)->op_sv, SOME_RECURSION);
748 ADD_SIZE(st, "padop", sizeof(struct padop));
753 ADD_SIZE(st, "gvop", sizeof(struct gvop));
754 sv_size(aTHX_ st, NPathLink("GVOP"), ((GVOP *)baseop)->op_gv, SOME_RECURSION);
758 check_new_and_strlen(st, ((PVOP *)baseop)->op_pv, NPathLink("op_pv"));
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);
771 basecop = (COP *)baseop;
772 ADD_SIZE(st, "cop", sizeof(struct cop));
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. */
781 #if (PERL_VERSION < 11)
782 check_new_and_strlen(st, basecop->cop_label, NPathLink("cop_label"));
785 check_new_and_strlen(st, basecop->cop_file, NPathLink("cop_file"));
786 check_new_and_strlen(st, basecop->cop_stashpv, NPathLink("cop_stashpv"));
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);
799 if (st->dangle_whine)
800 warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
805 hek_size(pTHX_ struct state *st, HEK *hek, U32 shared, pPATH)
807 dNPathNodes(1, NPathArg);
809 /* Hash keys can be shared. Have we seen this before? */
810 if (!check_new(st, hek))
812 NPathPushNode("hek", NPtype_NAME);
813 ADD_SIZE(st, "hek_len", HEK_BASESIZE + hek->hek_len
815 + 1 /* No hash key flags prior to 5.8.0 */
821 #if PERL_VERSION < 10
822 ADD_SIZE(st, "he", sizeof(struct he));
824 ADD_SIZE(st, "shared_he", STRUCT_OFFSET(struct shared_he, shared_he_hek));
830 #if PERL_VERSION < 8 || PERL_SUBVERSION < 9
835 # define MAYBE_PURIFY(normal, pure) (pure)
836 # define MAYBE_OFFSET(struct_name, member) 0
838 # define MAYBE_PURIFY(normal, pure) (normal)
839 # define MAYBE_OFFSET(struct_name, member) STRUCT_OFFSET(struct_name, member)
842 const U8 body_sizes[SVt_LAST] = {
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 */
860 #elif PERL_VERSION == 10 && PERL_SUBVERSION == 0
864 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
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 */
877 #elif PERL_VERSION == 10 && PERL_SUBVERSION == 1
881 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
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 */
894 #elif PERL_VERSION < 13
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 */
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 */
933 padlist_size(pTHX_ struct state *const st, pPATH, PADLIST *padlist,
936 dNPathUseParent(NPathArg);
937 /* based on Perl_do_dump_pad() */
945 pad_name = MUTABLE_AV(*av_fetch(MUTABLE_AV(padlist), 0, FALSE));
946 pname = AvARRAY(pad_name);
948 for (ix = 1; ix <= AvFILLp(pad_name); ix++) {
949 const SV *namesv = pname[ix];
950 if (namesv && namesv == &PL_sv_undef) {
955 ADD_ATTR(st, NPattr_PADFAKE, SvPVX_const(namesv), ix);
957 ADD_ATTR(st, NPattr_PADNAME, SvPVX_const(namesv), ix);
960 ADD_ATTR(st, NPattr_PADTMP, "SVs_PADTMP", ix);
964 sv_size(aTHX_ st, NPathArg, (SV*)padlist, recurse);
969 sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing,
971 const SV *thing = orig_thing;
972 dNPathNodes(3, NPathArg);
975 if(!check_new(st, orig_thing))
978 type = SvTYPE(thing);
979 if (type > SVt_LAST) {
980 warn("Devel::Size: Unknown variable type: %d encountered\n", type);
983 NPathPushNode(thing, NPtype_SV);
984 ADD_SIZE(st, "sv", sizeof(SV) + body_sizes[type]);
986 if (type >= SVt_PVMG) {
987 magic_size(aTHX_ thing, st, NPathLink("MG"));
991 #if (PERL_VERSION < 11)
992 /* Is it a reference? */
997 if(recurse && SvROK(thing))
998 sv_size(aTHX_ st, NPathLink("RV"), SvRV_const(thing), recurse);
1002 /* Is there anything in the array? */
1003 if (AvMAX(thing) != -1) {
1004 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
1005 ADD_SIZE(st, "av_max", sizeof(SV *) * (AvMAX(thing) + 1));
1006 dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
1008 if (recurse >= TOTAL_SIZE_RECURSION) {
1009 SSize_t i = AvFILLp(thing) + 1;
1012 sv_size(aTHX_ st, NPathLink("AVelem"), AvARRAY(thing)[i], recurse);
1015 /* Add in the bits on the other side of the beginning */
1017 dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
1018 st->total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
1020 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
1021 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
1022 if (AvALLOC(thing) != 0) {
1023 ADD_SIZE(st, "AvALLOC", (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing))));
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. */
1030 sv_size(aTHX_ st, NPathLink("ARYLEN"), AvARYLEN(thing), recurse);
1034 /* Now the array of buckets */
1035 ADD_SIZE(st, "hv_max", (sizeof(HE *) * (HvMAX(thing) + 1)));
1036 if (HvENAME(thing)) {
1037 ADD_ATTR(st, NPattr_NAME, HvENAME(thing), 0);
1039 /* Now walk the bucket chain */
1040 if (HvARRAY(thing)) {
1043 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
1044 cur_entry = *(HvARRAY(thing) + cur_bucket);
1046 ADD_SIZE(st, "he", sizeof(HE));
1047 hek_size(aTHX_ st, cur_entry->hent_hek, HvSHAREKEYS(thing), NPathLink("hent_hek"));
1048 if (recurse >= TOTAL_SIZE_RECURSION) {
1049 /* I've seen a PL_strtab HeVAL == 0xC and 0x40C etc
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.
1054 if (PTR2UV(HeVAL(cur_entry)) > 0xFFF)
1055 sv_size(aTHX_ st, NPathLink("HeVAL"), HeVAL(cur_entry), recurse);
1057 cur_entry = cur_entry->hent_next;
1063 /* This direct access is arguably "naughty": */
1064 struct mro_meta *meta = HvAUX(thing)->xhv_mro_meta;
1065 #if PERL_VERSION > 13 || PERL_SUBVERSION > 8
1067 I32 count = HvAUX(thing)->xhv_name_count;
1070 HEK **names = HvAUX(thing)->xhv_name_u.xhvnameu_names;
1074 hek_size(aTHX_ st, names[count], 1, NPathLink("HvAUXelem"));
1079 hek_size(aTHX_ st, HvNAME_HEK(thing), 1, NPathLink("HvNAME_HEK"));
1082 ADD_SIZE(st, "xpvhv_aux", sizeof(struct xpvhv_aux));
1084 ADD_SIZE(st, "mro_meta", sizeof(struct mro_meta));
1085 sv_size(aTHX_ st, NPathLink("mro_nextmethod"), (SV *)meta->mro_nextmethod, TOTAL_SIZE_RECURSION);
1086 #if PERL_VERSION > 10 || (PERL_VERSION == 10 && PERL_SUBVERSION > 0)
1087 sv_size(aTHX_ st, NPathLink("isa"), (SV *)meta->isa, TOTAL_SIZE_RECURSION);
1089 #if PERL_VERSION > 10
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);
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);
1099 check_new_and_strlen(st, HvNAME_get(thing), NPathLink("HvNAME"));
1105 padlist_size(aTHX_ st, NPathLink("CvPADLIST"), CvPADLIST(thing), SOME_RECURSION);
1106 sv_size(aTHX_ st, NPathLink("CvOUTSIDE"), (SV *)CvOUTSIDE(thing), recurse);
1108 if (st->go_yell && !st->fm_whine) {
1109 carp("Devel::Size: Calculated sizes for FMs are incomplete");
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);
1120 if (CvISXSUB(thing)) {
1121 sv_size(aTHX_ st, NPathLink("cv_const_sv"), cv_const_sv((CV *)thing), recurse);
1123 op_size(aTHX_ CvSTART(thing), st, NPathLink("CvSTART"));
1124 op_size(aTHX_ CvROOT(thing), st, NPathLink("CvROOT"));
1129 /* Some embedded char pointers */
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"));
1133 /* Throw the GVs on the list to be walked if they're not-null */
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);
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 */
1142 /* Dig into xio_ifp and xio_ofp here */
1143 warn("Devel::Size: Can't size up perlio layers yet\n");
1148 #if (PERL_VERSION < 9)
1153 if(isGV_with_GP(thing)) {
1155 hek_size(aTHX_ st, GvNAME_HEK(thing), 1, NPathLink("GvNAME_HEK"));
1157 ADD_SIZE(st, "GvNAMELEN", GvNAMELEN(thing));
1159 ADD_ATTR(st, NPattr_NAME, GvNAME_get(thing), 0);
1161 hek_size(aTHX_ st, GvFILE_HEK(thing), 1, NPathLink("GvFILE_HEK"));
1162 #elif defined(GvFILE)
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) */
1171 check_new_and_strlen(st, GvFILE(thing), NPathLink("GvFILE"));
1174 /* Is there something hanging off the glob? */
1175 if (check_new(st, GvGP(thing))) {
1176 ADD_SIZE(st, "GP", sizeof(GP));
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);
1184 #if (PERL_VERSION >= 9)
1188 #if PERL_VERSION <= 8
1196 if(recurse && SvROK(thing))
1197 sv_size(aTHX_ st, NPathLink("RV"), SvRV_const(thing), recurse);
1198 else if (SvIsCOW_shared_hash(thing))
1199 hek_size(aTHX_ st, SvSHARED_HEK_FROM_PV(SvPVX(thing)), 1, NPathLink("SvSHARED_HEK_FROM_PV"));
1201 ADD_SIZE(st, "SvLEN", SvLEN(thing));
1205 SvOOK_offset(thing, len);
1206 ADD_SIZE(st, "SvOOK", len);
1214 static struct state *
1220 Newxz(st, 1, struct state);
1222 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
1223 st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
1225 if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
1226 st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
1228 check_new(st, &PL_sv_undef);
1229 check_new(st, &PL_sv_no);
1230 check_new(st, &PL_sv_yes);
1231 #if PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 0)
1232 check_new(st, &PL_sv_placeholder);
1234 #ifdef PATH_TRACKING
1236 st->node_stream = stdout;
1237 if (st->node_stream)
1238 st->add_attr_cb = np_stream_node_path_info;
1240 st->add_attr_cb = np_dump_node_path_info;
1245 MODULE = Devel::Size PACKAGE = Devel::Size
1253 total_size = TOTAL_SIZE_RECURSION
1256 SV *thing = orig_thing;
1257 struct state *st = new_state(aTHX);
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 */
1262 thing = SvRV(thing);
1265 sv_size(aTHX_ st, NULL, thing, ix);
1266 RETVAL = st->total_size;
1276 dNPathNodes(2, NULL);
1277 struct state *st = new_state(aTHX);
1278 NPathPushNode("perl_size", NPtype_NAME); /* provide a root node */
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
1283 sv_size(aTHX_ st, NPathLink("PL_defstash"), (SV*)PL_defstash, TOTAL_SIZE_RECURSION);
1285 NPathPushNode("others", NPtype_NAME); /* group these (typically much smaller) items */
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);
1297 sv_size(aTHX_ st, NPathLink("PL_regex_padav"), (SV*)PL_regex_padav, TOTAL_SIZE_RECURSION);
1299 /* TODO PL_pidstatus */
1300 /* TODO PL_stashpad */
1302 /* in theory we shouldn't have any elements in PL_strtab that haven't been seen yet */
1303 sv_size(aTHX_ st, NPathLink("PL_strtab"), (SV*)PL_strtab, TOTAL_SIZE_RECURSION);
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 */
1309 /* TODO anything missed? */
1311 RETVAL = st->total_size;