11 /* Checks to see if thing is in the hash. Returns true or false, and
12 notes thing in the hash.
14 This code does one Evil Thing. Since we're tracking pointers, we
15 tell perl that the string key is the address in the pointer. We do this by
16 passing in the address of the address, along with the size of a
17 pointer as the length. Perl then uses the four (or eight, on
18 64-bit machines) bytes of the address as the string we're using as
20 IV check_new(HV *tracking_hash, void *thing) {
21 if (hv_exists(tracking_hash, (char *)&thing, sizeof(void *))) {
24 hv_store(tracking_hash, (char *)&thing, sizeof(void *), &PL_sv_undef, 0);
29 /* Figure out how much magic is attached to the SV and return the
31 IV magic_size(SV *thing, HV *tracking_hash) {
36 if (!SvMAGIC(thing)) {
41 /* Get the base magic pointer */
42 magic_pointer = SvMAGIC(thing);
44 /* Have we seen the magic pointer? */
45 while (magic_pointer && check_new(tracking_hash, magic_pointer)) {
46 total_size += sizeof(MAGIC);
48 /* Have we seen the magic vtable? */
49 if (magic_pointer->mg_virtual &&
50 check_new(tracking_hash, magic_pointer->mg_virtual)) {
51 total_size += sizeof(MGVTBL);
54 /* Get the next in the chain */
55 magic_pointer = magic_pointer->mg_moremagic;
62 UV thing_size(SV *orig_thing, HV *tracking_hash) {
63 SV *thing = orig_thing;
64 UV total_size = sizeof(SV);
66 switch (SvTYPE(thing)) {
70 /* Just a plain integer. This will be differently sized depending
71 on whether purify's been compiled in */
74 total_size += sizeof(sizeof(XPVIV));
76 total_size += sizeof(IV);
79 /* Is it a float? Like the int, it depends on purify */
82 total_size += sizeof(sizeof(XPVNV));
84 total_size += sizeof(NV);
87 /* Is it a reference? */
89 total_size += sizeof(XRV);
91 /* How about a plain string? In which case we need to add in how
92 much has been allocated */
94 total_size += sizeof(XPV);
95 total_size += SvLEN(thing);
97 /* A string with an integer part? */
99 total_size += sizeof(XPVIV);
100 total_size += SvLEN(thing);
102 /* A string with a float part? */
104 total_size += sizeof(XPVNV);
105 total_size += SvLEN(thing);
108 total_size += sizeof(XPVMG);
109 total_size += SvLEN(thing);
110 total_size += magic_size(thing, tracking_hash);
113 total_size += sizeof(XPVBM);
114 total_size += SvLEN(thing);
115 total_size += magic_size(thing, tracking_hash);
118 total_size += sizeof(XPVLV);
119 total_size += SvLEN(thing);
120 total_size += magic_size(thing, tracking_hash);
122 /* How much space is dedicated to the array? Not counting the
123 elements in the array, mind, just the array itself */
125 total_size += sizeof(XPVAV);
126 /* Is there anything in the array? */
127 if (AvMAX(thing) != -1) {
128 total_size += sizeof(SV *) * AvMAX(thing);
130 /* Add in the bits on the other side of the beginning */
131 total_size += (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing)));
132 /* Is there something hanging off the arylen element? */
133 if (AvARYLEN(thing)) {
134 if (check_new(tracking_hash, AvARYLEN(thing))) {
135 total_size += thing_size(AvARYLEN(thing), tracking_hash);
138 total_size += magic_size(thing, tracking_hash);
141 /* First the base struct */
142 total_size += sizeof(XPVHV);
143 /* Now the array of buckets */
144 total_size += (sizeof(HE *) * (HvMAX(thing) + 1));
145 /* Now walk the bucket chain */
146 if (HvARRAY(thing)) {
149 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
150 cur_entry = *(HvARRAY(thing) + cur_bucket);
152 total_size += sizeof(HE);
153 if (cur_entry->hent_hek) {
154 /* Hash keys can be shared. Have we seen this before? */
155 if (check_new(tracking_hash, cur_entry->hent_hek)) {
156 total_size += sizeof(HEK);
157 total_size += cur_entry->hent_hek->hek_len - 1;
160 cur_entry = cur_entry->hent_next;
164 total_size += magic_size(thing, tracking_hash);
167 total_size += sizeof(XPVCV);
168 total_size += magic_size(thing, tracking_hash);
169 carp("CV isn't complete");
172 total_size += magic_size(thing, tracking_hash);
173 total_size += sizeof(XPVGV);
174 total_size += GvNAMELEN(thing);
175 /* Is there a file? */
177 if (check_new(tracking_hash, GvFILE(thing))) {
178 total_size += strlen(GvFILE(thing));
181 /* Is there something hanging off the glob? */
183 if (check_new(tracking_hash, GvGP(thing))) {
184 total_size += sizeof(GP);
189 total_size += sizeof(XPVFM);
190 carp("FM isn't complete");
193 total_size += sizeof(XPVIO);
194 carp("IO isn't complete");
197 croak("Unknown variable type");
203 MODULE = Devel::Size PACKAGE = Devel::Size
210 SV *thing = orig_thing;
211 /* Hash to track our seen pointers */
212 HV *tracking_hash = newHV();
214 /* If they passed us a reference then dereference it. This is the
215 only way we can check the sizes of arrays and hashes */
216 if (SvOK(thing) && SvROK(thing)) {
220 RETVAL = thing_size(thing, tracking_hash);
221 /* Clean up after ourselves */
222 SvREFCNT_dec(tracking_hash);
229 total_size(orig_thing)
233 SV *thing = orig_thing;
234 /* Hash to track our seen pointers */
235 HV *tracking_hash = newHV();
236 AV *pending_array = newAV();
238 /* Size starts at zero */
241 /* If they passed us a reference then dereference it. This is the
242 only way we can check the sizes of arrays and hashes */
243 if (SvOK(thing) && SvROK(thing)) {
247 /* Put it on the pending array */
248 av_push(pending_array, thing);
250 /* Now just yank things off the end of the array until it's done */
251 while (av_len(pending_array) >= 0) {
252 thing = av_pop(pending_array);
253 /* Process it if we've not seen it */
254 if (check_new(tracking_hash, thing)) {
257 /* Yes, it is. So let's check the type */
258 switch (SvTYPE(thing)) {
260 av_push(pending_array, SvRV(thing));
265 /* Quick alias to cut down on casting */
266 AV *tempAV = (AV *)thing;
270 if (av_len(tempAV) != -1) {
272 /* Run through them all */
273 for (index = 0; index <= av_len(tempAV); index++) {
274 /* Did we get something? */
275 if (tempSV = av_fetch(tempAV, index, 0)) {
277 if (*tempSV != &PL_sv_undef) {
278 /* Apparently not. Save it for later */
279 av_push(pending_array, *tempSV);
288 /* Is there anything in here? */
289 if (hv_iterinit((HV *)thing)) {
291 while (temp_he = hv_iternext((HV *)thing)) {
292 av_push(pending_array, hv_iterval((HV *)thing, temp_he));
298 /* Run through all the pieces and push the ones with bits */
300 av_push(pending_array, (SV *)GvSV(thing));
303 av_push(pending_array, (SV *)GvFORM(thing));
306 av_push(pending_array, (SV *)GvAV(thing));
309 av_push(pending_array, (SV *)GvHV(thing));
312 av_push(pending_array, (SV *)GvCV(thing));
320 RETVAL += thing_size(thing, tracking_hash);
324 /* Clean up after ourselves */
325 SvREFCNT_dec(tracking_hash);
326 SvREFCNT_dec(pending_array);