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