cpp: search local dir only for quoted headers
[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 #if HAVE_INT128
36 static jit_type_t jit_type_llong;
37 static jit_type_t jit_type_ullong;
38 #endif
39
40 static inline jit_type_t psi_jit_decl_arg_type(struct psi_decl_arg *darg);
41
42 static inline jit_type_t psi_jit_token_type(token_t t)
43 {
44 switch (t) {
45 default:
46 assert(0);
47 /* no break */
48 case PSI_T_VOID:
49 return jit_type_void;
50 case PSI_T_INT8:
51 return jit_type_sbyte;
52 case PSI_T_UINT8:
53 return jit_type_ubyte;
54 case PSI_T_INT16:
55 return jit_type_short;
56 case PSI_T_UINT16:
57 return jit_type_ushort;
58 case PSI_T_INT32:
59 return jit_type_int;
60 case PSI_T_UINT32:
61 return jit_type_uint;
62 case PSI_T_INT64:
63 return jit_type_long;
64 case PSI_T_UINT64:
65 return jit_type_ulong;
66 #if HAVE_INT128
67 case PSI_T_INT128:
68 return jit_type_llong;
69 case PSI_T_UINT128:
70 return jit_type_ullong;
71 #endif
72 case PSI_T_BOOL:
73 return jit_type_sys_bool;
74 case PSI_T_ENUM:
75 return jit_type_sys_int;
76 case PSI_T_FLOAT:
77 return jit_type_sys_float;
78 case PSI_T_DOUBLE:
79 return jit_type_sys_double;
80 #ifdef HAVE_LONG_DOUBLE
81 case PSI_T_LONG_DOUBLE:
82 return jit_type_sys_long_double;
83 #endif
84 case PSI_T_POINTER:
85 case PSI_T_FUNCTION:
86 return jit_type_void_ptr;
87 }
88 }
89 static inline jit_type_t psi_jit_impl_type(token_t impl_type)
90 {
91 switch (impl_type) {
92 case PSI_T_BOOL:
93 return jit_type_sbyte;
94 case PSI_T_INT:
95 return jit_type_long;
96 case PSI_T_STRING:
97 return jit_type_void_ptr;
98 case PSI_T_FLOAT:
99 case PSI_T_DOUBLE:
100 return jit_type_sys_double;
101 EMPTY_SWITCH_DEFAULT_CASE()
102 ;
103 }
104 return NULL;
105 }
106
107 struct psi_jit_struct_type {
108 jit_type_t strct;
109 jit_type_t *fields;
110 };
111
112 static void psi_jit_struct_type_dtor(void *ptr)
113 {
114 struct psi_jit_struct_type *type = ptr;
115 unsigned i, n = jit_type_num_fields(type->strct);
116
117 for (i = 0; i < n; ++i) {
118 jit_type_free(jit_type_get_field(type->strct, i));
119 }
120 jit_type_free(type->strct);
121 free(type->fields);
122 free(type);
123 }
124
125 static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding)
126 {
127 size_t i;
128
129 for (i = 0; i < padding; ++i) {
130 *els++ = jit_type_copy(jit_type_sys_char);
131 }
132
133 return padding;
134 }
135
136 static unsigned psi_jit_struct_type_elements(struct psi_decl_struct *strct,
137 jit_type_t **fields)
138 {
139 size_t i = 0, argc = psi_plist_count(strct->args), nels = 0, offset = 0,
140 maxalign = 0, last_arg_pos = -1;
141 struct psi_decl_arg *darg;
142 jit_type_t *tmp;
143
144 *fields = calloc(argc + 1, sizeof(*fields));
145
146 while (psi_plist_get(strct->args, i++, &darg)) {
147 jit_type_t type;
148 size_t padding, alignment;
149
150 if (darg->layout->pos == last_arg_pos) {
151 /* skip bit fields */
152 continue;
153 }
154 last_arg_pos = darg->layout->pos;
155
156 type = jit_type_copy(psi_jit_decl_arg_type(darg));
157
158 if ((alignment = jit_type_get_alignment(type)) > maxalign) {
159 maxalign = alignment;
160 }
161
162 assert(jit_type_get_size(type) <= darg->layout->len);
163 if ((padding = psi_offset_padding(darg->layout->pos - offset, alignment))) {
164 if (nels + padding > argc) {
165 argc += padding;
166 tmp = realloc(*fields, (argc + 1) * sizeof(*fields));
167 if (tmp) {
168 *fields = tmp;
169 } else {
170 free(*fields);
171 return 0;
172 }
173 }
174 psi_jit_struct_type_pad(&(*fields)[nels], padding);
175 nels += padding;
176 offset += padding;
177 }
178 assert(offset == darg->layout->pos);
179
180 offset = (offset + darg->layout->len + alignment - 1)
181 & ~(alignment - 1);
182 (*fields)[nels++] = type;
183 }
184
185 /* apply struct alignment padding */
186 offset = (offset + maxalign - 1) & ~(maxalign - 1);
187
188 assert(offset <= strct->size);
189 if (offset < strct->size) {
190 nels += psi_jit_struct_type_pad(&(*fields)[nels], strct->size - offset);
191 }
192
193 return nels;
194 }
195 static inline jit_type_t psi_jit_decl_type(struct psi_decl_type *type)
196 {
197 struct psi_decl_type *real = psi_decl_type_get_real(type);
198
199 switch (real->type) {
200 case PSI_T_STRUCT:
201 if (!real->real.strct->engine.type) {
202 unsigned count;
203 struct psi_jit_struct_type *type = calloc(1, sizeof(*type));
204
205 count = psi_jit_struct_type_elements(real->real.strct, &type->fields);
206 type->strct = jit_type_create_struct(type->fields, count, 0);
207
208 real->real.strct->engine.type = type;
209 real->real.strct->engine.dtor = psi_jit_struct_type_dtor;
210 }
211
212 return ((struct psi_jit_struct_type *) real->real.strct->engine.type)->strct;
213
214 case PSI_T_UNION:
215 {
216 struct psi_decl_arg *arg;
217 psi_plist_get(real->real.unn->args, 0, &arg);
218 return psi_jit_decl_arg_type(arg);
219 }
220
221 default:
222 return psi_jit_token_type(real->type);
223 }
224 }
225 static inline jit_type_t psi_jit_decl_arg_type(struct psi_decl_arg *darg)
226 {
227 if (darg->var->pointer_level) {
228 return jit_type_void_ptr;
229 } else {
230 return psi_jit_decl_type(darg->type);
231 }
232 }
233
234 static inline jit_abi_t psi_jit_abi(const char *convention)
235 {
236 if (!strcasecmp(convention, "stdcall")) {
237 return jit_abi_stdcall;
238 }
239 if (!strcasecmp(convention, "fastcall")) {
240 return jit_abi_fastcall;
241 }
242 return jit_abi_cdecl;
243 }
244
245 struct psi_jit_context {
246 jit_context_t jit;
247 jit_type_t signature;
248 };
249
250 struct psi_jit_impl_info {
251 struct psi_context *context;
252 struct psi_call_frame *frame;
253
254 void *closure;
255 };
256
257 struct psi_jit_callback_info {
258 struct psi_jit_impl_info *impl_info;
259 struct psi_let_exp *let_exp;
260
261 void *closure;
262 };
263
264 struct psi_jit_decl_info {
265 jit_type_t signature;
266 void *params[1];
267 };
268
269 static inline struct psi_jit_decl_info *psi_jit_decl_init(struct psi_decl *decl) {
270 if (!decl->info) {
271 size_t i, c = psi_plist_count(decl->args);
272 struct psi_decl_arg *arg;
273 struct psi_jit_decl_info *info = calloc(1, sizeof(*info) + 2 * c * sizeof(void *));
274
275 for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
276 info->params[i] = psi_jit_decl_arg_type(arg);
277 }
278 info->params[c] = NULL;
279
280 info->signature = jit_type_create_signature(
281 psi_jit_abi(decl->abi->convention),
282 psi_jit_decl_arg_type(decl->func),
283 (jit_type_t *) info->params,
284 c, 1);
285
286 if (!info->signature) {
287 free(info);
288 } else {
289 decl->info = info;
290 }
291 }
292
293 return decl->info;
294 }
295
296 static inline void psi_jit_decl_dtor(struct psi_decl *decl) {
297 if (decl->info) {
298 struct psi_jit_decl_info *info = decl->info;
299
300 jit_type_free(info->signature);
301 free(info);
302 decl->info = NULL;
303 }
304 }
305
306 static void psi_jit_handler(jit_type_t sig, void *result, void **args, void *data)
307 {
308 struct psi_impl *impl = data;
309 struct psi_jit_impl_info *info = impl->info;
310
311 psi_context_call(info->context, *(zend_execute_data **)args[0], *(zval **) args[1], impl);
312 }
313
314 static void psi_jit_callback(jit_type_t sig, void *result, void **args, void *data)
315 {
316 struct psi_jit_callback_info *cb_info = data;
317 struct psi_call_frame_callback cb_data;
318
319 assert(cb_info->impl_info->frame);
320
321 cb_data.cb = cb_info->let_exp;
322 cb_data.argc = jit_type_num_params(sig);
323 cb_data.argv = args;
324 cb_data.rval = result;
325
326 psi_call_frame_do_callback(cb_info->impl_info->frame, &cb_data);
327 }
328
329 static inline void psi_jit_callback_init(struct psi_jit_impl_info *impl_info,
330 struct psi_let_exp *let_exp)
331 {
332 struct psi_jit_context *context = impl_info->context->context;
333 struct psi_jit_callback_info *cb_info;
334 struct psi_jit_decl_info *decl_info;
335 struct psi_let_callback *cb;
336 struct psi_let_func *fn = NULL;
337
338 switch (let_exp->kind) {
339 case PSI_LET_CALLBACK:
340 cb = let_exp->data.callback;
341 if (cb->decl->info) {
342 decl_info = cb->decl->info;
343 } else {
344 decl_info = psi_jit_decl_init(cb->decl);
345 }
346
347 cb_info = calloc(1, sizeof(*cb_info));
348 cb_info->impl_info = impl_info;
349 cb_info->let_exp = let_exp;
350 cb_info->closure = jit_closure_create(context->jit, decl_info->signature,
351 &psi_jit_callback, cb_info);
352
353 if (!cb_info->closure) {
354 free(cb_info);
355 break;
356 }
357 cb->info = cb_info;
358
359 assert(!cb->decl->sym);
360 cb->decl->sym = cb_info->closure;
361 fn = cb->func;
362 /* no break */
363
364 case PSI_LET_FUNC:
365 if (!fn) {
366 fn = let_exp->data.func;
367 }
368 if (fn->inner) {
369 size_t i = 0;
370 struct psi_let_exp *inner_let;
371
372 while (psi_plist_get(fn->inner, i++, &inner_let)) {
373 psi_jit_callback_init(impl_info, inner_let);
374 }
375 }
376 break;
377 default:
378 break;
379 }
380 }
381
382 static inline void psi_jit_callback_dtor(struct psi_let_exp *let_exp) {
383 struct psi_let_callback *cb;
384 struct psi_let_func *fn = NULL;
385
386 switch (let_exp->kind) {
387 case PSI_LET_CALLBACK:
388 cb = let_exp->data.callback;
389
390 psi_jit_decl_dtor(cb->decl);
391
392 if (cb->info) {
393 struct psi_jit_callback_info *info = cb->info;
394
395 if (info->closure) {
396 /* The memory for the closure will be reclaimed when the context is destroyed.
397 free(info->closure); */
398 }
399 free(info);
400 cb->info = NULL;
401 }
402 fn = cb->func;
403 /* no break */
404 case PSI_LET_FUNC:
405 if (!fn) {
406 fn = let_exp->data.func;
407 }
408
409 if (fn->inner) {
410 size_t i = 0;
411 struct psi_let_exp *cb;
412
413 while (psi_plist_get(fn->inner, i++, &cb)) {
414 psi_jit_callback_dtor(cb);
415 }
416 }
417 break;
418 default:
419 break;
420 }
421 }
422
423 static inline struct psi_jit_impl_info *psi_jit_impl_init(struct psi_impl * impl,
424 struct psi_context *C)
425 {
426 struct psi_jit_context *context = C->context;
427 struct psi_jit_impl_info *info = calloc(1, sizeof(*info));
428 struct psi_let_stmt *let;
429 size_t l = 0;
430
431 info->context = C;
432 info->closure = jit_closure_create(context->jit, context->signature,
433 &psi_jit_handler, impl);
434
435 if (!info->closure) {
436 free(info);
437 return NULL;
438 }
439
440 while (psi_plist_get(impl->stmts.let, l++, &let)) {
441 psi_jit_callback_init(info, let->exp);
442 }
443
444 return impl->info = info;
445 }
446
447
448 static inline void psi_jit_impl_dtor(struct psi_impl *impl) {
449 struct psi_jit_impl_info *info = impl->info;
450 struct psi_let_stmt *let;
451 size_t j = 0;
452
453 while (psi_plist_get(impl->stmts.let, j++, &let)) {
454 psi_jit_callback_dtor(let->exp);
455 }
456
457 if (info) {
458 if (info->closure) {
459 /* The memory for the closure will be reclaimed when the context is destroyed.
460 free(info->closure); */
461 }
462 free(info);
463 impl->info = NULL;
464 }
465 }
466
467 static inline struct psi_jit_context *psi_jit_context_init(
468 struct psi_jit_context *L)
469 {
470 jit_type_t params[] = {jit_type_void_ptr, jit_type_void_ptr};
471
472 if (!L) {
473 L = malloc(sizeof(*L));
474 }
475 memset(L, 0, sizeof(*L));
476
477 L->jit = jit_context_create();
478 L->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void,
479 params, 2, 1);
480
481 return L;
482 }
483
484 static inline void psi_jit_context_dtor(struct psi_jit_context *L)
485 {
486 jit_type_free(L->signature);
487 jit_context_destroy(L->jit);
488 }
489
490 static inline void psi_jit_context_free(struct psi_jit_context **L)
491 {
492 if (*L) {
493 psi_jit_context_dtor(*L);
494 free(*L);
495 *L = NULL;
496 }
497 }
498
499 static void psi_jit_init(struct psi_context *C)
500 {
501 C->context = psi_jit_context_init(NULL);
502 }
503
504 static void psi_jit_dtor(struct psi_context *C)
505 {
506 if (C->decls) {
507 size_t i = 0;
508 struct psi_decl *decl;
509
510 while (psi_plist_get(C->decls, i++, &decl)) {
511 psi_jit_decl_dtor(decl);
512 }
513 }
514 if (C->impls) {
515 size_t i = 0;
516 struct psi_impl *impl;
517
518 while (psi_plist_get(C->impls, i++, &impl)) {
519 psi_jit_impl_dtor(impl);
520 }
521 }
522 psi_jit_context_free((void *) &C->context);
523 }
524
525 static zend_function_entry *psi_jit_compile(struct psi_context *C)
526 {
527 size_t i = 0, d = 0, nf = 0;
528 struct psi_impl *impl;
529 struct psi_decl *decl;
530 zend_function_entry *zfe;
531 struct psi_jit_context *ctx = C->context;
532
533 if (!C->impls) {
534 return NULL;
535 }
536
537 zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
538 jit_context_build_start(ctx->jit);
539
540 while (psi_plist_get(C->impls, i++, &impl)) {
541 zend_function_entry *zf = &zfe[nf];
542
543 if (!impl->decl) {
544 continue;
545 }
546 if (!psi_jit_decl_init(impl->decl)) {
547 continue;
548 }
549 if (!psi_jit_impl_init(impl, C)) {
550 continue;
551 }
552
553 zf->fname = impl->func->name + (impl->func->name[0] == '\\');
554 zf->handler = ((struct psi_jit_impl_info *) impl->info)->closure;
555 zf->num_args = psi_plist_count(impl->func->args);
556 zf->arg_info = psi_internal_arginfo(impl);
557 ++nf;
558 }
559
560 while (psi_plist_get(C->decls, d++, &decl)) {
561 if (decl->info) {
562 continue;
563 }
564
565 psi_jit_decl_init(decl);
566 }
567
568 jit_context_build_end(ctx->jit);
569
570 return zfe;
571 }
572
573 static inline void psi_jit_call_ex(struct psi_call_frame *frame) {
574 struct psi_decl *decl = psi_call_frame_get_decl(frame);
575 struct psi_impl *impl = psi_call_frame_get_impl(frame);
576 struct psi_jit_decl_info *decl_info = decl->info;
577 struct psi_jit_impl_info *impl_info;
578 struct psi_call_frame *prev;
579
580 if (impl) {
581 impl_info = impl->info;
582 prev = impl_info->frame;
583 impl_info->frame = frame;
584 }
585 jit_apply(decl_info->signature, decl->sym,
586 psi_call_frame_get_arg_pointers(frame), psi_plist_count(decl->args),
587 psi_call_frame_get_rpointer(frame));
588 if (impl) {
589 impl_info->frame = prev;
590 }
591 }
592
593 static inline void psi_jit_call_va(struct psi_call_frame *frame) {
594 jit_type_t signature;
595 struct psi_call_frame *prev;
596 struct psi_decl *decl = psi_call_frame_get_decl(frame);
597 struct psi_impl *impl = psi_call_frame_get_impl(frame);
598 struct psi_jit_decl_info *decl_info = decl->info;
599 struct psi_jit_impl_info *impl_info;
600 size_t i, va_count, argc;
601 jit_type_t *param_types;
602
603 argc = psi_plist_count(decl->args);
604 va_count = psi_call_frame_num_var_args(frame);
605 param_types = ecalloc(argc + va_count + 1, sizeof(jit_type_t));
606 memcpy(param_types, decl_info->params, argc * sizeof(jit_type_t));
607 for (i = 0; i < va_count; ++i) {
608 struct psi_call_frame_argument *frame_arg;
609
610 frame_arg = psi_call_frame_get_var_argument(frame, i);
611 param_types[argc + i] = psi_jit_impl_type(frame_arg->va_type);
612 }
613
614 signature = jit_type_create_signature(jit_abi_vararg,
615 jit_type_get_return(decl_info->signature),
616 param_types, argc + va_count,
617 1);
618 assert(signature);
619
620 if (impl) {
621 impl_info = impl->info;
622 prev = impl_info->frame;
623 impl_info->frame = frame;
624 }
625 jit_apply(signature, decl->sym,
626 psi_call_frame_get_arg_pointers(frame), argc,
627 psi_call_frame_get_rpointer(frame));
628 if (impl) {
629 impl_info->frame = prev;
630 }
631
632 jit_type_free(signature);
633
634 efree(param_types);
635 }
636
637 static void psi_jit_call(struct psi_call_frame *frame) {
638 if (psi_call_frame_num_var_args(frame)) {
639 psi_jit_call_va(frame);
640 } else {
641 psi_jit_call_ex(frame);
642 }
643 }
644
645 static void *psi_jit_query(struct psi_context *C, enum psi_context_query q,
646 void *arg)
647 {
648 switch (q) {
649 case PSI_CONTEXT_QUERY_SELF:
650 return "jit";
651 case PSI_CONTEXT_QUERY_TYPE:
652 return psi_jit_impl_type(*(token_t *) arg);
653 }
654 return NULL;
655 }
656
657 static ZEND_RESULT_CODE psi_jit_load(void)
658 {
659 #if HAVE_INT128
660 jit_type_t ll_fields[2], ull_fields[2];
661
662 ll_fields[0] = ll_fields[1] = jit_type_long;
663 jit_type_llong = jit_type_create_struct(ll_fields, 2, 1);
664
665 ull_fields[0] = ull_fields[1] = jit_type_ulong;
666 jit_type_ullong = jit_type_create_struct(ull_fields, 2, 1);
667 #endif
668 return SUCCESS;
669 }
670
671 static void psi_jit_free(void)
672 {
673 #if HAVE_INT128
674 jit_type_free(jit_type_llong);
675 jit_type_free(jit_type_ullong);
676 #endif
677 }
678
679 static struct psi_context_ops ops = {
680 psi_jit_load,
681 psi_jit_free,
682 psi_jit_init,
683 psi_jit_dtor,
684 psi_jit_compile,
685 psi_jit_call,
686 psi_jit_query
687 };
688
689 struct psi_context_ops *psi_libjit_ops(void)
690 {
691 return &ops;
692 }
693
694 #endif /* HAVE_LIBJIT */