X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=blobdiff_plain;f=src%2Flibffi.c;h=f14a9cd651645cb380a8f65e82d795aefb49b488;hp=6935ef9c7f760cd4df46cef545169f20c76bf9cb;hb=fecb0372ee8e219a7ebd51406dee3e1008ccb7ec;hpb=6ec1a060415f860bc3eb4c74fbce1c43f5aa7e55 diff --git a/src/libffi.c b/src/libffi.c index 6935ef9..f14a9cd 100644 --- a/src/libffi.c +++ b/src/libffi.c @@ -51,6 +51,33 @@ # endif #endif +struct psi_ffi_context { + ffi_cif signature; + ffi_type *params[2]; +}; + +struct psi_ffi_impl_info { + struct psi_context *context; + struct psi_call_frame *frame; + + void *code; + ffi_closure *closure; +}; + +struct psi_ffi_callback_info { + struct psi_ffi_impl_info *impl_info; + struct psi_let_exp *let_exp; + + void *code; + ffi_closure *closure; +}; + +struct psi_ffi_decl_info { + ffi_cif signature; + ffi_type *rv_array; + ffi_type *params[1]; +}; + static void *psi_ffi_closure_alloc(size_t s, void **code) { #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC @@ -173,7 +200,7 @@ static inline ffi_type *psi_ffi_impl_type(token_t impl_type) { } return NULL; } -static void psi_ffi_struct_type_dtor(void *type) { +static void psi_ffi_type_dtor(void *type) { ffi_type *strct = type; if (strct->elements) { @@ -200,77 +227,100 @@ static size_t psi_ffi_struct_type_pad(ffi_type **els, size_t padding) { return padding; } -static ffi_type **psi_ffi_struct_type_elements(struct psi_decl_struct *strct) { - size_t i = 0, argc, nels = 0, offset = 0, maxalign = 0, last_arg_pos = -1; - ffi_type **tmp, **els; - struct psi_decl_arg *darg; +struct psi_ffi_struct_element_storage { + ffi_type **els; + size_t nels; + size_t argc; + size_t offset; + size_t max_align; + size_t last_arg_pos; +}; - argc = psi_plist_count(strct->args); - els = calloc(argc + 1, sizeof(*els)); +static inline void psi_ffi_struct_type_element( + struct psi_ffi_struct_element_storage *s, struct psi_decl_arg *darg, + ffi_type *darg_type) { - while (psi_plist_get(strct->args, i++, &darg)) { - ffi_type *type; - size_t padding; + ffi_type *type, **tmp; + size_t padding; - if (darg->layout->pos == last_arg_pos) { - /* skip bit fields */ - continue; - } - last_arg_pos = darg->layout->pos; + if (darg->layout->pos == s->last_arg_pos) { + /* skip bit fields */ + return; + } + s->last_arg_pos = darg->layout->pos; - type = malloc(sizeof(*type)); - *type = *psi_ffi_decl_arg_type(darg); + type = malloc(sizeof(*type)); + *type = *darg_type; - if (type->alignment > maxalign) { - maxalign = type->alignment; - } + if (type->alignment > s->max_align) { + s->max_align = type->alignment; + } - assert(type->size <= darg->layout->len); - if ((padding = psi_offset_padding(darg->layout->pos - offset, type->alignment))) { - if (nels + padding + 1 > argc) { - argc += padding; - tmp = realloc(els, (argc + 1) * sizeof(*els)); - if (tmp) { - els = tmp; - } else { - free(els); - return NULL; - } - els[argc] = NULL; + assert(type->size <= darg->layout->len); + if ((padding = psi_offset_padding(darg->layout->pos - s->offset, type->alignment))) { + if (s->nels + padding + 1 > s->argc) { + s->argc += padding; + tmp = realloc(s->els, (s->argc + 1) * sizeof(*s->els)); + if (tmp) { + s->els = tmp; + } else { + free(s->els); + abort(); } - psi_ffi_struct_type_pad(&els[nels], padding); - nels += padding; - offset += padding; + s->els[s->argc] = NULL; } - assert(offset == darg->layout->pos); + psi_ffi_struct_type_pad(&s->els[s->nels], padding); + s->nels += padding; + s->offset += padding; + } + assert(s->offset == darg->layout->pos); + + s->offset = (s->offset + darg->layout->len + type->alignment - 1) & ~(type->alignment - 1); + s->els[s->nels++] = type; +} + +static ffi_type **psi_ffi_struct_type_elements(struct psi_decl_struct *strct) { + size_t i = 0; + ffi_type **tmp; + struct psi_decl_arg *darg; + struct psi_ffi_struct_element_storage s = {0}; + + s.last_arg_pos = -1; + s.argc = psi_plist_count(strct->args); + s.els = calloc(s.argc + 1, sizeof(*s.els)); - offset = (offset + darg->layout->len + type->alignment - 1) & ~(type->alignment - 1); - els[nels++] = type; + while (psi_plist_get(strct->args, i++, &darg)) { + psi_ffi_struct_type_element(&s, darg, psi_ffi_decl_arg_type(darg)); } /* apply struct alignment padding */ - offset = (offset + maxalign - 1) & ~(maxalign - 1); + s.offset = (s.offset + s.max_align - 1) & ~(s.max_align - 1); - assert(offset <= strct->size); - if (offset < strct->size) { - size_t padding = strct->size - offset; + assert(s.offset <= strct->size); + if (s.offset < strct->size) { /* WTF? */ + size_t padding = strct->size - s.offset; - tmp = realloc(els, (padding + argc + 1) * sizeof(*els)); + tmp = realloc(s.els, (padding + s.argc + 1) * sizeof(*s.els)); if (tmp) { - els = tmp; + s.els = tmp; } else { - free(els); + free(s.els); return NULL; } - psi_ffi_struct_type_pad(&els[nels], padding); - els[argc + padding] = NULL; + psi_ffi_struct_type_pad(&s.els[s.nels], padding); + s.els[s.argc + padding] = NULL; } - return els; + return s.els; } + static inline ffi_type *psi_ffi_decl_type(struct psi_decl_type *type) { struct psi_decl_type *real = psi_decl_type_get_real(type); + if (real != type && type->real.def->var->pointer_level) { + return &ffi_type_pointer; + } + switch (real->type) { case PSI_T_STRUCT: if (!real->real.strct->engine.type) { @@ -281,7 +331,7 @@ static inline ffi_type *psi_ffi_decl_type(struct psi_decl_type *type) { strct->elements = psi_ffi_struct_type_elements(real->real.strct); real->real.strct->engine.type = strct; - real->real.strct->engine.dtor = psi_ffi_struct_type_dtor; + real->real.strct->engine.dtor = psi_ffi_type_dtor; } return real->real.strct->engine.type; @@ -294,9 +344,53 @@ static inline ffi_type *psi_ffi_decl_type(struct psi_decl_type *type) { } default: - return psi_ffi_token_type(real->type); + break; } + + return psi_ffi_token_type(real->type); } + +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)); + + 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) { if (darg->var->pointer_level) { return &ffi_type_pointer; @@ -305,6 +399,20 @@ static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg) { } } +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) { + /* mimic a struct resembling the array return type of fn */ + return psi_ffi_decl_func_array_type(fn); + } + return &ffi_type_pointer; + } else { + return psi_ffi_decl_type(darg->type); + } +} + static inline ffi_abi psi_ffi_abi(const char *convention) { if (FFI_LAST_ABI - 2 != FFI_FIRST_ABI) { #ifdef HAVE_FFI_STDCALL @@ -321,32 +429,6 @@ static inline ffi_abi psi_ffi_abi(const char *convention) { return FFI_DEFAULT_ABI; } -struct psi_ffi_context { - ffi_cif signature; - ffi_type *params[2]; -}; - -struct psi_ffi_impl_info { - struct psi_context *context; - struct psi_call_frame *frame; - - void *code; - ffi_closure *closure; -}; - -struct psi_ffi_callback_info { - struct psi_ffi_impl_info *impl_info; - struct psi_let_exp *let_exp; - - void *code; - ffi_closure *closure; -}; - -struct psi_ffi_decl_info { - ffi_cif signature; - ffi_type *params[1]; -}; - static inline struct psi_ffi_decl_info *psi_ffi_decl_init(struct psi_decl *decl) { if (!decl->info) { int rc; @@ -354,18 +436,19 @@ static inline struct psi_ffi_decl_info *psi_ffi_decl_init(struct psi_decl *decl) struct psi_decl_arg *arg; struct psi_ffi_decl_info *info = calloc(1, sizeof(*info) + 2 * c * sizeof(void *)); + decl->info = info; + for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) { 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), info->params); + c, psi_ffi_decl_func_type(decl), info->params); if (FFI_OK != rc) { free(info); - } else { - decl->info = info; + decl->info = NULL; } } @@ -374,6 +457,11 @@ static inline struct psi_ffi_decl_info *psi_ffi_decl_init(struct psi_decl *decl) static inline void psi_ffi_decl_dtor(struct psi_decl *decl) { if (decl->info) { + struct psi_ffi_decl_info *info = decl->info; + + if (info->rv_array) { + psi_ffi_type_dtor(info->rv_array); + } free(decl->info); decl->info = NULL; } @@ -537,6 +625,76 @@ static inline void psi_ffi_impl_dtor(struct psi_impl *impl) { } } +static void psi_ffi_extvar_get(ffi_cif *sig, void *result, void **args, void *data) { + struct psi_decl_extvar *evar = data; + + psi_decl_extvar_get(evar, result); +} + +static void psi_ffi_extvar_set(ffi_cif *sig, void *result, void **args, void *data) { + struct psi_decl_extvar *evar = data; + + psi_decl_extvar_set(evar, args[0]); +} + +struct psi_ffi_extvar_info { + struct { + ffi_cif signature; + void *code; + ffi_closure *closure; + } get; + struct { + ffi_cif signature; + ffi_type *params[1]; + void *code; + ffi_closure *closure; + } set; +}; + +static inline ffi_status psi_ffi_extvar_init(struct psi_decl_extvar *evar) { + struct psi_ffi_extvar_info *info = calloc(1, sizeof(*info)); + ffi_status rc; + + evar->info = info; + + psi_ffi_decl_init(evar->getter); + psi_ffi_decl_init(evar->setter); + + rc = ffi_prep_cif(&info->get.signature, FFI_DEFAULT_ABI, 0, + psi_ffi_decl_func_type(evar->getter), NULL); + if (FFI_OK != rc) { + return rc; + } + rc = psi_ffi_prep_closure(&info->get.closure, &info->get.code, + &info->get.signature, psi_ffi_extvar_get, evar); + if (FFI_OK != rc) { + return rc; + } + + 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) { + return rc; + } + rc = psi_ffi_prep_closure(&info->set.closure, &info->set.code, + &info->set.signature, psi_ffi_extvar_set, evar); + if (FFI_OK != rc) { + return rc; + } + + evar->getter->sym = info->get.code; + evar->setter->sym = info->set.code; + + return FFI_OK; +} + +static inline void psi_ffi_extvar_dtor(struct psi_decl_extvar *evar) { + if (evar->info) { + free(evar->info); + evar->info = NULL; + } +} static inline struct psi_ffi_context *psi_ffi_context_init(struct psi_ffi_context *L) { ffi_status rc; @@ -577,6 +735,14 @@ static void psi_ffi_dtor(struct psi_context *C) } } + if (C->vars) { + size_t i = 0; + struct psi_decl_extvar *evar; + + while (psi_plist_get(C->vars, i++, &evar)) { + psi_ffi_extvar_dtor(evar); + } + } if (C->impls) { size_t i = 0; struct psi_impl *impl; @@ -591,35 +757,40 @@ static void psi_ffi_dtor(struct psi_context *C) static zend_function_entry *psi_ffi_compile(struct psi_context *C) { - size_t i = 0, d = 0, nf = 0; + size_t i = 0, d = 0, v = 0, nf = 0; struct psi_impl *impl; struct psi_decl *decl; - zend_function_entry *zfe; + struct psi_decl_extvar *evar; + zend_function_entry *zfe = NULL; - if (!C->impls) { - return NULL; + while (psi_plist_get(C->vars, v++, &evar)) { + if (FFI_OK == psi_ffi_extvar_init(evar)) { + /* */ + } } - zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe)); + if (C->impls) { + zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe)); - while (psi_plist_get(C->impls, i++, &impl)) { - zend_function_entry *zf = &zfe[nf]; + while (psi_plist_get(C->impls, i++, &impl)) { + zend_function_entry *zf = &zfe[nf]; - if (!impl->decl) { - continue; - } - if (!psi_ffi_decl_init(impl->decl)) { - continue; - } - if (!psi_ffi_impl_init(impl, C)) { - continue; - } + if (!impl->decl) { + continue; + } + if (!psi_ffi_decl_init(impl->decl)) { + continue; + } + if (!psi_ffi_impl_init(impl, C)) { + continue; + } - zf->fname = impl->func->name + (impl->func->name[0] == '\\'); - zf->handler = ((struct psi_ffi_impl_info *) impl->info)->code; - zf->num_args = psi_plist_count(impl->func->args); - zf->arg_info = psi_internal_arginfo(impl); - ++nf; + zf->fname = impl->func->name + (impl->func->name[0] == '\\'); + zf->handler = ((struct psi_ffi_impl_info *) impl->info)->code; + zf->num_args = psi_plist_count(impl->func->args); + zf->arg_info = psi_internal_arginfo(impl); + ++nf; + } } while (psi_plist_get(C->decls, d++, &decl)) {