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);
219 if (check_new(tracking_hash, baseop->op_next)) {
220 total_size += op_size(baseop->op_next, tracking_hash);
223 switch (cc_opclass(baseop)) {
225 total_size += sizeof(struct op);
228 total_size += sizeof(struct unop);
229 if (check_new(tracking_hash, cUNOPx(baseop)->op_first)) {
230 total_size += op_size(cUNOPx(baseop)->op_first, tracking_hash);
234 total_size += sizeof(struct binop);
235 if (check_new(tracking_hash, cBINOPx(baseop)->op_first)) {
236 total_size += op_size(cBINOPx(baseop)->op_first, tracking_hash);
238 if (check_new(tracking_hash, cBINOPx(baseop)->op_last)) {
239 total_size += op_size(cBINOPx(baseop)->op_last, tracking_hash);
243 total_size += sizeof(struct logop);
244 if (check_new(tracking_hash, cLOGOPx(baseop)->op_first)) {
245 total_size += op_size(cBINOPx(baseop)->op_first, tracking_hash);
247 if (check_new(tracking_hash, cLOGOPx(baseop)->op_other)) {
248 total_size += op_size(cLOGOPx(baseop)->op_other, tracking_hash);
252 total_size += sizeof(struct listop);
253 if (check_new(tracking_hash, cLISTOPx(baseop)->op_first)) {
254 total_size += op_size(cLISTOPx(baseop)->op_first, tracking_hash);
256 if (check_new(tracking_hash, cLISTOPx(baseop)->op_last)) {
257 total_size += op_size(cLISTOPx(baseop)->op_last, tracking_hash);
261 total_size += sizeof(struct pmop);
262 if (check_new(tracking_hash, cPMOPx(baseop)->op_first)) {
263 total_size += op_size(cPMOPx(baseop)->op_first, tracking_hash);
265 if (check_new(tracking_hash, cPMOPx(baseop)->op_last)) {
266 total_size += op_size(cPMOPx(baseop)->op_last, tracking_hash);
268 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmreplroot)) {
269 total_size += op_size(cPMOPx(baseop)->op_pmreplroot, tracking_hash);
271 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmreplstart)) {
272 total_size += op_size(cPMOPx(baseop)->op_pmreplstart, tracking_hash);
274 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmnext)) {
275 total_size += op_size((OP *)cPMOPx(baseop)->op_pmnext, tracking_hash);
277 /* This is defined away in perl 5.8.x, but it is in there for
280 if (check_new(tracking_hash, PM_GETRE((cPMOPx(baseop))))) {
281 total_size += regex_size(PM_GETRE(cPMOPx(baseop)), tracking_hash);
284 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmregexp)) {
285 total_size += regex_size(cPMOPx(baseop)->op_pmregexp, tracking_hash);
290 total_size += sizeof(struct pmop);
291 if (check_new(tracking_hash, cSVOPx(baseop)->op_sv)) {
292 total_size += thing_size(cSVOPx(baseop)->op_sv, tracking_hash);
296 total_size += sizeof(struct padop);
299 if (check_new(tracking_hash, cPVOPx(baseop)->op_pv)) {
300 total_size += strlen(cPVOPx(baseop)->op_pv);
303 total_size += sizeof(struct loop);
304 if (check_new(tracking_hash, cLOOPx(baseop)->op_first)) {
305 total_size += op_size(cLOOPx(baseop)->op_first, tracking_hash);
307 if (check_new(tracking_hash, cLOOPx(baseop)->op_last)) {
308 total_size += op_size(cLOOPx(baseop)->op_last, tracking_hash);
310 if (check_new(tracking_hash, cLOOPx(baseop)->op_redoop)) {
311 total_size += op_size(cLOOPx(baseop)->op_redoop, tracking_hash);
313 if (check_new(tracking_hash, cLOOPx(baseop)->op_nextop)) {
314 total_size += op_size(cLOOPx(baseop)->op_nextop, tracking_hash);
316 /* Not working for some reason, but the code's here for later
318 if (check_new(tracking_hash, cLOOPx(baseop)->op_lastop)) {
319 total_size += op_size(cLOOPx(baseop)->op_lastop, tracking_hash);
326 basecop = (COP *)baseop;
327 total_size += sizeof(struct cop);
329 if (check_new(tracking_hash, basecop->cop_label)) {
330 total_size += strlen(basecop->cop_label);
333 if (check_new(tracking_hash, basecop->cop_file)) {
334 total_size += strlen(basecop->cop_file);
336 if (check_new(tracking_hash, basecop->cop_stashpv)) {
337 total_size += strlen(basecop->cop_stashpv);
340 if (check_new(tracking_hash, basecop->cop_stash)) {
341 total_size += thing_size((SV *)basecop->cop_stash, tracking_hash);
343 if (check_new(tracking_hash, basecop->cop_filegv)) {
344 total_size += thing_size((SV *)basecop->cop_filegv, tracking_hash);
356 #if PERL_VERSION > 9 || (PERL_VERSION == 9 && PERL_SUBVERSION > 2)
357 # define NEW_HEAD_LAYOUT
360 UV thing_size(SV *orig_thing, HV *tracking_hash) {
361 SV *thing = orig_thing;
362 UV total_size = sizeof(SV);
364 switch (SvTYPE(thing)) {
368 /* Just a plain integer. This will be differently sized depending
369 on whether purify's been compiled in */
371 #ifndef NEW_HEAD_LAYOUT
373 total_size += sizeof(sizeof(XPVIV));
375 total_size += sizeof(IV);
379 /* Is it a float? Like the int, it depends on purify */
382 total_size += sizeof(sizeof(XPVNV));
384 total_size += sizeof(NV);
387 /* Is it a reference? */
389 #ifndef NEW_HEAD_LAYOUT
390 total_size += sizeof(XRV);
393 /* How about a plain string? In which case we need to add in how
394 much has been allocated */
396 total_size += sizeof(XPV);
397 total_size += SvLEN(thing);
399 /* A string with an integer part? */
401 total_size += sizeof(XPVIV);
402 total_size += SvLEN(thing);
403 total_size += SvIVX(thing);
405 /* A string with a float part? */
407 total_size += sizeof(XPVNV);
408 total_size += SvLEN(thing);
411 total_size += sizeof(XPVMG);
412 total_size += SvLEN(thing);
413 total_size += magic_size(thing, tracking_hash);
416 total_size += sizeof(XPVBM);
417 total_size += SvLEN(thing);
418 total_size += magic_size(thing, tracking_hash);
421 total_size += sizeof(XPVLV);
422 total_size += SvLEN(thing);
423 total_size += magic_size(thing, tracking_hash);
425 /* How much space is dedicated to the array? Not counting the
426 elements in the array, mind, just the array itself */
428 total_size += sizeof(XPVAV);
429 /* Is there anything in the array? */
430 if (AvMAX(thing) != -1) {
431 total_size += sizeof(SV *) * AvMAX(thing);
433 /* Add in the bits on the other side of the beginning */
434 total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
435 /* Is there something hanging off the arylen element? */
436 if (AvARYLEN(thing)) {
437 if (check_new(tracking_hash, AvARYLEN(thing))) {
438 total_size += thing_size(AvARYLEN(thing), tracking_hash);
441 total_size += magic_size(thing, tracking_hash);
444 /* First the base struct */
445 total_size += sizeof(XPVHV);
446 /* Now the array of buckets */
447 total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
448 /* Now walk the bucket chain */
449 if (HvARRAY(thing)) {
452 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
453 cur_entry = *(HvARRAY(thing) + cur_bucket);
455 total_size += sizeof(HE);
456 if (cur_entry->hent_hek) {
457 /* Hash keys can be shared. Have we seen this before? */
458 if (check_new(tracking_hash, cur_entry->hent_hek)) {
459 total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
462 cur_entry = cur_entry->hent_next;
466 total_size += magic_size(thing, tracking_hash);
469 total_size += sizeof(XPVCV);
470 total_size += magic_size(thing, tracking_hash);
472 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
473 if (check_new(tracking_hash, CvSTASH(thing))) {
474 total_size += thing_size((SV *)CvSTASH(thing), tracking_hash);
476 if (check_new(tracking_hash, SvSTASH(thing))) {
477 total_size += thing_size((SV *)SvSTASH(thing), tracking_hash);
479 if (check_new(tracking_hash, CvGV(thing))) {
480 total_size += thing_size((SV *)CvGV(thing), tracking_hash);
482 if (check_new(tracking_hash, CvPADLIST(thing))) {
483 total_size += thing_size((SV *)CvPADLIST(thing), tracking_hash);
485 if (check_new(tracking_hash, CvOUTSIDE(thing))) {
486 total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
489 if (check_new(tracking_hash, CvSTART(thing))) {
490 total_size += op_size(CvSTART(thing), tracking_hash);
492 if (check_new(tracking_hash, CvROOT(thing))) {
493 total_size += op_size(CvROOT(thing), tracking_hash);
498 total_size += magic_size(thing, tracking_hash);
499 total_size += sizeof(XPVGV);
500 total_size += GvNAMELEN(thing);
502 /* Is there a file? */
504 if (check_new(tracking_hash, GvFILE(thing))) {
505 total_size += strlen(GvFILE(thing));
509 /* Is there something hanging off the glob? */
511 if (check_new(tracking_hash, GvGP(thing))) {
512 total_size += sizeof(GP);
515 if (generic_thing = (SV *)(GvGP(thing)->gp_sv)) {
516 total_size += thing_size(generic_thing, tracking_hash);
518 if (generic_thing = (SV *)(GvGP(thing)->gp_form)) {
519 total_size += thing_size(generic_thing, tracking_hash);
521 if (generic_thing = (SV *)(GvGP(thing)->gp_av)) {
522 total_size += thing_size(generic_thing, tracking_hash);
524 if (generic_thing = (SV *)(GvGP(thing)->gp_hv)) {
525 total_size += thing_size(generic_thing, tracking_hash);
527 if (generic_thing = (SV *)(GvGP(thing)->gp_egv)) {
528 total_size += thing_size(generic_thing, tracking_hash);
530 if (generic_thing = (SV *)(GvGP(thing)->gp_cv)) {
531 total_size += thing_size(generic_thing, tracking_hash);
538 total_size += sizeof(XPVFM);
539 total_size += magic_size(thing, tracking_hash);
540 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
541 if (check_new(tracking_hash, CvPADLIST(thing))) {
542 total_size += thing_size((SV *)CvPADLIST(thing), tracking_hash);
544 if (check_new(tracking_hash, CvOUTSIDE(thing))) {
545 total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
548 if (go_yell && !fm_whine) {
549 carp("Devel::Size: Calculated sizes for FMs are incomplete");
554 total_size += sizeof(XPVIO);
555 total_size += magic_size(thing, tracking_hash);
556 if (check_new(tracking_hash, (SvPVX(thing)))) {
557 total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
559 /* Some embedded char pointers */
560 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_top_name)) {
561 total_size += strlen(((XPVIO *) SvANY(thing))->xio_top_name);
563 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_fmt_name)) {
564 total_size += strlen(((XPVIO *) SvANY(thing))->xio_fmt_name);
566 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_bottom_name)) {
567 total_size += strlen(((XPVIO *) SvANY(thing))->xio_bottom_name);
569 /* Throw the GVs on the list to be walked if they're not-null */
570 if (((XPVIO *) SvANY(thing))->xio_top_gv) {
571 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_top_gv,
574 if (((XPVIO *) SvANY(thing))->xio_bottom_gv) {
575 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv,
578 if (((XPVIO *) SvANY(thing))->xio_fmt_gv) {
579 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv,
583 /* Only go trotting through the IO structures if they're really
584 trottable. If USE_PERLIO is defined we can do this. If
585 not... we can't, so we don't even try */
587 /* Dig into xio_ifp and xio_ofp here */
588 croak("Devel::Size: Can't size up perlio layers yet");
592 croak("Devel::Size: Unknown variable type");
597 MODULE = Devel::Size PACKAGE = Devel::Size
606 SV *thing = orig_thing;
607 /* Hash to track our seen pointers */
608 HV *tracking_hash = newHV();
611 /* Check warning status */
616 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
617 go_yell = SvIV(warn_flag);
621 /* If they passed us a reference then dereference it. This is the
622 only way we can check the sizes of arrays and hashes */
623 if (SvOK(thing) && SvROK(thing)) {
627 RETVAL = thing_size(thing, tracking_hash);
628 /* Clean up after ourselves */
629 SvREFCNT_dec(tracking_hash);
636 total_size(orig_thing)
640 SV *thing = orig_thing;
641 /* Hash to track our seen pointers */
642 HV *tracking_hash = newHV();
643 AV *pending_array = newAV();
649 /* Size starts at zero */
652 /* Check warning status */
657 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
658 go_yell = SvIV(warn_flag);
662 /* If they passed us a reference then dereference it. This is the
663 only way we can check the sizes of arrays and hashes */
664 if (SvOK(thing) && SvROK(thing)) {
668 /* Put it on the pending array */
669 av_push(pending_array, thing);
671 /* Now just yank things off the end of the array until it's done */
672 while (av_len(pending_array) >= 0) {
673 thing = av_pop(pending_array);
674 /* Process it if we've not seen it */
675 if (check_new(tracking_hash, thing)) {
678 /* Yes, it is. So let's check the type */
679 switch (SvTYPE(thing)) {
681 av_push(pending_array, SvRV(thing));
686 /* Quick alias to cut down on casting */
687 AV *tempAV = (AV *)thing;
691 if (av_len(tempAV) != -1) {
693 /* Run through them all */
694 for (index = 0; index <= av_len(tempAV); index++) {
695 /* Did we get something? */
696 if (tempSV = av_fetch(tempAV, index, 0)) {
698 if (*tempSV != &PL_sv_undef) {
699 /* Apparently not. Save it for later */
700 av_push(pending_array, *tempSV);
709 /* Is there anything in here? */
710 if (hv_iterinit((HV *)thing)) {
712 while (temp_he = hv_iternext((HV *)thing)) {
713 av_push(pending_array, hv_iterval((HV *)thing, temp_he));
719 /* Run through all the pieces and push the ones with bits */
721 av_push(pending_array, (SV *)GvSV(thing));
724 av_push(pending_array, (SV *)GvFORM(thing));
727 av_push(pending_array, (SV *)GvAV(thing));
730 av_push(pending_array, (SV *)GvHV(thing));
733 av_push(pending_array, (SV *)GvCV(thing));
742 size = thing_size(thing, tracking_hash);
747 /* Clean up after ourselves */
748 SvREFCNT_dec(tracking_hash);
749 SvREFCNT_dec(pending_array);