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