From: Michael Wallner Date: Thu, 15 Oct 2015 14:28:26 +0000 (+0200) Subject: flush X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=commitdiff_plain;h=7d79fea75fc664e54a5d5a2668a55f554296a845 flush --- diff --git a/config.m4 b/config.m4 index 9915505..5be9e35 100644 --- a/config.m4 +++ b/config.m4 @@ -1,4 +1,4 @@ -PHP_ARG_ENABLE(psi, whether to enable psi support, +PHP_ARG_WITH(psi, whether to enable psi support, [ --with-psi[[=path to libjit]] Enable PHP System Interface support]) @@ -21,6 +21,10 @@ if test "$PHP_PSI" != "no"; then AC_MSG_ERROR([Could not find libjit, please provide the base install path]) fi + PHP_ADD_INCLUDE($PSI_cv_LIBJIT_DIR/include) + PHP_ADD_LIBRARY_WITH_PATH(jit, $PSI_cv_LIBJIT_DIR/$PHP_LIBDIR, PSI_SHARED_LIBADD) + PHP_SUBST(PSI_SHARED_LIBADD) + PHP_PSI_SRCDIR=PHP_EXT_SRCDIR(psi) PHP_PSI_BUILDDIR=PHP_EXT_BUILDDIR(psi) @@ -29,7 +33,7 @@ if test "$PHP_PSI" != "no"; then PHP_PSI_HEADERS=`(cd $PHP_PSI_SRCDIR/src && echo *.h)` PHP_PSI_SOURCES=`(cd $PHP_PSI_SRCDIR && echo src/*.c)` - PHP_PSI_SOURCES="src/parser.c src/parser_proc.c" + PHP_PSI_SOURCES=`(echo $PHP_PSI_SOURCES src/parser.c src/parser_proc.c | xargs -n1 | sort | uniq)` PHP_NEW_EXTENSION(psi, $PHP_PSI_SOURCES, $ext_shared) PHP_INSTALL_HEADERS(ext/psi, php_psi.h $PHP_PSI_HEADERS) diff --git a/src/compiler.c b/src/compiler.c index e075a39..0c5fcb5 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -7,7 +7,7 @@ #include "compiler.h" -PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V) +PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V, void *context) { if (!C) { C = malloc(sizeof(*C)); @@ -15,13 +15,26 @@ PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V) memset(C, 0, sizeof(*C)); PSI_DataExchange((PSI_Data *) C, (PSI_Data *) V); + + C->context = context; + return C; } typedef struct PSI_ClosureData { + void *context; impl *impl; } PSI_ClosureData; +static inline PSI_ClosureData *PSI_ClosureDataAlloc(void *context, impl *impl) { + PSI_ClosureData *data = malloc(sizeof(*data)); + + data->context = context; + data->impl = impl; + + return data; +} + static inline size_t impl_num_min_args(impl *impl) { size_t i, n = impl->func->args->count; @@ -32,7 +45,8 @@ static inline size_t impl_num_min_args(impl *impl) { } return n; } -void PSI_Closure(jit_type_t signature, void *result, void **args, void *user_data) + +void jit_closure_handler(jit_type_t signature, void *result, void **args, void *user_data) { zend_execute_data *execute_data = args[0]; zval *return_value = args[1]; @@ -79,3 +93,30 @@ void PSI_Closure(jit_type_t signature, void *result, void **args, void *user_dat goto nextarg; ZEND_PARSE_PARAMETERS_END(); } + +zend_function_entry *PSI_CompilerCompile(PSI_Compiler *C) +{ + size_t i, j = 0; + jit_type_t signature, params[] = { + jit_type_void_ptr, + jit_type_void_ptr + }; + zend_function_entry *zfe = calloc(C->impls->count + 1, sizeof(*zfe)); + + for (i = 0; i < C->impls->count; ++i) { + zend_function_entry *zf; + PSI_ClosureData *data; + + if (!C->impls->list[i]->decl) { + continue; + } + signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void, params, 2, 1); + + zf = &zfe[++j]; + data = PSI_ClosureDataAlloc(C->context, C->impls->list[i]); + zf->fname = C->impls->list[i]->func->name; + zf->handler = jit_closure_create(C->context, signature, jit_closure_handler, data); + } + + return zfe; +} diff --git a/src/compiler.h b/src/compiler.h index c5e447f..1374d39 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -9,8 +9,12 @@ typedef struct PSI_Compiler { impls *impls; char *lib; char *fn; + void *context; } PSI_Compiler; -PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V); +PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V, void *context); +void PSI_CompilerDtor(PSI_Compiler *C); +void PSI_CompilerFree(PSI_Compiler **C); +zend_function_entry *PSI_CompilerCompile(PSI_Compiler *C); #endif diff --git a/src/module.c b/src/module.c index 31bd2df..389cbc5 100644 --- a/src/module.c +++ b/src/module.c @@ -4,21 +4,36 @@ #endif #include +#include +#include #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" +#include "php_scandir.h" + #include "php_psi.h" +#include "parser.h" +#include "validator.h" +#include "compiler.h" + ZEND_DECLARE_MODULE_GLOBALS(psi); PHP_INI_BEGIN() - STD_PHP_INI_ENTRY("psi.directory", "psis", PHP_INI_ALL, OnUpdateString, directory, zend_psi_globals, psi_globals) + STD_PHP_INI_ENTRY("psi.directory", "psis", PHP_INI_ALL, OnUpdateString, directory, zend_psi_globals, psi_globals) PHP_INI_END(); +static int psi_select_dirent(const struct dirent *entry) +{ + return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD); +} + PHP_MINIT_FUNCTION(psi) { jit_context_t ctx; + int i, n; + struct dirent **entries = NULL; REGISTER_INI_ENTRIES(); @@ -31,12 +46,62 @@ PHP_MINIT_FUNCTION(psi) PSI_G(context) = ctx; + n = php_scandir(PSI_G(directory), &entries, psi_select_dirent, alphasort); + if (n < 0) { + php_error(E_WARNING, "Failed to scan PSI directory '%s'", PSI_G(directory)); + } else for (i = 0; i < n; ++i) { + char psi[MAXPATHLEN]; + PSI_Parser P; + PSI_Validator V; + + if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", PSI_G(directory), entries[i]->d_name)) { + php_error(E_WARNING, "Path to PSI file too long: %s/%s", + PSI_G(directory), entries[i]->d_name); + } + if (!PSI_ParserInit(&P, psi, 0)) { + php_error(E_WARNING, "Failed to init PSI parser (%s): %s", + psi, strerror(errno)); + continue; + } + + while (-1 != PSI_ParserScan(&P)) { + PSI_ParserParse(&P, PSI_TokenAlloc(&P)); + }; + PSI_ParserParse(&P, NULL); + + if (!PSI_ValidatorInit(&V, &P)) { + php_error(E_WARNING, "Failed to init PSI validator"); + break; + } + PSI_ParserDtor(&P); + + if (PSI_ValidatorValidate(&V)) { + PSI_Compiler C; + + jit_context_build_start(ctx); + if (PSI_CompilerInit(&C, &V, ctx)) { + zend_function_entry *closures = PSI_CompilerCompile(&C); + + if (closures) { + zend_register_functions(NULL, closures, NULL, MODULE_PERSISTENT); + } + PSI_CompilerDtor(&C); + } + jit_context_build_end(ctx); + } + PSI_ValidatorDtor(&V); + } + if (entries) { + for (i = 0; i < n; ++i) { + free(entries[i]); + } + free(entries); + } return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(psi) { jit_context_t ctx = PSI_G(context); - jit_context_destroy(ctx); UNREGISTER_INI_ENTRIES(); diff --git a/src/parser.re b/src/parser.re index 906e8b9..31ddfe1 100644 --- a/src/parser.re +++ b/src/parser.re @@ -262,6 +262,7 @@ token_t PSI_ParserScan(PSI_Parser *P) NAME {RETURN(PSI_T_NAME);} NSNAME {RETURN(PSI_T_NSNAME);} QUOTED_STRING {RETURN(PSI_T_QUOTED_STRING);} + [^] {break;} */ } return -1; diff --git a/src/parser_proc.y b/src/parser_proc.y index 66946ca..d99c96d 100644 --- a/src/parser_proc.y +++ b/src/parser_proc.y @@ -83,6 +83,7 @@ decl_arg(arg) ::= decl_type(type) decl_var(var). { } %type decl_args {decl_args*} +decl_args ::= VOID. decl_args(args) ::= decl_arg(arg). { args = init_decl_args(arg); } @@ -286,6 +287,10 @@ set_func(func) ::= TO_BOOL(T). { func = init_set_func(T->type, T->text); free(T); } +set_func(func) ::= VOID(T). { + func = init_set_func(T->type, T->text); + free(T); +} %type ret_stmt {ret_stmt*} ret_stmt(ret) ::= RET set_func(func) LPAREN decl_var(var) RPAREN EOS. {