| 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
|
|
|
|
|
|
|
|