-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])
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)
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)
#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));
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;
}
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];
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;
+}
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
#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();
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();
NAME {RETURN(PSI_T_NAME);}
NSNAME {RETURN(PSI_T_NSNAME);}
QUOTED_STRING {RETURN(PSI_T_QUOTED_STRING);}
+ [^] {break;}
*/
}
return -1;
}
%type decl_args {decl_args*}
+decl_args ::= VOID.
decl_args(args) ::= decl_arg(arg). {
args = init_decl_args(arg);
}
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. {