5 static int regex_whine;
10 UV thing_size(SV *, HV *);
34 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
36 if (o->op_type == OP_SASSIGN)
37 return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
40 if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
44 switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
71 * Character translations (tr///) are usually a PVOP, keeping a
72 * pointer to a table of shorts used to look up translations.
73 * Under utf8, however, a simple table isn't practical; instead,
74 * the OP is an SVOP, and the SV is a reference to a swash
75 * (i.e., an RV pointing to an HV).
77 return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
78 ? OPc_SVOP : OPc_PVOP;
86 case OA_BASEOP_OR_UNOP:
88 * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on
89 * whether parens were seen. perly.y uses OPf_SPECIAL to
90 * signal whether a BASEOP had empty parens or none.
91 * Some other UNOPs are created later, though, so the best
92 * test is OPf_KIDS, which is set in newUNOP.
94 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
98 * The file stat OPs are created via UNI(OP_foo) in toke.c but use
99 * the OPf_REF flag to distinguish between OP types instead of the
100 * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we
101 * return OPc_UNOP so that walkoptree can find our children. If
102 * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set
103 * (no argument to the operator) it's an OP; with OPf_REF set it's
104 * an SVOP (and op_sv is the GV for the filehandle argument).
106 return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
108 (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
110 (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
114 * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a
115 * label was omitted (in which case it's a BASEOP) or else a term was
116 * seen. In this last case, all except goto are definitely PVOP but
117 * goto is either a PVOP (with an ordinary constant label), an UNOP
118 * with OPf_STACKED (with a non-constant non-sub) or an UNOP for
119 * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to
122 if (o->op_flags & OPf_STACKED)
124 else if (o->op_flags & OPf_SPECIAL)
129 warn("can't determine class of operator %s, assuming BASEOP\n",
130 PL_op_name[o->op_type]);
139 static int go_yell = 1;
141 /* Checks to see if thing is in the hash. Returns true or false, and
142 notes thing in the hash.
144 This code does one Evil Thing. Since we're tracking pointers, we
145 tell perl that the string key is the address in the pointer. We do this by
146 passing in the address of the address, along with the size of a
147 pointer as the length. Perl then uses the four (or eight, on
148 64-bit machines) bytes of the address as the string we're using as
150 IV check_new(HV *tracking_hash, void *thing) {
154 if (hv_exists(tracking_hash, (char *)&thing, sizeof(void *))) {
157 hv_store(tracking_hash, (char *)&thing, sizeof(void *), &PL_sv_yes, 0);
162 /* Figure out how much magic is attached to the SV and return the
164 IV magic_size(SV *thing, HV *tracking_hash) {
166 MAGIC *magic_pointer;
169 if (!SvMAGIC(thing)) {
174 /* Get the base magic pointer */
175 magic_pointer = SvMAGIC(thing);
177 /* Have we seen the magic pointer? */
178 while (magic_pointer && check_new(tracking_hash, magic_pointer)) {
179 total_size += sizeof(MAGIC);
181 /* Have we seen the magic vtable? */
182 if (magic_pointer->mg_virtual &&
183 check_new(tracking_hash, magic_pointer->mg_virtual)) {
184 total_size += sizeof(MGVTBL);
187 /* Get the next in the chain */
188 magic_pointer = magic_pointer->mg_moremagic;
194 UV regex_size(REGEXP *baseregex, HV *tracking_hash) {
197 total_size += sizeof(REGEXP);
198 /* Note hte size of the paren offset thing */
199 total_size += sizeof(I32) * baseregex->nparens * 2;
200 total_size += strlen(baseregex->precomp);
202 if (go_yell && !regex_whine) {
203 carp("Devel::Size: Calculated sizes for compiled regexes are incomple, and probably always will be");
210 UV op_size(OP *baseop, HV *tracking_hash) {
213 if (check_new(tracking_hash, baseop->op_next)) {
214 total_size += op_size(baseop->op_next, 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);
322 basecop = (COP *)baseop;
323 total_size += sizeof(struct cop);
325 if (check_new(tracking_hash, basecop->cop_label)) {
326 total_size += strlen(basecop->cop_label);
329 if (check_new(tracking_hash, basecop->cop_file)) {
330 total_size += strlen(basecop->cop_file);
332 if (check_new(tracking_hash, basecop->cop_stashpv)) {
333 total_size += strlen(basecop->cop_stashpv);
336 if (check_new(tracking_hash, basecop->cop_stash)) {
337 total_size += thing_size((SV *)basecop->cop_stash, tracking_hash);
339 if (check_new(tracking_hash, basecop->cop_filegv)) {
340 total_size += thing_size((SV *)basecop->cop_filegv, tracking_hash);
352 UV thing_size(SV *orig_thing, HV *tracking_hash) {
353 SV *thing = orig_thing;
354 UV total_size = sizeof(SV);
356 switch (SvTYPE(thing)) {
360 /* Just a plain integer. This will be differently sized depending
361 on whether purify's been compiled in */
364 total_size += sizeof(sizeof(XPVIV));
366 total_size += sizeof(IV);
369 /* Is it a float? Like the int, it depends on purify */
372 total_size += sizeof(sizeof(XPVNV));
374 total_size += sizeof(NV);
377 /* Is it a reference? */
379 total_size += sizeof(XRV);
381 /* How about a plain string? In which case we need to add in how
382 much has been allocated */
384 total_size += sizeof(XPV);
385 total_size += SvLEN(thing);
387 /* A string with an integer part? */
389 total_size += sizeof(XPVIV);
390 total_size += SvLEN(thing);
392 /* A string with a float part? */
394 total_size += sizeof(XPVNV);
395 total_size += SvLEN(thing);
398 total_size += sizeof(XPVMG);
399 total_size += SvLEN(thing);
400 total_size += magic_size(thing, tracking_hash);
403 total_size += sizeof(XPVBM);
404 total_size += SvLEN(thing);
405 total_size += magic_size(thing, tracking_hash);
408 total_size += sizeof(XPVLV);
409 total_size += SvLEN(thing);
410 total_size += magic_size(thing, tracking_hash);
412 /* How much space is dedicated to the array? Not counting the
413 elements in the array, mind, just the array itself */
415 total_size += sizeof(XPVAV);
416 /* Is there anything in the array? */
417 if (AvMAX(thing) != -1) {
418 total_size += sizeof(SV *) * AvMAX(thing);
420 /* Add in the bits on the other side of the beginning */
421 total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
422 /* Is there something hanging off the arylen element? */
423 if (AvARYLEN(thing)) {
424 if (check_new(tracking_hash, AvARYLEN(thing))) {
425 total_size += thing_size(AvARYLEN(thing), tracking_hash);
428 total_size += magic_size(thing, tracking_hash);
431 /* First the base struct */
432 total_size += sizeof(XPVHV);
433 /* Now the array of buckets */
434 total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
435 /* Now walk the bucket chain */
436 if (HvARRAY(thing)) {
439 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
440 cur_entry = *(HvARRAY(thing) + cur_bucket);
442 total_size += sizeof(HE);
443 if (cur_entry->hent_hek) {
444 /* Hash keys can be shared. Have we seen this before? */
445 if (check_new(tracking_hash, cur_entry->hent_hek)) {
446 total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
449 cur_entry = cur_entry->hent_next;
453 total_size += magic_size(thing, tracking_hash);
456 total_size += sizeof(XPVCV);
457 total_size += magic_size(thing, tracking_hash);
459 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
460 if (check_new(tracking_hash, CvSTASH(thing))) {
461 total_size += thing_size((SV *)CvSTASH(thing), tracking_hash);
463 if (check_new(tracking_hash, SvSTASH(thing))) {
464 total_size += thing_size((SV *)SvSTASH(thing), tracking_hash);
466 if (check_new(tracking_hash, CvGV(thing))) {
467 total_size += thing_size((SV *)CvGV(thing), tracking_hash);
469 if (check_new(tracking_hash, CvPADLIST(thing))) {
470 total_size += thing_size((SV *)CvPADLIST(thing), tracking_hash);
472 if (check_new(tracking_hash, CvOUTSIDE(thing))) {
473 total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
476 if (check_new(tracking_hash, CvSTART(thing))) {
477 total_size += op_size(CvSTART(thing), tracking_hash);
479 if (check_new(tracking_hash, CvROOT(thing))) {
480 total_size += op_size(CvROOT(thing), tracking_hash);
485 total_size += magic_size(thing, tracking_hash);
486 total_size += sizeof(XPVGV);
487 total_size += GvNAMELEN(thing);
489 /* Is there a file? */
491 if (check_new(tracking_hash, GvFILE(thing))) {
492 total_size += strlen(GvFILE(thing));
496 /* Is there something hanging off the glob? */
498 if (check_new(tracking_hash, GvGP(thing))) {
499 total_size += sizeof(GP);
502 if (generic_thing = (SV *)(GvGP(thing)->gp_sv)) {
503 total_size += thing_size(generic_thing, tracking_hash);
505 if (generic_thing = (SV *)(GvGP(thing)->gp_form)) {
506 total_size += thing_size(generic_thing, tracking_hash);
508 if (generic_thing = (SV *)(GvGP(thing)->gp_av)) {
509 total_size += thing_size(generic_thing, tracking_hash);
511 if (generic_thing = (SV *)(GvGP(thing)->gp_hv)) {
512 total_size += thing_size(generic_thing, tracking_hash);
514 if (generic_thing = (SV *)(GvGP(thing)->gp_egv)) {
515 total_size += thing_size(generic_thing, tracking_hash);
517 if (generic_thing = (SV *)(GvGP(thing)->gp_cv)) {
518 total_size += thing_size(generic_thing, tracking_hash);
525 total_size += sizeof(XPVFM);
526 total_size += magic_size(thing, tracking_hash);
527 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
528 if (check_new(tracking_hash, CvPADLIST(thing))) {
529 total_size += thing_size((SV *)CvPADLIST(thing), tracking_hash);
531 if (check_new(tracking_hash, CvOUTSIDE(thing))) {
532 total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
535 if (go_yell && !fm_whine) {
536 carp("Devel::Size: Calculated sizes for FMs are incomplete");
541 total_size += sizeof(XPVIO);
542 total_size += magic_size(thing, tracking_hash);
543 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xpv_pv)) {
544 total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
546 /* Some embedded char pointers */
547 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_top_name)) {
548 total_size += strlen(((XPVIO *) SvANY(thing))->xio_top_name);
550 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_fmt_name)) {
551 total_size += strlen(((XPVIO *) SvANY(thing))->xio_fmt_name);
553 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_bottom_name)) {
554 total_size += strlen(((XPVIO *) SvANY(thing))->xio_bottom_name);
556 /* Throw the GVs on the list to be walked if they're not-null */
557 if (((XPVIO *) SvANY(thing))->xio_top_gv) {
558 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_top_gv,
561 if (((XPVIO *) SvANY(thing))->xio_bottom_gv) {
562 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv,
565 if (((XPVIO *) SvANY(thing))->xio_fmt_gv) {
566 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv,
570 /* Only go trotting through the IO structures if they're really
571 trottable. If USE_PERLIO is defined we can do this. If
572 not... we can't, so we don't even try */
574 /* Dig into xio_ifp and xio_ofp here */
575 croak("Devel::Size: Can't size up perlio layers yet");
579 croak("Devel::Size: Unknown variable type");
584 MODULE = Devel::Size PACKAGE = Devel::Size
593 SV *thing = orig_thing;
594 /* Hash to track our seen pointers */
595 HV *tracking_hash = newHV();
598 /* Check warning status */
603 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
604 go_yell = SvIV(warn_flag);
608 /* If they passed us a reference then dereference it. This is the
609 only way we can check the sizes of arrays and hashes */
610 if (SvOK(thing) && SvROK(thing)) {
614 RETVAL = thing_size(thing, tracking_hash);
615 /* Clean up after ourselves */
616 SvREFCNT_dec(tracking_hash);
623 total_size(orig_thing)
627 SV *thing = orig_thing;
628 /* Hash to track our seen pointers */
629 HV *tracking_hash = newHV();
630 AV *pending_array = newAV();
636 /* Size starts at zero */
639 /* Check warning status */
644 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
645 go_yell = SvIV(warn_flag);
649 /* If they passed us a reference then dereference it. This is the
650 only way we can check the sizes of arrays and hashes */
651 if (SvOK(thing) && SvROK(thing)) {
655 /* Put it on the pending array */
656 av_push(pending_array, thing);
658 /* Now just yank things off the end of the array until it's done */
659 while (av_len(pending_array) >= 0) {
660 thing = av_pop(pending_array);
661 /* Process it if we've not seen it */
662 if (check_new(tracking_hash, thing)) {
665 /* Yes, it is. So let's check the type */
666 switch (SvTYPE(thing)) {
668 av_push(pending_array, SvRV(thing));
673 /* Quick alias to cut down on casting */
674 AV *tempAV = (AV *)thing;
678 if (av_len(tempAV) != -1) {
680 /* Run through them all */
681 for (index = 0; index <= av_len(tempAV); index++) {
682 /* Did we get something? */
683 if (tempSV = av_fetch(tempAV, index, 0)) {
685 if (*tempSV != &PL_sv_undef) {
686 /* Apparently not. Save it for later */
687 av_push(pending_array, *tempSV);
696 /* Is there anything in here? */
697 if (hv_iterinit((HV *)thing)) {
699 while (temp_he = hv_iternext((HV *)thing)) {
700 av_push(pending_array, hv_iterval((HV *)thing, temp_he));
706 /* Run through all the pieces and push the ones with bits */
708 av_push(pending_array, (SV *)GvSV(thing));
711 av_push(pending_array, (SV *)GvFORM(thing));
714 av_push(pending_array, (SV *)GvAV(thing));
717 av_push(pending_array, (SV *)GvHV(thing));
720 av_push(pending_array, (SV *)GvCV(thing));
729 size = thing_size(thing, tracking_hash);
734 /* Clean up after ourselves */
735 SvREFCNT_dec(tracking_hash);
736 SvREFCNT_dec(pending_array);