39d12917a0c3a183f342eeb3ccbbbb75457b7a18
[m6w6/ext-psi] / src / module.c
1
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5
6 #include "php.h"
7 #include "php_ini.h"
8 #include "ext/standard/info.h"
9 #include "zend_exceptions.h"
10 #include "zend_constants.h"
11 #include "zend_operators.h"
12
13 #include "php_psi.h"
14
15 #if HAVE_LIBJIT
16 # include "libjit.h"
17 # ifndef HAVE_LIBFFI
18 # define PSI_ENGINE "jit"
19 # endif
20 #endif
21 #if HAVE_LIBFFI
22 # include "libffi.h"
23 # define PSI_ENGINE "ffi"
24 #endif
25
26 ZEND_DECLARE_MODULE_GLOBALS(psi);
27
28 PHP_INI_BEGIN()
29 STD_PHP_INI_ENTRY("psi.engine", PSI_ENGINE, PHP_INI_SYSTEM, OnUpdateString, engine, zend_psi_globals, psi_globals)
30 STD_PHP_INI_ENTRY("psi.directory", "psi.d", PHP_INI_SYSTEM, OnUpdateString, directory, zend_psi_globals, psi_globals)
31 PHP_INI_END();
32
33 static zend_object_handlers psi_object_handlers;
34 static zend_class_entry *psi_class_entry;
35
36 void psi_error_wrapper(PSI_Token *t, int type, const char *msg, ...)
37 {
38 va_list argv;
39
40 va_start(argv, msg);
41 psi_verror(type, t?t->file:"Unknown", t?*t->line:0, msg, argv);
42 va_end(argv);
43 }
44 void psi_error(int type, const char *fn, unsigned ln, const char *msg, ...)
45 {
46 va_list argv;
47
48 va_start(argv, msg);
49 psi_verror(type, fn, ln, msg, argv);
50 va_end(argv);
51 }
52 void psi_verror(int type, const char *fn, unsigned ln, const char *msg, va_list argv)
53 {
54 zend_error_cb(type, fn, ln, msg, argv);
55 }
56
57 size_t psi_t_alignment(token_t t)
58 {
59 #define PSI_ALIGNOF(T) case PSI_T_## T: return ALIGNOF_## T ##_T;
60 switch (t) {
61 PSI_ALIGNOF(INT8);
62 PSI_ALIGNOF(UINT8);
63 PSI_ALIGNOF(INT16);
64 PSI_ALIGNOF(UINT16);
65 PSI_ALIGNOF(INT32);
66 PSI_ALIGNOF(UINT32);
67 PSI_ALIGNOF(INT64);
68 PSI_ALIGNOF(UINT64);
69 case PSI_T_FLOAT:
70 return ALIGNOF_FLOAT;
71 case PSI_T_DOUBLE:
72 return ALIGNOF_DOUBLE;
73 case PSI_T_POINTER:
74 return ALIGNOF_VOID_P;
75 EMPTY_SWITCH_DEFAULT_CASE();
76 }
77 return 0;
78 }
79
80 size_t psi_t_size(token_t t)
81 {
82 #define PSI_SIZEOF(T) case PSI_T_## T : return SIZEOF_## T ##_T;
83 switch (t) {
84 PSI_SIZEOF(INT8);
85 PSI_SIZEOF(UINT8);
86 PSI_SIZEOF(INT16);
87 PSI_SIZEOF(UINT16);
88 PSI_SIZEOF(INT32);
89 PSI_SIZEOF(UINT32);
90 PSI_SIZEOF(INT64);
91 PSI_SIZEOF(UINT64);
92 case PSI_T_FLOAT:
93 return SIZEOF_FLOAT;
94 case PSI_T_DOUBLE:
95 return SIZEOF_DOUBLE;
96 case PSI_T_POINTER:
97 return SIZEOF_VOID_P;
98 EMPTY_SWITCH_DEFAULT_CASE();
99 }
100 return 0;
101 }
102
103 size_t psi_t_align(token_t t, size_t s)
104 {
105 size_t a = psi_t_alignment(t);
106 return ((s - 1) | (a - 1)) + 1;
107 }
108
109 int psi_internal_type(impl_type *type)
110 {
111 switch (type->type) {
112 case PSI_T_BOOL:
113 return _IS_BOOL;
114 case PSI_T_INT:
115 return IS_LONG;
116 case PSI_T_FLOAT:
117 case PSI_T_DOUBLE:
118 return IS_DOUBLE;
119 case PSI_T_STRING:
120 return IS_STRING;
121 case PSI_T_ARRAY:
122 return IS_ARRAY;
123 default:
124 return 0;
125 }
126 }
127
128 zend_internal_arg_info *psi_internal_arginfo(impl *impl)
129 {
130 size_t i;
131 zend_internal_arg_info *aip;
132 zend_internal_function_info *fi;
133
134 aip = calloc(impl->func->args->count + 1 + !!impl->func->args->vararg.name, sizeof(*aip));
135
136 fi = (zend_internal_function_info *) &aip[0];
137 fi->allow_null = 1;
138 fi->required_num_args = psi_num_min_args(impl);
139 fi->return_reference = impl->func->return_reference;
140 fi->type_hint = psi_internal_type(impl->func->return_type);
141
142 if (impl->func->args->vararg.name) {
143 impl_arg *vararg = impl->func->args->vararg.name;
144 zend_internal_arg_info *ai = &aip[impl->func->args->count];
145
146 ai->name = vararg->var->name;
147 ai->type_hint = psi_internal_type(vararg->type);
148 if (vararg->var->reference) {
149 ai->pass_by_reference = 1;
150 }
151 ai->is_variadic = 1;
152 }
153
154 for (i = 0; i < impl->func->args->count; ++i) {
155 impl_arg *iarg = impl->func->args->args[i];
156 zend_internal_arg_info *ai = &aip[i+1];
157
158 ai->name = iarg->var->name;
159 ai->type_hint = psi_internal_type(iarg->type);
160 if (iarg->var->reference) {
161 ai->pass_by_reference = 1;
162 }
163 if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
164 ai->allow_null = 1;
165 }
166 }
167
168 return aip;
169 }
170
171 size_t psi_num_min_args(impl *impl)
172 {
173 size_t i, n = impl->func->args->count;
174
175 for (i = 0; i < impl->func->args->count; ++i) {
176 if (impl->func->args->args[i]->def) {
177 --n;
178 }
179 }
180 return n;
181 }
182
183 void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val)
184 {
185 RETVAL_NULL();
186 }
187
188 void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val)
189 {
190 psi_to_int(return_value, set, ret_val);
191 convert_to_boolean(return_value);
192 }
193
194 void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val)
195 {
196 decl_var *var = set->vars->vars[0];
197 token_t t = real_decl_type(var->arg->type)->type;
198 impl_val *v = deref_impl_val(ret_val, var);
199
200 switch (t) {
201 case PSI_T_FLOAT:
202 RETVAL_DOUBLE((double) v->fval);
203 convert_to_long(return_value);
204 break;
205 case PSI_T_DOUBLE:
206 RETVAL_DOUBLE(v->dval);
207 convert_to_long(return_value);
208 break;
209 case PSI_T_INT8:
210 RETVAL_LONG(v->i8);
211 break;
212 case PSI_T_UINT8:
213 RETVAL_LONG(v->u8);
214 break;
215 case PSI_T_INT16:
216 RETVAL_LONG(v->i16);
217 break;
218 case PSI_T_UINT16:
219 RETVAL_LONG(v->u16);
220 break;
221 case PSI_T_INT32:
222 RETVAL_LONG(v->i32);
223 break;
224 case PSI_T_UINT32:
225 #if UINT32_MAX >= ZEND_LONG_MAX
226 if (v->u32 > ZEND_LONG_MAX) {
227 char d[12] = {0};
228
229 RETVAL_STRING(zend_print_ulong_to_buf(&d[10], v->u32));
230 } else {
231 #endif
232 RETVAL_LONG(v->u32);
233 #if UINT32_MAX >= ZEND_LONG_MAX
234 }
235 #endif
236 break;
237 case PSI_T_INT64:
238 RETVAL_LONG(v->i64);
239 break;
240 case PSI_T_UINT64:
241 if (v->u64 > ZEND_LONG_MAX) {
242 char d[24] = {0};
243
244 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], v->u64));
245 } else {
246 RETVAL_LONG(v->u64);
247 }
248 break;
249 EMPTY_SWITCH_DEFAULT_CASE();
250 }
251 }
252
253 void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val)
254 {
255 decl_var *var = set->vars->vars[0];
256 token_t t = real_decl_type(var->arg->type)->type;
257 impl_val *v = deref_impl_val(ret_val, var);
258
259 switch (t) {
260 case PSI_T_FLOAT:
261 RETVAL_DOUBLE((double) v->fval);
262 break;
263 case PSI_T_DOUBLE:
264 RETVAL_DOUBLE(v->dval);
265 break;
266 case PSI_T_INT8:
267 RETVAL_DOUBLE((double) v->i8);
268 break;
269 case PSI_T_UINT8:
270 RETVAL_DOUBLE((double) v->u8);
271 break;
272 case PSI_T_INT16:
273 RETVAL_DOUBLE((double) v->i16);
274 break;
275 case PSI_T_UINT16:
276 RETVAL_DOUBLE((double) v->u16);
277 break;
278 case PSI_T_INT32:
279 RETVAL_DOUBLE((double) v->i32);
280 break;
281 case PSI_T_UINT32:
282 RETVAL_DOUBLE((double) v->u32);
283 break;
284 case PSI_T_INT64:
285 RETVAL_DOUBLE((double) v->i64);
286 break;
287 case PSI_T_UINT64:
288 RETVAL_DOUBLE((double) v->u64);
289 break;
290 EMPTY_SWITCH_DEFAULT_CASE();
291 }
292 }
293
294 void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val)
295 {
296 decl_var *var = set->vars->vars[0];
297 token_t t = real_decl_type(var->arg->type)->type;
298
299 switch (t) {
300 case PSI_T_VOID:
301 case PSI_T_INT8:
302 case PSI_T_UINT8:
303 if (!var->arg->var->pointer_level) {
304 RETVAL_STRINGL(&ret_val->cval, 1);
305 } else {
306 ret_val = deref_impl_val(ret_val, var);
307 if (ret_val && ret_val->ptr) {
308 if (set->num) {
309 RETVAL_STRINGL(ret_val->ptr, psi_long_num_exp(set->num, set->outer.val));
310 } else {
311 RETVAL_STRING(ret_val->ptr);
312 }
313 } else {
314 RETVAL_EMPTY_STRING();
315 }
316 }
317 return;
318 case PSI_T_FLOAT:
319 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval);
320 break;
321 case PSI_T_DOUBLE:
322 RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval);
323 break;
324 default:
325 psi_to_int(return_value, set, ret_val);
326 break;
327 }
328 convert_to_string(return_value);
329 }
330
331
332 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
333 {
334 memset(tmp, 0, sizeof(*tmp));
335 memcpy(tmp, ((void*) val->ptr) + size * i, size);
336 return tmp;
337 }
338
339 void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
340 {
341 decl_type *type = real_decl_type(spec->type);
342
343 switch (type->type) {
344 case PSI_T_FLOAT:
345 mem->fval = (float) zval_get_double(zv);
346 break;
347 case PSI_T_DOUBLE:
348 mem->dval = zval_get_double(zv);
349 break;
350 case PSI_T_INT8:
351 case PSI_T_UINT8:
352 if (spec->var->pointer_level) {
353 zend_string *zs = zval_get_string(zv);
354 *tmp = mem->ptr = estrndup(zs->val, zs->len);
355 zend_string_release(zs);
356 break;
357 }
358 /* no break */
359 default:
360 mem->zend.lval = zval_get_long(zv);
361 break;
362 }
363 }
364
365 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
366 {
367 size_t i, j = 0;
368 char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
369
370 if (arr) for (i = 0; i < s->args->count; ++i) {
371 decl_arg *darg = s->args->args[i];
372 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
373
374 if (entry) {
375 impl_val val;
376 void *tmp = NULL;
377
378 memset(&tmp, 0, sizeof(tmp));
379 psi_from_zval(&val, darg, entry, &tmp);
380 memcpy(mem + darg->layout->pos, &val, darg->layout->len);
381 if (tmp) {
382 ((void **)(mem + s->size))[j++] = tmp;
383 }
384 }
385 }
386 return mem;
387 }
388
389 void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
390 {
391 size_t i;
392 decl_var *var = set->vars->vars[0];
393 token_t t = real_decl_type(var->arg->type)->type;
394 impl_val tmp, *ret_val = deref_impl_val(r_val, var);
395
396 if ((intptr_t) ret_val->ptr <= (intptr_t) 0) {
397 RETURN_NULL();
398 }
399
400 array_init(return_value);
401
402 if (t == PSI_T_STRUCT) {
403 // decl_struct *s = real_decl_type(var->arg->type)->strct;
404
405 if (set->count) {
406 /* explicit member casts */
407 for (i = 0; i < set->count; ++i) {
408 set_value *sub_set = set->inner[i];
409 decl_var *sub_var = sub_set->vars->vars[0];
410
411 sub_set->outer.val = r_val;
412
413 if (sub_var->arg) {
414 impl_val *tmp = NULL, *val;
415 zval ztmp;
416
417 val = deref_impl_val(struct_member_ref(sub_var->arg, ret_val, &tmp), sub_var);
418 sub_set->func->handler(&ztmp, sub_set, val);
419 add_assoc_zval(return_value, sub_var->name, &ztmp);
420
421 if (tmp) {
422 free(tmp);
423 }
424 }
425 }
426 }
427 return;
428 }
429
430 if (var->arg->var->array_size) {
431 /* to_array(foo[NUMBER]) */
432 for (i = 0; i < var->arg->var->array_size; ++i) {
433 size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t);
434 impl_val *ptr = iterate(ret_val, size, i, &tmp);
435 zval ele;
436
437 switch (t) {
438 case PSI_T_FLOAT:
439 ZVAL_DOUBLE(&ele, (double) ptr->fval);
440 break;
441 case PSI_T_DOUBLE:
442 ZVAL_DOUBLE(&ele, ptr->dval);
443 break;
444 default:
445 ZVAL_LONG(&ele, ptr->lval);
446 break;
447 }
448
449 add_next_index_zval(return_value, &ele);
450 }
451 return;
452 } else if (set->num) {
453 /* to_array(arr_var, num_expr, to_int(*arr_var))
454 */
455 zval ele;
456 zend_long i, n = psi_long_num_exp(set->num, set->outer.val);
457
458 for (i = 0; i < n; ++i) {
459 size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
460 impl_val *ptr = iterate(ret_val, size, i, &tmp);
461
462 set->inner[0]->func->handler(&ele, set->inner[0], ptr);
463 add_next_index_zval(return_value, &ele);
464 }
465 } else {
466 ZEND_ASSERT(0);
467 }
468 }
469
470 void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
471 {
472 decl_var *var = set->vars->vars[0];
473 impl_val *ret_val = deref_impl_val(r_val, var);
474 psi_object *obj;
475
476 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
477 object_init_ex(return_value, psi_class_entry);
478 obj = PSI_OBJ(return_value, NULL);
479 obj->data = ret_val->ptr;
480 } else {
481 RETVAL_NULL();
482 }
483 }
484
485 static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
486 {
487 size_t i;
488 impl_arg *iarg;
489 zend_error_handling zeh;
490
491 zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
492
493 if (!impl->func->args->count) {
494 ZEND_RESULT_CODE rv;
495
496 rv = zend_parse_parameters_none();
497 zend_restore_error_handling(&zeh);
498 return rv;
499 }
500
501 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->vararg.name ? -1 : impl->func->args->count)
502 nextarg:
503 if (impl->func->args->vararg.name && _i >= impl->func->args->count) {
504 impl_arg *varg = impl->func->args->vararg.name;
505 iarg = init_impl_arg(
506 init_impl_type(varg->type->type, varg->type->name),
507 init_impl_var(varg->var->name, varg->var->reference),
508 NULL);
509
510 Z_PARAM_OPTIONAL;
511 if (_i == impl->func->args->count) {
512 impl->func->args->vararg.args = init_impl_args(iarg);
513 } else {
514 add_impl_arg(impl->func->args->vararg.args, iarg);
515 }
516 } else {
517 iarg = impl->func->args->args[_i];
518 if (iarg->def) {
519 Z_PARAM_OPTIONAL;
520 }
521 }
522 if (PSI_T_BOOL == iarg->type->type) {
523 Z_PARAM_BOOL(iarg->val.zend.bval);
524 } else if (PSI_T_INT == iarg->type->type) {
525 Z_PARAM_LONG(iarg->val.zend.lval);
526 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
527 Z_PARAM_DOUBLE(iarg->val.dval);
528 } else if (PSI_T_STRING == iarg->type->type) {
529 Z_PARAM_STR_EX(iarg->val.zend.str, 1, iarg->var->reference);
530 if (iarg->val.zend.str) {
531 zend_string_addref(iarg->val.zend.str);
532 }
533 } else if (PSI_T_ARRAY == iarg->type->type) {
534 Z_PARAM_PROLOGUE(0);
535 } else if (PSI_T_OBJECT == iarg->type->type) {
536 Z_PARAM_PROLOGUE(0);
537 } else if (PSI_T_MIXED == iarg->type->type) {
538 Z_PARAM_PROLOGUE(0);
539 } else {
540 error_code = ZPP_ERROR_FAILURE;
541 break;
542 }
543 iarg->_zv = _arg;
544 ZVAL_DEREF(iarg->_zv);
545 if (_i < _num_args) {
546 goto nextarg;
547 }
548 ZEND_PARSE_PARAMETERS_END_EX(
549 zend_restore_error_handling(&zeh);
550 return FAILURE
551 );
552
553 /* set up defaults */
554 for (i = 0; i < impl->func->args->count; ++i) {
555 if (i >= EX_NUM_ARGS() && iarg->def) {
556 iarg = impl->func->args->args[i];
557
558 switch (iarg->type->type) {
559 case PSI_T_BOOL:
560 iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
561 break;
562 case PSI_T_INT:
563 iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
564 break;
565 case PSI_T_FLOAT:
566 case PSI_T_DOUBLE:
567 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
568 break;
569 case PSI_T_STRING:
570 /* FIXME */
571 iarg->val.zend.str = zend_string_init(&iarg->def->text[1], strlen(iarg->def->text) - 2, 0);
572 break;
573 }
574 }
575 }
576
577 zend_restore_error_handling(&zeh);
578 return SUCCESS;
579 }
580
581 static inline void *psi_do_calloc(let_calloc *alloc)
582 {
583 zend_long n = psi_long_num_exp(alloc->nmemb, NULL), s = psi_long_num_exp(alloc->size, NULL);
584 void *mem = safe_emalloc(n, s, sizeof(void *));
585 memset(mem, 0, n * s + sizeof(void *));
586 return mem;
587 }
588
589 static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, impl_val *arg_val, decl_struct *strct, void **to_free)
590 {
591 switch (let_func) {
592 case PSI_T_BOOLVAL:
593 if (iarg->type->type == PSI_T_BOOL) {
594 arg_val->cval = iarg->val.zend.bval;
595 } else {
596 arg_val->cval = zend_is_true(iarg->_zv);
597 }
598 break;
599 case PSI_T_INTVAL:
600 if (iarg->type->type == PSI_T_INT) {
601 arg_val->lval = iarg->val.zend.lval;
602 } else {
603 arg_val->lval = zval_get_long(iarg->_zv);
604 }
605 break;
606 case PSI_T_FLOATVAL:
607 if (iarg->type->type == PSI_T_FLOAT || iarg->type->type == PSI_T_DOUBLE) {
608 arg_val->dval = iarg->val.dval;
609 } else {
610 arg_val->dval = zval_get_double(iarg->_zv);
611 }
612 break;
613 case PSI_T_PATHVAL:
614 case PSI_T_STRVAL:
615 if (iarg->type->type == PSI_T_STRING) {
616 if (iarg->val.zend.str) {
617 arg_val->ptr = estrdup(iarg->val.zend.str->val);
618 *to_free = arg_val->ptr;
619 } else {
620 arg_val->ptr = "";
621 }
622 } else {
623 zend_string *zs = zval_get_string(iarg->_zv);
624 arg_val->ptr = estrdup(zs->val);
625 *to_free = arg_val->ptr;
626 zend_string_release(zs);
627 }
628 if (PSI_T_PATHVAL == let_func) {
629 if (SUCCESS != php_check_open_basedir(arg_val->ptr)) {
630 efree(arg_val->ptr);
631 return FAILURE;
632 }
633 }
634 break;
635 case PSI_T_STRLEN:
636 if (iarg->type->type == PSI_T_STRING) {
637 if (iarg->val.zend.str) {
638 arg_val->lval = iarg->val.zend.str->len;
639 } else {
640 arg_val->lval = 0;
641 }
642 } else {
643 zend_string *zs = zval_get_string(iarg->_zv);
644 arg_val->lval = zs->len;
645 zend_string_release(zs);
646 }
647 break;
648 case PSI_T_ARRVAL:
649 if (iarg->type->type == PSI_T_ARRAY) {
650 arg_val->ptr = psi_array_to_struct(strct, HASH_OF(iarg->_zv));
651 *to_free = arg_val->ptr;
652 }
653 break;
654 case PSI_T_OBJVAL:
655 if (iarg->type->type == PSI_T_OBJECT) {
656 psi_object *obj;
657
658 if (!instanceof_function(Z_OBJCE_P(iarg->_zv), psi_class_entry)) {
659 return FAILURE;
660 }
661
662 obj = PSI_OBJ(iarg->_zv, NULL);
663 arg_val->ptr = obj->data;
664 }
665 break;
666 EMPTY_SWITCH_DEFAULT_CASE();
667 }
668 return SUCCESS;
669 }
670
671 static inline void *psi_do_let(let_stmt *let)
672 {
673 decl_arg *darg = let->var->arg;
674 impl_val *arg_val = darg->ptr;
675 impl_arg *iarg;
676
677 switch (let->val ? let->val->kind : PSI_LET_NULL) {
678 case PSI_LET_TMP:
679 arg_val->ptr = deref_impl_val(let->val->data.var->arg->val.ptr, let->var);
680 break;
681 case PSI_LET_NULL:
682 if (darg->var->array_size) {
683 arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val));
684 darg->mem = arg_val->ptr;
685 } else {
686 memset(arg_val, 0, sizeof(*arg_val));
687 }
688 break;
689 case PSI_LET_CALLOC:
690 arg_val->ptr = psi_do_calloc(let->val->data.alloc);
691 darg->mem = arg_val->ptr;
692 break;
693 case PSI_LET_NUMEXP:
694 arg_val->zend.lval = psi_long_num_exp(let->val->data.num, NULL);
695 break;
696 case PSI_LET_FUNC:
697 iarg = let->val->data.func->arg;
698
699 if (SUCCESS != psi_let_val(let->val->data.func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem)) {
700 return NULL;
701 }
702 }
703
704 if (let->val && let->val->flags.one.is_reference) {
705 return let->ptr = &darg->ptr;
706 } else {
707 return let->ptr = darg->ptr;
708 }
709 }
710
711 static inline void psi_do_set(zval *return_value, set_value *set)
712 {
713 zval_dtor(return_value);
714 set->func->handler(return_value, set, set->vars->vars[0]->arg->ptr);
715 }
716
717 static inline void psi_do_return(zval *return_value, return_stmt *ret)
718 {
719 ret->set->func->handler(return_value, ret->set, ret->set->vars->vars[0]->arg->ptr);
720 }
721
722 static inline void psi_do_free(free_stmt *fre)
723 {
724 size_t i, j;
725
726 for (i = 0; i < fre->calls->count; ++i) {
727 free_call *f = fre->calls->list[i];
728
729 for (j = 0; j < f->vars->count; ++j) {
730 decl_var *dvar = f->vars->vars[j];
731 decl_arg *darg = dvar->arg;
732
733 f->decl->call.args[j] = &darg->val;
734 }
735
736 /* FIXME: check in validate_* that free functions return scalar */
737 PSI_ContextCall(&PSI_G(context), &f->decl->call, NULL);
738 }
739 }
740
741 static inline void psi_do_clean(impl *impl)
742 {
743 size_t i;
744
745 for (i = 0; i < impl->func->args->count; ++i ) {
746 impl_arg *iarg = impl->func->args->args[i];
747
748 switch (iarg->type->type) {
749 case PSI_T_STRING:
750 if (iarg->val.zend.str) {
751 zend_string_release(iarg->val.zend.str);
752 }
753 break;
754 }
755 }
756
757 if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
758 decl_arg *darg = impl->decl->args->args[i];
759
760 if (darg->mem) {
761 decl_type *type = real_decl_type(darg->type);
762
763 if (type->type == PSI_T_STRUCT) {
764 void **ptr = (void **) ((char *) darg->mem + type->strct->size);
765
766 while (*ptr) {
767 efree(*ptr++);
768 }
769 }
770 efree(darg->mem);
771 darg->mem = NULL;
772 }
773 }
774
775 if (impl->func->args->vararg.args) {
776 free_impl_args(impl->func->args->vararg.args);
777 impl->func->args->vararg.args = NULL;
778 }
779 if (impl->func->args->vararg.types) {
780 efree(impl->func->args->vararg.types);
781 impl->func->args->vararg.types = NULL;
782 }
783 if (impl->func->args->vararg.values) {
784 efree(impl->func->args->vararg.values);
785 impl->func->args->vararg.values = NULL;
786 }
787 if (impl->func->args->vararg.free_list) {
788 void **list = impl->func->args->vararg.free_list;
789
790 while (*list) {
791 efree(*list++);
792 }
793
794 efree(impl->func->args->vararg.free_list);
795 impl->func->args->vararg.free_list = NULL;
796 }
797 }
798
799 static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *strct, impl_val *res) {
800 impl_val *ref, *tmp = NULL;
801
802 switch (exp->t) {
803 case PSI_T_NUMBER:
804 switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) res, (double *) res, 0)) {
805 case IS_LONG:
806 return PSI_T_INT64;
807 case IS_DOUBLE:
808 return PSI_T_DOUBLE;
809 }
810 break;
811
812 case PSI_T_NSNAME:
813 switch (exp->u.cnst->type->type) {
814 case PSI_T_INT:
815 res->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval;
816 return PSI_T_INT64;
817 case PSI_T_FLOAT:
818 res->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval;
819 return PSI_T_DOUBLE;
820 default:
821 return 0;
822 }
823 break;
824
825 case PSI_T_NAME:
826 if (strct) {
827 ref = struct_member_ref(exp->u.dvar->arg, strct, &tmp);
828 } else {
829 ref = exp->u.dvar->arg->ptr;
830 }
831 switch (real_decl_type(exp->u.dvar->arg->type)->type) {
832 case PSI_T_INT8:
833 case PSI_T_UINT8:
834 case PSI_T_INT16:
835 case PSI_T_UINT16:
836 case PSI_T_INT32:
837 case PSI_T_UINT32:
838 case PSI_T_INT64:
839 case PSI_T_UINT64:
840 memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
841 if (tmp) {
842 free(tmp);
843 }
844 return real_decl_type(exp->u.dvar->arg->type)->type;
845
846 case PSI_T_FLOAT:
847 case PSI_T_DOUBLE:
848 memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
849 if (tmp) {
850 free(tmp);
851 }
852 return real_decl_type(exp->u.dvar->arg->type)->type;
853
854 EMPTY_SWITCH_DEFAULT_CASE();
855 }
856 break;
857
858 EMPTY_SWITCH_DEFAULT_CASE();
859 }
860 return 0;
861 }
862
863 int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) {
864 impl_val num = {0};
865 int num_type = psi_calc_num_exp_value(exp, strct, &num);
866
867 if (exp->operand) {
868 impl_val tmp = {0};
869 int tmp_type = psi_calc_num_exp(exp->operand, strct, &tmp);
870
871 return exp->calculator(num_type, &num, tmp_type, &tmp, res);
872 }
873
874 memcpy(res, &num, sizeof(*res));
875 return num_type;
876 }
877
878 #define PRIfval "f"
879 #define PRIdval "lf"
880
881 #define PSI_CALC_OP(var) do { \
882 const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
883 res->var = PSI_CALC(v1->var, v2->var); \
884 if (!res->var) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
885 } while (0)
886 #define PSI_CALC_OP2(vres, var1, var2) do { \
887 const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
888 res->vres = PSI_CALC(v1->var1, v2->var2); \
889 if (!res->vres) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
890 } while(0)
891 #define PSI_CALC_FN(op) int psi_calc_##op(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res) \
892 { \
893 if (t1 == t2) { \
894 switch (t1) { \
895 case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \
896 case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \
897 case PSI_T_INT8: PSI_CALC_OP(i8); break; \
898 case PSI_T_UINT8: PSI_CALC_OP(u8); break; \
899 case PSI_T_INT16: PSI_CALC_OP(i16); break; \
900 case PSI_T_UINT16: PSI_CALC_OP(u16); break; \
901 case PSI_T_INT32: PSI_CALC_OP(i32); break; \
902 case PSI_T_UINT32: PSI_CALC_OP(u32); break; \
903 case PSI_T_INT64: PSI_CALC_OP(i64); break; \
904 case PSI_T_UINT64: PSI_CALC_OP(u64); break; \
905 EMPTY_SWITCH_DEFAULT_CASE(); \
906 } \
907 return t1; \
908 } else if (t1 == PSI_T_DOUBLE) { \
909 switch (t2) { \
910 case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \
911 case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \
912 case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \
913 case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \
914 case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \
915 case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \
916 case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \
917 case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \
918 case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \
919 EMPTY_SWITCH_DEFAULT_CASE(); \
920 } \
921 return t1; \
922 } else if (t2 == PSI_T_DOUBLE) { \
923 switch (t1) { \
924 case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \
925 case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \
926 case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \
927 case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \
928 case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \
929 case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \
930 case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \
931 case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \
932 case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \
933 EMPTY_SWITCH_DEFAULT_CASE(); \
934 } \
935 return t2; \
936 } else if (t1 == PSI_T_FLOAT) { \
937 switch (t2) { \
938 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \
939 case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \
940 case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \
941 case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \
942 case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \
943 case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \
944 case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \
945 case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \
946 case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \
947 EMPTY_SWITCH_DEFAULT_CASE(); \
948 } \
949 return t1; \
950 } else if (t2 == PSI_T_FLOAT) { \
951 switch (t1) { \
952 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \
953 case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \
954 case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \
955 case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \
956 case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \
957 case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \
958 case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \
959 case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \
960 case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \
961 EMPTY_SWITCH_DEFAULT_CASE(); \
962 } \
963 return t2; \
964 } else { \
965 int64_t sval1 = v1->i64, sval2 = v2->i64; \
966 uint64_t uval1 = v1->u64, uval2 = v2->u64; \
967 switch (t1) { \
968 case PSI_T_INT8: sval1 >>= 8; \
969 case PSI_T_INT16: sval1 >>= 8; \
970 case PSI_T_INT32: sval1 >>= 8; \
971 case PSI_T_INT64: \
972 switch (t2) { \
973 case PSI_T_INT8: sval2 >>= 8; \
974 case PSI_T_INT16: sval2 >>= 8; \
975 case PSI_T_INT32: sval2 >>= 8; \
976 case PSI_T_INT64: \
977 res->i64 = PSI_CALC(sval1 , sval2); \
978 return PSI_T_INT64; \
979 case PSI_T_UINT8: uval2 >>= 8; \
980 case PSI_T_UINT16: uval2 >>= 8; \
981 case PSI_T_UINT32: uval2 >>= 8; \
982 case PSI_T_UINT64: \
983 res->i64 = PSI_CALC(sval1, uval2); \
984 return PSI_T_INT64; \
985 } \
986 break; \
987 case PSI_T_UINT8: uval1 >>= 8; \
988 case PSI_T_UINT16: uval1 >>= 8; \
989 case PSI_T_UINT32: uval1 >>= 8; \
990 case PSI_T_UINT64: \
991 switch (t2) { \
992 case PSI_T_INT8: sval2 >>= 8; \
993 case PSI_T_INT16: sval2 >>= 8; \
994 case PSI_T_INT32: sval2 >>= 8; \
995 case PSI_T_INT64: \
996 res->i64 = PSI_CALC(uval1, sval2); \
997 return PSI_T_INT64; \
998 case PSI_T_UINT8: uval2 >>= 8; \
999 case PSI_T_UINT16: uval2 >>= 8; \
1000 case PSI_T_UINT32: uval2 >>= 8; \
1001 case PSI_T_UINT64: \
1002 res->u64 = PSI_CALC(uval1, uval2); \
1003 return PSI_T_UINT64; \
1004 } \
1005 break; \
1006 } \
1007 } \
1008 ZEND_ASSERT(0); \
1009 return 0; \
1010 }
1011
1012 #undef PSI_CALC
1013 #define PSI_CALC(var1, var2) (var1) + (var2)
1014 PSI_CALC_FN(add)
1015 #undef PSI_CALC
1016 #define PSI_CALC(var1, var2) (var1) * (var2)
1017 PSI_CALC_FN(mul)
1018 #undef PSI_CALC
1019 #define PSI_CALC(var1, var2) (var1) - (var2)
1020 PSI_CALC_FN(sub)
1021 #undef PSI_CALC
1022 #define PSI_CALC(var1, var2) (var1) / (var2)
1023 PSI_CALC_FN(div)
1024
1025 static inline void psi_do_args(impl *impl) {
1026 size_t i;
1027
1028 for (i = 0; i < impl->decl->args->count; ++i) {
1029 impl->decl->call.args[i] = impl->decl->args->args[i]->let->ptr;
1030 }
1031 }
1032
1033 static inline impl_vararg *psi_do_varargs(impl *impl) {
1034 size_t i, j;
1035 impl_vararg *va = &impl->func->args->vararg;
1036 size_t vacount = va->args->count;
1037
1038
1039 if (!vacount) {
1040 return NULL;
1041 }
1042
1043 va->types = ecalloc(vacount, sizeof(*va->types));
1044 va->values = ecalloc(vacount, sizeof(*va->values));
1045
1046 for (i = 0, j = 0; i < vacount; ++i) {
1047 impl_arg *vaarg = va->args->args[i];
1048 void *to_free = NULL;
1049 token_t let_fn, vatype = va->name->type->type;
1050
1051 if (vatype == PSI_T_MIXED) {
1052 switch (Z_TYPE_P(vaarg->_zv)) {
1053 case IS_TRUE:
1054 case IS_FALSE: vatype = PSI_T_BOOL; break;
1055 case IS_LONG: vatype = PSI_T_INT; break;
1056 case IS_DOUBLE: vatype = PSI_T_FLOAT; break;
1057 default: vatype = PSI_T_STRING; break;
1058 }
1059 }
1060
1061
1062 switch (vatype) {
1063 case PSI_T_BOOL: let_fn = PSI_T_BOOLVAL; break;
1064 case PSI_T_INT: let_fn = PSI_T_INTVAL; break;
1065 case PSI_T_FLOAT:
1066 case PSI_T_DOUBLE: let_fn = PSI_T_FLOATVAL;break;
1067 case PSI_T_STRING: let_fn = PSI_T_STRVAL; break;
1068 EMPTY_SWITCH_DEFAULT_CASE();
1069 }
1070
1071 va->types[i] = vatype;
1072 psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free);
1073
1074 if (to_free) {
1075 if (!va->free_list) {
1076 va->free_list = ecalloc(vacount - i + 1, sizeof(*va->free_list));
1077 }
1078 va->free_list[j++] = to_free;
1079 }
1080 }
1081
1082 return va;
1083 }
1084
1085 void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
1086 {
1087 size_t i;
1088 impl_vararg *va = NULL;
1089
1090 memset(impl->decl->func->ptr, 0, sizeof(impl_val));
1091
1092 if (SUCCESS != psi_parse_args(execute_data, impl)) {
1093 return;
1094 }
1095
1096 for (i = 0; i < impl->stmts->let.count; ++i) {
1097 let_stmt *let = impl->stmts->let.list[i];
1098
1099 if (!psi_do_let(let)) {
1100 psi_do_return(return_value, impl->stmts->ret.list[0]);
1101 psi_do_clean(impl);
1102 return;
1103 }
1104 }
1105
1106 if (impl->decl->args) {
1107 psi_do_args(impl);
1108
1109 if (impl->func->args->vararg.args) {
1110 va = psi_do_varargs(impl);
1111 }
1112 }
1113
1114 PSI_ContextCall(&PSI_G(context), &impl->decl->call, va);
1115 psi_do_return(return_value, impl->stmts->ret.list[0]);
1116
1117 for (i = 0; i < impl->stmts->set.count; ++i) {
1118 set_stmt *set = impl->stmts->set.list[i];
1119
1120 if (set->arg->_zv) {
1121 psi_do_set(set->arg->_zv, set->val);
1122 }
1123 }
1124
1125 for (i = 0; i < impl->stmts->fre.count; ++i) {
1126 free_stmt *fre = impl->stmts->fre.list[i];
1127
1128 psi_do_free(fre);
1129 }
1130 psi_do_clean(impl);
1131 }
1132
1133 static void psi_object_free(zend_object *o)
1134 {
1135 psi_object *obj = PSI_OBJ(NULL, o);
1136
1137 if (obj->data) {
1138 // free(obj->data);
1139 obj->data = NULL;
1140 }
1141 zend_object_std_dtor(o);
1142 }
1143
1144 static zend_object *psi_object_init(zend_class_entry *ce)
1145 {
1146 psi_object *o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
1147
1148 zend_object_std_init(&o->std, ce);
1149 object_properties_init(&o->std, ce);
1150 o->std.handlers = &psi_object_handlers;
1151 return &o->std;
1152 }
1153
1154 PHP_MINIT_FUNCTION(psi)
1155 {
1156 PSI_ContextOps *ops = NULL;
1157 zend_class_entry ce = {0};
1158
1159 REGISTER_INI_ENTRIES();
1160
1161 INIT_NS_CLASS_ENTRY(ce, "psi", "object", NULL);
1162 psi_class_entry = zend_register_internal_class_ex(&ce, NULL);
1163 psi_class_entry->create_object = psi_object_init;
1164
1165 memcpy(&psi_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1166 psi_object_handlers.offset = XtOffsetOf(psi_object, std);
1167 psi_object_handlers.free_obj = psi_object_free;
1168 psi_object_handlers.clone_obj = NULL;
1169
1170 #ifdef HAVE_LIBJIT
1171 if (!strcasecmp(PSI_G(engine), "jit")) {
1172 ops = PSI_Libjit();
1173 } else
1174 #endif
1175 #ifdef HAVE_LIBFFI
1176 ops = PSI_Libffi();
1177 #endif
1178
1179 if (!ops) {
1180 php_error(E_WARNING, "No PSI engine found");
1181 return FAILURE;
1182 }
1183
1184 PSI_ContextInit(&PSI_G(context), ops, psi_error_wrapper);
1185 PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
1186
1187 if (psi_check_env("PSI_DUMP")) {
1188 PSI_ContextDump(&PSI_G(context), STDOUT_FILENO);
1189 }
1190
1191 return SUCCESS;
1192 }
1193
1194 PHP_MSHUTDOWN_FUNCTION(psi)
1195 {
1196 PSI_ContextDtor(&PSI_G(context));
1197
1198 UNREGISTER_INI_ENTRIES();
1199
1200 return SUCCESS;
1201 }
1202
1203 #if defined(COMPILE_DL_PSI) && defined(ZTS)
1204 PHP_RINIT_FUNCTION(psi)
1205 {
1206 ZEND_TSRMLS_CACHE_UPDATE();
1207 return SUCCESS;
1208 }
1209 #endif
1210
1211 PHP_MINFO_FUNCTION(psi)
1212 {
1213 php_info_print_table_start();
1214 php_info_print_table_header(2, "psi support", "enabled");
1215 php_info_print_table_end();
1216
1217 DISPLAY_INI_ENTRIES();
1218 }
1219 const zend_function_entry psi_functions[] = {
1220 PHP_FE_END
1221 };
1222
1223 zend_module_entry psi_module_entry = {
1224 STANDARD_MODULE_HEADER,
1225 "psi",
1226 psi_functions,
1227 PHP_MINIT(psi),
1228 PHP_MSHUTDOWN(psi),
1229 #if defined(COMPILE_DL_PSI) && defined(ZTS)
1230 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
1231 #else
1232 NULL,
1233 #endif
1234 NULL,
1235 PHP_MINFO(psi),
1236 PHP_PSI_VERSION,
1237 STANDARD_MODULE_PROPERTIES
1238 };
1239
1240 #ifdef COMPILE_DL_PSI
1241 #ifdef ZTS
1242 ZEND_TSRMLS_CACHE_DEFINE();
1243 #endif
1244 ZEND_GET_MODULE(psi)
1245 #endif
1246
1247 /*
1248 * Local variables:
1249 * tab-width: 4
1250 * c-basic-offset: 4
1251 * End:
1252 * vim600: noet sw=4 ts=4 fdm=marker
1253 * vim<600: noet sw=4 ts=4
1254 */