flush
authorMichael Wallner <mike@php.net>
Thu, 15 Oct 2015 14:28:26 +0000 (16:28 +0200)
committerMichael Wallner <mike@php.net>
Thu, 15 Oct 2015 14:28:26 +0000 (16:28 +0200)
config.m4
src/compiler.c
src/compiler.h
src/module.c
src/parser.re
src/parser_proc.y

index 991550584e99eef07506cf760d61c1c102323964..5be9e351fe2ae89aca8d744eb2ba76a6c7934180 100644 (file)
--- 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)
index e075a398d9ed3f9005ee4034d1639375e6af19ea..0c5fcb5e63d35a5b3675774c56b84ea617928b4b 100644 (file)
@@ -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;
+}
index c5e447fe84dbcbb57345becd9fbd33bef9790c8e..1374d39b776fa2124d44f6f89b8d0dfe157ef6cb 100644 (file)
@@ -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
index 31bd2df0441260ef79f3721fb7b32475f13c22fc..389cbc5752e123fc33cd1fab4eb8a4f7c264da80 100644 (file)
@@ -4,21 +4,36 @@
 #endif
 
 #include <jit/jit.h>
+#include <dirent.h>
+#include <fnmatch.h>
 
 #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();
index 906e8b940252ce1ad45db6a1795e4df69ef323df..31ddfe16bfcc2304f1a3a592345bc182ee439a7c 100644 (file)
@@ -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;
index 66946ca1274bfb6991e1fcf51bbf6eb24d5e1173..d99c96d482bb956966915960d6508631b621b622 100644 (file)
@@ -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. {