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 *******************************************************************************/
26 #include "php_psi_stdinc.h"
36 static jit_type_t jit_type_llong
;
37 static jit_type_t jit_type_ullong
;
40 struct psi_jit_context
{
45 struct psi_jit_callback_info
{
46 struct psi_jit_impl_info
*impl_info
;
47 struct psi_let_exp
*let_exp
;
52 struct psi_jit_decl_info
{
54 struct psi_jit_struct_info
*rv_array
;
58 struct psi_jit_extvar_info
{
70 struct psi_jit_impl_info
{
71 struct psi_context
*context
;
72 struct psi_call_frame
*frame
;
77 struct psi_jit_struct_info
{
79 struct psi_plist
*eles
;
82 static inline jit_type_t
psi_jit_token_type(token_t t
)
91 return jit_type_sbyte
;
93 return jit_type_ubyte
;
95 return jit_type_short
;
97 return jit_type_ushort
;
101 return jit_type_uint
;
103 return jit_type_long
;
105 return jit_type_ulong
;
108 return jit_type_llong
;
110 return jit_type_ullong
;
113 return jit_type_sys_bool
;
115 return jit_type_sys_int
;
117 return jit_type_sys_float
;
119 return jit_type_sys_double
;
120 #ifdef HAVE_LONG_DOUBLE
121 case PSI_T_LONG_DOUBLE
:
122 return jit_type_sys_long_double
;
126 return jit_type_void_ptr
;
129 static inline jit_type_t
psi_jit_impl_type(token_t impl_type
)
133 return jit_type_sbyte
;
135 return jit_type_long
;
137 return jit_type_void_ptr
;
140 return jit_type_sys_double
;
141 EMPTY_SWITCH_DEFAULT_CASE();
146 static void psi_jit_type_free(jit_type_t
*typ_ptr
)
148 jit_type_free(*typ_ptr
);
151 static inline jit_abi_t
psi_jit_abi(zend_string
*convention
)
153 if (zend_string_equals_literal(convention
, "stdcall")) {
154 return jit_abi_stdcall
;
156 if (zend_string_equals_literal(convention
, "fastcall")) {
157 return jit_abi_fastcall
;
159 return jit_abi_cdecl
;
162 static void psi_jit_handler(jit_type_t sig
, void *result
, void **args
, void *data
)
164 struct psi_impl
*impl
= data
;
165 struct psi_jit_impl_info
*info
= impl
->info
;
167 psi_context_call(info
->context
, *(zend_execute_data
**)args
[0], *(zval
**) args
[1], impl
);
170 static void psi_jit_callback(jit_type_t sig
, void *result
, void **args
, void *data
)
172 struct psi_jit_callback_info
*cb_info
= data
;
173 struct psi_call_frame_callback cb_data
;
175 assert(cb_info
->impl_info
->frame
);
177 cb_data
.cb
= cb_info
->let_exp
;
178 cb_data
.argc
= jit_type_num_params(sig
);
180 cb_data
.rval
= result
;
182 psi_call_frame_do_callback(cb_info
->impl_info
->frame
, &cb_data
);
185 static bool psi_jit_load(void)
188 jit_type_t ll_fields
[2], ull_fields
[2];
190 ll_fields
[0] = ll_fields
[1] = jit_type_long
;
191 jit_type_llong
= jit_type_create_struct(ll_fields
, 2, 1);
193 ull_fields
[0] = ull_fields
[1] = jit_type_ulong
;
194 jit_type_ullong
= jit_type_create_struct(ull_fields
, 2, 1);
199 static void psi_jit_free(void)
202 jit_type_free(jit_type_llong
);
203 jit_type_free(jit_type_ullong
);
207 static bool psi_jit_init(struct psi_context
*C
)
209 struct psi_jit_context
*context
= pecalloc(1, sizeof(*context
), 1);
210 jit_type_t params
[] = {jit_type_void_ptr
, jit_type_void_ptr
};
212 context
->jit
= jit_context_create();
218 context
->signature
= jit_type_create_signature(jit_abi_fastcall
, jit_type_void
,
220 if (!context
->signature
) {
221 jit_context_destroy(context
->jit
);
226 C
->context
= context
;
230 static void psi_jit_dtor(struct psi_context
*C
)
233 struct psi_jit_context
*context
= C
->context
;
235 jit_type_free(context
->signature
);
236 jit_context_destroy(context
->jit
);
238 pefree(C
->context
, 1);
244 static bool psi_jit_composite_init(struct psi_context
*C
,
245 struct psi_decl_arg
*darg
)
247 struct psi_jit_struct_info
*info
;
249 if (darg
->engine
.type
) {
253 info
= pecalloc(1, sizeof(*info
), 1);
254 info
->eles
= psi_plist_init((psi_plist_dtor
) psi_jit_type_free
);
255 psi_context_composite_type_elements(C
, darg
, &info
->eles
);
256 info
->strct
= jit_type_create_struct((jit_type_t
*)
257 psi_plist_eles(info
->eles
),
258 psi_plist_count(info
->eles
), 0);
260 darg
->engine
.info
= info
;
261 darg
->engine
.type
= info
->strct
;
266 static void psi_jit_composite_dtor(struct psi_context
*C
,
267 struct psi_decl_arg
*darg
)
269 struct psi_jit_struct_info
*info
= darg
->engine
.info
;
272 darg
->engine
.info
= NULL
;
273 darg
->engine
.type
= NULL
;
275 jit_type_free(info
->strct
);
277 pefree(info
->eles
, 1);
282 static void psi_jit_extvar_get(jit_type_t sig
, void *result
, void **args
, void *data
)
284 struct psi_decl_extvar
*evar
= data
;
286 psi_decl_extvar_get(evar
, result
);
289 static void psi_jit_extvar_set(jit_type_t sig
, void *result
, void **args
, void *data
)
291 struct psi_decl_extvar
*evar
= data
;
293 psi_decl_extvar_set(evar
, args
[0]);
296 static bool psi_jit_decl_init(struct psi_context
*, struct psi_decl
*);
298 static bool psi_jit_extvar_init(struct psi_context
*C
,
299 struct psi_decl_extvar
*evar
)
301 struct psi_jit_context
*ctx
= C
->context
;
302 struct psi_jit_extvar_info
*info
= pecalloc(1, sizeof(*info
), 1);
306 psi_jit_decl_init(C
, evar
->getter
);
307 psi_jit_decl_init(C
, evar
->setter
);
309 jit_context_build_start(ctx
->jit
);
311 info
->get
.signature
= jit_type_create_signature(jit_abi_cdecl
,
312 psi_context_decl_arg_call_type(C
, evar
->getter
->func
), NULL
, 0, 1);
313 if (!info
->get
.signature
) {
316 info
->get
.closure
= jit_closure_create(ctx
->jit
, info
->get
.signature
,
317 psi_jit_extvar_get
, evar
);
318 if (!info
->get
.closure
) {
322 info
->set
.params
[0] = psi_context_decl_arg_call_type(C
, evar
->arg
);
323 info
->set
.signature
= jit_type_create_signature(jit_abi_cdecl
,
324 psi_context_decl_arg_call_type(C
, evar
->setter
->func
),
325 info
->set
.params
, 1, 1);
326 if (!info
->set
.signature
) {
329 info
->set
.closure
= jit_closure_create(ctx
->jit
, info
->set
.signature
,
330 psi_jit_extvar_set
, evar
);
331 if (!info
->set
.closure
) {
335 evar
->getter
->sym
= info
->get
.closure
;
336 evar
->setter
->sym
= info
->set
.closure
;
338 jit_context_build_end(ctx
->jit
);
341 jit_context_build_end(ctx
->jit
);
345 static void psi_jit_extvar_dtor(struct psi_context
*C
,
346 struct psi_decl_extvar
*evar
) {
348 pefree(evar
->info
, 1);
353 static bool psi_jit_decl_init(struct psi_context
*C
, struct psi_decl
*decl
)
356 struct psi_jit_context
*ctx
= C
->context
;
357 size_t i
, c
= psi_plist_count(decl
->args
);
358 struct psi_decl_arg
*arg
;
359 struct psi_jit_decl_info
*info
= pecalloc(1,
360 sizeof(*info
) + 2 * c
* sizeof(void *), 1);
364 jit_context_build_start(ctx
->jit
);
366 for (i
= 0; psi_plist_get(decl
->args
, i
, &arg
); ++i
) {
367 info
->params
[i
] = psi_context_decl_arg_call_type(C
, arg
);
369 info
->params
[c
] = NULL
;
371 info
->signature
= jit_type_create_signature(
372 psi_jit_abi(decl
->abi
->convention
),
373 psi_context_decl_arg_full_type(C
, decl
->func
),
374 (jit_type_t
*) info
->params
, c
, 1);
376 jit_context_build_end(ctx
->jit
);
378 if (!info
->signature
) {
388 static void psi_jit_decl_dtor(struct psi_context
*C
, struct psi_decl
*decl
) {
390 struct psi_jit_decl_info
*info
= decl
->info
;
392 jit_type_free(info
->signature
);
398 static bool psi_jit_impl_init(struct psi_context
*C
,
399 struct psi_impl
*impl
, zif_handler
*zh
)
401 struct psi_jit_context
*context
= C
->context
;
402 struct psi_jit_impl_info
*info
= calloc(1, sizeof(*info
));
407 info
->closure
= jit_closure_create(context
->jit
, context
->signature
,
408 &psi_jit_handler
, impl
);
410 if (!info
->closure
) {
424 static void psi_jit_impl_dtor(struct psi_context
*C
, struct psi_impl
*impl
) {
425 struct psi_jit_impl_info
*info
= impl
->info
;
428 /* The memory for the closure will be reclaimed
429 * when the context is destroyed.
436 static bool psi_jit_cb_init(struct psi_context
*C
,
437 struct psi_let_exp
*exp
, struct psi_impl
*impl
)
439 struct psi_jit_context
*context
= C
->context
;
440 struct psi_jit_callback_info
*cb_info
;
441 struct psi_jit_decl_info
*decl_info
;
443 assert(exp
->kind
== PSI_LET_CALLBACK
);
445 if (!psi_jit_decl_init(C
, exp
->data
.callback
->decl
)) {
449 cb_info
= pecalloc(1, sizeof(*cb_info
), 1);
450 cb_info
->impl_info
= impl
->info
;
451 cb_info
->let_exp
= exp
;
453 decl_info
= exp
->data
.callback
->decl
->info
;
454 cb_info
->closure
= jit_closure_create(context
->jit
, decl_info
->signature
,
455 &psi_jit_callback
, cb_info
);
457 if (!cb_info
->closure
) {
462 assert(!exp
->data
.callback
->decl
->sym
);
463 exp
->data
.callback
->info
= cb_info
;
464 exp
->data
.callback
->decl
->sym
= cb_info
->closure
;
469 static void psi_jit_cb_dtor(struct psi_context
*C
,
470 struct psi_let_exp
*let_exp
, struct psi_impl
*impl
)
472 assert(let_exp
->kind
== PSI_LET_CALLBACK
);
474 psi_jit_decl_dtor(C
, let_exp
->data
.callback
->decl
);
476 if (let_exp
->data
.callback
->info
) {
477 struct psi_jit_callback_info
*info
= let_exp
->data
.callback
->info
;
479 /* The memory for the closure will be reclaimed
480 * when the context is destroyed.
483 let_exp
->data
.callback
->info
= NULL
;
487 static void psi_jit_call(struct psi_call_frame
*frame
) {
488 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
489 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
490 struct psi_jit_decl_info
*decl_info
= decl
->info
;
491 struct psi_jit_impl_info
*impl_info
;
492 struct psi_call_frame
*prev
;
495 impl_info
= impl
->info
;
496 prev
= impl_info
->frame
;
497 impl_info
->frame
= frame
;
499 jit_apply(decl_info
->signature
, decl
->sym
,
500 psi_call_frame_get_arg_pointers(frame
), psi_plist_count(decl
->args
),
501 psi_call_frame_get_rpointer(frame
));
503 impl_info
->frame
= prev
;
507 static void psi_jit_call_va(struct psi_call_frame
*frame
) {
508 jit_type_t signature
;
509 struct psi_call_frame
*prev
;
510 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
511 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
512 struct psi_jit_decl_info
*decl_info
= decl
->info
;
513 struct psi_jit_impl_info
*impl_info
;
514 size_t i
, va_count
, argc
;
515 jit_type_t
*param_types
;
517 argc
= psi_plist_count(decl
->args
);
518 va_count
= psi_call_frame_num_var_args(frame
);
519 param_types
= ecalloc(argc
+ va_count
+ 1, sizeof(jit_type_t
));
520 memcpy(param_types
, decl_info
->params
, argc
* sizeof(jit_type_t
));
521 for (i
= 0; i
< va_count
; ++i
) {
522 struct psi_call_frame_argument
*frame_arg
;
524 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
525 param_types
[argc
+ i
] = psi_jit_impl_type(frame_arg
->va_type
);
528 signature
= jit_type_create_signature(jit_abi_vararg
,
529 jit_type_get_return(decl_info
->signature
),
530 param_types
, argc
+ va_count
, 1);
534 impl_info
= impl
->info
;
535 prev
= impl_info
->frame
;
536 impl_info
->frame
= frame
;
538 jit_apply(signature
, decl
->sym
,
539 psi_call_frame_get_arg_pointers(frame
), argc
,
540 psi_call_frame_get_rpointer(frame
));
542 impl_info
->frame
= prev
;
545 jit_type_free(signature
);
550 static void *psi_jit_typeof_impl(struct psi_context
*C
, token_t impl_type
)
552 return psi_jit_impl_type(impl_type
);
555 static void *psi_jit_typeof_decl(struct psi_context
*C
, token_t decl_type
)
557 return psi_jit_token_type(decl_type
);
560 static void *psi_jit_copyof_type(struct psi_context
*C
, void *orig_type
)
562 return jit_type_copy(orig_type
);
565 static void psi_jit_layoutof_type(struct psi_context
*C
, void *orig_type
,
566 struct psi_layout
*l
)
568 l
->pos
= jit_type_get_alignment(orig_type
);
569 l
->len
= jit_type_get_size(orig_type
);
575 static struct psi_context_ops ops
= {
581 psi_jit_composite_init
,
582 psi_jit_composite_dtor
,
596 psi_jit_layoutof_type
,
599 struct psi_context_ops
*psi_libjit_ops(void)
604 #endif /* HAVE_LIBJIT */