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
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 && ret_val->ptr) {
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 /* no break */
320 default:
321 mem->zend.lval = zval_get_long(zv);
322 break;
323 }
324 }
325
326 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
327 {
328 size_t i, j = 0, size = decl_struct_size(s);
329 char *mem = ecalloc(1, size + s->args->count * sizeof(void *));
330
331 if (arr) for (i = 0; i < s->args->count; ++i) {
332 decl_struct_layout *layout = &s->layout[i];
333 decl_arg *darg = s->args->args[i];
334 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
335
336 if (entry) {
337 impl_val val;
338 void *tmp = NULL;
339
340 memset(&tmp, 0, sizeof(tmp));
341 psi_from_zval(&val, darg, entry, &tmp);
342 memcpy(mem + layout->pos, &val, layout->len);
343 if (tmp) {
344 ((void **)(mem + size))[j++] = tmp;
345 }
346 }
347 }
348 return mem;
349 }
350
351 void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, decl_var *var)
352 {
353 zval ele;
354 unsigned i;
355 impl_val tmp;
356
357 array_init(return_value);
358
359 if (t == PSI_T_STRUCT) {
360 decl_struct *s = real_decl_type(var->arg->type)->strct;
361 ret_val = deref_impl_val(ret_val, var);
362
363 ZEND_ASSERT(s);
364 for (i = 0; i < s->args->count; ++i) {
365 decl_arg *darg = s->args->args[i];
366 decl_struct_layout layout = s->layout[i];
367 impl_val tmp;
368 zval ztmp;
369 char *ptr = (char *) ret_val->ptr + layout.pos;
370
371 memset(&tmp, 0, sizeof(tmp));
372 memcpy(&tmp, ptr, layout.len);
373 switch (real_decl_type(darg->type)->type) {
374 case PSI_T_CHAR:
375 if (darg->var->pointer_level) {
376 psi_to_string(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
377 break;
378 }
379 /* no break */
380 case PSI_T_INT:
381 case PSI_T_LONG:
382 psi_to_int(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
383 break;
384 default:
385 printf("t=%d\n", real_decl_type(darg->type)->type);
386 abort();
387 }
388 add_assoc_zval(return_value, darg->var->name, &ztmp);
389 }
390 return;
391 }
392 ret_val = deref_impl_val(ret_val, var);
393 for (i = 0; i < var->arg->var->array_size; ++i) {
394 impl_val *ptr = iterate(ret_val, t, i, &tmp);
395
396 switch (t) {
397 case PSI_T_FLOAT:
398 ZVAL_DOUBLE(&ele, (double) ptr->fval);
399 break;
400 case PSI_T_DOUBLE:
401 ZVAL_DOUBLE(&ele, ptr->dval);
402 break;
403 default:
404 ZVAL_LONG(&ele, ptr->lval);
405 break;
406 }
407
408 add_next_index_zval(return_value, &ele);
409 }
410 }
411
412 ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
413 {
414 impl_arg *iarg;
415
416 if (!impl->func->args->count) {
417 return zend_parse_parameters_none();
418 }
419
420 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->count)
421 nextarg:
422 iarg = impl->func->args->args[_i];
423 if (iarg->def) {
424 Z_PARAM_OPTIONAL;
425 }
426 if (PSI_T_BOOL == iarg->type->type) {
427 if (iarg->def) {
428 iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
429 }
430 Z_PARAM_BOOL(iarg->val.zend.bval);
431 } else if (PSI_T_INT == iarg->type->type || PSI_T_LONG == iarg->type->type) {
432 if (iarg->def) {
433 iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
434 }
435 Z_PARAM_LONG(iarg->val.zend.lval);
436 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
437 if (iarg->def) {
438 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
439 }
440 Z_PARAM_DOUBLE(iarg->val.dval);
441 } else if (PSI_T_STRING == iarg->type->type) {
442 struct {char *val; size_t len;} str;
443 if (iarg->def) {
444 /* FIXME */
445 str.len = strlen(iarg->def->text) - 2;
446 str.val = &iarg->def->text[1];
447 }
448 Z_PARAM_STR_EX(iarg->val.zend.str, 1, 0);
449 if (iarg->val.zend.str) {
450 zend_string_addref(iarg->val.zend.str);
451 } else if (iarg->def) {
452 iarg->val.zend.str = zend_string_init(str.val, str.len, 0);
453 }
454 } else if (PSI_T_ARRAY == iarg->type->type) {
455 /* handled as _zv in let or set */
456 Z_PARAM_PROLOGUE(0);
457 } else {
458 error_code = ZPP_ERROR_FAILURE;
459 break;
460 }
461 iarg->_zv = _arg;
462 if (_i < _max_num_args) {
463 goto nextarg;
464 }
465 ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
466
467 return SUCCESS;
468 }
469
470 void *psi_do_calloc(let_calloc *alloc)
471 {
472 decl_type *type = real_decl_type(alloc->type);
473 size_t size;
474
475 if (type->type == PSI_T_STRUCT) {
476 /* psi_do_clean expects a NULL pointer after the struct */
477 size = decl_struct_size(type->strct) + sizeof(void *);
478 } else {
479 size = psi_t_size(type->type);
480 }
481
482 return ecalloc(alloc->n, size);
483 }
484
485 void *psi_do_let(decl_arg *darg)
486 {
487 impl_arg *iarg = darg->let->arg;
488 impl_val *arg_val;
489
490 darg->let->ptr = &darg->let->out;
491 arg_val = darg->let->ptr;
492
493 if (!iarg) {
494 /* let foo = calloc(1, long);
495 * let foo = NULL;
496 * let foo;
497 */
498 if (darg->let->val->func && darg->let->val->func->type == PSI_T_CALLOC) {
499 arg_val->ptr = psi_do_calloc(darg->let->val->func->alloc);
500 darg->let->mem = arg_val->ptr;
501 } else if (darg->var->array_size) {
502 arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val));
503 darg->let->mem = arg_val->ptr;
504 } else {
505 memset(arg_val, 0, sizeof(*arg_val));
506 }
507 } else {
508
509 switch (darg->let->val->func->type) {
510 case PSI_T_BOOLVAL:
511 if (iarg->type->type == PSI_T_BOOL) {
512 arg_val->cval = iarg->val.zend.bval;
513 } else {
514 arg_val->cval = zend_is_true(iarg->_zv);
515 }
516 break;
517 case PSI_T_INTVAL:
518 if (iarg->type->type == PSI_T_INT || iarg->type->type == PSI_T_LONG) {
519 arg_val->lval = iarg->val.zend.lval;
520 } else {
521 arg_val->lval = zval_get_long(iarg->_zv);
522 }
523 break;
524 case PSI_T_STRVAL:
525 if (iarg->type->type == PSI_T_STRING) {
526 arg_val->ptr = estrdup(iarg->val.zend.str->val);
527 darg->let->mem = arg_val->ptr;
528 zend_string_release(iarg->val.zend.str);
529 } else {
530 zend_string *zs = zval_get_string(iarg->_zv);
531 arg_val->ptr = estrdup(zs->val);
532 darg->let->mem = arg_val->ptr;
533 zend_string_release(zs);
534 }
535 break;
536 case PSI_T_STRLEN:
537 if (iarg->type->type == PSI_T_STRING) {
538 arg_val->lval = iarg->val.zend.str->len;
539 zend_string_release(iarg->val.zend.str);
540 } else {
541 zend_string *zs = zval_get_string(iarg->_zv);
542 arg_val->lval = zs->len;
543 zend_string_release(zs);
544 }
545 break;
546 case PSI_T_ARRVAL:
547 if (iarg->type->type == PSI_T_ARRAY) {
548 decl_type *type = real_decl_type(darg->type);
549
550 switch (type->type) {
551 case PSI_T_STRUCT:
552 arg_val->ptr = psi_array_to_struct(type->strct, HASH_OF(iarg->_zv));
553 darg->let->mem = arg_val->ptr;
554 break;
555 }
556 }
557 break;
558 EMPTY_SWITCH_DEFAULT_CASE();
559 }
560 }
561
562 if (darg->let->val && darg->let->val->is_reference) {
563 return &darg->let->ptr;
564 } else {
565 return darg->let->ptr;
566 }
567 }
568
569 void psi_do_set(zval *return_value, set_func *func, decl_vars *vars)
570 {
571 impl_val *val = (impl_val *) &vars->vars[0]->arg->let->ptr;
572
573 ZVAL_DEREF(return_value);
574 zval_dtor(return_value);
575
576 switch (func->type) {
577 case PSI_T_TO_STRING:
578 psi_to_string(return_value, real_decl_type(vars->vars[0]->arg->type)->type, val, vars->vars[0]);
579 break;
580 case PSI_T_TO_ARRAY:
581 psi_to_array(return_value, real_decl_type(vars->vars[0]->arg->type)->type, val, vars->vars[0]);
582 break;
583 EMPTY_SWITCH_DEFAULT_CASE();
584 }
585 }
586
587 void psi_do_return(impl *impl, impl_val *ret_val, zval *return_value)
588 {
589 return_stmt *ret = impl->stmts->ret.list[0];
590
591 switch (ret->func->type) {
592 case PSI_T_TO_STRING:
593 psi_to_string(return_value, real_decl_type(impl->decl->func->type)->type, ret_val, ret->decl);
594 break;
595 case PSI_T_TO_INT:
596 psi_to_int(return_value, real_decl_type(impl->decl->func->type)->type, ret_val, ret->decl);
597 break;
598 case PSI_T_TO_ARRAY:
599 psi_to_array(return_value, real_decl_type(impl->decl->func->type)->type, ret_val, ret->decl);
600 break;
601 EMPTY_SWITCH_DEFAULT_CASE();
602 }
603 }
604
605 void psi_do_free(free_stmt *fre)
606 {
607 size_t i;
608
609 for (i = 0; i < fre->vars->count; ++i) {
610 decl_var *dvar = fre->vars->vars[i];
611
612 if (dvar->arg && dvar->arg->let->out.ptr) {
613 free(dvar->arg->let->out.ptr);
614 dvar->arg->let->out.ptr = NULL;
615 }
616 }
617 }
618
619 void psi_do_clean(impl *impl)
620 {
621 size_t i;
622
623 for (i = 0; i < impl->func->args->count; ++i ) {
624 impl_arg *iarg = impl->func->args->args[i];
625
626 switch (iarg->type->type) {
627 case PSI_T_STRING:
628 if (iarg->val.zend.str) {
629 zend_string_release(iarg->val.zend.str);
630 }
631 break;
632 }
633 }
634
635 if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
636 decl_arg *darg = impl->decl->args->args[i];
637
638 if (darg->let && darg->let->mem) {
639 decl_type *type = real_decl_type(darg->type);
640
641 if (type->type == PSI_T_STRUCT) {
642 size_t eos = decl_struct_size(type->strct);
643 void **ptr = (void **) ((char *) darg->let->mem + eos);
644
645 while (*ptr) {
646 efree(*ptr++);
647 }
648 }
649 efree(darg->let->mem);
650 darg->let->mem = NULL;
651 }
652 }
653 }
654
655 PHP_MINIT_FUNCTION(psi)
656 {
657 PSI_ContextOps *ops;
658
659 REGISTER_INI_ENTRIES();
660
661 if (!strcasecmp(PSI_G(engine), "jit")) {
662 ops = PSI_Libjit();
663 } else {
664 ops = PSI_Libffi();
665 }
666
667 PSI_ContextInit(&PSI_G(context), ops, psi_error);
668 PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
669
670 return SUCCESS;
671 }
672 PHP_MSHUTDOWN_FUNCTION(psi)
673 {
674 PSI_ContextDtor(&PSI_G(context));
675
676 UNREGISTER_INI_ENTRIES();
677
678 return SUCCESS;
679 }
680
681 /* Remove if there's nothing to do at request start */
682 /* {{{ PHP_RINIT_FUNCTION
683 */
684 PHP_RINIT_FUNCTION(psi)
685 {
686 #if defined(COMPILE_DL_PSI) && defined(ZTS)
687 ZEND_TSRMLS_CACHE_UPDATE();
688 #endif
689 return SUCCESS;
690 }
691 /* }}} */
692
693 /* Remove if there's nothing to do at request end */
694 /* {{{ PHP_RSHUTDOWN_FUNCTION
695 */
696 PHP_RSHUTDOWN_FUNCTION(psi)
697 {
698 return SUCCESS;
699 }
700 /* }}} */
701
702 PHP_MINFO_FUNCTION(psi)
703 {
704 php_info_print_table_start();
705 php_info_print_table_header(2, "psi support", "enabled");
706 php_info_print_table_end();
707
708 DISPLAY_INI_ENTRIES();
709 }
710 const zend_function_entry psi_functions[] = {
711 PHP_FE_END
712 };
713
714 zend_module_entry psi_module_entry = {
715 STANDARD_MODULE_HEADER,
716 "psi",
717 psi_functions,
718 PHP_MINIT(psi),
719 PHP_MSHUTDOWN(psi),
720 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
721 PHP_RSHUTDOWN(psi), /* Replace with NULL if there's nothing to do at request end */
722 PHP_MINFO(psi),
723 PHP_PSI_VERSION,
724 STANDARD_MODULE_PROPERTIES
725 };
726
727 #ifdef COMPILE_DL_PSI
728 #ifdef ZTS
729 ZEND_TSRMLS_CACHE_DEFINE();
730 #endif
731 ZEND_GET_MODULE(psi)
732 #endif
733
734 /*
735 * Local variables:
736 * tab-width: 4
737 * c-basic-offset: 4
738 * End:
739 * vim600: noet sw=4 ts=4 fdm=marker
740 * vim<600: noet sw=4 ts=4
741 */