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 int min_recurse_threshold;
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);
102 void *state_cb_data; /* free'd by free_state() after free_state_cb() call */
103 /* this stuff wil be moved to state_cb_data later */
107 #define ADD_SIZE(st, leafname, bytes) (NPathAddSizeCb(st, leafname, bytes) (st)->total_size += (bytes))
109 #define PATH_TRACKING
112 #define pPATH npath_node_t *NPathArg
114 /* A subtle point here is that dNPathNodes and NPathPushNode leave NP pointing
115 * to the next unused slot (though with prev already filled in)
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.
118 * seqn==0 indicates the node is new (hasn't been output yet)
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]; \
123 NP->seqn = NP->type = 0; NP->id = Nullch; /* safety/debug */ \
125 #define NPathPushNode(nodeid, nodetype) \
127 NP->type = nodetype; \
129 if(0)fprintf(stderr,"NPathPushNode (%p <-) %p <- [%d %s]\n", NP->prev, NP, nodetype,(char*)nodeid);\
131 NP->id = Nullch; /* safety/debug */ \
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);\
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.
144 #define dNPathUseParent(prev_np) npath_node_t *NP = (((prev_np+1)->prev = prev_np), prev_np+1)
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
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
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))
162 #define NPathOpLink (NPathArg)
163 #define NPathAddSizeCb(st, name, bytes) (st->add_attr_cb && st->add_attr_cb(st, NP-1, NPattr_LEAFSIZE, (name), (bytes))),
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))
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
175 #endif /* PATH_TRACKING */
182 static const char *svtypenames[SVt_LAST] = {
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",
192 "NULL", "BIND", "IV", "NV", "PV", "PVIV", "PVNV", "PVMG", "REGEXP", "PVGV", "PVLV", "PVAV", "PVHV", "PVCV", "PVFM", "PVIO",
197 np_print_node_name(FILE *fp, npath_node_t *npath_node)
199 char buf[1024]; /* XXX */
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];
206 fprintf(fp, "SV(%s)", typename);
207 switch(type) { /* add some useful details */
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;
213 case NPtype_OP: { /* id is pointer to the OP op_size was called on */
214 const OP *op = (OP*)npath_node->id;
215 fprintf(fp, "OP(%s)", OP_NAME(op));
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] */
221 fprintf(fp, "MAGIC(%c)", magic_pointer->mg_type ? magic_pointer->mg_type : '0');
225 fprintf(fp, "%s->", npath_node->id);
228 fprintf(fp, "%s", npath_node->id);
230 default: /* assume id is a string pointer */
231 fprintf(fp, "UNKNOWN(%d,%p)", npath_node->type, npath_node->id);
238 np_dump_indent(int depth) {
240 fprintf(stderr, ": ");
244 np_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))
249 if (npath_node->seqn) /* node already output */
252 if (npath_node->prev) {
253 np_walk_new_nodes(st, npath_node->prev, npath_node, cb); /* recurse */
254 npath_node->depth = npath_node->prev->depth + 1;
256 else npath_node->depth = 0;
257 npath_node->seqn = ++st->seqn;
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);
266 npath_node->seqn = --st->seqn;
267 npath_node_deeper->prev = npath_node->prev;
275 np_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)
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");
286 np_dump_node_path_info(struct state *st, npath_node_t *npath_node, UV attr_type, const char *attr_name, UV attr_value)
288 if (!attr_type && !attr_value)
289 return 0; /* ignore zero sized leaf items */
290 np_walk_new_nodes(st, npath_node, NULL, np_dump_formatted_node);
291 np_dump_indent(npath_node->depth+1);
293 fprintf(stderr, "~NAMED('%s') %lu", attr_name, attr_value);
296 fprintf(stderr, "+%ld ", attr_value);
297 fprintf(stderr, "%s ", attr_name);
298 fprintf(stderr, "=%ld ", attr_value+st->total_size);
300 fprintf(stderr, "\n");
305 np_stream_formatted_node(struct state *st, npath_node_t *npath_node, npath_node_t *npath_node_deeper) {
306 fprintf(st->node_stream, "-%u %lu %u ",
307 npath_node->type, npath_node->seqn, (unsigned)npath_node->depth
309 np_print_node_name(st->node_stream, npath_node);
310 fprintf(st->node_stream, "\n");
315 np_stream_node_path_info(struct state *st, npath_node_t *npath_node, UV attr_type, const char *attr_name, UV attr_value)
317 if (!attr_type && !attr_value)
318 return 0; /* ignore zero sized leaf items */
319 np_walk_new_nodes(st, npath_node, NULL, np_stream_formatted_node);
320 if (attr_type) { /* Attribute type, name and value */
321 fprintf(st->node_stream, "%lu %lu ", attr_type, npath_node->seqn);
323 else { /* Leaf name and memory size */
324 fprintf(st->node_stream, "L %lu ", npath_node->seqn);
326 fprintf(st->node_stream, "%lu %s\n", attr_value, attr_name);
330 #endif /* PATH_TRACKING */
334 Checks to see if thing is in the bitstring.
335 Returns true or false, and
336 notes thing in the segmented bitstring.
339 check_new(struct state *st, const void *const p) {
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
347 const size_t cooked_p
348 = (raw_p >> ALIGN_BITS) | (raw_p << (bits - ALIGN_BITS));
349 const U8 this_bit = 1 << (cooked_p & 0x7);
353 void **tv_p = (void **) (st->tracking);
355 if (NULL == p) return FALSE;
357 const char c = *(const char *)p;
360 if (st->dangle_whine)
361 warn( "Devel::Size: Encountered invalid pointer: %p\n", p );
367 /* bits now 24 (32 bit pointers) or 56 (64 bit pointers) */
369 /* First level is always present. */
371 i = (unsigned int)((cooked_p >> bits) & 0xFF);
373 Newxz(tv_p[i], 256, void *);
374 tv_p = (void **)(tv_p[i]);
376 } while (bits > LEAF_BITS + BYTE_BITS);
377 /* bits now 16 always */
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 */
383 leaf_p = (U8 **)tv_p;
384 i = (unsigned int)((cooked_p >> bits) & 0xFF);
386 Newxz(leaf_p[i], 1 << LEAF_BITS, U8);
391 i = (unsigned int)((cooked_p >> BYTE_BITS) & LEAF_MASK);
393 if(leaf[i] & this_bit)
401 free_tracking_at(void **tv, int level)
409 free_tracking_at((void **) tv[i], level);
423 free_state(struct state *st)
425 const int top_level = (sizeof(void *) * 8 - LEAF_BITS - BYTE_BITS) / 8;
426 if (st->free_state_cb)
427 st->free_state_cb(st);
428 if (st->state_cb_data)
429 Safefree(st->state_cb_data);
430 free_tracking_at((void **)st->tracking, top_level);
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. */
444 #define NO_RECURSION 0
445 #define SOME_RECURSION 1
446 #define TOTAL_SIZE_RECURSION 2
448 static void sv_size(pTHX_ struct state *, pPATH, const SV *const, const int recurse);
464 , OPc_CONDOP /* 12 */
473 cc_opclass(const OP * const o)
479 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
481 if (o->op_type == OP_SASSIGN)
482 return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
485 if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
489 if ((o->op_type == OP_TRANS)) {
493 switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
525 #ifdef OA_PVOP_OR_SVOP
526 case OA_PVOP_OR_SVOP: TAG;
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).
534 return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
535 ? OPc_SVOP : OPc_PVOP;
544 case OA_BASEOP_OR_UNOP: TAG;
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.
552 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
554 case OA_FILESTATOP: TAG;
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).
564 return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
566 (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
568 (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
570 case OA_LOOPEXOP: TAG;
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
580 if (o->op_flags & OPf_STACKED)
582 else if (o->op_flags & OPf_SPECIAL)
592 warn("Devel::Size: Can't determine class of operator %s, assuming BASEOP\n",
593 PL_op_name[o->op_type]);
599 /* Figure out how much magic is attached to the SV and return the
602 magic_size(pTHX_ const SV * const thing, struct state *st, pPATH) {
603 dNPathNodes(1, NPathArg);
604 MAGIC *magic_pointer = SvMAGIC(thing);
606 /* push a dummy node for NPathSetNode to update inside the while loop */
607 NPathPushNode("dummy", NPtype_NAME);
609 /* Have we seen the magic pointer? (NULL has always been seen before) */
610 while (check_new(st, magic_pointer)) {
612 NPathSetNode(magic_pointer, NPtype_MAGIC);
614 ADD_SIZE(st, "mg", sizeof(MAGIC));
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.)
621 sv_size(aTHX_ st, NPathLink("mg_obj"), magic_pointer->mg_obj, TOTAL_SIZE_RECURSION);
622 if (magic_pointer->mg_len == HEf_SVKEY) {
623 sv_size(aTHX_ st, NPathLink("mg_ptr"), (SV *)magic_pointer->mg_ptr, TOTAL_SIZE_RECURSION);
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)) {
628 ADD_SIZE(st, "PERL_MAGIC_utf8", PERL_MAGIC_UTF8_CACHESIZE * 2 * sizeof(STRLEN));
632 else if (magic_pointer->mg_len > 0) {
633 if (check_new(st, magic_pointer->mg_ptr)) {
634 ADD_SIZE(st, "mg_len", magic_pointer->mg_len);
638 /* Get the next in the chain */
639 magic_pointer = magic_pointer->mg_moremagic;
642 if (st->dangle_whine)
643 warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
649 check_new_and_strlen(struct state *st, const char *const p, pPATH) {
650 dNPathNodes(1, NPathArg->prev);
651 if(check_new(st, p)) {
652 NPathPushNode(NPathArg->id, NPtype_NAME);
653 ADD_SIZE(st, NPathArg->id, 1 + strlen(p));
658 regex_size(const REGEXP * const baseregex, struct state *st, pPATH) {
659 dNPathNodes(1, NPathArg);
660 if(!check_new(st, baseregex))
662 NPathPushNode("regex_size", NPtype_NAME);
663 ADD_SIZE(st, "REGEXP", sizeof(REGEXP));
664 #if (PERL_VERSION < 11)
665 /* Note the size of the paren offset thing */
666 ADD_SIZE(st, "nparens", sizeof(I32) * baseregex->nparens * 2);
667 ADD_SIZE(st, "precomp", strlen(baseregex->precomp));
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));*/
673 if (st->go_yell && !st->regex_whine) {
674 carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
680 op_size(pTHX_ const OP * const baseop, struct state *st, pPATH)
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().
687 dNPathUseParent(NPathArg);
691 if(!check_new(st, baseop))
694 op_size(aTHX_ baseop->op_next, st, NPathOpLink);
696 switch (cc_opclass(baseop)) {
697 case OPc_BASEOP: TAG;
698 ADD_SIZE(st, "op", sizeof(struct op));
701 ADD_SIZE(st, "unop", sizeof(struct unop));
702 op_size(aTHX_ ((UNOP *)baseop)->op_first, st, NPathOpLink);
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);
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);
715 case OPc_CONDOP: TAG;
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);
722 case OPc_LISTOP: TAG;
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);
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);
731 #if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
732 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplroot, st, NPathOpLink);
733 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplstart, st, NPathOpLink);
735 /* This is defined away in perl 5.8.x, but it is in there for
738 regex_size(PM_GETRE((PMOP *)baseop), st, NPathLink("PM_GETRE"));
740 regex_size(((PMOP *)baseop)->op_pmregexp, st, NPathLink("op_pmregexp"));
744 ADD_SIZE(st, "svop", sizeof(struct svop));
745 if (!(baseop->op_type == OP_AELEMFAST
746 && baseop->op_flags & OPf_SPECIAL)) {
747 /* not an OP_PADAV replacement */
748 sv_size(aTHX_ st, NPathLink("SVOP"), ((SVOP *)baseop)->op_sv, SOME_RECURSION);
753 ADD_SIZE(st, "padop", sizeof(struct padop));
758 ADD_SIZE(st, "gvop", sizeof(struct gvop));
759 sv_size(aTHX_ st, NPathLink("GVOP"), ((GVOP *)baseop)->op_gv, SOME_RECURSION);
763 check_new_and_strlen(st, ((PVOP *)baseop)->op_pv, NPathLink("op_pv"));
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);
776 basecop = (COP *)baseop;
777 ADD_SIZE(st, "cop", sizeof(struct cop));
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. */
786 #if (PERL_VERSION < 11)
787 check_new_and_strlen(st, basecop->cop_label, NPathLink("cop_label"));
790 check_new_and_strlen(st, basecop->cop_file, NPathLink("cop_file"));
791 check_new_and_strlen(st, basecop->cop_stashpv, NPathLink("cop_stashpv"));
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);
804 if (st->dangle_whine)
805 warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
810 hek_size(pTHX_ struct state *st, HEK *hek, U32 shared, pPATH)
812 dNPathNodes(1, NPathArg);
814 /* Hash keys can be shared. Have we seen this before? */
815 if (!check_new(st, hek))
817 NPathPushNode("hek", NPtype_NAME);
818 ADD_SIZE(st, "hek_len", HEK_BASESIZE + hek->hek_len
820 + 1 /* No hash key flags prior to 5.8.0 */
826 #if PERL_VERSION < 10
827 ADD_SIZE(st, "he", sizeof(struct he));
829 ADD_SIZE(st, "shared_he", STRUCT_OFFSET(struct shared_he, shared_he_hek));
835 #if PERL_VERSION < 8 || PERL_SUBVERSION < 9
840 # define MAYBE_PURIFY(normal, pure) (pure)
841 # define MAYBE_OFFSET(struct_name, member) 0
843 # define MAYBE_PURIFY(normal, pure) (normal)
844 # define MAYBE_OFFSET(struct_name, member) STRUCT_OFFSET(struct_name, member)
847 const U8 body_sizes[SVt_LAST] = {
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 */
865 #elif PERL_VERSION == 10 && PERL_SUBVERSION == 0
869 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
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 */
882 #elif PERL_VERSION == 10 && PERL_SUBVERSION == 1
886 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
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 */
899 #elif PERL_VERSION < 13
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 */
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 */
937 /* based on Perl_do_dump_pad() - wraps sv_size and adds ADD_ATTR calls for the pad names */
939 padlist_size(pTHX_ struct state *const st, pPATH, PADLIST *padlist,
942 dNPathUseParent(NPathArg);
950 pad_name = MUTABLE_AV(*av_fetch(MUTABLE_AV(padlist), 0, FALSE));
951 pname = AvARRAY(pad_name);
953 for (ix = 1; ix <= AvFILLp(pad_name); ix++) {
954 const SV *namesv = pname[ix];
955 if (namesv && namesv == &PL_sv_undef) {
960 ADD_ATTR(st, NPattr_PADFAKE, SvPVX_const(namesv), ix);
962 ADD_ATTR(st, NPattr_PADNAME, SvPVX_const(namesv), ix);
965 ADD_ATTR(st, NPattr_PADTMP, "SVs_PADTMP", ix);
969 sv_size(aTHX_ st, NPathArg, (SV*)padlist, recurse);
974 sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing,
976 const SV *thing = orig_thing;
977 dNPathNodes(3, NPathArg);
980 if(!check_new(st, orig_thing))
983 type = SvTYPE(thing);
984 if (type > SVt_LAST) {
985 warn("Devel::Size: Unknown variable type: %d encountered\n", type);
988 NPathPushNode(thing, NPtype_SV);
989 ADD_SIZE(st, "sv", sizeof(SV) + body_sizes[type]);
991 if (type >= SVt_PVMG) {
992 magic_size(aTHX_ thing, st, NPathLink("MG"));
996 #if (PERL_VERSION < 11)
997 /* Is it a reference? */
1002 if(recurse && SvROK(thing))
1003 sv_size(aTHX_ st, NPathLink("RV"), SvRV_const(thing), recurse);
1007 /* Is there anything in the array? */
1008 if (AvMAX(thing) != -1) {
1009 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
1010 ADD_SIZE(st, "av_max", sizeof(SV *) * (AvMAX(thing) + 1));
1011 dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
1013 if (recurse >= st->min_recurse_threshold) {
1014 SSize_t i = AvFILLp(thing) + 1;
1017 sv_size(aTHX_ st, NPathLink("AVelem"), AvARRAY(thing)[i], recurse);
1020 /* Add in the bits on the other side of the beginning */
1022 dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
1023 st->total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
1025 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
1026 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
1027 if (AvALLOC(thing) != 0) {
1028 ADD_SIZE(st, "AvALLOC", (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing))));
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. */
1035 sv_size(aTHX_ st, NPathLink("ARYLEN"), AvARYLEN(thing), recurse);
1039 /* Now the array of buckets */
1040 ADD_SIZE(st, "hv_max", (sizeof(HE *) * (HvMAX(thing) + 1)));
1041 if (HvENAME(thing)) {
1042 ADD_ATTR(st, NPattr_NAME, HvENAME(thing), 0);
1044 /* Now walk the bucket chain */
1045 if (HvARRAY(thing)) {
1048 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
1049 cur_entry = *(HvARRAY(thing) + cur_bucket);
1051 ADD_SIZE(st, "he", sizeof(HE));
1052 hek_size(aTHX_ st, cur_entry->hent_hek, HvSHAREKEYS(thing), NPathLink("hent_hek"));
1053 if (recurse >= st->min_recurse_threshold) {
1054 /* I've seen a PL_strtab HeVAL == 0xC and 0x40C etc
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.
1059 if (PTR2UV(HeVAL(cur_entry)) > 0xFFF)
1060 sv_size(aTHX_ st, NPathLink("HeVAL"), HeVAL(cur_entry), recurse);
1062 cur_entry = cur_entry->hent_next;
1068 /* This direct access is arguably "naughty": */
1069 struct mro_meta *meta = HvAUX(thing)->xhv_mro_meta;
1070 #if PERL_VERSION > 13 || PERL_SUBVERSION > 8
1072 I32 count = HvAUX(thing)->xhv_name_count;
1075 HEK **names = HvAUX(thing)->xhv_name_u.xhvnameu_names;
1079 hek_size(aTHX_ st, names[count], 1, NPathLink("HvAUXelem"));
1084 hek_size(aTHX_ st, HvNAME_HEK(thing), 1, NPathLink("HvNAME_HEK"));
1087 ADD_SIZE(st, "xpvhv_aux", sizeof(struct xpvhv_aux));
1089 ADD_SIZE(st, "mro_meta", sizeof(struct mro_meta));
1090 sv_size(aTHX_ st, NPathLink("mro_nextmethod"), (SV *)meta->mro_nextmethod, TOTAL_SIZE_RECURSION);
1091 #if PERL_VERSION > 10 || (PERL_VERSION == 10 && PERL_SUBVERSION > 0)
1092 sv_size(aTHX_ st, NPathLink("isa"), (SV *)meta->isa, TOTAL_SIZE_RECURSION);
1094 #if PERL_VERSION > 10
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);
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);
1104 check_new_and_strlen(st, HvNAME_get(thing), NPathLink("HvNAME"));
1110 padlist_size(aTHX_ st, NPathLink("CvPADLIST"), CvPADLIST(thing), SOME_RECURSION);
1111 sv_size(aTHX_ st, NPathLink("CvOUTSIDE"), (SV *)CvOUTSIDE(thing), recurse);
1113 if (st->go_yell && !st->fm_whine) {
1114 carp("Devel::Size: Calculated sizes for FMs are incomplete");
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);
1125 if (CvISXSUB(thing)) {
1126 sv_size(aTHX_ st, NPathLink("cv_const_sv"), cv_const_sv((CV *)thing), recurse);
1128 if(1)op_size(aTHX_ CvSTART(thing), st, NPathLinkAndNode("CvSTART", "OPs")); /* XXX ? */
1129 op_size(aTHX_ CvROOT(thing), st, NPathLinkAndNode("CvROOT", "OPs"));
1134 /* Some embedded char pointers */
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"));
1138 /* Throw the GVs on the list to be walked if they're not-null */
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);
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 */
1147 /* Dig into xio_ifp and xio_ofp here */
1148 warn("Devel::Size: Can't size up perlio layers yet\n");
1153 #if (PERL_VERSION < 9)
1158 if(isGV_with_GP(thing)) {
1160 hek_size(aTHX_ st, GvNAME_HEK(thing), 1, NPathLink("GvNAME_HEK"));
1162 ADD_SIZE(st, "GvNAMELEN", GvNAMELEN(thing));
1164 ADD_ATTR(st, NPattr_NAME, GvNAME_get(thing), 0);
1166 hek_size(aTHX_ st, GvFILE_HEK(thing), 1, NPathLink("GvFILE_HEK"));
1167 #elif defined(GvFILE)
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) */
1176 check_new_and_strlen(st, GvFILE(thing), NPathLink("GvFILE"));
1179 /* Is there something hanging off the glob? */
1180 if (check_new(st, GvGP(thing))) {
1181 ADD_SIZE(st, "GP", sizeof(GP));
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);
1189 #if (PERL_VERSION >= 9)
1193 #if PERL_VERSION <= 8
1201 if(recurse && SvROK(thing))
1202 sv_size(aTHX_ st, NPathLink("RV"), SvRV_const(thing), recurse);
1203 else if (SvIsCOW_shared_hash(thing))
1204 hek_size(aTHX_ st, SvSHARED_HEK_FROM_PV(SvPVX(thing)), 1, NPathLink("SvSHARED_HEK_FROM_PV"));
1206 ADD_SIZE(st, "SvLEN", SvLEN(thing));
1210 SvOOK_offset(thing, len);
1211 ADD_SIZE(st, "SvOOK", len);
1219 static struct state *
1225 Newxz(st, 1, struct state);
1227 st->min_recurse_threshold = TOTAL_SIZE_RECURSION;
1228 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
1229 st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
1231 if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
1232 st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
1234 check_new(st, &PL_sv_undef);
1235 check_new(st, &PL_sv_no);
1236 check_new(st, &PL_sv_yes);
1237 #if PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 0)
1238 check_new(st, &PL_sv_placeholder);
1240 #ifdef PATH_TRACKING
1241 if (getenv("M") && atoi(getenv("M"))) /* XXX quick hack */
1242 st->node_stream = stdout;
1243 if (st->node_stream)
1244 st->add_attr_cb = np_stream_node_path_info;
1246 st->add_attr_cb = np_dump_node_path_info;
1251 MODULE = Devel::Size PACKAGE = Devel::Size
1259 total_size = TOTAL_SIZE_RECURSION
1262 SV *thing = orig_thing;
1263 struct state *st = new_state(aTHX);
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 */
1268 thing = SvRV(thing);
1271 sv_size(aTHX_ st, NULL, thing, ix);
1272 RETVAL = st->total_size;
1282 dNPathNodes(2, NULL);
1283 struct state *st = new_state(aTHX);
1284 NPathPushNode("perl_size", NPtype_NAME); /* provide a root node */
1286 st->min_recurse_threshold = NO_RECURSION; /* so always recurse */
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
1291 sv_size(aTHX_ st, NPathLink("PL_defstash"), (SV*)PL_defstash, TOTAL_SIZE_RECURSION);
1293 NPathPushNode("others", NPtype_NAME); /* group these (typically much smaller) items */
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);
1305 sv_size(aTHX_ st, NPathLink("PL_regex_padav"), (SV*)PL_regex_padav, TOTAL_SIZE_RECURSION);
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);
1313 /* TODO PL_pidstatus */
1314 /* TODO PL_stashpad */
1315 /* TODO PL_compiling? COP */
1317 /* in theory we shouldn't have any elements in PL_strtab that haven't been seen yet */
1318 sv_size(aTHX_ st, NPathLink("PL_strtab"), (SV*)PL_strtab, TOTAL_SIZE_RECURSION);
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 */
1323 /* TODO PL_exitlist */
1325 /* TODO PerlIO? PL_known_layers PL_def_layerlist PL_perlio_fd_refcnt etc */
1327 /* TODO anything missed? */
1329 RETVAL = st->total_size;