0b4989b1dd2f92f35cb96dd2997e8078633cceee
[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 struct psi_jit_context {
41 jit_context_t jit;
42 jit_type_t signature;
43 };
44
45 struct psi_jit_callback_info {
46 struct psi_jit_impl_info *impl_info;
47 struct psi_let_exp *let_exp;
48
49 void *closure;
50 };
51
52 struct psi_jit_decl_info {
53 jit_type_t signature;
54 struct psi_jit_struct_info *rv_array;
55 void *params[1];
56 };
57
58 struct psi_jit_extvar_info {
59 struct {
60 jit_type_t signature;
61 void *closure;
62 } get;
63 struct {
64 jit_type_t signature;
65 jit_type_t params[1];
66 void *closure;
67 } set;
68 };
69
70 struct psi_jit_impl_info {
71 struct psi_context *context;
72 struct psi_call_frame *frame;
73
74 void *closure;
75 };
76
77 struct psi_jit_struct_info {
78 jit_type_t strct;
79 struct psi_plist *eles;
80 };
81
82 static inline jit_type_t psi_jit_token_type(token_t t)
83 {
84 switch (t) {
85 default:
86 assert(0);
87 /* no break */
88 case PSI_T_VOID:
89 return jit_type_void;
90 case PSI_T_INT8:
91 return jit_type_sbyte;
92 case PSI_T_UINT8:
93 return jit_type_ubyte;
94 case PSI_T_INT16:
95 return jit_type_short;
96 case PSI_T_UINT16:
97 return jit_type_ushort;
98 case PSI_T_INT32:
99 return jit_type_int;
100 case PSI_T_UINT32:
101 return jit_type_uint;
102 case PSI_T_INT64:
103 return jit_type_long;
104 case PSI_T_UINT64:
105 return jit_type_ulong;
106 #if HAVE_INT128
107 case PSI_T_INT128:
108 return jit_type_llong;
109 case PSI_T_UINT128:
110 return jit_type_ullong;
111 #endif
112 case PSI_T_BOOL:
113 return jit_type_sys_bool;
114 case PSI_T_ENUM:
115 return jit_type_sys_int;
116 case PSI_T_FLOAT:
117 return jit_type_sys_float;
118 case PSI_T_DOUBLE:
119 return jit_type_sys_double;
120 #ifdef HAVE_LONG_DOUBLE
121 case PSI_T_LONG_DOUBLE:
122 return jit_type_sys_long_double;
123 #endif
124 case PSI_T_POINTER:
125 case PSI_T_FUNCTION:
126 return jit_type_void_ptr;
127 }
128 }
129 static inline jit_type_t psi_jit_impl_type(token_t impl_type)
130 {
131 switch (impl_type) {
132 case PSI_T_BOOL:
133 return jit_type_sbyte;
134 case PSI_T_INT:
135 return jit_type_long;
136 case PSI_T_STRING:
137 return jit_type_void_ptr;
138 case PSI_T_FLOAT:
139 case PSI_T_DOUBLE:
140 return jit_type_sys_double;
141 EMPTY_SWITCH_DEFAULT_CASE();
142 }
143 return NULL;
144 }
145
146 static void psi_jit_type_free(jit_type_t *typ_ptr)
147 {
148 jit_type_free(*typ_ptr);
149 }
150
151 static inline jit_abi_t psi_jit_abi(zend_string *convention)
152 {
153 if (zend_string_equals_literal(convention, "stdcall")) {
154 return jit_abi_stdcall;
155 }
156 if (zend_string_equals_literal(convention, "fastcall")) {
157 return jit_abi_fastcall;
158 }
159 return jit_abi_cdecl;
160 }
161
162 static void psi_jit_handler(jit_type_t sig, void *result, void **args, void *data)
163 {
164 struct psi_impl *impl = data;
165 struct psi_jit_impl_info *info = impl->info;
166
167 psi_context_call(info->context, *(zend_execute_data **)args[0], *(zval **) args[1], impl);
168 }
169
170 static void psi_jit_callback(jit_type_t sig, void *result, void **args, void *data)
171 {
172 struct psi_jit_callback_info *cb_info = data;
173 struct psi_call_frame_callback cb_data;
174
175 assert(cb_info->impl_info->frame);
176
177 cb_data.cb = cb_info->let_exp;
178 cb_data.argc = jit_type_num_params(sig);
179 cb_data.argv = args;
180 cb_data.rval = result;
181
182 psi_call_frame_do_callback(cb_info->impl_info->frame, &cb_data);
183 }
184
185 static bool psi_jit_load(void)
186 {
187 #if HAVE_INT128
188 jit_type_t ll_fields[2], ull_fields[2];
189
190 ll_fields[0] = ll_fields[1] = jit_type_long;
191 jit_type_llong = jit_type_create_struct(ll_fields, 2, 1);
192
193 ull_fields[0] = ull_fields[1] = jit_type_ulong;
194 jit_type_ullong = jit_type_create_struct(ull_fields, 2, 1);
195 #endif
196 return true;
197 }
198
199 static void psi_jit_free(void)
200 {
201 #if HAVE_INT128
202 jit_type_free(jit_type_llong);
203 jit_type_free(jit_type_ullong);
204 #endif
205 }
206
207 static bool psi_jit_init(struct psi_context *C)
208 {
209 struct psi_jit_context *context = pecalloc(1, sizeof(*context), 1);
210 jit_type_t params[] = {jit_type_void_ptr, jit_type_void_ptr};
211
212 context->jit = jit_context_create();
213 if (!context->jit) {
214 pefree(context, 1);
215 return false;
216 }
217
218 context->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void,
219 params, 2, 1);
220 if (!context->signature) {
221 jit_context_destroy(context->jit);
222 pefree(context, 1);
223 return false;
224 }
225
226 C->context = context;
227 return true;
228 }
229
230 static void psi_jit_dtor(struct psi_context *C)
231 {
232 if (C->context) {
233 struct psi_jit_context *context = C->context;
234
235 jit_type_free(context->signature);
236 jit_context_destroy(context->jit);
237
238 pefree(C->context, 1);
239 C->context = NULL;
240 }
241 }
242
243
244 static bool psi_jit_composite_init(struct psi_context *C,
245 struct psi_decl_arg *darg)
246 {
247 struct psi_jit_struct_info *info;
248
249 if (darg->engine.type) {
250 return true;
251 }
252
253 info = pecalloc(1, sizeof(*info), 1);
254 info->eles = psi_plist_init((psi_plist_dtor) psi_jit_type_free);
255 info->strct = jit_type_create_struct((jit_type_t *)
256 psi_context_composite_type_elements(C, darg, &info->eles),
257 psi_plist_count(info->eles), 0);
258
259 darg->engine.info = info;
260 darg->engine.type = info->strct;
261
262 return true;
263 }
264
265 static void psi_jit_composite_dtor(struct psi_context *C,
266 struct psi_decl_arg *darg)
267 {
268 struct psi_jit_struct_info *info = darg->engine.info;
269
270 if (info) {
271 darg->engine.info = NULL;
272 darg->engine.type = NULL;
273
274 jit_type_free(info->strct);
275 psi_plist_free(info->eles);
276 pefree(info, 1);
277 }
278 }
279
280 static void psi_jit_extvar_get(jit_type_t sig, void *result, void **args, void *data)
281 {
282 struct psi_decl_extvar *evar = data;
283
284 psi_decl_extvar_get(evar, result);
285 }
286
287 static void psi_jit_extvar_set(jit_type_t sig, void *result, void **args, void *data)
288 {
289 struct psi_decl_extvar *evar = data;
290
291 psi_decl_extvar_set(evar, args[0]);
292 }
293
294 static bool psi_jit_decl_init(struct psi_context *, struct psi_decl *);
295
296 static bool psi_jit_extvar_init(struct psi_context *C,
297 struct psi_decl_extvar *evar)
298 {
299 struct psi_jit_context *ctx = C->context;
300 struct psi_jit_extvar_info *info = pecalloc(1, sizeof(*info), 1);
301
302 evar->info = info;
303
304 psi_jit_decl_init(C, evar->getter);
305 psi_jit_decl_init(C, evar->setter);
306
307 jit_context_build_start(ctx->jit);
308
309 info->get.signature = jit_type_create_signature(jit_abi_cdecl,
310 psi_context_decl_arg_full_type(C, evar->getter->func), NULL, 0, 1);
311 if (!info->get.signature) {
312 goto failure;
313 }
314 info->get.closure = jit_closure_create(ctx->jit, info->get.signature,
315 psi_jit_extvar_get, evar);
316 if (!info->get.closure) {
317 goto failure;
318 }
319
320 info->set.params[0] = psi_context_decl_arg_call_type(C, evar->arg);
321 info->set.signature = jit_type_create_signature(jit_abi_cdecl,
322 psi_context_decl_arg_full_type(C, evar->setter->func),
323 info->set.params, 1, 1);
324 if (!info->set.signature) {
325 goto failure;
326 }
327 info->set.closure = jit_closure_create(ctx->jit, info->set.signature,
328 psi_jit_extvar_set, evar);
329 if (!info->set.closure) {
330 goto failure;
331 }
332
333 evar->getter->sym = info->get.closure;
334 evar->setter->sym = info->set.closure;
335
336 jit_context_build_end(ctx->jit);
337 return true;
338 failure: ;
339 jit_context_build_end(ctx->jit);
340 return false;
341 }
342
343 static void psi_jit_extvar_dtor(struct psi_context *C,
344 struct psi_decl_extvar *evar) {
345 if (evar->info) {
346 pefree(evar->info, 1);
347 evar->info = NULL;
348 }
349 }
350
351 static bool psi_jit_decl_init(struct psi_context *C, struct psi_decl *decl)
352 {
353 if (!decl->info) {
354 struct psi_jit_context *ctx = C->context;
355 size_t i, c = psi_plist_count(decl->args);
356 struct psi_decl_arg *arg;
357 struct psi_jit_decl_info *info = pecalloc(1,
358 sizeof(*info) + 2 * c * sizeof(void *), 1);
359
360 decl->info = info;
361
362 jit_context_build_start(ctx->jit);
363
364 for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
365 info->params[i] = psi_context_decl_arg_call_type(C, arg);
366 }
367 info->params[c] = NULL;
368
369 info->signature = jit_type_create_signature(
370 psi_jit_abi(decl->abi->convention),
371 psi_context_decl_arg_full_type(C, decl->func),
372 (jit_type_t *) info->params, c, 1);
373
374 jit_context_build_end(ctx->jit);
375
376 if (!info->signature) {
377 pefree(info, 1);
378 decl->info = NULL;
379 return false;
380 }
381 }
382
383 return true;
384 }
385
386 static void psi_jit_decl_dtor(struct psi_context *C, struct psi_decl *decl) {
387 if (decl->info) {
388 struct psi_jit_decl_info *info = decl->info;
389
390 jit_type_free(info->signature);
391 pefree(info, 1);
392 decl->info = NULL;
393 }
394 }
395
396 static bool psi_jit_impl_init(struct psi_context *C,
397 struct psi_impl *impl, zif_handler *zh)
398 {
399 struct psi_jit_context *context = C->context;
400 struct psi_jit_impl_info *info = calloc(1, sizeof(*info));
401
402 impl->info = info;
403 info->context = C;
404
405 info->closure = jit_closure_create(context->jit, context->signature,
406 &psi_jit_handler, impl);
407
408 if (!info->closure) {
409 goto failure;
410 }
411
412 *zh = info->closure;
413 return true;
414
415 failure: ;
416 impl->info = NULL;
417 pefree(info, 1);
418 return false;
419 }
420
421
422 static void psi_jit_impl_dtor(struct psi_context *C, struct psi_impl *impl) {
423 struct psi_jit_impl_info *info = impl->info;
424
425 if (info) {
426 /* The memory for the closure will be reclaimed
427 * when the context is destroyed.
428 */
429 pefree(info, 1);
430 impl->info = NULL;
431 }
432 }
433
434 static bool psi_jit_cb_init(struct psi_context *C,
435 struct psi_let_exp *exp, struct psi_impl *impl)
436 {
437 struct psi_jit_context *context = C->context;
438 struct psi_jit_callback_info *cb_info;
439 struct psi_jit_decl_info *decl_info;
440
441 assert(exp->kind == PSI_LET_CALLBACK);
442
443 if (!psi_jit_decl_init(C, exp->data.callback->decl)) {
444 return false;
445 }
446
447 cb_info = pecalloc(1, sizeof(*cb_info), 1);
448 cb_info->impl_info = impl->info;
449 cb_info->let_exp = exp;
450
451 decl_info = exp->data.callback->decl->info;
452 cb_info->closure = jit_closure_create(context->jit, decl_info->signature,
453 &psi_jit_callback, cb_info);
454
455 if (!cb_info->closure) {
456 free(cb_info);
457 return false;
458 }
459
460 assert(!exp->data.callback->decl->sym);
461 exp->data.callback->info = cb_info;
462 exp->data.callback->decl->sym = cb_info->closure;
463
464 return true;
465 }
466
467 static void psi_jit_cb_dtor(struct psi_context *C,
468 struct psi_let_exp *let_exp, struct psi_impl *impl)
469 {
470 assert(let_exp->kind == PSI_LET_CALLBACK);
471
472 psi_jit_decl_dtor(C, let_exp->data.callback->decl);
473
474 if (let_exp->data.callback->info) {
475 struct psi_jit_callback_info *info = let_exp->data.callback->info;
476
477 /* The memory for the closure will be reclaimed
478 * when the context is destroyed.
479 */
480 pefree(info, 1);
481 let_exp->data.callback->info = NULL;
482 }
483 }
484
485 static void psi_jit_call(struct psi_call_frame *frame) {
486 struct psi_decl *decl = psi_call_frame_get_decl(frame);
487 struct psi_impl *impl = psi_call_frame_get_impl(frame);
488 struct psi_jit_decl_info *decl_info = decl->info;
489 struct psi_jit_impl_info *impl_info;
490 struct psi_call_frame *prev;
491
492 if (impl) {
493 impl_info = impl->info;
494 prev = impl_info->frame;
495 impl_info->frame = frame;
496 }
497 jit_apply(decl_info->signature, decl->sym,
498 psi_call_frame_get_arg_pointers(frame), psi_plist_count(decl->args),
499 psi_call_frame_get_rpointer(frame));
500 if (impl) {
501 impl_info->frame = prev;
502 }
503 }
504
505 static void psi_jit_call_va(struct psi_call_frame *frame) {
506 jit_type_t signature;
507 struct psi_call_frame *prev;
508 struct psi_decl *decl = psi_call_frame_get_decl(frame);
509 struct psi_impl *impl = psi_call_frame_get_impl(frame);
510 struct psi_jit_decl_info *decl_info = decl->info;
511 struct psi_jit_impl_info *impl_info;
512 size_t i, va_count, argc;
513 jit_type_t *param_types;
514
515 argc = psi_plist_count(decl->args);
516 va_count = psi_call_frame_num_var_args(frame);
517 param_types = ecalloc(argc + va_count + 1, sizeof(jit_type_t));
518 memcpy(param_types, decl_info->params, argc * sizeof(jit_type_t));
519 for (i = 0; i < va_count; ++i) {
520 struct psi_call_frame_argument *frame_arg;
521
522 frame_arg = psi_call_frame_get_var_argument(frame, i);
523 param_types[argc + i] = psi_jit_impl_type(frame_arg->va_type);
524 }
525
526 signature = jit_type_create_signature(jit_abi_vararg,
527 jit_type_get_return(decl_info->signature),
528 param_types, argc + va_count, 1);
529 assert(signature);
530
531 if (impl) {
532 impl_info = impl->info;
533 prev = impl_info->frame;
534 impl_info->frame = frame;
535 }
536 jit_apply(signature, decl->sym,
537 psi_call_frame_get_arg_pointers(frame), argc,
538 psi_call_frame_get_rpointer(frame));
539 if (impl) {
540 impl_info->frame = prev;
541 }
542
543 jit_type_free(signature);
544
545 efree(param_types);
546 }
547
548 static void *psi_jit_typeof_impl(struct psi_context *C, token_t impl_type)
549 {
550 return psi_jit_impl_type(impl_type);
551 }
552
553 static void *psi_jit_typeof_decl(struct psi_context *C, token_t decl_type)
554 {
555 return psi_jit_token_type(decl_type);
556 }
557
558 static void *psi_jit_copyof_type(struct psi_context *C, void *orig_type)
559 {
560 return jit_type_copy(orig_type);
561 }
562
563 static void psi_jit_layoutof_type(struct psi_context *C, void *orig_type,
564 struct psi_layout *l)
565 {
566 l->pos = jit_type_get_alignment(orig_type);
567 l->len = jit_type_get_size(orig_type);
568 }
569
570 static struct psi_context_ops ops = {
571 "libjit",
572 psi_jit_load,
573 psi_jit_free,
574 psi_jit_init,
575 psi_jit_dtor,
576 psi_jit_composite_init,
577 psi_jit_composite_dtor,
578 psi_jit_extvar_init,
579 psi_jit_extvar_dtor,
580 psi_jit_decl_init,
581 psi_jit_decl_dtor,
582 psi_jit_impl_init,
583 psi_jit_impl_dtor,
584 psi_jit_cb_init,
585 psi_jit_cb_dtor,
586 psi_jit_call,
587 psi_jit_call_va,
588 psi_jit_typeof_impl,
589 psi_jit_typeof_decl,
590 psi_jit_copyof_type,
591 psi_jit_layoutof_type,
592 };
593
594 struct psi_context_ops *psi_libjit_ops(void)
595 {
596 return &ops;
597 }
598
599 #endif /* HAVE_LIBJIT */