fix cppcheck warnings
[m6w6/ext-psi] / src / libjit.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27 #include "context.h"
28 #include "call.h"
29 #include "php.h"
30
31 #ifdef HAVE_LIBJIT
32
33 #include <jit/jit.h>
34
35 static inline jit_type_t psi_jit_decl_arg_type(struct psi_decl_arg *darg);
36
37 static inline jit_abi_t psi_jit_abi(const char *convention)
38 {
39 return jit_abi_cdecl;
40 }
41 static inline jit_type_t psi_jit_token_type(token_t t)
42 {
43 switch (t) {
44 default:
45 assert(0);
46 /* no break */
47 case PSI_T_VOID:
48 return jit_type_void;
49 case PSI_T_INT8:
50 return jit_type_sbyte;
51 case PSI_T_UINT8:
52 return jit_type_ubyte;
53 case PSI_T_INT16:
54 return jit_type_short;
55 case PSI_T_UINT16:
56 return jit_type_ushort;
57 case PSI_T_INT32:
58 return jit_type_int;
59 case PSI_T_UINT32:
60 return jit_type_uint;
61 case PSI_T_INT64:
62 return jit_type_long;
63 case PSI_T_UINT64:
64 return jit_type_ulong;
65 case PSI_T_BOOL:
66 return jit_type_sys_bool;
67 case PSI_T_INT:
68 case PSI_T_ENUM:
69 return jit_type_sys_int;
70 case PSI_T_LONG:
71 return jit_type_sys_long;
72 case PSI_T_FLOAT:
73 return jit_type_sys_float;
74 case PSI_T_DOUBLE:
75 return jit_type_sys_double;
76 #ifdef HAVE_LONG_DOUBLE
77 case PSI_T_LONG_DOUBLE:
78 return jit_type_sys_long_double;
79 #endif
80 case PSI_T_POINTER:
81 case PSI_T_FUNCTION:
82 return jit_type_void_ptr;
83 }
84 }
85 static inline jit_type_t psi_jit_impl_type(token_t impl_type)
86 {
87 switch (impl_type) {
88 case PSI_T_BOOL:
89 return jit_type_sbyte;
90 case PSI_T_INT:
91 return jit_type_long;
92 case PSI_T_STRING:
93 return jit_type_void_ptr;
94 case PSI_T_FLOAT:
95 case PSI_T_DOUBLE:
96 return jit_type_sys_double;
97 EMPTY_SWITCH_DEFAULT_CASE()
98 ;
99 }
100 return NULL;
101 }
102
103 static void psi_jit_struct_type_dtor(void *type)
104 {
105 jit_type_t strct = type;
106
107 jit_type_free(strct);
108 }
109
110 static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding)
111 {
112 size_t i;
113
114 for (i = 0; i < padding; ++i) {
115 *els++ = jit_type_copy(jit_type_sys_char);
116 }
117
118 return padding;
119 }
120
121 static unsigned psi_jit_struct_type_elements(struct psi_decl_struct *strct,
122 jit_type_t **fields)
123 {
124 size_t i = 0, argc = psi_plist_count(strct->args), nels = 0, offset = 0,
125 maxalign;
126 struct psi_decl_arg *darg;
127
128 *fields = calloc(argc + 1, sizeof(*fields));
129
130 while (psi_plist_get(strct->args, i++, &darg)) {
131 jit_type_t type = jit_type_copy(psi_jit_decl_arg_type(darg));
132 size_t padding, alignment;
133
134 if ((alignment = jit_type_get_alignment(type)) > maxalign) {
135 maxalign = alignment;
136 }
137
138 assert(jit_type_get_size(type) == darg->layout->len);
139 if ((padding = psi_offset_padding(darg->layout->pos - offset, alignment))) {
140 if (nels + padding > argc) {
141 argc += padding;
142 *fields = realloc(*fields, (argc + 1) * sizeof(*fields));
143 }
144 psi_jit_struct_type_pad(&(*fields)[nels], padding);
145 nels += padding;
146 offset += padding;
147 }
148 assert(offset == darg->layout->pos);
149
150 offset = (offset + darg->layout->len + alignment - 1)
151 & ~(alignment - 1);
152 (*fields)[nels++] = type;
153 }
154
155 /* apply struct alignment padding */
156 offset = (offset + maxalign - 1) & ~(maxalign - 1);
157
158 assert(offset <= strct->size);
159 if (offset < strct->size) {
160 nels += psi_jit_struct_type_pad(&(*fields)[nels], strct->size - offset);
161 }
162
163 return nels;
164 }
165 static inline jit_type_t psi_jit_decl_type(struct psi_decl_type *type)
166 {
167 struct psi_decl_type *real = psi_decl_type_get_real(type);
168
169 switch (real->type) {
170 case PSI_T_STRUCT:
171 if (!real->real.strct->engine.type) {
172 unsigned count;
173 jit_type_t strct, *fields = NULL;
174
175 count = psi_jit_struct_type_elements(real->real.strct, &fields);
176 strct = jit_type_create_struct(fields, count, 0);
177
178 real->real.strct->engine.type = strct;
179 real->real.strct->engine.dtor = psi_jit_struct_type_dtor;
180 }
181
182 return real->real.strct->engine.type;
183
184 case PSI_T_UNION:
185 {
186 struct psi_decl_arg *arg;
187 psi_plist_get(real->real.unn->args, 0, &arg);
188 return psi_jit_decl_arg_type(arg);
189 }
190
191 default:
192 return psi_jit_token_type(real->type);
193 }
194 }
195 static inline jit_type_t psi_jit_decl_arg_type(struct psi_decl_arg *darg)
196 {
197 if (darg->var->pointer_level) {
198 return jit_type_void_ptr;
199 } else {
200 return psi_jit_decl_type(darg->type);
201 }
202 }
203
204 struct psi_jit_context {
205 jit_context_t jit;
206 jit_type_t signature;
207 };
208
209 struct psi_jit_call {
210 struct psi_context *context;
211 union {
212 struct {
213 struct psi_impl *impl;
214 struct psi_call_frame *frame;
215 } fn;
216 struct {
217 struct psi_let_exp *let_exp;
218 struct psi_jit_call *impl_call;
219 } cb;
220 } impl;
221 void *closure;
222 jit_type_t signature;
223 void *params[1]; /* [type1, type2, ... ] */
224 };
225
226 static void psi_jit_handler(jit_type_t sig, void *result, void **args, void *data)
227 {
228 struct psi_jit_call *call = data;
229
230 psi_context_call(call->context, *(zend_execute_data **)args[0], *(zval **) args[1], call->impl.fn.impl);
231 }
232
233 static void psi_jit_callback(jit_type_t sig, void *result, void **args,
234 void *data)
235 {
236 struct psi_jit_call *call = data, *impl_call = call->impl.cb.impl_call;
237 struct psi_call_frame_callback cbdata;
238
239 cbdata.cb = call->impl.cb.let_exp;
240 cbdata.argc = jit_type_num_params(sig);
241 cbdata.argv = args;
242 cbdata.rval = result;
243
244 psi_call_frame_do_callback(impl_call->impl.fn.frame, &cbdata);
245 }
246
247 static inline struct psi_jit_call *psi_jit_call_alloc(struct psi_context *C,
248 struct psi_decl *decl)
249 {
250 size_t i, c = psi_plist_count(decl->args);
251 struct psi_jit_call *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
252 struct psi_decl_arg *arg;
253
254 decl->info = call;
255 call->context = C;
256 for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
257 call->params[i] = psi_jit_decl_arg_type(arg);
258 }
259 call->params[c] = NULL;
260
261 call->signature = jit_type_create_signature(
262 psi_jit_abi(decl->abi->convention),
263 psi_jit_decl_arg_type(decl->func),
264 (jit_type_t *) call->params,
265 c, 1);
266 assert(call->signature);
267
268 return call;
269 }
270
271 static inline void *psi_jit_call_init_closure(struct psi_context *C,
272 struct psi_jit_call *call, struct psi_impl *impl)
273 {
274 struct psi_jit_context *context = C->context;
275
276 call->impl.fn.impl = impl;
277 return call->closure = jit_closure_create(context->jit, context->signature,
278 &psi_jit_handler, call);
279 }
280
281 static inline void *psi_jit_call_init_callback_closure(struct psi_context *C,
282 struct psi_jit_call *call, struct psi_jit_call *impl_call,
283 struct psi_let_exp *cb)
284 {
285 struct psi_jit_context *context = C->context;
286
287 call->impl.cb.let_exp = cb;
288 call->impl.cb.impl_call = impl_call;
289
290 return call->closure = jit_closure_create(context->jit, call->signature,
291 &psi_jit_callback, call);
292 }
293
294 static inline void psi_jit_call_free(struct psi_jit_call *call)
295 {
296 jit_type_free(call->signature);
297 free(call);
298 }
299
300 static inline struct psi_jit_context *psi_jit_context_init(
301 struct psi_jit_context *L)
302 {
303 jit_type_t params[] = {jit_type_void_ptr, jit_type_void_ptr};
304
305 if (!L) {
306 L = malloc(sizeof(*L));
307 }
308 memset(L, 0, sizeof(*L));
309
310 L->jit = jit_context_create();
311 L->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void,
312 params, 2, 1);
313
314 return L;
315 }
316
317 static inline void psi_jit_context_dtor(struct psi_jit_context *L)
318 {
319 jit_type_free(L->signature);
320 jit_context_destroy(L->jit);
321 }
322
323 static inline void psi_jit_context_free(struct psi_jit_context **L)
324 {
325 if (*L) {
326 psi_jit_context_dtor(*L);
327 free(*L);
328 *L = NULL;
329 }
330 }
331
332 static void psi_jit_init(struct psi_context *C)
333 {
334 C->context = psi_jit_context_init(NULL);
335 }
336
337 static inline void psi_jit_destroy_callbacks(struct psi_context *C,
338 struct psi_let_exp *let_exp)
339 {
340 struct psi_let_callback *cb;
341 struct psi_let_func *fn = NULL;
342
343 switch (let_exp->kind) {
344 case PSI_LET_CALLBACK:
345 cb = let_exp->data.callback;
346
347 if (cb->decl && cb->decl->info) {
348 psi_jit_call_free(cb->decl->info);
349 }
350 fn = cb->func;
351 /* no break */
352 case PSI_LET_FUNC:
353 if (!fn) {
354 fn = let_exp->data.func;
355 }
356
357 if (fn->inner) {
358 size_t i = 0;
359 struct psi_let_exp *inner_let;
360
361 while (psi_plist_get(fn->inner, i++, &inner_let)) {
362 psi_jit_destroy_callbacks(C, inner_let);
363 }
364 }
365 break;
366 default:
367 break;
368 }
369 }
370
371 static void psi_jit_dtor(struct psi_context *C)
372 {
373 if (C->decls) {
374 size_t i = 0;
375 struct psi_decl *decl;
376
377 while (psi_plist_get(C->decls, i++, &decl)) {
378 if (decl->info) {
379 psi_jit_call_free(decl->info);
380 }
381 }
382 }
383 if (C->impls) {
384 size_t i = 0;
385 struct psi_impl *impl;
386
387 while (psi_plist_get(C->impls, i++, &impl)) {
388 size_t l = 0;
389 struct psi_let_stmt *let;
390
391 while (psi_plist_get(impl->stmts.let, l++, &let)) {
392 psi_jit_destroy_callbacks(C, let->exp);
393 }
394 }
395 }
396 psi_jit_context_free((void *) &C->context);
397 }
398
399 static inline void psi_jit_compile_callbacks(struct psi_context *C,
400 struct psi_jit_call *impl_call, struct psi_let_exp *let_exp)
401 {
402 struct psi_jit_call *call;
403 struct psi_let_callback *cb;
404 struct psi_let_func *fn = NULL;
405
406 switch (let_exp->kind) {
407 case PSI_LET_CALLBACK:
408 cb = let_exp->data.callback;
409 if ((call = psi_jit_call_alloc(C, cb->decl))) {
410 if (!psi_jit_call_init_callback_closure(C, call, impl_call, let_exp)) {
411 psi_jit_call_free(call);
412 break;
413 }
414
415 cb->decl->sym = call->closure;
416 }
417 fn = cb->func;
418 /* no break */
419 case PSI_LET_FUNC:
420 if (!fn) {
421 fn = let_exp->data.func;
422 }
423 if (fn->inner) {
424 size_t i = 0;
425 struct psi_let_exp *inner_let;
426
427 while (psi_plist_get(fn->inner, i++, &inner_let)) {
428 psi_jit_compile_callbacks(C, impl_call, inner_let);
429 }
430 }
431 break;
432 default:
433 break;
434 }
435 }
436
437 static zend_function_entry *psi_jit_compile(struct psi_context *C)
438 {
439 size_t i = 0, d = 0, nf = 0;
440 struct psi_impl *impl;
441 struct psi_decl *decl;
442 zend_function_entry *zfe;
443 struct psi_jit_context *ctx = C->context;
444
445 if (!C->impls) {
446 return NULL;
447 }
448
449 zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
450 jit_context_build_start(ctx->jit);
451
452 while (psi_plist_get(C->impls, i++, &impl)) {
453 zend_function_entry *zf = &zfe[nf];
454 struct psi_jit_call *call;
455 size_t l = 0;
456 struct psi_let_stmt *let;
457
458 if (!impl->decl) {
459 continue;
460 }
461 if (!(call = psi_jit_call_alloc(C, impl->decl))) {
462 continue;
463 }
464 if (!psi_jit_call_init_closure(C, call, impl)) {
465 psi_jit_call_free(call);
466 continue;
467 }
468
469 zf->fname = impl->func->name + (impl->func->name[0] == '\\');
470 zf->handler = call->closure;
471 zf->num_args = psi_plist_count(impl->func->args);
472 zf->arg_info = psi_internal_arginfo(impl);
473 ++nf;
474
475 while (psi_plist_get(impl->stmts.let, l++, &let)) {
476 psi_jit_compile_callbacks(C, call, let->exp);
477 }
478 }
479
480 while (psi_plist_get(C->decls, d++, &decl)) {
481 if (decl->info) {
482 continue;
483 }
484
485 psi_jit_call_alloc(C, decl);
486 }
487
488 jit_context_build_end(ctx->jit);
489
490 return zfe;
491 }
492
493 static void psi_jit_call(struct psi_context *C, struct psi_call_frame *frame,
494 struct psi_decl *decl, void *rval, void **args)
495 {
496 struct psi_jit_call *call = decl->info;
497 struct psi_call_frame *prev = call->impl.fn.frame;
498
499 call->impl.fn.frame = frame;
500 jit_apply(call->signature, decl->sym, args, psi_plist_count(decl->args), rval);
501 call->impl.fn.frame = prev;
502 }
503
504 static void psi_jit_call_va(struct psi_context *C, struct psi_call_frame *frame,
505 struct psi_decl *decl, void *rval, void **args, size_t va_count,
506 void **va_types)
507 {
508 struct psi_jit_call *info = decl->info;
509 struct psi_call_frame *prev = info->impl.fn.frame;
510 size_t argc = psi_plist_count(decl->args);
511 jit_type_t signature;
512 jit_type_t *param_types = ecalloc(argc + va_count + 1, sizeof(jit_type_t));
513
514 memcpy(param_types, info->params, argc * sizeof(jit_type_t));
515 memcpy(param_types + argc, va_types, va_count * sizeof(jit_type_t));
516
517 signature = jit_type_create_signature(jit_abi_vararg,
518 jit_type_get_return(info->signature), param_types, argc + va_count,
519 1);
520 assert(signature);
521
522 info->impl.fn.frame = frame;
523 jit_apply(signature, decl->sym, args, argc, rval);
524 info->impl.fn.frame = prev;
525 jit_type_free(signature);
526 efree(param_types);
527 }
528
529 static void *psi_jit_query(struct psi_context *C, enum psi_context_query q,
530 void *arg)
531 {
532 switch (q) {
533 case PSI_CONTEXT_QUERY_SELF:
534 return "jit";
535 case PSI_CONTEXT_QUERY_TYPE:
536 return psi_jit_impl_type(*(token_t *) arg);
537 }
538 return NULL;
539 }
540
541 static struct psi_context_ops ops = {psi_jit_init, psi_jit_dtor,
542 psi_jit_compile, psi_jit_call, psi_jit_call_va, psi_jit_query};
543
544 struct psi_context_ops *psi_libjit_ops(void)
545 {
546 return &ops;
547 }
548
549 #endif /* HAVE_LIBJIT */