45ee8e766c34a8153439cee6351cb4617c4782ee
[m6w6/ext-psi] / src / libjit.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include "php.h"
6
7 #ifdef HAVE_LIBJIT
8
9 #include "php_psi.h"
10 #include "libjit.h"
11
12 #include <jit/jit.h>
13
14 static void psi_jit_handler(jit_type_t _sig, void *result, void **_args, void *_data);
15
16 static inline jit_abi_t psi_jit_abi(const char *convention) {
17 return jit_abi_cdecl;
18 }
19 static inline jit_type_t psi_jit_token_type(token_t t) {
20 switch (t) {
21 case PSI_T_VOID:
22 return jit_type_void;
23 case PSI_T_INT8:
24 return jit_type_sbyte;
25 case PSI_T_UINT8:
26 return jit_type_ubyte;
27 case PSI_T_INT16:
28 return jit_type_short;
29 case PSI_T_UINT16:
30 return jit_type_ushort;
31 case PSI_T_INT32:
32 return jit_type_int;
33 case PSI_T_UINT32:
34 return jit_type_uint;
35 case PSI_T_INT64:
36 return jit_type_long;
37 case PSI_T_UINT64:
38 return jit_type_ulong;
39 case PSI_T_BOOL:
40 return jit_type_sys_bool;
41 case PSI_T_FLOAT:
42 return jit_type_sys_float;
43 case PSI_T_DOUBLE:
44 return jit_type_sys_double;
45 EMPTY_SWITCH_DEFAULT_CASE();
46 }
47 }
48 static inline jit_type_t psi_jit_decl_type(decl_type *type) {
49 return psi_jit_token_type(real_decl_type(type)->type);
50 }
51 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) {
52 if (darg->var->pointer_level) {
53 return jit_type_void_ptr;
54 } else {
55 return psi_jit_decl_type(darg->type);
56 }
57 }
58
59 typedef struct PSI_LibjitContext {
60 jit_context_t jit;
61 jit_type_t signature;
62 struct {
63 struct PSI_LibjitData **list;
64 size_t count;
65 } data;
66 } PSI_LibjitContext;
67
68 typedef struct PSI_LibjitCall {
69 void *closure;
70 jit_type_t signature;
71 jit_type_t params[1]; /* [type1, type2, NULL, arg1, arg2] ... */
72 } PSI_LibjitCall;
73
74 typedef struct PSI_LibjitData {
75 PSI_LibjitContext *context;
76 impl *impl;
77 zend_internal_arg_info *arginfo;
78 } PSI_LibjitData;
79
80 static inline PSI_LibjitCall *PSI_LibjitCallAlloc(PSI_Context *C, decl *decl) {
81 size_t i, c = decl->args ? decl->args->count : 0;
82 PSI_LibjitCall *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
83
84 for (i = 0; i < c; ++i) {
85 call->params[i] = psi_jit_decl_arg_type(decl->args->args[i]);
86 }
87 call->params[c] = NULL;
88
89 decl->call.info = call;
90 decl->call.args = (void **) &call->params[c+1];
91
92 call->signature = jit_type_create_signature(
93 psi_jit_abi(decl->abi->convention),
94 psi_jit_decl_arg_type(decl->func),
95 call->params, c, 1);
96 return call;
97 }
98
99 static inline void PSI_LibjitCallInitClosure(PSI_Context *C, PSI_LibjitCall *call, impl *impl) {
100 PSI_LibjitContext *context = C->context;
101 call->closure = jit_closure_create(context->jit, context->signature,
102 &psi_jit_handler, impl);
103 }
104
105 static inline void PSI_LibjitCallFree(PSI_LibjitCall *call) {
106 jit_type_free(call->signature);
107 }
108
109 static inline PSI_LibjitContext *PSI_LibjitContextInit(PSI_LibjitContext *L) {
110 jit_type_t params[] = {
111 jit_type_void_ptr,
112 jit_type_void_ptr
113 };
114
115 if (!L) {
116 L = malloc(sizeof(*L));
117 }
118 memset(L, 0, sizeof(*L));
119
120 L->jit = jit_context_create();
121 L->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void,
122 params, 2, 1);
123
124 return L;
125 }
126
127 static inline void PSI_LibjitContextDtor(PSI_LibjitContext *L) {
128 jit_type_free(L->signature);
129 jit_context_destroy(L->jit);
130 }
131
132 static inline void PSI_LibjitContextFree(PSI_LibjitContext **L) {
133 if (*L) {
134 PSI_LibjitContextDtor(*L);
135 free(*L);
136 *L = NULL;
137 }
138 }
139
140 static void psi_jit_handler(jit_type_t _sig, void *result, void **_args, void *_data)
141 {
142 psi_call(*(zend_execute_data **)_args[0], *(zval **)_args[1], _data);
143 }
144
145 static void psi_jit_init(PSI_Context *C)
146 {
147 C->context = PSI_LibjitContextInit(NULL);
148 }
149
150 static void psi_jit_dtor(PSI_Context *C)
151 {
152 if (C->decls) {
153 size_t i;
154
155 for (i = 0; i < C->decls->count; ++i) {
156 decl *decl = C->decls->list[i];
157
158 PSI_LibjitCallFree(decl->call.info);
159 }
160 }
161 PSI_LibjitContextFree((void *) &C->context);
162 }
163
164 static zend_function_entry *psi_jit_compile(PSI_Context *C)
165 {
166 size_t i, j = 0;
167 zend_function_entry *zfe;
168 PSI_LibjitContext *ctx = C->context;
169
170 if (!C->impls) {
171 return NULL;
172 }
173
174 zfe = calloc(C->impls->count + 1, sizeof(*zfe));
175 jit_context_build_start(ctx->jit);
176
177 for (i = 0; i < C->impls->count; ++i) {
178 zend_function_entry *zf = &zfe[j];
179 PSI_LibjitCall *call;
180 impl *impl = C->impls->list[i];
181
182 if (!impl->decl) {
183 continue;
184 }
185
186 call = PSI_LibjitCallAlloc(C, impl->decl);
187 PSI_LibjitCallInitClosure(C, call, impl);
188
189 zf->fname = impl->func->name + (impl->func->name[0] == '\\');
190 zf->num_args = impl->func->args->count;
191 zf->handler = call->closure;
192 zf->arg_info = psi_internal_arginfo(impl);
193 ++j;
194 }
195
196 for (i = 0; i < C->decls->count; ++i) {
197 decl *decl = C->decls->list[i];
198
199 if (decl->impl) {
200 continue;
201 }
202
203 PSI_LibjitCallAlloc(C, decl);
204 }
205
206 jit_context_build_end(ctx->jit);
207
208 return zfe;
209 }
210
211 static void psi_jit_call(PSI_Context *C, impl_val *ret_val, decl *decl) {
212 PSI_LibjitCall *call = decl->call.info;
213
214 jit_apply(call->signature, decl->call.sym, decl->call.args,
215 decl->args->count, ret_val);
216 }
217
218 static PSI_ContextOps ops = {
219 psi_jit_init,
220 psi_jit_dtor,
221 psi_jit_compile,
222 psi_jit_call,
223 };
224
225 PSI_ContextOps *PSI_Libjit(void)
226 {
227 return &ops;
228 }
229
230 #endif /* HAVE_LIBJIT */