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