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