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"
35 static inline jit_type_t
psi_jit_decl_arg_type(struct psi_decl_arg
*darg
);
37 static inline jit_type_t
psi_jit_token_type(token_t t
)
46 return jit_type_sbyte
;
48 return jit_type_ubyte
;
50 return jit_type_short
;
52 return jit_type_ushort
;
60 return jit_type_ulong
;
62 return jit_type_sys_bool
;
64 return jit_type_sys_int
;
66 return jit_type_sys_float
;
68 return jit_type_sys_double
;
69 #ifdef HAVE_LONG_DOUBLE
70 case PSI_T_LONG_DOUBLE
:
71 return jit_type_sys_long_double
;
75 return jit_type_void_ptr
;
78 static inline jit_type_t
psi_jit_impl_type(token_t impl_type
)
82 return jit_type_sbyte
;
86 return jit_type_void_ptr
;
89 return jit_type_sys_double
;
90 EMPTY_SWITCH_DEFAULT_CASE()
96 struct psi_jit_struct_type
{
101 static void psi_jit_struct_type_dtor(void *ptr
)
103 struct psi_jit_struct_type
*type
= ptr
;
104 unsigned i
, n
= jit_type_num_fields(type
->strct
);
106 for (i
= 0; i
< n
; ++i
) {
107 jit_type_free(jit_type_get_field(type
->strct
, i
));
109 jit_type_free(type
->strct
);
114 static size_t psi_jit_struct_type_pad(jit_type_t
*els
, size_t padding
)
118 for (i
= 0; i
< padding
; ++i
) {
119 *els
++ = jit_type_copy(jit_type_sys_char
);
125 static unsigned psi_jit_struct_type_elements(struct psi_decl_struct
*strct
,
128 size_t i
= 0, argc
= psi_plist_count(strct
->args
), nels
= 0, offset
= 0,
129 maxalign
= 0, last_arg_pos
= -1;
130 struct psi_decl_arg
*darg
;
133 *fields
= calloc(argc
+ 1, sizeof(*fields
));
135 while (psi_plist_get(strct
->args
, i
++, &darg
)) {
137 size_t padding
, alignment
;
139 if (darg
->layout
->pos
== last_arg_pos
) {
140 /* skip bit fields */
143 last_arg_pos
= darg
->layout
->pos
;
145 type
= jit_type_copy(psi_jit_decl_arg_type(darg
));
147 if ((alignment
= jit_type_get_alignment(type
)) > maxalign
) {
148 maxalign
= alignment
;
151 assert(jit_type_get_size(type
) <= darg
->layout
->len
);
152 if ((padding
= psi_offset_padding(darg
->layout
->pos
- offset
, alignment
))) {
153 if (nels
+ padding
> argc
) {
155 tmp
= realloc(*fields
, (argc
+ 1) * sizeof(*fields
));
163 psi_jit_struct_type_pad(&(*fields
)[nels
], padding
);
167 assert(offset
== darg
->layout
->pos
);
169 offset
= (offset
+ darg
->layout
->len
+ alignment
- 1)
171 (*fields
)[nels
++] = type
;
174 /* apply struct alignment padding */
175 offset
= (offset
+ maxalign
- 1) & ~(maxalign
- 1);
177 assert(offset
<= strct
->size
);
178 if (offset
< strct
->size
) {
179 nels
+= psi_jit_struct_type_pad(&(*fields
)[nels
], strct
->size
- offset
);
184 static inline jit_type_t
psi_jit_decl_type(struct psi_decl_type
*type
)
186 struct psi_decl_type
*real
= psi_decl_type_get_real(type
);
188 switch (real
->type
) {
190 if (!real
->real
.strct
->engine
.type
) {
192 struct psi_jit_struct_type
*type
= calloc(1, sizeof(*type
));
194 count
= psi_jit_struct_type_elements(real
->real
.strct
, &type
->fields
);
195 type
->strct
= jit_type_create_struct(type
->fields
, count
, 0);
197 real
->real
.strct
->engine
.type
= type
;
198 real
->real
.strct
->engine
.dtor
= psi_jit_struct_type_dtor
;
201 return ((struct psi_jit_struct_type
*) real
->real
.strct
->engine
.type
)->strct
;
205 struct psi_decl_arg
*arg
;
206 psi_plist_get(real
->real
.unn
->args
, 0, &arg
);
207 return psi_jit_decl_arg_type(arg
);
211 return psi_jit_token_type(real
->type
);
214 static inline jit_type_t
psi_jit_decl_arg_type(struct psi_decl_arg
*darg
)
216 if (darg
->var
->pointer_level
) {
217 return jit_type_void_ptr
;
219 return psi_jit_decl_type(darg
->type
);
223 static inline jit_abi_t
psi_jit_abi(const char *convention
)
225 if (!strcasecmp(convention
, "stdcall")) {
226 return jit_abi_stdcall
;
228 if (!strcasecmp(convention
, "fastcall")) {
229 return jit_abi_fastcall
;
231 return jit_abi_cdecl
;
234 struct psi_jit_context
{
236 jit_type_t signature
;
239 struct psi_jit_impl_info
{
240 struct psi_context
*context
;
241 struct psi_call_frame
*frame
;
246 struct psi_jit_callback_info
{
247 struct psi_jit_impl_info
*impl_info
;
248 struct psi_let_exp
*let_exp
;
253 struct psi_jit_decl_info
{
254 jit_type_t signature
;
258 static inline struct psi_jit_decl_info
*psi_jit_decl_init(struct psi_decl
*decl
) {
260 size_t i
, c
= psi_plist_count(decl
->args
);
261 struct psi_decl_arg
*arg
;
262 struct psi_jit_decl_info
*info
= calloc(1, sizeof(*info
) + 2 * c
* sizeof(void *));
264 for (i
= 0; psi_plist_get(decl
->args
, i
, &arg
); ++i
) {
265 info
->params
[i
] = psi_jit_decl_arg_type(arg
);
267 info
->params
[c
] = NULL
;
269 info
->signature
= jit_type_create_signature(
270 psi_jit_abi(decl
->abi
->convention
),
271 psi_jit_decl_arg_type(decl
->func
),
272 (jit_type_t
*) info
->params
,
275 if (!info
->signature
) {
285 static inline void psi_jit_decl_dtor(struct psi_decl
*decl
) {
287 struct psi_jit_decl_info
*info
= decl
->info
;
289 jit_type_free(info
->signature
);
295 static void psi_jit_handler(jit_type_t sig
, void *result
, void **args
, void *data
)
297 struct psi_impl
*impl
= data
;
298 struct psi_jit_impl_info
*info
= impl
->info
;
300 psi_context_call(info
->context
, *(zend_execute_data
**)args
[0], *(zval
**) args
[1], impl
);
303 static void psi_jit_callback(jit_type_t sig
, void *result
, void **args
, void *data
)
305 struct psi_jit_callback_info
*cb_info
= data
;
306 struct psi_call_frame_callback cb_data
;
308 assert(cb_info
->impl_info
->frame
);
310 cb_data
.cb
= cb_info
->let_exp
;
311 cb_data
.argc
= jit_type_num_params(sig
);
313 cb_data
.rval
= result
;
315 psi_call_frame_do_callback(cb_info
->impl_info
->frame
, &cb_data
);
318 static inline void psi_jit_callback_init(struct psi_jit_impl_info
*impl_info
,
319 struct psi_let_exp
*let_exp
)
321 struct psi_jit_context
*context
= impl_info
->context
->context
;
322 struct psi_jit_callback_info
*cb_info
;
323 struct psi_jit_decl_info
*decl_info
;
324 struct psi_let_callback
*cb
;
325 struct psi_let_func
*fn
= NULL
;
327 switch (let_exp
->kind
) {
328 case PSI_LET_CALLBACK
:
329 cb
= let_exp
->data
.callback
;
330 if (cb
->decl
->info
) {
331 decl_info
= cb
->decl
->info
;
333 decl_info
= psi_jit_decl_init(cb
->decl
);
336 cb_info
= calloc(1, sizeof(*cb_info
));
337 cb_info
->impl_info
= impl_info
;
338 cb_info
->let_exp
= let_exp
;
339 cb_info
->closure
= jit_closure_create(context
->jit
, decl_info
->signature
,
340 &psi_jit_callback
, cb_info
);
342 if (!cb_info
->closure
) {
348 assert(!cb
->decl
->sym
);
349 cb
->decl
->sym
= cb_info
->closure
;
355 fn
= let_exp
->data
.func
;
359 struct psi_let_exp
*inner_let
;
361 while (psi_plist_get(fn
->inner
, i
++, &inner_let
)) {
362 psi_jit_callback_init(impl_info
, inner_let
);
371 static inline void psi_jit_callback_dtor(struct psi_let_exp
*let_exp
) {
372 struct psi_let_callback
*cb
;
373 struct psi_let_func
*fn
= NULL
;
375 switch (let_exp
->kind
) {
376 case PSI_LET_CALLBACK
:
377 cb
= let_exp
->data
.callback
;
379 psi_jit_decl_dtor(cb
->decl
);
382 struct psi_jit_callback_info
*info
= cb
->info
;
385 /* The memory for the closure will be reclaimed when the context is destroyed.
386 free(info->closure); */
395 fn
= let_exp
->data
.func
;
400 struct psi_let_exp
*cb
;
402 while (psi_plist_get(fn
->inner
, i
++, &cb
)) {
403 psi_jit_callback_dtor(cb
);
412 static inline struct psi_jit_impl_info
*psi_jit_impl_init(struct psi_impl
* impl
,
413 struct psi_context
*C
)
415 struct psi_jit_context
*context
= C
->context
;
416 struct psi_jit_impl_info
*info
= calloc(1, sizeof(*info
));
417 struct psi_let_stmt
*let
;
421 info
->closure
= jit_closure_create(context
->jit
, context
->signature
,
422 &psi_jit_handler
, impl
);
424 if (!info
->closure
) {
429 while (psi_plist_get(impl
->stmts
.let
, l
++, &let
)) {
430 psi_jit_callback_init(info
, let
->exp
);
433 return impl
->info
= info
;
437 static inline void psi_jit_impl_dtor(struct psi_impl
*impl
) {
438 struct psi_jit_impl_info
*info
= impl
->info
;
439 struct psi_let_stmt
*let
;
442 while (psi_plist_get(impl
->stmts
.let
, j
++, &let
)) {
443 psi_jit_callback_dtor(let
->exp
);
448 /* The memory for the closure will be reclaimed when the context is destroyed.
449 free(info->closure); */
456 static inline struct psi_jit_context
*psi_jit_context_init(
457 struct psi_jit_context
*L
)
459 jit_type_t params
[] = {jit_type_void_ptr
, jit_type_void_ptr
};
462 L
= malloc(sizeof(*L
));
464 memset(L
, 0, sizeof(*L
));
466 L
->jit
= jit_context_create();
467 L
->signature
= jit_type_create_signature(jit_abi_cdecl
, jit_type_void
,
473 static inline void psi_jit_context_dtor(struct psi_jit_context
*L
)
475 jit_type_free(L
->signature
);
476 jit_context_destroy(L
->jit
);
479 static inline void psi_jit_context_free(struct psi_jit_context
**L
)
482 psi_jit_context_dtor(*L
);
488 static void psi_jit_init(struct psi_context
*C
)
490 C
->context
= psi_jit_context_init(NULL
);
493 static void psi_jit_dtor(struct psi_context
*C
)
497 struct psi_decl
*decl
;
499 while (psi_plist_get(C
->decls
, i
++, &decl
)) {
500 psi_jit_decl_dtor(decl
);
505 struct psi_impl
*impl
;
507 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
508 psi_jit_impl_dtor(impl
);
511 psi_jit_context_free((void *) &C
->context
);
514 static zend_function_entry
*psi_jit_compile(struct psi_context
*C
)
516 size_t i
= 0, d
= 0, nf
= 0;
517 struct psi_impl
*impl
;
518 struct psi_decl
*decl
;
519 zend_function_entry
*zfe
;
520 struct psi_jit_context
*ctx
= C
->context
;
526 zfe
= calloc(psi_plist_count(C
->impls
) + 1, sizeof(*zfe
));
527 jit_context_build_start(ctx
->jit
);
529 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
530 zend_function_entry
*zf
= &zfe
[nf
];
535 if (!psi_jit_decl_init(impl
->decl
)) {
538 if (!psi_jit_impl_init(impl
, C
)) {
542 zf
->fname
= impl
->func
->name
+ (impl
->func
->name
[0] == '\\');
543 zf
->handler
= ((struct psi_jit_impl_info
*) impl
->info
)->closure
;
544 zf
->num_args
= psi_plist_count(impl
->func
->args
);
545 zf
->arg_info
= psi_internal_arginfo(impl
);
549 while (psi_plist_get(C
->decls
, d
++, &decl
)) {
554 psi_jit_decl_init(decl
);
557 jit_context_build_end(ctx
->jit
);
562 static inline void psi_jit_call_ex(struct psi_call_frame
*frame
) {
563 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
564 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
565 struct psi_jit_decl_info
*decl_info
= decl
->info
;
566 struct psi_jit_impl_info
*impl_info
;
567 struct psi_call_frame
*prev
;
570 impl_info
= impl
->info
;
571 prev
= impl_info
->frame
;
572 impl_info
->frame
= frame
;
574 jit_apply(decl_info
->signature
, decl
->sym
,
575 psi_call_frame_get_arg_pointers(frame
), psi_plist_count(decl
->args
),
576 psi_call_frame_get_rpointer(frame
));
578 impl_info
->frame
= prev
;
582 static inline void psi_jit_call_va(struct psi_call_frame
*frame
) {
583 jit_type_t signature
;
584 struct psi_call_frame
*prev
;
585 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
586 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
587 struct psi_jit_decl_info
*decl_info
= decl
->info
;
588 struct psi_jit_impl_info
*impl_info
;
589 size_t i
, va_count
, argc
;
590 jit_type_t
*param_types
;
592 argc
= psi_plist_count(decl
->args
);
593 va_count
= psi_call_frame_num_var_args(frame
);
594 param_types
= ecalloc(argc
+ va_count
+ 1, sizeof(jit_type_t
));
595 memcpy(param_types
, decl_info
->params
, argc
* sizeof(jit_type_t
));
596 for (i
= 0; i
< va_count
; ++i
) {
597 struct psi_call_frame_argument
*frame_arg
;
599 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
600 param_types
[argc
+ i
] = psi_jit_impl_type(frame_arg
->va_type
);
603 signature
= jit_type_create_signature(jit_abi_vararg
,
604 jit_type_get_return(decl_info
->signature
),
605 param_types
, argc
+ va_count
,
610 impl_info
= impl
->info
;
611 prev
= impl_info
->frame
;
612 impl_info
->frame
= frame
;
614 jit_apply(signature
, decl
->sym
,
615 psi_call_frame_get_arg_pointers(frame
), argc
,
616 psi_call_frame_get_rpointer(frame
));
618 impl_info
->frame
= prev
;
621 jit_type_free(signature
);
626 static void psi_jit_call(struct psi_call_frame
*frame
) {
627 if (psi_call_frame_num_var_args(frame
)) {
628 psi_jit_call_va(frame
);
630 psi_jit_call_ex(frame
);
634 static void *psi_jit_query(struct psi_context
*C
, enum psi_context_query q
,
638 case PSI_CONTEXT_QUERY_SELF
:
640 case PSI_CONTEXT_QUERY_TYPE
:
641 return psi_jit_impl_type(*(token_t
*) arg
);
646 static struct psi_context_ops ops
= {
654 struct psi_context_ops
*psi_libjit_ops(void)
659 #endif /* HAVE_LIBJIT */