6 UV thing_size(SV *, HV *);
30 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
32 if (o->op_type == OP_SASSIGN)
33 return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
36 if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
40 switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
67 * Character translations (tr///) are usually a PVOP, keeping a
68 * pointer to a table of shorts used to look up translations.
69 * Under utf8, however, a simple table isn't practical; instead,
70 * the OP is an SVOP, and the SV is a reference to a swash
71 * (i.e., an RV pointing to an HV).
73 return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
74 ? OPc_SVOP : OPc_PVOP;
82 case OA_BASEOP_OR_UNOP:
84 * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on
85 * whether parens were seen. perly.y uses OPf_SPECIAL to
86 * signal whether a BASEOP had empty parens or none.
87 * Some other UNOPs are created later, though, so the best
88 * test is OPf_KIDS, which is set in newUNOP.
90 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
94 * The file stat OPs are created via UNI(OP_foo) in toke.c but use
95 * the OPf_REF flag to distinguish between OP types instead of the
96 * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we
97 * return OPc_UNOP so that walkoptree can find our children. If
98 * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set
99 * (no argument to the operator) it's an OP; with OPf_REF set it's
100 * an SVOP (and op_sv is the GV for the filehandle argument).
102 return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
104 (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
106 (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
110 * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a
111 * label was omitted (in which case it's a BASEOP) or else a term was
112 * seen. In this last case, all except goto are definitely PVOP but
113 * goto is either a PVOP (with an ordinary constant label), an UNOP
114 * with OPf_STACKED (with a non-constant non-sub) or an UNOP for
115 * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to
118 if (o->op_flags & OPf_STACKED)
120 else if (o->op_flags & OPf_SPECIAL)
125 warn("can't determine class of operator %s, assuming BASEOP\n",
126 PL_op_name[o->op_type]);
135 static int go_yell = 1;
137 /* Checks to see if thing is in the hash. Returns true or false, and
138 notes thing in the hash.
140 This code does one Evil Thing. Since we're tracking pointers, we
141 tell perl that the string key is the address in the pointer. We do this by
142 passing in the address of the address, along with the size of a
143 pointer as the length. Perl then uses the four (or eight, on
144 64-bit machines) bytes of the address as the string we're using as
146 IV check_new(HV *tracking_hash, void *thing) {
150 if (hv_exists(tracking_hash, (char *)&thing, sizeof(void *))) {
153 hv_store(tracking_hash, (char *)&thing, sizeof(void *), &PL_sv_yes, 0);
158 /* Figure out how much magic is attached to the SV and return the
160 IV magic_size(SV *thing, HV *tracking_hash) {
162 MAGIC *magic_pointer;
165 if (!SvMAGIC(thing)) {
170 /* Get the base magic pointer */
171 magic_pointer = SvMAGIC(thing);
173 /* Have we seen the magic pointer? */
174 while (magic_pointer && check_new(tracking_hash, magic_pointer)) {
175 total_size += sizeof(MAGIC);
177 /* Have we seen the magic vtable? */
178 if (magic_pointer->mg_virtual &&
179 check_new(tracking_hash, magic_pointer->mg_virtual)) {
180 total_size += sizeof(MGVTBL);
183 /* Get the next in the chain */
184 magic_pointer = magic_pointer->mg_moremagic;
190 UV regex_size(REGEXP *baseregex, HV *tracking_hash) {
196 UV op_size(OP *baseop, HV *tracking_hash) {
199 if (check_new(tracking_hash, baseop->op_next)) {
200 total_size += op_size(baseop->op_next, tracking_hash);
202 if (check_new(tracking_hash, baseop->op_next)) {
203 total_size += op_size(baseop->op_next, tracking_hash);
206 switch (cc_opclass(baseop)) {
208 total_size += sizeof(struct op);
211 total_size += sizeof(struct unop);
212 if (check_new(tracking_hash, cUNOPx(baseop)->op_first)) {
213 total_size += op_size(cUNOPx(baseop)->op_first, tracking_hash);
217 total_size += sizeof(struct binop);
218 if (check_new(tracking_hash, cBINOPx(baseop)->op_first)) {
219 total_size += op_size(cBINOPx(baseop)->op_first, tracking_hash);
221 if (check_new(tracking_hash, cBINOPx(baseop)->op_last)) {
222 total_size += op_size(cBINOPx(baseop)->op_last, tracking_hash);
226 total_size += sizeof(struct logop);
227 if (check_new(tracking_hash, cLOGOPx(baseop)->op_first)) {
228 total_size += op_size(cBINOPx(baseop)->op_first, tracking_hash);
230 if (check_new(tracking_hash, cLOGOPx(baseop)->op_other)) {
231 total_size += op_size(cLOGOPx(baseop)->op_other, tracking_hash);
235 total_size += sizeof(struct listop);
236 if (check_new(tracking_hash, cLISTOPx(baseop)->op_first)) {
237 total_size += op_size(cLISTOPx(baseop)->op_first, tracking_hash);
239 if (check_new(tracking_hash, cLISTOPx(baseop)->op_last)) {
240 total_size += op_size(cLISTOPx(baseop)->op_last, tracking_hash);
244 total_size += sizeof(struct pmop);
245 if (check_new(tracking_hash, cPMOPx(baseop)->op_first)) {
246 total_size += op_size(cPMOPx(baseop)->op_first, tracking_hash);
248 if (check_new(tracking_hash, cPMOPx(baseop)->op_last)) {
249 total_size += op_size(cPMOPx(baseop)->op_last, tracking_hash);
251 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmreplroot)) {
252 total_size += op_size(cPMOPx(baseop)->op_pmreplroot, tracking_hash);
254 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmreplstart)) {
255 total_size += op_size(cPMOPx(baseop)->op_pmreplstart, tracking_hash);
257 if (check_new(tracking_hash, cPMOPx(baseop)->op_pmnext)) {
258 total_size += op_size((OP *)cPMOPx(baseop)->op_pmnext, tracking_hash);
260 // if (check_new(tracking_hash, cPMOPx(baseop)->op_pmregexp)) {
261 // total_size += regex_size(cPMOPx(baseop)->op_pmregexp, tracking_hash);
265 total_size += sizeof(struct pmop);
266 if (check_new(tracking_hash, cSVOPx(baseop)->op_sv)) {
267 total_size += thing_size(cSVOPx(baseop)->op_sv, tracking_hash);
271 total_size += sizeof(struct padop);
274 if (check_new(tracking_hash, cPVOPx(baseop)->op_pv)) {
275 total_size += strlen(cPVOPx(baseop)->op_pv);
278 total_size += sizeof(struct loop);
279 if (check_new(tracking_hash, cLOOPx(baseop)->op_first)) {
280 total_size += op_size(cLOOPx(baseop)->op_first, tracking_hash);
282 if (check_new(tracking_hash, cLOOPx(baseop)->op_last)) {
283 total_size += op_size(cLOOPx(baseop)->op_last, tracking_hash);
285 if (check_new(tracking_hash, cLOOPx(baseop)->op_redoop)) {
286 total_size += op_size(cLOOPx(baseop)->op_redoop, tracking_hash);
288 if (check_new(tracking_hash, cLOOPx(baseop)->op_nextop)) {
289 total_size += op_size(cLOOPx(baseop)->op_nextop, tracking_hash);
291 // if (check_new(tracking_hash, cLOOPx(baseop)->op_lastop)) {
292 // total_size += op_size(cLOOPx(baseop)->op_lastop, tracking_hash);
297 basecop = (COP *)baseop;
298 total_size += sizeof(struct cop);
300 if (check_new(tracking_hash, basecop->cop_label)) {
301 total_size += strlen(basecop->cop_label);
304 if (check_new(tracking_hash, basecop->cop_file)) {
305 total_size += strlen(basecop->cop_file);
307 if (check_new(tracking_hash, basecop->cop_stashpv)) {
308 total_size += strlen(basecop->cop_stashpv);
311 if (check_new(tracking_hash, basecop->cop_stash)) {
312 total_size += thing_size((SV *)basecop->cop_stash, tracking_hash);
314 if (check_new(tracking_hash, basecop->cop_filegv)) {
315 total_size += thing_size((SV *)basecop->cop_filegv, tracking_hash);
327 UV thing_size(SV *orig_thing, HV *tracking_hash) {
328 SV *thing = orig_thing;
329 UV total_size = sizeof(SV);
331 switch (SvTYPE(thing)) {
335 /* Just a plain integer. This will be differently sized depending
336 on whether purify's been compiled in */
339 total_size += sizeof(sizeof(XPVIV));
341 total_size += sizeof(IV);
344 /* Is it a float? Like the int, it depends on purify */
347 total_size += sizeof(sizeof(XPVNV));
349 total_size += sizeof(NV);
352 /* Is it a reference? */
354 total_size += sizeof(XRV);
356 /* How about a plain string? In which case we need to add in how
357 much has been allocated */
359 total_size += sizeof(XPV);
360 total_size += SvLEN(thing);
362 /* A string with an integer part? */
364 total_size += sizeof(XPVIV);
365 total_size += SvLEN(thing);
367 /* A string with a float part? */
369 total_size += sizeof(XPVNV);
370 total_size += SvLEN(thing);
373 total_size += sizeof(XPVMG);
374 total_size += SvLEN(thing);
375 total_size += magic_size(thing, tracking_hash);
378 total_size += sizeof(XPVBM);
379 total_size += SvLEN(thing);
380 total_size += magic_size(thing, tracking_hash);
383 total_size += sizeof(XPVLV);
384 total_size += SvLEN(thing);
385 total_size += magic_size(thing, tracking_hash);
387 /* How much space is dedicated to the array? Not counting the
388 elements in the array, mind, just the array itself */
390 total_size += sizeof(XPVAV);
391 /* Is there anything in the array? */
392 if (AvMAX(thing) != -1) {
393 total_size += sizeof(SV *) * AvMAX(thing);
395 /* Add in the bits on the other side of the beginning */
396 total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
397 /* Is there something hanging off the arylen element? */
398 if (AvARYLEN(thing)) {
399 if (check_new(tracking_hash, AvARYLEN(thing))) {
400 total_size += thing_size(AvARYLEN(thing), tracking_hash);
403 total_size += magic_size(thing, tracking_hash);
406 /* First the base struct */
407 total_size += sizeof(XPVHV);
408 /* Now the array of buckets */
409 total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
410 /* Now walk the bucket chain */
411 if (HvARRAY(thing)) {
414 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
415 cur_entry = *(HvARRAY(thing) + cur_bucket);
417 total_size += sizeof(HE);
418 if (cur_entry->hent_hek) {
419 /* Hash keys can be shared. Have we seen this before? */
420 if (check_new(tracking_hash, cur_entry->hent_hek)) {
421 total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
424 cur_entry = cur_entry->hent_next;
428 total_size += magic_size(thing, tracking_hash);
431 total_size += sizeof(XPVCV);
432 total_size += magic_size(thing, tracking_hash);
434 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
435 if (check_new(tracking_hash, CvSTASH(thing))) {
436 total_size += thing_size((SV *)CvSTASH(thing), tracking_hash);
438 if (check_new(tracking_hash, SvSTASH(thing))) {
439 total_size += thing_size((SV *)SvSTASH(thing), tracking_hash);
441 if (check_new(tracking_hash, CvGV(thing))) {
442 total_size += thing_size((SV *)CvGV(thing), tracking_hash);
444 if (check_new(tracking_hash, CvPADLIST(thing))) {
445 total_size += thing_size((SV *)CvPADLIST(thing), tracking_hash);
447 if (check_new(tracking_hash, CvOUTSIDE(thing))) {
448 total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
451 if (check_new(tracking_hash, CvSTART(thing))) {
452 total_size += op_size(CvSTART(thing), tracking_hash);
454 if (check_new(tracking_hash, CvROOT(thing))) {
455 total_size += op_size(CvROOT(thing), tracking_hash);
460 total_size += magic_size(thing, tracking_hash);
461 total_size += sizeof(XPVGV);
462 total_size += GvNAMELEN(thing);
464 /* Is there a file? */
466 if (check_new(tracking_hash, GvFILE(thing))) {
467 total_size += strlen(GvFILE(thing));
471 /* Is there something hanging off the glob? */
473 if (check_new(tracking_hash, GvGP(thing))) {
474 total_size += sizeof(GP);
477 if (generic_thing = (SV *)(GvGP(thing)->gp_sv)) {
478 total_size += thing_size(generic_thing, tracking_hash);
480 if (generic_thing = (SV *)(GvGP(thing)->gp_form)) {
481 total_size += thing_size(generic_thing, tracking_hash);
483 if (generic_thing = (SV *)(GvGP(thing)->gp_av)) {
484 total_size += thing_size(generic_thing, tracking_hash);
486 if (generic_thing = (SV *)(GvGP(thing)->gp_hv)) {
487 total_size += thing_size(generic_thing, tracking_hash);
489 if (generic_thing = (SV *)(GvGP(thing)->gp_egv)) {
490 total_size += thing_size(generic_thing, tracking_hash);
492 if (generic_thing = (SV *)(GvGP(thing)->gp_cv)) {
493 total_size += thing_size(generic_thing, tracking_hash);
500 total_size += sizeof(XPVFM);
501 total_size += magic_size(thing, tracking_hash);
502 total_size += ((XPVIO *) SvANY(thing))->xpv_len;
503 if (check_new(tracking_hash, CvPADLIST(thing))) {
504 total_size += thing_size((SV *)CvPADLIST(thing), tracking_hash);
506 if (check_new(tracking_hash, CvOUTSIDE(thing))) {
507 total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
511 carp("Devel::Size: Calculated sizes for FMs are incomplete");
515 total_size += sizeof(XPVIO);
516 total_size += magic_size(thing, tracking_hash);
517 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xpv_pv)) {
518 total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
520 /* Some embedded char pointers */
521 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_top_name)) {
522 total_size += strlen(((XPVIO *) SvANY(thing))->xio_top_name);
524 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_fmt_name)) {
525 total_size += strlen(((XPVIO *) SvANY(thing))->xio_fmt_name);
527 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_bottom_name)) {
528 total_size += strlen(((XPVIO *) SvANY(thing))->xio_bottom_name);
530 /* Throw the GVs on the list to be walked if they're not-null */
531 if (((XPVIO *) SvANY(thing))->xio_top_gv) {
532 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_top_gv,
535 if (((XPVIO *) SvANY(thing))->xio_bottom_gv) {
536 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv,
539 if (((XPVIO *) SvANY(thing))->xio_fmt_gv) {
540 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv,
544 /* Only go trotting through the IO structures if they're really
545 trottable. If USE_PERLIO is defined we can do this. If
546 not... we can't, so we don't even try */
548 /* Dig into xio_ifp and xio_ofp here */
549 croak("Devel::Size: Can't size up perlio layers yet");
553 croak("Devel::Size: Unknown variable type");
558 MODULE = Devel::Size PACKAGE = Devel::Size
567 SV *thing = orig_thing;
568 /* Hash to track our seen pointers */
569 HV *tracking_hash = newHV();
572 /* Check warning status */
575 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
576 go_yell = SvIV(warn_flag);
580 /* If they passed us a reference then dereference it. This is the
581 only way we can check the sizes of arrays and hashes */
582 if (SvOK(thing) && SvROK(thing)) {
586 RETVAL = thing_size(thing, tracking_hash);
587 /* Clean up after ourselves */
588 SvREFCNT_dec(tracking_hash);
595 total_size(orig_thing)
599 SV *thing = orig_thing;
600 /* Hash to track our seen pointers */
601 HV *tracking_hash = newHV();
602 AV *pending_array = newAV();
608 /* Size starts at zero */
611 /* Check warning status */
614 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
615 go_yell = SvIV(warn_flag);
619 /* If they passed us a reference then dereference it. This is the
620 only way we can check the sizes of arrays and hashes */
621 if (SvOK(thing) && SvROK(thing)) {
625 /* Put it on the pending array */
626 av_push(pending_array, thing);
628 /* Now just yank things off the end of the array until it's done */
629 while (av_len(pending_array) >= 0) {
630 thing = av_pop(pending_array);
631 /* Process it if we've not seen it */
632 if (check_new(tracking_hash, thing)) {
635 /* Yes, it is. So let's check the type */
636 switch (SvTYPE(thing)) {
638 av_push(pending_array, SvRV(thing));
643 /* Quick alias to cut down on casting */
644 AV *tempAV = (AV *)thing;
648 if (av_len(tempAV) != -1) {
650 /* Run through them all */
651 for (index = 0; index <= av_len(tempAV); index++) {
652 /* Did we get something? */
653 if (tempSV = av_fetch(tempAV, index, 0)) {
655 if (*tempSV != &PL_sv_undef) {
656 /* Apparently not. Save it for later */
657 av_push(pending_array, *tempSV);
666 /* Is there anything in here? */
667 if (hv_iterinit((HV *)thing)) {
669 while (temp_he = hv_iternext((HV *)thing)) {
670 av_push(pending_array, hv_iterval((HV *)thing, temp_he));
676 /* Run through all the pieces and push the ones with bits */
678 av_push(pending_array, (SV *)GvSV(thing));
681 av_push(pending_array, (SV *)GvFORM(thing));
684 av_push(pending_array, (SV *)GvAV(thing));
687 av_push(pending_array, (SV *)GvHV(thing));
690 av_push(pending_array, (SV *)GvCV(thing));
699 size = thing_size(thing, tracking_hash);
704 /* Clean up after ourselves */
705 SvREFCNT_dec(tracking_hash);
706 SvREFCNT_dec(pending_array);