flush
[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.name, 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.name) {
134 impl_arg *vararg = impl->func->args->vararg.name;
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.name ? -1 : impl->func->args->count)
494 nextarg:
495 if (impl->func->args->vararg.name && _i >= impl->func->args->count) {
496 impl_arg *varg = impl->func->args->vararg.name;
497 iarg = init_impl_arg(
498 init_impl_type(varg->type->type, varg->type->name),
499 init_impl_var(varg->var->name, varg->var->reference),
500 NULL);
501
502 Z_PARAM_OPTIONAL;
503 if (_i == impl->func->args->count) {
504 impl->func->args->vararg.args = init_impl_args(iarg);
505 } else {
506 add_impl_arg(impl->func->args->vararg.args, iarg);
507 }
508 } else {
509 iarg = impl->func->args->args[_i];
510 if (iarg->def) {
511 Z_PARAM_OPTIONAL;
512 }
513 }
514 if (PSI_T_BOOL == iarg->type->type) {
515 Z_PARAM_BOOL(iarg->val.zend.bval);
516 } else if (PSI_T_INT == iarg->type->type) {
517 Z_PARAM_LONG(iarg->val.zend.lval);
518 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
519 Z_PARAM_DOUBLE(iarg->val.dval);
520 } else if (PSI_T_STRING == iarg->type->type) {
521 Z_PARAM_STR_EX(iarg->val.zend.str, 1, iarg->var->reference);
522 if (iarg->val.zend.str) {
523 zend_string_addref(iarg->val.zend.str);
524 }
525 } else if (PSI_T_ARRAY == iarg->type->type) {
526 Z_PARAM_PROLOGUE(0);
527 } else if (PSI_T_OBJECT == iarg->type->type) {
528 Z_PARAM_PROLOGUE(0);
529 } else if (PSI_T_MIXED == iarg->type->type) {
530 Z_PARAM_PROLOGUE(0);
531 } else {
532 error_code = ZPP_ERROR_FAILURE;
533 break;
534 }
535 if (_i < _num_args) {
536 goto nextarg;
537 }
538 ZEND_PARSE_PARAMETERS_END_EX(
539 zend_restore_error_handling(&zeh);
540 return FAILURE
541 );
542
543 /* set up defaults */
544 for (i = 0; i < impl->func->args->count; ++i) {
545 iarg = impl->func->args->args[i];
546
547 if (i < EX_NUM_ARGS()) {
548 iarg->_zv = ++zarg;
549 ZVAL_DEREF(iarg->_zv);
550 } else if (iarg->def) {
551 switch (iarg->type->type) {
552 case PSI_T_BOOL:
553 iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
554 break;
555 case PSI_T_INT:
556 iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
557 break;
558 case PSI_T_FLOAT:
559 case PSI_T_DOUBLE:
560 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
561 break;
562 case PSI_T_STRING:
563 /* FIXME */
564 iarg->val.zend.str = zend_string_init(&iarg->def->text[1], strlen(iarg->def->text) - 2, 0);
565 break;
566 }
567 }
568 }
569
570 zend_restore_error_handling(&zeh);
571 return SUCCESS;
572 }
573
574 static inline void *psi_do_calloc(let_calloc *alloc)
575 {
576 zend_long n = psi_long_num_exp(alloc->nmemb, NULL), s = psi_long_num_exp(alloc->size, NULL);
577 void *mem = safe_emalloc(n, s, sizeof(void *));
578 memset(mem, 0, n * s + sizeof(void *));
579 return mem;
580 }
581
582 static inline token_t psi_let_fn(token_t impl_type) {
583 switch (impl_type) {
584 case PSI_T_BOOL:
585 return PSI_T_BOOLVAL;
586 case PSI_T_INT:
587 return PSI_T_INTVAL;
588 case PSI_T_FLOAT:
589 case PSI_T_DOUBLE:
590 return PSI_T_FLOATVAL;
591 case PSI_T_STRING:
592 return PSI_T_STRVAL;
593 }
594 return 0;
595 }
596
597 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)
598 {
599 switch (let_func) {
600 case PSI_T_BOOLVAL:
601 if (iarg->type->type == PSI_T_BOOL) {
602 arg_val->cval = iarg->val.zend.bval;
603 } else {
604 arg_val->cval = zend_is_true(iarg->_zv);
605 }
606 break;
607 case PSI_T_INTVAL:
608 if (iarg->type->type == PSI_T_INT) {
609 arg_val->lval = iarg->val.zend.lval;
610 } else {
611 arg_val->lval = zval_get_long(iarg->_zv);
612 }
613 break;
614 case PSI_T_FLOATVAL:
615 if (iarg->type->type == PSI_T_FLOAT || iarg->type->type == PSI_T_DOUBLE) {
616 arg_val->dval = iarg->val.dval;
617 } else {
618 arg_val->dval = zval_get_double(iarg->_zv);
619 }
620 break;
621 case PSI_T_PATHVAL:
622 case PSI_T_STRVAL:
623 if (iarg->type->type == PSI_T_STRING) {
624 if (iarg->val.zend.str) {
625 arg_val->ptr = estrdup(iarg->val.zend.str->val);
626 *to_free = arg_val->ptr;
627 } else {
628 arg_val->ptr = "";
629 }
630 } else {
631 zend_string *zs = zval_get_string(iarg->_zv);
632 arg_val->ptr = estrdup(zs->val);
633 *to_free = arg_val->ptr;
634 zend_string_release(zs);
635 }
636 if (PSI_T_PATHVAL == let_func) {
637 if (SUCCESS != php_check_open_basedir(arg_val->ptr)) {
638 efree(arg_val->ptr);
639 return FAILURE;
640 }
641 }
642 break;
643 case PSI_T_STRLEN:
644 if (iarg->type->type == PSI_T_STRING) {
645 if (iarg->val.zend.str) {
646 arg_val->lval = iarg->val.zend.str->len;
647 } else {
648 arg_val->lval = 0;
649 }
650 } else {
651 zend_string *zs = zval_get_string(iarg->_zv);
652 arg_val->lval = zs->len;
653 zend_string_release(zs);
654 }
655 break;
656 case PSI_T_ARRVAL:
657 if (iarg->type->type == PSI_T_ARRAY) {
658 arg_val->ptr = psi_array_to_struct(strct, HASH_OF(iarg->_zv));
659 *to_free = arg_val->ptr;
660 }
661 break;
662 case PSI_T_OBJVAL:
663 if (iarg->type->type == PSI_T_OBJECT) {
664 psi_object *obj;
665
666 if (!instanceof_function(Z_OBJCE_P(iarg->_zv), psi_class_entry)) {
667 return FAILURE;
668 }
669
670 obj = PSI_OBJ(iarg->_zv, NULL);
671 arg_val->ptr = obj->data;
672 }
673 break;
674 EMPTY_SWITCH_DEFAULT_CASE();
675 }
676 return SUCCESS;
677 }
678
679 static inline void *psi_do_let(let_stmt *let)
680 {
681 decl_arg *darg = let->var->arg;
682 impl_val *arg_val = darg->ptr;
683 impl_arg *iarg;
684
685 switch (let->val ? let->val->kind : PSI_LET_NULL) {
686 case PSI_LET_TMP:
687 arg_val->ptr = deref_impl_val(let->val->data.var->arg->val.ptr, let->var);
688 break;
689 case PSI_LET_NULL:
690 if (darg->var->array_size) {
691 arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val));
692 darg->mem = arg_val->ptr;
693 } else {
694 memset(arg_val, 0, sizeof(*arg_val));
695 }
696 break;
697 case PSI_LET_CALLOC:
698 arg_val->ptr = psi_do_calloc(let->val->data.alloc);
699 darg->mem = arg_val->ptr;
700 break;
701 case PSI_LET_NUMEXP:
702 arg_val->zend.lval = psi_long_num_exp(let->val->data.num, NULL);
703 break;
704 case PSI_LET_FUNC:
705 iarg = let->val->data.func->arg;
706
707 if (SUCCESS != psi_let_val(let->val->data.func->type, iarg, real_decl_type(darg->type)->strct, darg->ptr, &darg->mem)) {
708 return NULL;
709 }
710 }
711
712 if (let->val && let->val->flags.one.is_reference) {
713 return let->ptr = &darg->ptr;
714 } else {
715 return let->ptr = darg->ptr;
716 }
717 }
718
719 static inline void psi_do_set(zval *return_value, set_value *set)
720 {
721 zval_dtor(return_value);
722 set->func->handler(return_value, set, set->vars->vars[0]->arg->ptr);
723 }
724
725 static inline void psi_do_return(zval *return_value, return_stmt *ret)
726 {
727 ret->set->func->handler(return_value, ret->set, ret->set->vars->vars[0]->arg->ptr);
728 }
729
730 static inline void psi_do_free(free_stmt *fre)
731 {
732 size_t i, j;
733
734 for (i = 0; i < fre->calls->count; ++i) {
735 free_call *f = fre->calls->list[i];
736
737 for (j = 0; j < f->vars->count; ++j) {
738 decl_var *dvar = f->vars->vars[j];
739 decl_arg *darg = dvar->arg;
740
741 f->decl->call.args[j] = &darg->val;
742 }
743
744 /* FIXME: check in validate_* that free functions return scalar */
745 PSI_ContextCall(&PSI_G(context), &f->decl->call);
746 }
747 }
748
749 static inline void psi_do_clean(impl *impl)
750 {
751 size_t i;
752
753 for (i = 0; i < impl->func->args->count; ++i ) {
754 impl_arg *iarg = impl->func->args->args[i];
755
756 switch (iarg->type->type) {
757 case PSI_T_STRING:
758 if (iarg->val.zend.str) {
759 zend_string_release(iarg->val.zend.str);
760 }
761 break;
762 }
763 }
764
765 if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
766 decl_arg *darg = impl->decl->args->args[i];
767
768 if (darg->mem) {
769 decl_type *type = real_decl_type(darg->type);
770
771 if (type->type == PSI_T_STRUCT) {
772 void **ptr = (void **) ((char *) darg->mem + type->strct->size);
773
774 while (*ptr) {
775 efree(*ptr++);
776 }
777 }
778 efree(darg->mem);
779 darg->mem = NULL;
780 }
781 }
782 }
783
784 static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *strct, impl_val *res) {
785 impl_val *ref, *tmp = NULL;
786
787 switch (exp->t) {
788 case PSI_T_NUMBER:
789 switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) res, (double *) res, 0)) {
790 case IS_LONG:
791 return PSI_T_INT64;
792 case IS_DOUBLE:
793 return PSI_T_DOUBLE;
794 }
795 break;
796
797 case PSI_T_NSNAME:
798 switch (exp->u.cnst->type->type) {
799 case PSI_T_INT:
800 res->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval;
801 return PSI_T_INT64;
802 case PSI_T_FLOAT:
803 res->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval;
804 return PSI_T_DOUBLE;
805 default:
806 return 0;
807 }
808 break;
809
810 case PSI_T_NAME:
811 if (strct) {
812 ref = struct_member_ref(exp->u.dvar->arg, strct, &tmp);
813 } else {
814 ref = exp->u.dvar->arg->ptr;
815 }
816 switch (real_decl_type(exp->u.dvar->arg->type)->type) {
817 case PSI_T_INT8:
818 case PSI_T_UINT8:
819 case PSI_T_INT16:
820 case PSI_T_UINT16:
821 case PSI_T_INT32:
822 case PSI_T_UINT32:
823 case PSI_T_INT64:
824 case PSI_T_UINT64:
825 memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
826 if (tmp) {
827 free(tmp);
828 }
829 return real_decl_type(exp->u.dvar->arg->type)->type;
830
831 case PSI_T_FLOAT:
832 case PSI_T_DOUBLE:
833 memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
834 if (tmp) {
835 free(tmp);
836 }
837 return real_decl_type(exp->u.dvar->arg->type)->type;
838
839 EMPTY_SWITCH_DEFAULT_CASE();
840 }
841 break;
842
843 EMPTY_SWITCH_DEFAULT_CASE();
844 }
845 return 0;
846 }
847
848 int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) {
849 impl_val num = {0};
850 int num_type = psi_calc_num_exp_value(exp, strct, &num);
851
852 if (exp->operand) {
853 impl_val tmp = {0};
854 int tmp_type = psi_calc_num_exp(exp->operand, strct, &tmp);
855
856 return exp->calculator(num_type, &num, tmp_type, &tmp, res);
857 }
858
859 memcpy(res, &num, sizeof(*res));
860 return num_type;
861 }
862
863 #define PRIfval "f"
864 #define PRIdval "lf"
865
866 #define PSI_CALC_OP(var) do { \
867 const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
868 res->var = PSI_CALC(v1->var, v2->var); \
869 if (!res->var) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
870 } while (0)
871 #define PSI_CALC_OP2(vres, var1, var2) do { \
872 const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
873 res->vres = PSI_CALC(v1->var1, v2->var2); \
874 if (!res->vres) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
875 } while(0)
876 #define PSI_CALC_FN(op) int psi_calc_##op(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res) \
877 { \
878 if (t1 == t2) { \
879 switch (t1) { \
880 case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \
881 case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \
882 case PSI_T_INT8: PSI_CALC_OP(i8); break; \
883 case PSI_T_UINT8: PSI_CALC_OP(u8); break; \
884 case PSI_T_INT16: PSI_CALC_OP(i16); break; \
885 case PSI_T_UINT16: PSI_CALC_OP(u16); break; \
886 case PSI_T_INT32: PSI_CALC_OP(i32); break; \
887 case PSI_T_UINT32: PSI_CALC_OP(u32); break; \
888 case PSI_T_INT64: PSI_CALC_OP(i64); break; \
889 case PSI_T_UINT64: PSI_CALC_OP(u64); break; \
890 EMPTY_SWITCH_DEFAULT_CASE(); \
891 } \
892 return t1; \
893 } else if (t1 == PSI_T_DOUBLE) { \
894 switch (t2) { \
895 case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \
896 case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \
897 case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \
898 case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \
899 case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \
900 case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \
901 case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \
902 case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \
903 case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \
904 EMPTY_SWITCH_DEFAULT_CASE(); \
905 } \
906 return t1; \
907 } else if (t2 == PSI_T_DOUBLE) { \
908 switch (t1) { \
909 case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \
910 case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \
911 case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \
912 case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \
913 case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \
914 case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \
915 case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \
916 case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \
917 case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \
918 EMPTY_SWITCH_DEFAULT_CASE(); \
919 } \
920 return t2; \
921 } else if (t1 == PSI_T_FLOAT) { \
922 switch (t2) { \
923 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \
924 case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \
925 case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \
926 case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \
927 case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \
928 case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \
929 case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \
930 case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \
931 case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \
932 EMPTY_SWITCH_DEFAULT_CASE(); \
933 } \
934 return t1; \
935 } else if (t2 == PSI_T_FLOAT) { \
936 switch (t1) { \
937 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \
938 case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \
939 case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \
940 case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \
941 case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \
942 case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \
943 case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \
944 case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \
945 case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \
946 EMPTY_SWITCH_DEFAULT_CASE(); \
947 } \
948 return t2; \
949 } else { \
950 int64_t sval1 = v1->i64, sval2 = v2->i64; \
951 uint64_t uval1 = v1->u64, uval2 = v2->u64; \
952 switch (t1) { \
953 case PSI_T_INT8: sval1 >>= 8; \
954 case PSI_T_INT16: sval1 >>= 8; \
955 case PSI_T_INT32: sval1 >>= 8; \
956 case PSI_T_INT64: \
957 switch (t2) { \
958 case PSI_T_INT8: sval2 >>= 8; \
959 case PSI_T_INT16: sval2 >>= 8; \
960 case PSI_T_INT32: sval2 >>= 8; \
961 case PSI_T_INT64: \
962 res->i64 = PSI_CALC(sval1 , sval2); \
963 return PSI_T_INT64; \
964 case PSI_T_UINT8: uval2 >>= 8; \
965 case PSI_T_UINT16: uval2 >>= 8; \
966 case PSI_T_UINT32: uval2 >>= 8; \
967 case PSI_T_UINT64: \
968 res->i64 = PSI_CALC(sval1, uval2); \
969 return PSI_T_INT64; \
970 } \
971 break; \
972 case PSI_T_UINT8: uval1 >>= 8; \
973 case PSI_T_UINT16: uval1 >>= 8; \
974 case PSI_T_UINT32: uval1 >>= 8; \
975 case PSI_T_UINT64: \
976 switch (t2) { \
977 case PSI_T_INT8: sval2 >>= 8; \
978 case PSI_T_INT16: sval2 >>= 8; \
979 case PSI_T_INT32: sval2 >>= 8; \
980 case PSI_T_INT64: \
981 res->i64 = PSI_CALC(uval1, sval2); \
982 return PSI_T_INT64; \
983 case PSI_T_UINT8: uval2 >>= 8; \
984 case PSI_T_UINT16: uval2 >>= 8; \
985 case PSI_T_UINT32: uval2 >>= 8; \
986 case PSI_T_UINT64: \
987 res->u64 = PSI_CALC(uval1, uval2); \
988 return PSI_T_UINT64; \
989 } \
990 break; \
991 } \
992 } \
993 ZEND_ASSERT(0); \
994 return 0; \
995 }
996
997 #undef PSI_CALC
998 #define PSI_CALC(var1, var2) (var1) + (var2)
999 PSI_CALC_FN(add)
1000 #undef PSI_CALC
1001 #define PSI_CALC(var1, var2) (var1) * (var2)
1002 PSI_CALC_FN(mul)
1003 #undef PSI_CALC
1004 #define PSI_CALC(var1, var2) (var1) - (var2)
1005 PSI_CALC_FN(sub)
1006 #undef PSI_CALC
1007 #define PSI_CALC(var1, var2) (var1) / (var2)
1008 PSI_CALC_FN(div)
1009
1010 static inline void psi_do_args(impl *impl) {
1011 size_t i;
1012
1013 for (i = 0; i < impl->decl->args->count; ++i) {
1014 impl->decl->call.args[i] = impl->decl->args->args[i]->let->ptr;
1015 }
1016 }
1017
1018 static inline void psi_do_varargs(impl *impl, void ***free_list) {
1019 size_t i, j;
1020 impl_vararg *va = &impl->func->args->vararg;
1021 size_t vacount = va->args->count;
1022 void **tmpvals = calloc(vacount, sizeof(*tmpvals));
1023 token_t type = psi_let_fn(va->name->type->type);
1024
1025 va->types = calloc(vacount, sizeof(*va->types));
1026 va->values = calloc(vacount, sizeof(*va->values));
1027
1028 for (i = 0, j = 0; i < vacount; ++i) {
1029 impl_arg *vaarg = va->args->args[i];
1030 void *to_free = NULL;
1031
1032 psi_let_val(type, vaarg, &va->values[i], NULL, &to_free);
1033 if (to_free) {
1034 *free_list = realloc(*free_list, (j + 1) * sizeof(*free_list));
1035 (*free_list)[j++] = to_free;
1036 }
1037 }
1038 }
1039
1040 void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
1041 {
1042 size_t i, j;
1043 decl_callinfo *call = &impl->decl->call;
1044 void **free_list = NULL;
1045
1046 memset(impl->decl->func->ptr, 0, sizeof(impl_val));
1047
1048 if (SUCCESS != psi_parse_args(execute_data, impl)) {
1049 return;
1050 }
1051
1052 for (i = 0; i < impl->stmts->let.count; ++i) {
1053 let_stmt *let = impl->stmts->let.list[i];
1054
1055 if (!psi_do_let(let)) {
1056 psi_do_return(return_value, impl->stmts->ret.list[0]);
1057 psi_do_clean(impl);
1058 return;
1059 }
1060 }
1061
1062 if (impl->decl->args) {
1063 psi_do_args(impl);
1064
1065 if (impl->func->args->vararg.args) {
1066 call = psi_do_varargs(impl, &free_list);
1067 }
1068 }
1069
1070 if (impl->func->args->vararg.args) {
1071 PSI_ContextCallVarargs(&PSI_G(context), &impl->decl->call)
1072 } else {
1073 PSI_ContextCall(&PSI_G(context), &impl->decl->call);
1074 }
1075 psi_do_return(return_value, impl->stmts->ret.list[0]);
1076
1077 for (i = 0; i < impl->stmts->set.count; ++i) {
1078 set_stmt *set = impl->stmts->set.list[i];
1079
1080 if (set->arg->_zv) {
1081 psi_do_set(set->arg->_zv, set->val);
1082 }
1083 }
1084
1085 for (i = 0; i < impl->stmts->fre.count; ++i) {
1086 free_stmt *fre = impl->stmts->fre.list[i];
1087
1088 psi_do_free(fre);
1089 }
1090 psi_do_clean(impl);
1091 }
1092
1093 static void psi_object_free(zend_object *o)
1094 {
1095 psi_object *obj = PSI_OBJ(NULL, o);
1096
1097 if (obj->data) {
1098 // free(obj->data);
1099 obj->data = NULL;
1100 }
1101 zend_object_std_dtor(o);
1102 }
1103
1104 static zend_object *psi_object_init(zend_class_entry *ce)
1105 {
1106 psi_object *o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
1107
1108 zend_object_std_init(&o->std, ce);
1109 object_properties_init(&o->std, ce);
1110 o->std.handlers = &psi_object_handlers;
1111 return &o->std;
1112 }
1113
1114 PHP_MINIT_FUNCTION(psi)
1115 {
1116 PSI_ContextOps *ops = NULL;
1117 zend_class_entry ce = {0};
1118
1119 REGISTER_INI_ENTRIES();
1120
1121 INIT_NS_CLASS_ENTRY(ce, "psi", "object", NULL);
1122 psi_class_entry = zend_register_internal_class_ex(&ce, NULL);
1123 psi_class_entry->create_object = psi_object_init;
1124
1125 memcpy(&psi_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1126 psi_object_handlers.offset = XtOffsetOf(psi_object, std);
1127 psi_object_handlers.free_obj = psi_object_free;
1128 psi_object_handlers.clone_obj = NULL;
1129
1130 #ifdef HAVE_LIBJIT
1131 if (!strcasecmp(PSI_G(engine), "jit")) {
1132 ops = PSI_Libjit();
1133 } else
1134 #endif
1135 #ifdef HAVE_LIBFFI
1136 ops = PSI_Libffi();
1137 #endif
1138
1139 if (!ops) {
1140 php_error(E_WARNING, "No PSI engine found");
1141 return FAILURE;
1142 }
1143
1144 PSI_ContextInit(&PSI_G(context), ops, psi_error);
1145 PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
1146
1147 if (psi_check_env("PSI_DUMP")) {
1148 PSI_ContextDump(&PSI_G(context), STDOUT_FILENO);
1149 }
1150
1151 return SUCCESS;
1152 }
1153
1154 PHP_MSHUTDOWN_FUNCTION(psi)
1155 {
1156 PSI_ContextDtor(&PSI_G(context));
1157
1158 UNREGISTER_INI_ENTRIES();
1159
1160 return SUCCESS;
1161 }
1162
1163 #if defined(COMPILE_DL_PSI) && defined(ZTS)
1164 PHP_RINIT_FUNCTION(psi)
1165 {
1166 ZEND_TSRMLS_CACHE_UPDATE();
1167 return SUCCESS;
1168 }
1169 #endif
1170
1171 PHP_MINFO_FUNCTION(psi)
1172 {
1173 php_info_print_table_start();
1174 php_info_print_table_header(2, "psi support", "enabled");
1175 php_info_print_table_end();
1176
1177 DISPLAY_INI_ENTRIES();
1178 }
1179 const zend_function_entry psi_functions[] = {
1180 PHP_FE_END
1181 };
1182
1183 zend_module_entry psi_module_entry = {
1184 STANDARD_MODULE_HEADER,
1185 "psi",
1186 psi_functions,
1187 PHP_MINIT(psi),
1188 PHP_MSHUTDOWN(psi),
1189 #if defined(COMPILE_DL_PSI) && defined(ZTS)
1190 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
1191 #else
1192 NULL,
1193 #endif
1194 NULL,
1195 PHP_MINFO(psi),
1196 PHP_PSI_VERSION,
1197 STANDARD_MODULE_PROPERTIES
1198 };
1199
1200 #ifdef COMPILE_DL_PSI
1201 #ifdef ZTS
1202 ZEND_TSRMLS_CACHE_DEFINE();
1203 #endif
1204 ZEND_GET_MODULE(psi)
1205 #endif
1206
1207 /*
1208 * Local variables:
1209 * tab-width: 4
1210 * c-basic-offset: 4
1211 * End:
1212 * vim600: noet sw=4 ts=4 fdm=marker
1213 * vim<600: noet sw=4 ts=4
1214 */