fixes
[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
10 #include "php_psi.h"
11 #include "parser.h"
12
13 #include "libjit.h"
14 #include "libffi.h"
15
16 ZEND_DECLARE_MODULE_GLOBALS(psi);
17
18 PHP_INI_BEGIN()
19 STD_PHP_INI_ENTRY("psi.engine", "ffi", PHP_INI_SYSTEM, OnUpdateString, engine, zend_psi_globals, psi_globals)
20 STD_PHP_INI_ENTRY("psi.directory", "psis", PHP_INI_SYSTEM, OnUpdateString, directory, zend_psi_globals, psi_globals)
21 PHP_INI_END();
22
23 void psi_error(int type, const char *msg, ...)
24 {
25 char buf[0x1000];
26 va_list argv;
27
28 va_start(argv, msg);
29 vslprintf(buf, 0x1000, msg, argv);
30 va_end(argv);
31
32 php_error(type, buf);
33 }
34
35 int psi_internal_type(impl_type *type)
36 {
37 switch (type->type) {
38 case PSI_T_BOOL:
39 return _IS_BOOL;
40 case PSI_T_INT:
41 case PSI_T_LONG:
42 return IS_LONG;
43 case PSI_T_FLOAT:
44 case PSI_T_DOUBLE:
45 return IS_DOUBLE;
46 case PSI_T_STRING:
47 return IS_STRING;
48 case PSI_T_ARRAY:
49 return IS_ARRAY;
50 default:
51 return 0;
52 }
53 }
54
55 zend_internal_arg_info *psi_internal_arginfo(impl *impl)
56 {
57 size_t i;
58 zend_internal_arg_info *aip;
59 zend_internal_function_info *fi;
60
61 aip = calloc(impl->func->args->count + 1, sizeof(*aip));
62
63 fi = (zend_internal_function_info *) &aip[0];
64 fi->required_num_args = psi_num_min_args(impl);
65 fi->return_reference = impl->func->return_reference;
66 fi->type_hint = psi_internal_type(impl->func->return_type);
67
68 for (i = 0; i < impl->func->args->count; ++i) {
69 impl_arg *iarg = impl->func->args->args[i];
70 zend_internal_arg_info *ai = &aip[i+1];
71
72 ai->name = iarg->var->name;
73 ai->type_hint = psi_internal_type(iarg->type);
74 if (iarg->var->reference) {
75 ai->pass_by_reference = 1;
76 }
77 if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
78 ai->allow_null = 1;
79 }
80 }
81
82 return aip;
83 }
84
85 size_t psi_num_min_args(impl *impl)
86 {
87 size_t i, n = impl->func->args->count;
88
89 for (i = 0; i < impl->func->args->count; ++i) {
90 if (impl->func->args->args[i]->def) {
91 --n;
92 }
93 }
94 return n;
95 }
96
97 void psi_to_int(zval *return_value, token_t t, impl_val *ret_val, decl_var *var)
98 {
99 switch (t) {
100 case PSI_T_FLOAT:
101 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval);
102 convert_to_long(return_value);
103 break;
104 case PSI_T_DOUBLE:
105 RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval);
106 convert_to_long(return_value);
107 break;
108 default:
109 RETVAL_LONG(deref_impl_val(ret_val, var)->lval);
110 }
111 }
112
113 void psi_to_double(zval *return_value, token_t t, impl_val *ret_val, decl_var *var)
114 {
115 switch (t) {
116 case PSI_T_FLOAT:
117 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval);
118 break;
119 case PSI_T_DOUBLE:
120 RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval);
121 break;
122 default:
123 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->lval);
124 break;
125 }
126 }
127
128 void psi_to_string(zval *return_value, token_t t, impl_val *ret_val, decl_var *var)
129 {
130 switch (t) {
131 case PSI_T_CHAR:
132 case PSI_T_SINT8:
133 case PSI_T_UINT8:
134 if (!var->arg->var->pointer_level) {
135 RETVAL_STRINGL(&ret_val->cval, 1);
136 } else {
137 ret_val = deref_impl_val(ret_val, var);
138 if (ret_val) {
139 RETVAL_STRING(ret_val->ptr);
140 } else {
141 RETVAL_EMPTY_STRING();
142 }
143 }
144 break;
145 case PSI_T_FLOAT:
146 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval);
147 convert_to_string(return_value);
148 break;
149 case PSI_T_DOUBLE:
150 RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval);
151 convert_to_string(return_value);
152 break;
153 default:
154 RETVAL_LONG(deref_impl_val(ret_val, var)->lval);
155 convert_to_string(return_value);
156 break;
157 }
158 }
159
160 size_t psi_t_alignment(token_t t)
161 {
162 size_t align;
163 #define PSI_TAS_D(T) struct PSI_TAS_ ##T { \
164 char c; \
165 T x; \
166 }
167 #define PSI_TAS_P(T) struct PSI_TAS_ ## T ## _pointer { \
168 char c; \
169 T *x; \
170 }
171 #define PSI_TAS_C(T) align = offsetof(struct PSI_TAS_ ##T, x)
172 #define PSI_TAS_CASE(T) { \
173 PSI_TAS_D(T); \
174 PSI_TAS_C(T); \
175 }
176 switch (t) {
177 case PSI_T_CHAR:
178 PSI_TAS_CASE(char);
179 break;
180 case PSI_T_SINT8:
181 PSI_TAS_CASE(int8_t);
182 break;
183 case PSI_T_UINT8:
184 PSI_TAS_CASE(uint8_t);
185 break;
186 case PSI_T_SHORT:
187 PSI_TAS_CASE(short);
188 break;
189 case PSI_T_SINT16:
190 PSI_TAS_CASE(int16_t);
191 break;
192 case PSI_T_UINT16:
193 PSI_TAS_CASE(uint16_t);
194 break;
195 case PSI_T_INT:
196 PSI_TAS_CASE(int);
197 break;
198 case PSI_T_SINT32:
199 PSI_TAS_CASE(int32_t);
200 break;
201 case PSI_T_UINT32:
202 PSI_TAS_CASE(uint32_t);
203 break;
204 case PSI_T_LONG:
205 PSI_TAS_CASE(long);
206 break;
207 case PSI_T_SINT64:
208 PSI_TAS_CASE(int64_t);
209 break;
210 case PSI_T_UINT64:
211 PSI_TAS_CASE(uint64_t);
212 break;
213 case PSI_T_FLOAT:
214 PSI_TAS_CASE(float);
215 break;
216 case PSI_T_DOUBLE:
217 PSI_TAS_CASE(double);
218 break;
219 case PSI_T_SIZE_T:
220 PSI_TAS_CASE(size_t);
221 break;
222 case PSI_T_POINTER:
223 {
224 PSI_TAS_P(char);
225 PSI_TAS_C(char_pointer);
226 }
227 break;
228 EMPTY_SWITCH_DEFAULT_CASE();
229 }
230
231 return align;
232 }
233
234 size_t psi_t_size(token_t t)
235 {
236 size_t size;
237
238 switch (t) {
239 case PSI_T_CHAR:
240 size = sizeof(char);
241 break;
242 case PSI_T_SINT8:
243 case PSI_T_UINT8:
244 size = 1;
245 break;
246 case PSI_T_SHORT:
247 size = sizeof(short);
248 break;
249 case PSI_T_SINT16:
250 case PSI_T_UINT16:
251 size = 2;
252 break;
253 case PSI_T_INT:
254 size = sizeof(int);
255 break;
256 case PSI_T_SINT32:
257 case PSI_T_UINT32:
258 size = 4;
259 break;
260 case PSI_T_LONG:
261 size = sizeof(long);
262 break;
263 case PSI_T_SINT64:
264 case PSI_T_UINT64:
265 size = 8;
266 break;
267 case PSI_T_FLOAT:
268 size = sizeof(float);
269 break;
270 case PSI_T_DOUBLE:
271 size = sizeof(double);
272 break;
273 case PSI_T_SIZE_T:
274 size = sizeof(size_t);
275 break;
276 case PSI_T_POINTER:
277 size = sizeof(char *);
278 break;
279 EMPTY_SWITCH_DEFAULT_CASE();
280 }
281 return size;
282 }
283
284 size_t psi_t_align(token_t t, size_t s)
285 {
286 size_t a = psi_t_alignment(t);
287 return ((s - 1) | (a - 1)) + 1;
288 }
289
290 static impl_val *iterate(impl_val *val, token_t t, unsigned i, impl_val *tmp)
291 {
292 size_t size = psi_t_size(t);
293
294 memset(tmp, 0, sizeof(*tmp));
295 memcpy(tmp, val->ptr + size * i, size);
296 return tmp;
297 }
298
299 void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
300 {
301 decl_type *type = real_decl_type(spec->type);
302
303 switch (type->type) {
304 case PSI_T_FLOAT:
305 mem->fval = (float) zval_get_double(zv);
306 break;
307 case PSI_T_DOUBLE:
308 mem->dval = zval_get_double(zv);
309 break;
310 case PSI_T_CHAR:
311 case PSI_T_SINT8:
312 case PSI_T_UINT8:
313 if (spec->var->pointer_level) {
314 zend_string *zs = zval_get_string(zv);
315 *tmp = mem->ptr = estrndup(zs->val, zs->len);
316 zend_string_release(zs);
317 break;
318 }
319 default:
320 mem->zend.lval = zval_get_long(zv);
321 break;
322 }
323 }
324
325 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
326 {
327 size_t i, j = 0, size = decl_struct_size(s);
328 char *mem = ecalloc(1, size + s->args->count * sizeof(void *));
329
330 for (i = 0; i < s->args->count; ++i) {
331 decl_struct_layout *layout = &s->layout[i];
332 decl_arg *darg = s->args->args[i];
333 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
334
335 if (entry) {
336 impl_val val;
337 void *tmp = NULL;
338
339 memset(&tmp, 0, sizeof(tmp));
340 psi_from_zval(&val, darg, entry, &tmp);
341 memcpy(mem + layout->pos, &val, layout->len);
342 if (tmp) {
343 ((void **)(mem + size))[j++] = tmp;
344 }
345 }
346 }
347 return mem;
348 }
349
350 void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, decl_var *var)
351 {
352 zval ele;
353 unsigned i;
354 impl_val tmp;
355
356 array_init(return_value);
357
358 if (t == PSI_T_STRUCT) {
359 decl_struct *s = real_decl_type(var->arg->type)->strct;
360 ret_val = deref_impl_val(ret_val, var);
361
362 ZEND_ASSERT(s);
363 for (i = 0; i < s->args->count; ++i) {
364 decl_arg *darg = s->args->args[i];
365 decl_struct_layout layout = s->layout[i];
366 impl_val tmp;
367 zval ztmp;
368 char *ptr = (char *) ret_val + layout.pos;
369
370 memset(&tmp, 0, sizeof(tmp));
371 memcpy(&tmp, ptr, layout.len);
372 switch (real_decl_type(darg->type)->type) {
373 case PSI_T_CHAR:
374 if (darg->var->pointer_level) {
375 psi_to_string(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
376 break;
377 }
378 /* nobreak */
379 case PSI_T_INT:
380 case PSI_T_LONG:
381 psi_to_int(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
382 break;
383 default:
384 printf("t=%d\n", real_decl_type(darg->type)->type);
385 abort();
386 }
387 add_assoc_zval(return_value, darg->var->name, &ztmp);
388 }
389 return;
390 }
391 ret_val = deref_impl_val(ret_val, var);
392 for (i = 0; i < var->arg->var->array_size; ++i) {
393 impl_val *ptr = iterate(ret_val, t, i, &tmp);
394
395 switch (t) {
396 case PSI_T_FLOAT:
397 ZVAL_DOUBLE(&ele, (double) ptr->fval);
398 break;
399 case PSI_T_DOUBLE:
400 ZVAL_DOUBLE(&ele, ptr->dval);
401 break;
402 default:
403 ZVAL_LONG(&ele, ptr->lval);
404 break;
405 }
406
407 add_next_index_zval(return_value, &ele);
408 }
409 }
410
411 ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
412 {
413 impl_arg *iarg;
414
415 if (!impl->func->args->count) {
416 return zend_parse_parameters_none();
417 }
418
419 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->count)
420 nextarg:
421 iarg = impl->func->args->args[_i];
422 if (iarg->def) {
423 Z_PARAM_OPTIONAL;
424 }
425 if (PSI_T_BOOL == iarg->type->type) {
426 if (iarg->def) {
427 iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
428 }
429 Z_PARAM_BOOL(iarg->val.zend.bval);
430 } else if (PSI_T_INT == iarg->type->type || PSI_T_LONG == iarg->type->type) {
431 if (iarg->def) {
432 iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
433 }
434 Z_PARAM_LONG(iarg->val.zend.lval);
435 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
436 if (iarg->def) {
437 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
438 }
439 Z_PARAM_DOUBLE(iarg->val.dval);
440 } else if (PSI_T_STRING == iarg->type->type) {
441 struct {char *val; size_t len;} str;
442 if (iarg->def) {
443 /* FIXME */
444 str.len = strlen(iarg->def->text) - 2;
445 str.val = &iarg->def->text[1];
446 }
447 Z_PARAM_STR_EX(iarg->val.zend.str, 1, 0);
448 if (iarg->val.zend.str) {
449 zend_string_addref(iarg->val.zend.str);
450 } else if (iarg->def) {
451 iarg->val.zend.str = zend_string_init(str.val, str.len, 0);
452 }
453 } else if (PSI_T_ARRAY == iarg->type->type) {
454 /* handled as _zv in let or set */
455 Z_PARAM_PROLOGUE(0);
456 } else {
457 error_code = ZPP_ERROR_FAILURE;
458 break;
459 }
460 iarg->_zv = _arg;
461 if (_i < _max_num_args) {
462 goto nextarg;
463 }
464 ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
465
466 return SUCCESS;
467 }
468
469 void *psi_do_calloc(let_calloc *alloc)
470 {
471 decl_type *type = real_decl_type(alloc->type);
472 size_t size;
473
474 if (type->type == PSI_T_STRUCT) {
475 /* psi_do_clean expects a NULL pointer after the struct */
476 size = decl_struct_size(type->strct) + sizeof(void *);
477 } else {
478 size = psi_t_size(type->type);
479 }
480
481 return ecalloc(alloc->n, size);
482 }
483
484 impl_val *psi_do_let(decl_arg *darg)
485 {
486 impl_val *arg_val = &darg->let->out;
487 impl_arg *iarg = darg->let->arg;
488
489 if (!iarg) {
490 /* let foo = calloc(1, long);
491 * let foo = NULL;
492 * let foo;
493 */
494 if (darg->let->val->func->type == PSI_T_CALLOC) {
495 arg_val->ptr = psi_do_calloc(darg->let->val->func->alloc);
496 darg->let->mem = arg_val->ptr;
497 } else if (darg->var->array_size) {
498 arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val));
499 darg->let->mem = arg_val->ptr;
500 } else {
501 memset(arg_val, 0, sizeof(*arg_val));
502 }
503 return arg_val;
504 }
505
506 switch (darg->let->val->func->type) {
507 case PSI_T_BOOLVAL:
508 if (iarg->type->type == PSI_T_BOOL) {
509 arg_val->cval = iarg->val.zend.bval;
510 } else {
511 arg_val->cval = zend_is_true(iarg->_zv);
512 }
513 break;
514 case PSI_T_INTVAL:
515 if (iarg->type->type == PSI_T_INT || iarg->type->type == PSI_T_LONG) {
516 arg_val->lval = iarg->val.zend.lval;
517 } else {
518 arg_val->lval = zval_get_long(iarg->_zv);
519 }
520 break;
521 case PSI_T_STRVAL:
522 if (iarg->type->type == PSI_T_STRING) {
523 arg_val->ptr = estrdup(iarg->val.zend.str->val);
524 darg->let->mem = arg_val->ptr;
525 zend_string_release(iarg->val.zend.str);
526 } else {
527 zend_string *zs = zval_get_string(iarg->_zv);
528 arg_val->ptr = estrdup(zs->val);
529 darg->let->mem = arg_val->ptr;
530 zend_string_release(zs);
531 }
532 break;
533 case PSI_T_STRLEN:
534 if (iarg->type->type == PSI_T_STRING) {
535 arg_val->lval = iarg->val.zend.str->len;
536 zend_string_release(iarg->val.zend.str);
537 } else {
538 zend_string *zs = zval_get_string(iarg->_zv);
539 arg_val->lval = zs->len;
540 zend_string_release(zs);
541 }
542 break;
543 case PSI_T_ARRVAL:
544 if (iarg->type->type == PSI_T_ARRAY) {
545 decl_type *type = real_decl_type(darg->type);
546
547 switch (type->type) {
548 case PSI_T_STRUCT:
549 arg_val->ptr = psi_array_to_struct(type->strct, HASH_OF(iarg->_zv));
550 darg->let->mem = arg_val->ptr;
551 break;
552 }
553 }
554 break;
555 EMPTY_SWITCH_DEFAULT_CASE();
556 }
557
558 return arg_val;
559 }
560
561 void psi_do_set(zval *return_value, set_func *func, decl_vars *vars)
562 {
563 impl_val *val = (impl_val *) &vars->vars[0]->arg->let->ptr;
564
565 ZVAL_DEREF(return_value);
566 zval_dtor(return_value);
567
568 switch (func->type) {
569 case PSI_T_TO_STRING:
570 psi_to_string(return_value, real_decl_type(vars->vars[0]->arg->type)->type, val, vars->vars[0]);
571 break;
572 case PSI_T_TO_ARRAY:
573 psi_to_array(return_value, real_decl_type(vars->vars[0]->arg->type)->type, val, vars->vars[0]);
574 break;
575 EMPTY_SWITCH_DEFAULT_CASE();
576 }
577 }
578
579 void psi_do_return(impl *impl, impl_val *ret_val, zval *return_value)
580 {
581 return_stmt *ret = impl->stmts->ret.list[0];
582
583 switch (ret->func->type) {
584 case PSI_T_TO_STRING:
585 psi_to_string(return_value, real_decl_type(impl->decl->func->type)->type, ret_val, ret->decl);
586 break;
587 case PSI_T_TO_INT:
588 psi_to_int(return_value, real_decl_type(impl->decl->func->type)->type, ret_val, ret->decl);
589 break;
590 case PSI_T_TO_ARRAY:
591 psi_to_array(return_value, real_decl_type(impl->decl->func->type)->type, ret_val, ret->decl);
592 break;
593 EMPTY_SWITCH_DEFAULT_CASE();
594 }
595 }
596
597 void psi_do_free(free_stmt *fre)
598 {
599 size_t i;
600
601 for (i = 0; i < fre->vars->count; ++i) {
602 decl_var *dvar = fre->vars->vars[i];
603
604 if (dvar->arg && dvar->arg->let->out.ptr) {
605 free(dvar->arg->let->out.ptr);
606 dvar->arg->let->out.ptr = NULL;
607 }
608 }
609 }
610
611 void psi_do_clean(impl *impl)
612 {
613 size_t i;
614
615 for (i = 0; i < impl->func->args->count; ++i ) {
616 impl_arg *iarg = impl->func->args->args[i];
617
618 switch (iarg->type->type) {
619 case PSI_T_STRING:
620 if (iarg->val.zend.str) {
621 zend_string_release(iarg->val.zend.str);
622 }
623 break;
624 }
625 }
626
627 if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
628 decl_arg *darg = impl->decl->args->args[i];
629
630 if (darg->let && darg->let->mem) {
631 decl_type *type = real_decl_type(darg->type);
632
633 if (type->type == PSI_T_STRUCT) {
634 size_t eos = decl_struct_size(type->strct);
635 void **ptr = (void **) ((char *) darg->let->mem + eos);
636
637 while (*ptr) {
638 efree(*ptr++);
639 }
640 }
641 efree(darg->let->mem);
642 darg->let->mem = NULL;
643 }
644 }
645 }
646
647 PHP_MINIT_FUNCTION(psi)
648 {
649 PSI_ContextOps *ops;
650
651 REGISTER_INI_ENTRIES();
652
653 if (!strcasecmp(PSI_G(engine), "jit")) {
654 ops = PSI_Libjit();
655 } else {
656 ops = PSI_Libffi();
657 }
658
659 PSI_ContextInit(&PSI_G(context), ops, psi_error);
660 PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
661
662 return SUCCESS;
663 }
664 PHP_MSHUTDOWN_FUNCTION(psi)
665 {
666 PSI_ContextDtor(&PSI_G(context));
667
668 UNREGISTER_INI_ENTRIES();
669
670 return SUCCESS;
671 }
672
673 /* Remove if there's nothing to do at request start */
674 /* {{{ PHP_RINIT_FUNCTION
675 */
676 PHP_RINIT_FUNCTION(psi)
677 {
678 #if defined(COMPILE_DL_PSI) && defined(ZTS)
679 ZEND_TSRMLS_CACHE_UPDATE();
680 #endif
681 return SUCCESS;
682 }
683 /* }}} */
684
685 /* Remove if there's nothing to do at request end */
686 /* {{{ PHP_RSHUTDOWN_FUNCTION
687 */
688 PHP_RSHUTDOWN_FUNCTION(psi)
689 {
690 return SUCCESS;
691 }
692 /* }}} */
693
694 PHP_MINFO_FUNCTION(psi)
695 {
696 php_info_print_table_start();
697 php_info_print_table_header(2, "psi support", "enabled");
698 php_info_print_table_end();
699
700 DISPLAY_INI_ENTRIES();
701 }
702 const zend_function_entry psi_functions[] = {
703 PHP_FE_END
704 };
705
706 zend_module_entry psi_module_entry = {
707 STANDARD_MODULE_HEADER,
708 "psi",
709 psi_functions,
710 PHP_MINIT(psi),
711 PHP_MSHUTDOWN(psi),
712 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
713 PHP_RSHUTDOWN(psi), /* Replace with NULL if there's nothing to do at request end */
714 PHP_MINFO(psi),
715 PHP_PSI_VERSION,
716 STANDARD_MODULE_PROPERTIES
717 };
718
719 #ifdef COMPILE_DL_PSI
720 #ifdef ZTS
721 ZEND_TSRMLS_CACHE_DEFINE();
722 #endif
723 ZEND_GET_MODULE(psi)
724 #endif
725
726 /*
727 * Local variables:
728 * tab-width: 4
729 * c-basic-offset: 4
730 * End:
731 * vim600: noet sw=4 ts=4 fdm=marker
732 * vim<600: noet sw=4 ts=4
733 */