From fecb0372ee8e219a7ebd51406dee3e1008ccb7ec Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 24 Oct 2018 16:33:45 +0200 Subject: [PATCH] ffi: improve support for functions returning arrays --- psi.d/time.psi | 9 +++++ src/libffi.c | 69 +++++++++++++++++++++++++-------------- src/marshal.c | 2 -- tests/time/tzname001.phpt | 25 ++++++++++++++ 4 files changed, 79 insertions(+), 26 deletions(-) create mode 100644 tests/time/tzname001.phpt diff --git a/psi.d/time.psi b/psi.d/time.psi index 0acbf98..716e176 100644 --- a/psi.d/time.psi +++ b/psi.d/time.psi @@ -117,3 +117,12 @@ function psi\times(array &$tms = NULL) : int { to_int(tms_cstime) ); } + + +function psi\tzset() : void { + return tzset() as void(tzset); +} + +function psi\tzname() : array { + return tzname_get() as to_array(tzname_get, 2, to_string(*tzname_get)); +} diff --git a/src/libffi.c b/src/libffi.c index 99f5c5f..f14a9cd 100644 --- a/src/libffi.c +++ b/src/libffi.c @@ -137,8 +137,7 @@ static ffi_type *ffi_type_sint128; static ffi_type *ffi_type_uint128; #endif -static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg, - struct psi_decl *fn); +static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg); static inline ffi_type *psi_ffi_token_type(token_t t) { switch (t) { @@ -238,7 +237,8 @@ struct psi_ffi_struct_element_storage { }; static inline void psi_ffi_struct_type_element( - struct psi_ffi_struct_element_storage *s, struct psi_decl_arg *darg) { + struct psi_ffi_struct_element_storage *s, struct psi_decl_arg *darg, + ffi_type *darg_type) { ffi_type *type, **tmp; size_t padding; @@ -250,7 +250,7 @@ static inline void psi_ffi_struct_type_element( s->last_arg_pos = darg->layout->pos; type = malloc(sizeof(*type)); - *type = *psi_ffi_decl_arg_type(darg, NULL); + *type = *darg_type; if (type->alignment > s->max_align) { s->max_align = type->alignment; @@ -290,7 +290,7 @@ static ffi_type **psi_ffi_struct_type_elements(struct psi_decl_struct *strct) { s.els = calloc(s.argc + 1, sizeof(*s.els)); while (psi_plist_get(strct->args, i++, &darg)) { - psi_ffi_struct_type_element(&s, darg); + psi_ffi_struct_type_element(&s, darg, psi_ffi_decl_arg_type(darg)); } /* apply struct alignment padding */ @@ -340,7 +340,7 @@ static inline ffi_type *psi_ffi_decl_type(struct psi_decl_type *type) { { struct psi_decl_arg *arg; psi_plist_get(real->real.unn->args, 0, &arg); - return psi_ffi_decl_arg_type(arg, NULL); + return psi_ffi_decl_arg_type(arg); } default: @@ -354,32 +354,56 @@ static inline ffi_type *psi_ffi_decl_func_array_type(struct psi_decl *fn) { struct psi_ffi_decl_info *info = fn->info; struct psi_ffi_struct_element_storage s = {0}; struct psi_layout l; + ffi_type *type; size_t i; + if (info->rv_array) { + return info->rv_array; + } + s.last_arg_pos = -1; s.argc = fn->func->var->array_size; s.els = calloc(s.argc + 1, sizeof(*s.els)); - assert(!fn->func->layout); - l.pos = 0; - l.len = psi_decl_arg_get_size(fn->func); - - fn->func->layout = &l; - psi_ffi_struct_type_element(&s, fn->func); - fn->func->layout = NULL; - info->rv_array = calloc(1, sizeof(ffi_type)); info->rv_array->type = FFI_TYPE_STRUCT; info->rv_array->size = 0; info->rv_array->elements = s.els; + l.pos = 0; + if (fn->func->var->pointer_level > 1) { + l.len = SIZEOF_VOID_P; + type = &ffi_type_pointer; + } else { + l.len = psi_decl_type_get_size(fn->func->type, NULL); + type = psi_ffi_decl_type(fn->func->type); + } + + assert(!fn->func->layout); + fn->func->layout = &l; + for (i = 0; i < fn->func->var->array_size; ++i) { + psi_ffi_struct_type_element(&s, fn->func, type); + info->rv_array->elements = s.els; + l.pos += l.len; + } + fn->func->layout = NULL; + return info->rv_array; } -static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg, - struct psi_decl *fn) { +static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg) { + if (darg->var->pointer_level) { + return &ffi_type_pointer; + } else { + return psi_ffi_decl_type(darg->type); + } +} + +static inline ffi_type *psi_ffi_decl_func_type(struct psi_decl *fn) { + struct psi_decl_arg *darg = fn->func; + if (darg->var->pointer_level) { - if (darg->var->array_size && fn) { + if (darg->var->array_size) { /* mimic a struct resembling the array return type of fn */ return psi_ffi_decl_func_array_type(fn); } @@ -415,12 +439,12 @@ static inline struct psi_ffi_decl_info *psi_ffi_decl_init(struct psi_decl *decl) decl->info = info; for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) { - info->params[i] = psi_ffi_decl_arg_type(arg, NULL); + info->params[i] = psi_ffi_decl_arg_type(arg); } info->params[c] = NULL; rc = ffi_prep_cif(&info->signature, psi_ffi_abi(decl->abi->convention), - c, psi_ffi_decl_arg_type(decl->func, decl), info->params); + c, psi_ffi_decl_func_type(decl), info->params); if (FFI_OK != rc) { free(info); @@ -629,7 +653,6 @@ struct psi_ffi_extvar_info { static inline ffi_status psi_ffi_extvar_init(struct psi_decl_extvar *evar) { struct psi_ffi_extvar_info *info = calloc(1, sizeof(*info)); - ffi_type *type; ffi_status rc; evar->info = info; @@ -637,10 +660,8 @@ static inline ffi_status psi_ffi_extvar_init(struct psi_decl_extvar *evar) { psi_ffi_decl_init(evar->getter); psi_ffi_decl_init(evar->setter); - type = psi_ffi_decl_arg_type(evar->arg, evar->getter); - rc = ffi_prep_cif(&info->get.signature, FFI_DEFAULT_ABI, 0, - type, NULL); + psi_ffi_decl_func_type(evar->getter), NULL); if (FFI_OK != rc) { return rc; } @@ -650,7 +671,7 @@ static inline ffi_status psi_ffi_extvar_init(struct psi_decl_extvar *evar) { return rc; } - info->set.params[0] = type; + info->set.params[0] = psi_ffi_decl_arg_type(evar->arg); rc = ffi_prep_cif(&info->set.signature, FFI_DEFAULT_ABI, 1, &ffi_type_void, info->set.params); if (FFI_OK != rc) { diff --git a/src/marshal.c b/src/marshal.c index 834a38f..c7651f6 100644 --- a/src/marshal.c +++ b/src/marshal.c @@ -526,8 +526,6 @@ void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *re impl_val *ptr = deref_impl_val(ret_val, var); char *str; - /* holy moly, this breaks arrays of pointers to char, - * like e.g. tzname */ if (var->arg->var->array_size && var->arg->var->pointer_level == 1) { str = (char *) ptr; } else { diff --git a/tests/time/tzname001.phpt b/tests/time/tzname001.phpt new file mode 100644 index 0000000..8f26743 --- /dev/null +++ b/tests/time/tzname001.phpt @@ -0,0 +1,25 @@ +--TEST-- +tzname +--INI-- +psi.directory={PWD}/../../psi.d:{PWD} +date.timezone=CET +--SKIPIF-- + +--FILE-- +===TEST=== + +===DONE=== +--EXPECTF-- +===TEST=== +NULL +array(2) { + [0]=> + string(3) "CET" + [1]=> + string(4) "CEST" +} +===DONE=== -- 2.30.2