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