From ed5ebb3caac1ac8bf6a4b32eabfb523f23de8576 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 29 Jan 2016 14:05:38 +0100 Subject: [PATCH 1/1] flush --- config.m4 | 23 +-- m4/errno.m4 | 2 +- m4/fcntl.m4 | 2 +- m4/glob.m4 | 3 +- m4/locale.m4 | 2 +- m4/ndbm.m4 | 2 +- m4/netdb.m4 | 2 +- m4/netinet_in.m4 | 2 +- m4/netinet_tcp.m4 | 2 +- m4/poll.m4 | 2 +- m4/psi.m4 | 9 ++ m4/stdio.m4 | 2 +- m4/sys_select.m4 | 2 +- m4/sys_socket.m4 | 2 +- m4/sys_stat.m4 | 2 +- m4/sys_time.m4 | 2 +- m4/sys_times.m4 | 2 +- m4/sys_uio.m4 | 2 +- m4/sys_utsname.m4 | 2 +- m4/syslog.m4 | 2 +- m4/time.m4 | 2 +- m4/wchar.m4 | 2 +- m4/wctype.m4 | 2 +- src/context_dump.c | 33 ++++ src/context_validate.c | 276 ++++++++++++++++++++++++++------- src/engine.c | 16 -- src/engine.h | 14 +- src/libffi.c | 1 + src/parser.h | 59 +++++++ src/parser_proc.h | 20 +-- src/parser_proc.y | 67 +++++++- tests/div/div001.phpt | 1 + tests/div/ldiv001.phpt | 1 + tests/div/lldiv001.phpt | 2 + tests/parser/dump/dump001.phpt | 6 +- 35 files changed, 451 insertions(+), 120 deletions(-) diff --git a/config.m4 b/config.m4 index ade6f45..74fefdb 100644 --- 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 diff --git a/m4/errno.m4 b/m4/errno.m4 index be6f996..4d28b8b 100644 --- a/m4/errno.m4 +++ b/m4/errno.m4 @@ -1,5 +1,5 @@ PSI_CHECK_ERRNO() { - AC_CHECK_HEADERS(errno.h) + PSI_CONFIG_POSIX(errno, errno.h) PSI_EXTVAR(int errno) diff --git a/m4/fcntl.m4 b/m4/fcntl.m4 index a9b59d4..9e992cc 100644 --- a/m4/fcntl.m4 +++ b/m4/fcntl.m4 @@ -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) diff --git a/m4/glob.m4 b/m4/glob.m4 index 343b372..da5dc0e 100644 --- a/m4/glob.m4 +++ b/m4/glob.m4 @@ -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, diff --git a/m4/locale.m4 b/m4/locale.m4 index e422a92..3459101 100644 --- a/m4/locale.m4 +++ b/m4/locale.m4 @@ -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, diff --git a/m4/ndbm.m4 b/m4/ndbm.m4 index 1005722..3d60b06 100644 --- a/m4/ndbm.m4 +++ b/m4/ndbm.m4 @@ -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) diff --git a/m4/netdb.m4 b/m4/netdb.m4 index 5049a53..43008e5 100644 --- a/m4/netdb.m4 +++ b/m4/netdb.m4 @@ -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, diff --git a/m4/netinet_in.m4 b/m4/netinet_in.m4 index 4dcca38..e226d05 100644 --- a/m4/netinet_in.m4 +++ b/m4/netinet_in.m4 @@ -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) diff --git a/m4/netinet_tcp.m4 b/m4/netinet_tcp.m4 index 7c4677c..4e10420 100644 --- a/m4/netinet_tcp.m4 +++ b/m4/netinet_tcp.m4 @@ -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) } diff --git a/m4/poll.m4 b/m4/poll.m4 index 2105a64..bbbb221 100644 --- a/m4/poll.m4 +++ b/m4/poll.m4 @@ -1,5 +1,5 @@ PSI_CHECK_POLL() { - AC_CHECK_HEADERS(poll.h) + PSI_CONFIG_POSIX(poll, poll.h) PSI_STRUCT(struct pollfd, [ int fd, diff --git a/m4/psi.m4 b/m4/psi.m4 index 97ea6fe..e8d8069 100644 --- 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(). diff --git a/m4/stdio.m4 b/m4/stdio.m4 index 9144cb1..a2b40b5 100644 --- a/m4/stdio.m4 +++ b/m4/stdio.m4 @@ -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) diff --git a/m4/sys_select.m4 b/m4/sys_select.m4 index 8bd7e88..0390299 100644 --- a/m4/sys_select.m4 +++ b/m4/sys_select.m4 @@ -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, []) diff --git a/m4/sys_socket.m4 b/m4/sys_socket.m4 index 4d28cdd..6d1eaf3 100644 --- a/m4/sys_socket.m4 +++ b/m4/sys_socket.m4 @@ -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) diff --git a/m4/sys_stat.m4 b/m4/sys_stat.m4 index 937eb38..fb44945 100644 --- a/m4/sys_stat.m4 +++ b/m4/sys_stat.m4 @@ -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, diff --git a/m4/sys_time.m4 b/m4/sys_time.m4 index 1b845dd..9c1f744 100644 --- a/m4/sys_time.m4 +++ b/m4/sys_time.m4 @@ -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) diff --git a/m4/sys_times.m4 b/m4/sys_times.m4 index 9f9da56..3301070 100644 --- a/m4/sys_times.m4 +++ b/m4/sys_times.m4 @@ -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, diff --git a/m4/sys_uio.m4 b/m4/sys_uio.m4 index e7cbce3..7cd4c3c 100644 --- a/m4/sys_uio.m4 +++ b/m4/sys_uio.m4 @@ -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, diff --git a/m4/sys_utsname.m4 b/m4/sys_utsname.m4 index dde0313..36f49d3 100644 --- a/m4/sys_utsname.m4 +++ b/m4/sys_utsname.m4 @@ -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@:>@, diff --git a/m4/syslog.m4 b/m4/syslog.m4 index 198f4f8..3547f75 100644 --- a/m4/syslog.m4 +++ b/m4/syslog.m4 @@ -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) diff --git a/m4/time.m4 b/m4/time.m4 index 6fd6c10..e1b4011 100644 --- a/m4/time.m4 +++ b/m4/time.m4 @@ -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) diff --git a/m4/wchar.m4 b/m4/wchar.m4 index c399a06..f1a7026 100644 --- a/m4/wchar.m4 +++ b/m4/wchar.m4 @@ -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) diff --git a/m4/wctype.m4 b/m4/wctype.m4 index 627b919..319dada 100644 --- a/m4/wctype.m4 +++ b/m4/wctype.m4 @@ -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) diff --git a/src/context_dump.c b/src/context_dump.c index 708b36f..c62ebf2 100644 --- a/src/context_dump.c +++ b/src/context_dump.c @@ -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"); } diff --git a/src/context_validate.c b/src/context_validate.c index 7c7a245..01dbfb7 100644 --- a/src/context_validate.c +++ b/src/context_validate.c @@ -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]; diff --git a/src/engine.c b/src/engine.c index d14bac7..dc9d274 100644 --- a/src/engine.c +++ b/src/engine.c @@ -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) { diff --git a/src/engine.h b/src/engine.h index 9a2ddcf..364ec55 100644 --- a/src/engine.h +++ b/src/engine.h @@ -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); diff --git a/src/libffi.c b/src/libffi.c index 1f5bf01..369fe33 100644 --- a/src/libffi.c +++ b/src/libffi.c @@ -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; diff --git a/src/parser.h b/src/parser.h index 0f5671d..066e8a3 100644 --- a/src/parser.h +++ b/src/parser.h @@ -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); } diff --git a/src/parser_proc.h b/src/parser_proc.h index 4749e82..47239e8 100644 --- a/src/parser_proc.h +++ b/src/parser_proc.h @@ -10,16 +10,16 @@ #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 diff --git a/src/parser_proc.y b/src/parser_proc.y index e488c0e..0e966a8 100644 --- a/src/parser_proc.y +++ b/src/parser_proc.y @@ -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; diff --git a/tests/div/div001.phpt b/tests/div/div001.phpt index ea511f8..6d2904d 100644 --- a/tests/div/div001.phpt +++ b/tests/div/div001.phpt @@ -5,6 +5,7 @@ psi.directory={PWD}:{PWD}/../../psi.d --SKIPIF-- --FILE-- ===TEST=== diff --git a/tests/div/ldiv001.phpt b/tests/div/ldiv001.phpt index 7712631..6d77ef8 100644 --- a/tests/div/ldiv001.phpt +++ b/tests/div/ldiv001.phpt @@ -5,6 +5,7 @@ psi.directory={PWD}:{PWD}/../../psi.d --SKIPIF-- --FILE-- ===TEST=== diff --git a/tests/div/lldiv001.phpt b/tests/div/lldiv001.phpt index f084912..c0e1bbf 100644 --- a/tests/div/lldiv001.phpt +++ b/tests/div/lldiv001.phpt @@ -2,9 +2,11 @@ lldiv --INI-- psi.directory={PWD}:{PWD}/../../psi.d +display_startup_errors=0 --SKIPIF-- --FILE-- ===TEST=== diff --git a/tests/parser/dump/dump001.phpt b/tests/parser/dump/dump001.phpt index da8589c..8a504e7 100644 --- a/tests/parser/dump/dump001.phpt +++ b/tests/parser/dump/dump001.phpt @@ -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-- - \ No newline at end of file -- 2.30.2