flush
authorMichael Wallner <mike@php.net>
Tue, 10 Nov 2015 14:04:42 +0000 (15:04 +0100)
committerMichael Wallner <mike@php.net>
Tue, 10 Nov 2015 14:04:42 +0000 (15:04 +0100)
config.m4
src/context.c
src/context.h
src/libffi.c
src/libjit.c
src/module.c
src/parser.h
src/parser.re
src/parser_proc.y
tests/idn/idn.psi
tests/time/time.psi

index 338fcd32097d495294322467c8352df11030c3da..ee54dac1f5b12d9a809dd7fe0d0771fd0d258ae4 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -119,7 +119,6 @@ if test "$PHP_PSI" != "no"; then
        ])
 
 
-       PSI_CONSTS=""
        dnl PSI_COMPUTE_STR(variable, string or expression, includes)
        AC_DEFUN(PSI_COMPUTE_STR, [
                AC_TRY_RUN([
@@ -132,6 +131,7 @@ if test "$PHP_PSI" != "no"; then
                ])
        ])
 
+       PSI_CONSTS=""
        dnl PSI_CONST(const name, type, headers to include)
        AC_DEFUN(PSI_CONST, [
                AC_CACHE_CHECK(value of $1, psi_cv_const_$1, [
@@ -155,10 +155,10 @@ if test "$PHP_PSI" != "no"; then
                then
                        case $2 in
                        str*|quoted_str*)
-                               PSI_CONSTS="{PSI_T_STRING, \"string\", \"$1\", $psi_cv_const_$1, PSI_T_QUOTED_STRING}, $PSI_CONSTS"
+                               PSI_CONSTS="{PSI_T_STRING, \"string\", \"psi\\\\$1\", $psi_cv_const_$1, PSI_T_QUOTED_STRING}, $PSI_CONSTS"
                                ;;
                        *)
-                               PSI_CONSTS="{PSI_T_INT, \"int\", \"$1\", \"$psi_cv_const_$1\", PSI_T_NUMBER}, $PSI_CONSTS"
+                               PSI_CONSTS="{PSI_T_INT, \"int\", \"psi\\\\$1\", \"$psi_cv_const_$1\", PSI_T_NUMBER}, $PSI_CONSTS"
                                ;;
                        esac
                fi
@@ -218,7 +218,13 @@ if test "$PHP_PSI" != "no"; then
                                then
                                        psi_struct_member_pl=`expr $psi_struct_member_pl + 1`
                                fi
-                               psi_struct_members="{`psi_type_pair $psi_member_type $ac_cv_sizeof_struct_$1[]_[]member`, \"[]member[]\", $ac_cv_offsetof_struct_$1[]_[]member, $ac_cv_sizeof_struct_$1[]_[]member, $psi_struct_member_pl, $psi_struct_member_as}, $psi_struct_members"
+                               psi_struct_member="{`psi_type_pair $psi_member_type $ac_cv_sizeof_struct_$1[]_[]member`, \"[]member[]\", $ac_cv_offsetof_struct_$1[]_[]member, $ac_cv_sizeof_struct_$1[]_[]member, $psi_struct_member_pl, $psi_struct_member_as}"
+                               if test "$psi_struct_members"
+                               then
+                                       psi_struct_members="$psi_struct_members, $psi_struct_member"
+                               else
+                                       psi_struct_members="$psi_struct_member"
+                               fi
                        ], [], PSI_INCLUDES_DEFAULT($4))
                ])
                PSI_STRUCTS="{\"$1\", {$psi_struct_members}}, $PSI_STRUCTS"
@@ -395,6 +401,19 @@ if test "$PHP_PSI" != "no"; then
        PSI_CONST(UTIME_NOW, int, sys/stat.h)
        PSI_CONST(UTIME_OMIT, int, sys/stat.h)
        dnl sys/time.h
+       PSI_STRUCT(timeval, [
+               [tv_sec],
+               [tv_usec]], [
+       ], sys/time.h)
+       PSI_STRUCT(itimerval, [
+               [it_interval],
+               [it_value]], [
+               it_*) psi_member_type="struct timeval" ;;
+       ], sys/time.h)
+       PSI_STRUCT(timezone, [
+               [tz_minuteswest],
+               [tz_dsttime]], [
+       ], sys/time.h)
        PSI_CONST(ITIMER_REAL, int, sys/time.h)
        PSI_CONST(ITIMER_VIRTUAL, int, sys/time.h)
        PSI_CONST(ITIMER_PROF, int, sys/time.h)
@@ -419,7 +438,28 @@ if test "$PHP_PSI" != "no"; then
        PSI_TYPE(time_t, int)
        PSI_TYPE(timer_t, int)
        PSI_TYPE(uid_t)
-
+       dnl time.h
+       PSI_STRUCT(tm, [
+               [tm_sec],
+               [tm_min],
+               [tm_hour],
+               [tm_mday],
+               [tm_mon],
+               [tm_year],
+               [tm_wday],
+               [tm_yday],
+               [tm_isdst]], [
+       ], time.h)
+       PSI_STRUCT(timespec, [
+               [tv_sec],
+               [tv_nsec]], [
+       ], time.h)
+       PSI_CONST(CLOCKS_PER_SEC, int, time.h)
+       PSI_CONST(CLOCK_MONOTONIC, int, time.h)
+       PSI_CONST(CLOCK_PROCESS_CPUTIME_ID, int, time.h)
+       PSI_CONST(CLOCK_REALTIME, int, time.h)
+       PSI_CONST(CLOCK_THREAD_CPUTIME_ID, int, time.h)
+       PSI_CONST(TIMER_ABSTIME, int, time.h)
        dnl wchar.h
        AC_CHECK_TYPE(wint_t, [
                AX_CHECK_SIGN(wint_t, psi_wint_t=int, psi_wint_t=uint)
@@ -444,7 +484,7 @@ if test "$PHP_PSI" != "no"; then
        PHP_ADD_BUILD_DIR($PHP_PSI_BUILDDIR/src)
 
        PHP_PSI_HEADERS=`(cd $PHP_PSI_SRCDIR/src && echo *.h)`
-       PHP_PSI_SOURCES="src/parser_proc.c src/parser.c src/validator.c src/module.c src/context.c"
+       PHP_PSI_SOURCES="src/parser_proc.c src/parser.c src/module.c src/context.c"
        PHP_PSI_SOURCES="$PHP_PSI_SOURCES src/libjit.c src/libffi.c"
 
        PHP_NEW_EXTENSION(psi, $PHP_PSI_SOURCES, $ext_shared)
index 2d821ad2ab97d93d481ce5cf7f5f95fb434f5431..f0080f753e1ca6ec5aa15b2b5ec559e69e9a707b 100644 (file)
@@ -1,4 +1,5 @@
 #include <sys/param.h>
+#include <dlfcn.h>
 #include <dirent.h>
 #include <fnmatch.h>
 #include <errno.h>
@@ -9,9 +10,9 @@
 
 #include "php.h"
 #include "php_scandir.h"
+#include "php_psi.h"
 #include "context.h"
 #include "parser.h"
-#include "validator.h"
 
 #define psi_predef_count(of) ((sizeof(psi_predef ##of## s)/sizeof(psi_predef ##of))-1)
 typedef struct psi_predef_type {
@@ -55,10 +56,403 @@ static const psi_predef_struct psi_predef_structs[] = {
 };
 #define psi_predef_struct_count() psi_predef_count(_struct)
 
+static int validate_lib(PSI_Data *data, void **dlopened) {
+       char lib[MAXPATHLEN];
+       const char *ptr = data->psi.file.ln;
+       size_t len;
+
+       if (!ptr) {
+               /* FIXME: assume stdlib */
+               return 1;
+       } else if (!strchr(ptr, '/')) {
+#ifdef DARWIN
+               len = snprintf(lib, MAXPATHLEN, "lib%s.dylib", ptr);
+#else
+               len = snprintf(lib, MAXPATHLEN, "lib%s.so", ptr);
+#endif
+               if (MAXPATHLEN == len) {
+                       data->error(PSI_WARNING, "Library name too long: '%s'", ptr);
+               }
+               lib[len] = 0;
+               ptr = lib;
+       }
+       if (!(*dlopened = dlopen(ptr, RTLD_LAZY|RTLD_LOCAL))) {
+               data->error(PSI_WARNING, "Could not open library '%s': %s.",
+                               data->psi.file.fn, dlerror());
+               return 0;
+       }
+       return 1;
+}
+
+static inline int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) {
+       size_t i;
+
+       if (type->real) {
+               return 1;
+       }
+       for (i = 0; i < defs->count; ++i) {
+               if (!strcmp(defs->list[i]->alias, type->name)) {
+                       type->real = defs->list[i]->type;
+                       return 1;
+               }
+       }
+       return 0;
+}
+static inline int locate_decl_type_struct(decl_structs *structs, decl_type *type) {
+       size_t i;
+
+       if (type->strct) {
+               return 1;
+       }
+       for (i = 0; i < structs->count; ++i) {
+               if (!strcmp(structs->list[i]->name, type->name)) {
+                       type->strct = structs->list[i];
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static inline int validate_decl_type(PSI_Data *data, decl_type *type) {
+       switch (type->type) {
+       case PSI_T_NAME:
+               if (!data->defs || !locate_decl_type_alias(data->defs, type)) {
+                       return 0;
+               }
+               return validate_decl_type(data, type->real);
+       case PSI_T_STRUCT:
+               if (!data->structs || !locate_decl_type_struct(data->structs, type)) {
+                       return 0;
+               }
+               break;
+       }
+       return 1;
+}
+static inline int validate_decl_typedef(PSI_Data *data, decl_typedef *def) {
+       if (!validate_decl_type(data, def->type)) {
+               data->error(PSI_WARNING, "Type '%s' cannot be aliased to '%s'",
+                       def->type->name, def->alias);
+               return 0;
+       }
+       /* FIXME: check def->alias */
+       return 1;
+}
+
+static inline int validate_constant(PSI_Data *data, constant *c) {
+       /* FIXME */
+       return 1;
+}
+
+static inline int validate_decl_arg(PSI_Data *data, decl_arg *arg) {
+       if (!validate_decl_type(data, arg->type)) {
+               data->error(PSI_WARNING, "Cannot use '%s' as type for '%s'",
+                       arg->type->name, arg->var->name);
+               return 0;
+       }
+       return 1;
+}
+
+static inline int validate_decl_struct(PSI_Data *data, decl_struct *s) {
+       size_t i;
+
+       for (i = 0; i < s->args->count; ++i) {
+               if (!validate_decl_arg(data, s->args->args[i])) {
+                       return 0;
+               }
+       }
+
+       for (i = 0; i < s->args->count; ++i) {
+               decl_arg *darg = s->args->args[i];
+
+               if (!validate_decl_arg(data, darg)) {
+                       return 0;
+               }
+
+               ZEND_ASSERT(!darg->var->arg);
+               darg->var->arg = darg;
+
+               if (!darg->layout) {
+                       token_t t;
+
+                       if (darg->var->pointer_level && (!darg->var->array_size || darg->var->pointer_level == 1)) {
+                               t = PSI_T_POINTER;
+                       } else {
+                               t = real_decl_type(darg->type)->type;
+                       }
+
+                       if (i) {
+                               decl_arg *last = s->args->args[i-1];
+                               darg->layout = init_decl_struct_layout(
+                                               psi_t_align(t, last->layout->pos + last->layout->len),
+                                               psi_t_size(t) * darg->var->array_size);
+                       } else {
+                               darg->layout = init_decl_struct_layout(0, psi_t_size(t));
+                       }
+               }
+               if (s->size < darg->layout->pos + darg->layout->len) {
+                       s->size = darg->layout->pos + darg->layout->len;
+               }
+       }
+       return 1;
+}
+
+static const char * const abi_ccs[] = {
+               "default", /* \                 */
+               "extern",  /*  > - all the same */
+               "cdecl",   /* /                 */
+               "stdcall",
+               "fastcall",
+};
+static inline int validate_decl_abi(PSI_Data *data, decl_abi *abi) {
+       size_t i;
+
+       for (i = 0; i < sizeof(abi_ccs)/sizeof(char*); ++i) {
+               if (strcasecmp(abi->convention, abi_ccs[i])) {
+                       return 1;
+               }
+       }
+       data->error(PSI_WARNING, "Invalid calling convention: '%s'", abi->convention);
+       return 0;
+}
+static inline int validate_decl_func(PSI_Data *data, void *dl, decl *decl, decl_arg *func)
+{
+       if (!strcmp(func->var->name, "dlsym")) {
+               data->error(PSI_WARNING, "Cannot dlsym dlsym (sic!)");
+               return 0;
+       }
+
+       if (!validate_decl_arg(data, func)) {
+               return 0;
+       }
+#ifndef RTLD_NEXT
+# define RTLD_NEXT ((void *) -1l)
+#endif
+       decl->dlptr = dlsym(dl ?: RTLD_NEXT, func->var->name);
+       if (!decl->dlptr) {
+               data->error(PSI_WARNING, "Failed to located symbol '%s': %s",
+                       func->var->name, dlerror());
+       }
+       return 1;
+}
+
+static inline int validate_decl(PSI_Data *data, void *dl, decl *decl) {
+       if (!validate_decl_abi(data, decl->abi)) {
+               return 0;
+       }
+       if (!validate_decl_func(data, dl, decl, decl->func)) {
+               return 0;
+       }
+       if (decl->args) {
+               size_t i;
+
+               for (i = 0; i < decl->args->count; ++i) {
+                       if (!validate_decl_arg(data, decl->args->args[i])) {
+                               return 0;
+                       }
+               }
+       }
+       return 1;
+}
+
+static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) {
+       size_t i;
+
+       for (i = 0; i < decls->count; ++i) {
+               if (!strcmp(decls->list[i]->func->var->name, ret->decl->name)) {
+                       ret->decl->arg = decls->list[i]->func;
+                       return decls->list[i];
+               }
+       }
+       return NULL;
+}
+static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) {
+       /* we must have exactly one ret stmt delcaring the native func to call */
+       /* and which type cast to apply */
+       if (impl->stmts->ret.count != 1) {
+               if (impl->stmts->ret.count > 1) {
+                       data->error(PSI_WARNING, "Too many `return` statements for implmentation %s;"
+                                       " found %zu, exactly one is needed",
+                                       impl->func->name, impl->stmts->ret.count);
+               } else {
+                       data->error(PSI_WARNING, "Missing `return` statement for implementation %s",
+                                       impl->func->name);
+               }
+               return 0;
+       }
+       if (!(impl->decl = locate_impl_decl(data->decls, impl->stmts->ret.list[0]))) {
+               data->error(PSI_WARNING, "Missing declaration for implementation %s",
+                               impl->func->name);
+               return 0;
+       }
+
+       return 1;
+}
+static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) {
+       size_t i, j;
+       /* we can have multiple let stmts */
+       /* check that we have a let stmt for every decl arg */
+       if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
+               decl_arg *darg = impl->decl->args->args[i];
+               int check = 0;
+
+               for (j = 0; j < impl->stmts->let.count; ++j) {
+                       let_stmt *let = impl->stmts->let.list[j];
+
+                       if (!strcmp(let->var->name, darg->var->name)) {
+                               darg->let = let;
+                               check = 1;
+                               break;
+                       }
+               }
+               if (!check) {
+                       data->error(PSI_WARNING, "Missing `let` statement for arg '%s %.*s%s'"
+                                       " of declaration '%s' for implementation '%s'",
+                                       darg->type->name, (int) darg->var->pointer_level, "*****",
+                                       darg->var->name, impl->decl->func->var->name, impl->func->name);
+                       return 0;
+               }
+       }
+       /* check that the let_value references a known variable or NULL */
+       for (i = 0; i < impl->stmts->let.count; ++i) {
+               let_stmt *let = impl->stmts->let.list[i];
+               int check = 0;
+
+               if (let->val && let->val->func && let->val->func->alloc) {
+                       if (!validate_decl_type(data, let->val->func->alloc->type)) {
+                               data->error(PSI_WARNING, "Cannot use '%s' as type for calloc in `let` statement",
+                                       let->val->func->alloc->type->name);
+                               return 0;
+                       }
+               }
+               if (let->val && let->val->var) {
+                       if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) {
+                               impl_arg *iarg = impl->func->args->args[j];
+
+                               if (!strcmp(let->val->var->name, iarg->var->name)) {
+                                       let->arg = iarg;
+                                       check = 1;
+                                       break;
+                               }
+                       }
+                       if (!check) {
+                               data->error(PSI_WARNING, "Unknown value '$%s' of `let` statement"
+                                               " for variable '%s' of implementation '%s'",
+                                               let->val->var->name, let->var->name, impl->func->name);
+                               return 0;
+                       }
+               }
+       }
+       return 1;
+}
+static inline int validate_impl_set_stmts(PSI_Data *data, impl *impl) {
+       size_t i, j, k;
+       /* we can have any count of set stmts; processing out vars */
+       /* check that set stmts reference known variables */
+       for (i = 0; i < impl->stmts->set.count; ++i) {
+               set_stmt *set = impl->stmts->set.list[i];
+               int check = 0;
+
+               if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) {
+                       impl_arg *iarg = impl->func->args->args[j];
+
+                       if (!strcmp(set->var->name, iarg->var->name)) {
+                               set->arg = iarg;
+                               check = 1;
+                               break;
+                       }
+               }
+               if (!check) {
+                       data->error(PSI_WARNING, "Unknown variable '$%s' of `set` statement"
+                                       " of implementation '%s'",
+                                       set->var->name, impl->func->name);
+                       return 0;
+               }
+
+               for (j = 0; j < set->val->vars->count; ++j) {
+                       decl_var *set_var = set->val->vars->vars[j];
+
+                       check = 0;
+                       if (impl->decl->args) for (k = 0; k < impl->decl->args->count; ++k) {
+                               decl_arg *set_arg = impl->decl->args->args[k];
+
+                               if (!strcmp(set_var->name, set_arg->var->name)) {
+                                       check = 1;
+                                       set_var->arg = set_arg;
+                                       break;
+                               }
+                       }
+
+                       if (!check) {
+                               data->error(PSI_WARNING, "Unknown value '%s' of `set` statement"
+                                               " for variable '$%s' of implementation '%s'",
+                                               set_var->name, set->arg->var->name, impl->func->name);
+                               return 0;
+                       }
+               }
+       }
+       return 1;
+}
+static inline int validate_impl_free_stmts(PSI_Data *data, impl *impl) {
+       size_t i, j, k;
+       /* we can have any count of free stmts; freeing any out vars */
+       for (i = 0; i < impl->stmts->fre.count; ++i) {
+               free_stmt *fre = impl->stmts->fre.list[i];
+
+               for (j = 0; j < fre->vars->count; ++j) {
+                       decl_var *free_var = fre->vars->vars[j];
+                       int check = 0;
+
+                       if (!strcmp(free_var->name, impl->decl->func->var->name)) {
+                               continue;
+                       }
+                       if (impl->decl->args) for (k = 0; k < impl->decl->args->count; ++k) {
+                               decl_arg *free_arg = impl->decl->args->args[k];
+
+                               if (!strcmp(free_var->name, free_arg->var->name)) {
+                                       check = 1;
+                                       free_var->arg = free_arg;
+                                       break;
+                               }
+                       }
+
+                       if (!check) {
+                               data->error(PSI_WARNING, "Unknown variable '%s' of `free` statement"
+                                               " of implementation '%s'",
+                                               free_var->name, impl->func->name);
+                               return 0;
+                       }
+               }
+       }
+       return 1;
+}
+static inline int validate_impl_stmts(PSI_Data *data, impl *impl) {
+       if (!impl->stmts) {
+               data->error(PSI_WARNING, "Missing body for implementation %s!",
+                               impl->func->name);
+               return 0;
+       }
+
+       if (!validate_impl_ret_stmt(data, impl)) {
+               return 0;
+       }
+
+       if (!validate_impl_let_stmts(data, impl)) {
+               return 0;
+       }
+       if (!validate_impl_set_stmts(data, impl)) {
+               return 0;
+       }
+       if (!validate_impl_free_stmts(data, impl)) {
+               return 0;
+       }
+
+       return 1;
+}
+
 PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error)
 {
        size_t i, j;
-       PSI_Data data;
+       PSI_Data T;
 
        if (!C) {
                C = malloc(sizeof(*C));
@@ -69,13 +463,16 @@ PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErr
        C->ops = ops;
        ops->init(C);
 
-       memset(&data, 0, sizeof(data));
+       /* build up predefs in a temporary PSI_Data for validation */
+       memset(&T, 0, sizeof(T));
+       T.error = error;
+
        for (i = 0; i < psi_predef_type_count(); ++i) {
                const psi_predef_type *pre = &psi_predef_types[i];
                decl_type *type = init_decl_type(pre->type_tag, pre->type_name);
                decl_typedef *def = init_decl_typedef(pre->alias, type);
 
-               data.defs = add_decl_typedef(data.defs, def);
+               T.defs = add_decl_typedef(T.defs, def);
        }
        for (i = 0; i < psi_predef_const_count(); ++i) {
                const psi_predef_const *pre = &psi_predef_consts[i];
@@ -83,16 +480,18 @@ PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErr
                const_type *type = init_const_type(pre->type_tag, pre->type_name);
                constant *constant = init_constant(type, pre->name, val);
 
-               data.consts = add_constant(data.consts, constant);
+               T.consts = add_constant(T.consts, constant);
        }
        for (i = 0; i < psi_predef_struct_count(); ++i) {
                const psi_predef_struct *pre = &psi_predef_structs[i];
                decl_args *dargs = init_decl_args(NULL);
+               decl_struct *dstruct;
 
                for (j = 0; j < PSI_PREDEF_STRUCT_MEMBERS; ++j) {
                        const psi_predef_struct_member *member = &pre->members[j];
                        decl_type *type;
                        decl_var *dvar;
+                       decl_arg *darg;
 
                        if (!member->name) {
                                break;
@@ -100,15 +499,111 @@ PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErr
 
                        type = init_decl_type(member->type_tag, member->type_name);
                        dvar = init_decl_var(member->name, member->pointer_level, member->array_size);
-                       dargs = add_decl_arg(dargs, init_decl_arg(type, dvar));
+                       darg = init_decl_arg(type, dvar);
+                       darg->layout = init_decl_struct_layout(member->off, member->len);
+                       dargs = add_decl_arg(dargs, darg);
                }
 
-               data.structs = add_decl_struct(data.structs,
-                               init_decl_struct(pre->name, dargs));
+               dstruct = init_decl_struct(pre->name, dargs);
+               T.structs = add_decl_struct(T.structs, dstruct);
        }
+
+       for (i = 0; i < psi_predef_type_count(); ++i) {
+               decl_typedef *def = T.defs->list[i];
+
+               if (validate_decl_typedef(&T, def)) {
+                       C->defs = add_decl_typedef(C->defs, def);
+               }
+       }
+
+       for (i = 0; i < psi_predef_const_count(); ++i) {
+               constant *constant = T.consts->list[i];
+
+               if (validate_constant(&T, constant)) {
+                       C->consts = add_constant(C->consts, constant);
+               }
+       }
+
+       for (i = 0; i < psi_predef_struct_count(); ++i) {
+               decl_struct *dstruct = T.structs->list[i];
+
+               if (validate_decl_struct(&T, dstruct)) {
+                       C->structs = add_decl_struct(C->structs, dstruct);
+               }
+       }
+
+       C->count = 1;
+       C->data = malloc(sizeof(*C->data));
+       PSI_DataExchange(C->data, &T);
+
        return C;
 }
 
+int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P)
+{
+       PSI_Data *D;
+       void *dlopened = NULL;
+       size_t count = C->count++;
+
+       C->data = realloc(C->data, C->count * sizeof(*C->data));
+       D = PSI_DataExchange(&C->data[count], PSI_DATA(P));
+
+       if (D->defs) {
+               size_t i;
+
+               for (i = 0; i < D->defs->count; ++i) {
+                       if (validate_decl_typedef(PSI_DATA(C), D->defs->list[i])) {
+                               C->defs = add_decl_typedef(C->defs, D->defs->list[i]);
+                       }
+               }
+       }
+       if (D->structs) {
+               size_t i;
+
+               for (i = 0; i < D->structs->count; ++i) {
+                       if (validate_decl_struct(PSI_DATA(C), D->structs->list[i])) {
+                               C->structs = add_decl_struct(C->structs, D->structs->list[i]);
+                       }
+               }
+       }
+       if (D->consts) {
+               size_t i;
+
+               for (i = 0; i < D->consts->count; ++i) {
+                       if (validate_constant(PSI_DATA(C), D->consts->list[i])) {
+                               C->consts = add_constant(C->consts, D->consts->list[i]);
+                       }
+               }
+       }
+
+       if (!validate_lib(D, &dlopened)) {
+               return 0;
+       }
+
+       add_decl_lib(&C->psi.libs, dlopened);
+
+       if (D->decls) {
+               size_t i;
+
+               for (i = 0; i < D->decls->count; ++i) {
+                       if (validate_decl(PSI_DATA(C), dlopened, D->decls->list[i])) {
+                               C->decls = add_decl(C->decls, D->decls->list[i]);
+                       }
+               }
+       }
+       if (D->impls) {
+               size_t i;
+
+               for (i = 0; i < D->impls->count; ++i) {
+                       if (validate_impl_stmts(PSI_DATA(C), D->impls->list[i])) {
+                               C->impls = add_impl(C->impls, D->impls->list[i]);
+                       }
+               }
+       }
+
+       return 1;
+}
+
 static int psi_select_dirent(const struct dirent *entry)
 {
 #ifndef FNM_CASEFOLD
@@ -117,7 +612,6 @@ static int psi_select_dirent(const struct dirent *entry)
        return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD);
 }
 
-
 void PSI_ContextBuild(PSI_Context *C, const char *path)
 {
        int i, n;
@@ -130,7 +624,6 @@ void PSI_ContextBuild(PSI_Context *C, const char *path)
        } else for (i = 0; i < n; ++i) {
                char psi[MAXPATHLEN];
                PSI_Parser P;
-               PSI_Validator V;
 
                if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", path, entries[i]->d_name)) {
                        C->error(PSI_WARNING, "Path to PSI file too long: %s/%s",
@@ -146,23 +639,14 @@ void PSI_ContextBuild(PSI_Context *C, const char *path)
                        PSI_ParserParse(&P, PSI_TokenAlloc(&P));
                };
                PSI_ParserParse(&P, NULL);
-
-               if (!PSI_ValidatorInit(&V, &P)) {
-                       C->error(PSI_WARNING, "Failed to init PSI validator");
-                       break;
-               }
+               PSI_ContextValidate(C, &P);
                PSI_ParserDtor(&P);
+       }
 
-               if (PSI_ValidatorValidate(&V)) {
-                       zend_function_entry *closures;
-
-                       closures = PSI_ContextCompile(C, (PSI_Data *) &V);
-                       if (closures && SUCCESS != zend_register_functions(NULL, closures, NULL, MODULE_PERSISTENT)) {
-                               C->error(PSI_WARNING, "Failed to register functions!");
-                       }
-               }
-               PSI_ValidatorDtor(&V);
+       if (PSI_ContextCompile(C) && SUCCESS != zend_register_functions(NULL, C->closures, NULL, MODULE_PERSISTENT)) {
+               C->error(PSI_WARNING, "Failed to register functions!");
        }
+
        if (entries) {
                for (i = 0; i < n; ++i) {
                        free(entries[i]);
@@ -172,19 +656,18 @@ void PSI_ContextBuild(PSI_Context *C, const char *path)
 
 }
 
-zend_function_entry *PSI_ContextCompile(PSI_Context *C, PSI_Data *D)
+zend_function_entry *PSI_ContextCompile(PSI_Context *C)
 {
-       size_t i, count = C->count++;
-       zend_function_entry *zfe;
+       size_t i;
 
-       if (D->consts) {
+       if (C->consts) {
                zend_constant zc;
 
                zc.flags = CONST_PERSISTENT|CONST_CS;
                zc.module_number = EG(current_module)->module_number;
 
-               for (i = 0; i < D->consts->count; ++i) {
-                       constant *c = D->consts->list[i];
+               for (i = 0; i < C->consts->count; ++i) {
+                       constant *c = C->consts->list[i];
 
                        zc.name = zend_string_init(c->name + (c->name[0] == '\\'), strlen(c->name) - (c->name[0] == '\\'), 1);
                        ZVAL_NEW_STR(&zc.value, zend_string_init(c->val->text, strlen(c->val->text), 1));
@@ -204,15 +687,8 @@ zend_function_entry *PSI_ContextCompile(PSI_Context *C, PSI_Data *D)
                }
        }
 
-       C->data = realloc(C->data, C->count * sizeof(*C->data));
-       PSI_DataExchange(&C->data[count], D);
-
-       zfe = C->ops->compile(C, &C->data[count]);
 
-       C->closures = realloc(C->closures, C->count * sizeof(*C->closures));
-       C->closures[count] = zfe;
-
-       return zfe;
+       return C->closures = C->ops->compile(C);
 }
 
 void PSI_ContextDtor(PSI_Context *C)
@@ -221,15 +697,46 @@ void PSI_ContextDtor(PSI_Context *C)
 
        C->ops->dtor(C);
 
+       free_decl_libs(&C->psi.libs);
+
        for (i = 0; i < C->count; ++i) {
                PSI_DataDtor(&C->data[i]);
-               if (C->closures[i]){
-                       free(C->closures[i]);
-               }
        }
+
        free(C->data);
        free(C->closures);
 
+       if (C->consts) {
+               if (C->consts->list) {
+                       free(C->consts->list);
+               }
+               free(C->consts);
+       }
+       if (C->defs) {
+               if (C->defs->list) {
+                       free(C->defs->list);
+               }
+               free(C->defs);
+       }
+       if (C->structs) {
+               if (C->structs->list) {
+                       free(C->structs->list);
+               }
+               free(C->structs);
+       }
+       if (C->decls) {
+               if (C->decls->list) {
+                       free(C->decls->list);
+               }
+               free(C->decls);
+       }
+       if (C->impls) {
+               if (C->impls->list) {
+                       free(C->impls->list);
+               }
+               free(C->impls);
+       }
+
        memset(C, 0, sizeof(*C));
 }
 
index 24bdb9c5a8083d450c3dc5445ae812acfee84f6b..351799b46289f24a99a4180bcc192b0f612523e6 100644 (file)
@@ -13,21 +13,22 @@ typedef struct PSI_ContextOps PSI_ContextOps;
 struct PSI_ContextOps {
        void (*init)(PSI_Context *C);
        void (*dtor)(PSI_Context *C);
-       zend_function_entry *(*compile)(PSI_Context *C, PSI_Data *D);
+       zend_function_entry *(*compile)(PSI_Context *C);
 };
 
 struct PSI_Context {
+       PSI_DATA_MEMBERS;
        void *context;
-       PSI_ContextErrorFunc error;
        struct PSI_ContextOps *ops;
-       struct PSI_Data *data;
-       zend_function_entry **closures;
+       zend_function_entry *closures;
+       PSI_Data *data;
        size_t count;
 };
 
 PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error);
 void PSI_ContextBuild(PSI_Context *C, const char *path);
-zend_function_entry *PSI_ContextCompile(PSI_Context *C, PSI_Data *D);
+int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P);
+zend_function_entry *PSI_ContextCompile(PSI_Context *C);
 void PSI_ContextDtor(PSI_Context *C);
 void PSI_ContextFree(PSI_Context **C);
 
index 25456d25ce78d412ad63b2423614e80f1d86a6aa..38fa09615a0b79c63a1444802d4f4ce6341c7b6a 100644 (file)
@@ -257,23 +257,28 @@ static void psi_ffi_dtor(PSI_Context *C)
        PSI_LibffiContextFree((void *) &C->context);
 }
 
-static zend_function_entry *psi_ffi_compile(PSI_Context *C, PSI_Data *D)
+static zend_function_entry *psi_ffi_compile(PSI_Context *C)
 {
        size_t i, j = 0;
-       zend_function_entry *zfe = calloc(D->impls->count + 1, sizeof(*zfe));
+       zend_function_entry *zfe;
        PSI_LibffiContext *ctx = C->context;
 
-       for (i = 0; i < D->impls->count; ++i) {
+       if (!C->impls) {
+               return NULL;
+       }
+
+       zfe = calloc(C->impls->count + 1, sizeof(*zfe));
+       for (i = 0; i < C->impls->count; ++i) {
                zend_function_entry *zf = &zfe[j];
                PSI_LibffiData *data;
 
-               if (!D->impls->list[i]->decl) {
+               if (!C->impls->list[i]->decl) {
                        continue;
                }
 
-               data = PSI_LibffiDataAlloc(ctx, D->impls->list[i]);
-               zf->fname = D->impls->list[i]->func->name + (D->impls->list[i]->func->name[0] == '\\');
-               zf->num_args = D->impls->list[i]->func->args->count;
+               data = PSI_LibffiDataAlloc(ctx, C->impls->list[i]);
+               zf->fname = C->impls->list[i]->func->name + (C->impls->list[i]->func->name[0] == '\\');
+               zf->num_args = C->impls->list[i]->func->args->count;
                zf->handler = data->code;
                zf->arg_info = data->arginfo;
                ++j;
index 055ba1b125ece773ddb560c53c7c56f79fbd8b76..773f0e02deafc0743bdc06d09f547a6c92730bfe 100644 (file)
@@ -196,25 +196,30 @@ static void psi_jit_dtor(PSI_Context *C)
        PSI_LibjitContextFree((void *) &C->context);
 }
 
-static zend_function_entry *psi_jit_compile(PSI_Context *C, PSI_Data *D)
+static zend_function_entry *psi_jit_compile(PSI_Context *C)
 {
        size_t i, j = 0;
-       zend_function_entry *zfe = calloc(D->impls->count + 1, sizeof(*zfe));
+       zend_function_entry *zfe;
        PSI_LibjitContext *ctx = C->context;
 
+       if (!C->impls) {
+               return NULL;
+       }
+
+       zfe = calloc(C->impls->count + 1, sizeof(*zfe));
        jit_context_build_start(ctx->jit);
 
-       for (i = 0; i < D->impls->count; ++i) {
+       for (i = 0; i < C->impls->count; ++i) {
                zend_function_entry *zf = &zfe[j];
                PSI_LibjitData *data;
 
-               if (!D->impls->list[i]->decl) {
+               if (!C->impls->list[i]->decl) {
                        continue;
                }
 
-               data = PSI_LibjitDataAlloc(ctx, D->impls->list[i]);
-               zf->fname = D->impls->list[i]->func->name + (D->impls->list[i]->func->name[0] == '\\');
-               zf->num_args = D->impls->list[i]->func->args->count;
+               data = PSI_LibjitDataAlloc(ctx, C->impls->list[i]);
+               zf->fname = C->impls->list[i]->func->name + (C->impls->list[i]->func->name[0] == '\\');
+               zf->num_args = C->impls->list[i]->func->args->count;
                zf->handler = data->closure;
                zf->arg_info = data->arginfo;
                ++j;
index 628694b44840f6b4c4c54ee43389fe50fac77cf4..3b4a643e2710986b92039992a167990dee058421 100644 (file)
@@ -295,11 +295,10 @@ void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
 
 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
 {
-       size_t i, j = 0, size = decl_struct_size(s);
-       char *mem = ecalloc(1, size + s->args->count * sizeof(void *));
+       size_t i, j = 0;
+       char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
 
        if (arr) for (i = 0; i < s->args->count; ++i) {
-               decl_struct_layout *layout = &s->layout[i];
                decl_arg *darg = s->args->args[i];
                zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
 
@@ -309,9 +308,9 @@ void *psi_array_to_struct(decl_struct *s, HashTable *arr)
 
                        memset(&tmp, 0, sizeof(tmp));
                        psi_from_zval(&val, darg, entry, &tmp);
-                       memcpy(mem + layout->pos, &val, layout->len);
+                       memcpy(mem + darg->layout->pos, &val, darg->layout->len);
                        if (tmp) {
-                               ((void **)(mem + size))[j++] = tmp;
+                               ((void **)(mem + s->size))[j++] = tmp;
                        }
                }
        }
@@ -333,13 +332,12 @@ void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, decl_var *va
                ZEND_ASSERT(s);
                for (i = 0; i < s->args->count; ++i) {
                        decl_arg *darg = s->args->args[i];
-                       decl_struct_layout layout = s->layout[i];
                        impl_val tmp;
                        zval ztmp;
-                       char *ptr = (char *) ret_val->ptr + layout.pos;
+                       char *ptr = (char *) ret_val->ptr + darg->layout->pos;
 
                        memset(&tmp, 0, sizeof(tmp));
-                       memcpy(&tmp, ptr, layout.len);
+                       memcpy(&tmp, ptr, darg->layout->len);
                        switch (real_decl_type(darg->type)->type) {
                        case PSI_T_FLOAT:
                        case PSI_T_DOUBLE:
@@ -452,8 +450,8 @@ void *psi_do_calloc(let_calloc *alloc)
        size_t size;
 
        if (type->type == PSI_T_STRUCT) {
-               /* psi_do_clean expects a NULL pointer after the struct */
-               size = decl_struct_size(type->strct) + sizeof(void *);
+               /* psi_do_clean expects at least one NULL pointer after the struct */
+               size = type->strct->size + sizeof(void *);
        } else {
                size = psi_t_size(type->type);
        }
@@ -618,8 +616,7 @@ void psi_do_clean(impl *impl)
                        decl_type *type = real_decl_type(darg->type);
 
                        if (type->type == PSI_T_STRUCT) {
-                               size_t eos = decl_struct_size(type->strct);
-                               void **ptr = (void **) ((char *) darg->let->mem + eos);
+                               void **ptr = (void **) ((char *) darg->let->mem + type->strct->size);
 
                                while (*ptr) {
                                        efree(*ptr++);
index cb069c90e80216f4540846b99a0aeaa27e1bdd10..3d2dd6fefb9bf5e7ddeca8be285cb665652a225f 100644 (file)
@@ -113,9 +113,27 @@ static inline void free_decl_var(decl_var *var) {
        free(var);
 }
 
+typedef struct decl_struct_layout {
+       size_t pos;
+       size_t len;
+} decl_struct_layout;
+
+static inline decl_struct_layout *init_decl_struct_layout(size_t pos, size_t len) {
+       decl_struct_layout *l = calloc(1, sizeof(*l));
+
+       l->pos = pos;
+       l->len = len;
+       return l;
+}
+
+static inline void free_decl_struct_layout(decl_struct_layout *l) {
+       free(l);
+}
+
 typedef struct decl_arg {
        decl_type *type;
        decl_var *var;
+       decl_struct_layout *layout;
        struct let_stmt *let;
 } decl_arg;
 
@@ -123,13 +141,15 @@ static inline decl_arg *init_decl_arg(decl_type *type, decl_var *var) {
        decl_arg *arg = calloc(1, sizeof(*arg));
        arg->type = type;
        arg->var = var;
-       arg->let = NULL;
        return arg;
 }
 
 static inline void free_decl_arg(decl_arg *arg) {
        free_decl_type(arg->type);
        free_decl_var(arg->var);
+       if (arg->layout) {
+               free_decl_struct_layout(arg->layout);
+       }
        free(arg);
 }
 
@@ -140,9 +160,11 @@ typedef struct decl_vars {
 
 static inline decl_vars *init_decl_vars(decl_var *var) {
        decl_vars *vars = calloc(1, sizeof(*vars));
-       vars->count = 1;
-       vars->vars = calloc(1, sizeof(*vars->vars));
-       vars->vars[0] = var;
+       if (var) {
+               vars->count = 1;
+               vars->vars = calloc(1, sizeof(*vars->vars));
+               vars->vars[0] = var;
+       }
        return vars;
 }
 
@@ -169,9 +191,11 @@ typedef struct decl_args {
 
 static inline decl_args *init_decl_args(decl_arg *arg) {
        decl_args *args = calloc(1, sizeof(*args));
-       args->count = 1;
-       args->args = calloc(1, sizeof(*args->args));
-       args->args[0] = arg;
+       if (arg) {
+               args->count = 1;
+               args->args = calloc(1, sizeof(*args->args));
+               args->args[0] = arg;
+       }
        return args;
 }
 
@@ -254,15 +278,10 @@ static inline void free_decls(decls *decls) {
        free(decls);
 }
 
-typedef struct decl_struct_layout {
-       size_t pos;
-       size_t len;
-} decl_struct_layout;
-
 typedef struct decl_struct {
        char *name;
        decl_args *args;
-       decl_struct_layout *layout;
+       size_t size;
 } decl_struct;
 
 static inline decl_struct *init_decl_struct(const char *name, decl_args *args) {
@@ -276,19 +295,10 @@ static inline void free_decl_struct(decl_struct *s) {
        if (s->args) {
                free_decl_args(s->args);
        }
-       if (s->layout) {
-               free(s->layout);
-       }
        free(s->name);
        free(s);
 }
 
-static inline size_t decl_struct_size(decl_struct *s) {
-       size_t c = s->args->count - 1;
-       decl_type *type = real_decl_type(s->args->args[c]->type);
-       return s->layout[c].pos + psi_t_alignment(type->type);
-}
-
 typedef struct decl_structs {
        size_t count;
        decl_struct **list;
@@ -426,13 +436,10 @@ typedef struct impl_args {
 
 static inline impl_args *init_impl_args(impl_arg *arg) {
        impl_args *args = calloc(1, sizeof(*args));
-       args->args = calloc(1, sizeof(*args->args));
        if (arg) {
                args->count = 1;
+               args->args = calloc(1, sizeof(*args->args));
                args->args[0] = arg;
-       } else {
-               args->count = 0;
-               args->args = NULL;
        }
        return args;
 }
@@ -866,22 +873,67 @@ static inline void free_constants(constants *c) {
 #define PSI_WARNING 32
 typedef void (*psi_error_cb)(int type, const char *msg, ...);
 
+typedef struct decl_file {
+       char *ln;
+       char *fn;
+} decl_file;
+
+static inline void free_decl_file(decl_file *file) {
+       if (file->ln) {
+               free(file->ln);
+       }
+       if (file->fn) {
+               free(file->fn);
+       }
+       memset(file, 0, sizeof(*file));
+}
+
+typedef struct decl_libs {
+       void **dl;
+       size_t count;
+} decl_libs;
+
+static inline void free_decl_libs(decl_libs *libs) {
+       if (libs->dl) {
+               size_t i;
+               for (i = 0; i < libs->count; ++i) {
+                       if (libs->dl[i]) {
+                               dlclose(libs->dl[i]);
+                       }
+               }
+               free(libs->dl);
+       }
+       memset(libs, 0, sizeof(*libs));
+}
+
+static inline void add_decl_lib(decl_libs *libs, void *dlopened) {
+       libs->dl = realloc(libs->dl, ++libs->count * sizeof(*libs->dl));
+       libs->dl[libs->count-1] = dlopened;
+}
+
+#define PSI_DATA(D) ((PSI_Data *) (D))
 #define PSI_DATA_MEMBERS \
        constants *consts; \
        decl_typedefs *defs; \
        decl_structs *structs; \
        decls *decls; \
        impls *impls; \
-       char *lib; \
-       char *fn; \
+       union { \
+               decl_file file; \
+               decl_libs libs; \
+       } psi; \
        psi_error_cb error
 typedef struct PSI_Data {
        PSI_DATA_MEMBERS;
 } PSI_Data;
 
-static inline void PSI_DataExchange(PSI_Data *dest, PSI_Data *src) {
+static inline PSI_Data *PSI_DataExchange(PSI_Data *dest, PSI_Data *src) {
+       if (!dest) {
+               dest = malloc(sizeof(*dest));
+       }
        memcpy(dest, src, sizeof(*dest));
        memset(src, 0, sizeof(*src));
+       return dest;
 }
 
 static inline void PSI_DataDtor(PSI_Data *data) {
@@ -900,12 +952,7 @@ static inline void PSI_DataDtor(PSI_Data *data) {
        if (data->impls) {
                free_impls(data->impls);
        }
-       if (data->lib) {
-               free(data->lib);
-       }
-       if (data->fn) {
-               free(data->fn);
-       }
+       free_decl_file(&data->psi.file);
 }
 
 typedef struct PSI_Parser {
index 831b218757c108e571c646ee05a17e4682b9514d..0eae9439b88c4f6f4f5b8fda20eec78d437a672c 100644 (file)
@@ -30,8 +30,8 @@ PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename, psi_error_cb err
        }
        memset(P, 0, sizeof(*P));
 
+       P->psi.file.fn = strdup(filename);
        P->fp = fp;
-       P->fn = strdup(filename);
        P->line = 1;
        P->error = error;
        P->flags = flags;
index 2fb309ea0c983cce74587517bf28eef72d28e7a8..81a013ceecb7f2e899d31b6feece3b6b0434f3a8 100644 (file)
@@ -15,7 +15,7 @@
 %extra_argument {PSI_Parser *P}
 /* TOKEN is defined inside syntax_error */
 %syntax_error {
-       PSI_ParserSyntaxError(P, P->fn, P->line, "Unexpected token '%s'", TOKEN->text);
+       PSI_ParserSyntaxError(P, P->psi.file.fn, P->line, "Unexpected token '%s'", TOKEN->text);
 }
 
 %nonassoc NAME.
@@ -28,10 +28,10 @@ blocks ::= blocks block.
 block ::= COMMENT.
 
 block ::= LIB(T) QUOTED_STRING(libname) EOS. {
-       if (P->lib) {
-               PSI_ParserSyntaxError(P, P->fn, T->line, "Extra 'lib %s' statement has no effect", libname->text);
+       if (P->psi.file.ln) {
+               PSI_ParserSyntaxError(P, P->psi.file.ln, T->line, "Extra 'lib %s' statement has no effect", libname->text);
        } else {
-               P->lib = strndup(libname->text + 1, libname->size - 2);
+               P->psi.file.ln = strndup(libname->text + 1, libname->size - 2);
        }
        free(libname);
        free(T);
index 1583680060fd7bf54d1987ee1a2b4ae0c3ea6368..845335bf6af23e42e5e39a59690ba85520209d96 100644 (file)
@@ -20,7 +20,7 @@ const int \IDNA_ALLOW_UNASSIGNED = 1;
 const int \IDNA_USE_STD3_ASCII_RULES = 2;
 
 
-default int idna_to_ascii_8z(sint8 *host, sint8 **buffer, int flags);
+default int idna_to_ascii_8z(char *host, char **buffer, int flags);
 function idn\utf8_to_ascii(string $host, string &$result, int $flags = 0) : int {
        let buffer = &NULL;
        let host = strval($host);
@@ -29,7 +29,7 @@ function idn\utf8_to_ascii(string $host, string &$result, int $flags = 0) : int
        return to_int(idna_to_ascii_8z);
        free *buffer;
 }
-default sint8 *idna_strerror(int rc);
+default char *idna_strerror(int rc);
 function idn\strerror(int $rc) : string {
        return to_string(idna_strerror);
        let rc = intval($rc);
index 5a9b2b04f0bafca6a3a57adbbfdc973aa0281c9a..5b02dc4a5afa80f3eaf42c7c25e2c939b3cf51f2 100644 (file)
@@ -1,35 +1,3 @@
-typedef long time_t;
-typedef int suseconds_t;
-
-struct timespec {
-       time_t tv_sec;
-       long tv_nsec;
-}
-
-struct timeval {
-       time_t tv_sec;
-       suseconds_t tv_usec;
-}
-
-struct timezone {
-       int tz_minuteswest;
-       int tz_dsttime;
-}
-
-struct tm {
-       int tm_sec;
-       int tm_min;
-       int tm_hour;
-       int tm_mday;
-       int tm_mon;
-       int tm_year;
-       int tm_wday;
-       int tm_yday;
-       int tm_isdst;
-       long tm_gmtoff;
-       char *tm_zone;
-}
-
 extern int gettimeofday(struct timeval *tv, struct timezone *tz);
 function psi\gettimeofday(array &$tv = NULL, array &$tz = NULL) : int {
        let tv = calloc(1, struct timeval);