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_abi_t
psi_jit_abi(const char *convention
)
39 if (!strcasecmp(convention
, "stdcall")) {
40 return jit_abi_stdcall
;
42 if (!strcasecmp(convention
, "fastcall")) {
43 return jit_abi_fastcall
;
47 static inline jit_type_t
psi_jit_token_type(token_t t
)
56 return jit_type_sbyte
;
58 return jit_type_ubyte
;
60 return jit_type_short
;
62 return jit_type_ushort
;
70 return jit_type_ulong
;
72 return jit_type_sys_bool
;
75 return jit_type_sys_int
;
77 return jit_type_sys_long
;
79 return jit_type_sys_float
;
81 return jit_type_sys_double
;
82 #ifdef HAVE_LONG_DOUBLE
83 case PSI_T_LONG_DOUBLE
:
84 return jit_type_sys_long_double
;
88 return jit_type_void_ptr
;
91 static inline jit_type_t
psi_jit_impl_type(token_t impl_type
)
95 return jit_type_sbyte
;
99 return jit_type_void_ptr
;
102 return jit_type_sys_double
;
103 EMPTY_SWITCH_DEFAULT_CASE()
109 static void psi_jit_struct_type_dtor(void *type
)
111 jit_type_t strct
= type
;
113 jit_type_free(strct
);
116 static size_t psi_jit_struct_type_pad(jit_type_t
*els
, size_t padding
)
120 for (i
= 0; i
< padding
; ++i
) {
121 *els
++ = jit_type_copy(jit_type_sys_char
);
127 static unsigned psi_jit_struct_type_elements(struct psi_decl_struct
*strct
,
130 size_t i
= 0, argc
= psi_plist_count(strct
->args
), nels
= 0, offset
= 0,
131 maxalign
, last_arg_pos
= -1;
132 struct psi_decl_arg
*darg
;
134 *fields
= calloc(argc
+ 1, sizeof(*fields
));
136 while (psi_plist_get(strct
->args
, i
++, &darg
)) {
138 size_t padding
, alignment
;
140 if (darg
->layout
->pos
== last_arg_pos
) {
141 /* skip bit fields */
144 last_arg_pos
= darg
->layout
->pos
;
146 type
= jit_type_copy(psi_jit_decl_arg_type(darg
));
148 if ((alignment
= jit_type_get_alignment(type
)) > maxalign
) {
149 maxalign
= alignment
;
152 assert(jit_type_get_size(type
) == darg
->layout
->len
);
153 if ((padding
= psi_offset_padding(darg
->layout
->pos
- offset
, alignment
))) {
154 if (nels
+ padding
> argc
) {
156 *fields
= realloc(*fields
, (argc
+ 1) * sizeof(*fields
));
158 psi_jit_struct_type_pad(&(*fields
)[nels
], padding
);
162 assert(offset
== darg
->layout
->pos
);
164 offset
= (offset
+ darg
->layout
->len
+ alignment
- 1)
166 (*fields
)[nels
++] = type
;
169 /* apply struct alignment padding */
170 offset
= (offset
+ maxalign
- 1) & ~(maxalign
- 1);
172 assert(offset
<= strct
->size
);
173 if (offset
< strct
->size
) {
174 nels
+= psi_jit_struct_type_pad(&(*fields
)[nels
], strct
->size
- offset
);
179 static inline jit_type_t
psi_jit_decl_type(struct psi_decl_type
*type
)
181 struct psi_decl_type
*real
= psi_decl_type_get_real(type
);
183 switch (real
->type
) {
185 if (!real
->real
.strct
->engine
.type
) {
187 jit_type_t strct
, *fields
= NULL
;
189 count
= psi_jit_struct_type_elements(real
->real
.strct
, &fields
);
190 strct
= jit_type_create_struct(fields
, count
, 0);
192 real
->real
.strct
->engine
.type
= strct
;
193 real
->real
.strct
->engine
.dtor
= psi_jit_struct_type_dtor
;
196 return real
->real
.strct
->engine
.type
;
200 struct psi_decl_arg
*arg
;
201 psi_plist_get(real
->real
.unn
->args
, 0, &arg
);
202 return psi_jit_decl_arg_type(arg
);
206 return psi_jit_token_type(real
->type
);
209 static inline jit_type_t
psi_jit_decl_arg_type(struct psi_decl_arg
*darg
)
211 if (darg
->var
->pointer_level
) {
212 return jit_type_void_ptr
;
214 return psi_jit_decl_type(darg
->type
);
218 struct psi_jit_context
{
220 jit_type_t signature
;
223 struct psi_jit_call
{
224 struct psi_context
*context
;
227 struct psi_impl
*impl
;
228 struct psi_call_frame
*frame
;
231 struct psi_let_exp
*let_exp
;
232 struct psi_jit_call
*impl_call
;
236 jit_type_t signature
;
237 void *params
[1]; /* [type1, type2, ... ] */
240 static void psi_jit_handler(jit_type_t sig
, void *result
, void **args
, void *data
)
242 struct psi_jit_call
*call
= data
;
244 psi_context_call(call
->context
, *(zend_execute_data
**)args
[0], *(zval
**) args
[1], call
->impl
.fn
.impl
);
247 static void psi_jit_callback(jit_type_t sig
, void *result
, void **args
,
250 struct psi_jit_call
*call
= data
, *impl_call
= call
->impl
.cb
.impl_call
;
251 struct psi_call_frame_callback cbdata
;
253 cbdata
.cb
= call
->impl
.cb
.let_exp
;
254 cbdata
.argc
= jit_type_num_params(sig
);
256 cbdata
.rval
= result
;
258 psi_call_frame_do_callback(impl_call
->impl
.fn
.frame
, &cbdata
);
261 static inline struct psi_jit_call
*psi_jit_call_alloc(struct psi_context
*C
,
262 struct psi_decl
*decl
)
264 size_t i
, c
= psi_plist_count(decl
->args
);
265 struct psi_jit_call
*call
= calloc(1, sizeof(*call
) + 2 * c
* sizeof(void *));
266 struct psi_decl_arg
*arg
;
270 for (i
= 0; psi_plist_get(decl
->args
, i
, &arg
); ++i
) {
271 call
->params
[i
] = psi_jit_decl_arg_type(arg
);
273 call
->params
[c
] = NULL
;
275 call
->signature
= jit_type_create_signature(
276 psi_jit_abi(decl
->abi
->convention
),
277 psi_jit_decl_arg_type(decl
->func
),
278 (jit_type_t
*) call
->params
,
280 assert(call
->signature
);
285 static inline void *psi_jit_call_init_closure(struct psi_context
*C
,
286 struct psi_jit_call
*call
, struct psi_impl
*impl
)
288 struct psi_jit_context
*context
= C
->context
;
290 call
->impl
.fn
.impl
= impl
;
291 return call
->closure
= jit_closure_create(context
->jit
, context
->signature
,
292 &psi_jit_handler
, call
);
295 static inline void *psi_jit_call_init_callback_closure(struct psi_context
*C
,
296 struct psi_jit_call
*call
, struct psi_jit_call
*impl_call
,
297 struct psi_let_exp
*cb
)
299 struct psi_jit_context
*context
= C
->context
;
301 call
->impl
.cb
.let_exp
= cb
;
302 call
->impl
.cb
.impl_call
= impl_call
;
304 return call
->closure
= jit_closure_create(context
->jit
, call
->signature
,
305 &psi_jit_callback
, call
);
308 static inline void psi_jit_call_free(struct psi_jit_call
*call
)
310 jit_type_free(call
->signature
);
314 static inline struct psi_jit_context
*psi_jit_context_init(
315 struct psi_jit_context
*L
)
317 jit_type_t params
[] = {jit_type_void_ptr
, jit_type_void_ptr
};
320 L
= malloc(sizeof(*L
));
322 memset(L
, 0, sizeof(*L
));
324 L
->jit
= jit_context_create();
325 L
->signature
= jit_type_create_signature(jit_abi_cdecl
, jit_type_void
,
331 static inline void psi_jit_context_dtor(struct psi_jit_context
*L
)
333 jit_type_free(L
->signature
);
334 jit_context_destroy(L
->jit
);
337 static inline void psi_jit_context_free(struct psi_jit_context
**L
)
340 psi_jit_context_dtor(*L
);
346 static void psi_jit_init(struct psi_context
*C
)
348 C
->context
= psi_jit_context_init(NULL
);
351 static inline void psi_jit_destroy_callbacks(struct psi_context
*C
,
352 struct psi_let_exp
*let_exp
)
354 struct psi_let_callback
*cb
;
355 struct psi_let_func
*fn
= NULL
;
357 switch (let_exp
->kind
) {
358 case PSI_LET_CALLBACK
:
359 cb
= let_exp
->data
.callback
;
361 if (cb
->decl
&& cb
->decl
->info
) {
362 psi_jit_call_free(cb
->decl
->info
);
368 fn
= let_exp
->data
.func
;
373 struct psi_let_exp
*inner_let
;
375 while (psi_plist_get(fn
->inner
, i
++, &inner_let
)) {
376 psi_jit_destroy_callbacks(C
, inner_let
);
385 static void psi_jit_dtor(struct psi_context
*C
)
389 struct psi_decl
*decl
;
391 while (psi_plist_get(C
->decls
, i
++, &decl
)) {
393 psi_jit_call_free(decl
->info
);
399 struct psi_impl
*impl
;
401 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
403 struct psi_let_stmt
*let
;
405 while (psi_plist_get(impl
->stmts
.let
, l
++, &let
)) {
406 psi_jit_destroy_callbacks(C
, let
->exp
);
410 psi_jit_context_free((void *) &C
->context
);
413 static inline void psi_jit_compile_callbacks(struct psi_context
*C
,
414 struct psi_jit_call
*impl_call
, struct psi_let_exp
*let_exp
)
416 struct psi_jit_call
*call
;
417 struct psi_let_callback
*cb
;
418 struct psi_let_func
*fn
= NULL
;
420 switch (let_exp
->kind
) {
421 case PSI_LET_CALLBACK
:
422 cb
= let_exp
->data
.callback
;
423 if ((call
= psi_jit_call_alloc(C
, cb
->decl
))) {
424 if (!psi_jit_call_init_callback_closure(C
, call
, impl_call
, let_exp
)) {
425 psi_jit_call_free(call
);
429 cb
->decl
->sym
= call
->closure
;
435 fn
= let_exp
->data
.func
;
439 struct psi_let_exp
*inner_let
;
441 while (psi_plist_get(fn
->inner
, i
++, &inner_let
)) {
442 psi_jit_compile_callbacks(C
, impl_call
, inner_let
);
451 static zend_function_entry
*psi_jit_compile(struct psi_context
*C
)
453 size_t i
= 0, d
= 0, nf
= 0;
454 struct psi_impl
*impl
;
455 struct psi_decl
*decl
;
456 zend_function_entry
*zfe
;
457 struct psi_jit_context
*ctx
= C
->context
;
463 zfe
= calloc(psi_plist_count(C
->impls
) + 1, sizeof(*zfe
));
464 jit_context_build_start(ctx
->jit
);
466 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
467 zend_function_entry
*zf
= &zfe
[nf
];
468 struct psi_jit_call
*call
;
470 struct psi_let_stmt
*let
;
475 if (!(call
= psi_jit_call_alloc(C
, impl
->decl
))) {
478 if (!psi_jit_call_init_closure(C
, call
, impl
)) {
479 psi_jit_call_free(call
);
483 zf
->fname
= impl
->func
->name
+ (impl
->func
->name
[0] == '\\');
484 zf
->handler
= call
->closure
;
485 zf
->num_args
= psi_plist_count(impl
->func
->args
);
486 zf
->arg_info
= psi_internal_arginfo(impl
);
489 while (psi_plist_get(impl
->stmts
.let
, l
++, &let
)) {
490 psi_jit_compile_callbacks(C
, call
, let
->exp
);
494 while (psi_plist_get(C
->decls
, d
++, &decl
)) {
499 psi_jit_call_alloc(C
, decl
);
502 jit_context_build_end(ctx
->jit
);
507 static void psi_jit_call(struct psi_context
*C
, struct psi_call_frame
*frame
,
508 struct psi_decl
*decl
, void *rval
, void **args
)
510 struct psi_jit_call
*call
= decl
->info
;
511 struct psi_call_frame
*prev
= call
->impl
.fn
.frame
;
513 call
->impl
.fn
.frame
= frame
;
514 jit_apply(call
->signature
, decl
->sym
, args
, psi_plist_count(decl
->args
), rval
);
515 call
->impl
.fn
.frame
= prev
;
518 static void psi_jit_call_va(struct psi_context
*C
, struct psi_call_frame
*frame
,
519 struct psi_decl
*decl
, void *rval
, void **args
, size_t va_count
,
522 struct psi_jit_call
*info
= decl
->info
;
523 struct psi_call_frame
*prev
= info
->impl
.fn
.frame
;
524 size_t argc
= psi_plist_count(decl
->args
);
525 jit_type_t signature
;
526 jit_type_t
*param_types
= ecalloc(argc
+ va_count
+ 1, sizeof(jit_type_t
));
528 memcpy(param_types
, info
->params
, argc
* sizeof(jit_type_t
));
529 memcpy(param_types
+ argc
, va_types
, va_count
* sizeof(jit_type_t
));
531 signature
= jit_type_create_signature(jit_abi_vararg
,
532 jit_type_get_return(info
->signature
), param_types
, argc
+ va_count
,
536 info
->impl
.fn
.frame
= frame
;
537 jit_apply(signature
, decl
->sym
, args
, argc
, rval
);
538 info
->impl
.fn
.frame
= prev
;
539 jit_type_free(signature
);
543 static void *psi_jit_query(struct psi_context
*C
, enum psi_context_query q
,
547 case PSI_CONTEXT_QUERY_SELF
:
549 case PSI_CONTEXT_QUERY_TYPE
:
550 return psi_jit_impl_type(*(token_t
*) arg
);
555 static struct psi_context_ops ops
= {psi_jit_init
, psi_jit_dtor
,
556 psi_jit_compile
, psi_jit_call
, psi_jit_call_va
, psi_jit_query
};
558 struct psi_context_ops
*psi_libjit_ops(void)
563 #endif /* HAVE_LIBJIT */