File Coverage

JIT.xs
Criterion Covered Total %
statement 101 107 94.3
branch 51 72 70.8
condition n/a
subroutine n/a
pod n/a
total 152 179 84.9


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #include "lib/XS/JIT/xs_jit.h"
7             #include "lib/XS/JIT/xs_jit_builder.h"
8              
9             MODULE = XS::JIT PACKAGE = XS::JIT
10              
11             PROTOTYPES: DISABLE
12              
13             int
14             compile(class, ...)
15             SV *class
16             PREINIT:
17 284           const char *code = NULL;
18 284           const char *name = NULL;
19 284           const char *cache_dir = NULL;
20 284           const char *extra_cflags = NULL;
21 284           const char *extra_ldflags = NULL;
22 284           int force = 0;
23 284           HV *functions_hv = NULL;
24 284           XS_JIT_Func *functions = NULL;
25 284 50         int num_functions = 0;
26             int i;
27             HE *entry;
28             CODE:
29             PERL_UNUSED_VAR(class);
30              
31             /* Parse named arguments */
32 284 100         if ((items - 1) % 2 != 0) {
33 1           croak("XS::JIT->compile requires key => value pairs");
34             }
35              
36 1407 100         for (i = 1; i < items; i += 2) {
37 1125           const char *key = SvPV_nolen(ST(i));
38 1125           SV *val = ST(i + 1);
39              
40 1125 100         if (strEQ(key, "code")) {
41 282           code = SvPV_nolen(val);
42 843 100         } else if (strEQ(key, "name")) {
43 282           name = SvPV_nolen(val);
44 561 100         } else if (strEQ(key, "cache_dir")) {
45 278 50         if (SvOK(val)) {
46 278           cache_dir = SvPV_nolen(val);
47             }
48 283 100         } else if (strEQ(key, "force")) {
49 1           force = SvTRUE(val) ? 1 : 0;
50 282 50         } else if (strEQ(key, "extra_cflags")) {
51 0 0         if (SvOK(val)) {
52 0           extra_cflags = SvPV_nolen(val);
53             }
54 282 50         } else if (strEQ(key, "extra_ldflags")) {
55 0 0         if (SvOK(val)) {
56 0           extra_ldflags = SvPV_nolen(val);
57             }
58 282 50         } else if (strEQ(key, "functions")) {
59 282 50         if (!SvROK(val) || SvTYPE(SvRV(val)) != SVt_PVHV) {
    100          
60 1           croak("XS::JIT->compile: 'functions' must be a hashref");
61             }
62 281           functions_hv = (HV*)SvRV(val);
63             }
64             }
65              
66             /* Validate required arguments */
67 282 100         if (!code) {
68 1           croak("XS::JIT->compile: 'code' is required");
69             }
70 281 100         if (!name) {
71 1           croak("XS::JIT->compile: 'name' is required");
72             }
73 280 100         if (!functions_hv) {
74 1           croak("XS::JIT->compile: 'functions' is required");
75             }
76              
77             /* Count and allocate functions array */
78 279 50         num_functions = HvKEYS(functions_hv);
79 279 100         if (num_functions == 0) {
80 1           croak("XS::JIT->compile: 'functions' must not be empty");
81             }
82              
83 278           Newx(functions, num_functions + 1, XS_JIT_Func);
84              
85             /* Fill functions array from hash
86             * Value can be:
87             * - A simple string: 'Package::func' => 'source_func'
88             * - A hashref: 'Package::func' => { source => 'source_func', is_xs_native => 1 }
89             */
90 278           i = 0;
91 278           hv_iterinit(functions_hv);
92 822 100         while ((entry = hv_iternext(functions_hv)) != NULL) {
93             I32 klen;
94 544           const char *target = hv_iterkey(entry, &klen);
95 544           SV *val = hv_iterval(functions_hv, entry);
96             const char *source;
97 544           int is_xs_native = 0;
98              
99 1015 100         if (SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVHV) {
    50          
100             /* Hashref with options */
101 471           HV *opts = (HV*)SvRV(val);
102 471           SV **source_sv = hv_fetch(opts, "source", 6, 0);
103 471           SV **native_sv = hv_fetch(opts, "is_xs_native", 12, 0);
104              
105 471 50         if (!source_sv || !SvOK(*source_sv)) {
    50          
106 0           croak("XS::JIT->compile: function '%s' missing 'source' key", target);
107             }
108 471           source = SvPV_nolen(*source_sv);
109 471 50         if (native_sv && SvTRUE(*native_sv)) {
    50          
110 471           is_xs_native = 1;
111             }
112             } else {
113             /* Simple string value */
114 73           source = SvPV_nolen(val);
115             }
116              
117             /* Duplicate strings since they might be temporary */
118 544           functions[i].target = savepv(target);
119 544           functions[i].source = savepv(source);
120 544           functions[i].has_varargs = 1; /* Default to varargs for safety */
121 544           functions[i].is_xs_native = is_xs_native;
122 544           i++;
123             }
124 278           functions[i].target = NULL;
125 278           functions[i].source = NULL;
126 278           functions[i].has_varargs = 0;
127 278           functions[i].is_xs_native = 0;
128              
129             /* Call the C compile function */
130 278           RETVAL = xs_jit_compile(aTHX_ code, name, functions, num_functions,
131             cache_dir, force, extra_cflags, extra_ldflags);
132              
133             /* Clean up */
134 822 100         for (i = 0; i < num_functions; i++) {
135 544           Safefree((char*)functions[i].target);
136 544           Safefree((char*)functions[i].source);
137             }
138 278           Safefree(functions);
139              
140             OUTPUT:
141             RETVAL
142              
143             int
144             is_cached(class, code, name, ...)
145             SV *class
146             const char *code
147             const char *name
148             PREINIT:
149 11 50         const char *cache_dir = NULL;
150             CODE:
151             PERL_UNUSED_VAR(class);
152 11 50         if (items > 3 && SvOK(ST(3))) {
    50          
153 11           cache_dir = SvPV_nolen(ST(3));
154             }
155 11           RETVAL = xs_jit_is_cached(aTHX_ code, name, cache_dir);
156             OUTPUT:
157             RETVAL
158              
159             SV *
160             generate_code(class, code, name, functions_hv)
161             SV *class
162             const char *code
163             const char *name
164             HV *functions_hv
165             PREINIT:
166 2           XS_JIT_Func *functions = NULL;
167 2           int num_functions = 0;
168             int i;
169             HE *entry;
170             char *generated;
171             CODE:
172             PERL_UNUSED_VAR(class);
173              
174 2 50         num_functions = HvKEYS(functions_hv);
175 2 100         if (num_functions == 0) {
176 1           croak("XS::JIT->generate_code: functions must not be empty");
177             }
178              
179 1           Newx(functions, num_functions + 1, XS_JIT_Func);
180              
181 1           i = 0;
182 1           hv_iterinit(functions_hv);
183 2 100         while ((entry = hv_iternext(functions_hv)) != NULL) {
184             I32 klen;
185 1           const char *target = hv_iterkey(entry, &klen);
186 1           SV *source_sv = hv_iterval(functions_hv, entry);
187 1           const char *source = SvPV_nolen(source_sv);
188              
189 1           functions[i].target = savepv(target);
190 1           functions[i].source = savepv(source);
191 1           functions[i].has_varargs = 1;
192 1           functions[i].is_xs_native = 0;
193 1           i++;
194             }
195 1           functions[i].target = NULL;
196 1           functions[i].source = NULL;
197 1           functions[i].has_varargs = 0;
198 1           functions[i].is_xs_native = 0;
199              
200 1           generated = xs_jit_generate_code(aTHX_ code, name, functions, num_functions);
201              
202 2 100         for (i = 0; i < num_functions; i++) {
203 1           Safefree((char*)functions[i].target);
204 1           Safefree((char*)functions[i].source);
205             }
206 1           Safefree(functions);
207              
208 1 50         if (generated) {
209 1           RETVAL = newSVpv(generated, 0);
210 1           free(generated);
211             } else {
212 0           RETVAL = &PL_sv_undef;
213             }
214             OUTPUT:
215             RETVAL
216