cppcheck: fix possible null deref and unused structs
[m6w6/ext-psi] / src / libjit.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #else
4 # include "php_config.h"
5 #endif
6
7 #include "php.h"
8
9 #ifdef HAVE_LIBJIT
10
11 #include "php_psi.h"
12 #include "libjit.h"
13 #include "engine.h"
14
15 #include <jit/jit.h>
16
17 static void psi_jit_handler(jit_type_t _sig, void *_result, void **_args, void *_data)
18 {
19 psi_call(*(zend_execute_data **)_args[0], *(zval **)_args[1], _data);
20 }
21
22 static void psi_jit_callback(jit_type_t _sig, void *_result, void **_args, void *_data)
23 {
24 psi_callback(_data, _result, jit_type_num_params(_sig), _args);
25 }
26
27 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg);
28
29 static inline jit_abi_t psi_jit_abi(const char *convention) {
30 return jit_abi_cdecl;
31 }
32 static inline jit_type_t psi_jit_token_type(token_t t) {
33 switch (t) {
34 default:
35 ZEND_ASSERT(0);
36 /* no break */
37 case PSI_T_VOID:
38 return jit_type_void;
39 case PSI_T_INT8:
40 return jit_type_sbyte;
41 case PSI_T_UINT8:
42 return jit_type_ubyte;
43 case PSI_T_INT16:
44 return jit_type_short;
45 case PSI_T_UINT16:
46 return jit_type_ushort;
47 case PSI_T_INT32:
48 return jit_type_int;
49 case PSI_T_UINT32:
50 return jit_type_uint;
51 case PSI_T_INT64:
52 return jit_type_long;
53 case PSI_T_UINT64:
54 return jit_type_ulong;
55 case PSI_T_BOOL:
56 return jit_type_sys_bool;
57 case PSI_T_INT:
58 case PSI_T_ENUM:
59 return jit_type_sys_int;
60 case PSI_T_LONG:
61 return jit_type_sys_long;
62 case PSI_T_FLOAT:
63 return jit_type_sys_float;
64 case PSI_T_DOUBLE:
65 return jit_type_sys_double;
66 #ifdef HAVE_LONG_DOUBLE
67 case PSI_T_LONG_DOUBLE:
68 return jit_type_sys_long_double;
69 #endif
70 case PSI_T_POINTER:
71 case PSI_T_FUNCTION:
72 return jit_type_void_ptr;
73 }
74 }
75 static inline jit_type_t psi_jit_impl_type(token_t impl_type) {
76 switch (impl_type) {
77 case PSI_T_BOOL:
78 return jit_type_sbyte;
79 case PSI_T_INT:
80 return jit_type_long;
81 case PSI_T_STRING:
82 return jit_type_void_ptr;
83 case PSI_T_FLOAT:
84 case PSI_T_DOUBLE:
85 return jit_type_sys_double;
86 EMPTY_SWITCH_DEFAULT_CASE();
87 }
88 return NULL;
89 }
90
91 static void psi_jit_struct_type_dtor(void *type) {
92 jit_type_t strct = type;
93
94 jit_type_free(strct);
95 }
96
97 static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding) {
98 size_t i;
99
100 for (i = 0; i < padding; ++i) {
101 *els++ = jit_type_copy(jit_type_sys_char);
102 }
103
104 return padding;
105 }
106
107 static unsigned psi_jit_struct_type_elements(decl_struct *strct, jit_type_t **fields) {
108 size_t i, argc = strct->args->count, nels = 0, offset = 0, maxalign;
109 *fields = calloc(argc + 1, sizeof(*fields));
110
111 for (i = 0; i < strct->args->count; ++i) {
112 decl_arg *darg = strct->args->args[i];
113 jit_type_t type = jit_type_copy(psi_jit_decl_arg_type(darg));
114 size_t padding, alignment;
115
116 ZEND_ASSERT(jit_type_get_size(type) == darg->layout->len);
117
118 if ((alignment = jit_type_get_alignment(type)) > maxalign) {
119 maxalign = alignment;
120 }
121
122 if ((padding = psi_offset_padding(darg->layout->pos - offset, alignment))) {
123 if (nels + padding > argc) {
124 argc += padding;
125 *fields = realloc(*fields, (argc + 1) * sizeof(*fields));
126 }
127 psi_jit_struct_type_pad(&(*fields)[nels], padding);
128 nels += padding;
129 offset += padding;
130 }
131 ZEND_ASSERT(offset == darg->layout->pos);
132
133 offset = (offset + darg->layout->len + alignment - 1) & ~(alignment - 1);
134 (*fields)[nels++] = type;
135 }
136
137 /* apply struct alignment padding */
138 offset = (offset + maxalign - 1) & ~(maxalign - 1);
139
140 ZEND_ASSERT(offset <= strct->size);
141 if (offset < strct->size) {
142 nels += psi_jit_struct_type_pad(&(*fields)[nels], strct->size - offset);
143 }
144
145 return nels;
146 }
147 static inline jit_type_t psi_jit_decl_type(decl_type *type) {
148 decl_type *real = real_decl_type(type);
149
150 switch (real->type) {
151 case PSI_T_STRUCT:
152 if (!real->real.strct->engine.type) {
153 unsigned count;
154 jit_type_t strct, *fields = NULL;
155
156 count = psi_jit_struct_type_elements(real->real.strct, &fields);
157 strct = jit_type_create_struct(fields, count, 0);
158
159 real->real.strct->engine.type = strct;
160 real->real.strct->engine.dtor = psi_jit_struct_type_dtor;
161 }
162
163 return real->real.strct->engine.type;
164
165 case PSI_T_UNION:
166 return psi_jit_decl_arg_type(real->real.unn->args->args[0]);
167
168 default:
169 return psi_jit_token_type(real->type);
170 }
171 }
172 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) {
173 if (darg->var->pointer_level) {
174 return jit_type_void_ptr;
175 } else {
176 return psi_jit_decl_type(darg->type);
177 }
178 }
179
180 struct psi_jit_context {
181 jit_context_t jit;
182 jit_type_t signature;
183 };
184
185 struct psi_jit_call {
186 void *closure;
187 jit_type_t signature;
188 void *params[1]; /* [type1, type2, NULL, arg1, arg2] ... */
189 };
190
191 static inline struct psi_jit_call *psi_jit_call_alloc(struct psi_context *C, decl *decl) {
192 size_t i, c = decl->args ? decl->args->count : 0;
193 struct psi_jit_call *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
194
195 for (i = 0; i < c; ++i) {
196 call->params[i] = psi_jit_decl_arg_type(decl->args->args[i]);
197 }
198 call->params[c] = NULL;
199
200 decl->call.info = call;
201 decl->call.rval = &decl->func->ptr;
202 decl->call.argc = c;
203 decl->call.args = (void **) &call->params[c+1];
204
205 call->signature = jit_type_create_signature(
206 psi_jit_abi(decl->abi->convention),
207 psi_jit_decl_arg_type(decl->func),
208 (jit_type_t *) call->params, c, 1);
209 ZEND_ASSERT(call->signature);
210
211 return call;
212 }
213
214 static inline void *psi_jit_call_init_closure(struct psi_context *C, struct psi_jit_call *call, impl *impl) {
215 struct psi_jit_context *context = C->context;
216 return call->closure = jit_closure_create(context->jit, context->signature,
217 &psi_jit_handler, impl);
218 }
219
220 static inline void *psi_jit_call_init_callback_closure(struct psi_context *C, struct psi_jit_call *call, let_callback *cb) {
221 struct psi_jit_context *context = C->context;
222 return call->closure = jit_closure_create(context->jit, call->signature,
223 &psi_jit_callback, cb);
224 }
225
226 static inline void psi_jit_call_free(struct psi_jit_call *call) {
227 jit_type_free(call->signature);
228 free(call);
229 }
230
231 static inline struct psi_jit_context *psi_jit_context_init(struct psi_jit_context *L) {
232 jit_type_t params[] = {
233 jit_type_void_ptr,
234 jit_type_void_ptr
235 };
236
237 if (!L) {
238 L = malloc(sizeof(*L));
239 }
240 memset(L, 0, sizeof(*L));
241
242 L->jit = jit_context_create();
243 L->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void,
244 params, 2, 1);
245
246 return L;
247 }
248
249 static inline void psi_jit_context_dtor(struct psi_jit_context *L) {
250 jit_type_free(L->signature);
251 jit_context_destroy(L->jit);
252 }
253
254 static inline void psi_jit_context_free(struct psi_jit_context **L) {
255 if (*L) {
256 psi_jit_context_dtor(*L);
257 free(*L);
258 *L = NULL;
259 }
260 }
261
262 static void psi_jit_init(struct psi_context *C)
263 {
264 C->context = psi_jit_context_init(NULL);
265 }
266
267 static inline void psi_jit_destroy_callbacks(struct psi_context *C, let_val *let_val) {
268 let_callback *cb;
269 let_func *fn = NULL;
270
271 switch (let_val->kind) {
272 case PSI_LET_CALLBACK:
273 cb = let_val->data.callback;
274
275 if (cb->decl && cb->decl->call.info) {
276 psi_jit_call_free(cb->decl->call.info);
277 }
278 fn = cb->func;
279 /* no break */
280 case PSI_LET_FUNC:
281 if (!fn) {
282 fn = let_val->data.func;
283 }
284
285 if (fn->inner) {
286 size_t i;
287
288 for (i = 0; i < fn->inner->count; ++i) {
289 psi_jit_destroy_callbacks(C, fn->inner->vals[i]);
290 }
291 }
292 break;
293 default:
294 break;
295 }
296 }
297
298 static void psi_jit_dtor(struct psi_context *C)
299 {
300 if (C->decls) {
301 size_t i;
302
303 for (i = 0; i < C->decls->count; ++i) {
304 decl *decl = C->decls->list[i];
305
306 if (decl->call.info) {
307 psi_jit_call_free(decl->call.info);
308 }
309 }
310 }
311 if (C->impls) {
312 size_t i, j;
313
314 for (i = 0; i < C->impls->count; ++i) {
315 impl *impl = C->impls->list[i];
316
317 for (j = 0; j < impl->stmts->let.count; ++j) {
318 psi_jit_destroy_callbacks(C, impl->stmts->let.list[j]->val);
319 }
320 }
321 }
322 psi_jit_context_free((void *) &C->context);
323 }
324
325 static inline void psi_jit_compile_callbacks(struct psi_context *C, let_val *let_val) {
326 struct psi_jit_call *call;
327 let_callback *cb;
328 let_func *fn = NULL;
329
330 switch (let_val->kind) {
331 case PSI_LET_CALLBACK:
332 cb = let_val->data.callback;
333 if ((call = psi_jit_call_alloc(C, cb->decl))) {
334 if (!psi_jit_call_init_callback_closure(C, call, cb)) {
335 psi_jit_call_free(call);
336 break;
337 }
338
339 cb->decl->call.sym = call->closure;
340 }
341 fn = cb->func;
342 /* no break */
343 case PSI_LET_FUNC:
344 if (!fn) {
345 fn = let_val->data.func;
346 }
347 if (fn->inner) {
348 size_t i;
349
350 for (i = 0; i < fn->inner->count; ++i) {
351 psi_jit_compile_callbacks(C, fn->inner->vals[i]);
352 }
353 }
354 break;
355 default:
356 break;
357 }
358 }
359
360 static zend_function_entry *psi_jit_compile(struct psi_context *C)
361 {
362 size_t c, i, j = 0;
363 zend_function_entry *zfe;
364 struct psi_jit_context *ctx = C->context;
365
366 if (!C->impls) {
367 return NULL;
368 }
369
370 zfe = calloc(C->impls->count + 1, sizeof(*zfe));
371 jit_context_build_start(ctx->jit);
372
373 for (i = 0; i < C->impls->count; ++i) {
374 zend_function_entry *zf = &zfe[j];
375 struct psi_jit_call *call;
376 impl *impl = C->impls->list[i];
377
378 if (!impl->decl) {
379 continue;
380 }
381 if (!(call = psi_jit_call_alloc(C, impl->decl))) {
382 continue;
383 }
384 if (!psi_jit_call_init_closure(C, call, impl)) {
385 psi_jit_call_free(call);
386 continue;
387 }
388
389 zf->fname = impl->func->name + (impl->func->name[0] == '\\');
390 zf->num_args = impl->func->args->count;
391 zf->handler = call->closure;
392 zf->arg_info = psi_internal_arginfo(impl);
393 ++j;
394
395 for (c = 0; c < impl->stmts->let.count; ++c) {
396 psi_jit_compile_callbacks(C, impl->stmts->let.list[c]->val);
397 }
398 }
399
400 for (i = 0; i < C->decls->count; ++i) {
401 decl *decl = C->decls->list[i];
402
403 if (decl->call.info) {
404 continue;
405 }
406
407 psi_jit_call_alloc(C, decl);
408 }
409
410 jit_context_build_end(ctx->jit);
411
412 return zfe;
413 }
414
415 static void psi_jit_call(struct psi_context *C, decl_callinfo *decl_call, impl_vararg *va) {
416 struct psi_jit_call *call = decl_call->info;
417
418 if (va) {
419 jit_type_t signature;
420 size_t i, nfixedargs = decl_call->argc, ntotalargs = nfixedargs + va->args->count;
421 void **params = calloc(2 * ntotalargs + 2, sizeof(void *));
422
423 for (i = 0; i < nfixedargs; ++i) {
424 params[i] = call->params[i];
425 params[i + ntotalargs + 1] = call->params[i + nfixedargs + 1];
426 }
427 for (i = 0; i < va->args->count; ++i) {
428 params[nfixedargs + i] = psi_jit_impl_type(va->types[i]);
429 params[nfixedargs + i + ntotalargs + 1] = &va->values[i];
430 }
431
432 signature = jit_type_create_signature(
433 jit_type_get_abi(call->signature),
434 jit_type_get_return(call->signature),
435 (jit_type_t *) params, ntotalargs, 1);
436 ZEND_ASSERT(signature);
437
438 jit_apply(signature, decl_call->sym, &params[ntotalargs + 1],
439 nfixedargs, *decl_call->rval);
440 jit_type_free(signature);
441 free(params);
442 } else {
443 jit_apply(call->signature, decl_call->sym, decl_call->args,
444 decl_call->argc, *decl_call->rval);
445 }
446 }
447
448 static struct psi_context_ops ops = {
449 psi_jit_init,
450 psi_jit_dtor,
451 psi_jit_compile,
452 psi_jit_call,
453 };
454
455 struct psi_context_ops *psi_libjit_ops(void)
456 {
457 return &ops;
458 }
459
460 #endif /* HAVE_LIBJIT */