fix macro expansion
[m6w6/ext-psi] / src / call.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31
32 #include "context.h"
33 #include "data.h"
34 #include "call.h"
35
36 #include "php_psi.h"
37
38 #include "php.h"
39 #include "zend_exceptions.h"
40
41 struct psi_call_frame_argument *psi_call_frame_argument_init(struct psi_impl_arg *spec,
42 impl_val *ival, zval *zptr, int is_vararg) {
43 struct psi_call_frame_argument *frame_arg = ecalloc(1, sizeof(*frame_arg));
44
45
46 if ((frame_arg->zval_ptr = zptr)) {
47 ZVAL_DEREF(frame_arg->zval_ptr);
48
49 /* use userland type if the declared type of the vararg is mixed */
50 if (is_vararg) {
51 if (spec->type->type == PSI_T_MIXED) {
52 switch (Z_TYPE_P(zptr)) {
53 case IS_TRUE:
54 frame_arg->va_type = PSI_T_BOOL;
55 ival->zend.bval = 1;
56 break;
57 case IS_FALSE:
58 frame_arg->va_type = PSI_T_BOOL;
59 ival->zend.bval = 0;
60 break;
61 case IS_LONG:
62 frame_arg->va_type = PSI_T_INT;
63 ival->zend.lval = Z_LVAL_P(zptr);
64 break;
65 case IS_DOUBLE:
66 frame_arg->va_type = PSI_T_FLOAT;
67 ival->dval = Z_DVAL_P(zptr);
68 break;
69 default:
70 frame_arg->va_type = PSI_T_STRING;
71 ival->zend.str = zval_get_string(zptr);
72 break;
73 }
74 } else {
75 frame_arg->va_type = spec->type->type;
76 }
77 }
78 }
79
80 frame_arg->ival = *ival;
81 frame_arg->ival_ptr = &frame_arg->ival;
82 frame_arg->spec = spec;
83
84 return frame_arg;
85 }
86
87 void psi_call_frame_argument_free(struct psi_call_frame_argument *arg) {
88 switch (arg->spec->type->type) {
89 case PSI_T_STRING:
90 if (arg->ival.zend.str) {
91 zend_string_release(arg->ival.zend.str);
92 }
93 break;
94 case PSI_T_CALLABLE:
95 if (arg->ival.zend.cb) {
96 if (arg->ival.zend.cb->fci.size) {
97 zend_fcall_info_args_clear(&arg->ival.zend.cb->fci, 1);
98 }
99 efree(arg->ival.zend.cb);
100 }
101 break;
102 default:
103 break;
104 }
105 if (arg->ival_ptr && arg->ival_ptr != &arg->temp_val && arg->ival_ptr != &arg->ival) {
106 efree(arg->ival_ptr);
107 }
108 efree(arg);
109 }
110
111 struct psi_call_frame_symbol *psi_call_frame_symbol_init(struct psi_decl_var *dvar) {
112 struct psi_call_frame_symbol *frame_sym;
113 size_t size = psi_decl_type_get_size(dvar->arg->type, NULL);
114
115 frame_sym = ecalloc(1, sizeof(*frame_sym) + size);
116 frame_sym->ptr = frame_sym->ival_ptr = &frame_sym->temp_val;
117
118 return frame_sym;
119 }
120
121 void psi_call_frame_symbol_free(struct psi_call_frame_symbol *sym) {
122 efree(sym);
123 }
124
125 static void psi_call_frame_free_argument(zval *zptr) {
126 psi_call_frame_argument_free(Z_PTR_P(zptr));
127 }
128
129 static void psi_call_frame_free_symbol(zval *zptr) {
130 psi_call_frame_symbol_free(Z_PTR_P(zptr));
131 }
132
133 struct psi_call_frame_auto_free {
134 void *data;
135 void (*dtor)(void *);
136 };
137
138 static void psi_call_frame_free_temp(void *ptr) {
139 struct psi_call_frame_auto_free *f = ptr;
140
141 if (f->data) {
142 if (f->dtor) {
143 f->dtor(&f->data);
144 } else {
145 efree(f->data);
146 }
147 }
148 }
149
150 struct psi_call_frame *psi_call_frame_init(struct psi_context *C, struct psi_decl *decl, struct psi_impl *impl) {
151 struct psi_call_frame *frame = ecalloc(1, sizeof(*frame));
152
153 frame->context = C;
154 frame->decl = decl;
155 frame->impl = impl;
156
157 zend_hash_init(&frame->arguments, 8, NULL, psi_call_frame_free_argument, 0);
158 zend_hash_init(&frame->symbols, 8, NULL, psi_call_frame_free_symbol, 0);
159 zend_llist_init(&frame->temp, sizeof(struct psi_call_frame_auto_free), psi_call_frame_free_temp, 0);
160
161 return frame;
162 }
163
164 struct psi_call_frame_symbol *psi_call_frame_fetch_symbol(
165 struct psi_call_frame *frame, struct psi_decl_var *dvar) {
166 struct psi_call_frame_symbol *frame_sym;
167
168 frame_sym = zend_hash_find_ptr(&frame->symbols, dvar->fqn);
169 if (!frame_sym) {
170 frame_sym = zend_hash_add_ptr(&frame->symbols, dvar->fqn,
171 psi_call_frame_symbol_init(dvar));
172 }
173 return frame_sym;
174 }
175
176 zval *psi_call_frame_new_argument(struct psi_call_frame *frame,
177 struct psi_call_frame_argument *frame_arg) {
178 if (frame_arg->va_type) {
179 /* varargs are just appended with numeric indices */
180 return zend_hash_next_index_insert_ptr(&frame->arguments, frame_arg);
181 } else {
182 return zend_hash_add_ptr(&frame->arguments,
183 frame_arg->spec->var->name, frame_arg);
184 }
185 }
186
187 zval *psi_call_frame_sub_argument(struct psi_call_frame *frame,
188 struct psi_impl_var *inner_var, zval *outer_zval, zend_string *name) {
189 struct psi_call_frame_argument *iarg;
190 zval *inner_zval = zend_symtable_str_find(Z_ARRVAL_P(outer_zval),
191 &inner_var->name->val[1], inner_var->name->len - 1);
192
193 if (!inner_zval) {
194 zval empty_zval;
195
196 SEPARATE_ZVAL(outer_zval);
197 ZVAL_NULL(&empty_zval);
198 inner_zval = zend_symtable_str_update(Z_ARRVAL_P(outer_zval),
199 &inner_var->name->val[1], inner_var->name->len - 1,
200 &empty_zval);
201 }
202
203 iarg = psi_call_frame_get_argument(frame, name);
204
205 if (!iarg) {
206 struct psi_call_frame_argument *frame_arg;
207 impl_val empty_val = {0};
208 zend_string *type_str = psi_string_init_interned(ZEND_STRL("mixed"), 1);
209 struct psi_impl_arg *carg_spec = psi_impl_arg_init(
210 psi_impl_type_init(PSI_T_MIXED, type_str),
211 psi_impl_var_copy(inner_var), NULL);
212
213 psi_call_frame_push_auto_ex(frame, carg_spec, (void(*)(void*)) psi_impl_arg_free);
214 frame_arg = psi_call_frame_argument_init(carg_spec, &empty_val, inner_zval, 0);
215 zend_hash_add_ptr(&frame->arguments, name, frame_arg);
216 zend_string_release(type_str);
217 }
218
219 return inner_zval;
220 }
221
222 struct psi_call_frame_argument *psi_call_frame_get_argument(
223 struct psi_call_frame *frame, zend_string *name) {
224 return zend_hash_find_ptr(&frame->arguments, name);
225 }
226
227 size_t psi_call_frame_num_var_args(struct psi_call_frame *frame) {
228 return zend_hash_next_free_element(&frame->arguments);
229 }
230
231 size_t psi_call_frame_num_fixed_args(struct psi_call_frame *frame) {
232 return psi_plist_count(frame->decl->args);
233 }
234
235 struct psi_call_frame_argument *psi_call_frame_get_var_argument(
236 struct psi_call_frame *frame, zend_long index) {
237 return zend_hash_index_find_ptr(&frame->arguments, index);
238 }
239
240 void **psi_call_frame_get_arg_pointers(struct psi_call_frame *frame) {
241 return frame->pointers;
242 }
243
244 void *psi_call_frame_get_rpointer(struct psi_call_frame *frame) {
245 return frame->rpointer;
246 }
247
248 struct psi_decl *psi_call_frame_get_decl(struct psi_call_frame *frame) {
249 return frame->decl;
250 }
251
252 struct psi_impl *psi_call_frame_get_impl(struct psi_call_frame *frame) {
253 return frame->impl;
254 }
255
256 struct psi_context *psi_call_frame_get_context(struct psi_call_frame *frame) {
257 return frame->context;
258 }
259
260 #if PHP_VERSION_ID < 70300
261 # define PARAM_PROLOGUE(separate) Z_PARAM_PROLOGUE(separate)
262 #else
263 # define PARAM_PROLOGUE(separate) Z_PARAM_PROLOGUE(1, separate)
264 #endif
265 bool psi_call_frame_parse_args(struct psi_call_frame *frame,
266 zend_execute_data *execute_data) {
267 size_t i, argc = psi_plist_count(frame->impl->func->args);
268 zend_error_handling zeh;
269
270 zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
271
272 if (!argc) {
273 ZEND_RESULT_CODE rv;
274
275 rv = zend_parse_parameters_none();
276 zend_restore_error_handling(&zeh);
277 return rv == SUCCESS;
278 }
279
280 ZEND_PARSE_PARAMETERS_START(
281 psi_impl_num_min_args(frame->impl),
282 frame->impl->func->vararg ? -1 : argc
283 )
284 nextarg: {
285
286 struct psi_impl_arg *iarg;
287 impl_val ival = {0};
288
289 if (frame->impl->func->vararg && _i >= argc) {
290 iarg = frame->impl->func->vararg;
291 Z_PARAM_OPTIONAL;
292 } else {
293 psi_plist_get(frame->impl->func->args, _i, &iarg);
294 if (iarg->def) {
295 Z_PARAM_OPTIONAL;
296 }
297 }
298
299 if (PSI_T_BOOL == iarg->type->type) {
300 Z_PARAM_BOOL(ival.zend.bval);
301 } else if (PSI_T_INT == iarg->type->type) {
302 Z_PARAM_LONG(ival.zend.lval);
303 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
304 Z_PARAM_DOUBLE(ival.dval);
305 } else if (PSI_T_STRING == iarg->type->type) {
306 Z_PARAM_STR_EX(ival.zend.str, 1, iarg->var->reference);
307 if (ival.zend.str) {
308 zend_string_addref(ival.zend.str);
309 }
310 } else if (PSI_T_ARRAY == iarg->type->type) {
311 zval *tmp;
312 Z_PARAM_ARRAY_EX(tmp, _optional || iarg->var->reference,
313 iarg->var->reference);
314 } else if (PSI_T_OBJECT == iarg->type->type) {
315 PARAM_PROLOGUE(iarg->var->reference);
316 } else if (PSI_T_MIXED == iarg->type->type) {
317 PARAM_PROLOGUE(iarg->var->reference);
318 } else if (PSI_T_CALLABLE == iarg->type->type) {
319 zend_fcall_info fci;
320 zend_fcall_info_cache fcc;
321
322 Z_PARAM_FUNC_EX(fci, fcc, 1, 0);
323
324 if (fci.size) {
325 ival.zend.cb = ecalloc(1, sizeof(zend_fcall));
326 ival.zend.cb->fci = fci;
327 ival.zend.cb->fcc = fcc;
328 }
329 } else {
330 error_code = ZPP_ERROR_FAILURE;
331 break;
332 }
333
334 psi_call_frame_new_argument(frame,
335 psi_call_frame_argument_init(iarg, &ival, _arg, _i > argc));
336
337 if (_i < _num_args) {
338 goto nextarg;
339 }
340 }
341 ZEND_PARSE_PARAMETERS_END_EX(
342 zend_restore_error_handling(&zeh);
343 return false;
344 );
345
346 /* set up defaults */
347 for (i = EX_NUM_ARGS(); i < argc; ++i) {
348 struct psi_impl_arg *iarg;
349
350 psi_plist_get(frame->impl->func->args, i, &iarg);
351
352 assert(iarg->def);
353 psi_call_frame_new_argument(frame, psi_call_frame_argument_init(iarg,
354 &iarg->def->ival, NULL, 0));
355 }
356
357 zend_restore_error_handling(&zeh);
358 return true;
359 }
360
361 void psi_call_frame_enter(struct psi_call_frame *frame) {
362 size_t argc = psi_call_frame_num_fixed_args(frame);
363 size_t va_count = psi_call_frame_num_var_args(frame);
364 size_t rsize = psi_decl_arg_get_size(frame->decl->func);
365 struct psi_call_frame_symbol *rv_sym;
366
367 /* initialize ffi argument array */
368 frame->pointers = ecalloc(argc + va_count + 1, sizeof(void *));
369
370 /* initialize return value symbol */
371 rv_sym = psi_call_frame_fetch_symbol(frame, frame->decl->func->var);
372 if (rsize > sizeof(impl_val)) {
373 rv_sym->ival_ptr = ecalloc(1, rsize);
374 } else {
375 rv_sym->ival_ptr = &rv_sym->temp_val;
376 }
377 frame->rpointer = rv_sym->ptr = rv_sym->ival_ptr;
378 }
379
380 bool psi_call_frame_do_let(struct psi_call_frame *frame) {
381 size_t i;
382 struct psi_let_stmt *let;
383 struct psi_decl_arg *arg;
384 size_t argc = psi_call_frame_num_fixed_args(frame);
385 size_t va_count = psi_call_frame_num_var_args(frame);
386
387 for (i = 0; psi_plist_get(frame->impl->stmts.let, i, &let); ++i) {
388 psi_let_stmt_exec(let, frame);
389 }
390 for (i = 0; psi_plist_get(frame->decl->args, i, &arg); ++i) {
391 struct psi_let_stmt *let;
392 struct psi_call_frame_symbol *frame_sym;
393
394 let = psi_impl_get_let(frame->impl, arg->var);
395 frame_sym = psi_call_frame_fetch_symbol(frame, let->exp->var);
396 frame->pointers[i] = frame_sym->ptr;
397 }
398 /* varargs */
399 if (va_count) {
400 for (i = 0; i < va_count; ++i) {
401 struct psi_call_frame_argument *frame_arg;
402 psi_marshal_let let_fn;
403 void *temp = NULL;
404
405 frame_arg = psi_call_frame_get_var_argument(frame, i);
406 switch (frame_arg->va_type) {
407 case PSI_T_BOOL: let_fn = psi_let_boolval; break;
408 case PSI_T_INT: let_fn = psi_let_intval; break;
409 case PSI_T_FLOAT:
410 case PSI_T_DOUBLE: let_fn = psi_let_floatval; break;
411 case PSI_T_STRING: let_fn = psi_let_strval; break;
412 default:
413 assert(0);
414 }
415
416 frame_arg->ival_ptr = let_fn(&frame_arg->temp_val, NULL, frame_arg->va_type,
417 &frame_arg->ival, frame_arg->zval_ptr, &temp);
418 if (temp) {
419 psi_call_frame_push_auto(frame, temp);
420 }
421
422 frame->pointers[argc + i] = frame_arg->ival_ptr;
423 }
424 }
425
426 return true;
427 }
428
429 bool psi_call_frame_do_assert(struct psi_call_frame *frame, enum psi_assert_kind kind) {
430 size_t i = 0;
431 struct psi_assert_stmt *ass;
432
433 while (psi_plist_get(frame->impl->stmts.ass, i++, &ass)) {
434 if (ass->kind == kind) {
435 if (!psi_assert_stmt_exec(ass, frame)) {
436 psi_assert_stmt_throw(ass);
437 return false;
438 }
439 }
440 }
441
442 return true;
443 }
444
445 void psi_call_frame_do_call(struct psi_call_frame *frame) {
446 frame->context->ops->call(frame);
447 }
448
449 void psi_call_frame_do_callback(struct psi_call_frame *frame, struct psi_call_frame_callback *cbdata)
450 {
451 size_t i;
452 void *retptr;
453 ZEND_RESULT_CODE rc;
454 struct psi_let_callback *cb = cbdata->cb->data.callback;
455 zval return_value, *zargv = ecalloc(cbdata->argc, sizeof(*zargv));
456 struct psi_call_frame_argument *frame_arg;
457
458 assert(cbdata->argc == psi_plist_count(cb->decl->args));
459
460 /* prepare args for the userland call */
461 for (i = 0; i < cbdata->argc; ++i) {
462 struct psi_set_exp *set_exp;
463 struct psi_decl_var *set_var;
464 struct psi_call_frame_symbol *set_sym;
465
466 psi_plist_get(cb->args, i, &set_exp);
467 set_var = psi_set_exp_get_decl_var(set_exp);
468 set_sym = psi_call_frame_fetch_symbol(frame, set_var);
469
470 set_sym->ptr = cbdata->argv[i];
471 psi_set_exp_exec_ex(set_exp, &zargv[i], set_sym->ptr, frame);
472 }
473
474 frame_arg = psi_call_frame_get_argument(frame, cb->func->var->fqn);
475
476 /* callback into userland */
477 ZVAL_UNDEF(&return_value);
478 zend_fcall_info_argp(&frame_arg->ival_ptr->zend.cb->fci, cbdata->argc, zargv);
479 rc = zend_fcall_info_call(&frame_arg->ival_ptr->zend.cb->fci,
480 &frame_arg->ival_ptr->zend.cb->fcc, &return_value, NULL);
481 assert(rc == SUCCESS);
482 (void) rc;
483
484 /* marshal return value of the userland call */
485 frame_arg->zval_ptr = &return_value;
486 retptr = psi_let_func_exec(cbdata->cb, cb->func, cb->decl->func, frame);
487 memcpy(cbdata->rval, retptr, psi_decl_arg_get_size(cb->decl->func));
488
489 /* cleanup */
490 zend_fcall_info_args_clear(&frame_arg->ival_ptr->zend.cb->fci, 0);
491 for (i = 0; i < cbdata->argc; ++i) {
492 zval_ptr_dtor(&zargv[i]);
493 }
494 efree(zargv);
495 }
496
497 void psi_call_frame_do_return(struct psi_call_frame *frame, zval *return_value) {
498 struct psi_return_stmt *ret;
499
500 psi_plist_get(frame->impl->stmts.ret, 0, &ret);
501 psi_return_stmt_exec(ret, return_value, frame);
502 }
503
504 void psi_call_frame_do_set(struct psi_call_frame *frame) {
505 size_t i = 0;
506 struct psi_set_stmt *set;
507
508 while (psi_plist_get(frame->impl->stmts.set, i++, &set)) {
509 psi_set_stmt_exec(set, frame);
510 }
511 }
512
513 void psi_call_frame_do_free(struct psi_call_frame *frame) {
514 size_t i = 0;
515 struct psi_free_stmt *fre;
516
517 while (psi_plist_get(frame->impl->stmts.fre, i++, &fre)) {
518 psi_free_stmt_exec(fre, frame);
519 }
520 }
521
522 void **psi_call_frame_push_auto_ex(struct psi_call_frame *frame, void *auto_free, void (*dtor)(void*)) {
523 struct psi_call_frame_auto_free f;
524
525 f.data = auto_free;
526 f.dtor = dtor;
527
528 zend_llist_add_element(&frame->temp, &f);
529 return &((struct psi_call_frame_auto_free *) zend_llist_get_last(&frame->temp))->data;
530 }
531
532 void **psi_call_frame_push_auto(struct psi_call_frame *frame, void *auto_free) {
533 return psi_call_frame_push_auto_ex(frame, auto_free, NULL);
534 }
535
536 static void psi_call_frame_local_auto_dtor(void *auto_list)
537 {
538 zend_llist_destroy(auto_list);
539 efree(auto_list);
540 }
541
542 void psi_call_frame_free(struct psi_call_frame *frame) {
543 zend_hash_destroy(&frame->arguments);
544 zend_hash_destroy(&frame->symbols);
545 if (frame->impl && frame->impl->func->static_memory) {
546 zend_llist *temp = emalloc(sizeof(*temp));
547 zval zlocal;
548
549 memcpy(temp, &frame->temp, sizeof(*temp));
550 ZVAL_OBJ(&zlocal, psi_object_init_ex(NULL, temp, psi_call_frame_local_auto_dtor));
551 zend_set_local_var(frame->impl->func->name, &zlocal, /* force */ 1);
552 } else {
553 zend_llist_destroy(&frame->temp);
554 }
555 efree(frame->pointers);
556 efree(frame);
557 }
558
559
560