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