11 static int go_yell = 1;
13 /* Checks to see if thing is in the hash. Returns true or false, and
14 notes thing in the hash.
16 This code does one Evil Thing. Since we're tracking pointers, we
17 tell perl that the string key is the address in the pointer. We do this by
18 passing in the address of the address, along with the size of a
19 pointer as the length. Perl then uses the four (or eight, on
20 64-bit machines) bytes of the address as the string we're using as
22 IV check_new(HV *tracking_hash, void *thing) {
23 if (hv_exists(tracking_hash, (char *)&thing, sizeof(void *))) {
26 hv_store(tracking_hash, (char *)&thing, sizeof(void *), &PL_sv_yes, 0);
31 /* Figure out how much magic is attached to the SV and return the
33 IV magic_size(SV *thing, HV *tracking_hash) {
38 if (!SvMAGIC(thing)) {
43 /* Get the base magic pointer */
44 magic_pointer = SvMAGIC(thing);
46 /* Have we seen the magic pointer? */
47 while (magic_pointer && check_new(tracking_hash, magic_pointer)) {
48 total_size += sizeof(MAGIC);
50 /* Have we seen the magic vtable? */
51 if (magic_pointer->mg_virtual &&
52 check_new(tracking_hash, magic_pointer->mg_virtual)) {
53 total_size += sizeof(MGVTBL);
56 /* Get the next in the chain */
57 magic_pointer = magic_pointer->mg_moremagic;
64 UV thing_size(SV *orig_thing, HV *tracking_hash) {
65 SV *thing = orig_thing;
66 UV total_size = sizeof(SV);
68 switch (SvTYPE(thing)) {
72 /* Just a plain integer. This will be differently sized depending
73 on whether purify's been compiled in */
76 total_size += sizeof(sizeof(XPVIV));
78 total_size += sizeof(IV);
81 /* Is it a float? Like the int, it depends on purify */
84 total_size += sizeof(sizeof(XPVNV));
86 total_size += sizeof(NV);
89 /* Is it a reference? */
91 total_size += sizeof(XRV);
93 /* How about a plain string? In which case we need to add in how
94 much has been allocated */
96 total_size += sizeof(XPV);
97 total_size += SvLEN(thing);
99 /* A string with an integer part? */
101 total_size += sizeof(XPVIV);
102 total_size += SvLEN(thing);
104 /* A string with a float part? */
106 total_size += sizeof(XPVNV);
107 total_size += SvLEN(thing);
110 total_size += sizeof(XPVMG);
111 total_size += SvLEN(thing);
112 total_size += magic_size(thing, tracking_hash);
115 total_size += sizeof(XPVBM);
116 total_size += SvLEN(thing);
117 total_size += magic_size(thing, tracking_hash);
120 total_size += sizeof(XPVLV);
121 total_size += SvLEN(thing);
122 total_size += magic_size(thing, tracking_hash);
124 /* How much space is dedicated to the array? Not counting the
125 elements in the array, mind, just the array itself */
127 total_size += sizeof(XPVAV);
128 /* Is there anything in the array? */
129 if (AvMAX(thing) != -1) {
130 total_size += sizeof(SV *) * AvMAX(thing);
132 /* Add in the bits on the other side of the beginning */
133 total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
134 /* Is there something hanging off the arylen element? */
135 if (AvARYLEN(thing)) {
136 if (check_new(tracking_hash, AvARYLEN(thing))) {
137 total_size += thing_size(AvARYLEN(thing), tracking_hash);
140 total_size += magic_size(thing, tracking_hash);
143 /* First the base struct */
144 total_size += sizeof(XPVHV);
145 /* Now the array of buckets */
146 total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
147 /* Now walk the bucket chain */
148 if (HvARRAY(thing)) {
151 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
152 cur_entry = *(HvARRAY(thing) + cur_bucket);
154 total_size += sizeof(HE);
155 if (cur_entry->hent_hek) {
156 /* Hash keys can be shared. Have we seen this before? */
157 if (check_new(tracking_hash, cur_entry->hent_hek)) {
158 total_size += HEK_BASESIZE + cur_entry->hent_hek->hek_len + 2;
161 cur_entry = cur_entry->hent_next;
165 total_size += magic_size(thing, tracking_hash);
168 total_size += sizeof(XPVCV);
169 total_size += magic_size(thing, tracking_hash);
171 carp("Devel::Size: Calculated sizes for CVs are incomplete");
175 total_size += magic_size(thing, tracking_hash);
176 total_size += sizeof(XPVGV);
177 total_size += GvNAMELEN(thing);
179 /* Is there a file? */
181 if (check_new(tracking_hash, GvFILE(thing))) {
182 total_size += strlen(GvFILE(thing));
186 /* Is there something hanging off the glob? */
188 if (check_new(tracking_hash, GvGP(thing))) {
189 total_size += sizeof(GP);
192 if (generic_thing = (SV *)(GvGP(thing)->gp_sv)) {
193 total_size += thing_size(generic_thing, tracking_hash);
195 if (generic_thing = (SV *)(GvGP(thing)->gp_form)) {
196 total_size += thing_size(generic_thing, tracking_hash);
198 if (generic_thing = (SV *)(GvGP(thing)->gp_av)) {
199 total_size += thing_size(generic_thing, tracking_hash);
201 if (generic_thing = (SV *)(GvGP(thing)->gp_hv)) {
202 total_size += thing_size(generic_thing, tracking_hash);
204 if (generic_thing = (SV *)(GvGP(thing)->gp_egv)) {
205 total_size += thing_size(generic_thing, tracking_hash);
207 if (generic_thing = (SV *)(GvGP(thing)->gp_cv)) {
208 total_size += thing_size(generic_thing, tracking_hash);
215 total_size += sizeof(XPVFM);
217 carp("Devel::Size: Calculated sizes for FMs are incomplete");
221 total_size += sizeof(XPVIO);
222 total_size += magic_size(thing, tracking_hash);
223 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xpv_pv)) {
224 total_size += ((XPVIO *) SvANY(thing))->xpv_cur;
226 /* Some embedded char pointers */
227 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_top_name)) {
228 total_size += strlen(((XPVIO *) SvANY(thing))->xio_top_name);
230 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_fmt_name)) {
231 total_size += strlen(((XPVIO *) SvANY(thing))->xio_fmt_name);
233 if (check_new(tracking_hash, ((XPVIO *) SvANY(thing))->xio_bottom_name)) {
234 total_size += strlen(((XPVIO *) SvANY(thing))->xio_bottom_name);
236 /* Throw the GVs on the list to be walked if they're not-null */
237 if (((XPVIO *) SvANY(thing))->xio_top_gv) {
238 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_top_gv,
241 if (((XPVIO *) SvANY(thing))->xio_bottom_gv) {
242 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv,
245 if (((XPVIO *) SvANY(thing))->xio_fmt_gv) {
246 total_size += thing_size((SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv,
250 /* Only go trotting through the IO structures if they're really
251 trottable. If USE_PERLIO is defined we can do this. If
252 not... we can't, so we don't even try */
254 /* Dig into xio_ifp and xio_ofp here */
255 croak("Devel::Size: Can't size up perlio layers yet");
259 croak("Devel::Size: Unknown variable type");
264 MODULE = Devel::Size PACKAGE = Devel::Size
273 SV *thing = orig_thing;
274 /* Hash to track our seen pointers */
275 HV *tracking_hash = newHV();
278 /* Check warning status */
281 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
282 go_yell = SvIV(warn_flag);
286 /* If they passed us a reference then dereference it. This is the
287 only way we can check the sizes of arrays and hashes */
288 if (SvOK(thing) && SvROK(thing)) {
292 RETVAL = thing_size(thing, tracking_hash);
293 /* Clean up after ourselves */
294 SvREFCNT_dec(tracking_hash);
301 total_size(orig_thing)
305 SV *thing = orig_thing;
306 /* Hash to track our seen pointers */
307 HV *tracking_hash = newHV();
308 AV *pending_array = newAV();
314 /* Size starts at zero */
317 /* Check warning status */
320 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
321 go_yell = SvIV(warn_flag);
325 /* If they passed us a reference then dereference it. This is the
326 only way we can check the sizes of arrays and hashes */
327 if (SvOK(thing) && SvROK(thing)) {
331 /* Put it on the pending array */
332 av_push(pending_array, thing);
334 /* Now just yank things off the end of the array until it's done */
335 while (av_len(pending_array) >= 0) {
336 thing = av_pop(pending_array);
337 /* Process it if we've not seen it */
338 if (check_new(tracking_hash, thing)) {
341 /* Yes, it is. So let's check the type */
342 switch (SvTYPE(thing)) {
344 av_push(pending_array, SvRV(thing));
349 /* Quick alias to cut down on casting */
350 AV *tempAV = (AV *)thing;
354 if (av_len(tempAV) != -1) {
356 /* Run through them all */
357 for (index = 0; index <= av_len(tempAV); index++) {
358 /* Did we get something? */
359 if (tempSV = av_fetch(tempAV, index, 0)) {
361 if (*tempSV != &PL_sv_undef) {
362 /* Apparently not. Save it for later */
363 av_push(pending_array, *tempSV);
372 /* Is there anything in here? */
373 if (hv_iterinit((HV *)thing)) {
375 while (temp_he = hv_iternext((HV *)thing)) {
376 av_push(pending_array, hv_iterval((HV *)thing, temp_he));
382 /* Run through all the pieces and push the ones with bits */
384 av_push(pending_array, (SV *)GvSV(thing));
387 av_push(pending_array, (SV *)GvFORM(thing));
390 av_push(pending_array, (SV *)GvAV(thing));
393 av_push(pending_array, (SV *)GvHV(thing));
396 av_push(pending_array, (SV *)GvCV(thing));
405 size = thing_size(thing, tracking_hash);
410 /* Clean up after ourselves */
411 SvREFCNT_dec(tracking_hash);
412 SvREFCNT_dec(pending_array);