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