flush
authorMichael Wallner <mike@php.net>
Fri, 29 Jan 2016 13:05:38 +0000 (14:05 +0100)
committerMichael Wallner <mike@php.net>
Fri, 29 Jan 2016 13:05:38 +0000 (14:05 +0100)
35 files changed:
config.m4
m4/errno.m4
m4/fcntl.m4
m4/glob.m4
m4/locale.m4
m4/ndbm.m4
m4/netdb.m4
m4/netinet_in.m4
m4/netinet_tcp.m4
m4/poll.m4
m4/psi.m4
m4/stdio.m4
m4/sys_select.m4
m4/sys_socket.m4
m4/sys_stat.m4
m4/sys_time.m4
m4/sys_times.m4
m4/sys_uio.m4
m4/sys_utsname.m4
m4/syslog.m4
m4/time.m4
m4/wchar.m4
m4/wctype.m4
src/context_dump.c
src/context_validate.c
src/engine.c
src/engine.h
src/libffi.c
src/parser.h
src/parser_proc.h
src/parser_proc.y
tests/div/div001.phpt
tests/div/ldiv001.phpt
tests/div/lldiv001.phpt
tests/parser/dump/dump001.phpt

index ade6f45b52f415348c42f4063fcf69bf5e2aece1..74fefdb3ed4ce0fef45a7b84a56c0b6d7eb65c52 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -1,12 +1,3 @@
-PHP_ARG_ENABLE(psi, whether to enable PHP System Interface support,
-[  --enable-psi            Enable PHP System Interface support])
-
-PHP_ARG_WITH(psi-libjit, where to find libjit,
-[  --with-psi-libjit=DIR   PSI: path to libjit], [ ], [ ])
-
-PHP_ARG_WITH(psi-libffi, where to find libffi,
-[  --with-psi-libffi=DIR   PSI: path to libffi], [ ], [ ])
-
 PHP_PSI_SRCDIR=PHP_EXT_SRCDIR(psi)
 PHP_PSI_BUILDDIR=PHP_EXT_BUILDDIR(psi)
 
@@ -49,6 +40,18 @@ m4_foreach(incfile, [
        sinclude([ext/psi/m4/]incfile)
 ])
 
+PHP_ARG_ENABLE(psi, whether to enable PHP System Interface support,
+[  --enable-psi            Enable PHP System Interface support])
+
+PHP_ARG_ENABLE(psi-posix, whether to pre-define POSIX decls,
+[  --ebable-psi-posix      PSI: pre-define POSIX decls], [ ], [ ])
+
+PHP_ARG_WITH(psi-libjit, where to find libjit,
+[  --with-psi-libjit=DIR   PSI: path to libjit], [ ], [ ])
+
+PHP_ARG_WITH(psi-libffi, where to find libffi,
+[  --with-psi-libffi=DIR   PSI: path to libffi], [ ], [ ])
+
 if test "$PHP_PSI" != no; then
        PHP_CONFIGURE_PART(Configuring PSI)
 
@@ -62,8 +65,8 @@ if test "$PHP_PSI" != no; then
        PSI_CONFIG_INIT
        PSI_CHECK_STD_TYPES
        PSI_CHECK_STDINT
-       PSI_CHECK_STDDEF
        PSI_CHECK_SYS_TYPES
+       PSI_CHECK_STDDEF
        PSI_CHECK_ERRNO
        PSI_CHECK_FCNTL
        PSI_CHECK_GLOB
index be6f99613d413888a5f859cefb0789b070a74b61..4d28b8bc903dac69d7a7d243787dae91cc8f536b 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_ERRNO() {
-    AC_CHECK_HEADERS(errno.h)
+    PSI_CONFIG_POSIX(errno, errno.h)
 
     PSI_EXTVAR(int errno)
 
index a9b59d49548ec30de2feb6efd19c41864f272249..9e992cce318363ebc8dde4803438883ebd5c7e7d 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_FCNTL() {
-       AC_CHECK_HEADERS(fcntl.h)
+       PSI_CONFIG_POSIX(fcntl, fcntl.h)
 
        PSI_CONST(F_DUPFD, int)
        PSI_CONST(F_DUPFD_CLOEXEC, int)
index 343b3729b280018d5d2e37d4fbd5b2f2ab32eaa5..da5dc0edb29f2df6ab534ecfe5930c08a6b838bb 100644 (file)
@@ -1,5 +1,6 @@
 PSI_CHECK_GLOB() {
-    AC_CHECK_HEADERS(glob.h)
+    PSI_CONFIG_POSIX(glob, glob.h)
+    
     PSI_STRUCT(glob_t, [
         size_t gl_pathc,
         int gl_matchc,
index e422a928a85908f4cb4247379bc0aaafc50a13d7..3459101090053dd6e5c37e3a12eb7b1fa7bc84fb 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_LOCALE() {
-       AC_CHECK_HEADERS(locale.h xlocale.h)
+       PSI_CONFIG_POSIX(locale, locale.h xlocale.h)
 
        PSI_STRUCT(struct lconv, [
                char    *currency_symbol,
index 100572269050700e540b5048713f8aec1a1f4df8..3d60b06dbf58ef837ae53a6318a6047f7873c320 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_NDBM() {
-       AC_CHECK_HEADERS(ndbm.h)
+       PSI_CONFIG_POSIX(ndbm, ndbm.h)
        
        PHP_CHECK_FUNC_LIB(dbm_open, gdbm_compat)
        
index 5049a53cc9d81f5f73cf8f875a0e03f8ac47f082..43008e50bc10dac8b95151043cee4c3f98ab683c 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_NETDB() {
-       AC_CHECK_HEADERS(netdb.h)
+       PSI_CONFIG_POSIX(netdb, netdb.h)
 
        PSI_STRUCT(struct hostent, [
                char *h_name,
index 4dcca38bbbf85571a163c43157c12ff87e4dd288..e226d0517b1fdb807ac98e60ffa32858f8d4232b 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_NETINET_IN() {
-       AC_CHECK_HEADERS(netinet/in.h)
+       PSI_CONFIG_POSIX(netinet/in, netinet/in.h)
 
        PSI_TYPE(in_port_t, uint)
        PSI_TYPE(in_addr_t, uint)
index 7c4677cfb3f73be9ea35ffae8c85cdfb4334e32a..4e10420884559c69c3b6b6dcd1b921148d4330ef 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_NETINET_TCP() {
-       AC_CHECK_HEADERS(netinet/tcp.h)
+       PSI_CONFIG_POSIX(netinet/tcp, netinet/tcp.h)
 
        PSI_CONST(TCP_NODELAY, int)
 }
index 2105a645e46f49df44fc43317e82b9b1b26215e4..bbbb221374ef8330a33855aaddbed7212d7cf51f 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_POLL() {
-       AC_CHECK_HEADERS(poll.h)
+       PSI_CONFIG_POSIX(poll, poll.h)
 
        PSI_STRUCT(struct pollfd, [
                int fd,
index 97ea6fec13115ef0391aa843b56904a8b3835bfd..e8d8069c35b4f0642a187cf3e0a3d07f05220813 100644 (file)
--- a/m4/psi.m4
+++ b/m4/psi.m4
@@ -99,6 +99,15 @@ EOF
        done
 ])
 
+dnl PSI_CONFIG_POSIX(section, headers)
+AC_DEFUN(PSI_CONFIG_POSIX, [
+       case "$PHP_PSI_POSIX" in
+       yes|all) ;;
+       *) expr "$PHP_PSI_POSIX" : '\b$1\b' >/dev/null || return 0 ;;
+       esac
+       ifelse($2,,,AC_CHECK_HEADERS($2))
+])
+
 dnl PSI_INCLUDES()
 dnl Expands to a complete list of include statements including
 dnl AC_INCLUDES_DEFAULT().
index 9144cb1df0faaeb61afd8377027cf1e4d2c44ef8..a2b40b56477a4ad74519350f28b3fc1b808b4be5 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_STDIO() {
-    AC_CHECK_HEADER(stdio.h)
+    PSI_CONFIG_POSIX(stdio, stdio.h)
 
     PSI_STRUCT(FILE)
     PSI_STRUCT(fpos_t)
index 8bd7e88956be4577a919b877d756cd2f3fa5a47f..0390299802338d022e6d0db7d27f92ad8d1eb0c8 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_SYS_SELECT() {
-       AC_CHECK_HEADERS(sys/select.h)
+       PSI_CONFIG_POSIX(sys/select, sys/select.h)
 
        PSI_STRUCT(fd_set, [])
 
index 4d28cdde84a83fc2d372baf5ee6973e77f0a0a24..6d1eaf3fd44a5e7841b758a345441129597e38bf 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_SYS_SOCKET() {
-       AC_CHECK_HEADERS(sys/socket.h)
+       PSI_CONFIG_POSIX(sys/socket, sys/socket.h)
 
        PSI_TYPE(socklen_t, int)
        PSI_TYPE(sa_family_t, uint)
index 937eb3853025d42f7b92b4b2300fcab789b91873..fb4494512ce165dc5f6a867215b127e7a3ae8c09 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_SYS_STAT() {
-       AC_CHECK_HEADERS([sys/stat.h])
+       PSI_CONFIG_POSIX(sys/stat, sys/stat.h)
 
        PSI_STRUCT(struct stat, [
                dev_t st_dev,
index 1b845dd5b8e7f35aef9b290ba6533a35c6316e0d..9c1f74444ecb63c4f4d31eb57e1341180f03e12c 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_SYS_TIME() {
-       AC_CHECK_HEADERS(sys/time.h)
+       PSI_CONFIG_POSIX(sys/time, sys/time.h)
 
        PSI_CONST(ITIMER_REAL, int)
        PSI_CONST(ITIMER_VIRTUAL, int)
index 9f9da565d6cc8e190bbcc3118083bdf0791bad32..33010700b70aedd831417edae0ee035de4f9839f 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_SYS_TIMES() {
-       AC_CHECK_HEADERS(sys/times.h)
+       PSI_CONFIG_POSIX(sys/times, sys/times.h)
 
        PSI_STRUCT(struct tms, [
                clock_t tms_utime,
index e7cbce357fd86242bc2e7769c872fa2afcbd6db9..7cd4c3c5490e51099a7e4c06b148bfebcf0749a8 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_SYS_UIO() {
-       AC_CHECK_HEADERS(sys/uio.h)
+       PSI_CONFIG_POSIX(sys/uio, sys/uio.h)
 
        PSI_STRUCT(struct iovec, [
                void *iov_base,
index dde03137fd5d6bca13603efed749c9c7797300ad..36f49d33db5ea7b6d92299deef9ada9884c9a707 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_SYS_UTSNAME() {
-       AC_CHECK_HEADERS(sys/utsname.h)
+       PSI_CONFIG_POSIX(sys/utsname, sys/utsname.h)
 
        PSI_STRUCT(struct utsname, [
                char sysname@<:@0@:>@,
index 198f4f8113224da7d2e7d58af8f4309bbab30040..3547f752acd6df1ccdf5d3bc9ca65ef06447de74 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_SYSLOG() {
-       AC_CHECK_HEADERS(syslog.h)
+       PSI_CONFIG_POSIX(syslog, syslog.h)
 
        PSI_CONST(LOG_PID, int)
        PSI_CONST(LOG_CONS, int)
index 6fd6c1004679ce5f9c0f110fe97a00f105d13875..e1b4011c7910bf30c11f34fafb29c6809939c3d5 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_TIME() {
-       AC_CHECK_HEADERS(time.h)
+       PSI_CONFIG_POSIX(time, time.h)
 
        PSI_CONST(CLOCKS_PER_SEC, int)
        PSI_CONST(CLOCK_MONOTONIC, int)
index c399a061cf2dfc1860fb9b1cf5a06334e8c1daef..f1a7026b55415101e9b06976624c235c57d0efcb 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_WCHAR() {
-       AC_CHECK_HEADERS(wchar.h)
+       PSI_CONFIG_POSIX(wchar, wchar.h)
 
        PSI_TYPE(wint_t, int)
        PSI_STRUCT(mbstate_t)
index 627b919cdf2708634ac18b9001fc69d4dd798255..319dada892186f72e04b58cd990f7f024054bfe3 100644 (file)
@@ -1,5 +1,5 @@
 PSI_CHECK_WCTYPE() {
-       AC_CHECK_HEADERS(wctype.h)
+       PSI_CONFIG_POSIX(wctype, wctype.h)
 
        PSI_TYPE(wctype_t, int)
        PSI_TYPE(wctrans_t, int)
index 708b36f1e950ab581121ac768c82b15dece6934f..c62ebf23b4bd5e7d1b2b2d427eccec729a0fceca 100644 (file)
@@ -4,15 +4,46 @@
 #include "libjit.h"
 #include "libffi.h"
 
+static inline void dump_decl_arg(int fd, decl_arg *darg);
+
 static inline void dump_decl_type(int fd, decl_type *t) {
        const char *pre;
+       size_t j;
 
        switch (t->type) {
+       case PSI_T_POINTER:
+               dprintf(fd, "%s *", t->name);
+               return;
+
+       case PSI_T_FUNCTION:
+               dump_decl_arg(fd, t->func->func);
+               dprintf(fd, "(");
+               if (t->func->args) {
+                       for (j = 0; j < t->func->args->count; ++j) {
+                               if (j) {
+                                       dprintf(fd, ", ");
+                               }
+                               dump_decl_arg(fd, t->func->args->args[j]);
+                       }
+                       if (t->func->args->varargs) {
+                               dprintf(fd, ", ...");
+                       }
+               }
+               dprintf(fd, ")");
+               return;
+
        case PSI_T_STRUCT:
                pre = "struct ";
                break;
+       case PSI_T_ENUM:
+               pre = "enum ";
+               break;
+       case PSI_T_UNION:
+               pre = "union ";
+               break;
        default:
                pre = "";
+               break;
        }
        dprintf(fd, "%s%s", pre, t->name);
 }
@@ -114,6 +145,7 @@ static inline void dump_impl_set_value(int fd, set_value *set, unsigned level, i
 static inline void dump_typedef(int fd, decl_arg *tdef) {
        dprintf(fd, "typedef ");
        dump_decl_arg(fd, tdef);
+       dprintf(fd, ";");
        /*
        dump_decl_type(fd, tdef->type);
        dprintf(fd, " %s%s;", tdef->type->type == PSI_T_POINTER ? "*":"",
@@ -157,6 +189,7 @@ static inline void dump_structs(int fd, decl_structs *structs) {
        for (i = 0; i < structs->count; ++i) {
                decl_struct *strct = structs->list[i];
 
+
                dump_struct(fd, strct);
                dprintf(fd, "\n");
        }
index 7c7a245abee60d27e54581163a583ecbe297971b..01dbfb7eca2cfc81f98d163cc6ef7f271d076ea9 100644 (file)
@@ -81,6 +81,21 @@ static inline int locate_decl_type_struct(decl_structs *structs, decl_type *type
        return 0;
 }
 
+static inline int locate_decl_type_union(decl_unions *unions, decl_type *type) {
+       size_t i;
+
+       if (type->unn) {
+               return 1;
+       }
+       if (unions) for (i = 0; i < unions->count; ++i) {
+               if (!strcmp(unions->list[i]->name, type->name)) {
+                       type->unn = unions->list[i];
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 static inline int locate_decl_type_enum(decl_enums *enums, decl_type *type) {
        size_t i;
 
@@ -96,6 +111,10 @@ static inline int locate_decl_type_enum(decl_enums *enums, decl_type *type) {
        return 0;
 }
 
+static inline int validate_decl_struct(PSI_Data *data, decl_struct *s);
+static inline int validate_decl_union(PSI_Data *data, decl_union *u);
+static inline int validate_decl_enum(PSI_Data *data, decl_enum *e);
+
 static inline int validate_decl_type(PSI_Data *data, decl_type *type) {
        switch (type->type) {
        case PSI_T_CHAR:
@@ -115,6 +134,11 @@ static inline int validate_decl_type(PSI_Data *data, decl_type *type) {
                        return 0;
                }
                break;
+       case PSI_T_UNION:
+               if (!locate_decl_type_union(data->unions, type)) {
+                       return 0;
+               }
+               break;
        case PSI_T_ENUM:
                if (!locate_decl_type_enum(data->enums, type)) {
                        return 0;
@@ -141,8 +165,8 @@ static inline int validate_constant(PSI_Data *data, constant *c) {
 static inline int validate_decl_arg(PSI_Data *data, decl_arg *arg) {
        if (!validate_decl_type(data, arg->type)) {
                data->error(arg->type->token, PSI_WARNING,
-                       "Cannot use '%s'(%d) as type for decl var '%s'",
-                       arg->type->name, arg->type->type, arg->var->name);
+                       "Cannot use '%s' as type for '%s'",
+                       arg->type->name, arg->var->name);
                return 0;
        }
        return 1;
@@ -172,18 +196,101 @@ static void psi_sort_struct_arg_swp(void *a, void *b) {
        *_b = *_a;
        *_a = _c;
 }
-static inline void psi_sort_struct_args(decl_struct *s) {
-       zend_insert_sort(s->args->args, s->args->count, sizeof(*s->args->args),
+static inline void psi_sort_struct_args(void **args, size_t count) {
+       zend_insert_sort(args, count, sizeof(*args),
                        psi_sort_struct_arg_cmp, psi_sort_struct_arg_swp);
 }
 
-static inline int validate_decl_struct(PSI_Data *data, decl_struct *s) {
-       size_t i;
+static inline int validate_decl_struct_darg(PSI_Data *data, decl_arg *darg) {
+       decl_type *real = real_decl_type(darg->type);
 
-       for (i = 0; i < s->args->count; ++i) {
-               if (!validate_decl_arg(data, s->args->args[i])) {
+       /* pre-validate any structs/unions/enums */
+       switch (real->type) {
+       case PSI_T_STRUCT:
+               if (!validate_decl_struct(data, real->strct)) {
+                       return 0;
+               }
+               break;
+       case PSI_T_UNION:
+               if (!validate_decl_union(data, real->unn)) {
                        return 0;
                }
+               break;
+       case PSI_T_ENUM:
+               if (!validate_decl_enum(data, real->enm)) {
+                       return 0;
+               }
+               break;
+       }
+
+       return 1;
+}
+
+static inline size_t sizeof_decl_arg(decl_arg *darg) {
+       size_t size;
+       decl_type *real = real_decl_type(darg->type);
+
+       if (darg->var->array_size) {
+               if (darg->var->pointer_level > 2) {
+                       size = psi_t_size(PSI_T_POINTER) * darg->var->array_size;
+               } else {
+                       size = psi_t_size(real->type) * darg->var->array_size;
+               }
+       } else if (darg->var->pointer_level) {
+               size = psi_t_size(PSI_T_POINTER);
+       } else {
+               switch (real->type) {
+               case PSI_T_UNION:
+                       size = real->unn->size;
+                       break;
+               case PSI_T_STRUCT:
+                       size = real->strct->size;
+                       break;
+               case PSI_T_ENUM:
+               default:
+                       size = psi_t_size(real->type);
+                       break;
+               }
+       }
+
+       return size;
+}
+
+static inline size_t align_decl_arg(decl_arg *darg, size_t *pos, size_t *len) {
+       size_t align;
+
+       if (darg->var->pointer_level && (!darg->var->array_size || darg->var->pointer_level > 2)) {
+               align = psi_t_alignment(PSI_T_POINTER);
+       } else {
+               decl_type *real = real_decl_type(darg->type);
+
+               switch (real->type) {
+               case PSI_T_STRUCT:
+                       align = real->strct->align;
+                       break;
+               case PSI_T_UNION:
+                       align = real->unn->align;
+                       break;
+               default:
+                       align = psi_t_alignment(real->type);
+                       break;
+               }
+       }
+
+       *len = sizeof_decl_arg(darg);
+       *pos = psi_align(align, *pos);
+
+       return align;
+}
+
+static inline int validate_decl_struct(PSI_Data *data, decl_struct *s) {
+       size_t i, pos, len, size, align;
+
+       if (!s->size && !s->args->count) {
+               data->error(s->token, PSI_WARNING,
+                               "Cannot compute size of empty struct %s",
+                               s->name);
+               return 0;
        }
 
        for (i = 0; i < s->args->count; ++i) {
@@ -197,68 +304,119 @@ static inline int validate_decl_struct(PSI_Data *data, decl_struct *s) {
                darg->var->arg = darg;
 
                if (darg->layout) {
-                       size_t size;
+                       pos = darg->layout->pos;
 
-                       if (darg->var->array_size) {
-                               size = psi_t_size(real_decl_type(darg->type)->type) * darg->var->array_size;
-                       } else if (darg->var->pointer_level) {
-                               size = psi_t_size(PSI_T_POINTER);
-                       } else {
-                               decl_type *real = real_decl_type(darg->type);
+                       align = align_decl_arg(darg, &pos, &len);
 
-                               if (real->type == PSI_T_STRUCT) {
-                                       size = real->strct->size;
-                               } else {
-                                       size = psi_t_size(real->type);
-                               }
-                       }
-                       if (darg->layout->len != size) {
+                       if (darg->layout->len != len) {
                                data->error(darg->token, PSI_WARNING,
-                                               "Computed length %zu of %s.%s does not match"
-                                               " pre-defined length %zu of type '%s'",
-                                               darg->layout->len, s->name, darg->var->name, size,
+                                               "Computed size %zu of %s.%s does not match"
+                                               " pre-defined size %zu of type '%s'",
+                                               darg->layout->len, s->name, darg->var->name, len,
                                                darg->type->name);
                                return 0;
                        }
+                       if (darg->layout->pos != pos) {
+                               data->error(darg->token, PSI_WARNING,
+                                               "Computed offset %zu of %s.%s does not match"
+                                               " pre-defined offset %zu",
+                                               darg->layout->len, s->name, darg->var->name, len);
+                               return 0;
+                       }
+               } else if (!validate_decl_struct_darg(data, darg)) {
+                       return 0;
                } else {
-                       token_t t;
-                       size_t size, align;
-
-                       if (darg->var->pointer_level && (!darg->var->array_size || darg->var->pointer_level == 1)) {
-                               t = PSI_T_POINTER;
+                       if (i) {
+                               pos = s->args->args[i-1]->layout->pos +
+                                               s->args->args[i-1]->layout->len;
                        } else {
-                               t = real_decl_type(darg->type)->type;
+                               pos = 0;
                        }
 
-                       switch (t) {
-                       case PSI_T_STRUCT:
-                               if (!validate_decl_struct(data, real_decl_type(darg->type)->strct)) {
-                                       return 0;
-                               }
-                               size = real_decl_type(darg->type)->strct->size;
-                               break;
-                       default:
-                               size = psi_t_size(t) * (darg->var->array_size ?: 1);
-                               break;
-                       }
+                       align = align_decl_arg(darg, &pos, &len);
+                       darg->layout = init_decl_struct_layout(pos, len);
+               }
 
-                       if (i) {
-                               decl_arg *last = s->args->args[i-1];
+               if (align > s->align) {
+                       s->align = align;
+               }
+       }
 
-                               align = psi_t_align(t, last->layout->pos + last->layout->len);
-                       } else {
-                               align = 0;
+       psi_sort_struct_args((void **) s->args->args, s->args->count);
+
+       if (s->args->count) {
+               decl_arg *darg = s->args->args[s->args->count-1];
+
+               size = darg->layout->pos + darg->layout->len;
+               if (s->size < size) {
+                       s->size = psi_align(size, s->align);
+               }
+       }
+
+       return 1;
+}
+
+static inline int validate_decl_union(PSI_Data *data, decl_union *u) {
+       size_t i, pos, len, size, align;
+
+       if (!u->size && !u->args->count) {
+               data->error(u->token, PSI_WARNING,
+                               "Cannot compute size of empty union %s",
+                               u->name);
+               return 0;
+       }
+
+       for (i = 0; i < u->args->count; ++i) {
+               decl_arg *darg = u->args->args[i];
+
+               if (!validate_decl_arg(data, darg)) {
+                       return 0;
+               }
+
+               ZEND_ASSERT(!darg->var->arg || darg->var->arg == darg);
+               darg->var->arg = darg;
+
+               if (darg->layout) {
+                       pos = darg->layout->pos;
+
+                       align = align_decl_arg(darg, &pos, &len);
+
+                       if (darg->layout->pos != 0) {
+                               data->error(darg->token, PSI_WARNING,
+                                               "Offset of %s.%s must be 0",
+                                               u->name, darg->var->name);
+                               return 0;
+                       }
+                       if (darg->layout->len != len) {
+                               data->error(darg->token, PSI_WARNING,
+                                               "Computed size %zu of %s.%s does not match"
+                                               " pre-defined size %zu of type '%s'",
+                                               darg->layout->len, u->name, darg->var->name, size,
+                                               darg->type->name);
+                               return 0;
                        }
+               } else if (!validate_decl_struct_darg(data, darg)) {
+                       return 0;
+               } else {
+                       pos = 0;
+
+                       align = align_decl_arg(darg, &pos, &len);
+                       darg->layout = init_decl_struct_layout(pos, len);
 
-                       darg->layout = init_decl_struct_layout(align, size);
                }
-               if (s->size < darg->layout->pos + darg->layout->len) {
-                       s->size = darg->layout->pos + darg->layout->len;
-                       /* FIXME: align struct */
+               if (len > size) {
+                       size = len;
+               }
+               if (align > u->align) {
+                       u->align = align;
                }
        }
 
-       psi_sort_struct_args(s);
+       psi_sort_struct_args((void **) u->args->args, u->args->count);
+
+       if (u->size < size) {
+               u->size = psi_align(size, u->align);
+       }
 
        return 1;
 }
@@ -306,7 +464,7 @@ static inline int validate_decl_func(PSI_Data *data, void *dl, decl *decl, decl_
                if (!decl->call.sym) {
                        data->error(func->token, PSI_WARNING,
                                "Failed to locate symbol '%s': %s",
-                               func->var->name, dlerror());
+                               func->var->name, dlerror() ?: "not found");
                }
        }
        return 1;
@@ -1113,6 +1271,18 @@ int PSI_ContextValidateData(PSI_Data *dest, PSI_Data *source)
                }
        }
 
+       if (source->unions) for (i = 0; i < source->unions->count; ++i) {
+               decl_union *dunion = source->unions->list[i];
+
+               if (validate_decl_union(source, dunion)) {
+                       if (dest) {
+                               dest->unions = add_decl_union(dest->unions, dunion);
+                       }
+               } else {
+                       ++errors;
+               }
+       }
+
        if (source->enums) for (i = 0; i < source->enums->count; ++i) {
                decl_enum *denum = source->enums->list[i];
 
index d14bac727bbe0f32ad699480afc10b8bd58ff241..dc9d2746f235aff80c90a36a35eaf7319dbf0488 100644 (file)
@@ -29,7 +29,6 @@ size_t psi_t_alignment(token_t t)
                return ALIGNOF_DOUBLE;
        case PSI_T_POINTER:
        case PSI_T_FUNCTION:
-       case PSI_T_STRUCT:
                return ALIGNOF_VOID_P;
        case PSI_T_ENUM:
                return ALIGNOF_INT;
@@ -64,21 +63,6 @@ size_t psi_t_size(token_t t)
        return 0;
 }
 
-size_t psi_t_align(token_t t, size_t s)
-{
-       size_t a = psi_t_alignment(t);
-       return ((s - 1) | (a - 1)) + 1;
-}
-
-size_t psi_offset_padding(size_t diff, size_t alignment)
-{
-       if (diff && diff <= ((diff - 1) | (alignment -1)) + 1) {
-               diff = 0;
-       }
-
-       return diff;
-}
-
 int psi_internal_type(impl_type *type)
 {
        switch (type->type) {
index 9a2ddcf5296dbe8df365785371b0b0bb744e4dd7..364ec550fd760350e5d334522b842b8ab6a7f63f 100644 (file)
@@ -3,9 +3,19 @@
 
 size_t psi_t_alignment(token_t t);
 size_t psi_t_size(token_t t);
-size_t psi_t_align(token_t t, size_t s);
 
-size_t psi_offset_padding(size_t diff, size_t alignment);
+static inline size_t psi_align(size_t s, size_t a) {
+       return ((s - 1) | (a - 1)) + 1;
+}
+
+static inline size_t psi_offset_padding(size_t diff, size_t alignment) {
+       if (diff && diff <= psi_align(diff, alignment)) {
+               diff = 0;
+       }
+
+       return diff;
+}
+
 int psi_internal_type(impl_type *type);
 zend_internal_arg_info *psi_internal_arginfo(impl *impl);
 size_t psi_num_min_args(impl *impl);
index 1f5bf016a8a714add395b3fb7a0de32b801eda43..369fe3367ba5d46b3c24398e19ed6168503ab8c4 100644 (file)
@@ -88,6 +88,7 @@ static inline ffi_type *psi_ffi_token_type(token_t t) {
        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;
index 0f5671d38ebf7782f3b42ae68120df801182487a..066e8a355c947321cb6c41c29734ae5808c80073 100644 (file)
@@ -62,6 +62,7 @@ typedef struct decl_type {
        token_t type;
        struct decl_type *real;
        struct decl_struct *strct;
+       struct decl_union *unn;
        struct decl_enum *enm;
        struct decl *func;
 } decl_type;
@@ -166,6 +167,9 @@ static inline decl_arg *init_decl_arg(decl_type *type, decl_var *var) {
 }
 
 static inline void free_decl_arg(decl_arg *arg) {
+       if (arg->token && arg->token != arg->var->token) {
+               free(arg->token);
+       }
        free_decl_type(arg->type);
        free_decl_var(arg->var);
        if (arg->layout) {
@@ -343,6 +347,7 @@ typedef struct decl_struct {
        char *name;
        decl_args *args;
        size_t size;
+       size_t align;
        struct {
                void *type;
                void (*dtor)(void *type);
@@ -394,6 +399,56 @@ static inline void free_decl_structs(decl_structs *ss) {
        free(ss);
 }
 
+typedef struct decl_union {
+       PSI_Token *token;
+       char *name;
+       decl_args *args;
+       size_t size;
+       size_t align;
+} decl_union;
+
+static inline decl_union *init_decl_union(const char *name, decl_args *args) {
+       decl_union *u = calloc(1, sizeof(*u));
+       u->name = strdup(name);
+       u->args = args;
+       return u;
+}
+
+static inline void free_decl_union(decl_union *u) {
+       if (u->token) {
+               free(u->token);
+       }
+       if (u->args) {
+               free_decl_args(u->args);
+       }
+       free(u->name);
+       free(u);
+}
+
+typedef struct decl_unions {
+       decl_union **list;
+       size_t count;
+} decl_unions;
+
+static inline decl_unions *add_decl_union(decl_unions *uu, decl_union *u) {
+       if (!uu) {
+               uu = calloc(1, sizeof(*uu));
+       }
+       uu->list = realloc(uu->list, ++uu->count * sizeof(*uu->list));
+       uu->list[uu->count-1] = u;
+       return uu;
+}
+
+static inline void free_decl_unions(decl_unions *uu) {
+       size_t i;
+
+       for (i = 0; i < uu->count; ++i) {
+               free_decl_union(uu->list[i]);
+       }
+       free(uu->list);
+       free(uu);
+}
+
 typedef struct impl_type {
        char *name;
        token_t type;
@@ -1361,6 +1416,7 @@ typedef void (*psi_error_cb)(PSI_Token *token, int type, const char *msg, ...);
        constants *consts; \
        decl_typedefs *defs; \
        decl_structs *structs; \
+       decl_unions *unions; \
        decl_enums *enums; \
        decls *decls; \
        impls *impls; \
@@ -1392,6 +1448,9 @@ static inline void PSI_DataDtor(PSI_Data *data) {
        if (data->structs) {
                free_decl_structs(data->structs);
        }
+       if (data->unions) {
+               free_decl_unions(data->unions);
+       }
        if (data->enums) {
                free_decl_enums(data->enums);
        }
index 4749e82197132c41bdcef8e55f6e785b265d3051..47239e82b5e66f1bef60fb1cf1715c57cccf8f60 100644 (file)
 #define PSI_T_RETURN                          10
 #define PSI_T_LIB                             11
 #define PSI_T_STRING                          12
-#define PSI_T_STRUCT                          13
-#define PSI_T_UNION                           14
-#define PSI_T_EOF                             15
-#define PSI_T_EOS                             16
-#define PSI_T_QUOTED_STRING                   17
-#define PSI_T_ENUM                            18
-#define PSI_T_LBRACE                          19
-#define PSI_T_RBRACE                          20
-#define PSI_T_COMMA                           21
-#define PSI_T_EQUALS                          22
+#define PSI_T_EOF                             13
+#define PSI_T_EOS                             14
+#define PSI_T_QUOTED_STRING                   15
+#define PSI_T_ENUM                            16
+#define PSI_T_LBRACE                          17
+#define PSI_T_RBRACE                          18
+#define PSI_T_COMMA                           19
+#define PSI_T_EQUALS                          20
+#define PSI_T_UNION                           21
+#define PSI_T_STRUCT                          22
 #define PSI_T_COLON                           23
 #define PSI_T_LPAREN                          24
 #define PSI_T_NUMBER                          25
index e488c0e475ac0e6eea149f5fdcb6381ed210a175..0e966a8fbd8cb864ab8bec7beac8a111fbb5627b 100644 (file)
@@ -30,7 +30,6 @@ void psi_error(int, const char *, int, const char *, ...);
 %left PLUS MINUS.
 %left SLASH ASTERISK.
 %fallback NAME TEMP FREE SET LET RETURN LIB STRING.
-%fallback STRUCT UNION.
 
 file ::= blocks.
 
@@ -71,6 +70,9 @@ block ::= constant(constant). {
 block ::= decl_struct(strct). {
        P->structs = add_decl_struct(P->structs, strct);
 }
+block ::= decl_union(u). {
+       P->unions = add_decl_union(P->unions, u);
+}
 block ::= decl_enum(e). {
        P->enums = add_decl_enum(P->enums, e);
 }
@@ -81,6 +83,7 @@ optional_name(n) ::= .{
 optional_name(n) ::= NAME(N). {
        n = N;
 }
+
 enum_name(n) ::= ENUM(E) optional_name(N). {
        if (N) {
                n = N;
@@ -120,6 +123,18 @@ decl_enum_item(i) ::= NAME(N). {
        i->token = N;
 }
 
+union_name(n) ::= UNION(U) optional_name(N). {
+       if (N) {
+               n = N;
+               free(U);
+       } else {
+               char digest[17];
+
+               PSI_TokenHash(U, digest);
+               n = PSI_TokenTranslit(PSI_TokenAppend(U, 1, digest), " ", "@");
+       }
+}
+
 struct_name(n) ::= STRUCT(S) optional_name(N). {
        if (N) {
                n = N;
@@ -149,7 +164,7 @@ decl_struct_args(args_) ::= EOS. {
 
 %type decl_struct {decl_struct*}
 %destructor decl_struct {free_decl_struct($$);}
-decl_struct(strct) ::= struct_name(N) struct_size(size_) decl_struct_args(args). {
+decl_struct(strct) ::= STRUCT NAME(N) struct_size(size_) decl_struct_args(args). {
        strct = init_decl_struct(N->text, args);
        strct->size = size_;
        strct->token = N;
@@ -164,6 +179,14 @@ struct_size(size) ::= COLON COLON LPAREN NUMBER(SIZ) RPAREN. {
        free(SIZ);
 }
 
+%type decl_union {decl_union*}
+%destructor decl_union {free_decl_union($$);}
+decl_union(u) ::= UNION NAME(N) struct_size(size_) decl_struct_args(args). {
+       u = init_decl_union(N->text, args);
+       u->size = size_;
+       u->token = N;
+}
+
 %token_class const_type_token BOOL INT FLOAT STRING.
 %type const_type {const_type*}
 %destructor const_type {free_const_type($$);}
@@ -204,6 +227,9 @@ decl_typedef(def) ::= TYPEDEF(T) decl_typedef_body(def_) EOS. {
        if ($$->type->enm) {
                free_decl_enum($$->type->enm);
        }
+       if ($$->type->unn) {
+               free_decl_union($$->type->unn);
+       }
        if ($$->type->func) {
                free_decl($$->type->func);
        }
@@ -215,6 +241,13 @@ decl_typedef_body_ex(def) ::= struct_name(N) struct_size(size_) decl_struct_args
        def->type->strct->token = N;
        def->type->strct->size = size_;
 }
+decl_typedef_body_ex(def) ::= union_name(N) struct_size(size_) decl_struct_args_block(args) decl_var(var). {
+       def = init_decl_arg(init_decl_type(PSI_T_UNION, N->text), var);
+       def->type->token = PSI_TokenCopy(N);
+       def->type->unn = init_decl_union(N->text, args);
+       def->type->unn->token = N;
+       def->type->unn->size = size_;
+}
 decl_typedef_body_ex(def) ::= decl_enum(e) NAME(ALIAS). {
        def = init_decl_arg(init_decl_type(PSI_T_ENUM, e->name), init_decl_var(ALIAS->text, 0, 0));
        def->var->token = ALIAS;
@@ -230,6 +263,9 @@ decl_typedef_body_ex(def) ::= decl_enum(e) NAME(ALIAS). {
        if ($$->type->enm) {
                free_decl_enum($$->type->enm);
        }
+       if ($$->type->unn) {
+               free_decl_union($$->type->unn);
+       }
        if ($$->type->func) {
                free_decl($$->type->func);
        }
@@ -264,7 +300,8 @@ decl_func(func) ::= VOID(T) NAME(N). {
                init_decl_var(N->text, 0, 0)
        );
        func->type->token = T;
-       free(N);
+       func->var->token = N;
+       func->token = N;
 }
 
 %type decl_abi {decl_abi*}
@@ -343,9 +380,26 @@ struct_args(args) ::= struct_args(args_) struct_arg(arg). {
        args = add_decl_arg(args_, arg);
 }
 %type struct_arg {decl_arg*}
-%destructor struct_arg {free_decl_arg($$);}
+%destructor struct_arg {
+       free_decl_arg($$);
+       if ($$->type->strct) {
+               free_decl_struct($$->type->strct);
+       }
+       if ($$->type->enm) {
+               free_decl_enum($$->type->enm);
+       }
+       if ($$->type->func) {
+               free_decl($$->type->func);
+       }
+}
 struct_arg(arg_) ::= decl_typedef_body_ex(def) EOS. {
        arg_ = def;
+       if (def->type->strct) {
+               P->structs = add_decl_struct(P->structs, def->type->strct);
+       }
+       if (def->type->enm) {
+               P->enums = add_decl_enum(P->enums, def->type->enm);
+       }
 }
 struct_arg(arg) ::= decl_arg(arg_) struct_layout(layout_) EOS. {
        arg_->layout = layout_;
@@ -448,6 +502,11 @@ decl_type(type_) ::= STRUCT(S) NAME(T). {
        type_->token = T;
        free(S);
 }
+decl_type(type_) ::= UNION(U) NAME(T). {
+       type_ = init_decl_type(U->type, T->text);
+       type_->token = T;
+       free(U);
+}
 decl_type(type_) ::= ENUM(E) NAME(T). {
        type_ = init_decl_type(E->type, T->text);
        type_->token = T;
index ea511f852b3612d62c988bc3d4ef3b24fb398587..6d2904dd536085f0abfe962470d08e2e787790f9 100644 (file)
@@ -5,6 +5,7 @@ psi.directory={PWD}:{PWD}/../../psi.d
 --SKIPIF--
 <?php 
 extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\div") or die("skip - need psi\\div()");
 ?>
 --FILE--
 ===TEST===
index 771263104246f8874b7e6d7836a0e7c42e0e43ec..6d77ef87a949d390c165f7587d172db9e5b9498d 100644 (file)
@@ -5,6 +5,7 @@ psi.directory={PWD}:{PWD}/../../psi.d
 --SKIPIF--
 <?php 
 extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\ldiv") or die("skip - need psi\\ldiv()");
 ?>
 --FILE--
 ===TEST===
index f084912fd0f70f073ad36efbc4328541c0380160..c0e1bbfc6b43fada9c406e93d0fe65c1499148e4 100644 (file)
@@ -2,9 +2,11 @@
 lldiv
 --INI--
 psi.directory={PWD}:{PWD}/../../psi.d
+display_startup_errors=0
 --SKIPIF--
 <?php 
 extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\lldiv") or die("skip - need psi\\lldiv()");
 ?>
 --FILE--
 ===TEST===
index da8589c63df08b6c996c179799691efa9eb9b30b..8a504e73a31ecabc41a8bd7d5a41b4fad5887731 100644 (file)
@@ -15,6 +15,8 @@ fclose($fd);
 var_dump(file_exists($fn));
 var_dump(psi_validate($fn));
 
+@unlink(__DIR__."/dump.psi");
+
 ?>
 ===DONE===
 --EXPECT--
@@ -22,7 +24,3 @@ var_dump(psi_validate($fn));
 bool(true)
 bool(true)
 ===DONE===
---CLEAN--
-<?php 
-@unlink(__DIR__."/dump.psi");
-?>
\ No newline at end of file