166596434ae8a4447bcebcf362c8e5d5b85751e8
[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_string(impl_val *ret_val, decl_arg *func, zval *return_value)
111 {
112 switch (real_decl_type(func->type)->type) {
113 case PSI_T_CHAR:
114 case PSI_T_SINT8:
115 case PSI_T_UINT8:
116 if (!func->var->pointer_level) {
117 char chr = ret_val->lval;
118 RETVAL_STRINGL(&chr, 1);
119 } else {
120 ret_val = deref_impl_val(1, ret_val, func);
121 if (ret_val->ptr) {
122 RETVAL_STRING(ret_val->ptr);
123 } else {
124 RETVAL_EMPTY_STRING();
125 }
126 }
127 break;
128 case PSI_T_FLOAT:
129 case PSI_T_DOUBLE:
130 RETVAL_DOUBLE(deref_impl_val(0, ret_val, func)->dval);
131 convert_to_string(return_value);
132 break;
133 default:
134 RETVAL_LONG(deref_impl_val(0, ret_val, func)->lval);
135 convert_to_string(return_value);
136 break;
137 }
138 }
139
140 ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
141 {
142 impl_arg *iarg;
143
144 if (!impl->func->args->count) {
145 return zend_parse_parameters_none();
146 }
147
148 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->count)
149 nextarg:
150 iarg = impl->func->args->args[_i];
151 if (iarg->def) {
152 Z_PARAM_OPTIONAL;
153 }
154 if (PSI_T_BOOL == iarg->type->type) {
155 if (iarg->def) {
156 iarg->val.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
157 }
158 Z_PARAM_BOOL(iarg->val.bval);
159 } else if (PSI_T_INT == iarg->type->type) {
160 if (iarg->def) {
161 iarg->val.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
162 }
163 Z_PARAM_LONG(iarg->val.lval);
164 } else if (PSI_T_FLOAT == iarg->type->type) {
165 if (iarg->def) {
166 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
167 }
168 Z_PARAM_DOUBLE(iarg->val.dval);
169 } else if (PSI_T_STRING == iarg->type->type) {
170 struct {char *val; size_t len;} str;
171 if (iarg->def) {
172 /* FIXME */
173 str.len = strlen(iarg->def->text) - 2;
174 str.val = &iarg->def->text[1];
175 }
176 Z_PARAM_STR_EX(iarg->val.str, 1, 0);
177 if (iarg->val.str) {
178 zend_string_addref(iarg->val.str);
179 } else if (iarg->def) {
180 iarg->val.str = zend_string_init(str.val, str.len, 0);
181 }
182 } else {
183 error_code = ZPP_ERROR_FAILURE;
184 break;
185 }
186 iarg->_zv = _arg;
187 if (_i < _max_num_args) {
188 goto nextarg;
189 }
190 ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
191
192 return SUCCESS;
193 }
194
195 impl_val *psi_do_let(decl_arg *darg)
196 {
197 impl_val *arg_val = &darg->let->out;
198 impl_arg *iarg = darg->let->arg;
199
200 if (!iarg) {
201 /* let foo = NULL */
202 memset(arg_val, 0, sizeof(*arg_val));
203 return arg_val;
204 }
205 switch (darg->let->val->func->type) {
206 case PSI_T_BOOLVAL:
207 if (iarg->type->type == PSI_T_BOOL) {
208 arg_val->cval = iarg->val.cval;
209 } else {
210 arg_val->cval = zend_is_true(iarg->_zv);
211 }
212 break;
213 case PSI_T_INTVAL:
214 if (iarg->type->type == PSI_T_INT) {
215 arg_val->lval = iarg->val.lval;
216 } else {
217 arg_val->lval = zval_get_long(iarg->_zv);
218 }
219 break;
220 case PSI_T_STRVAL:
221 if (iarg->type->type == PSI_T_STRING) {
222 arg_val->ptr = estrdup(iarg->val.str->val);
223 darg->let->mem = arg_val->ptr;
224 zend_string_release(iarg->val.str);
225 } else {
226 zend_string *zs = zval_get_string(iarg->_zv);
227 arg_val->ptr = estrdup(zs->val);
228 darg->let->mem = arg_val->ptr;
229 zend_string_release(zs);
230 }
231 break;
232 case PSI_T_STRLEN:
233 if (iarg->type->type == PSI_T_STRING) {
234 arg_val->lval = iarg->val.str->len;
235 zend_string_release(iarg->val.str);
236 } else {
237 zend_string *zs = zval_get_string(iarg->_zv);
238 arg_val->lval = zs->len;
239 zend_string_release(zs);
240 }
241 break;
242 EMPTY_SWITCH_DEFAULT_CASE();
243 }
244
245 return arg_val;
246 }
247
248 void psi_do_set(zval *return_value, set_func *func, decl_vars *vars)
249 {
250 impl_val *val = (impl_val *) &vars->vars[0]->arg->let->ptr;
251
252 ZVAL_DEREF(return_value);
253 zval_dtor(return_value);
254
255 switch (func->type) {
256 case PSI_T_TO_STRING:
257 psi_to_string(val, vars->vars[0]->arg, return_value);
258 break;
259 EMPTY_SWITCH_DEFAULT_CASE();
260 }
261 }
262
263 void psi_do_return(impl *impl, impl_val *ret_val, zval *return_value)
264 {
265 switch (impl->stmts->ret.list[0]->func->type) {
266 case PSI_T_TO_STRING:
267 psi_to_string(ret_val, impl->decl->func, return_value);
268 break;
269 case PSI_T_TO_INT:
270 psi_to_int(ret_val, impl->decl->func, return_value);
271 break;
272 EMPTY_SWITCH_DEFAULT_CASE();
273 }
274 }
275
276 void psi_do_free(free_stmt *fre)
277 {
278 size_t i;
279
280 for (i = 0; i < fre->vars->count; ++i) {
281 decl_var *dvar = fre->vars->vars[i];
282
283 if (dvar->arg && dvar->arg->let->out.ptr) {
284 free(dvar->arg->let->out.ptr);
285 dvar->arg->let->out.ptr = NULL;
286 }
287 }
288 }
289
290 void psi_do_clean(impl *impl)
291 {
292 size_t i;
293
294 for (i = 0; i < impl->func->args->count; ++i ) {
295 impl_arg *iarg = impl->func->args->args[i];
296
297 switch (iarg->type->type) {
298 case PSI_T_STRING:
299 if (iarg->val.str) {
300 zend_string_release(iarg->val.str);
301 }
302 break;
303 }
304 }
305
306 for (i = 0; i < impl->decl->args->count; ++i) {
307 decl_arg *darg = impl->decl->args->args[i];
308
309 if (darg->let && darg->let->mem) {
310 efree(darg->let->mem);
311 darg->let->mem = NULL;
312 }
313 }
314 }
315
316 PHP_MINIT_FUNCTION(psi)
317 {
318 PSI_ContextOps *ops;
319
320 REGISTER_INI_ENTRIES();
321
322 if (!strcasecmp(PSI_G(engine), "jit")) {
323 ops = PSI_Libjit();
324 } else {
325 ops = PSI_Libffi();
326 }
327
328 PSI_ContextInit(&PSI_G(context), ops, psi_error);
329 PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
330
331 return SUCCESS;
332 }
333 PHP_MSHUTDOWN_FUNCTION(psi)
334 {
335 PSI_ContextDtor(&PSI_G(context));
336
337 UNREGISTER_INI_ENTRIES();
338
339 return SUCCESS;
340 }
341
342 /* Remove if there's nothing to do at request start */
343 /* {{{ PHP_RINIT_FUNCTION
344 */
345 PHP_RINIT_FUNCTION(psi)
346 {
347 #if defined(COMPILE_DL_PSI) && defined(ZTS)
348 ZEND_TSRMLS_CACHE_UPDATE();
349 #endif
350 return SUCCESS;
351 }
352 /* }}} */
353
354 /* Remove if there's nothing to do at request end */
355 /* {{{ PHP_RSHUTDOWN_FUNCTION
356 */
357 PHP_RSHUTDOWN_FUNCTION(psi)
358 {
359 return SUCCESS;
360 }
361 /* }}} */
362
363 PHP_MINFO_FUNCTION(psi)
364 {
365 php_info_print_table_start();
366 php_info_print_table_header(2, "psi support", "enabled");
367 php_info_print_table_end();
368
369 DISPLAY_INI_ENTRIES();
370 }
371 const zend_function_entry psi_functions[] = {
372 PHP_FE_END
373 };
374
375 zend_module_entry psi_module_entry = {
376 STANDARD_MODULE_HEADER,
377 "psi",
378 psi_functions,
379 PHP_MINIT(psi),
380 PHP_MSHUTDOWN(psi),
381 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
382 PHP_RSHUTDOWN(psi), /* Replace with NULL if there's nothing to do at request end */
383 PHP_MINFO(psi),
384 PHP_PSI_VERSION,
385 STANDARD_MODULE_PROPERTIES
386 };
387
388 #ifdef COMPILE_DL_PSI
389 #ifdef ZTS
390 ZEND_TSRMLS_CACHE_DEFINE();
391 #endif
392 ZEND_GET_MODULE(psi)
393 #endif
394
395 /*
396 * Local variables:
397 * tab-width: 4
398 * c-basic-offset: 4
399 * End:
400 * vim600: noet sw=4 ts=4 fdm=marker
401 * vim<600: noet sw=4 ts=4
402 */