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