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