1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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.
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 *******************************************************************************/
29 # include "php_config.h"
41 static jit_type_t jit_type_llong
;
42 static jit_type_t jit_type_ullong
;
45 struct psi_jit_context
{
50 struct psi_jit_callback_info
{
51 struct psi_jit_impl_info
*impl_info
;
52 struct psi_let_exp
*let_exp
;
57 struct psi_jit_decl_info
{
59 struct psi_jit_struct_info
*rv_array
;
63 struct psi_jit_extvar_info
{
75 struct psi_jit_impl_info
{
76 struct psi_context
*context
;
77 struct psi_call_frame
*frame
;
82 struct psi_jit_struct_info
{
84 struct psi_plist
*eles
;
87 static inline jit_type_t
psi_jit_token_type(token_t t
)
96 return jit_type_sbyte
;
98 return jit_type_ubyte
;
100 return jit_type_short
;
102 return jit_type_ushort
;
106 return jit_type_uint
;
108 return jit_type_long
;
110 return jit_type_ulong
;
113 return jit_type_llong
;
115 return jit_type_ullong
;
118 return jit_type_sys_bool
;
120 return jit_type_sys_int
;
122 return jit_type_sys_float
;
124 return jit_type_sys_double
;
125 #ifdef HAVE_LONG_DOUBLE
126 case PSI_T_LONG_DOUBLE
:
127 return jit_type_sys_long_double
;
131 return jit_type_void_ptr
;
134 static inline jit_type_t
psi_jit_impl_type(token_t impl_type
)
138 return jit_type_sbyte
;
140 return jit_type_long
;
142 return jit_type_void_ptr
;
145 return jit_type_sys_double
;
146 EMPTY_SWITCH_DEFAULT_CASE();
151 static void psi_jit_type_free(jit_type_t
*typ_ptr
)
153 jit_type_free(*typ_ptr
);
156 static inline jit_abi_t
psi_jit_abi(zend_string
*convention
)
158 if (zend_string_equals_literal(convention
, "stdcall")) {
159 return jit_abi_stdcall
;
161 if (zend_string_equals_literal(convention
, "fastcall")) {
162 return jit_abi_fastcall
;
164 return jit_abi_cdecl
;
167 static void psi_jit_handler(jit_type_t sig
, void *result
, void **args
, void *data
)
169 struct psi_impl
*impl
= data
;
170 struct psi_jit_impl_info
*info
= impl
->info
;
172 psi_context_call(info
->context
, *(zend_execute_data
**)args
[0], *(zval
**) args
[1], impl
);
175 static void psi_jit_callback(jit_type_t sig
, void *result
, void **args
, void *data
)
177 struct psi_jit_callback_info
*cb_info
= data
;
178 struct psi_call_frame_callback cb_data
;
180 assert(cb_info
->impl_info
->frame
);
182 cb_data
.cb
= cb_info
->let_exp
;
183 cb_data
.argc
= jit_type_num_params(sig
);
185 cb_data
.rval
= result
;
187 psi_call_frame_do_callback(cb_info
->impl_info
->frame
, &cb_data
);
190 static bool psi_jit_load(void)
193 jit_type_t ll_fields
[2], ull_fields
[2];
195 ll_fields
[0] = ll_fields
[1] = jit_type_long
;
196 jit_type_llong
= jit_type_create_struct(ll_fields
, 2, 1);
198 ull_fields
[0] = ull_fields
[1] = jit_type_ulong
;
199 jit_type_ullong
= jit_type_create_struct(ull_fields
, 2, 1);
204 static void psi_jit_free(void)
207 jit_type_free(jit_type_llong
);
208 jit_type_free(jit_type_ullong
);
212 static bool psi_jit_init(struct psi_context
*C
)
214 struct psi_jit_context
*context
= pecalloc(1, sizeof(*context
), 1);
215 jit_type_t params
[] = {jit_type_void_ptr
, jit_type_void_ptr
};
217 context
->jit
= jit_context_create();
223 context
->signature
= jit_type_create_signature(jit_abi_fastcall
, jit_type_void
,
225 if (!context
->signature
) {
226 jit_context_destroy(context
->jit
);
231 C
->context
= context
;
235 static void psi_jit_dtor(struct psi_context
*C
)
238 struct psi_jit_context
*context
= C
->context
;
240 jit_type_free(context
->signature
);
241 jit_context_destroy(context
->jit
);
243 pefree(C
->context
, 1);
249 static bool psi_jit_composite_init(struct psi_context
*C
,
250 struct psi_decl_arg
*darg
)
252 struct psi_jit_struct_info
*info
;
254 if (darg
->engine
.type
) {
258 info
= pecalloc(1, sizeof(*info
), 1);
259 info
->eles
= psi_plist_init((psi_plist_dtor
) psi_jit_type_free
);
260 psi_context_composite_type_elements(C
, darg
, &info
->eles
);
261 info
->strct
= jit_type_create_struct((jit_type_t
*)
262 psi_plist_eles(info
->eles
),
263 psi_plist_count(info
->eles
), 0);
265 darg
->engine
.info
= info
;
266 darg
->engine
.type
= info
->strct
;
271 static void psi_jit_composite_dtor(struct psi_context
*C
,
272 struct psi_decl_arg
*darg
)
274 struct psi_jit_struct_info
*info
= darg
->engine
.info
;
277 darg
->engine
.info
= NULL
;
278 darg
->engine
.type
= NULL
;
280 jit_type_free(info
->strct
);
282 pefree(info
->eles
, 1);
287 static void psi_jit_extvar_get(jit_type_t sig
, void *result
, void **args
, void *data
)
289 struct psi_decl_extvar
*evar
= data
;
291 psi_decl_extvar_get(evar
, result
);
294 static void psi_jit_extvar_set(jit_type_t sig
, void *result
, void **args
, void *data
)
296 struct psi_decl_extvar
*evar
= data
;
298 psi_decl_extvar_set(evar
, args
[0]);
301 static bool psi_jit_decl_init(struct psi_context
*, struct psi_decl
*);
303 static bool psi_jit_extvar_init(struct psi_context
*C
,
304 struct psi_decl_extvar
*evar
)
306 struct psi_jit_context
*ctx
= C
->context
;
307 struct psi_jit_extvar_info
*info
= pecalloc(1, sizeof(*info
), 1);
311 psi_jit_decl_init(C
, evar
->getter
);
312 psi_jit_decl_init(C
, evar
->setter
);
314 jit_context_build_start(ctx
->jit
);
316 info
->get
.signature
= jit_type_create_signature(jit_abi_cdecl
,
317 psi_context_decl_arg_call_type(C
, evar
->getter
->func
), NULL
, 0, 1);
318 if (!info
->get
.signature
) {
321 info
->get
.closure
= jit_closure_create(ctx
->jit
, info
->get
.signature
,
322 psi_jit_extvar_get
, evar
);
323 if (!info
->get
.closure
) {
327 info
->set
.params
[0] = psi_context_decl_arg_call_type(C
, evar
->arg
);
328 info
->set
.signature
= jit_type_create_signature(jit_abi_cdecl
,
329 psi_context_decl_arg_call_type(C
, evar
->setter
->func
),
330 info
->set
.params
, 1, 1);
331 if (!info
->set
.signature
) {
334 info
->set
.closure
= jit_closure_create(ctx
->jit
, info
->set
.signature
,
335 psi_jit_extvar_set
, evar
);
336 if (!info
->set
.closure
) {
340 evar
->getter
->sym
= info
->get
.closure
;
341 evar
->setter
->sym
= info
->set
.closure
;
343 jit_context_build_end(ctx
->jit
);
346 jit_context_build_end(ctx
->jit
);
350 static void psi_jit_extvar_dtor(struct psi_context
*C
,
351 struct psi_decl_extvar
*evar
) {
353 pefree(evar
->info
, 1);
358 static bool psi_jit_decl_init(struct psi_context
*C
, struct psi_decl
*decl
)
361 struct psi_jit_context
*ctx
= C
->context
;
362 size_t i
, c
= psi_plist_count(decl
->args
);
363 struct psi_decl_arg
*arg
;
364 struct psi_jit_decl_info
*info
= pecalloc(1,
365 sizeof(*info
) + 2 * c
* sizeof(void *), 1);
369 jit_context_build_start(ctx
->jit
);
371 for (i
= 0; psi_plist_get(decl
->args
, i
, &arg
); ++i
) {
372 info
->params
[i
] = psi_context_decl_arg_call_type(C
, arg
);
374 info
->params
[c
] = NULL
;
376 info
->signature
= jit_type_create_signature(
377 psi_jit_abi(decl
->abi
->convention
),
378 psi_context_decl_arg_full_type(C
, decl
->func
),
379 (jit_type_t
*) info
->params
, c
, 1);
381 jit_context_build_end(ctx
->jit
);
383 if (!info
->signature
) {
393 static void psi_jit_decl_dtor(struct psi_context
*C
, struct psi_decl
*decl
) {
395 struct psi_jit_decl_info
*info
= decl
->info
;
397 jit_type_free(info
->signature
);
403 static bool psi_jit_impl_init(struct psi_context
*C
,
404 struct psi_impl
*impl
, zif_handler
*zh
)
406 struct psi_jit_context
*context
= C
->context
;
407 struct psi_jit_impl_info
*info
= calloc(1, sizeof(*info
));
412 info
->closure
= jit_closure_create(context
->jit
, context
->signature
,
413 &psi_jit_handler
, impl
);
415 if (!info
->closure
) {
429 static void psi_jit_impl_dtor(struct psi_context
*C
, struct psi_impl
*impl
) {
430 struct psi_jit_impl_info
*info
= impl
->info
;
433 /* The memory for the closure will be reclaimed
434 * when the context is destroyed.
441 static bool psi_jit_cb_init(struct psi_context
*C
,
442 struct psi_let_exp
*exp
, struct psi_impl
*impl
)
444 struct psi_jit_context
*context
= C
->context
;
445 struct psi_jit_callback_info
*cb_info
;
446 struct psi_jit_decl_info
*decl_info
;
448 assert(exp
->kind
== PSI_LET_CALLBACK
);
450 if (!psi_jit_decl_init(C
, exp
->data
.callback
->decl
)) {
454 cb_info
= pecalloc(1, sizeof(*cb_info
), 1);
455 cb_info
->impl_info
= impl
->info
;
456 cb_info
->let_exp
= exp
;
458 decl_info
= exp
->data
.callback
->decl
->info
;
459 cb_info
->closure
= jit_closure_create(context
->jit
, decl_info
->signature
,
460 &psi_jit_callback
, cb_info
);
462 if (!cb_info
->closure
) {
467 assert(!exp
->data
.callback
->decl
->sym
);
468 exp
->data
.callback
->info
= cb_info
;
469 exp
->data
.callback
->decl
->sym
= cb_info
->closure
;
474 static void psi_jit_cb_dtor(struct psi_context
*C
,
475 struct psi_let_exp
*let_exp
, struct psi_impl
*impl
)
477 assert(let_exp
->kind
== PSI_LET_CALLBACK
);
479 psi_jit_decl_dtor(C
, let_exp
->data
.callback
->decl
);
481 if (let_exp
->data
.callback
->info
) {
482 struct psi_jit_callback_info
*info
= let_exp
->data
.callback
->info
;
484 /* The memory for the closure will be reclaimed
485 * when the context is destroyed.
488 let_exp
->data
.callback
->info
= NULL
;
492 static void psi_jit_call(struct psi_call_frame
*frame
) {
493 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
494 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
495 struct psi_jit_decl_info
*decl_info
= decl
->info
;
496 struct psi_jit_impl_info
*impl_info
;
497 struct psi_call_frame
*prev
;
500 impl_info
= impl
->info
;
501 prev
= impl_info
->frame
;
502 impl_info
->frame
= frame
;
504 jit_apply(decl_info
->signature
, decl
->sym
,
505 psi_call_frame_get_arg_pointers(frame
), psi_plist_count(decl
->args
),
506 psi_call_frame_get_rpointer(frame
));
508 impl_info
->frame
= prev
;
512 static void psi_jit_call_va(struct psi_call_frame
*frame
) {
513 jit_type_t signature
;
514 struct psi_call_frame
*prev
;
515 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
516 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
517 struct psi_jit_decl_info
*decl_info
= decl
->info
;
518 struct psi_jit_impl_info
*impl_info
;
519 size_t i
, va_count
, argc
;
520 jit_type_t
*param_types
;
522 argc
= psi_plist_count(decl
->args
);
523 va_count
= psi_call_frame_num_var_args(frame
);
524 param_types
= ecalloc(argc
+ va_count
+ 1, sizeof(jit_type_t
));
525 memcpy(param_types
, decl_info
->params
, argc
* sizeof(jit_type_t
));
526 for (i
= 0; i
< va_count
; ++i
) {
527 struct psi_call_frame_argument
*frame_arg
;
529 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
530 param_types
[argc
+ i
] = psi_jit_impl_type(frame_arg
->va_type
);
533 signature
= jit_type_create_signature(jit_abi_vararg
,
534 jit_type_get_return(decl_info
->signature
),
535 param_types
, argc
+ va_count
, 1);
539 impl_info
= impl
->info
;
540 prev
= impl_info
->frame
;
541 impl_info
->frame
= frame
;
543 jit_apply(signature
, decl
->sym
,
544 psi_call_frame_get_arg_pointers(frame
), argc
,
545 psi_call_frame_get_rpointer(frame
));
547 impl_info
->frame
= prev
;
550 jit_type_free(signature
);
555 static void *psi_jit_typeof_impl(struct psi_context
*C
, token_t impl_type
)
557 return psi_jit_impl_type(impl_type
);
560 static void *psi_jit_typeof_decl(struct psi_context
*C
, token_t decl_type
)
562 return psi_jit_token_type(decl_type
);
565 static void *psi_jit_copyof_type(struct psi_context
*C
, void *orig_type
)
567 return jit_type_copy(orig_type
);
570 static void psi_jit_layoutof_type(struct psi_context
*C
, void *orig_type
,
571 struct psi_layout
*l
)
573 l
->pos
= jit_type_get_alignment(orig_type
);
574 l
->len
= jit_type_get_size(orig_type
);
580 static struct psi_context_ops ops
= {
586 psi_jit_composite_init
,
587 psi_jit_composite_dtor
,
601 psi_jit_layoutof_type
,
604 struct psi_context_ops
*psi_libjit_ops(void)
609 #endif /* HAVE_LIBJIT */