fix warnings
[m6w6/ext-psi] / src / libjit.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include "php.h"
6
7 #ifdef HAVE_LIBJIT
8
9 #include "php_psi.h"
10 #include "libjit.h"
11
12 #include <jit/jit.h>
13
14 static void psi_jit_handler(jit_type_t _sig, void *result, void **_args, void *_data);
15 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg);
16
17 static inline jit_abi_t psi_jit_abi(const char *convention) {
18 return jit_abi_cdecl;
19 }
20 static inline jit_type_t psi_jit_token_type(token_t t) {
21 switch (t) {
22 default:
23 ZEND_ASSERT(0);
24 /* no break */
25 case PSI_T_VOID:
26 return jit_type_void;
27 case PSI_T_INT8:
28 return jit_type_sbyte;
29 case PSI_T_UINT8:
30 return jit_type_ubyte;
31 case PSI_T_INT16:
32 return jit_type_short;
33 case PSI_T_UINT16:
34 return jit_type_ushort;
35 case PSI_T_INT32:
36 return jit_type_int;
37 case PSI_T_UINT32:
38 return jit_type_uint;
39 case PSI_T_INT64:
40 return jit_type_long;
41 case PSI_T_UINT64:
42 return jit_type_ulong;
43 case PSI_T_BOOL:
44 return jit_type_sys_bool;
45 case PSI_T_INT:
46 return jit_type_sys_int;
47 case PSI_T_LONG:
48 return jit_type_sys_long;
49 case PSI_T_FLOAT:
50 return jit_type_sys_float;
51 case PSI_T_DOUBLE:
52 return jit_type_sys_double;
53 #ifdef HAVE_LONG_DOUBLE
54 case PSI_T_LONG_DOUBLE:
55 return jit_type_sys_long_double;
56 #endif
57 case PSI_T_POINTER:
58 return jit_type_void_ptr;
59 }
60 }
61 static inline jit_type_t psi_jit_impl_type(token_t impl_type) {
62 switch (impl_type) {
63 case PSI_T_BOOL:
64 return jit_type_sbyte;
65 case PSI_T_INT:
66 return jit_type_long;
67 case PSI_T_STRING:
68 return jit_type_void_ptr;
69 case PSI_T_FLOAT:
70 case PSI_T_DOUBLE:
71 return jit_type_sys_double;
72 EMPTY_SWITCH_DEFAULT_CASE();
73 }
74 return NULL;
75 }
76
77 static void psi_jit_struct_type_dtor(void *type) {
78 jit_type_t strct = type;
79
80 jit_type_free(strct);
81 }
82
83 static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding) {
84 size_t i;
85
86 for (i = 0; i < padding; ++i) {
87 *els++ = jit_type_copy(jit_type_sys_char);
88 }
89
90 return padding;
91 }
92
93 static unsigned psi_jit_struct_type_elements(decl_struct *strct, jit_type_t **fields) {
94 size_t i, argc = strct->args->count, nels = 0, offset = 0, maxalign;
95 *fields = calloc(argc + 1, sizeof(*fields));
96
97 for (i = 0; i < strct->args->count; ++i) {
98 decl_arg *darg = strct->args->args[i];
99 jit_type_t type = jit_type_copy(psi_jit_decl_arg_type(darg));
100 size_t padding, alignment;
101
102 ZEND_ASSERT(jit_type_get_size(type) == darg->layout->len);
103
104 if ((alignment = jit_type_get_alignment(type)) > maxalign) {
105 maxalign = alignment;
106 }
107
108 if ((padding = psi_offset_padding(darg->layout->pos - offset, alignment))) {
109 if (nels + padding > argc) {
110 argc += padding;
111 *fields = realloc(*fields, (argc + 1) * sizeof(*fields));
112 }
113 psi_jit_struct_type_pad(&(*fields)[nels], padding);
114 nels += padding;
115 offset += padding;
116 }
117 ZEND_ASSERT(offset == darg->layout->pos);
118
119 offset = (offset + darg->layout->len + alignment - 1) & ~(alignment - 1);
120 (*fields)[nels++] = type;
121 }
122
123 /* apply struct alignment padding */
124 offset = (offset + maxalign - 1) & ~(maxalign - 1);
125
126 ZEND_ASSERT(offset <= strct->size);
127 if (offset < strct->size) {
128 nels += psi_jit_struct_type_pad(&(*fields)[nels], strct->size - offset);
129 }
130
131 return nels;
132 }
133 static inline jit_type_t psi_jit_decl_type(decl_type *type) {
134 decl_type *real = real_decl_type(type);
135
136 if (real->type == PSI_T_STRUCT) {
137 if (!real->strct->engine.type) {
138 unsigned count;
139 jit_type_t strct, *fields = NULL;
140
141 count = psi_jit_struct_type_elements(real->strct, &fields);
142 strct = jit_type_create_struct(fields, count, 0);
143
144 real->strct->engine.type = strct;
145 real->strct->engine.dtor = psi_jit_struct_type_dtor;
146 }
147
148 return real->strct->engine.type;
149 }
150 return psi_jit_token_type(real->type);
151 }
152 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) {
153 if (darg->var->pointer_level) {
154 return jit_type_void_ptr;
155 } else {
156 return psi_jit_decl_type(darg->type);
157 }
158 }
159
160 typedef struct PSI_LibjitContext {
161 jit_context_t jit;
162 jit_type_t signature;
163 struct {
164 struct PSI_LibjitData **list;
165 size_t count;
166 } data;
167 } PSI_LibjitContext;
168
169 typedef struct PSI_LibjitCall {
170 void *closure;
171 jit_type_t signature;
172 void *params[1]; /* [type1, type2, NULL, arg1, arg2] ... */
173 } PSI_LibjitCall;
174
175 typedef struct PSI_LibjitData {
176 PSI_LibjitContext *context;
177 impl *impl;
178 zend_internal_arg_info *arginfo;
179 } PSI_LibjitData;
180
181 static inline PSI_LibjitCall *PSI_LibjitCallAlloc(PSI_Context *C, decl *decl) {
182 size_t i, c = decl->args ? decl->args->count : 0;
183 PSI_LibjitCall *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
184
185 for (i = 0; i < c; ++i) {
186 call->params[i] = psi_jit_decl_arg_type(decl->args->args[i]);
187 }
188 call->params[c] = NULL;
189
190 decl->call.info = call;
191 decl->call.rval = &decl->func->ptr;
192 decl->call.argc = c;
193 decl->call.args = (void **) &call->params[c+1];
194
195 call->signature = jit_type_create_signature(
196 psi_jit_abi(decl->abi->convention),
197 psi_jit_decl_arg_type(decl->func),
198 (jit_type_t *) call->params, c, 1);
199 return call;
200 }
201
202 static inline void PSI_LibjitCallInitClosure(PSI_Context *C, PSI_LibjitCall *call, impl *impl) {
203 PSI_LibjitContext *context = C->context;
204 call->closure = jit_closure_create(context->jit, context->signature,
205 &psi_jit_handler, impl);
206 }
207
208 static inline void PSI_LibjitCallFree(PSI_LibjitCall *call) {
209 jit_type_free(call->signature);
210 free(call);
211 }
212
213 static inline PSI_LibjitContext *PSI_LibjitContextInit(PSI_LibjitContext *L) {
214 jit_type_t params[] = {
215 jit_type_void_ptr,
216 jit_type_void_ptr
217 };
218
219 if (!L) {
220 L = malloc(sizeof(*L));
221 }
222 memset(L, 0, sizeof(*L));
223
224 L->jit = jit_context_create();
225 L->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void,
226 params, 2, 1);
227
228 return L;
229 }
230
231 static inline void PSI_LibjitContextDtor(PSI_LibjitContext *L) {
232 jit_type_free(L->signature);
233 jit_context_destroy(L->jit);
234 }
235
236 static inline void PSI_LibjitContextFree(PSI_LibjitContext **L) {
237 if (*L) {
238 PSI_LibjitContextDtor(*L);
239 free(*L);
240 *L = NULL;
241 }
242 }
243
244 static void psi_jit_handler(jit_type_t _sig, void *result, void **_args, void *_data)
245 {
246 psi_call(*(zend_execute_data **)_args[0], *(zval **)_args[1], _data);
247 }
248
249 static void psi_jit_init(PSI_Context *C)
250 {
251 C->context = PSI_LibjitContextInit(NULL);
252 }
253
254 static void psi_jit_dtor(PSI_Context *C)
255 {
256 if (C->decls) {
257 size_t i;
258
259 for (i = 0; i < C->decls->count; ++i) {
260 decl *decl = C->decls->list[i];
261
262 PSI_LibjitCallFree(decl->call.info);
263 }
264 }
265 PSI_LibjitContextFree((void *) &C->context);
266 }
267
268 static zend_function_entry *psi_jit_compile(PSI_Context *C)
269 {
270 size_t i, j = 0;
271 zend_function_entry *zfe;
272 PSI_LibjitContext *ctx = C->context;
273
274 if (!C->impls) {
275 return NULL;
276 }
277
278 zfe = calloc(C->impls->count + 1, sizeof(*zfe));
279 jit_context_build_start(ctx->jit);
280
281 for (i = 0; i < C->impls->count; ++i) {
282 zend_function_entry *zf = &zfe[j];
283 PSI_LibjitCall *call;
284 impl *impl = C->impls->list[i];
285
286 if (!impl->decl) {
287 continue;
288 }
289
290 call = PSI_LibjitCallAlloc(C, impl->decl);
291 PSI_LibjitCallInitClosure(C, call, impl);
292
293 zf->fname = impl->func->name + (impl->func->name[0] == '\\');
294 zf->num_args = impl->func->args->count;
295 zf->handler = call->closure;
296 zf->arg_info = psi_internal_arginfo(impl);
297 ++j;
298 }
299
300 for (i = 0; i < C->decls->count; ++i) {
301 decl *decl = C->decls->list[i];
302
303 if (decl->impl) {
304 continue;
305 }
306
307 PSI_LibjitCallAlloc(C, decl);
308 }
309
310 jit_context_build_end(ctx->jit);
311
312 return zfe;
313 }
314
315 static void psi_jit_call(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va) {
316 PSI_LibjitCall *call = decl_call->info;
317
318 if (va) {
319 jit_type_t signature;
320 size_t i, nfixedargs = decl_call->argc, ntotalargs = nfixedargs + va->args->count;
321 void **params = calloc(2 * ntotalargs + 2, sizeof(void *));
322
323 for (i = 0; i < nfixedargs; ++i) {
324 params[i] = call->params[i];
325 params[i + ntotalargs + 1] = call->params[i + nfixedargs + 1];
326 }
327 for (i = 0; i < va->args->count; ++i) {
328 params[nfixedargs + i] = psi_jit_impl_type(va->types[i]);
329 params[nfixedargs + i + ntotalargs + 1] = &va->values[i];
330 }
331
332 signature = jit_type_create_signature(
333 jit_type_get_abi(call->signature),
334 jit_type_get_return(call->signature),
335 (jit_type_t *) params, ntotalargs, 1);
336 ZEND_ASSERT(signature);
337
338 jit_apply(signature, decl_call->sym, &params[ntotalargs + 1],
339 nfixedargs, *decl_call->rval);
340 jit_type_free(signature);
341 free(params);
342 } else {
343 jit_apply(call->signature, decl_call->sym, decl_call->args,
344 decl_call->argc, *decl_call->rval);
345 }
346 }
347
348 static PSI_ContextOps ops = {
349 psi_jit_init,
350 psi_jit_dtor,
351 psi_jit_compile,
352 psi_jit_call,
353 };
354
355 PSI_ContextOps *PSI_Libjit(void)
356 {
357 return &ops;
358 }
359
360 #endif /* HAVE_LIBJIT */