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 #if (PERL_VERSION < 11)
202 /* Note the size of the paren offset thing */
203 total_size += sizeof(I32) * baseregex->nparens * 2;
204 total_size += strlen(baseregex->precomp);
206 total_size += sizeof(struct regexp);
207 total_size += sizeof(I32) * SvANY(baseregex)->nparens * 2;
208 /*total_size += strlen(SvANY(baseregex)->subbeg);*/
210 if (go_yell && !regex_whine) {
211 carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
218 UV op_size(OP *baseop, HV *tracking_hash) {
221 if (check_new(tracking_hash, baseop->op_next)) {
222 total_size += op_size(baseop->op_next, tracking_hash);
225 switch (cc_opclass(baseop)) {
227 total_size += sizeof(struct op);
230 total_size += sizeof(struct unop);
231 if (check_new(tracking_hash, cUNOPx(baseop)->op_first)) {
232 total_size += op_size(cUNOPx(baseop)->op_first, tracking_hash);
236 total_size += sizeof(struct binop);
237 if (check_new(tracking_hash, cBINOPx(baseop)->op_first)) {
238 total_size += op_size(cBINOPx(baseop)->op_first, tracking_hash);
240 if (check_new(tracking_hash, cBINOPx(baseop)->op_last)) {
241 total_size += op_size(cBINOPx(baseop)->op_last, tracking_hash);
245 total_size += sizeof(struct logop);
246 if (check_new(tracking_hash, cLOGOPx(baseop)->op_first)) {
247 total_size += op_size(cBINOPx(baseop)->op_first, tracking_hash);
249 if (check_new(tracking_hash, cLOGOPx(baseop)->op_other)) {
250 total_size += op_size(cLOGOPx(baseop)->op_other, tracking_hash);
254 total_size += sizeof(struct listop);
255 if (check_new(tracking_hash, cLISTOPx(baseop)->op_first)) {
256 total_size += op_size(cLISTOPx(baseop)->op_first, tracking_hash);
258 if (check_new(tracking_hash, cLISTOPx(baseop)->op_last)) {
259 total_size += op_size(cLISTOPx(baseop)->op_last, tracking_hash);
263 total_size += sizeof(struct pmop);
264 if (check_new(tracking_hash, cPMOPx(baseop)->op_first)) {
265 total_size += op_size(cPMOPx(baseop)->op_first, tracking_hash);
267 if (check_new(tracking_hash, cPMOPx(baseop)->op_last)) {
268 total_size += op_size(cPMOPx(baseop)->op_last, tracking_hash);
270 #if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
271 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmreplroot)) {
272 total_size += op_size(cPMOPx(baseop)->op_pmreplroot, tracking_hash);
274 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmreplstart)) {
275 total_size += op_size(cPMOPx(baseop)->op_pmreplstart, tracking_hash);
277 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmnext)) {
278 total_size += op_size((OP *)cPMOPx(baseop)->op_pmnext, tracking_hash);
281 /* This is defined away in perl 5.8.x, but it is in there for
284 if (check_new(tracking_hash, PM_GETRE((cPMOPx(baseop))))) {
285 total_size += regex_size(PM_GETRE(cPMOPx(baseop)), tracking_hash);
288 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmregexp)) {
289 total_size += regex_size(cPMOPx(baseop)->op_pmregexp, tracking_hash);
294 total_size += sizeof(struct pmop);
295 if (check_new(tracking_hash, cSVOPx(baseop)->op_sv)) {
296 total_size += thing_size(cSVOPx(baseop)->op_sv, tracking_hash);
300 total_size += sizeof(struct padop);
303 if (check_new(tracking_hash, cPVOPx(baseop)->op_pv)) {
304 total_size += strlen(cPVOPx(baseop)->op_pv);
307 total_size += sizeof(struct loop);
308 if (check_new(tracking_hash, cLOOPx(baseop)->op_first)) {
309 total_size += op_size(cLOOPx(baseop)->op_first, tracking_hash);
311 if (check_new(tracking_hash, cLOOPx(baseop)->op_last)) {
312 total_size += op_size(cLOOPx(baseop)->op_last, tracking_hash);
314 if (check_new(tracking_hash, cLOOPx(baseop)->op_redoop)) {
315 total_size += op_size(cLOOPx(baseop)->op_redoop, tracking_hash);
317 if (check_new(tracking_hash, cLOOPx(baseop)->op_nextop)) {
318 total_size += op_size(cLOOPx(baseop)->op_nextop, tracking_hash);
320 /* Not working for some reason, but the code's here for later
322 if (check_new(tracking_hash, cLOOPx(baseop)->op_lastop)) {
323 total_size += op_size(cLOOPx(baseop)->op_lastop, tracking_hash);
330 basecop = (COP *)baseop;
331 total_size += sizeof(struct cop);
333 if (check_new(tracking_hash, basecop->cop_label)) {
334 total_size += strlen(basecop->cop_label);
337 if (check_new(tracking_hash, basecop->cop_file)) {
338 total_size += strlen(basecop->cop_file);
340 if (check_new(tracking_hash, basecop->cop_stashpv)) {
341 total_size += strlen(basecop->cop_stashpv);
344 if (check_new(tracking_hash, basecop->cop_stash)) {
345 total_size += thing_size((SV *)basecop->cop_stash, tracking_hash);
347 if (check_new(tracking_hash, basecop->cop_filegv)) {
348 total_size += thing_size((SV *)basecop->cop_filegv, tracking_hash);
360 #if PERL_VERSION > 9 || (PERL_VERSION == 9 && PERL_SUBVERSION > 2)
361 # define NEW_HEAD_LAYOUT
364 UV thing_size(SV *orig_thing, HV *tracking_hash) {
365 SV *thing = orig_thing;
366 UV total_size = sizeof(SV);
368 switch (SvTYPE(thing)) {
372 /* Just a plain integer. This will be differently sized depending
373 on whether purify's been compiled in */
375 #ifndef NEW_HEAD_LAYOUT
377 total_size += sizeof(sizeof(XPVIV));
379 total_size += sizeof(IV);
383 /* Is it a float? Like the int, it depends on purify */
386 total_size += sizeof(sizeof(XPVNV));
388 total_size += sizeof(NV);
391 #if (PERL_VERSION < 11)
392 /* Is it a reference? */
394 #ifndef NEW_HEAD_LAYOUT
395 total_size += sizeof(XRV);
399 /* How about a plain string? In which case we need to add in how
400 much has been allocated */
402 total_size += sizeof(XPV);
403 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
405 /* A string with an integer part? */
407 total_size += sizeof(XPVIV);
408 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
410 total_size += SvIVX(thing);
413 /* A scalar/string/reference with a float part? */
415 total_size += sizeof(XPVNV);
416 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
419 total_size += sizeof(XPVMG);
420 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
421 total_size += magic_size(thing, tracking_hash);
423 #if PERL_VERSION <= 8
425 total_size += sizeof(XPVBM);
426 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
427 total_size += magic_size(thing, tracking_hash);
431 total_size += sizeof(XPVLV);
432 total_size += SvROK(thing) ? thing_size( SvRV(thing), tracking_hash) : SvLEN(thing);
433 total_size += magic_size(thing, tracking_hash);
435 /* How much space is dedicated to the array? Not counting the
436 elements in the array, mind, just the array itself */
438 total_size += sizeof(XPVAV);
439 /* Is there anything in the array? */
440 if (AvMAX(thing) != -1) {
441 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
442 total_size += sizeof(SV *) * (AvMAX(thing) + 1);
443 /* printf ("total_size: %li AvMAX: %li av_len: %i\n", total_size, AvMAX(thing), av_len(thing)); */
445 /* Add in the bits on the other side of the beginning */
447 /* printf ("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
448 total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )); */
450 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
451 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
452 if (AvALLOC(thing) != 0) {
453 total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
455 /* Is there something hanging off the arylen element? */
456 if (AvARYLEN(thing)) {
457 if (check_new(tracking_hash, AvARYLEN(thing))) {
458 total_size += thing_size(AvARYLEN(thing), tracking_hash);
461 total_size += magic_size(thing, tracking_hash);
464 /* First the base struct */
465 total_size += sizeof(XPVHV);
466 /* Now the array of buckets */
467 total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
468 /* Now walk the bucket chain */
469 if (HvARRAY(thing)) {
472 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
473 cur_entry = *(HvARRAY(thing) + cur_bucket);
475 total_size += sizeof(HE);
476 if (cur_entry->hent_hek) {
477 /* Hash keys can be shared. Have we seen this before? */
478 if (check_new(tracking_hash, cur_entry->hent_hek)) {
479 total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
482 cur_entry = cur_entry->hent_next;
486 total_size += magic_size(thing, tracking_hash);
489 total_size += sizeof(XPVCV);
490 total_size += magic_size(thing, tracking_hash);
492 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
493 if (check_new(tracking_hash, CvSTASH(thing))) {
494 total_size += thing_size((SV *)CvSTASH(thing), tracking_hash);
496 if (check_new(tracking_hash, SvSTASH(thing))) {
497 total_size += thing_size((SV *)SvSTASH(thing), tracking_hash);
499 if (check_new(tracking_hash, CvGV(thing))) {
500 total_size += thing_size((SV *)CvGV(thing), tracking_hash);
502 if (check_new(tracking_hash, CvPADLIST(thing))) {
503 total_size += thing_size((SV *)CvPADLIST(thing), tracking_hash);
505 if (check_new(tracking_hash, CvOUTSIDE(thing))) {
506 total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
509 if (check_new(tracking_hash, CvSTART(thing))) {
510 total_size += op_size(CvSTART(thing), tracking_hash);
512 if (check_new(tracking_hash, CvROOT(thing))) {
513 total_size += op_size(CvROOT(thing), tracking_hash);
518 total_size += magic_size(thing, tracking_hash);
519 total_size += sizeof(XPVGV);
520 total_size += GvNAMELEN(thing);
522 /* Is there a file? */
524 if (check_new(tracking_hash, GvFILE(thing))) {
525 total_size += strlen(GvFILE(thing));
529 /* Is there something hanging off the glob? */
531 if (check_new(tracking_hash, GvGP(thing))) {
532 total_size += sizeof(GP);
535 if ((generic_thing = (SV *)(GvGP(thing)->gp_sv))) {
536 total_size += thing_size(generic_thing, tracking_hash);
538 if ((generic_thing = (SV *)(GvGP(thing)->gp_form))) {
539 total_size += thing_size(generic_thing, tracking_hash);
541 if ((generic_thing = (SV *)(GvGP(thing)->gp_av))) {
542 total_size += thing_size(generic_thing, tracking_hash);
544 if ((generic_thing = (SV *)(GvGP(thing)->gp_hv))) {
545 total_size += thing_size(generic_thing, tracking_hash);
547 if ((generic_thing = (SV *)(GvGP(thing)->gp_egv))) {
548 total_size += thing_size(generic_thing, tracking_hash);
550 if ((generic_thing = (SV *)(GvGP(thing)->gp_cv))) {
551 total_size += thing_size(generic_thing, tracking_hash);
558 total_size += sizeof(XPVFM);
559 total_size += magic_size(thing, tracking_hash);
560 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
561 if (check_new(tracking_hash, CvPADLIST(thing))) {
562 total_size += thing_size((SV *)CvPADLIST(thing), tracking_hash);
564 if (check_new(tracking_hash, CvOUTSIDE(thing))) {
565 total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
568 if (go_yell && !fm_whine) {
569 carp("Devel::Size: Calculated sizes for FMs are incomplete");
574 total_size += sizeof(XPVIO);
575 total_size += magic_size(thing, tracking_hash);
576 if (check_new(tracking_hash, (SvPVX(thing)))) {
577 total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
579 /* Some embedded char pointers */
580 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_top_name)) {
581 total_size += strlen(((XPVIO *) SvANY(thing))->xio_top_name);
583 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_fmt_name)) {
584 total_size += strlen(((XPVIO *) SvANY(thing))->xio_fmt_name);
586 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_bottom_name)) {
587 total_size += strlen(((XPVIO *) SvANY(thing))->xio_bottom_name);
589 /* Throw the GVs on the list to be walked if they're not-null */
590 if (((XPVIO *) SvANY(thing))->xio_top_gv) {
591 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_top_gv,
594 if (((XPVIO *) SvANY(thing))->xio_bottom_gv) {
595 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv,
598 if (((XPVIO *) SvANY(thing))->xio_fmt_gv) {
599 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv,
603 /* Only go trotting through the IO structures if they're really
604 trottable. If USE_PERLIO is defined we can do this. If
605 not... we can't, so we don't even try */
607 /* Dig into xio_ifp and xio_ofp here */
608 croak("Devel::Size: Can't size up perlio layers yet");
612 croak("Devel::Size: Unknown variable type");
617 MODULE = Devel::Size PACKAGE = Devel::Size
626 SV *thing = orig_thing;
627 /* Hash to track our seen pointers */
628 HV *tracking_hash = newHV();
631 /* Check warning status */
636 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
637 go_yell = SvIV(warn_flag);
641 /* If they passed us a reference then dereference it. This is the
642 only way we can check the sizes of arrays and hashes */
643 if (SvOK(thing) && SvROK(thing)) {
647 RETVAL = thing_size(thing, tracking_hash);
648 /* Clean up after ourselves */
649 SvREFCNT_dec(tracking_hash);
656 total_size(orig_thing)
660 SV *thing = orig_thing;
661 /* Hash to track our seen pointers */
662 HV *tracking_hash = newHV();
663 AV *pending_array = newAV();
667 /* Size starts at zero */
670 /* Check warning status */
675 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
676 go_yell = SvIV(warn_flag);
680 /* If they passed us a reference then dereference it. This is the
681 only way we can check the sizes of arrays and hashes */
682 if (SvOK(thing) && SvROK(thing)) {
686 /* Put it on the pending array */
687 av_push(pending_array, thing);
689 /* Now just yank things off the end of the array until it's done */
690 while (av_len(pending_array) >= 0) {
691 thing = av_pop(pending_array);
692 /* Process it if we've not seen it */
693 if (check_new(tracking_hash, thing)) {
696 /* printf ("Found type %i at %p\n", SvTYPE(thing), thing); */
698 /* Yes, it is. So let's check the type */
699 switch (SvTYPE(thing)) {
701 av_push(pending_array, SvRV(thing));
704 /* fix for bug #24846 (Does not correctly recurse into references in a PVNV-type scalar) */
708 av_push(pending_array, SvRV(thing));
714 /* Quick alias to cut down on casting */
715 AV *tempAV = (AV *)thing;
719 if (av_len(tempAV) != -1) {
721 /* Run through them all */
722 for (index = 0; index <= av_len(tempAV); index++) {
723 /* Did we get something? */
724 if ((tempSV = av_fetch(tempAV, index, 0))) {
726 if (*tempSV != &PL_sv_undef) {
727 /* Apparently not. Save it for later */
728 av_push(pending_array, *tempSV);
737 /* Is there anything in here? */
738 if (hv_iterinit((HV *)thing)) {
740 while ((temp_he = hv_iternext((HV *)thing))) {
741 av_push(pending_array, hv_iterval((HV *)thing, temp_he));
747 /* Run through all the pieces and push the ones with bits */
749 av_push(pending_array, (SV *)GvSV(thing));
752 av_push(pending_array, (SV *)GvFORM(thing));
755 av_push(pending_array, (SV *)GvAV(thing));
758 av_push(pending_array, (SV *)GvHV(thing));
761 av_push(pending_array, (SV *)GvCV(thing));
770 size = thing_size(thing, tracking_hash);
775 /* Clean up after ourselves */
776 SvREFCNT_dec(tracking_hash);
777 SvREFCNT_dec(pending_array);