5 static int regex_whine;
10 UV thing_size(SV *, HV *);
33 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
35 if (o->op_type == OP_SASSIGN)
36 return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
39 if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
43 if ((o->op_type = OP_TRANS)) {
47 switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
74 * Character translations (tr///) are usually a PVOP, keeping a
75 * pointer to a table of shorts used to look up translations.
76 * Under utf8, however, a simple table isn't practical; instead,
77 * the OP is an SVOP, and the SV is a reference to a swash
78 * (i.e., an RV pointing to an HV).
80 return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
81 ? OPc_SVOP : OPc_PVOP;
89 case OA_BASEOP_OR_UNOP:
91 * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on
92 * whether parens were seen. perly.y uses OPf_SPECIAL to
93 * signal whether a BASEOP had empty parens or none.
94 * Some other UNOPs are created later, though, so the best
95 * test is OPf_KIDS, which is set in newUNOP.
97 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
101 * The file stat OPs are created via UNI(OP_foo) in toke.c but use
102 * the OPf_REF flag to distinguish between OP types instead of the
103 * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we
104 * return OPc_UNOP so that walkoptree can find our children. If
105 * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set
106 * (no argument to the operator) it's an OP; with OPf_REF set it's
107 * an SVOP (and op_sv is the GV for the filehandle argument).
109 return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
111 (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
113 (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
117 * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a
118 * label was omitted (in which case it's a BASEOP) or else a term was
119 * seen. In this last case, all except goto are definitely PVOP but
120 * goto is either a PVOP (with an ordinary constant label), an UNOP
121 * with OPf_STACKED (with a non-constant non-sub) or an UNOP for
122 * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to
125 if (o->op_flags & OPf_STACKED)
127 else if (o->op_flags & OPf_SPECIAL)
132 warn("can't determine class of operator %s, assuming BASEOP\n",
133 PL_op_name[o->op_type]);
142 static int go_yell = 1;
144 /* Checks to see if thing is in the hash. Returns true or false, and
145 notes thing in the hash.
147 This code does one Evil Thing. Since we're tracking pointers, we
148 tell perl that the string key is the address in the pointer. We do this by
149 passing in the address of the address, along with the size of a
150 pointer as the length. Perl then uses the four (or eight, on
151 64-bit machines) bytes of the address as the string we're using as
153 IV check_new(HV *tracking_hash, const void *thing) {
157 if (hv_exists(tracking_hash, (char *)&thing, sizeof(void *))) {
160 hv_store(tracking_hash, (char *)&thing, sizeof(void *), &PL_sv_yes, 0);
165 /* Figure out how much magic is attached to the SV and return the
167 IV magic_size(SV *thing, HV *tracking_hash) {
169 MAGIC *magic_pointer;
172 if (!SvMAGIC(thing)) {
177 /* Get the base magic pointer */
178 magic_pointer = SvMAGIC(thing);
180 /* Have we seen the magic pointer? */
181 while (magic_pointer && check_new(tracking_hash, magic_pointer)) {
182 total_size += sizeof(MAGIC);
184 /* Have we seen the magic vtable? */
185 if (magic_pointer->mg_virtual &&
186 check_new(tracking_hash, magic_pointer->mg_virtual)) {
187 total_size += sizeof(MGVTBL);
190 /* Get the next in the chain */
191 magic_pointer = magic_pointer->mg_moremagic;
197 UV regex_size(REGEXP *baseregex, HV *tracking_hash) {
200 total_size += sizeof(REGEXP);
201 /* Note hte size of the paren offset thing */
202 total_size += sizeof(I32) * baseregex->nparens * 2;
203 total_size += strlen(baseregex->precomp);
205 if (go_yell && !regex_whine) {
206 carp("Devel::Size: Calculated sizes for compiled regexes are incomple, and probably always will be");
213 UV op_size(OP *baseop, HV *tracking_hash) {
216 if (check_new(tracking_hash, baseop->op_next)) {
217 total_size += op_size(baseop->op_next, tracking_hash);
220 switch (cc_opclass(baseop)) {
222 total_size += sizeof(struct op);
225 total_size += sizeof(struct unop);
226 if (check_new(tracking_hash, cUNOPx(baseop)->op_first)) {
227 total_size += op_size(cUNOPx(baseop)->op_first, tracking_hash);
231 total_size += sizeof(struct binop);
232 if (check_new(tracking_hash, cBINOPx(baseop)->op_first)) {
233 total_size += op_size(cBINOPx(baseop)->op_first, tracking_hash);
235 if (check_new(tracking_hash, cBINOPx(baseop)->op_last)) {
236 total_size += op_size(cBINOPx(baseop)->op_last, tracking_hash);
240 total_size += sizeof(struct logop);
241 if (check_new(tracking_hash, cLOGOPx(baseop)->op_first)) {
242 total_size += op_size(cBINOPx(baseop)->op_first, tracking_hash);
244 if (check_new(tracking_hash, cLOGOPx(baseop)->op_other)) {
245 total_size += op_size(cLOGOPx(baseop)->op_other, tracking_hash);
249 total_size += sizeof(struct listop);
250 if (check_new(tracking_hash, cLISTOPx(baseop)->op_first)) {
251 total_size += op_size(cLISTOPx(baseop)->op_first, tracking_hash);
253 if (check_new(tracking_hash, cLISTOPx(baseop)->op_last)) {
254 total_size += op_size(cLISTOPx(baseop)->op_last, tracking_hash);
258 total_size += sizeof(struct pmop);
259 if (check_new(tracking_hash, cPMOPx(baseop)->op_first)) {
260 total_size += op_size(cPMOPx(baseop)->op_first, tracking_hash);
262 if (check_new(tracking_hash, cPMOPx(baseop)->op_last)) {
263 total_size += op_size(cPMOPx(baseop)->op_last, tracking_hash);
265 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmreplroot)) {
266 total_size += op_size(cPMOPx(baseop)->op_pmreplroot, tracking_hash);
268 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmreplstart)) {
269 total_size += op_size(cPMOPx(baseop)->op_pmreplstart, tracking_hash);
271 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmnext)) {
272 total_size += op_size((OP *)cPMOPx(baseop)->op_pmnext, tracking_hash);
274 /* This is defined away in perl 5.8.x, but it is in there for
277 if (check_new(tracking_hash, PM_GETRE((cPMOPx(baseop))))) {
278 total_size += regex_size(PM_GETRE(cPMOPx(baseop)), tracking_hash);
281 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmregexp)) {
282 total_size += regex_size(cPMOPx(baseop)->op_pmregexp, tracking_hash);
287 total_size += sizeof(struct pmop);
288 if (check_new(tracking_hash, cSVOPx(baseop)->op_sv)) {
289 total_size += thing_size(cSVOPx(baseop)->op_sv, tracking_hash);
293 total_size += sizeof(struct padop);
296 if (check_new(tracking_hash, cPVOPx(baseop)->op_pv)) {
297 total_size += strlen(cPVOPx(baseop)->op_pv);
300 total_size += sizeof(struct loop);
301 if (check_new(tracking_hash, cLOOPx(baseop)->op_first)) {
302 total_size += op_size(cLOOPx(baseop)->op_first, tracking_hash);
304 if (check_new(tracking_hash, cLOOPx(baseop)->op_last)) {
305 total_size += op_size(cLOOPx(baseop)->op_last, tracking_hash);
307 if (check_new(tracking_hash, cLOOPx(baseop)->op_redoop)) {
308 total_size += op_size(cLOOPx(baseop)->op_redoop, tracking_hash);
310 if (check_new(tracking_hash, cLOOPx(baseop)->op_nextop)) {
311 total_size += op_size(cLOOPx(baseop)->op_nextop, tracking_hash);
313 /* Not working for some reason, but the code's here for later
315 if (check_new(tracking_hash, cLOOPx(baseop)->op_lastop)) {
316 total_size += op_size(cLOOPx(baseop)->op_lastop, tracking_hash);
323 basecop = (COP *)baseop;
324 total_size += sizeof(struct cop);
326 if (check_new(tracking_hash, basecop->cop_label)) {
327 total_size += strlen(basecop->cop_label);
330 if (check_new(tracking_hash, basecop->cop_file)) {
331 total_size += strlen(basecop->cop_file);
333 if (check_new(tracking_hash, basecop->cop_stashpv)) {
334 total_size += strlen(basecop->cop_stashpv);
337 if (check_new(tracking_hash, basecop->cop_stash)) {
338 total_size += thing_size((SV *)basecop->cop_stash, tracking_hash);
340 if (check_new(tracking_hash, basecop->cop_filegv)) {
341 total_size += thing_size((SV *)basecop->cop_filegv, tracking_hash);
353 #if PERL_VERSION > 9 || (PERL_VERSION == 9 && PERL_SUBVERSION > 2)
354 # define NEW_HEAD_LAYOUT
357 UV thing_size(SV *orig_thing, HV *tracking_hash) {
358 SV *thing = orig_thing;
359 UV total_size = sizeof(SV);
361 switch (SvTYPE(thing)) {
365 /* Just a plain integer. This will be differently sized depending
366 on whether purify's been compiled in */
368 #ifndef NEW_HEAD_LAYOUT
370 total_size += sizeof(sizeof(XPVIV));
372 total_size += sizeof(IV);
376 /* Is it a float? Like the int, it depends on purify */
379 total_size += sizeof(sizeof(XPVNV));
381 total_size += sizeof(NV);
384 /* Is it a reference? */
386 #ifndef NEW_HEAD_LAYOUT
387 total_size += sizeof(XRV);
390 /* How about a plain string? In which case we need to add in how
391 much has been allocated */
393 total_size += sizeof(XPV);
394 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
396 /* A string with an integer part? */
398 total_size += sizeof(XPVIV);
399 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
401 total_size += SvIVX(thing);
404 /* A scalar/string/reference with a float part? */
406 total_size += sizeof(XPVNV);
407 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
410 total_size += sizeof(XPVMG);
411 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
412 total_size += magic_size(thing, tracking_hash);
414 #if PERL_VERSION <= 8
416 total_size += sizeof(XPVBM);
417 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
418 total_size += magic_size(thing, tracking_hash);
422 total_size += sizeof(XPVLV);
423 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
424 total_size += magic_size(thing, tracking_hash);
426 /* How much space is dedicated to the array? Not counting the
427 elements in the array, mind, just the array itself */
429 total_size += sizeof(XPVAV);
430 /* Is there anything in the array? */
431 if (AvMAX(thing) != -1) {
432 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
433 total_size += sizeof(SV *) * (AvMAX(thing) + 1);
434 /* printf ("total_size: %li AvMAX: %li av_len: %i\n", total_size, AvMAX(thing), av_len(thing)); */
436 /* Add in the bits on the other side of the beginning */
438 /* printf ("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
439 total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )); */
441 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
442 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
443 if (AvALLOC(thing) != 0) {
444 total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
446 /* Is there something hanging off the arylen element? */
447 if (AvARYLEN(thing)) {
448 if (check_new(tracking_hash, AvARYLEN(thing))) {
449 total_size += thing_size(AvARYLEN(thing), tracking_hash);
452 total_size += magic_size(thing, tracking_hash);
455 /* First the base struct */
456 total_size += sizeof(XPVHV);
457 /* Now the array of buckets */
458 total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
459 /* Now walk the bucket chain */
460 if (HvARRAY(thing)) {
463 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
464 cur_entry = *(HvARRAY(thing) + cur_bucket);
466 total_size += sizeof(HE);
467 if (cur_entry->hent_hek) {
468 /* Hash keys can be shared. Have we seen this before? */
469 if (check_new(tracking_hash, cur_entry->hent_hek)) {
470 total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
473 cur_entry = cur_entry->hent_next;
477 total_size += magic_size(thing, tracking_hash);
480 total_size += sizeof(XPVCV);
481 total_size += magic_size(thing, tracking_hash);
483 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
484 if (check_new(tracking_hash, CvSTASH(thing))) {
485 total_size += thing_size((SV *)CvSTASH(thing), tracking_hash);
487 if (check_new(tracking_hash, SvSTASH(thing))) {
488 total_size += thing_size((SV *)SvSTASH(thing), tracking_hash);
490 if (check_new(tracking_hash, CvGV(thing))) {
491 total_size += thing_size((SV *)CvGV(thing), tracking_hash);
493 if (check_new(tracking_hash, CvPADLIST(thing))) {
494 total_size += thing_size((SV *)CvPADLIST(thing), tracking_hash);
496 if (check_new(tracking_hash, CvOUTSIDE(thing))) {
497 total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
500 if (check_new(tracking_hash, CvSTART(thing))) {
501 total_size += op_size(CvSTART(thing), tracking_hash);
503 if (check_new(tracking_hash, CvROOT(thing))) {
504 total_size += op_size(CvROOT(thing), tracking_hash);
509 total_size += magic_size(thing, tracking_hash);
510 total_size += sizeof(XPVGV);
511 total_size += GvNAMELEN(thing);
513 /* Is there a file? */
515 if (check_new(tracking_hash, GvFILE(thing))) {
516 total_size += strlen(GvFILE(thing));
520 /* Is there something hanging off the glob? */
522 if (check_new(tracking_hash, GvGP(thing))) {
523 total_size += sizeof(GP);
526 if ((generic_thing = (SV *)(GvGP(thing)->gp_sv))) {
527 total_size += thing_size(generic_thing, tracking_hash);
529 if ((generic_thing = (SV *)(GvGP(thing)->gp_form))) {
530 total_size += thing_size(generic_thing, tracking_hash);
532 if ((generic_thing = (SV *)(GvGP(thing)->gp_av))) {
533 total_size += thing_size(generic_thing, tracking_hash);
535 if ((generic_thing = (SV *)(GvGP(thing)->gp_hv))) {
536 total_size += thing_size(generic_thing, tracking_hash);
538 if ((generic_thing = (SV *)(GvGP(thing)->gp_egv))) {
539 total_size += thing_size(generic_thing, tracking_hash);
541 if ((generic_thing = (SV *)(GvGP(thing)->gp_cv))) {
542 total_size += thing_size(generic_thing, tracking_hash);
549 total_size += sizeof(XPVFM);
550 total_size += magic_size(thing, tracking_hash);
551 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
552 if (check_new(tracking_hash, CvPADLIST(thing))) {
553 total_size += thing_size((SV *)CvPADLIST(thing), tracking_hash);
555 if (check_new(tracking_hash, CvOUTSIDE(thing))) {
556 total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
559 if (go_yell && !fm_whine) {
560 carp("Devel::Size: Calculated sizes for FMs are incomplete");
565 total_size += sizeof(XPVIO);
566 total_size += magic_size(thing, tracking_hash);
567 if (check_new(tracking_hash, (SvPVX(thing)))) {
568 total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
570 /* Some embedded char pointers */
571 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_top_name)) {
572 total_size += strlen(((XPVIO *) SvANY(thing))->xio_top_name);
574 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_fmt_name)) {
575 total_size += strlen(((XPVIO *) SvANY(thing))->xio_fmt_name);
577 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_bottom_name)) {
578 total_size += strlen(((XPVIO *) SvANY(thing))->xio_bottom_name);
580 /* Throw the GVs on the list to be walked if they're not-null */
581 if (((XPVIO *) SvANY(thing))->xio_top_gv) {
582 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_top_gv,
585 if (((XPVIO *) SvANY(thing))->xio_bottom_gv) {
586 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv,
589 if (((XPVIO *) SvANY(thing))->xio_fmt_gv) {
590 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv,
594 /* Only go trotting through the IO structures if they're really
595 trottable. If USE_PERLIO is defined we can do this. If
596 not... we can't, so we don't even try */
598 /* Dig into xio_ifp and xio_ofp here */
599 croak("Devel::Size: Can't size up perlio layers yet");
603 croak("Devel::Size: Unknown variable type");
608 MODULE = Devel::Size PACKAGE = Devel::Size
617 SV *thing = orig_thing;
618 /* Hash to track our seen pointers */
619 HV *tracking_hash = newHV();
622 /* Check warning status */
627 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
628 go_yell = SvIV(warn_flag);
632 /* If they passed us a reference then dereference it. This is the
633 only way we can check the sizes of arrays and hashes */
634 if (SvOK(thing) && SvROK(thing)) {
638 RETVAL = thing_size(thing, tracking_hash);
639 /* Clean up after ourselves */
640 SvREFCNT_dec(tracking_hash);
647 total_size(orig_thing)
651 SV *thing = orig_thing;
652 /* Hash to track our seen pointers */
653 HV *tracking_hash = newHV();
654 AV *pending_array = newAV();
658 /* Size starts at zero */
661 /* Check warning status */
666 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
667 go_yell = SvIV(warn_flag);
671 /* If they passed us a reference then dereference it. This is the
672 only way we can check the sizes of arrays and hashes */
673 if (SvOK(thing) && SvROK(thing)) {
677 /* Put it on the pending array */
678 av_push(pending_array, thing);
680 /* Now just yank things off the end of the array until it's done */
681 while (av_len(pending_array) >= 0) {
682 thing = av_pop(pending_array);
683 /* Process it if we've not seen it */
684 if (check_new(tracking_hash, thing)) {
687 /* printf ("Found type %i at %p\n", SvTYPE(thing), thing); */
689 /* Yes, it is. So let's check the type */
690 switch (SvTYPE(thing)) {
692 av_push(pending_array, SvRV(thing));
695 /* fix for bug #24846 (Does not correctly recurse into references in a PVNV-type scalar) */
699 av_push(pending_array, SvRV(thing));
705 /* Quick alias to cut down on casting */
706 AV *tempAV = (AV *)thing;
710 if (av_len(tempAV) != -1) {
712 /* Run through them all */
713 for (index = 0; index <= av_len(tempAV); index++) {
714 /* Did we get something? */
715 if ((tempSV = av_fetch(tempAV, index, 0))) {
717 if (*tempSV != &PL_sv_undef) {
718 /* Apparently not. Save it for later */
719 av_push(pending_array, *tempSV);
728 /* Is there anything in here? */
729 if (hv_iterinit((HV *)thing)) {
731 while ((temp_he = hv_iternext((HV *)thing))) {
732 av_push(pending_array, hv_iterval((HV *)thing, temp_he));
738 /* Run through all the pieces and push the ones with bits */
740 av_push(pending_array, (SV *)GvSV(thing));
743 av_push(pending_array, (SV *)GvFORM(thing));
746 av_push(pending_array, (SV *)GvAV(thing));
749 av_push(pending_array, (SV *)GvHV(thing));
752 av_push(pending_array, (SV *)GvCV(thing));
761 size = thing_size(thing, tracking_hash);
766 /* Clean up after ourselves */
767 SvREFCNT_dec(tracking_hash);
768 SvREFCNT_dec(pending_array);