parser: extern var support
[m6w6/ext-psi] / src / libffi.c
index d01d907d36db2ded651f2eaaa8ee0c4336ff236d..e30966aeb3a4e635eb6fedb3a314a328338cbc17 100644 (file)
@@ -105,6 +105,11 @@ static void psi_ffi_prep_va(ffi_cif *base, ffi_cif *signature, size_t argc, size
        assert(FFI_OK == rc);
 }
 
+#if HAVE_INT128
+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);
 
 static inline ffi_type *psi_ffi_token_type(token_t t) {
@@ -130,13 +135,16 @@ static inline ffi_type *psi_ffi_token_type(token_t t) {
                return &ffi_type_sint64;
        case PSI_T_UINT64:
                return &ffi_type_uint64;
+#if HAVE_INT128
+       case PSI_T_INT128:
+               return ffi_type_sint128;
+       case PSI_T_UINT128:
+               return ffi_type_uint128;
+#endif
        case PSI_T_BOOL:
                return &ffi_type_uchar;
-       case PSI_T_INT:
        case PSI_T_ENUM:
                return &ffi_type_sint;
-       case PSI_T_LONG:
-               return &ffi_type_slong;
        case PSI_T_FLOAT:
                return &ffi_type_float;
        case PSI_T_DOUBLE:
@@ -217,7 +225,7 @@ static ffi_type **psi_ffi_struct_type_elements(struct psi_decl_struct *strct) {
                        maxalign = type->alignment;
                }
 
-               assert(type->size == darg->layout->len);
+               assert(type->size <= darg->layout->len);
                if ((padding = psi_offset_padding(darg->layout->pos - offset, type->alignment))) {
                        if (nels + padding + 1 > argc) {
                                argc += padding;
@@ -529,6 +537,73 @@ 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,
+               ffi_type *type) {
+       struct psi_ffi_extvar_info *info = calloc(1, sizeof(*info));
+       ffi_status rc;
+
+       rc = ffi_prep_cif(&info->get.signature, FFI_DEFAULT_ABI, 0,
+                       type, 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] = type;
+       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->info = info;
+       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;
@@ -569,6 +644,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;
@@ -583,35 +666,42 @@ 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)) {
+               ffi_type *type = psi_ffi_decl_arg_type(evar->arg);
+
+               if (FFI_OK == psi_ffi_extvar_init(evar, type)) {
+                       /* */
+               }
        }
 
-       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)) {
@@ -701,7 +791,43 @@ static void *psi_ffi_query(struct psi_context *C, enum psi_context_query q, void
        return NULL;
 }
 
+static ZEND_RESULT_CODE psi_ffi_load()
+{
+#if HAVE_INT128
+       ffi_type *i128, *u128;
+
+       i128 = calloc(1, 3*sizeof(ffi_type));
+       i128->type = FFI_TYPE_STRUCT;
+       i128->size = 0;
+       i128->elements = (ffi_type **) (i128 + 1);
+       i128->elements[0] = &ffi_type_sint64;
+       i128->elements[1] = &ffi_type_sint64;
+
+       ffi_type_sint128 = i128;
+
+       u128 = calloc(1, 3*sizeof(ffi_type));
+       u128->type = FFI_TYPE_STRUCT;
+       u128->size = 0;
+       u128->elements = (ffi_type **) (u128 + 1);
+       u128->elements[0] = &ffi_type_uint64;
+       u128->elements[1] = &ffi_type_uint64;
+
+       ffi_type_uint128 = u128;
+#endif
+       return SUCCESS;
+}
+
+static void psi_ffi_free()
+{
+#if HAVE_INT128
+       free(ffi_type_sint128);
+       free(ffi_type_uint128);
+#endif
+}
+
 static struct psi_context_ops ops = {
+       psi_ffi_load,
+       psi_ffi_free,
        psi_ffi_init,
        psi_ffi_dtor,
        psi_ffi_compile,