File Coverage

lib/Devel/MAT.xs
Criterion Covered Total %
statement 216 254 85.0
branch 86 168 51.1
condition n/a
subroutine n/a
pod n/a
total 302 422 71.5


line stmt bran cond sub pod time code
1             /* You may distribute under the terms of either the GNU General Public License
2             * or the Artistic License (the same terms as Perl itself)
3             *
4             * (C) Paul Evans, 2014-2022 -- leonerd@leonerd.org.uk
5             */
6              
7             #include "EXTERN.h"
8             #include "perl.h"
9             #include "XSUB.h"
10              
11             #ifndef av_count
12             # define av_count(av) (AvFILL(av) + 1)
13             #endif
14              
15             struct pmat_sv
16             {
17             SV *df;
18             long addr;
19             long refcnt;
20             long size;
21             long blessed_at;
22             long glob_at;
23             };
24              
25             /* Some subtypes */
26             struct pmat_sv_glob
27             {
28             struct pmat_sv _parent;
29             long stash_at;
30             long scalar_at, array_at, hash_at, code_at, egv_at, io_at, form_at;
31             long line;
32             const char *file;
33             const char *name;
34             };
35              
36             struct pmat_sv_scalar
37             {
38             struct pmat_sv _parent;
39             long uv;
40             long double nv;
41             char *pv;
42             size_t pv_strlen; /* length of the pv member data */
43             size_t pvlen; /* original PV length */
44             long ourstash_at;
45             char flags;
46             };
47              
48             struct pmat_sv_ref
49             {
50             struct pmat_sv _parent;
51             long rv_at;
52             long ourstash_at;
53             char is_weak;
54             };
55              
56             struct pmat_sv_array
57             {
58             struct pmat_sv _parent;
59             int flags;
60             char is_backrefs;
61             long n_elems;
62             long *elems_at;
63             long padcv_at;
64             };
65              
66             struct pmat_sv_hash
67             {
68             struct pmat_sv _parent;
69             long backrefs_at;
70             long n_values;
71             struct pmat_hval {
72             const char *key;
73             size_t klen;
74             long value;
75             } *values_at;
76             };
77              
78             struct pmat_sv_code
79             {
80             struct pmat_sv _parent;
81             long line;
82             long flags;
83             long oproot;
84             long depth;
85             long stash_at, outside_at, padlist_at, constval_at;
86             const char *file;
87             const char *name;
88             long protosub_at;
89             long padnames_at;
90             };
91              
92             struct pmat_sv_struct
93             {
94             struct pmat_sv _parent;
95             long n_fields;
96             struct pmat_sv_struct_field {
97             int type;
98             long val;
99             } *fields;
100             };
101              
102             struct pmat_sv_object
103             {
104             struct pmat_sv _parent;
105             long n_fields;
106             long *fields_at;
107             };
108              
109             #if (PERL_REVISION == 5) && (PERL_VERSION < 14)
110             static MAGIC *mg_findext(const SV *sv, int type, const MGVTBL *vtbl)
111             {
112             MAGIC *mg;
113             for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic)
114             if(mg->mg_type == type && mg->mg_virtual == vtbl)
115             return mg;
116             return NULL;
117             }
118             #endif
119              
120             /* Empty magic just for identity purposes */
121             const MGVTBL vtbl = { 0 };
122              
123             static struct pmat_sv *get_pmat_sv(HV *obj)
124             {
125 23489878           MAGIC *mg = mg_findext((SV *)obj, PERL_MAGIC_ext, &vtbl);
126 23489878           if(mg)
127 23489878           return (struct pmat_sv *)mg->mg_ptr;
128             else
129             return NULL;
130             }
131              
132 539896           static void free_pmat_sv(struct pmat_sv *sv)
133             {
134 539896           SvREFCNT_dec(sv->df);
135 539896           Safefree(sv);
136 539896           }
137              
138             /* An HV mapping strings to SvIVs of their usage count
139             */
140             static HV *strings;
141              
142 251547           static const char *save_string(const char *s, size_t len)
143             {
144 251547 100         if(!strings)
145 7           strings = newHV();
146              
147 251547           HE *ent = hv_fetch_ent(strings, sv_2mortal(newSVpv(s, len)), 1, 0);
148 251547           SV *count = HeVAL(ent);
149              
150 251547 100         if(!SvIOK(count))
151 54498           sv_setuv(count, 0);
152              
153             /* incr usage count */
154 251547 50         sv_setuv(count, SvUV(count) + 1);
155              
156 251547           return HeKEY(ent);;
157             }
158              
159 251547           static void drop_string(const char *s, size_t len)
160             {
161 251547           HE *ent = hv_fetch_ent(strings, sv_2mortal(newSVpv(s, len)), 0, 0);
162 251547 100         if(!ent)
163             return;
164              
165             /* decr usage count */
166 250535           SV *count = HeVAL(ent);
167 250535 50         if(SvUV(count) > 1) {
    100          
168 196044 50         sv_setuv(count, SvUV(count) - 1);
169 196044           return;
170             }
171              
172 54491           hv_delete(strings, s, 0, G_DISCARD);
173             }
174              
175             MODULE = Devel::MAT PACKAGE = Devel::MAT::SV
176              
177             void
178             _set_core_fields(self, type, df, addr, refcnt, size, blessed_at)
179             HV *self
180             int type
181             SV *df
182             long addr
183             long refcnt
184             long size
185             long blessed_at
186             CODE:
187             {
188             void *ptr;
189             struct pmat_sv *sv;
190 539896           switch(type) {
191             case 1: /* PMAT_SVtGLOB */
192 50390           Newx(ptr, 1, struct pmat_sv_glob); break;
193             case 2: /* PMAT_SVtSCALAR */
194             case 13: /* PMAT_SVtUNDEF */
195             case 14: /* PMAT_SVtYES */
196             case 15: /* PMAT_SVtNO */
197 357486           Newx(ptr, 1, struct pmat_sv_scalar); break;
198             case 3: /* PMAT_SVtREF */
199 25310           Newx(ptr, 1, struct pmat_sv_ref); break;
200             case 4: /* PMAT_SVtARRAY */
201 51096           Newx(ptr, 1, struct pmat_sv_array); break;
202             case 5: /* PMAT_SVtHASH */
203             case 6: /* PMAT_SVtSTASH */
204             case 17: /* PMAT_SVtCLASS */
205 9528           Newx(ptr, 1, struct pmat_sv_hash); break;
206             case 7: /* PMAT_SVtCODE */
207 40432           Newx(ptr, 1, struct pmat_sv_code); break;
208             case 16: /* PMAT_SVtOBJECT */
209 0           Newx(ptr, 1, struct pmat_sv_object); break;
210             case 0x7F: /* PMAT_SVtSTRUCT */
211 0           Newx(ptr, 1, struct pmat_sv_struct); break;
212             default:
213 5654           Newx(ptr, 1, struct pmat_sv); break;
214             }
215              
216             sv = ptr;
217              
218 539896           sv->df = newSVsv(df);
219 539896           sv->addr = addr;
220 539896           sv->refcnt = refcnt;
221 539896           sv->size = size;
222 539896           sv->blessed_at = blessed_at;
223 539896           sv->glob_at = 0;
224              
225 539896           sv_rvweaken(sv->df);
226              
227 539896           sv_magicext((SV *)self, NULL, PERL_MAGIC_ext, &vtbl, (char *)sv, 0);
228             }
229              
230             void DESTROY(self)
231             HV *self
232             CODE:
233             {
234             struct pmat_sv *sv = get_pmat_sv(self);
235 30964           free_pmat_sv(sv);
236             }
237              
238             void
239             _set_glob_at(self, glob_at)
240             HV *self
241             long glob_at
242             CODE:
243             {
244             struct pmat_sv *sv = get_pmat_sv(self);
245 87502           sv->glob_at = glob_at;
246             }
247              
248             SV *df(self)
249             HV *self
250             CODE:
251             {
252             struct pmat_sv *sv = get_pmat_sv(self);
253 5965891           RETVAL = SvREFCNT_inc(sv->df); /* return it directly */
254             }
255             OUTPUT:
256             RETVAL
257              
258             long addr(self)
259             HV *self
260             ALIAS:
261             addr = 0
262             refcnt = 1
263             size = 2
264             blessed_at = 3
265             glob_at = 4
266             CODE:
267             {
268             struct pmat_sv *sv = get_pmat_sv(self);
269 1109577 50         if(sv)
270 1109577           switch(ix) {
271 923314           case 0: RETVAL = sv->addr; break;
272 12           case 1: RETVAL = sv->refcnt; break;
273 17           case 2: RETVAL = sv->size; break;
274 171260           case 3: RETVAL = sv->blessed_at; break;
275 14974           case 4: RETVAL = sv->glob_at; break;
276             }
277             }
278             OUTPUT:
279             RETVAL
280              
281             MODULE = Devel::MAT PACKAGE = Devel::MAT::SV::GLOB
282              
283             void
284             _set_glob_fields(self, stash_at, scalar_at, array_at, hash_at, code_at, egv_at, io_at, form_at, line, file, name)
285             HV *self
286             long stash_at
287             long scalar_at
288             long array_at
289             long hash_at
290             long code_at
291             long egv_at
292             long io_at
293             long form_at
294             long line
295             SV *file
296             SV *name
297             CODE:
298             {
299             struct pmat_sv_glob *gv = (struct pmat_sv_glob *)get_pmat_sv(self);
300              
301 50390           gv->stash_at = stash_at;
302 50390           gv->scalar_at = scalar_at;
303 50390           gv->array_at = array_at;
304 50390           gv->hash_at = hash_at;
305 50390           gv->code_at = code_at;
306 50390           gv->egv_at = egv_at;
307 50390           gv->io_at = io_at;
308 50390           gv->form_at = form_at;
309              
310 50390 50         if(SvPOK(file))
311 50390 50         gv->file = save_string(SvPV_nolen(file), 0);
312             else
313 0           gv->file = NULL;
314              
315 50390           gv->line = line;
316              
317 50390 50         if(SvPOK(name))
318 50390 50         gv->name = savepv(SvPV_nolen(name));
319             else
320 0           gv->name = NULL;
321             }
322              
323             void DESTROY(self)
324             HV *self
325             CODE:
326             {
327             struct pmat_sv_glob *gv = (struct pmat_sv_glob *)get_pmat_sv(self);
328              
329 50390 50         if(gv->file)
330 50390           drop_string(gv->file, 0);
331 50390 50         if(gv->name)
332 50390           Safefree(gv->name);
333              
334 50390           free_pmat_sv((struct pmat_sv *)gv);
335             }
336              
337             long stash_at(self)
338             HV *self
339             ALIAS:
340             stash_at = 0
341             scalar_at = 1
342             array_at = 2
343             hash_at = 3
344             code_at = 4
345             egv_at = 5
346             io_at = 6
347             form_at = 7
348             line = 8
349             CODE:
350             {
351             struct pmat_sv_glob *gv = (struct pmat_sv_glob *)get_pmat_sv(self);
352 479956 50         if(gv)
353 479956           switch(ix) {
354 27           case 0: RETVAL = gv->stash_at; break;
355 91097           case 1: RETVAL = gv->scalar_at; break;
356 91092           case 2: RETVAL = gv->array_at; break;
357 91420           case 3: RETVAL = gv->hash_at; break;
358 91097           case 4: RETVAL = gv->code_at; break;
359 33832           case 5: RETVAL = gv->egv_at; break;
360 40696           case 6: RETVAL = gv->io_at; break;
361 40695           case 7: RETVAL = gv->form_at; break;
362 0           case 8: RETVAL = gv->line; break;
363             }
364             }
365             OUTPUT:
366             RETVAL
367              
368             const char *
369             file(self)
370             HV *self
371             ALIAS:
372             file = 0
373             name = 1
374             CODE:
375             {
376             struct pmat_sv_glob *gv = (struct pmat_sv_glob *)get_pmat_sv(self);
377 27 50         if(gv)
378 27           switch(ix) {
379 0           case 0: RETVAL = gv->file; break;
380 27           case 1: RETVAL = gv->name; break;
381             }
382             }
383             OUTPUT:
384             RETVAL
385              
386             MODULE = Devel::MAT PACKAGE = Devel::MAT::SV::SCALAR
387              
388             void
389             _set_scalar_fields(self, flags, uv, nv, pv, pvlen, ourstash_at)
390             HV *self
391             int flags
392             long uv
393             SV *nv
394             SV *pv
395             long pvlen
396             long ourstash_at
397             CODE:
398             {
399             struct pmat_sv_scalar *sv = (struct pmat_sv_scalar *)get_pmat_sv(self);
400              
401 357486           sv->flags = flags;
402 357486           sv->uv = uv;
403 357486           sv->pvlen = pvlen;
404 357486           sv->ourstash_at = ourstash_at;
405              
406 357486 100         if(flags & 0x04)
407 5414 100         if(SvNOK(nv))
408 5295 50         sv->nv = SvNV(nv);
409             else
410 119           sv->flags &= ~0x04;
411              
412 357486 100         if(flags & 0x08) {
413 157962           sv->pv_strlen = SvCUR(pv);
414              
415 157962 50         if(SvLEN(pv) && !SvOOK(pv)) {
    50          
416             /* Swipe pv's buffer */
417 157962           sv->pv = SvPVX(pv);
418              
419 157962           SvPVX(pv) = NULL;
420 157962           SvCUR(pv) = 0;
421 157962           SvLEN(pv) = 0;
422 157962           SvPOK_off(pv);
423             }
424             else {
425 0 0         sv->pv = savepvn(SvPV_nolen(pv), SvCUR(pv));
426             }
427             }
428             }
429              
430             void DESTROY(self)
431             HV *self
432             CODE:
433             {
434             struct pmat_sv_scalar *sv = (struct pmat_sv_scalar *)get_pmat_sv(self);
435              
436             // TODO: don't crash
437             //if(sv->pv)
438             // Safefree(sv->pv);
439              
440 357486           free_pmat_sv((struct pmat_sv *)sv);
441             }
442              
443             int pv_is_utf8(self)
444             HV *self
445             CODE:
446             {
447             struct pmat_sv_scalar *sv = (struct pmat_sv_scalar *)get_pmat_sv(self);
448 2 50         if(sv)
449 2           RETVAL = sv->flags & 0x10;
450             }
451             OUTPUT:
452             RETVAL
453              
454             SV *uv(self)
455             HV *self
456             CODE:
457             {
458             struct pmat_sv_scalar *sv = (struct pmat_sv_scalar *)get_pmat_sv(self);
459 542063           RETVAL = newSV(0);
460 542063 50         if(sv && sv->flags & 0x01 && !(sv->flags & 0x02))
    100          
461 69031           sv_setuv(RETVAL, sv->uv);
462             }
463             OUTPUT:
464             RETVAL
465              
466             SV *iv(self)
467             HV *self
468             CODE:
469             {
470             struct pmat_sv_scalar *sv = (struct pmat_sv_scalar *)get_pmat_sv(self);
471 486118           RETVAL = newSV(0);
472 486118 50         if(sv && sv->flags & 0x01 && sv->flags & 0x02)
    100          
473 95           sv_setiv(RETVAL, sv->uv);
474             }
475             OUTPUT:
476             RETVAL
477              
478             SV *nv(self)
479             HV *self
480             CODE:
481             {
482             struct pmat_sv_scalar *sv = (struct pmat_sv_scalar *)get_pmat_sv(self);
483 486041           RETVAL = newSV(0);
484 486041 50         if(sv && sv->flags & 0x04)
    100          
485 8026           sv_setnv(RETVAL, sv->nv);
486             }
487             OUTPUT:
488             RETVAL
489              
490             SV *pv(self)
491             HV *self
492             CODE:
493             {
494             struct pmat_sv_scalar *sv = (struct pmat_sv_scalar *)get_pmat_sv(self);
495 531359           RETVAL = newSV(0);
496 531359 50         if(sv && sv->flags & 0x08)
    100          
497 270962           sv_setpvn(RETVAL, sv->pv, sv->pv_strlen);
498 531359 50         if(sv && sv->flags & 0x10)
    100          
499 399           SvUTF8_on(RETVAL);
500             }
501             OUTPUT:
502             RETVAL
503              
504             SV *pvlen(self)
505             HV *self
506             CODE:
507             {
508             struct pmat_sv_scalar *sv = (struct pmat_sv_scalar *)get_pmat_sv(self);
509 5           RETVAL = newSV(0);
510 5 50         if(sv && sv->flags & 0x08)
    50          
511 5           sv_setuv(RETVAL, sv->pvlen);
512             }
513             OUTPUT:
514             RETVAL
515              
516             long
517             ourstash_at(self)
518             HV *self
519             CODE:
520             {
521             struct pmat_sv_scalar *sv = (struct pmat_sv_scalar *)get_pmat_sv(self);
522 102146 50         RETVAL = sv ? sv->ourstash_at : 0;
523             }
524             OUTPUT:
525             RETVAL
526              
527             MODULE = Devel::MAT PACKAGE = Devel::MAT::SV::REF
528              
529             void
530             _set_ref_fields(self, rv_at, ourstash_at, is_weak)
531             HV *self
532             long rv_at
533             long ourstash_at
534             char is_weak
535             CODE:
536             {
537             struct pmat_sv_ref *rv = (struct pmat_sv_ref *)get_pmat_sv(self);
538              
539 25310           rv->rv_at = rv_at;
540 25310           rv->ourstash_at = ourstash_at;
541 25310           rv->is_weak = is_weak;
542             }
543              
544             long
545             rv_at(self)
546             HV *self
547             ALIAS:
548             rv_at = 0
549             ourstash_at = 1
550             CODE:
551             {
552             struct pmat_sv_ref *rv = (struct pmat_sv_ref *)get_pmat_sv(self);
553 25521 50         if(rv)
554 25521           switch(ix) {
555 18263           case 0: RETVAL = rv->rv_at; break;
556 7258           case 1: RETVAL = rv->ourstash_at; break;
557             }
558             }
559             OUTPUT:
560             RETVAL
561              
562             char
563             is_weak(self)
564             HV *self
565             CODE:
566             {
567             struct pmat_sv_ref *rv = (struct pmat_sv_ref *)get_pmat_sv(self);
568 14490 50         RETVAL = rv ? rv->is_weak : 0;
569             }
570             OUTPUT:
571             RETVAL
572              
573             MODULE = Devel::MAT PACKAGE = Devel::MAT::SV::ARRAY
574              
575             void
576             _set_array_fields(self, flags, elems_at)
577             HV *self
578             int flags
579             AV *elems_at
580             CODE:
581             {
582             struct pmat_sv_array *av = (struct pmat_sv_array *)get_pmat_sv(self);
583             long n, i;
584              
585 51096           av->flags = flags;
586 51096           av->is_backrefs = 0;
587 51096           av->padcv_at = 0;
588              
589 51096 50         n = av_count(elems_at);
590 51096           av->n_elems = n;
591              
592 51096 50         Newx(av->elems_at, n, long);
593 373220 100         for(i = 0; i < n; i++)
594 322124 50         av->elems_at[i] = SvUV(AvARRAY(elems_at)[i]);
595             }
596              
597             void DESTROY(self)
598             HV *self
599             CODE:
600             {
601             struct pmat_sv_array *av = (struct pmat_sv_array *)get_pmat_sv(self);
602              
603 51096           Safefree(av->elems_at);
604              
605 51096           free_pmat_sv((struct pmat_sv *)av);
606             }
607              
608             void
609             _set_backrefs(self, is_backrefs)
610             HV *self
611             int is_backrefs
612             CODE:
613             {
614             struct pmat_sv_array *av = (struct pmat_sv_array *)get_pmat_sv(self);
615 2124           av->is_backrefs = !!is_backrefs;
616 2124 50         if(is_backrefs) {
617             /* All backrefs ARRAYs are always UNREAL */
618 2124           av->flags |= 0x01;
619             }
620             }
621              
622             void
623             _clear_elem(self, i)
624             HV *self
625             unsigned long i
626             CODE:
627             {
628             struct pmat_sv_array *av = (struct pmat_sv_array *)get_pmat_sv(self);
629 0 0         if(av && i < av->n_elems)
    0          
630 0           av->elems_at[i] = 0;
631             }
632              
633             void
634             _set_padcv_at(self, padcv_at)
635             HV *self
636             long padcv_at
637             CODE:
638             {
639             struct pmat_sv_array *av = (struct pmat_sv_array *)get_pmat_sv(self);
640 21098           av->padcv_at = padcv_at;
641             }
642              
643             int
644             is_unreal(self)
645             HV *self
646             CODE:
647             {
648             struct pmat_sv_array *av = (struct pmat_sv_array *)get_pmat_sv(self);
649 20579 50         RETVAL = av ? av->flags & 0x01 : 0;
650             }
651             OUTPUT:
652             RETVAL
653              
654             int
655             is_backrefs(self)
656             HV *self
657             CODE:
658             {
659             struct pmat_sv_array *av = (struct pmat_sv_array *)get_pmat_sv(self);
660 1 50         RETVAL = av ? av->is_backrefs : 0;
661             }
662             OUTPUT:
663             RETVAL
664              
665             long
666             n_elems(self)
667             HV *self
668             ALIAS:
669             n_elems = 0
670             padcv_at = 1
671             CODE:
672             {
673             struct pmat_sv_array *av = (struct pmat_sv_array *)get_pmat_sv(self);
674 47096 50         if(av)
675 47096           switch(ix) {
676 41042           case 0: RETVAL = av->n_elems; break;
677 6054           case 1: RETVAL = av->padcv_at; break;
678             }
679             }
680             OUTPUT:
681             RETVAL
682              
683             long
684             elem_at(self, i)
685             HV *self
686             unsigned long i
687             CODE:
688             {
689             struct pmat_sv_array *av = (struct pmat_sv_array *)get_pmat_sv(self);
690 9778783 50         if(av && i < av->n_elems)
    50          
691 9778783           RETVAL = av->elems_at[i];
692             }
693             OUTPUT:
694             RETVAL
695              
696             MODULE = Devel::MAT PACKAGE = Devel::MAT::SV::HASH
697              
698             void
699             _set_hash_fields(self, backrefs_at, values_at)
700             HV *self
701             long backrefs_at
702             HV *values_at
703             CODE:
704             {
705             long i, n;
706             HE *ent;
707             struct pmat_sv_hash *hv = (struct pmat_sv_hash *)get_pmat_sv(self);
708              
709 9528           n = hv_iterinit(values_at);
710              
711 9528           hv->backrefs_at = backrefs_at;
712 9528           hv->n_values = n;
713              
714 9528 50         Newx(hv->values_at, n, struct pmat_hval);
715 170253 100         for(i = 0; ent = hv_iternext(values_at); i++) {
716             I32 klen;
717 160725           const char *key = hv_iterkey(ent, &klen);
718              
719 160725           hv->values_at[i].key = save_string(key, klen);
720 160725           hv->values_at[i].klen = klen;
721 160725 50         hv->values_at[i].value = SvUV(hv_iterval(values_at, ent));
722             }
723              
724             // TODO: sort the values so we can binsearch for them later
725             }
726              
727             void DESTROY(self)
728             HV *self
729             CODE:
730             {
731             struct pmat_sv_hash *hv = (struct pmat_sv_hash *)get_pmat_sv(self);
732             long i;
733              
734 170253 100         for(i = 0; i < hv->n_values; i++)
735 160725           drop_string(hv->values_at[i].key, hv->values_at[i].klen);
736              
737 9528           Safefree(hv->values_at);
738              
739 9528           free_pmat_sv((struct pmat_sv *)hv);
740             }
741              
742             long
743             backrefs_at(self)
744             HV *self
745             ALIAS:
746             backrefs_at = 0
747             n_values = 1
748             CODE:
749             {
750             struct pmat_sv_hash *hv = (struct pmat_sv_hash *)get_pmat_sv(self);
751 26029 50         if(hv)
752 26029           switch(ix) {
753 23307           case 0: RETVAL = hv->backrefs_at; break;
754 2722           case 1: RETVAL = hv->n_values; break;
755             }
756             }
757             OUTPUT:
758             RETVAL
759              
760             void
761             keys(self)
762             HV *self
763             ALIAS:
764             keys = 0
765             values_at = 1
766             PPCODE:
767             {
768             struct pmat_sv_hash *hv = (struct pmat_sv_hash *)get_pmat_sv(self);
769             long i;
770              
771 8651 50         EXTEND(SP, hv->n_values);
    100          
772 2286544 100         for(i = 0; i < hv->n_values; i++)
773 2277893           switch(ix) {
774             case 0: // keys
775 2274197           mPUSHp(hv->values_at[i].key, hv->values_at[i].klen);
776 2274197           break;
777             case 1: // values_at
778 3696           mPUSHu(hv->values_at[i].value);
779 3696           break;
780             }
781              
782 8651           XSRETURN(hv->n_values);
783             }
784              
785             SV *
786             value_at(self, key)
787             HV *self
788             SV *key
789             CODE:
790             {
791             struct pmat_sv_hash *hv = (struct pmat_sv_hash *)get_pmat_sv(self);
792             long i;
793 2274254           long klen = SvCUR(key);
794              
795             RETVAL = &PL_sv_undef;
796              
797             // TODO: store values sorted so we can binsearch
798 709697037 50         for(i = 0; i < hv->n_values; i++) {
799 709697037 100         if(hv->values_at[i].klen != klen)
800 641036927           continue;
801 68660110 50         if(memcmp(hv->values_at[i].key, SvPV_nolen(key), klen) != 0)
    100          
802 66385856           continue;
803              
804 2274254           RETVAL = newSVuv(hv->values_at[i].value);
805 2274254           break;
806             }
807             }
808             OUTPUT:
809             RETVAL
810              
811             MODULE = Devel::MAT PACKAGE = Devel::MAT::SV::CODE
812              
813             void
814             _set_code_fields(self, line, flags, oproot, depth, stash_at, outside_at, padlist_at, constval_at, file, name)
815             HV *self
816             long line
817             long flags
818             long oproot
819             long depth
820             long stash_at
821             long outside_at
822             long padlist_at
823             long constval_at
824             SV *file
825             SV *name
826             CODE:
827             {
828             struct pmat_sv_code *cv = (struct pmat_sv_code *)get_pmat_sv(self);
829              
830 40432           cv->line = line;
831 40432           cv->flags = flags;
832 40432           cv->oproot = oproot;
833 40432           cv->depth = depth;
834 40432           cv->stash_at = stash_at;
835 40432           cv->outside_at = outside_at;
836 40432           cv->padlist_at = padlist_at;
837 40432           cv->constval_at = constval_at;
838 40432           cv->protosub_at = 0;
839 40432           cv->padnames_at = 0;
840              
841 40432 50         if(SvPOK(file))
842 40432 50         cv->file = save_string(SvPV_nolen(file), 0);
843             else
844 0           cv->file = NULL;
845              
846 40432 50         if(SvPOK(name))
847 0 0         cv->name = save_string(SvPV_nolen(name), 0);
848             else
849 40432           cv->name = NULL;
850             }
851              
852             void DESTROY(self)
853             HV *self
854             CODE:
855             {
856             struct pmat_sv_code *cv = (struct pmat_sv_code *)get_pmat_sv(self);
857              
858 40432 50         if(cv->file)
859 40432           drop_string(cv->file, 0);
860              
861 40432           free_pmat_sv((struct pmat_sv *)cv);
862             }
863              
864             void
865             _set_protosub_at(self, addr)
866             HV *self
867             long addr
868             ALIAS:
869             _set_protosub_at = 0
870             _set_padnames_at = 1
871             CODE:
872             {
873             struct pmat_sv_code *cv = (struct pmat_sv_code *)get_pmat_sv(self);
874 23495           switch(ix) {
875 2460           case 0: cv->protosub_at = addr; break;
876 21035           case 1: cv->padnames_at = addr; break;
877             }
878             }
879              
880             int
881             is_clone(self)
882             HV *self
883             ALIAS:
884             is_clone = 0x01
885             is_cloned = 0x02
886             is_xsub = 0x04
887             is_weakoutside = 0x08
888             is_cvgv_rc = 0x10
889             is_lexical = 0x20
890             CODE:
891             {
892             struct pmat_sv_code *cv = (struct pmat_sv_code *)get_pmat_sv(self);
893 125042 50         RETVAL = cv ? cv->flags & ix : 0;
894             }
895             OUTPUT:
896             RETVAL
897              
898             long
899             line(self)
900             HV *self
901             ALIAS:
902             line = 0
903             oproot = 1
904             depth = 2
905             stash_at = 3
906             outside_at = 4
907             padlist_at = 5
908             constval_at = 6
909             protosub_at = 7
910             padnames_at = 8
911             CODE:
912             {
913             struct pmat_sv_code *cv = (struct pmat_sv_code *)get_pmat_sv(self);
914 257867 50         if(cv)
915 257867           switch(ix) {
916 1           case 0: RETVAL = cv->line; break;
917 55331           case 1: RETVAL = cv->oproot; break;
918 7           case 2: RETVAL = cv->depth; break;
919 14942           case 3: RETVAL = cv->stash_at; break;
920 20057           case 4: RETVAL = cv->outside_at; break;
921 60489           case 5: RETVAL = cv->padlist_at; break;
922 31608           case 6: RETVAL = cv->constval_at; break;
923 14943           case 7: RETVAL = cv->protosub_at; break;
924 60489           case 8: RETVAL = cv->padnames_at; break;
925             }
926             }
927             OUTPUT:
928             RETVAL
929              
930             const char *
931             file(self)
932             HV *self
933             ALIAS:
934             file = 0
935             hekname = 1
936             CODE:
937             {
938             struct pmat_sv_code *cv = (struct pmat_sv_code *)get_pmat_sv(self);
939 23 50         if(cv)
940 23           switch(ix) {
941 0           case 0: RETVAL = cv->file; break;
942 23           case 1: RETVAL = cv->name; break;
943             }
944             }
945             OUTPUT:
946             RETVAL
947              
948             MODULE = Devel::MAT PACKAGE = Devel::MAT::SV::OBJECT
949              
950             void
951             _set_object_fields(self, fields_at)
952             HV *self
953             AV *fields_at
954             CODE:
955             {
956             struct pmat_sv_object *obj = (struct pmat_sv_object *)get_pmat_sv(self);
957             long n, i;
958              
959 0 0         n = av_count(fields_at);
960 0           obj->n_fields = n;
961              
962 0 0         Newx(obj->fields_at, n, long);
963 0 0         for(i = 0; i < n; i++)
964 0 0         obj->fields_at[i] = SvUV(AvARRAY(fields_at)[i]);
965             }
966              
967             void DESTROY(self)
968             HV *self
969             CODE:
970             {
971             struct pmat_sv_object *obj = (struct pmat_sv_object *)get_pmat_sv(self);
972              
973 0           Safefree(obj->fields_at);
974              
975 0           free_pmat_sv((struct pmat_sv *)obj);
976             }
977              
978             long
979             n_fields(self)
980             HV *self
981             CODE:
982             {
983             struct pmat_sv_object *obj = (struct pmat_sv_object *)get_pmat_sv(self);
984 0 0         if(obj)
985 0           RETVAL = obj->n_fields;
986             }
987             OUTPUT:
988             RETVAL
989              
990             long
991             field_at(self, i)
992             HV *self
993             unsigned long i
994             CODE:
995             {
996             struct pmat_sv_object *obj = (struct pmat_sv_object *)get_pmat_sv(self);
997 0 0         if(obj && i < obj->n_fields)
    0          
998 0           RETVAL = obj->fields_at[i];
999             }
1000             OUTPUT:
1001             RETVAL
1002              
1003             MODULE = Devel::MAT PACKAGE = Devel::MAT::SV::C_STRUCT
1004              
1005             long
1006             structid(self)
1007             HV *self
1008             ALIAS:
1009             structid = 0
1010             blessed_at = 1
1011             CODE:
1012             {
1013             struct pmat_sv *sv = get_pmat_sv(self);
1014 0           switch(ix) {
1015 0           case 0: RETVAL = sv->blessed_at; break;
1016 0           case 1: RETVAL = 0; break;
1017             }
1018             }
1019             OUTPUT:
1020             RETVAL
1021              
1022             void
1023             _set_struct_fields(self, ...)
1024             HV *self
1025             CODE:
1026             {
1027             struct pmat_sv_struct *st = (struct pmat_sv_struct *)get_pmat_sv(self);
1028             long n, i;
1029              
1030 0           n = (items-1) / 2;
1031 0           st->n_fields = n;
1032              
1033 0 0         Newx(st->fields, n, struct pmat_sv_struct_field);
1034 0 0         for(i = 0; i < n; i++) {
1035 0 0         int type = SvIV(ST(1 + 2*i));
1036 0           st->fields[i].type = type;
1037              
1038 0 0         switch(type) {
1039             case 0x00: // PTR
1040             case 0x01: // BOOL
1041             case 0x02: // U8
1042             case 0x03: // U32
1043             case 0x04: // UINT
1044 0 0         st->fields[i].val = SvUV(ST(2 + 2*i));
1045             break;
1046             default:
1047 0           croak("ARGH TODO _set_struct_fields from type=%d\n", type);
1048             }
1049             }
1050             }
1051              
1052             long
1053             n_fields(self)
1054             HV *self
1055             CODE:
1056             {
1057             struct pmat_sv_struct *st = (struct pmat_sv_struct *)get_pmat_sv(self);
1058 0           RETVAL = st->n_fields;
1059             }
1060             OUTPUT:
1061             RETVAL
1062              
1063             long
1064             field(self, i)
1065             HV *self
1066             unsigned long i
1067             CODE:
1068             {
1069             struct pmat_sv_struct *st = (struct pmat_sv_struct *)get_pmat_sv(self);
1070 0 0         if(i < st->n_fields)
1071 0           RETVAL = st->fields[i].val;
1072             }
1073             OUTPUT:
1074             RETVAL