-* move numbers to the lexer
* avoid allocs inside structures by reallocating the whole structure
* let the various list types be hashtables where appropriate
* check out jit-dynamic
* fix arginfo with nullable types
* pemalloc
-* unions
-* callbacks and function pointers
-* let impl_Var point to impl_arg, just like decl_var?
\ No newline at end of file
+* CPP style #if(def(ined)) support in parser.re with a HashTable
+* think about a better system for EXTVARs, separate \set and \get functions are clunky
\ No newline at end of file
])
PSI_DECL(int raise, [(int sig)])
- PSI_DECL(int sigaction, [(int sig, const struct sigaction *act, struct sigaction *oact)])
+ PSI_DECL(int sigaction, [(int sig, struct sigaction *act, struct sigaction *oact)])
PSI_DECL(int sigaddset, [(sigset_t * set, int signum)])
PSI_DECL(int sigaltstack, [(const stack_t *ss, stack_t *oss)])
PSI_DECL(int sigdelset, [(sigset_t *set, int signum)])
PSI_CHECK_UNISTD() {
PSI_CONFIG_POSIX(unistd, unistd.h)
-
+
PSI_CONST(F_LOCK, int)
PSI_CONST(F_TEST, int)
PSI_CONST(F_TLOCK, int)
PSI_CONST(_XOPEN_UNIX, int)
PSI_CONST(_XOPEN_UUCP, int)
PSI_CONST(_XOPEN_VERSION, int)
-
+
PSI_EXTVAR(char *optarg)
PSI_EXTVAR(int opterr)
PSI_EXTVAR(int optind)
PSI_EXTVAR(int optopt)
-
+ PSI_EXTVAR(int optreset)
+
PSI_DECL(int access, [(const char *path, int amode)])
PSI_DECL(unsigned alarm, [(unsigned seconds)])
PSI_DECL(int chdir, [(const char *path)])
PSI_DECL(ssize_t write, [(int fildes, const void *buf, size_t nbyte)])
-}
\ No newline at end of file
+}
AC_DEFUN(PSI_CONFIG_DONE, [
cat >$PSI_STDINC <<EOF
/* generated by configure */
-#ifndef _PSI_STDINC
-# define _PSI_STDINC
+#ifndef PSI_STDINC_H
+#define PSI_STDINC_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else
+# include "php_config.h"
+#endif
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#ifndef _REENTRANT
+# define _REENTRANT
+#endif
+
PSI_INCLUDES
#endif
EOF
# define _REENTRANT
#endif
AC_INCLUDES_DEFAULT()
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# ifndef HAVE__BOOL
+# ifdef __cplusplus
+typedef bool _Bool;
+# else
+# define _Bool signed char
+# endif
+# endif
+# define bool _Bool
+# define false 0
+# define true 1
+# define __bool_true_false_are_defined 1
+#endif
#ifdef HAVE_ERRNO_H
# include <errno.h>
#endif
PHP_EVAL_INCLINE(`$PKG_CONFIG --cflags libffi`)
PHP_EVAL_LIBLINE(`$PKG_CONFIG --libs libffi`, PSI_SHARED_LIBADD)
AC_DEFINE(HAVE_LIBFFI, 1, Have libffi)
+ AC_DEFINE_UNQUOTED([PHP_PSI_LIBFFI_VERSION], ["`$PKG_CONFIG --modversion libffi`"], [libffi version])
else
AC_CACHE_CHECK(for libffi, psi_cv_libffi_dir, [
for psi_cv_libffi_dir in $PHP_PSI_LIBFFI {/usr{,/local},/opt}{,/libffi}
# Add a pre-defined type to $PSI_TYPES.
psi_add_type() {
cat >>$PSI_TYPES <<EOF
- $1,
+ $1,
EOF
}
psi_add_stdtype() {
cat >>$PSI_STDTYPES <<EOF
- $1,
+ $1,
EOF
}
psi_type_pair() {
local psi_type_name=`printf "%s" "$1" | tr -cd A-Za-z0-9_`
local psi_type_lower=`printf "%s" "$1" | tr A-Z a-z`
+ while expr "$psi_type_lower" : const >/dev/null; do
+ psi_type_lower=`printf "%s" "$psi_type_lower" | cut -d " " -f2-`
+ done
case $psi_type_lower in
int*|uint*)
local psi_type_upper=`printf "%s" "$psi_type_name" | tr a-z A-Z`
dnl PSI_TYPE(type name, basic type)
dnl Check for a specific type, optionally referring to a basic type.
dnl Calls AC_TYPE_<TYPE> (if defined) and PSI_CHECK_SIZEOF.
-dnl If the basic type is just specified as "int" (in contrast to "sint" or
+dnl If the basic type is just specified as "int" (in contrast to "sint" or
dnl "uint"), AX_CHECK_SIGN is used to discover signedness of the type.
dnl Defines a pre-defined type in $PSI_TYPES.
AC_DEFUN(PSI_TYPE, [
PSI_CHECK_SIZEOF($1)
if PSI_SH_TEST_SIZEOF($1); then
m4_case([$1],
+ [bool],[psi_add_stdtype "{PSI_T_BOOL, \"bool\", NULL}"],
[float],[psi_add_stdtype "{PSI_T_FLOAT, \"float\", NULL}"],
[double],[psi_add_stdtype "{PSI_T_DOUBLE, \"double\", NULL}"],
[long double],[psi_add_stdtype "{PSI_T_LONG_DOUBLE, \"long double\", NULL}"],
[PSI_T_NAME, \"m4_bregexp([$1], [^\(\w+ \)*\w+], [\&])\"])])
dnl PSI_CHECK_STD_TYPES()
-dnl Checks for standard ANSI-C and stdint types.
+dnl Checks for standard ANSI-C, stdint and stdbool types.
AC_DEFUN(PSI_CHECK_STD_TYPES, [
AC_CHECK_HEADERS(stdint.h)
+ AC_HEADER_STDBOOL
AC_TYPE_INT8_T
PSI_CHECK_SIZEOF(int8_t)
AC_TYPE_UINT64_T
PSI_CHECK_SIZEOF(uint64_t)
AC_CHECK_ALIGNOF(uint64_t)
-
+
PSI_CHECK_SIZEOF(void *)
AC_CHECK_ALIGNOF(void *)
PSI_STDTYPE(long double)
AC_CHECK_ALIGNOF(long double)
+ PSI_STDTYPE(bool)
+ AC_CHECK_ALIGNOF(bool, PSI_INCLUDES)
+
PSI_STDTYPE(char, int)
AC_CHECK_ALIGNOF(char)
PSI_STDTYPE(signed char, int)
PSI_STDTYPE(signed long long int, int)
PSI_STDTYPE(unsigned long long, uint)
PSI_STDTYPE(unsigned long long int, uint)
- dnl this must come after the check fo "unsigned long long int"; autoconf, wth?
+ dnl this must come after the check for "unsigned long long int"; autoconf, wth?
PSI_STDTYPE(long long int, int)
])
<file role="src" name="let_func.h"/>
<file role="src" name="let_stmt.c"/>
<file role="src" name="let_stmt.h"/>
- <file role="src" name="let_val.c"/>
- <file role="src" name="let_val.h"/>
+ <file role="src" name="let_exp.c"/>
+ <file role="src" name="let_exp.h"/>
<file role="src" name="let_vals.c"/>
<file role="src" name="let_vals.h"/>
<file role="src" name="num_exp.c"/>
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
#ifndef PHP_PSI_H
#define PHP_PSI_H
#include "TSRM.h"
#endif
-#include "context.h"
-
static inline int psi_check_env(const char *var) {
char *set = getenv(var);
return (set && *set && '0' != *set);
typedef struct psi_object {
void *data;
+ void (*dtor)(void *data);
size_t size;
zend_object std;
} psi_object;
return (void *) (((char *) zo) - zo->handlers->offset);
}
+PHP_PSI_API zend_object *psi_object_init(zend_class_entry *ce);
+PHP_PSI_API zend_object *psi_object_init_ex(zend_class_entry *ce, void *data, void (*dtor)(void *));
PHP_PSI_API zend_class_entry *psi_object_get_class_entry();
ZEND_BEGIN_MODULE_GLOBALS(psi)
char *engine;
char *directory;
- struct psi_context context;
+ struct psi_context *context;
ZEND_END_MODULE_GLOBALS(psi);
ZEND_EXTERN_MODULE_GLOBALS(psi);
let _v = intval($value);
return void(opterr_set);
}
-function psi\optind() : int {
- return to_int(optind);
+function psi\optind\get() : int {
+ return to_int(optind_get);
+}
+function psi\optind\set(int $v) : void {
+ let _v = intval($v);
+ return void(optind_set);
}
function psi\optopt() : int {
return to_int(optopt);
function psi\optarg() : string {
return to_string(optarg);
}
-
-function psi\getopt(array &$argv, string $options) : int {
+/* OSX
+function psi\optreset() : void {
+ let _v = 1;
+ return void(optreset_set);
+}
+*/
+static function psi\getopt(array &$argv, string $options) : int {
let argc = count($argv);
let argv = &arrval($argv,
*argv = strval($argv)
);
let optstring = strval($options);
- return to_int(getopt);
- set $argv = to_array(argv,
- to_string(argv)
+ return to_int(getopt);
+ set $argv = to_array(
+ *argv,
+ argc,
+ to_string(*argv)
);
}
to_string(epath),
to_int(eerrno)
));
- let buf = &arrval($glob);
+ let buf = &arrval($glob,
+ intval($gl_matchc),
+ intval($gl_pathc),
+ intval($gl_offs),
+ intval($gl_flags),
+ &arrval($gl_pathv,
+ strval($gl_pathv)
+ )
+ );
return to_int(glob);
set $glob = to_array(*buf,
to_int(gl_matchc),
to_int(gl_pathc),
to_int(gl_offs),
to_int(gl_flags),
- to_array(gl_pathv, gl_pathc + gl_offs, to_string(gl_pathv))
+ to_array(*gl_pathv, gl_pathc + gl_offs, to_string(*gl_pathv))
);
free globfree(buf);
}
}
// extern int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
-function psi\getaddrinfo(string $node, string $service, array $hints, object &$res = NULL) : int {
+function psi\getaddrinfo(string $node, string $service, array $hints = NULL, object &$res = NULL) : int {
let node = strval($node);
let service = strval($service);
- let hints = &arrval($hints);
+ let hints = &arrval($hints,
+ intval($ai_flags),
+ intval($ai_family),
+ intval($ai_socktype),
+ intval($ai_protocol)
+ );
let res = &NULL;
return to_int(getaddrinfo);
set $res = to_array(**res,
}
// extern char *asctime(struct tm *tm);
-function psi\asctime(array $tm = NULL) : string {
- let tm = &arrval($tm);
+function psi\asctime(array $tm) : string {
+ let tm = &arrval($tm,
+ intval($tm_sec),
+ intval($tm_min),
+ intval($tm_hour),
+ intval($tm_mday),
+ intval($tm_mon),
+ intval($tm_year),
+ intval($tm_wday),
+ intval($tm_yday),
+ intval($tm_isdst)
+ );
return to_string(asctime);
}
// extern char *asctime_r(struct tm *tm, char *buf);
-function psi\asctime_r(array $tm = NULL) : string {
- let tm = &arrval($tm);
+function psi\asctime_r(array $tm) : string {
+ let tm = &arrval($tm,
+ intval($tm_sec),
+ intval($tm_min),
+ intval($tm_hour),
+ intval($tm_mday),
+ intval($tm_mon),
+ intval($tm_year),
+ intval($tm_wday),
+ intval($tm_yday),
+ intval($tm_isdst)
+ );
let buf = calloc(32, psi\SIZEOF_CHAR);
return to_string(asctime_r);
}
// extern int nanosleep(struct timespec *rqts, struct timespec *rmts);
function psi\nanosleep(array $rq = NULL, array &$rm = NULL) : int {
- let rqts = &arrval($rq);
+ let rqts = &arrval($rq,
+ intval($tv_sec),
+ intval($tv_nsec)
+ );
let rmts = calloc(1, psi\SIZEOF_STRUCT_TIMESPEC);
return to_int(nanosleep);
set $rm = to_array(*rmts,
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
-#include "php.h"
-#include "php_psi.h"
-#include "parser.h"
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+
+#include "token.h"
#include "calc.h"
-static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *strct, impl_val *res) {
- impl_val *ref, *tmp = NULL;
-
- switch (exp->t) {
- case PSI_T_NUMBER:
- switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) res, (double *) res, 0)) {
- case IS_LONG:
- return PSI_T_INT64;
- case IS_DOUBLE:
- return PSI_T_DOUBLE;
- }
- break;
-
- case PSI_T_NSNAME:
- switch (exp->u.cnst->type->type) {
- case PSI_T_INT:
- res->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval;
- return PSI_T_INT64;
- case PSI_T_FLOAT:
- res->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval;
- return PSI_T_DOUBLE;
- default:
- return 0;
- }
- break;
-
- case PSI_T_ENUM:
- return psi_calc_num_exp(exp->u.enm->num ?: &exp->u.enm->inc, NULL, res);
- break;
-
- case PSI_T_NAME:
- if (strct) {
- ref = struct_member_ref(exp->u.dvar->arg, strct, &tmp);
- } else {
- ref = exp->u.dvar->arg->let;
- }
- switch (real_decl_type(exp->u.dvar->arg->type)->type) {
- case PSI_T_INT8:
- case PSI_T_UINT8:
- case PSI_T_INT16:
- case PSI_T_UINT16:
- case PSI_T_INT32:
- case PSI_T_UINT32:
- case PSI_T_INT64:
- case PSI_T_UINT64:
- memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
- if (tmp) {
- free(tmp);
- }
- return real_decl_type(exp->u.dvar->arg->type)->type;
-
- case PSI_T_FLOAT:
- case PSI_T_DOUBLE:
- memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
- if (tmp) {
- free(tmp);
- }
- return real_decl_type(exp->u.dvar->arg->type)->type;
-
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- break;
-
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- return 0;
-}
-
-int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) {
- impl_val num = {0};
- int num_type = psi_calc_num_exp_value(exp, strct, &num);
-
- if (exp->operand) {
- impl_val tmp = {0};
- int tmp_type = psi_calc_num_exp(exp->operand, strct, &tmp);
-
- return exp->calculator(num_type, &num, tmp_type, &tmp, res);
- }
-
- memcpy(res, &num, sizeof(*res));
- return num_type;
-}
-
#define PRIfval "f"
#define PRIdval "lf"
#define PRIldval "Lf"
} while(0)
#ifdef HAVE_LONG_DOUBLE
-#define PSI_CALC_NO_LD
-#define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
-#define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
-#define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
+# define PSI_CALC_NO_LD
+# define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
+# define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
+# define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
#else
-#define PSI_CALC_NO_LD abort()
-#define PSI_CALC_OP_LD PSI_CALC_NO_LD
-#define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
-#define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
+# define PSI_CALC_NO_LD abort()
+# define PSI_CALC_OP_LD PSI_CALC_NO_LD
+# define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
+# define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
#endif
-#define PSI_CALC_FN(op) int psi_calc_##op(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res) \
+#define PSI_CALC_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
{ \
if (t1 == t2) { \
switch (t1) { \
-#ifndef _PSI_CALC_H
-#define _PSI_CALC_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
-#include "num_exp.h"
-#include "impl_val.h"
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
-int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res);
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
-static inline zend_long psi_long_num_exp(num_exp *exp, impl_val *strct) {
- impl_val val = {0};
+#ifndef PSI_CALC_H
+#define PSI_CALC_H
- switch (psi_calc_num_exp(exp, strct, &val)) {
- case PSI_T_UINT8: return val.u8;
- case PSI_T_UINT16: return val.u16;
- case PSI_T_UINT32: return val.u32;
- case PSI_T_UINT64: return val.u64; /* FIXME */
- case PSI_T_INT8: return val.i8;
- case PSI_T_INT16: return val.i16;
- case PSI_T_INT32: return val.i32;
- case PSI_T_INT64: return val.i64;
- case PSI_T_FLOAT: return val.fval;
- case PSI_T_DOUBLE: return val.dval;
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- return 0;
-}
+#include "token.h"
+#include "impl_val.h"
-int psi_calc_add(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res);
-int psi_calc_sub(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res);
-int psi_calc_mul(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res);
-int psi_calc_div(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res);
+token_t psi_calc_add(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_sub(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_mul(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_div(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
#endif
--- /dev/null
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include "context.h"
+#include "data.h"
+#include "call.h"
+
+#include "php.h"
+#include "zend_exceptions.h"
+
+struct psi_call_frame_argument *psi_call_frame_argument_init(struct psi_impl_arg *spec,
+ impl_val *ival, zval *zptr, int is_vararg) {
+ struct psi_call_frame_argument *frame_arg = ecalloc(1, sizeof(*frame_arg));
+
+
+ if ((frame_arg->zval_ptr = zptr)) {
+ ZVAL_DEREF(frame_arg->zval_ptr);
+
+ /* use userland type if the declared type of the vararg is mixed */
+ if (is_vararg) {
+ if (spec->type->type == PSI_T_MIXED) {
+ switch (Z_TYPE_P(zptr)) {
+ case IS_TRUE:
+ frame_arg->va_type = PSI_T_BOOL;
+ ival->zend.bval = 1;
+ break;
+ case IS_FALSE:
+ frame_arg->va_type = PSI_T_BOOL;
+ ival->zend.bval = 0;
+ break;
+ case IS_LONG:
+ frame_arg->va_type = PSI_T_INT;
+ ival->zend.lval = Z_LVAL_P(zptr);
+ break;
+ case IS_DOUBLE:
+ frame_arg->va_type = PSI_T_FLOAT;
+ ival->dval = Z_DVAL_P(zptr);
+ break;
+ default:
+ frame_arg->va_type = PSI_T_STRING;
+ ival->zend.str = zval_get_string(zptr);
+ break;
+ }
+ } else {
+ frame_arg->va_type = spec->type->type;
+ }
+ }
+ }
+
+ frame_arg->ival = *ival;
+ frame_arg->ival_ptr = &frame_arg->ival;
+ frame_arg->spec = spec;
+
+ return frame_arg;
+}
+
+void psi_call_frame_argument_free(struct psi_call_frame_argument *arg) {
+ switch (arg->spec->type->type) {
+ case PSI_T_STRING:
+ if (arg->ival.zend.str) {
+ zend_string_release(arg->ival.zend.str);
+ }
+ break;
+ case PSI_T_CALLABLE:
+ if (arg->ival.zend.cb) {
+ if (arg->ival.zend.cb->fci.size) {
+ zend_fcall_info_args_clear(&arg->ival.zend.cb->fci, 1);
+ }
+ efree(arg->ival.zend.cb);
+ }
+ break;
+ default:
+ break;
+ }
+ if (arg->ival_ptr && arg->ival_ptr != &arg->temp_val && arg->ival_ptr != &arg->ival) {
+ efree(arg->ival_ptr);
+ }
+ efree(arg);
+}
+
+struct psi_call_frame_symbol *psi_call_frame_symbol_init(struct psi_decl_var *dvar) {
+ struct psi_call_frame_symbol *frame_sym;
+ size_t size = psi_decl_type_get_size(dvar->arg->type, NULL);
+
+ frame_sym = ecalloc(1, sizeof(*frame_sym) + size);
+ frame_sym->ptr = frame_sym->ival_ptr = &frame_sym->temp_val;
+
+ return frame_sym;
+}
+
+void psi_call_frame_symbol_free(struct psi_call_frame_symbol *sym) {
+ efree(sym);
+}
+
+static void psi_call_frame_free_argument(zval *zptr) {
+ psi_call_frame_argument_free(Z_PTR_P(zptr));
+}
+
+static void psi_call_frame_free_symbol(zval *zptr) {
+ psi_call_frame_symbol_free(Z_PTR_P(zptr));
+}
+
+struct psi_call_frame_auto_free {
+ void *data;
+ void (*dtor)(void *);
+};
+
+static void psi_call_frame_free_temp(void *ptr) {
+ struct psi_call_frame_auto_free *f = ptr;
+
+ if (f->data) {
+ if (f->dtor) {
+ f->dtor(&f->data);
+ } else {
+ efree(f->data);
+ }
+ }
+}
+
+struct psi_call_frame *psi_call_frame_init(struct psi_context *C, struct psi_decl *decl, struct psi_impl *impl) {
+ struct psi_call_frame *frame = ecalloc(1, sizeof(*frame));
+
+ frame->context = C;
+ frame->decl = decl;
+ frame->impl = impl;
+
+ zend_hash_init(&frame->arguments, 8, NULL, psi_call_frame_free_argument, 0);
+ zend_hash_init(&frame->symbols, 8, NULL, psi_call_frame_free_symbol, 0);
+ zend_llist_init(&frame->temp, sizeof(struct psi_call_frame_auto_free), psi_call_frame_free_temp, 0);
+
+ return frame;
+}
+
+struct psi_call_frame_symbol *psi_call_frame_fetch_symbol(
+ struct psi_call_frame *frame, struct psi_decl_var *dvar) {
+ struct psi_call_frame_symbol *frame_sym;
+
+ frame_sym = zend_hash_str_find_ptr(&frame->symbols, dvar->fqn, strlen(dvar->fqn));
+ if (!frame_sym) {
+ frame_sym = zend_hash_str_add_ptr(&frame->symbols, dvar->fqn, strlen(dvar->fqn),
+ psi_call_frame_symbol_init(dvar));
+ }
+ return frame_sym;
+}
+
+zval *psi_call_frame_new_argument(struct psi_call_frame *frame,
+ struct psi_call_frame_argument *frame_arg) {
+ if (frame_arg->va_type) {
+ /* varargs are just appended with numeric indices */
+ return zend_hash_next_index_insert_ptr(&frame->arguments, frame_arg);
+ } else {
+ return zend_hash_str_add_ptr(&frame->arguments,
+ frame_arg->spec->var->name, strlen(frame_arg->spec->var->name),
+ frame_arg);
+ }
+}
+
+zval *psi_call_frame_sub_argument(struct psi_call_frame *frame,
+ struct psi_impl_var *inner_var, zval *outer_zval, const char *name) {
+ struct psi_call_frame_argument *iarg;
+ zval *inner_zval = zend_symtable_str_find(Z_ARRVAL_P(outer_zval),
+ &inner_var->name[1], strlen(&inner_var->name[1]));
+
+ if (!inner_zval) {
+ zval empty_zval;
+
+ ZVAL_NULL(&empty_zval);
+ inner_zval = zend_symtable_str_update(Z_ARRVAL_P(outer_zval),
+ &inner_var->name[1], strlen(&inner_var->name[1]),
+ &empty_zval);
+ }
+
+ iarg = psi_call_frame_get_argument(frame, name);
+
+ if (!iarg) {
+ struct psi_call_frame_argument *frame_arg;
+ impl_val empty_val = {0};
+ struct psi_impl_arg *carg_spec = psi_impl_arg_init(
+ psi_impl_type_init(PSI_T_MIXED, "mixed"),
+ psi_impl_var_copy(inner_var), NULL);
+
+ psi_call_frame_push_auto_ex(frame, carg_spec, (void(*)(void*)) psi_impl_arg_free);
+ frame_arg = psi_call_frame_argument_init(carg_spec, &empty_val, inner_zval, 0);
+ zend_hash_str_add_ptr(&frame->arguments, name, strlen(name), frame_arg);
+ }
+
+ return inner_zval;
+}
+
+struct psi_call_frame_argument *psi_call_frame_get_argument(
+ struct psi_call_frame *frame, const char *name) {
+ return zend_hash_str_find_ptr(&frame->arguments, name, strlen(name));
+}
+
+size_t psi_call_frame_num_var_args(struct psi_call_frame *frame) {
+ return zend_hash_next_free_element(&frame->arguments);
+}
+
+size_t psi_call_frame_num_fixed_args(struct psi_call_frame *frame) {
+ return psi_plist_count(frame->decl->args);
+}
+
+struct psi_call_frame_argument *psi_call_frame_get_var_argument(
+ struct psi_call_frame *frame, zend_long index) {
+ return zend_hash_index_find_ptr(&frame->arguments, index);
+}
+
+void **psi_call_frame_get_arg_pointers(struct psi_call_frame *frame) {
+ return frame->pointers;
+}
+
+ZEND_RESULT_CODE psi_call_frame_parse_args(struct psi_call_frame *frame,
+ zend_execute_data *execute_data) {
+ size_t i, argc = psi_plist_count(frame->impl->func->args);
+ zend_error_handling zeh;
+
+ zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
+
+ if (!argc) {
+ ZEND_RESULT_CODE rv;
+
+ rv = zend_parse_parameters_none();
+ zend_restore_error_handling(&zeh);
+ return rv;
+ }
+
+ ZEND_PARSE_PARAMETERS_START(
+ psi_impl_num_min_args(frame->impl),
+ frame->impl->func->vararg ? -1 : argc
+ )
+ nextarg: {
+
+ struct psi_impl_arg *iarg;
+ impl_val ival = {0};
+
+ if (frame->impl->func->vararg && _i >= argc) {
+ iarg = frame->impl->func->vararg;
+ Z_PARAM_OPTIONAL;
+ } else {
+ psi_plist_get(frame->impl->func->args, _i, &iarg);
+ if (iarg->def) {
+ Z_PARAM_OPTIONAL;
+ }
+ }
+
+ if (PSI_T_BOOL == iarg->type->type) {
+ Z_PARAM_BOOL(ival.zend.bval);
+ } else if (PSI_T_INT == iarg->type->type) {
+ Z_PARAM_LONG(ival.zend.lval);
+ } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
+ Z_PARAM_DOUBLE(ival.dval);
+ } else if (PSI_T_STRING == iarg->type->type) {
+ Z_PARAM_STR_EX(ival.zend.str, 1, iarg->var->reference);
+ if (ival.zend.str) {
+ zend_string_addref(ival.zend.str);
+ }
+ } else if (PSI_T_ARRAY == iarg->type->type) {
+ zval *tmp;
+ Z_PARAM_ARRAY_EX(tmp, _optional || iarg->var->reference,
+ iarg->var->reference);
+ } else if (PSI_T_OBJECT == iarg->type->type) {
+ Z_PARAM_PROLOGUE(0);
+ } else if (PSI_T_MIXED == iarg->type->type) {
+ Z_PARAM_PROLOGUE(0);
+ } else if (PSI_T_CALLABLE == iarg->type->type) {
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+
+ Z_PARAM_FUNC_EX(fci, fcc, 1, 0);
+
+ if (fci.size) {
+ ival.zend.cb = ecalloc(1, sizeof(zend_fcall));
+ ival.zend.cb->fci = fci;
+ ival.zend.cb->fcc = fcc;
+ }
+ } else {
+ error_code = ZPP_ERROR_FAILURE;
+ break;
+ }
+
+ psi_call_frame_new_argument(frame,
+ psi_call_frame_argument_init(iarg, &ival, _arg, _i > argc));
+
+ if (_i < _num_args) {
+ goto nextarg;
+ }
+ }
+ ZEND_PARSE_PARAMETERS_END_EX(
+ zend_restore_error_handling(&zeh);
+ return FAILURE;
+ );
+
+ /* set up defaults */
+ for (i = EX_NUM_ARGS(); i < argc; ++i) {
+ struct psi_impl_arg *iarg;
+
+ psi_plist_get(frame->impl->func->args, i, &iarg);
+
+ assert(iarg->def);
+ psi_call_frame_new_argument(frame, psi_call_frame_argument_init(iarg,
+ &iarg->def->ival, NULL, 0));
+ }
+
+ zend_restore_error_handling(&zeh);
+ return SUCCESS;
+}
+
+void psi_call_frame_enter(struct psi_call_frame *frame) {
+ size_t argc = psi_call_frame_num_fixed_args(frame);
+ size_t va_count = psi_call_frame_num_var_args(frame);
+ size_t rsize = psi_decl_arg_get_size(frame->decl->func);
+ struct psi_call_frame_symbol *rv_sym;
+
+ /* initialize ffi argument array */
+ frame->pointers = ecalloc(argc + va_count + 1, sizeof(void *));
+
+ /* initialize return value symbol */
+ rv_sym = psi_call_frame_fetch_symbol(frame, frame->decl->func->var);
+ if (rsize > sizeof(impl_val)) {
+ rv_sym->ival_ptr = ecalloc(1, rsize);
+ } else {
+ rv_sym->ival_ptr = &rv_sym->temp_val;
+ }
+ frame->rpointer = rv_sym->ptr = rv_sym->ival_ptr;
+}
+
+ZEND_RESULT_CODE psi_call_frame_do_let(struct psi_call_frame *frame) {
+ size_t i;
+ struct psi_let_stmt *let;
+ struct psi_decl_arg *arg;
+ size_t argc = psi_call_frame_num_fixed_args(frame);
+ size_t va_count = psi_call_frame_num_var_args(frame);
+
+ for (i = 0; psi_plist_get(frame->impl->stmts.let, i, &let); ++i) {
+ psi_let_stmt_exec(let, frame);
+ }
+ for (i = 0; psi_plist_get(frame->decl->args, i, &arg); ++i) {
+ struct psi_let_stmt *let;
+ struct psi_call_frame_symbol *frame_sym;
+
+ let = psi_impl_get_let(frame->impl, arg->var);
+ frame_sym = psi_call_frame_fetch_symbol(frame, let->exp->var);
+ frame->pointers[i] = frame_sym->ptr;
+ }
+ /* varargs */
+ if (va_count) {
+ for (i = 0; i < va_count; ++i) {
+ struct psi_call_frame_argument *frame_arg;
+ psi_marshal_let let_fn;
+ void *temp = NULL;
+
+ frame_arg = psi_call_frame_get_var_argument(frame, i);
+ switch (frame_arg->va_type) {
+ case PSI_T_BOOL: let_fn = psi_let_boolval; break;
+ case PSI_T_INT: let_fn = psi_let_intval; break;
+ case PSI_T_FLOAT:
+ case PSI_T_DOUBLE: let_fn = psi_let_floatval; break;
+ case PSI_T_STRING: let_fn = psi_let_strval; break;
+ default:
+ assert(0);
+ }
+
+ frame_arg->ival_ptr = let_fn(&frame_arg->temp_val, NULL, frame_arg->va_type,
+ &frame_arg->ival, frame_arg->zval_ptr, &temp);
+ if (temp) {
+ psi_call_frame_push_auto(frame, temp);
+ }
+
+ frame->pointers[argc + i] = frame_arg->ival_ptr;
+ }
+ }
+
+ return SUCCESS;
+}
+
+void psi_call_frame_do_call(struct psi_call_frame *frame) {
+ size_t va_count = psi_call_frame_num_var_args(frame);
+
+ if (va_count) {
+ void **va_types = ecalloc(va_count, sizeof(void *));
+ size_t i;
+
+ for (i = 0; i < va_count; ++i) {
+ struct psi_call_frame_argument *frame_arg;
+
+ frame_arg = psi_call_frame_get_var_argument(frame, i);
+ va_types[i] = frame->context->ops->query(frame->context,
+ PSI_CONTEXT_QUERY_TYPE, &frame_arg->va_type);
+ }
+
+ frame->context->ops->call_va(frame->context,
+ frame,
+ frame->decl,
+ frame->rpointer,
+ frame->pointers,
+ va_count,
+ va_types);
+
+ efree(va_types);
+ } else {
+ frame->context->ops->call(frame->context,
+ frame,
+ frame->decl,
+ frame->rpointer,
+ frame->pointers);
+ }
+}
+
+void psi_call_frame_do_callback(struct psi_call_frame *frame, struct psi_call_frame_callback *cbdata)
+{
+ size_t i;
+ void *retptr;
+ ZEND_RESULT_CODE rc;
+ struct psi_let_callback *cb = cbdata->cb->data.callback;
+ zval return_value, *zargv = ecalloc(cbdata->argc, sizeof(*zargv));
+ struct psi_call_frame_argument *frame_arg;
+
+ assert(cbdata->argc == psi_plist_count(cb->decl->args));
+
+ /* prepare args for the userland call */
+ for (i = 0; i < cbdata->argc; ++i) {
+ struct psi_set_exp *set_exp;
+ struct psi_decl_var *set_var;
+ struct psi_call_frame_symbol *set_sym;
+
+ psi_plist_get(cb->args, i, &set_exp);
+ set_var = psi_set_exp_get_decl_var(set_exp);
+ set_sym = psi_call_frame_fetch_symbol(frame, set_var);
+
+ set_sym->ptr = cbdata->argv[i];
+ psi_set_exp_exec_ex(set_exp, &zargv[i], set_sym->ptr, frame);
+ }
+
+ frame_arg = psi_call_frame_get_argument(frame, cb->func->var->fqn);
+
+ /* callback into userland */
+ ZVAL_UNDEF(&return_value);
+ zend_fcall_info_argp(&frame_arg->ival_ptr->zend.cb->fci, cbdata->argc, zargv);
+ rc = zend_fcall_info_call(&frame_arg->ival_ptr->zend.cb->fci,
+ &frame_arg->ival_ptr->zend.cb->fcc, &return_value, NULL);
+ assert(rc == SUCCESS);
+
+ /* marshal return value of the userland call */
+ frame_arg->zval_ptr = &return_value;
+ retptr = psi_let_func_exec(cbdata->cb, cb->func, cb->decl->func, frame);
+ memcpy(cbdata->rval, retptr, psi_decl_arg_get_size(cb->decl->func));
+
+ /* cleanup */
+ zend_fcall_info_args_clear(&frame_arg->ival_ptr->zend.cb->fci, 0);
+ for (i = 0; i < cbdata->argc; ++i) {
+ zval_ptr_dtor(&zargv[i]);
+ }
+ efree(zargv);
+}
+
+void psi_call_frame_do_return(struct psi_call_frame *frame, zval *return_value) {
+ struct psi_return_stmt *ret;
+
+ psi_plist_get(frame->impl->stmts.ret, 0, &ret);
+ psi_return_stmt_exec(ret, return_value, frame);
+}
+
+void psi_call_frame_do_set(struct psi_call_frame *frame) {
+ size_t i = 0;
+ struct psi_set_stmt *set;
+
+ while (psi_plist_get(frame->impl->stmts.set, i++, &set)) {
+ psi_set_stmt_exec(set, frame);
+ }
+}
+
+void psi_call_frame_do_free(struct psi_call_frame *frame) {
+ size_t i = 0;
+ struct psi_free_stmt *fre;
+
+ while (psi_plist_get(frame->impl->stmts.fre, i++, &fre)) {
+ psi_free_stmt_exec(fre, frame);
+ }
+}
+
+void **psi_call_frame_push_auto_ex(struct psi_call_frame *frame, void *auto_free, void (*dtor)(void*)) {
+ struct psi_call_frame_auto_free f;
+
+ f.data = auto_free;
+ f.dtor = dtor;
+
+ zend_llist_add_element(&frame->temp, &f);
+ return &((struct psi_call_frame_auto_free *) zend_llist_get_last(&frame->temp))->data;
+}
+
+void **psi_call_frame_push_auto(struct psi_call_frame *frame, void *auto_free) {
+ return psi_call_frame_push_auto_ex(frame, auto_free, NULL);
+}
+
+static void psi_call_frame_local_auto_dtor(void *auto_list)
+{
+ zend_llist_destroy(auto_list);
+ efree(auto_list);
+}
+
+#include "php_psi.h"
+
+void psi_call_frame_free(struct psi_call_frame *frame) {
+ zend_hash_destroy(&frame->arguments);
+ zend_hash_destroy(&frame->symbols);
+ if (frame->impl && frame->impl->func->static_memory) {
+ zend_llist *temp = emalloc(sizeof(*temp));
+ zval zlocal;
+
+ memcpy(temp, &frame->temp, sizeof(*temp));
+ ZVAL_OBJ(&zlocal, psi_object_init_ex(NULL, temp, psi_call_frame_local_auto_dtor));
+ zend_set_local_var_str(frame->impl->func->name,
+ strlen(frame->impl->func->name), &zlocal, /* force */ 1);
+ } else {
+ zend_llist_destroy(&frame->temp);
+ }
+ efree(frame->pointers);
+ efree(frame);
+}
+
+
+
--- /dev/null
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_CALL_H
+#define PSI_CALL_H
+
+#include "Zend/zend_types.h"
+
+#include "data.h"
+
+struct psi_call_frame_symbol {
+ impl_val *ival_ptr; /* marshaled */
+ void *ptr; /* possibly indirect (pointer to ival_ptr) */
+ impl_val temp_val;
+};
+
+struct psi_call_frame_argument {
+ impl_val ival; /* input */
+ impl_val temp_val; /* va */
+ impl_val *ival_ptr; /* marshaled, pointer to ival or temp_val */
+ zval *zval_ptr; /* input */
+ struct psi_impl_arg *spec;
+ token_t va_type;
+};
+
+struct psi_call_frame_callback {
+ struct psi_let_exp *cb;
+ size_t argc;
+ void **argv;
+ void *rval;
+};
+
+struct psi_call_frame_argument *psi_call_frame_argument_init(struct psi_impl_arg *spec, impl_val *ival, zval *zptr, int is_vararg);
+void psi_call_frame_argument_free(struct psi_call_frame_argument *arg);
+
+struct psi_call_frame_symbol *psi_call_frame_symbol_init();
+void psi_call_frame_symbol_free(struct psi_call_frame_symbol *arg);
+
+struct psi_call_frame {
+ struct psi_context *context;
+ struct psi_decl *decl;
+ struct psi_impl *impl;
+ HashTable arguments;
+ HashTable symbols;
+ void **pointers;
+ void *rpointer;
+ zend_llist temp;
+};
+
+struct psi_call_frame *psi_call_frame_init(struct psi_context *context, struct psi_decl *decl, struct psi_impl *impl);
+
+ZEND_RESULT_CODE psi_call_frame_parse_args(struct psi_call_frame *frame, zend_execute_data *execute_data);
+
+size_t psi_call_frame_num_var_args(struct psi_call_frame *frame);
+size_t psi_call_frame_num_fixed_args(struct psi_call_frame *frame);
+
+zval *psi_call_frame_new_argument(struct psi_call_frame *frame, struct psi_call_frame_argument *frame_arg);
+zval *psi_call_frame_sub_argument(struct psi_call_frame *frame, struct psi_impl_var *inner_var, zval *outer_zval, const char *name);
+
+struct psi_call_frame_argument *psi_call_frame_get_argument(struct psi_call_frame *frame, const char *name);
+struct psi_call_frame_argument *psi_call_frame_get_var_argument(struct psi_call_frame *frame, zend_long index);
+
+struct psi_call_frame_symbol *psi_call_frame_fetch_symbol(struct psi_call_frame *frame, struct psi_decl_var *dvar);
+
+void psi_call_frame_enter(struct psi_call_frame *frame);
+
+void **psi_call_frame_get_arg_pointers(struct psi_call_frame *frame);
+
+ZEND_RESULT_CODE psi_call_frame_do_let(struct psi_call_frame *frame);
+void psi_call_frame_do_call(struct psi_call_frame *frame);
+void psi_call_frame_do_callback(struct psi_call_frame *frame, struct psi_call_frame_callback *cb);
+void psi_call_frame_do_return(struct psi_call_frame *frame, zval *return_value);
+void psi_call_frame_do_set(struct psi_call_frame *frame);
+void psi_call_frame_do_free(struct psi_call_frame *frame);
+
+void **psi_call_frame_push_auto_ex(struct psi_call_frame *frame, void *auto_free, void (*dtor)(void*));
+void **psi_call_frame_push_auto(struct psi_call_frame *frame, void *auto_free);
+
+void psi_call_frame_free(struct psi_call_frame *frame);
+
+
+#endif
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
#include "php_psi_stdinc.h"
#include "php_scandir.h"
#include "php_psi.h"
#include "calc.h"
+#include "call.h"
#include "libjit.h"
#include "libffi.h"
}
memset(C, 0, sizeof(*C));
- C->error = error;
- C->flags = flags;
+ psi_data_ctor(PSI_DATA(C), error, flags);
C->ops = ops;
if (ops->init) {
/* build up predefs in a temporary PSI_Data for validation */
memset(&T, 0, sizeof(T));
- T.error = error;
+ psi_data_ctor_with_dtors(&T, error, flags);
for (predef_type = &psi_predef_types[0]; predef_type->type_tag; ++predef_type) {
- decl_type *type = init_decl_type(predef_type->type_tag, predef_type->type_name);
- decl_var *var = init_decl_var(predef_type->alias, 0, 0); /* FIXME: indirection */
- decl_arg *def = init_decl_arg(type, var);
+ struct psi_decl_type *type = psi_decl_type_init(predef_type->type_tag, predef_type->type_name);
+ struct psi_decl_var *var = psi_decl_var_init(predef_type->alias, 0, 0); /* FIXME: indirection */
+ struct psi_decl_arg *def = psi_decl_arg_init(type, var);
- T.defs = add_decl_typedef(T.defs, def);
+ T.types = psi_plist_add(T.types, &def);
}
for (predef_const = &psi_predef_consts[0]; predef_const->type_tag; ++predef_const) {
- impl_def_val *val = init_impl_def_val(predef_const->val_type_tag, predef_const->val_text);
- const_type *type = init_const_type(predef_const->type_tag, predef_const->type_name);
- constant *constant = init_constant(type, predef_const->var_name, val);
+ struct psi_impl_def_val *val = psi_impl_def_val_init(predef_const->val_type_tag, predef_const->val_text);
+ struct psi_const_type *type = psi_const_type_init(predef_const->type_tag, predef_const->type_name);
+ struct psi_const *constant = psi_const_init(type, predef_const->var_name, val);
- T.consts = add_constant(T.consts, constant);
+ T.consts = psi_plist_add(T.consts, &constant);
}
for (predef_struct = &psi_predef_structs[0]; predef_struct->type_tag; ++predef_struct) {
struct psi_predef_struct *member;
- decl_args *dargs = init_decl_args(NULL);
- decl_struct *dstruct = init_decl_struct(predef_struct->var_name, dargs);
+ struct psi_plist *dargs = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+ struct psi_decl_struct *dstruct = psi_decl_struct_init(predef_struct->var_name, dargs);
dstruct->size = predef_struct->size;
dstruct->align = predef_struct->offset;
for (member = &predef_struct[1]; member->type_tag; ++member) {
- decl_type *type;
- decl_var *dvar;
- decl_arg *darg;
-
- type = init_decl_type(member->type_tag, member->type_name);
- dvar = init_decl_var(member->var_name, member->pointer_level, member->array_size);
- darg = init_decl_arg(type, dvar);
- darg->layout = init_decl_struct_layout(member->offset, member->size);
- dargs = add_decl_arg(dargs, darg);
+ struct psi_decl_type *type;
+ struct psi_decl_var *dvar;
+ struct psi_decl_arg *darg;
+
+ type = psi_decl_type_init(member->type_tag, member->type_name);
+ dvar = psi_decl_var_init(member->var_name, member->pointer_level, member->array_size);
+ darg = psi_decl_arg_init(type, dvar);
+ darg->layout = psi_layout_init(member->offset, member->size);
+ dstruct->args = psi_plist_add(dstruct->args, &darg);
}
- T.structs = add_decl_struct(T.structs, dstruct);
+ T.structs = psi_plist_add(T.structs, &dstruct);
predef_struct = member;
}
for (predef_union = &psi_predef_unions[0]; predef_union->type_tag; ++predef_union) {
struct psi_predef_union *member;
- decl_args *dargs = init_decl_args(NULL);
- decl_union *dunion = init_decl_union(predef_union->var_name, dargs);
+ struct psi_plist *dargs = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+ struct psi_decl_union *dunion = psi_decl_union_init(predef_union->var_name, dargs);
dunion->size = predef_union->size;
dunion->align = predef_union->offset;
for (member = &predef_union[1]; member->type_tag; ++member) {
- decl_type *type;
- decl_var *dvar;
- decl_arg *darg;
-
- type = init_decl_type(member->type_tag, member->type_name);
- dvar = init_decl_var(member->var_name, member->pointer_level, member->array_size);
- darg = init_decl_arg(type, dvar);
- darg->layout = init_decl_struct_layout(member->offset, member->size);
- dargs = add_decl_arg(dargs, darg);
+ struct psi_decl_type *type;
+ struct psi_decl_var *dvar;
+ struct psi_decl_arg *darg;
+
+ type = psi_decl_type_init(member->type_tag, member->type_name);
+ dvar = psi_decl_var_init(member->var_name, member->pointer_level, member->array_size);
+ darg = psi_decl_arg_init(type, dvar);
+ darg->layout = psi_layout_init(member->offset, member->size);
+ dunion->args = psi_plist_add(dunion->args, &darg);
}
- T.unions = add_decl_union(T.unions, dunion);
+ T.unions = psi_plist_add(T.unions, &dunion);
predef_union = member;
}
for (predef_decl = &psi_predef_decls[0]; predef_decl->type_tag; ++predef_decl) {
struct psi_predef_decl *farg;
- decl_type *ftype = init_decl_type(predef_decl->type_tag, predef_decl->type_name);
- decl_var *fname = init_decl_var(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
- decl_arg *func = init_decl_arg(ftype, fname);
- decl_args *args = init_decl_args(NULL);
- decl *decl = init_decl(init_decl_abi("default"), func, args);
+ struct psi_decl_type *ftype = psi_decl_type_init(predef_decl->type_tag, predef_decl->type_name);
+ struct psi_decl_var *fname = psi_decl_var_init(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
+ struct psi_decl_arg *func = psi_decl_arg_init(ftype, fname);
+ struct psi_plist *args = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+ struct psi_decl *decl = psi_decl_init(psi_decl_abi_init("default"), func, args);
for (farg = &predef_decl[1]; farg->type_tag; ++farg) {
- decl_type *arg_type = init_decl_type(farg->type_tag, farg->type_name);
- decl_var *arg_var = init_decl_var(farg->var_name, farg->pointer_level, farg->array_size);
- decl_arg *darg = init_decl_arg(arg_type, arg_var);
- args = add_decl_arg(args, darg);
+ struct psi_decl_type *arg_type = psi_decl_type_init(farg->type_tag, farg->type_name);
+ struct psi_decl_var *arg_var = psi_decl_var_init(farg->var_name, farg->pointer_level, farg->array_size);
+ struct psi_decl_arg *darg = psi_decl_arg_init(arg_type, arg_var);
+ decl->args = psi_plist_add(decl->args, &darg);
}
- T.decls = add_decl(T.decls, decl);
+ T.decls = psi_plist_add(T.decls, &decl);
predef_decl = farg;
}
for (predef_decl = &psi_predef_vararg_decls[0]; predef_decl->type_tag; ++predef_decl) {
struct psi_predef_decl *farg;
- decl_type *ftype = init_decl_type(predef_decl->type_tag, predef_decl->type_name);
- decl_var *fname = init_decl_var(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
- decl_arg *func = init_decl_arg(ftype, fname);
- decl_args *args = init_decl_args(NULL);
- decl *decl = init_decl(init_decl_abi("default"), func, args);
+ struct psi_decl_type *ftype = psi_decl_type_init(predef_decl->type_tag, predef_decl->type_name);
+ struct psi_decl_var *fname = psi_decl_var_init(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
+ struct psi_decl_arg *func = psi_decl_arg_init(ftype, fname);
+ struct psi_plist *args = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+ struct psi_decl *decl = psi_decl_init(psi_decl_abi_init("default"), func, args);
for (farg = &predef_decl[1]; farg->type_tag; ++farg) {
- decl_type *arg_type = init_decl_type(farg->type_tag, farg->type_name);
- decl_var *arg_var = init_decl_var(farg->var_name, farg->pointer_level, farg->array_size);
- decl_arg *darg = init_decl_arg(arg_type, arg_var);
- args = add_decl_arg(args, darg);
+ struct psi_decl_type *arg_type = psi_decl_type_init(farg->type_tag, farg->type_name);
+ struct psi_decl_var *arg_var = psi_decl_var_init(farg->var_name, farg->pointer_level, farg->array_size);
+ struct psi_decl_arg *darg = psi_decl_arg_init(arg_type, arg_var);
+ decl->args = psi_plist_add(decl->args, &darg);
}
- args->varargs = 1;
+ decl->varargs = 1;
- T.decls = add_decl(T.decls, decl);
+ T.decls = psi_plist_add(T.decls, &decl);
predef_decl = farg;
}
for (predef_decl = &psi_predef_functor_decls[0]; predef_decl->type_tag; ++predef_decl) {
struct psi_predef_decl *farg;
- decl_type *dtype, *ftype = init_decl_type(predef_decl->type_tag, predef_decl->type_name);
- decl_var *fname = init_decl_var(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
- decl_arg *tdef, *func = init_decl_arg(ftype, fname);
- decl_args *args = init_decl_args(NULL);
- decl *decl = init_decl(init_decl_abi("default"), func, args);
+ struct psi_decl_type *dtype, *ftype = psi_decl_type_init(predef_decl->type_tag, predef_decl->type_name);
+ struct psi_decl_var *fname = psi_decl_var_init(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
+ struct psi_decl_arg *tdef, *func = psi_decl_arg_init(ftype, fname);
+ struct psi_plist *args = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+ struct psi_decl *decl = psi_decl_init(psi_decl_abi_init("default"), func, args);
for (farg = &predef_decl[1]; farg->type_tag; ++farg) {
- decl_type *arg_type = init_decl_type(farg->type_tag, farg->type_name);
- decl_var *arg_var = init_decl_var(farg->var_name, farg->pointer_level, farg->array_size);
- decl_arg *darg = init_decl_arg(arg_type, arg_var);
- args = add_decl_arg(args, darg);
+ struct psi_decl_type *arg_type = psi_decl_type_init(farg->type_tag, farg->type_name);
+ struct psi_decl_var *arg_var = psi_decl_var_init(farg->var_name, farg->pointer_level, farg->array_size);
+ struct psi_decl_arg *darg = psi_decl_arg_init(arg_type, arg_var);
+ decl->args = psi_plist_add(decl->args, &darg);
}
- dtype = init_decl_type(PSI_T_FUNCTION, fname->name);
+ dtype = psi_decl_type_init(PSI_T_FUNCTION, fname->name);
dtype->real.func = decl;
- tdef = init_decl_arg(dtype, copy_decl_var(fname));
- T.defs = add_decl_typedef(T.defs, tdef);
+ tdef = psi_decl_arg_init(dtype, psi_decl_var_copy(fname));
+ T.types = psi_plist_add(T.types, &tdef);
predef_decl = farg;
}
- psi_context_validate_data(PSI_DATA(C), &T);
-
- C->count = 1;
- C->data = malloc(sizeof(*C->data));
- psi_data_exchange(C->data, &T);
+ psi_context_add_data(C, &T);
return C;
}
static int psi_select_dirent(const struct dirent *entry)
{
#ifndef FNM_CASEFOLD
-#define FNM_CASEFOLD 0
+# define FNM_CASEFOLD 0
#endif
return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD);
}
struct psi_parser P;
if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", ptr, entries[i]->d_name)) {
- C->error(C, NULL, PSI_WARNING, "Path to PSI file too long: %s/%s",
+ C->error(PSI_DATA(C), NULL, PSI_WARNING, "Path to PSI file too long: %s/%s",
ptr, entries[i]->d_name);
}
if (!psi_parser_init(&P, psi, C->error, C->flags)) {
- C->error(C, NULL, PSI_WARNING, "Failed to init PSI parser (%s): %s",
+ C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to init PSI parser (%s): %s",
psi, strerror(errno));
continue;
}
}
psi_parser_parse(&P, NULL);
- psi_context_validate(C, &P);
+ psi_context_add_data(C, PSI_DATA(&P));
psi_parser_dtor(&P);
}
}
if (psi_context_compile(C) && SUCCESS != zend_register_functions(NULL, C->closures, NULL, MODULE_PERSISTENT)) {
- C->error(C, NULL, PSI_WARNING, "Failed to register functions!");
+ C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to register functions!");
}
free(cpy);
-
}
zend_function_entry *psi_context_compile(struct psi_context *C)
{
- size_t i;
zend_constant zc;
zc.flags = CONST_PERSISTENT|CONST_CS;
zc.module_number = EG(current_module)->module_number;
if (C->consts) {
- for (i = 0; i < C->consts->count; ++i) {
- constant *c = C->consts->list[i];
+ size_t i = 0;
+ struct psi_const *c;
+ while (psi_plist_get(C->consts, i++, &c)) {
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));
}
}
if (C->enums) {
- for (i = 0; i < C->enums->count; ++i) {
- decl_enum *e = C->enums->list[i];
- size_t j;
+ size_t i = 0;
+ struct psi_decl_enum *e;
+
+ while (psi_plist_get(C->enums, i++, &e)) {
+ size_t j = 0;
+ struct psi_decl_enum_item *item;
- for (j = 0; j < e->items->count; ++j) {
- decl_enum_item *i = e->items->list[j];
- zend_string *name = strpprintf(0, "psi\\%s\\%s", e->name, i->name);
+ while (psi_plist_get(e->items, j++, &item)) {
+ zend_string *name = strpprintf(0, "psi\\%s\\%s", e->name, item->name);
zc.name = zend_string_dup(name, 1);
- ZVAL_LONG(&zc.value, psi_long_num_exp(i->num, NULL));
+ ZVAL_LONG(&zc.value, psi_long_num_exp(item->num, NULL));
zend_register_constant(&zc);
zend_string_release(name);
}
}
-void psi_context_call(struct psi_context *C, struct decl_callinfo *decl_call, struct impl_vararg *va)
+ZEND_RESULT_CODE psi_context_call(struct psi_context *C, zend_execute_data *execute_data, zval *return_value, struct psi_impl *impl)
{
- C->ops->call(C, decl_call, va);
+ struct psi_call_frame *frame;
+
+ frame = psi_call_frame_init(C, impl->decl, impl);
+
+ if (SUCCESS != psi_call_frame_parse_args(frame, execute_data)) {
+ psi_call_frame_free(frame);
+
+ return FAILURE;
+ }
+
+ psi_call_frame_enter(frame);
+
+ if (SUCCESS != psi_call_frame_do_let(frame)) {
+ psi_call_frame_do_return(frame, return_value);
+ psi_call_frame_free(frame);
+
+ return FAILURE;
+ }
+
+ psi_call_frame_do_call(frame);
+ psi_call_frame_do_return(frame, return_value);
+ psi_call_frame_do_set(frame);
+ psi_call_frame_do_free(frame);
+ psi_call_frame_free(frame);
+
+ return SUCCESS;
}
C->ops->dtor(C);
}
- free_decl_libs(&C->psi.libs);
+ psi_data_dtor(PSI_DATA(C));
if (C->data) {
for (i = 0; i < C->count; ++i) {
}
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->unions) {
- if (C->unions->list) {
- free(C->unions->list);
- }
- free(C->unions);
- }
- if (C->enums) {
- if (C->enums->list) {
- free(C->enums->list);
- }
- free(C->enums);
- }
- 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));
}
void psi_context_free(struct psi_context **C)
}
}
-int psi_context_validate(struct psi_context *C, struct psi_parser *P)
+bool psi_context_add_data(struct psi_context *C, struct psi_data *P)
{
struct psi_data *D;
- void *dlopened = NULL;
- size_t i, count = C->count++, check_round, check_count;
- decl_typedefs *check_defs = P->defs;
- decl_structs *check_structs = P->structs;
- decl_unions *check_unions = P->unions;
- decl_enums *check_enums = P->enums;
- unsigned flags = C->flags;
-
- C->data = realloc(C->data, C->count * sizeof(*C->data));
- D = psi_data_exchange(&C->data[count], PSI_DATA(P));
-
-#define REVALIDATE(what) do { \
- if (check_round && check_ ##what) { \
- free(check_ ##what->list); \
- free(check_ ##what); \
- } \
- check_ ##what = recheck_ ##what; \
-} while (0)
-#define CHECK_TOTAL (CHECK_COUNT(defs) + CHECK_COUNT(structs) + CHECK_COUNT(enums))
-#define CHECK_COUNT(of) (check_ ##of ? check_ ##of->count : 0)
-
- if (!(flags & PSI_PARSER_SILENT)) {
- /* no warnings on first round */
- C->flags |= PSI_PARSER_SILENT;
- }
- for (check_round = 0, check_count = 0; CHECK_TOTAL && check_count != CHECK_TOTAL; ++check_round) {
- decl_typedefs *recheck_defs = NULL;
- decl_structs *recheck_structs = NULL;
- decl_unions *recheck_unions = NULL;
- decl_enums *recheck_enums = NULL;
-
- check_count = CHECK_TOTAL;
-
- for (i = 0; i < CHECK_COUNT(defs); ++i) {
- if (validate_decl_typedef(PSI_DATA(C), check_defs->list[i])) {
- C->defs = add_decl_typedef(C->defs, check_defs->list[i]);
- } else {
- recheck_defs = add_decl_typedef(recheck_defs, check_defs->list[i]);
- }
- }
- for (i = 0; i < CHECK_COUNT(structs); ++i) {
- if (validate_decl_struct(PSI_DATA(C), check_structs->list[i])) {
- C->structs = add_decl_struct(C->structs, check_structs->list[i]);
- } else {
- recheck_structs = add_decl_struct(recheck_structs, check_structs->list[i]);
- }
- }
- for (i = 0; i < CHECK_COUNT(unions); ++i) {
- if (validate_decl_union(PSI_DATA(C), check_unions->list[i])) {
- C->unions = add_decl_union(C->unions, check_unions->list[i]);
- } else {
- recheck_unions = add_decl_union(recheck_unions, check_unions->list[i]);
- }
- }
- for (i = 0; i < CHECK_COUNT(enums); ++i) {
- if (validate_decl_enum(PSI_DATA(C), check_enums->list[i])) {
- C->enums = add_decl_enum(C->enums, check_enums->list[i]);
- } else {
- recheck_enums = add_decl_enum(recheck_enums, check_enums->list[i]);
- }
- }
-
- REVALIDATE(defs);
- REVALIDATE(structs);
- REVALIDATE(unions);
- REVALIDATE(enums);
-
- if (check_round == 0 && !(flags & PSI_PARSER_SILENT)) {
- C->flags ^= PSI_PARSER_SILENT;
- }
- }
-
- C->flags = flags;
-
- if (D->consts) {
- 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_file(D, &dlopened)) {
- return 0;
- }
-
- add_decl_lib(&C->psi.libs, dlopened);
-
- if (D->decls) {
- 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) {
- for (i = 0; i < D->impls->count; ++i) {
- if (validate_impl(PSI_DATA(C), D->impls->list[i])) {
- C->impls = add_impl(C->impls, D->impls->list[i]);
- }
- }
- }
-
- return 1;
-}
-
-int psi_context_validate_data(struct psi_data *dest, struct psi_data *source)
-{
- size_t i;
- int errors = 0;
-
- if (source->defs) for (i = 0; i < source->defs->count; ++i) {
- decl_arg *def = source->defs->list[i];
-
- if (validate_decl_typedef(source, def)) {
- if (dest) {
- dest->defs = add_decl_typedef(dest->defs, def);
- }
- } else {
- ++errors;
- }
- }
- if (source->consts) for (i = 0; i < source->consts->count; ++i) {
- constant *constant = source->consts->list[i];
+ C->data = realloc(C->data, (C->count + 1) * sizeof(*C->data));
+ D = psi_data_exchange(&C->data[C->count++], P);
- if (validate_constant(source, constant)) {
- if (dest) {
- dest->consts = add_constant(dest->consts, constant);
- }
- } else {
- ++errors;
- }
- }
-
- if (source->structs) for (i = 0; i < source->structs->count; ++i) {
- decl_struct *dstruct = source->structs->list[i];
-
- if (validate_decl_struct(source, dstruct)) {
- if (dest) {
- dest->structs = add_decl_struct(dest->structs, dstruct);
- }
- } else {
- ++errors;
- }
- }
-
- 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];
-
- if (validate_decl_enum(source, denum)) {
- if (dest) {
- dest->enums = add_decl_enum(dest->enums, denum);
- }
- } else {
- ++errors;
- }
- }
-
- if (source->decls) for (i = 0; i < source->decls->count; ++i) {
- decl *decl = source->decls->list[i];
-
- if (validate_decl(source, NULL, decl)) {
- if (dest) {
- dest->decls = add_decl(dest->decls, decl);
- }
- } else {
- ++errors;
- }
- }
-
- if (source->impls) for (i = 0; i < source->impls->count; ++i) {
- impl *impl = source->impls->list[i];
-
- if (validate_impl(source, impl)) {
- if (dest) {
- dest->impls = add_impl(dest->impls, impl);
- }
- } else {
- ++errors;
- }
- }
-
- return errors;
-}
-
-static inline void dump_data(int fd, struct psi_data *D) {
- if (D->psi.file.fn) {
- dprintf(fd, "// psi.filename=%s\n", D->psi.file.fn);
- if (D->psi.file.ln) {
- dprintf(fd, "lib \"%s\";\n", D->psi.file.ln);
- }
- } else {
- dprintf(fd, "// builtin predef\n");
- }
- if (D->defs) {
- dump_decl_typedefs(fd, D->defs);
- dprintf(fd, "\n");
- }
- if (D->unions) {
- dump_decl_unions(fd, D->unions);
- dprintf(fd, "\n");
- }
- if (D->structs) {
- dump_decl_structs(fd, D->structs);
- dprintf(fd, "\n");
- }
- if (D->enums) {
- dump_decl_enums(fd, D->enums);
- dprintf(fd, "\n");
- }
- if (D->consts) {
- dump_constants(fd, D->consts);
- dprintf(fd, "\n");
- }
- if (D->decls) {
- dump_decls(fd, D->decls);
- dprintf(fd, "\n");
- }
- if (D->impls) {
- dump_impls(fd, D->impls);
- dprintf(fd, "\n");
- }
+ return psi_data_validate(PSI_DATA(C), D);
}
void psi_context_dump(struct psi_context *C, int fd)
{
- size_t i;
-#ifdef HAVE_LIBJIT
- if (C->ops == psi_libjit_ops()) {
- dprintf(fd, "// psi.engine=jit\n");
- }
-#endif
-#ifdef HAVE_LIBFFI
- if (C->ops == psi_libffi_ops()) {
- dprintf(fd, "// psi.engine=ffi\n");
- }
-#endif
- dprintf(fd, "\n");
+ dprintf(fd, "// psi.engine=%s\n",
+ (char *) C->ops->query(C, PSI_CONTEXT_QUERY_SELF, NULL));
- for (i = 0; i < C->count; ++i) {
- dump_data(fd, &C->data[i]);
- }
+ psi_data_dump(fd, PSI_DATA(C));
+
+// size_t i;
+// dprintf(fd, "/* parsed\n");
+// for (i = 0; i < C->count; ++i) {
+// psi_data_dump(fd, &C->data[i]);
+// }
+// dprintf(fd, "*/\n");
}
-#ifndef _PSI_CONTEXT_H
-#define _PSI_CONTEXT_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_CONTEXT_H
+#define PSI_CONTEXT_H
+
+/* zend_function_entry */
+#include "Zend/zend_API.h"
struct psi_context;
struct psi_token;
struct psi_parser;
-struct decl_callinfo;
+struct psi_call_frame;
struct impl_vararg;
+struct psi_decl;
+struct psi_impl;
+
+enum psi_context_query {
+ PSI_CONTEXT_QUERY_SELF, /* ffi/jit */
+ PSI_CONTEXT_QUERY_TYPE, /* impl type token_t to native ffi_type/jit_type */
+};
struct psi_context_ops {
void (*init)(struct psi_context *C);
void (*dtor)(struct psi_context *C);
zend_function_entry *(*compile)(struct psi_context *C);
- void (*call)(struct psi_context *C, struct decl_callinfo *decl_call, struct impl_vararg *va);
+ void (*call)(struct psi_context *C, struct psi_call_frame *frame, struct psi_decl *psi_decl, void *rval, void **args);
+ void (*call_va)(struct psi_context *C, struct psi_call_frame *frame, struct psi_decl *psi_decl, void *rval, void **args, size_t va_count, void **va_types);
+ void *(*query)(struct psi_context *C, enum psi_context_query q, void *arg);
};
#include "data.h"
size_t count;
};
+struct psi_context_call_data {
+ struct psi_context *context;
+ union {
+ struct psi_impl *fn;
+ struct psi_let_callback *cb;
+ } impl;
+};
+
struct psi_context *psi_context_init(struct psi_context *C, struct psi_context_ops *ops, psi_error_cb error, unsigned flags);
void psi_context_build(struct psi_context *C, const char *path);
-int psi_context_validate(struct psi_context *C, struct psi_parser *P);
-int psi_context_validate_data(struct psi_data *C, struct psi_data *D);
+bool psi_context_add_data(struct psi_context *C, struct psi_data *P);
zend_function_entry *psi_context_compile(struct psi_context *C);
-void psi_context_call(struct psi_context *C, struct decl_callinfo *decl_call, struct impl_vararg *va);
+ZEND_RESULT_CODE psi_context_call(struct psi_context *C, zend_execute_data *execute_data, zval *return_value, struct psi_impl *impl);
void psi_context_dump(struct psi_context *C, int fd);
void psi_context_dtor(struct psi_context *C);
void psi_context_free(struct psi_context **C);
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
-#include <string.h>
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *******************************************************************************/
+
+#include "php_psi_stdinc.h"
#include "data.h"
-struct psi_data *psi_data_exchange(struct psi_data *dest, struct psi_data *src) {
+#include "php_globals.h"
+
+#include <dlfcn.h>
+
+struct psi_data *psi_data_ctor_with_dtors(struct psi_data *data,
+ psi_error_cb error, unsigned flags)
+{
+ if (!data) {
+ data = calloc(1, sizeof(*data));
+ }
+
+ data->error = error;
+ data->flags = flags;
+
+ if (!data->consts) {
+ data->consts = psi_plist_init((psi_plist_dtor) psi_const_free);
+ }
+ if (!data->types) {
+ data->types = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+ }
+ if (!data->structs) {
+ data->structs = psi_plist_init((psi_plist_dtor) psi_decl_struct_free);
+ }
+ if (!data->unions) {
+ data->unions = psi_plist_init((psi_plist_dtor) psi_decl_union_free);
+ }
+ if (!data->enums) {
+ data->enums = psi_plist_init((psi_plist_dtor) psi_decl_enum_free);
+ }
+ if (!data->decls) {
+ data->decls = psi_plist_init((psi_plist_dtor) psi_decl_free);
+ }
+ if (!data->impls) {
+ data->impls = psi_plist_init((psi_plist_dtor) psi_impl_free);
+ }
+ if (!data->libs) {
+ data->libs = psi_plist_init((psi_plist_dtor) psi_libs_free);
+ }
+ return data;
+}
+
+struct psi_data *psi_data_ctor(struct psi_data *data, psi_error_cb error,
+ unsigned flags)
+{
+ if (!data) {
+ data = calloc(1, sizeof(*data));
+ }
+
+ data->error = error;
+ data->flags = flags;
+
+ if (!data->consts) {
+ data->consts = psi_plist_init(NULL);
+ }
+ if (!data->types) {
+ data->types = psi_plist_init(NULL);
+ }
+ if (!data->structs) {
+ data->structs = psi_plist_init(NULL);
+ }
+ if (!data->unions) {
+ data->unions = psi_plist_init(NULL);
+ }
+ if (!data->enums) {
+ data->enums = psi_plist_init(NULL);
+ }
+ if (!data->decls) {
+ data->decls = psi_plist_init(NULL);
+ }
+ if (!data->impls) {
+ data->impls = psi_plist_init(NULL);
+ }
+ if (!data->libs) {
+ data->libs = psi_plist_init(NULL);
+ }
+ return data;
+}
+
+struct psi_data *psi_data_exchange(struct psi_data *dest, struct psi_data *src)
+{
if (!dest) {
dest = malloc(sizeof(*dest));
}
- memcpy(dest, src, sizeof(*dest));
+ *dest = *src;
memset(src, 0, sizeof(*src));
return dest;
}
-void psi_data_dtor(struct psi_data *data) {
+void psi_data_dtor(struct psi_data *data)
+{
if (data->consts) {
- free_constants(data->consts);
+ psi_plist_free(data->consts);
}
- if (data->defs) {
- free_decl_typedefs(data->defs);
+ if (data->types) {
+ psi_plist_free(data->types);
}
if (data->structs) {
- free_decl_structs(data->structs);
+ psi_plist_free(data->structs);
}
if (data->unions) {
- free_decl_unions(data->unions);
+ psi_plist_free(data->unions);
}
if (data->enums) {
- free_decl_enums(data->enums);
+ psi_plist_free(data->enums);
}
if (data->decls) {
- free_decls(data->decls);
+ psi_plist_free(data->decls);
}
if (data->impls) {
- free_impls(data->impls);
+ psi_plist_free(data->impls);
+ }
+ if (data->libs) {
+ psi_plist_free(data->libs);
+ }
+
+ psi_decl_file_dtor(&data->file);
+}
+
+void psi_data_dump(int fd, struct psi_data *D)
+{
+ if (D->file.fn) {
+ dprintf(fd, "// filename=%s (%u errors)\n", D->file.fn, D->errors);
+ if (D->file.ln) {
+ dprintf(fd, "lib \"%s\";\n", D->file.ln);
+ }
+ } else {
+ dprintf(fd, "// builtin predef\n");
+ }
+ if (psi_plist_count(D->types)) {
+ size_t i = 0;
+ struct psi_decl_arg *def;
+
+ while (psi_plist_get(D->types, i++, &def)) {
+ dprintf(fd, "typedef ");
+ psi_decl_arg_dump(fd, def, 0);
+ dprintf(fd, ";\n");
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->unions)) {
+ size_t i = 0;
+ struct psi_decl_union *unn;
+
+ while (psi_plist_get(D->unions, i++, &unn)) {
+ if (!psi_decl_type_is_anon(unn->name, "union")) {
+ psi_decl_union_dump(fd, unn);
+ dprintf(fd, "\n");
+ }
+ }
+ dprintf(fd, "\n");
}
- free_decl_file(&data->psi.file);
+ if (psi_plist_count(D->structs)) {
+ size_t i = 0;
+ struct psi_decl_struct *strct;
+
+ while (psi_plist_get(D->structs, i++, &strct)) {
+ if (!psi_decl_type_is_anon(strct->name, "struct")) {
+ psi_decl_struct_dump(fd, strct);
+ dprintf(fd, "\n");
+ }
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->enums)) {
+ size_t i = 0;
+ struct psi_decl_enum *enm;
+
+ while (psi_plist_get(D->enums, i++, &enm)) {
+ if (!psi_decl_type_is_anon(enm->name, "enum")) {
+ psi_decl_enum_dump(fd, enm, 0);
+ dprintf(fd, "\n");
+ }
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->consts)) {
+ size_t i = 0;
+ struct psi_const *c;
+
+ while (psi_plist_get(D->consts, i++, &c)) {
+ psi_const_dump(fd, c);
+ dprintf(fd, "\n");
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->decls)) {
+ size_t i = 0;
+ struct psi_decl *decl;
+
+ while (psi_plist_get(D->decls, i++, &decl)) {
+ psi_decl_dump(fd, decl);
+ dprintf(fd, "\n");
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->impls)) {
+ size_t i = 0;
+ struct psi_impl *impl;
+
+ while (psi_plist_get(D->impls, i++, &impl)) {
+ psi_impl_dump(fd, impl);
+ dprintf(fd, "\n");
+ }
+ dprintf(fd, "\n");
+ }
+}
+
+bool psi_data_validate(struct psi_data *dst, struct psi_data *src)
+{
+ void *dlopened = NULL;
+ size_t check_count = ~0;
+ struct psi_plist *check_types = src->types;
+ struct psi_plist *check_structs = src->structs;
+ struct psi_plist *check_unions = src->unions;
+ struct psi_plist *check_enums = src->enums;
+ unsigned flags = dst->flags;
+ unsigned errors = src->errors;
+
+ /* fail early if library is not found */
+ if (!psi_decl_file_validate(dst, src, &dlopened)) {
+ return false;
+ }
+
+ dst->flags |= PSI_SILENT;
+
+ while (check_count) {
+ struct psi_plist *recheck_types;
+ struct psi_plist *recheck_structs;
+ struct psi_plist *recheck_unions;
+ struct psi_plist *recheck_enums;
+ size_t count_types = psi_plist_count(check_types);
+ size_t count_structs = psi_plist_count(check_structs);
+ size_t count_unions = psi_plist_count(check_unions);
+ size_t count_enums = psi_plist_count(check_enums);
+ size_t count_all = count_types + count_structs + count_unions
+ + count_enums;
+
+ if (check_count == count_all) {
+ /* nothing changed; bail out */
+ if (count_all && (dst->flags & PSI_SILENT) && !(flags & PSI_SILENT)) {
+ /* one last error-spitting round, if not explicitly suppressed */
+ dst->flags ^= PSI_SILENT;
+ check_count = ~0;
+
+ PSI_DEBUG_PRINT(dst, "PSI: validation bail out with %zu"
+ " type checks remaining, errors follow\n", count_all);
+ continue;
+ }
+ check_count = 0;
+ } else {
+ recheck_types = count_types ? psi_plist_init(NULL) : NULL;
+ recheck_structs = count_structs ? psi_plist_init(NULL) : NULL;
+ recheck_unions = count_unions ? psi_plist_init(NULL) : NULL;
+ recheck_enums = count_enums ? psi_plist_init(NULL) : NULL;
+
+ check_count = count_all;
+ src->errors = errors + check_count;
+
+ PSI_DEBUG_PRINT(dst, "PSI: validate data(%p) %zu type checks remaining\n",
+ src, check_count);
+
+ if (count_types) {
+ size_t i = 0;
+ struct psi_decl_arg *def;
+
+ while (psi_plist_get(check_types, i++, &def)) {
+ *dst->last_error = 0;
+ PSI_DEBUG_PRINT(dst, "PSI: validate typedef %s ", def->var->name);
+ if (psi_decl_arg_validate_typedef(PSI_DATA(dst), def)) {
+ PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+ dst->types = psi_plist_add(dst->types, &def);
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ recheck_types = psi_plist_add(recheck_types, &def);
+ }
+ }
+ }
+ if (count_structs) {
+ size_t i = 0;
+ struct psi_decl_struct *str;
+
+ while (psi_plist_get(check_structs, i++, &str)) {
+ *dst->last_error = 0;
+ dst->structs = psi_plist_add(dst->structs, &str);
+ PSI_DEBUG_PRINT(dst, "PSI: validate struct %s ", str->name);
+ if (psi_decl_struct_validate(PSI_DATA(dst), str)) {
+ PSI_DEBUG_PRINT(dst, "%s ::(%zu, %zu)\n", "✔", str->align, str->size);
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ recheck_structs = psi_plist_add(recheck_structs, &str);
+ psi_plist_pop(dst->structs, NULL);
+ }
+ }
+ }
+ if (count_unions) {
+ size_t i = 0;
+ struct psi_decl_union *unn;
+
+ while (psi_plist_get(check_unions, i++, &unn)) {
+ *dst->last_error = 0;
+ dst->unions = psi_plist_add(dst->unions, &unn);
+ PSI_DEBUG_PRINT(dst, "PSI: validate union %s ", unn->name);
+ if (psi_decl_union_validate(PSI_DATA(dst), unn)) {
+ PSI_DEBUG_PRINT(dst, "%s ::(%zu, %zu)\n", "✔", unn->align, unn->size);
+
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ recheck_unions = psi_plist_add(recheck_unions, &unn);
+ psi_plist_pop(dst->unions, NULL);
+ }
+ }
+ }
+ if (count_enums) {
+ size_t i = 0;
+ struct psi_decl_enum *enm;
+
+ while (psi_plist_get(check_enums, i++, &enm)) {
+ *dst->last_error = 0;
+ PSI_DEBUG_PRINT(dst, "PSI: validate enum %s ", enm->name);
+ if (psi_decl_enum_validate(PSI_DATA(dst), enm)) {
+ PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+ dst->enums = psi_plist_add(dst->enums, &enm);
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ recheck_enums = psi_plist_add(recheck_enums, &enm);
+ }
+ }
+ }
+ }
+
+ if (check_types && check_types != src->types) {
+ psi_plist_free(check_types);
+ }
+ check_types = recheck_types;
+ if (check_structs && check_structs != src->structs) {
+ psi_plist_free(check_structs);
+ }
+ check_structs = recheck_structs;
+ if (check_unions && check_unions != src->unions) {
+ psi_plist_free(check_unions);
+ }
+ check_unions = recheck_unions;
+ if (check_enums && check_enums != src->enums) {
+ psi_plist_free(check_enums);
+ }
+ check_enums = recheck_enums;
+ }
+
+ /* reset original flags */
+ dst->flags = flags;
+
+ if (src->consts) {
+ size_t i = 0;
+ struct psi_const *cnst;
+
+ while (psi_plist_get(src->consts, i++, &cnst)) {
+ *dst->last_error = 0;
+ PSI_DEBUG_PRINT(dst, "PSI: validate const %s ", cnst->name);
+ if (psi_const_validate(PSI_DATA(dst), cnst)) {
+ PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+ dst->consts = psi_plist_add(dst->consts, &cnst);
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ ++src->errors;
+ }
+ }
+ }
+
+ if (src->decls) {
+ size_t i = 0;
+ struct psi_decl *decl;
+
+ while (psi_plist_get(src->decls, i++, &decl)) {
+ *dst->last_error = 0;
+ PSI_DEBUG_PRINT(dst, "PSI: validate decl %s ", decl->func->var->name);
+ if (psi_decl_validate(PSI_DATA(dst), decl, dlopened)) {
+ PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+ dst->decls = psi_plist_add(dst->decls, &decl);
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ ++src->errors;
+ }
+ }
+ }
+
+ if (src->impls) {
+ size_t i = 0;
+ struct psi_impl *impl;
+
+ while (psi_plist_get(src->impls, i++, &impl)) {
+ *dst->last_error = 0;
+ PSI_DEBUG_PRINT(dst, "PSI: validate impl %s ", impl->func->name);
+ if (psi_impl_validate(PSI_DATA(dst), impl)) {
+ PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+ dst->impls = psi_plist_add(dst->impls, &impl);
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ ++src->errors;
+ }
+ }
+ }
+
+ return true;
}
-#ifndef _PSI_DATA_H
-#define _PSI_DATA_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_DATA_H
+#define PSI_DATA_H
#include "types.h"
#include "error.h"
+#include "plist.h"
+
+#define PSI_DEBUG 0x1
+#define PSI_SILENT 0x2
+
+#include <stdarg.h>
+
+#define PSI_DEBUG_PRINT(ctx, msg, ...) do { \
+ if (PSI_DATA(ctx)->flags & PSI_DEBUG) { \
+ fprintf(stderr, msg, __VA_ARGS__); \
+ } \
+} while(0)
+
#define PSI_DATA(D) ((struct psi_data *) (D))
#define PSI_DATA_MEMBERS \
- constants *consts; \
- decl_typedefs *defs; \
- decl_structs *structs; \
- decl_unions *unions; \
- decl_enums *enums; \
- decls *decls; \
- impls *impls; \
- union { \
- decl_file file; \
- decl_libs libs; \
- } psi; \
+ struct psi_decl_file file; \
+ struct psi_plist *consts; \
+ struct psi_plist *types; \
+ struct psi_plist *structs; \
+ struct psi_plist *unions; \
+ struct psi_plist *enums; \
+ struct psi_plist *decls; \
+ struct psi_plist *impls; \
+ struct psi_plist *libs; \
psi_error_cb error; \
+ char last_error[0x1000]; \
unsigned errors; \
unsigned flags
PSI_DATA_MEMBERS;
};
+struct psi_data *psi_data_ctor(struct psi_data *data, psi_error_cb error, unsigned flags);
+struct psi_data *psi_data_ctor_with_dtors(struct psi_data *data, psi_error_cb error, unsigned flags);
struct psi_data *psi_data_exchange(struct psi_data *dest, struct psi_data *src);
+bool psi_data_validate(struct psi_data *dst, struct psi_data *src);
void psi_data_dtor(struct psi_data *data);
+void psi_data_dump(int fd, struct psi_data *data);
#endif
+++ /dev/null
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
-#include "php.h"
-#include "php_psi.h"
-
-#include "zend_exceptions.h"
-#include "zend_interfaces.h"
-#include "ext/spl/spl_iterators.h"
-
-#include "parser.h"
-#include "engine.h"
-#include "calc.h"
-#include "marshal.h"
-
-static inline void psi_do_set(zval *return_value, set_value *set)
-{
- decl_arg *set_arg = set->vars->vars[0]->arg;
-
- zval_dtor(return_value);
- set->func->handler(return_value, set, set_arg->let);
-}
-
-int psi_internal_type(impl_type *type)
-{
- switch (type->type) {
- case PSI_T_BOOL:
- return _IS_BOOL;
- case PSI_T_INT:
- return IS_LONG;
- case PSI_T_FLOAT:
- case PSI_T_DOUBLE:
- return IS_DOUBLE;
- case PSI_T_STRING:
- return IS_STRING;
- case PSI_T_ARRAY:
- return IS_ARRAY;
- default:
- return 0;
- }
-}
-
-zend_long psi_zval_count(zval *zvalue)
-{
- /* mimic PHP count() */
- zend_long count;
- zval retval;
-
- switch (Z_TYPE_P(zvalue)) {
- default:
- count = 1;
- break;
- case IS_NULL:
- count = 0;
- break;
- case IS_ARRAY:
- count = zend_array_count(Z_ARRVAL_P(zvalue));
- break;
- case IS_OBJECT:
- count = 1;
- if (Z_OBJ_HT_P(zvalue)->count_elements) {
- if (SUCCESS == Z_OBJ_HT_P(zvalue)->count_elements(zvalue, &count)) {
- break;
- }
- }
-
- if (instanceof_function(Z_OBJCE_P(zvalue), spl_ce_Countable)) {
- zend_call_method_with_0_params(zvalue, NULL, NULL, "count", &retval);
- if (Z_TYPE(retval) != IS_UNDEF) {
- count = zval_get_long(&retval);
- zval_ptr_dtor(&retval);
- }
- }
- break;
- }
-
- return count;
-}
-
-zend_internal_arg_info *psi_internal_arginfo(impl *impl)
-{
- size_t i;
- zend_internal_arg_info *aip;
- zend_internal_function_info *fi;
-
- aip = calloc(impl->func->args->count + 1 + !!impl->func->args->vararg.name, sizeof(*aip));
-
- fi = (zend_internal_function_info *) &aip[0];
- fi->allow_null = 1;
- fi->required_num_args = psi_num_min_args(impl);
- fi->return_reference = impl->func->return_reference;
- fi->type_hint = psi_internal_type(impl->func->return_type);
-
- if (impl->func->args->vararg.name) {
- impl_arg *vararg = impl->func->args->vararg.name;
- zend_internal_arg_info *ai = &aip[impl->func->args->count];
-
- ai->name = vararg->var->name;
- ai->allow_null = 1;
- ai->type_hint = psi_internal_type(vararg->type);
- if (vararg->var->reference) {
- ai->pass_by_reference = 1;
- }
- ai->is_variadic = 1;
- }
-
- for (i = 0; i < impl->func->args->count; ++i) {
- impl_arg *iarg = impl->func->args->args[i];
- zend_internal_arg_info *ai = &aip[i+1];
-
- ai->name = iarg->var->name;
- ai->type_hint = psi_internal_type(iarg->type);
- if (iarg->var->reference) {
- ai->pass_by_reference = 1;
- }
- //if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
- ai->allow_null = 1;
- //}
- }
-
- return aip;
-}
-
-size_t psi_num_min_args(impl *impl)
-{
- size_t i, n = impl->func->args->count;
-
- for (i = 0; i < impl->func->args->count; ++i) {
- if (impl->func->args->args[i]->def) {
- --n;
- }
- }
- return n;
-}
-
-
-static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
-{
- size_t i;
- impl_arg *iarg;
- zend_error_handling zeh;
-
- zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
-
- if (!impl->func->args->count) {
- ZEND_RESULT_CODE rv;
-
- rv = zend_parse_parameters_none();
- zend_restore_error_handling(&zeh);
- return rv;
- }
-
- ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->vararg.name ? -1 : impl->func->args->count)
- nextarg:
- if (impl->func->args->vararg.name && _i >= impl->func->args->count) {
- impl_arg *varg = impl->func->args->vararg.name;
- iarg = init_impl_arg(
- init_impl_type(varg->type->type, varg->type->name),
- init_impl_var(varg->var->name, varg->var->reference),
- NULL);
-
- Z_PARAM_OPTIONAL;
- if (_i == impl->func->args->count) {
- impl->func->args->vararg.args = init_impl_args(iarg);
- } else {
- add_impl_arg(impl->func->args->vararg.args, iarg);
- }
- } else {
- iarg = impl->func->args->args[_i];
- if (iarg->def) {
- Z_PARAM_OPTIONAL;
- }
- }
- if (PSI_T_BOOL == iarg->type->type) {
- Z_PARAM_BOOL(iarg->val.zend.bval);
- } else if (PSI_T_INT == iarg->type->type) {
- Z_PARAM_LONG(iarg->val.zend.lval);
- } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
- Z_PARAM_DOUBLE(iarg->val.dval);
- } else if (PSI_T_STRING == iarg->type->type) {
- Z_PARAM_STR_EX(iarg->val.zend.str, 1, iarg->var->reference);
- if (iarg->val.zend.str) {
- zend_string_addref(iarg->val.zend.str);
- }
- } else if (PSI_T_ARRAY == iarg->type->type) {
- Z_PARAM_PROLOGUE(0);
- } else if (PSI_T_OBJECT == iarg->type->type) {
- Z_PARAM_PROLOGUE(0);
- } else if (PSI_T_MIXED == iarg->type->type) {
- Z_PARAM_PROLOGUE(0);
- } else if (PSI_T_CALLABLE == iarg->type->type) {
- zend_fcall_info fci;
- zend_fcall_info_cache fcc;
-
- Z_PARAM_FUNC_EX(fci, fcc, 1, 0);
-
- if (fci.size) {
- iarg->val.zend.cb = ecalloc(1, sizeof(zend_fcall));
- iarg->val.zend.cb->fci = fci;
- iarg->val.zend.cb->fcc = fcc;
- }
- } else {
- error_code = ZPP_ERROR_FAILURE;
- break;
- }
- iarg->_zv = _arg;
- ZVAL_DEREF(iarg->_zv);
- if (_i < _num_args) {
- goto nextarg;
- }
- ZEND_PARSE_PARAMETERS_END_EX(
- zend_restore_error_handling(&zeh);
- return FAILURE
- );
-
- /* set up defaults */
- for (i = 0; i < impl->func->args->count; ++i) {
- if (i >= EX_NUM_ARGS() && iarg->def) {
- iarg = impl->func->args->args[i];
-
- switch (iarg->type->type) {
- case PSI_T_BOOL:
- iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
- break;
- case PSI_T_INT:
- iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
- break;
- case PSI_T_FLOAT:
- case PSI_T_DOUBLE:
- iarg->val.dval = zend_strtod(iarg->def->text, NULL);
- break;
- case PSI_T_STRING:
- /* FIXME */
- iarg->val.zend.str = zend_string_init(&iarg->def->text[1], strlen(iarg->def->text) - 2, 0);
- break;
- }
- }
- }
-
- zend_restore_error_handling(&zeh);
- return SUCCESS;
-}
-
-static inline void *psi_do_calloc(let_calloc *alloc)
-{
- zend_long n = psi_long_num_exp(alloc->nmemb, NULL), s = psi_long_num_exp(alloc->size, NULL);
- void *mem = safe_emalloc(n, s, sizeof(void *));
- memset(mem, 0, n * s + sizeof(void *));
-#if 0
- fprintf(stderr, "calloc: %p\n", mem);
-#endif
- return mem;
-}
-
-static inline impl_val *psi_let_func(let_func *func, decl_arg *darg);
-
-static inline void *psi_let_val(let_val *val, decl_arg *darg)
-{
- ZEND_ASSERT(darg);
-
- switch (val ? val->kind : PSI_LET_NULL) {
- case PSI_LET_TMP:
- memcpy(darg->ptr, deref_impl_val(val->data.var->arg->let, val->data.var), sizeof(impl_val));
- break;
- case PSI_LET_NULL:
- if (darg->var->array_size) {
- darg->val.ptr = ecalloc(darg->var->array_size, sizeof(impl_val));
- darg->mem = darg->val.ptr;
- } else {
- memset(&darg->val, 0, sizeof(impl_val));
- }
- break;
- case PSI_LET_CALLOC:
- darg->val.ptr = psi_do_calloc(val->data.alloc);
- darg->mem = darg->val.ptr;
- break;
- case PSI_LET_NUMEXP:
- darg->val.zend.lval = psi_long_num_exp(val->data.num, NULL);
- break;
- case PSI_LET_CALLBACK:
- darg->val.ptr = val->data.callback->decl->call.sym;
- break;
- case PSI_LET_FUNC:
- if (!psi_let_func(val->data.func, darg)) {
- return NULL;
- }
- break;
- }
-
- if (val && val->is_reference) {
- return darg->let = &darg->ptr;
- } else {
- return darg->let = darg->ptr;
- }
-}
-
-static inline impl_val *psi_let_func_ex(let_func *func, void *dptr, decl_type *dtype, decl_var *dvar, token_t itype, impl_val *ival, zval *zvalue, void **to_free) {
- switch (func->type) {
- case PSI_T_BOOLVAL:
- return psi_let_boolval(dptr, dtype, itype, ival, zvalue, to_free);
- case PSI_T_INTVAL:
- return psi_let_intval(dptr, dtype, itype, ival, zvalue, to_free);
- case PSI_T_FLOATVAL:
- return psi_let_floatval(dptr, dtype, itype, ival, zvalue, to_free);
- case PSI_T_STRVAL:
- return psi_let_strval(dptr, dtype, itype, ival, zvalue, to_free);
- case PSI_T_STRLEN:
- return psi_let_strlen(dptr, dtype, itype, ival, zvalue, to_free);
- case PSI_T_PATHVAL:
- return psi_let_pathval(dptr, dtype, itype, ival, zvalue, to_free);
- case PSI_T_OBJVAL:
- return psi_let_objval(dptr, dtype, itype, ival, zvalue, to_free);
- case PSI_T_ZVAL:
- return psi_let_zval(dptr, dtype, itype, ival, zvalue, to_free);
- case PSI_T_VOID:
- return psi_let_void(dptr, dtype, itype, ival, zvalue, to_free);
- case PSI_T_COUNT:
- return psi_let_count(dptr, dtype, itype, ival, zvalue, to_free);
- case PSI_T_ARRVAL:
- if (func->inner) {
- char *mem = NULL;
- size_t i, j = 0;
- decl_type *real;
- decl_args *args = extract_decl_type_args(dtype, &real);
-
- if (itype != PSI_T_ARRAY) {
- SEPARATE_ARG_IF_REF(zvalue);
- convert_to_array(zvalue);
- }
-
- if (args) {
- size_t size = extract_decl_type_size(real, NULL);
-
- mem = ecalloc(1, size + args->count * sizeof(void *));
-
- for (i = 0; i < args->count; ++i) {
- decl_arg *darg = args->args[i];
- let_val *lval = locate_let_vals_val(func->inner, darg->var->name);
- impl_val *ptr = NULL;
-
- if (lval) {
- if ((ptr = psi_let_val(lval, darg))) {
- memcpy(mem + darg->layout->pos, ptr, darg->layout->len);
- if (darg->mem) {
- ((void **)(mem + size))[j++] = darg->mem;
- }
- }
- if (real->type == PSI_T_UNION) {
- break;
- }
- }
- }
- } else {
- zval *zv;
- let_val *inner = func->inner->vals[0];
- decl_var *sub_var;
- size_t size;
-
- if (inner->var) {
- sub_var = inner->var;
- } else {
- sub_var = copy_decl_var(dvar);
- assert(sub_var->pointer_level);
- --sub_var->pointer_level;
- }
-
- size = sub_var->pointer_level ? SIZEOF_VOID_P : extract_decl_type_size(real, NULL);
- mem = ecalloc(1, size * (1 + zend_array_count(Z_ARRVAL_P(zvalue))));
-
- ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(zvalue), zv)
- {
- void *tmp = NULL;
- impl_val val = {0}, *ptr, *sub;
-
- ptr = psi_let_func_ex(inner->data.func, &val, real, dvar, 0, NULL, zv, &tmp);
- sub = deref_impl_val(ptr, sub_var);
-
- memcpy(&mem[size * j++], &sub, size);
- }
- ZEND_HASH_FOREACH_END();
-
- if (sub_var != inner->var) {
- free_decl_var(sub_var);
- }
- }
- return *to_free = mem;
- } else {
- return psi_let_arrval(dptr, dtype, dvar, itype, ival, zvalue, to_free);
- }
- break;
- default:
- assert(0);
- }
- return NULL;
-}
-
-static inline impl_val *psi_let_func(let_func *func, decl_arg *darg) {
-
- if (func->var->arg) {
- return darg->ptr = psi_let_func_ex(func,
- darg->ptr, darg->type, darg->var,
- func->var->arg->type->type,
- &func->var->arg->val,
- func->var->arg->_zv,
- &darg->mem);
- } else {
- impl_var *ivar = locate_let_val_impl_var(func->outer);
- zval *entry = zend_symtable_str_find(Z_ARRVAL_P(ivar->arg->_zv), func->var->name+1, strlen(func->var->name)-1);
- impl_arg *iarg = init_impl_arg(
- init_impl_type(PSI_T_MIXED, "mixed"),
- copy_impl_var(func->var), NULL);
-
- func->var->arg = iarg;
- if (entry) {
- iarg->_zv = entry;
- } else {
- zval ztmp;
-
- ZVAL_NULL(&ztmp);
- iarg->_zv = zend_symtable_str_update_ind(Z_ARRVAL_P(ivar->arg->_zv), func->var->name+1, strlen(func->var->name)-1, &ztmp);
- }
-
- psi_let_func(func, darg);
- free_impl_arg(iarg);
- return darg->ptr;
- }
-
-}
-
-static inline void *psi_do_let(let_stmt *let)
-{
- return psi_let_val(let->val, let->val->var->arg);
-}
-
-static inline void psi_do_return(zval *return_value, return_stmt *ret)
-{
- ret->set->func->handler(return_value, ret->set, ret->set->vars->vars[0]->arg->ptr);
-}
-
-static inline void psi_do_free(free_stmt *fre)
-{
- size_t i, j;
-
- for (i = 0; i < fre->calls->count; ++i) {
- free_call *f = fre->calls->list[i];
-
- for (j = 0; j < f->vars->count; ++j) {
- decl_var *dvar = f->vars->vars[j];
- decl_arg *darg = dvar->arg;
- impl_val *fval = darg->let;
-
- f->decl->call.args[j] = deref_impl_val(fval, dvar);
- }
-
- /* FIXME: check in validate_* that free functions return scalar */
- psi_context_call(&PSI_G(context), &f->decl->call, NULL);
- }
-}
-
-static inline void psi_clean_array_struct(let_val *val, decl_arg *darg) {
- if (val->kind == PSI_LET_FUNC
- && val->data.func->type == PSI_T_ARRVAL) {
- decl_type *type = real_decl_type(darg->type);
-
- if (type->type == PSI_T_STRUCT) {
- void **ptr = (void **) ((char *) darg->mem + type->real.strct->size);
-
- while (*ptr) {
- efree(*ptr++);
- }
- // args = type->real.strct->args;
- } else if (type->type == PSI_T_UNION) {
- void **ptr = (void **) ((char *) darg->mem + type->real.unn->size);
-
- if (*ptr) {
- efree(*ptr);
- }
- // args = type->real.unn->args;
- }
-#if 0
- if (args && val->data.func->inner) {
- size_t i;
-
- for (i = 0; i < val->data.func->inner->count; ++i) {
- let_val *inner = val->data.func->inner->vals[i];
- decl_var *refvar = locate_let_val_inner_ref(inner)->var;
- decl_arg *subarg = locate_decl_arg(args, refvar->name);
-
- if (subarg) {
- psi_clean_array_struct(val->data.func->inner->vals[i], subarg);
- if (subarg->mem) {
- efree(subarg->mem);
- subarg->mem = NULL;
- }
- }
- }
- }
-#endif
- }
-}
-
-static inline void psi_clean_let_val(let_val *val) {
-
- let_func *func = locate_let_val_func(val);
-
- if (func && func->inner) {
- size_t i;
-
- for (i = 0; i < func->inner->count; ++i) {
- let_val *inner = func->inner->vals[i];
- psi_clean_let_val(inner);
- }
- }
- if (val->var) {
- decl_arg *darg = val->var->arg;
- if (darg) {
- if (darg->mem) {
- psi_clean_array_struct(val, darg);
- efree(darg->mem);
- darg->mem = NULL;
- }
- darg->ptr = &darg->val;
- darg->let = darg->ptr;
- }
- }
-}
-
-static inline void psi_do_clean(impl *impl)
-{
- size_t i;
-
- if (impl->decl->func->ptr != &impl->decl->func->val) {
- efree(impl->decl->func->ptr);
- impl->decl->func->ptr = &impl->decl->func->val;
- }
-
- for (i = 0; i < impl->func->args->count; ++i ) {
- impl_arg *iarg = impl->func->args->args[i];
-
- switch (iarg->type->type) {
- case PSI_T_STRING:
- if (iarg->val.zend.str) {
- zend_string_release(iarg->val.zend.str);
- }
- break;
- case PSI_T_CALLABLE:
- if (iarg->val.zend.cb) {
- if (iarg->val.zend.cb->fci.size) {
- zend_fcall_info_args_clear(&iarg->val.zend.cb->fci, 1);
- }
- efree(iarg->val.zend.cb);
- }
- break;
- }
- }
-
- for (i = 0; i < impl->stmts->let.count; ++i) {
- let_stmt *let = impl->stmts->let.list[i];
- psi_clean_let_val(let->val);
- }
-
- if (impl->func->args->vararg.args) {
- free_impl_args(impl->func->args->vararg.args);
- impl->func->args->vararg.args = NULL;
- }
- if (impl->func->args->vararg.types) {
- efree(impl->func->args->vararg.types);
- impl->func->args->vararg.types = NULL;
- }
- if (impl->func->args->vararg.values) {
- efree(impl->func->args->vararg.values);
- impl->func->args->vararg.values = NULL;
- }
- if (impl->func->args->vararg.free_list) {
- void **list = impl->func->args->vararg.free_list;
-
- while (*list) {
- efree(*list++);
- }
-
- efree(impl->func->args->vararg.free_list);
- impl->func->args->vararg.free_list = NULL;
- }
-}
-
-
-static inline void psi_do_args(impl *impl) {
- size_t i;
-
- for (i = 0; i < impl->decl->args->count; ++i) {
- impl->decl->call.args[i] = impl->decl->args->args[i]->let;
- }
-
- if (!impl->decl->func->var->pointer_level) {
- decl_type *real;
- decl_args *args = extract_decl_type_args(impl->decl->func->type, &real);
-
- switch (real->type) {
- case PSI_T_STRUCT:
- case PSI_T_UNION:
- impl->decl->func->ptr = ecalloc(1,
- extract_decl_type_size(real, NULL) + args->count * sizeof(void*));
- break;
- default:
- break;
- }
- }
-}
-
-static inline impl_vararg *psi_do_varargs(impl *impl) {
- size_t i, j;
- impl_vararg *va = &impl->func->args->vararg;
- size_t vacount = va->args->count;
-
-
- if (!vacount) {
- return NULL;
- }
-
- va->types = ecalloc(vacount, sizeof(*va->types));
- va->values = ecalloc(vacount, sizeof(*va->values));
-
- for (i = 0, j = 0; i < vacount; ++i) {
- impl_arg *vaarg = va->args->args[i];
- void *to_free = NULL;
- token_t vatype = va->name->type->type;
- psi_marshal_let let_fn;
-
- if (vatype == PSI_T_MIXED) {
- switch (Z_TYPE_P(vaarg->_zv)) {
- case IS_TRUE:
- case IS_FALSE: vatype = PSI_T_BOOL; break;
- case IS_LONG: vatype = PSI_T_INT; break;
- case IS_DOUBLE: vatype = PSI_T_FLOAT; break;
- default: vatype = PSI_T_STRING; break;
- }
- }
-
-
- switch (vatype) {
- case PSI_T_BOOL: let_fn = psi_let_boolval; break;
- case PSI_T_INT: let_fn = psi_let_intval; break;
- case PSI_T_FLOAT:
- case PSI_T_DOUBLE: let_fn = psi_let_floatval; break;
- case PSI_T_STRING: let_fn = psi_let_strval; break;
- EMPTY_SWITCH_DEFAULT_CASE();
- }
-
- va->types[i] = vatype;
-
- /* FIXME: varargs with struct-by-value :) */
- //if (!psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free)) {
- if (!let_fn(&va->values[i], NULL, vaarg->type->type, &vaarg->val, vaarg->_zv, &to_free)) {
- return NULL;
- }
-
- if (to_free) {
- if (!va->free_list) {
- va->free_list = ecalloc(vacount - i + 1, sizeof(*va->free_list));
- }
- va->free_list[j++] = to_free;
- }
- }
-
- return va;
-}
-
-ZEND_RESULT_CODE psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
-{
- size_t i;
- impl_vararg *va = NULL;
-
- memset(impl->decl->func->ptr, 0, sizeof(impl_val));
-
- if (SUCCESS != psi_parse_args(execute_data, impl)) {
- return FAILURE;
- }
-
- for (i = 0; i < impl->stmts->let.count; ++i) {
- let_stmt *let = impl->stmts->let.list[i];
-
- if (!psi_do_let(let)) {
- psi_do_return(return_value, impl->stmts->ret.list[0]);
- psi_do_clean(impl);
- return FAILURE;
- }
- }
-
- if (impl->decl->args) {
- psi_do_args(impl);
-
- if (impl->func->args->vararg.args) {
- va = psi_do_varargs(impl);
- }
- }
-
- psi_context_call(&PSI_G(context), &impl->decl->call, va);
- psi_do_return(return_value, impl->stmts->ret.list[0]);
-
- for (i = 0; i < impl->stmts->set.count; ++i) {
- set_stmt *set = impl->stmts->set.list[i];
-
- if (set->arg->_zv) {
- psi_do_set(set->arg->_zv, set->val);
- }
- }
-
- for (i = 0; i < impl->stmts->fre.count; ++i) {
- free_stmt *fre = impl->stmts->fre.list[i];
-
- psi_do_free(fre);
- }
- psi_do_clean(impl);
-
- return SUCCESS;
-}
-
-ZEND_RESULT_CODE psi_callback(let_callback *cb, void *retval, unsigned argc, void **argv)
-{
- size_t i;
- decl *decl_cb = cb->decl;
- impl_arg *iarg = cb->func->var->arg;
- zval return_value, *zargv = calloc(argc, sizeof(*zargv));
- void *result, *to_free = NULL;
-
- ZEND_ASSERT(argc == cb->decl->args->count);
-
- /* prepare args for the userland call */
- for (i = 0; i < argc; ++i) {
- cb->decl->args->args[i]->let = argv[i];
- }
- for (i = 0; i < cb->args->count; ++i) {
- psi_do_set(&zargv[i], cb->args->vals[i]);
- }
- zend_fcall_info_argp(&iarg->val.zend.cb->fci, cb->args->count, zargv);
-
- /* callback into userland */
- ZVAL_UNDEF(&return_value);
- iarg->_zv = &return_value;
- zend_fcall_info_call(&iarg->val.zend.cb->fci, &iarg->val.zend.cb->fcc, iarg->_zv, NULL);
-
- /* marshal return value of the userland call
- switch (iarg->type->type) {
- case PSI_T_BOOL: zend_parse_arg_bool(iarg->_zv, &iarg->val.zend.bval, NULL, 0); break;
- case PSI_T_LONG: zend_parse_arg_long(iarg->_zv, &iarg->val.zend.lval, NULL, 0, 1); break;
- case PSI_T_FLOAT:
- case PSI_T_DOUBLE: zend_parse_arg_double(iarg->_zv, &iarg->val.dval, NULL, 0); break;
- case PSI_T_STRING: zend_parse_arg_str(iarg->_zv, &iarg->val.zend.str, 0); break;
- }
- */
- result = psi_let_func_ex(cb->func, retval, decl_cb->func->type, decl_cb->func->var, 0, &iarg->val, iarg->_zv, &to_free);
- // result = cb->func->handler(retval, decl_cb->func->type, iarg, &to_free);
-
- if (result != retval) {
- *(void **)retval = result;
- }
-
- zend_fcall_info_args_clear(&iarg->val.zend.cb->fci, 0);
- for (i = 0; i < cb->args->count; ++i) {
- zval_ptr_dtor(&zargv[i]);
- }
- free(zargv);
-
- return SUCCESS;
-
-}
+++ /dev/null
-#ifndef _PSI_ENGINE_H
-#define _PSI_ENGINE_H
-
-int psi_internal_type(impl_type *type);
-zend_internal_arg_info *psi_internal_arginfo(impl *impl);
-size_t psi_num_min_args(impl *impl);
-zend_long psi_zval_count(zval *zvalue);
-
-ZEND_RESULT_CODE psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl);
-ZEND_RESULT_CODE psi_callback(let_callback *cb, void *retval, unsigned argc, void **argv);
-
-#endif
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+#include "php_psi_stdinc.h"
+#include "data.h"
-#include <stdlib.h>
-#include <stdio.h>
+/* zend_error_cb */
+#include "Zend/zend.h"
+/* is executing/compiling query API */
+#include "Zend/zend_compile.h"
+#include "Zend/zend_execute.h"
-#include "error.h"
+/* PG(), strlcpy, vslprintf */
+#include "php.h"
+void psi_error_wrapper(struct psi_data *context, struct psi_token *t, int type, const char *msg, ...)
+{
+ va_list argv;
+ const char *fn = NULL;
+ unsigned ln = 0;
+
+ if (context) {
+ if (context->flags & PSI_SILENT) {
+ /* context->last_error may be an argument to print */
+ char error[sizeof(context->last_error)];
+
+ va_start(argv, msg);
+ vslprintf(error, sizeof(error), msg, argv);
+ va_end(argv);
+
+ memcpy(context->last_error, error,
+ sizeof(context->last_error));
+ return;
+ }
+ }
+
+ if (t) {
+ fn = t->file;
+ ln = t->line;
+ } else if (zend_is_executing()) {
+ fn = zend_get_executed_filename();
+ ln = zend_get_executed_lineno();
+ } else if (zend_is_compiling()) {
+ fn = zend_get_compiled_filename()->val;
+ ln = zend_get_compiled_lineno();
+ } else {
+ fn = "PSI module startup";
+ }
+
+ va_start(argv, msg);
+ psi_verror(type, fn, ln, msg, argv);
+ va_end(argv);
+
+ if (context) {
+ strlcpy(context->last_error, PG(last_error_message),
+ sizeof(context->last_error));
+ }
+}
+
+void psi_error(int type, const char *fn, unsigned ln, const char *msg, ...)
+{
+ va_list argv;
+
+ va_start(argv, msg);
+ psi_verror(type, fn, ln, msg, argv);
+ va_end(argv);
+}
+
+void psi_verror(int type, const char *fn, unsigned ln, const char *msg, va_list argv)
+{
+ zend_error_cb(type, fn, ln, msg, argv);
+}
#include <stdarg.h>
-#include "token.h"
-
#define PSI_ERROR 16
#define PSI_WARNING 32
-typedef void (*psi_error_cb)(void *context, struct psi_token *token, int type, const char *msg, ...);
+struct psi_data;
+struct psi_token;
+
+typedef void (*psi_error_cb)(struct psi_data *context, struct psi_token *token, int type, const char *msg, ...);
-void psi_error_wrapper(void *context, struct psi_token *t, int type, const char *msg, ...);
+void psi_error_wrapper(struct psi_data *context, struct psi_token *t, int type, const char *msg, ...);
void psi_error(int type, const char *fn, unsigned ln, const char *msg, ...);
void psi_verror(int type, const char *fn, unsigned ln, const char *msg, va_list argv);
-#endif /* EXT_PSI_SRC_ERROR_H */
+#endif /* PSI_ERROR_H */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include "context.h"
+#include "call.h"
#include "php.h"
#ifdef HAVE_LIBFFI
-#include "php_psi.h"
-#include "engine.h"
-
#undef PACKAGE
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#else
# error "Neither ffi_prep_closure() nor ffi_prep_closure_loc() is available"
#endif
-
}
static void psi_ffi_closure_free(void *c)
#endif
}
-static void psi_ffi_handler(ffi_cif *_sig, void *_result, void **_args, void *_data)
-{
- psi_call(*(zend_execute_data **)_args[0], *(zval **)_args[1], _data);
-}
+static void psi_ffi_prep_va(ffi_cif *base, ffi_cif *signature, size_t argc, size_t va_count,
+ ffi_type **param_types) {
+ ffi_status rc;
-static void psi_ffi_callback(ffi_cif *_sig, void *_result, void **_args, void *_data)
-{
- psi_callback(_data, _result, _sig->nargs, _args);
+#ifdef PSI_HAVE_FFI_PREP_CIF_VAR
+ rc = ffi_prep_cif_var(signature, base->abi, argc, argc + va_count,
+ base->rtype, param_types);
+#else
+ /* FIXME: test in config.m4; assume we can just call anyway */
+ rc = ffi_prep_cif(signature, base->abi, argc + va_count, base->rtype, param_types);
+#endif
+
+ ZEND_ASSERT(FFI_OK == rc);
}
-static inline ffi_type *psi_ffi_decl_arg_type(decl_arg *darg);
+static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg);
struct psi_ffi_context {
ffi_cif signature;
};
struct psi_ffi_call {
+ struct psi_context *context;
+ union {
+ struct {
+ struct psi_impl *impl;
+ struct psi_call_frame *frame;
+ } fn;
+ struct {
+ struct psi_let_exp *let_exp;
+ struct psi_ffi_call *impl_call;
+ } cb;
+ } impl;
void *code;
ffi_closure *closure;
ffi_cif signature;
- void *params[1]; /* [type1, type2, NULL, arg1, arg2] ... */
+ ffi_type *params[1]; /* [type1, type2, ... ] */
};
+static void psi_ffi_handler(ffi_cif *sig, void *result, void **args, void *data)
+{
+ struct psi_ffi_call *call = data;
+
+ psi_context_call(call->context, *(zend_execute_data **)args[0], *(zval **)args[1], call->impl.fn.impl);
+}
+
+static void psi_ffi_callback(ffi_cif *sig, void *result, void **args, void *data)
+{
+ struct psi_ffi_call *call = data, *impl_call = call->impl.cb.impl_call;
+
+ if (impl_call->impl.fn.frame) {
+ struct psi_call_frame_callback cbdata;
+
+ cbdata.cb = call->impl.cb.let_exp;
+ cbdata.argc = sig->nargs;
+ cbdata.argv = args;
+ cbdata.rval = result;
+
+ psi_call_frame_do_callback(impl_call->impl.fn.frame, &cbdata);
+ } else {
+ assert(0);
+ }
+}
+
static inline ffi_abi psi_ffi_abi(const char *convention) {
return FFI_DEFAULT_ABI;
}
-static inline struct psi_ffi_call *psi_ffi_call_alloc(struct psi_context *C, decl *decl) {
+static inline struct psi_ffi_call *psi_ffi_call_alloc(struct psi_context *C, struct psi_decl *decl) {
int rc;
- size_t i, c = decl->args ? decl->args->count : 0;
+ size_t i, c = psi_plist_count(decl->args);
struct psi_ffi_call *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
+ struct psi_decl_arg *arg;
- for (i = 0; i < c; ++i) {
- call->params[i] = psi_ffi_decl_arg_type(decl->args->args[i]);
+ decl->info = call;
+ call->context = C;
+
+ for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
+ call->params[i] = psi_ffi_decl_arg_type(arg);
}
call->params[c] = NULL;
- decl->call.info = call;
- decl->call.rval = &decl->func->ptr;
- decl->call.argc = c;
- decl->call.args = (void **) &call->params[c+1];
-
rc = ffi_prep_cif(&call->signature, psi_ffi_abi(decl->abi->convention),
- c, psi_ffi_decl_arg_type(decl->func), (ffi_type **) call->params);
+ c, psi_ffi_decl_arg_type(decl->func), call->params);
ZEND_ASSERT(FFI_OK == rc);
return call;
}
-static inline ffi_status psi_ffi_call_init_closure(struct psi_context *C, struct psi_ffi_call *call, impl *impl) {
+static inline ffi_status psi_ffi_call_init_closure(struct psi_context *C, struct psi_ffi_call *call, struct psi_impl *impl) {
struct psi_ffi_context *context = C->context;
- return psi_ffi_prep_closure(&call->closure, &call->code, &context->signature, psi_ffi_handler, impl);
+ call->impl.fn.impl = impl;
+ return psi_ffi_prep_closure(&call->closure, &call->code, &context->signature, psi_ffi_handler, call);
}
-static inline ffi_status psi_ffi_call_init_callback_closure(struct psi_context *C, struct psi_ffi_call *call, let_callback *cb) {
- return psi_ffi_prep_closure(&call->closure, &call->code, &call->signature, psi_ffi_callback, cb);
+static inline ffi_status psi_ffi_call_init_callback_closure(struct psi_context *C,
+ struct psi_ffi_call *call, struct psi_ffi_call *impl_call,
+ struct psi_let_exp *cb) {
+ call->impl.cb.let_exp = cb;
+ call->impl.cb.impl_call = impl_call;
+ return psi_ffi_prep_closure(&call->closure, &call->code, &call->signature, psi_ffi_callback, call);
}
static inline void psi_ffi_call_free(struct psi_ffi_call *call) {
return padding;
}
-static ffi_type **psi_ffi_struct_type_elements(decl_struct *strct) {
- size_t i, argc = strct->args->count, nels = 0, offset = 0, maxalign = 0;
+static ffi_type **psi_ffi_struct_type_elements(struct psi_decl_struct *strct) {
+ size_t i = 0, argc = psi_plist_count(strct->args), nels = 0, offset = 0, maxalign = 0;
ffi_type **els = calloc(argc + 1, sizeof(*els));
+ struct psi_decl_arg *darg;
- for (i = 0; i < strct->args->count; ++i) {
- decl_arg *darg = strct->args->args[i];
+ while (psi_plist_get(strct->args, i++, &darg)) {
ffi_type *type = malloc(sizeof(*type));
size_t padding;
- memcpy(type, psi_ffi_decl_arg_type(darg), sizeof(*type));
-
- ZEND_ASSERT(type->size == darg->layout->len);
+ *type = *psi_ffi_decl_arg_type(darg);
if (type->alignment > maxalign) {
maxalign = type->alignment;
}
+ assert(type->size == darg->layout->len);
if ((padding = psi_offset_padding(darg->layout->pos - offset, type->alignment))) {
if (nels + padding + 1 > argc) {
argc += padding;
nels += padding;
offset += padding;
}
- ZEND_ASSERT(offset == darg->layout->pos);
+ assert(offset == darg->layout->pos);
offset = (offset + darg->layout->len + type->alignment - 1) & ~(type->alignment - 1);
els[nels++] = type;
/* apply struct alignment padding */
offset = (offset + maxalign - 1) & ~(maxalign - 1);
- ZEND_ASSERT(offset <= strct->size);
+ assert(offset <= strct->size);
if (offset < strct->size) {
psi_ffi_struct_type_pad(&els[nels], strct->size - offset);
}
return els;
}
-static inline ffi_type *psi_ffi_decl_type(decl_type *type) {
- decl_type *real = real_decl_type(type);
+static inline ffi_type *psi_ffi_decl_type(struct psi_decl_type *type) {
+ struct psi_decl_type *real = psi_decl_type_get_real(type);
switch (real->type) {
case PSI_T_STRUCT:
return real->real.strct->engine.type;
case PSI_T_UNION:
- return psi_ffi_decl_arg_type(real->real.unn->args->args[0]);
+ {
+ struct psi_decl_arg *arg;
+ psi_plist_get(real->real.unn->args, 0, &arg);
+ return psi_ffi_decl_arg_type(arg);
+ }
default:
return psi_ffi_token_type(real->type);
}
}
-static inline ffi_type *psi_ffi_decl_arg_type(decl_arg *darg) {
+static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg) {
if (darg->var->pointer_level) {
return &ffi_type_pointer;
} else {
C->context = psi_ffi_context_init(NULL);
}
-static inline void psi_ffi_destroy_callbacks(struct psi_context *C, let_val *let_val) {
- let_callback *cb;
- let_func *fn = NULL;
+static inline void psi_ffi_destroy_callbacks(struct psi_context *C, struct psi_let_exp *let_exp) {
+ struct psi_let_callback *cb;
+ struct psi_let_func *fn = NULL;
- switch (let_val->kind) {
+ switch (let_exp->kind) {
case PSI_LET_CALLBACK:
- cb = let_val->data.callback;
+ cb = let_exp->data.callback;
- if (cb->decl && cb->decl->call.info) {
- psi_ffi_call_free(cb->decl->call.info);
+ if (cb->decl && cb->decl->info) {
+ psi_ffi_call_free(cb->decl->info);
}
fn = cb->func;
/* no break */
case PSI_LET_FUNC:
if (!fn) {
- fn = let_val->data.func;
+ fn = let_exp->data.func;
}
if (fn->inner) {
- size_t i;
+ size_t i = 0;
+ struct psi_let_exp *cb;
- for (i = 0; i < fn->inner->count; ++i) {
- psi_ffi_destroy_callbacks(C, fn->inner->vals[i]);
+ while (psi_plist_get(fn->inner, i++, &cb)) {
+ psi_ffi_destroy_callbacks(C, cb);
}
}
break;
static void psi_ffi_dtor(struct psi_context *C)
{
if (C->decls) {
- size_t i;
-
- for (i = 0; i < C->decls->count; ++i) {
- decl *decl = C->decls->list[i];
+ size_t i = 0;
+ struct psi_decl *decl;
- if (decl->call.info) {
- psi_ffi_call_free(decl->call.info);
+ while (psi_plist_get(C->decls, i++, &decl)) {
+ if (decl->info) {
+ psi_ffi_call_free(decl->info);
}
}
}
if (C->impls) {
- size_t i, j;
-
- for (i = 0; i < C->impls->count; ++i) {
- impl *impl = C->impls->list[i];
+ size_t i = 0;
+ struct psi_impl *impl;
- for (j = 0; j < impl->stmts->let.count; ++j) {
- let_stmt *let = impl->stmts->let.list[j];
+ while (psi_plist_get(C->impls, i++, &impl)) {
+ size_t j = 0;
+ struct psi_let_stmt *let;
- if (let->val && let->val->kind == PSI_LET_CALLBACK) {
- let_callback *cb = let->val->data.callback;
-
- if (cb->decl && cb->decl->call.info) {
- psi_ffi_call_free(cb->decl->call.info);
- }
- }
+ while (psi_plist_get(impl->stmts.let, j++, &let)) {
+ psi_ffi_destroy_callbacks(C, let->exp);
}
}
}
psi_ffi_context_free((void *) &C->context);
}
-static inline void psi_ffi_compile_callbacks(struct psi_context *C, let_val *let_val) {
+static inline void psi_ffi_compile_callbacks(struct psi_context *C,
+ struct psi_ffi_call *impl_call, struct psi_let_exp *let_exp) {
struct psi_ffi_call *call;
- let_callback *cb;
- let_func *fn = NULL;
+ struct psi_let_callback *cb;
+ struct psi_let_func *fn = NULL;
- switch (let_val->kind) {
+ switch (let_exp->kind) {
case PSI_LET_CALLBACK:
- cb = let_val->data.callback;
+ cb = let_exp->data.callback;
if ((call = psi_ffi_call_alloc(C, cb->decl))) {
- if (FFI_OK != psi_ffi_call_init_callback_closure(C, call, cb)) {
+ if (FFI_OK != psi_ffi_call_init_callback_closure(C, call, impl_call, let_exp)) {
psi_ffi_call_free(call);
break;
}
- cb->decl->call.sym = call->code;
+ cb->decl->sym = call->code;
}
fn = cb->func;
/* no break */
case PSI_LET_FUNC:
if (!fn) {
- fn = let_val->data.func;
+ fn = let_exp->data.func;
}
if (fn->inner) {
- size_t i;
+ size_t i = 0;
+ struct psi_let_exp *inner_let;
- for (i = 0; i < fn->inner->count; ++i) {
- psi_ffi_compile_callbacks(C, fn->inner->vals[i]);
+ while (psi_plist_get(fn->inner, i++, &inner_let)) {
+ psi_ffi_compile_callbacks(C, impl_call, inner_let);
}
}
break;
static zend_function_entry *psi_ffi_compile(struct psi_context *C)
{
- size_t c, i, j = 0;
+ size_t i = 0, d = 0, nf = 0;
+ struct psi_impl *impl;
+ struct psi_decl *decl;
zend_function_entry *zfe;
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];
+ zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
+
+ while (psi_plist_get(C->impls, i++, &impl)) {
+ size_t l = 0;
+ struct psi_let_stmt *let;
struct psi_ffi_call *call;
- impl *impl = C->impls->list[i];
+ zend_function_entry *zf = &zfe[nf];
if (!impl->decl) {
continue;
}
zf->fname = impl->func->name + (impl->func->name[0] == '\\');
- zf->num_args = impl->func->args->count;
zf->handler = call->code;
+ zf->num_args = psi_plist_count(impl->func->args);
zf->arg_info = psi_internal_arginfo(impl);
- ++j;
+ ++nf;
- for (c = 0; c < impl->stmts->let.count; ++c) {
- psi_ffi_compile_callbacks(C, impl->stmts->let.list[c]->val);
+ while (psi_plist_get(impl->stmts.let, l++, &let)) {
+ psi_ffi_compile_callbacks(C, call, let->exp);
}
}
- for (i = 0; i < C->decls->count; ++i) {
- decl *decl = C->decls->list[i];
-
- if (decl->call.info) {
+ while (psi_plist_get(C->decls, d++, &decl)) {
+ if (decl->info) {
continue;
}
return zfe;
}
-static void psi_ffi_call(struct psi_context *C, decl_callinfo *decl_call, impl_vararg *va) {
- struct psi_ffi_call *call = decl_call->info;
+static void psi_ffi_call(struct psi_context *C, struct psi_call_frame *frame, struct psi_decl *decl, void *rval, void **args) {
+ struct psi_ffi_call *info = decl->info;
+ struct psi_call_frame *prev = info->impl.fn.frame;
- if (va) {
- ffi_status rc;
- ffi_cif signature;
- size_t i, nfixedargs = decl_call->argc, ntotalargs = nfixedargs + va->args->count;
- void **params = calloc(2 * ntotalargs + 2, sizeof(void *));
+ info->impl.fn.frame = frame;
+ ffi_call(&info->signature, FFI_FN(decl->sym), rval, args);
+ info->impl.fn.frame = prev;
+}
- for (i = 0; i < nfixedargs; ++i) {
- params[i] = call->params[i];
- params[i + ntotalargs + 1] = call->params[i + nfixedargs + 1];
- }
- for (i = 0; i < va->args->count; ++i) {
- params[nfixedargs + i] = psi_ffi_impl_type(va->types[i]);
- params[nfixedargs + i + ntotalargs + 1] = &va->values[i];
- }
-#ifdef PSI_HAVE_FFI_PREP_CIF_VAR
- rc = ffi_prep_cif_var(&signature, call->signature.abi,
- nfixedargs, ntotalargs,
- call->signature.rtype, (ffi_type **) params);
-#else
- /* FIXME: test in config.m4; assume we can just call anyway */
- rc = ffi_prep_cif(&signature, call->signature.abi, ntotalargs,
- call->signature.rtype, (ffi_type **) params);
-#endif
- ZEND_ASSERT(FFI_OK == rc);
- ffi_call(&signature, FFI_FN(decl_call->sym), *decl_call->rval, ¶ms[ntotalargs + 1]);
- free(params);
- } else {
- ffi_call(&call->signature, FFI_FN(decl_call->sym), *decl_call->rval, decl_call->args);
+static void psi_ffi_call_va(struct psi_context *C, struct psi_call_frame *frame, struct psi_decl *decl, void *rval, void **args,
+ size_t va_count, void **va_types) {
+ ffi_cif signature;
+ struct psi_ffi_call *info = decl->info;
+ struct psi_call_frame *prev = info->impl.fn.frame;
+ size_t argc = psi_plist_count(decl->args);
+ ffi_type **param_types = ecalloc(argc + va_count + 1, sizeof(ffi_type *));
+
+ memcpy(param_types, info->params, argc * sizeof(ffi_type *));
+ memcpy(param_types + argc, va_types, va_count * sizeof(ffi_type *));
+
+ psi_ffi_prep_va(&info->signature, &signature, argc, va_count, param_types);
+ info->impl.fn.frame = frame;
+ ffi_call(&signature, FFI_FN(decl->sym), rval, args);
+ info->impl.fn.frame = prev;
+ efree(param_types);
+}
+
+static void *psi_ffi_query(struct psi_context *C, enum psi_context_query q, void *arg) {
+ switch (q) {
+ case PSI_CONTEXT_QUERY_SELF:
+ return "ffi";
+ case PSI_CONTEXT_QUERY_TYPE:
+ return psi_ffi_impl_type(*(token_t *) arg);
}
+ return NULL;
}
static struct psi_context_ops ops = {
psi_ffi_dtor,
psi_ffi_compile,
psi_ffi_call,
+ psi_ffi_call_va,
+ psi_ffi_query,
};
struct psi_context_ops *psi_libffi_ops(void)
-#ifndef _PSI_LIBFFI_H
-#define _PSI_LIBFFI_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_LIBFFI_H
+#define PSI_LIBFFI_H
#include "context.h"
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include "context.h"
+#include "call.h"
#include "php.h"
#ifdef HAVE_LIBJIT
-#include "php_psi.h"
-#include "libjit.h"
-#include "engine.h"
-
#include <jit/jit.h>
-static void psi_jit_handler(jit_type_t _sig, void *_result, void **_args, void *_data)
-{
- psi_call(*(zend_execute_data **)_args[0], *(zval **)_args[1], _data);
-}
+static inline jit_type_t psi_jit_decl_arg_type(struct psi_decl_arg *darg);
-static void psi_jit_callback(jit_type_t _sig, void *_result, void **_args, void *_data)
+static inline jit_abi_t psi_jit_abi(const char *convention)
{
- psi_callback(_data, _result, jit_type_num_params(_sig), _args);
-}
-
-static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg);
-
-static inline jit_abi_t psi_jit_abi(const char *convention) {
return jit_abi_cdecl;
}
-static inline jit_type_t psi_jit_token_type(token_t t) {
+static inline jit_type_t psi_jit_token_type(token_t t)
+{
switch (t) {
default:
ZEND_ASSERT(0);
return jit_type_void_ptr;
}
}
-static inline jit_type_t psi_jit_impl_type(token_t impl_type) {
+static inline jit_type_t psi_jit_impl_type(token_t impl_type)
+{
switch (impl_type) {
case PSI_T_BOOL:
return jit_type_sbyte;
case PSI_T_FLOAT:
case PSI_T_DOUBLE:
return jit_type_sys_double;
- EMPTY_SWITCH_DEFAULT_CASE();
+ EMPTY_SWITCH_DEFAULT_CASE()
+ ;
}
return NULL;
}
-static void psi_jit_struct_type_dtor(void *type) {
+static void psi_jit_struct_type_dtor(void *type)
+{
jit_type_t strct = type;
jit_type_free(strct);
}
-static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding) {
+static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding)
+{
size_t i;
for (i = 0; i < padding; ++i) {
return padding;
}
-static unsigned psi_jit_struct_type_elements(decl_struct *strct, jit_type_t **fields) {
- size_t i, argc = strct->args->count, nels = 0, offset = 0, maxalign;
+static unsigned psi_jit_struct_type_elements(struct psi_decl_struct *strct,
+ jit_type_t **fields)
+{
+ size_t i = 0, argc = psi_plist_count(strct->args), nels = 0, offset = 0,
+ maxalign;
+ struct psi_decl_arg *darg;
+
*fields = calloc(argc + 1, sizeof(*fields));
- for (i = 0; i < strct->args->count; ++i) {
- decl_arg *darg = strct->args->args[i];
+ while (psi_plist_get(strct->args, i++, &darg)) {
jit_type_t type = jit_type_copy(psi_jit_decl_arg_type(darg));
size_t padding, alignment;
- ZEND_ASSERT(jit_type_get_size(type) == darg->layout->len);
-
if ((alignment = jit_type_get_alignment(type)) > maxalign) {
maxalign = alignment;
}
+ assert(jit_type_get_size(type) == darg->layout->len);
if ((padding = psi_offset_padding(darg->layout->pos - offset, alignment))) {
if (nels + padding > argc) {
argc += padding;
nels += padding;
offset += padding;
}
- ZEND_ASSERT(offset == darg->layout->pos);
+ assert(offset == darg->layout->pos);
- offset = (offset + darg->layout->len + alignment - 1) & ~(alignment - 1);
+ offset = (offset + darg->layout->len + alignment - 1)
+ & ~(alignment - 1);
(*fields)[nels++] = type;
}
return nels;
}
-static inline jit_type_t psi_jit_decl_type(decl_type *type) {
- decl_type *real = real_decl_type(type);
+static inline jit_type_t psi_jit_decl_type(struct psi_decl_type *type)
+{
+ struct psi_decl_type *real = psi_decl_type_get_real(type);
switch (real->type) {
case PSI_T_STRUCT:
return real->real.strct->engine.type;
case PSI_T_UNION:
- return psi_jit_decl_arg_type(real->real.unn->args->args[0]);
+ {
+ struct psi_decl_arg *arg;
+ psi_plist_get(real->real.unn->args, 0, &arg);
+ return psi_jit_decl_arg_type(arg);
+ }
default:
return psi_jit_token_type(real->type);
}
}
-static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) {
+static inline jit_type_t psi_jit_decl_arg_type(struct psi_decl_arg *darg)
+{
if (darg->var->pointer_level) {
return jit_type_void_ptr;
} else {
};
struct psi_jit_call {
+ struct psi_context *context;
+ union {
+ struct {
+ struct psi_impl *impl;
+ struct psi_call_frame *frame;
+ } fn;
+ struct {
+ struct psi_let_exp *let_exp;
+ struct psi_jit_call *impl_call;
+ } cb;
+ } impl;
void *closure;
jit_type_t signature;
- void *params[1]; /* [type1, type2, NULL, arg1, arg2] ... */
+ void *params[1]; /* [type1, type2, ... ] */
};
-static inline struct psi_jit_call *psi_jit_call_alloc(struct psi_context *C, decl *decl) {
- size_t i, c = decl->args ? decl->args->count : 0;
+static void psi_jit_handler(jit_type_t sig, void *result, void **args, void *data)
+{
+ struct psi_jit_call *call = data;
+
+ psi_context_call(call->context, *(zend_execute_data **)args[0], *(zval **) args[1], call->impl.fn.impl);
+}
+
+static void psi_jit_callback(jit_type_t sig, void *result, void **args,
+ void *data)
+{
+ struct psi_jit_call *call = data, *impl_call = call->impl.cb.impl_call;
+ struct psi_call_frame_callback cbdata;
+
+ cbdata.cb = call->impl.cb.let_exp;
+ cbdata.argc = jit_type_num_params(sig);
+ cbdata.argv = args;
+ cbdata.rval = result;
+
+ psi_call_frame_do_callback(impl_call->impl.fn.frame, &cbdata);
+}
+
+static inline struct psi_jit_call *psi_jit_call_alloc(struct psi_context *C,
+ struct psi_decl *decl)
+{
+ size_t i, c = psi_plist_count(decl->args);
struct psi_jit_call *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
+ struct psi_decl_arg *arg;
- for (i = 0; i < c; ++i) {
- call->params[i] = psi_jit_decl_arg_type(decl->args->args[i]);
+ decl->info = call;
+ call->context = C;
+ for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
+ call->params[i] = psi_jit_decl_arg_type(arg);
}
call->params[c] = NULL;
- decl->call.info = call;
- decl->call.rval = &decl->func->ptr;
- decl->call.argc = c;
- decl->call.args = (void **) &call->params[c+1];
-
call->signature = jit_type_create_signature(
psi_jit_abi(decl->abi->convention),
psi_jit_decl_arg_type(decl->func),
- (jit_type_t *) call->params, c, 1);
- ZEND_ASSERT(call->signature);
+ (jit_type_t *) call->params,
+ c, 1);
+ assert(call->signature);
return call;
}
-static inline void *psi_jit_call_init_closure(struct psi_context *C, struct psi_jit_call *call, impl *impl) {
+static inline void *psi_jit_call_init_closure(struct psi_context *C,
+ struct psi_jit_call *call, struct psi_impl *impl)
+{
struct psi_jit_context *context = C->context;
+
+ call->impl.fn.impl = impl;
return call->closure = jit_closure_create(context->jit, context->signature,
- &psi_jit_handler, impl);
+ &psi_jit_handler, call);
}
-static inline void *psi_jit_call_init_callback_closure(struct psi_context *C, struct psi_jit_call *call, let_callback *cb) {
+static inline void *psi_jit_call_init_callback_closure(struct psi_context *C,
+ struct psi_jit_call *call, struct psi_jit_call *impl_call,
+ struct psi_let_exp *cb)
+{
struct psi_jit_context *context = C->context;
+
+ call->impl.cb.let_exp = cb;
+ call->impl.cb.impl_call = impl_call;
+
return call->closure = jit_closure_create(context->jit, call->signature,
- &psi_jit_callback, cb);
+ &psi_jit_callback, call);
}
-static inline void psi_jit_call_free(struct psi_jit_call *call) {
+static inline void psi_jit_call_free(struct psi_jit_call *call)
+{
jit_type_free(call->signature);
free(call);
}
-static inline struct psi_jit_context *psi_jit_context_init(struct psi_jit_context *L) {
- jit_type_t params[] = {
- jit_type_void_ptr,
- jit_type_void_ptr
- };
+static inline struct psi_jit_context *psi_jit_context_init(
+ struct psi_jit_context *L)
+{
+ jit_type_t params[] = {jit_type_void_ptr, jit_type_void_ptr};
if (!L) {
L = malloc(sizeof(*L));
return L;
}
-static inline void psi_jit_context_dtor(struct psi_jit_context *L) {
+static inline void psi_jit_context_dtor(struct psi_jit_context *L)
+{
jit_type_free(L->signature);
jit_context_destroy(L->jit);
}
-static inline void psi_jit_context_free(struct psi_jit_context **L) {
+static inline void psi_jit_context_free(struct psi_jit_context **L)
+{
if (*L) {
psi_jit_context_dtor(*L);
free(*L);
C->context = psi_jit_context_init(NULL);
}
-static inline void psi_jit_destroy_callbacks(struct psi_context *C, let_val *let_val) {
- let_callback *cb;
- let_func *fn = NULL;
+static inline void psi_jit_destroy_callbacks(struct psi_context *C,
+ struct psi_let_exp *let_exp)
+{
+ struct psi_let_callback *cb;
+ struct psi_let_func *fn = NULL;
- switch (let_val->kind) {
+ switch (let_exp->kind) {
case PSI_LET_CALLBACK:
- cb = let_val->data.callback;
+ cb = let_exp->data.callback;
- if (cb->decl && cb->decl->call.info) {
- psi_jit_call_free(cb->decl->call.info);
+ if (cb->decl && cb->decl->info) {
+ psi_jit_call_free(cb->decl->info);
}
fn = cb->func;
/* no break */
case PSI_LET_FUNC:
if (!fn) {
- fn = let_val->data.func;
+ fn = let_exp->data.func;
}
if (fn->inner) {
- size_t i;
+ size_t i = 0;
+ struct psi_let_exp *inner_let;
- for (i = 0; i < fn->inner->count; ++i) {
- psi_jit_destroy_callbacks(C, fn->inner->vals[i]);
+ while (psi_plist_get(fn->inner, i++, &inner_let)) {
+ psi_jit_destroy_callbacks(C, inner_let);
}
}
break;
static void psi_jit_dtor(struct psi_context *C)
{
if (C->decls) {
- size_t i;
+ size_t i = 0;
+ struct psi_decl *decl;
- for (i = 0; i < C->decls->count; ++i) {
- decl *decl = C->decls->list[i];
-
- if (decl->call.info) {
- psi_jit_call_free(decl->call.info);
+ while (psi_plist_get(C->decls, i++, &decl)) {
+ if (decl->info) {
+ psi_jit_call_free(decl->info);
}
}
}
if (C->impls) {
- size_t i, j;
+ size_t i = 0;
+ struct psi_impl *impl;
- for (i = 0; i < C->impls->count; ++i) {
- impl *impl = C->impls->list[i];
+ while (psi_plist_get(C->impls, i++, &impl)) {
+ size_t l = 0;
+ struct psi_let_stmt *let;
- for (j = 0; j < impl->stmts->let.count; ++j) {
- psi_jit_destroy_callbacks(C, impl->stmts->let.list[j]->val);
+ while (psi_plist_get(impl->stmts.let, l++, &let)) {
+ psi_jit_destroy_callbacks(C, let->exp);
}
}
}
psi_jit_context_free((void *) &C->context);
}
-static inline void psi_jit_compile_callbacks(struct psi_context *C, let_val *let_val) {
+static inline void psi_jit_compile_callbacks(struct psi_context *C,
+ struct psi_jit_call *impl_call, struct psi_let_exp *let_exp)
+{
struct psi_jit_call *call;
- let_callback *cb;
- let_func *fn = NULL;
+ struct psi_let_callback *cb;
+ struct psi_let_func *fn = NULL;
- switch (let_val->kind) {
+ switch (let_exp->kind) {
case PSI_LET_CALLBACK:
- cb = let_val->data.callback;
+ cb = let_exp->data.callback;
if ((call = psi_jit_call_alloc(C, cb->decl))) {
- if (!psi_jit_call_init_callback_closure(C, call, cb)) {
+ if (!psi_jit_call_init_callback_closure(C, call, impl_call, let_exp)) {
psi_jit_call_free(call);
break;
}
- cb->decl->call.sym = call->closure;
+ cb->decl->sym = call->closure;
}
fn = cb->func;
/* no break */
case PSI_LET_FUNC:
if (!fn) {
- fn = let_val->data.func;
+ fn = let_exp->data.func;
}
if (fn->inner) {
- size_t i;
+ size_t i = 0;
+ struct psi_let_exp *inner_let;
- for (i = 0; i < fn->inner->count; ++i) {
- psi_jit_compile_callbacks(C, fn->inner->vals[i]);
+ while (psi_plist_get(fn->inner, i++, &inner_let)) {
+ psi_jit_compile_callbacks(C, impl_call, inner_let);
}
}
break;
static zend_function_entry *psi_jit_compile(struct psi_context *C)
{
- size_t c, i, j = 0;
+ size_t i = 0, d = 0, nf = 0;
+ struct psi_impl *impl;
+ struct psi_decl *decl;
zend_function_entry *zfe;
struct psi_jit_context *ctx = C->context;
return NULL;
}
- zfe = calloc(C->impls->count + 1, sizeof(*zfe));
+ zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
jit_context_build_start(ctx->jit);
- for (i = 0; i < C->impls->count; ++i) {
- zend_function_entry *zf = &zfe[j];
+ while (psi_plist_get(C->impls, i++, &impl)) {
+ zend_function_entry *zf = &zfe[nf];
struct psi_jit_call *call;
- impl *impl = C->impls->list[i];
+ size_t l = 0;
+ struct psi_let_stmt *let;
if (!impl->decl) {
continue;
}
zf->fname = impl->func->name + (impl->func->name[0] == '\\');
- zf->num_args = impl->func->args->count;
zf->handler = call->closure;
+ zf->num_args = psi_plist_count(impl->func->args);
zf->arg_info = psi_internal_arginfo(impl);
- ++j;
+ ++nf;
- for (c = 0; c < impl->stmts->let.count; ++c) {
- psi_jit_compile_callbacks(C, impl->stmts->let.list[c]->val);
+ while (psi_plist_get(impl->stmts.let, l++, &let)) {
+ psi_jit_compile_callbacks(C, call, let->exp);
}
}
- for (i = 0; i < C->decls->count; ++i) {
- decl *decl = C->decls->list[i];
-
- if (decl->call.info) {
+ while (psi_plist_get(C->decls, d++, &decl)) {
+ if (decl->info) {
continue;
}
return zfe;
}
-static void psi_jit_call(struct psi_context *C, decl_callinfo *decl_call, impl_vararg *va) {
- struct psi_jit_call *call = decl_call->info;
+static void psi_jit_call(struct psi_context *C, struct psi_call_frame *frame,
+ struct psi_decl *decl, void *rval, void **args)
+{
+ struct psi_jit_call *call = decl->info;
+ struct psi_call_frame *prev = call->impl.fn.frame;
- if (va) {
- jit_type_t signature;
- size_t i, nfixedargs = decl_call->argc, ntotalargs = nfixedargs + va->args->count;
- void **params = calloc(2 * ntotalargs + 2, sizeof(void *));
+ call->impl.fn.frame = frame;
+ jit_apply(call->signature, decl->sym, args, psi_plist_count(decl->args), rval);
+ call->impl.fn.frame = prev;
+}
- for (i = 0; i < nfixedargs; ++i) {
- params[i] = call->params[i];
- params[i + ntotalargs + 1] = call->params[i + nfixedargs + 1];
- }
- for (i = 0; i < va->args->count; ++i) {
- params[nfixedargs + i] = psi_jit_impl_type(va->types[i]);
- params[nfixedargs + i + ntotalargs + 1] = &va->values[i];
- }
+static void psi_jit_call_va(struct psi_context *C, struct psi_call_frame *frame,
+ struct psi_decl *decl, void *rval, void **args, size_t va_count,
+ void **va_types)
+{
+ struct psi_jit_call *info = decl->info;
+ struct psi_call_frame *prev = info->impl.fn.frame;
+ size_t argc = psi_plist_count(decl->args);
+ jit_type_t signature;
+ jit_type_t *param_types = ecalloc(argc + va_count + 1, sizeof(jit_type_t));
- signature = jit_type_create_signature(
- jit_type_get_abi(call->signature),
- jit_type_get_return(call->signature),
- (jit_type_t *) params, ntotalargs, 1);
- ZEND_ASSERT(signature);
+ memcpy(param_types, info->params, argc * sizeof(jit_type_t));
+ memcpy(param_types + argc, va_types, va_count * sizeof(jit_type_t));
- jit_apply(signature, decl_call->sym, ¶ms[ntotalargs + 1],
- nfixedargs, *decl_call->rval);
- jit_type_free(signature);
- free(params);
- } else {
- jit_apply(call->signature, decl_call->sym, decl_call->args,
- decl_call->argc, *decl_call->rval);
+ signature = jit_type_create_signature(jit_abi_vararg,
+ jit_type_get_return(info->signature), param_types, argc + va_count,
+ 1);
+ ZEND_ASSERT(signature);
+
+ info->impl.fn.frame = frame;
+ jit_apply(signature, decl->sym, args, argc, rval);
+ info->impl.fn.frame = prev;
+ jit_type_free(signature);
+ efree(param_types);
+}
+
+static void *psi_jit_query(struct psi_context *C, enum psi_context_query q,
+ void *arg)
+{
+ switch (q) {
+ case PSI_CONTEXT_QUERY_SELF:
+ return "jit";
+ case PSI_CONTEXT_QUERY_TYPE:
+ return psi_jit_impl_type(*(token_t *) arg);
}
+ return NULL;
}
-static struct psi_context_ops ops = {
- psi_jit_init,
- psi_jit_dtor,
- psi_jit_compile,
- psi_jit_call,
-};
+static struct psi_context_ops ops = {psi_jit_init, psi_jit_dtor,
+ psi_jit_compile, psi_jit_call, psi_jit_call_va, psi_jit_query};
struct psi_context_ops *psi_libjit_ops(void)
{
-#ifndef _PSI_LIBJIT_H
-#define _PSI_LIBJIT_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_LIBJIT_H
+#define PSI_LIBJIT_H
#include "context.h"
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include "data.h"
+#include "calc.h"
#include "php.h"
#include "php_psi.h"
-#include "parser.h"
-#include "marshal.h"
-#include "engine.h"
-#include "calc.h"
-void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val)
+#include "Zend/zend_interfaces.h"
+#include "ext/spl/spl_iterators.h"
+
+zend_long psi_zval_count(zval *zvalue)
+{
+ /* mimic PHP count() */
+ zend_long count;
+ zval retval;
+
+ switch (Z_TYPE_P(zvalue)) {
+ default:
+ count = 1;
+ break;
+ case IS_NULL:
+ count = 0;
+ break;
+ case IS_ARRAY:
+ count = zend_array_count(Z_ARRVAL_P(zvalue));
+ break;
+ case IS_OBJECT:
+ count = 1;
+ if (Z_OBJ_HT_P(zvalue)->count_elements) {
+ if (SUCCESS == Z_OBJ_HT_P(zvalue)->count_elements(zvalue, &count)) {
+ break;
+ }
+ }
+
+ if (instanceof_function(Z_OBJCE_P(zvalue), spl_ce_Countable)) {
+ zend_call_method_with_0_params(zvalue, NULL, NULL, "count", &retval);
+ if (Z_TYPE(retval) != IS_UNDEF) {
+ count = zval_get_long(&retval);
+ zval_ptr_dtor(&retval);
+ }
+ }
+ break;
+ }
+
+ return count;
+}
+
+int psi_internal_type(struct psi_impl_type *type)
+{
+ switch (type->type) {
+ case PSI_T_BOOL:
+ return _IS_BOOL;
+ case PSI_T_INT:
+ return IS_LONG;
+ case PSI_T_FLOAT:
+ case PSI_T_DOUBLE:
+ return IS_DOUBLE;
+ case PSI_T_STRING:
+ return IS_STRING;
+ case PSI_T_ARRAY:
+ return IS_ARRAY;
+ default:
+ return 0;
+ }
+}
+
+zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl)
+{
+ size_t i = 0, argc = psi_plist_count(impl->func->args);
+ zend_internal_arg_info *aip;
+ zend_internal_function_info *fi;
+ struct psi_impl_arg *iarg;
+
+ aip = calloc(argc + 1 + !!impl->func->vararg, sizeof(*aip));
+
+ fi = (zend_internal_function_info *) &aip[0];
+ fi->allow_null = 1;
+ fi->required_num_args = psi_impl_num_min_args(impl);
+ fi->return_reference = impl->func->return_reference;
+ fi->type_hint = psi_internal_type(impl->func->return_type);
+
+ if (impl->func->vararg) {
+ struct psi_impl_arg *vararg = impl->func->vararg;
+ zend_internal_arg_info *ai = &aip[argc];
+
+ ai->name = vararg->var->name;
+ ai->allow_null = 1;
+ ai->type_hint = psi_internal_type(vararg->type);
+ if (vararg->var->reference) {
+ ai->pass_by_reference = 1;
+ }
+ ai->is_variadic = 1;
+ }
+
+ while (psi_plist_get(impl->func->args, i++, &iarg)) {
+ zend_internal_arg_info *ai = &aip[i];
+
+ ai->name = iarg->var->name;
+ ai->type_hint = psi_internal_type(iarg->type);
+ if (iarg->var->reference) {
+ ai->pass_by_reference = 1;
+ }
+ /* FIXME: if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) */
+ ai->allow_null = 1;
+ }
+
+ return aip;
+}
+
+/*
+ * return void(dvar)
+ */
+void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
{
RETVAL_NULL();
}
-impl_val *psi_let_void(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * ?
+ */
+impl_val *psi_let_void(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
{
return tmp;
}
-void psi_to_zval(zval *return_value, set_value *set, impl_val *ret_val) {
+/*
+ * set $ivar = zval(dvar)
+ */
+void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) {
RETVAL_ZVAL(ret_val->ptr, 1, 0);
}
-impl_val *psi_let_zval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = zval($ivar)
+ */
+impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
{
*to_free = tmp->ptr = emalloc(sizeof(zval));
ZVAL_COPY_VALUE(tmp->ptr, zvalue);
return tmp;
}
-void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val)
+/*
+ * return to_bool(dvar)
+ */
+void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
{
- psi_to_int(return_value, set, ret_val);
+ psi_set_to_int(return_value, set, ret_val, frame);
convert_to_boolean(return_value);
}
return tmp;
}
-impl_val *psi_let_boolval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = boolval($ivar)
+ */
+impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
{
zend_bool boolval;
- token_t real_type = spec ? real_decl_type(spec)->type : PSI_T_UINT8;
+ token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_UINT8;
if (ival && impl_type == PSI_T_BOOL) {
boolval = ival->zend.bval;
RETVAL_LONG(V); \
}
-void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val)
+/*
+ * set $ivar = to_int(*dvar)
+ */
+void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
{
- decl_var *var = set->vars->vars[0];
- token_t t = real_decl_type(var->arg->type)->type;
+ struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
+ token_t t = psi_decl_type_get_real(var->arg->type)->type;
impl_val *v = deref_impl_val(ret_val, var);
switch (t) {
return tmp;
}
-impl_val *psi_let_intval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = intval($ivar)
+ */
+impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
{
zend_long intval;
- token_t real_type = spec ? real_decl_type(spec)->type : PSI_T_LONG;
+ token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_LONG;
if (ival && impl_type == PSI_T_INT) {
intval = ival->zend.lval;
return psi_val_intval(tmp, real_type, intval);
}
-void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val)
+/*
+ * set $ivar = to_float(dvar)
+ */
+void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
{
- decl_var *var = set->vars->vars[0];
- token_t t = real_decl_type(var->arg->type)->type;
+ struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
+ token_t t = psi_decl_type_get_real(var->arg->type)->type;
impl_val *v = deref_impl_val(ret_val, var);
switch (t) {
return tmp;
}
-impl_val *psi_let_floatval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = floatval($ivar)
+ */
+impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
{
double floatval;
- token_t real_type = spec ? real_decl_type(spec)->type : PSI_T_DOUBLE;
+ token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_DOUBLE;
if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) {
floatval = ival->dval;
return psi_val_floatval(tmp, real_type, floatval);
}
-void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val)
+/*
+ * set $ivar = to_string(dvar)
+ */
+void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
{
+ struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
+ impl_val *ptr = deref_impl_val(ret_val, var);
char *str;
- decl_var *var = set->vars->vars[0];
- token_t t = real_decl_type(var->arg->type)->type;
- switch (t) {
- case PSI_T_FLOAT: RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval); break;
- case PSI_T_DOUBLE: RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval); break;
-#ifdef HAVE_LONG_DOUBLE
- case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->ldval); break;
-#endif
- default:
- if (!var->arg->var->pointer_level) {
- RETVAL_STRINGL(&ret_val->cval, 1);
- } else {
- ret_val = deref_impl_val(ret_val, var);
- if (var->arg->var->array_size) {
- str = (char *) ret_val;
- } else {
- str = ret_val->ptr;
- }
- if (str) {
- if (set->num) {
- zend_long n = psi_long_num_exp(set->num, set->outer.val);
- RETVAL_STRINGL(str, n);
- } else {
- RETVAL_STRING(str);
- }
- } else {
- RETVAL_EMPTY_STRING();
- }
- }
- return;
+ if (var->arg->var->array_size) {
+ str = (char *) ptr;
+ } else {
+ str = ptr->ptr;
}
- convert_to_string(return_value);
+ if (str) {
+ RETVAL_STRING(str);
+ } else {
+ RETVAL_EMPTY_STRING();
+ }
}
-impl_val *psi_let_strval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * set $ivar = to_string(dvar, num_exp)
+ */
+void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
+{
+ struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
+ char *str = deref_impl_val(ret_val, var)->ptr;
+
+ if (str) {
+ struct psi_set_exp *sub_exp;
+
+ psi_plist_get(set->inner, 0, &sub_exp);
+ RETVAL_STRINGL(str, psi_long_num_exp(sub_exp->data.num, frame));
+ } else {
+ RETVAL_EMPTY_STRING();
+ }
+}
+
+/*
+ * let dvar = strval($ivar)
+ */
+impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
{
if (ival && impl_type == PSI_T_STRING) {
if (ival->zend.str) {
- /*tmp->ptr = estrndup(ival->zend.str->val, ival->zend.str->len);
- *to_free = tmp->ptr;*/
tmp->ptr = ival->zend.str->val;
} else {
tmp->ptr = "";
return tmp;
}
-impl_val *psi_let_pathval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = pathval($ivar)
+ */
+impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
{
tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free);
if (SUCCESS != php_check_open_basedir(tmp->ptr)) {
return tmp;
}
-impl_val *psi_let_strlen(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = strlen($ivar)
+ */
+impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
{
if (ival && impl_type == PSI_T_STRING) {
if (ival->zend.str) {
return tmp;
}
-void psi_from_zval_ex(void *cb_ctx, impl_val **ptr, decl_arg *spec, token_t cast, zval *zv, void **tmp)
-{
- decl_type *real = real_decl_type(spec->type);
- impl_val *val = *ptr;
-
- switch (real->type) {
- default:
- ZEND_ASSERT(0);
- val->i64 = zval_get_long(zv);
- break;
- case PSI_T_INT8:
- val->i8 = zval_get_long(zv);
- break;
- case PSI_T_UINT8:
- val->u8 = zval_get_long(zv);
- break;
- case PSI_T_INT16:
- val->i16 = zval_get_long(zv);
- break;
- case PSI_T_UINT16:
- val->u16 = zval_get_long(zv);
- break;
- case PSI_T_INT32:
- val->i32 = zval_get_long(zv);
- break;
- case PSI_T_UINT32:
- val->u32 = zval_get_long(zv);
- break;
- case PSI_T_INT64:
- val->i64 = zval_get_long(zv);
- break;
- case PSI_T_UINT64:
- val->u64 = zval_get_long(zv);
- break;
- case PSI_T_FLOAT:
- val->fval = zval_get_double(zv);
- break;
- case PSI_T_DOUBLE:
- val->dval = zval_get_double(zv);
- break;
-#ifdef HAVE_LONG_DOUBLE
- case PSI_T_LONG_DOUBLE:
- val->ldval = zval_get_double(zv);
- break;
-#endif
- case PSI_T_ENUM:
- val->ival = zval_get_long(zv);
- break;
- case PSI_T_STRUCT:
- *tmp = *ptr = psi_array_to_struct_ex(real->real.strct, HASH_OF(zv), psi_from_zval_ex, cb_ctx);
- break;
- case PSI_T_UNION:
- *tmp = *ptr = psi_array_to_union_ex(real->real.unn, HASH_OF(zv), psi_from_zval_ex, cb_ctx);
- break;
- case PSI_T_FUNCTION:
- /*FIXME*/
- val->ptr = NULL;
- break;
- case PSI_T_VOID:
- val->ptr = NULL;
- if (Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), psi_object_get_class_entry())) {
- *ptr = PSI_OBJ(zv, NULL)->data;
- } else {
- zend_string *zs = zval_get_string(zv);
- *tmp = val->ptr = estrndup(zs->val, zs->len);
- zend_string_release(zs);
- }
- break;
- }
+/*
+ * set $ivar = to_array(dvar,
+ * $foo = to_int(d_foo),
+ * $bar = to_string(d_bar),
+ * $baz = to_array(*d_next, ...)
+ */
+void psi_set_to_recursive(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) {
+ set->outer->data.func->handler(return_value, set, r_val, frame);
}
-void *psi_array_to_struct_ex(decl_struct *s, HashTable *arr, psi_marshal_zval cb, void *cb_ctx) {
- 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_arg *darg = s->args->args[i];
- zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
-
- if (entry) {
- impl_val val, *ptr = &val;
- void *tmp = NULL;
-
- memset(&val, 0, sizeof(val));
- cb(cb_ctx, &ptr, darg, /*FIXME*/0, entry, &tmp);
- memcpy(mem + darg->layout->pos, ptr, darg->layout->len);
- if (tmp) {
- ((void **)(mem + s->size))[j++] = tmp;
- }
- }
- }
- return mem;
-}
-
-void *psi_array_to_struct(decl_struct *s, HashTable *arr)
+/*
+ * set $ivar = to_array(dvar, to_string(*dvar));
+ */
+void psi_set_to_array_simple(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
{
- return psi_array_to_struct_ex(s, arr, psi_from_zval_ex, NULL);
-}
+ struct psi_set_exp *sub_exp;
+ struct psi_decl_var *var;
+ impl_val *ret_val;
+ char *ptr;
+ size_t size;
-void *psi_array_to_union_ex(decl_union *u, HashTable *arr, psi_marshal_zval cb, void *cb_ctx) {
- size_t i;
- char *mem = ecalloc(1, u->size + sizeof(void *));
-
- if (arr) for (i = 0; i < u->args->count; ++i) {
- decl_arg *darg = u->args->args[i];
- zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
-
- if (entry) {
- impl_val val, *ptr = &val;
- void *tmp = NULL;
+ array_init(return_value);
- memset(&val, 0, sizeof(val));
- cb(cb_ctx, &ptr, darg, /*FIXME*/0, entry, &tmp);
- memcpy(mem, &val, darg->layout->len);
- if (tmp) {
- ((void **)(mem + u->size))[0] = tmp;
- }
- /* first found entry wins */
- break;
- }
+ var = psi_set_exp_get_decl_var(set);
+ ret_val = deref_impl_val(r_val, var);
+ if ((intptr_t) ret_val <= (intptr_t) 0) {
+ return;
}
- return mem;
-}
+ psi_plist_get(set->inner, 0, &sub_exp);
-void *psi_array_to_union(decl_union *u, HashTable *arr) {
- return psi_array_to_union_ex(u, arr, psi_from_zval_ex, NULL);
-}
+ size = psi_decl_arg_get_size(var->arg);
+ for (ptr = ret_val->ptr; *(void **) ptr; ptr += size) {
+ zval ele;
-void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val) {
- set->outer.set->func->handler(return_value, set, r_val);
+ ZVAL_NULL(&ele);
+ sub_exp->data.func->handler(&ele, sub_exp, (void *) ptr, frame);
+ add_next_index_zval(return_value, &ele);
+ }
}
-void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
+/*
+ * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
+ */
+void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
{
- size_t i;
- decl_var *var = set->vars->vars[0];
- token_t t = real_decl_type(var->arg->type)->type;
- impl_val tmp, *ret_val = deref_impl_val(r_val, var);
+ struct psi_set_exp *sub_exp;
+ struct psi_decl_var *var;
+ impl_val *ret_val;
+ char *ptr;
+ size_t size;
+ zend_long count;
+
+ array_init(return_value);
+ var = psi_set_exp_get_decl_var(set);
+ ret_val = deref_impl_val(r_val, var);
if ((intptr_t) ret_val <= (intptr_t) 0) {
- RETURN_NULL();
+ return;
}
- array_init(return_value);
+ psi_plist_get(set->inner, 0, &sub_exp);
+ count = psi_long_num_exp(sub_exp->data.num, frame);
+ psi_plist_get(set->inner, 1, &sub_exp);
- if (t == PSI_T_STRUCT || t == PSI_T_UNION) {
- // decl_struct *s = real_decl_type(var->arg->type)->strct;
+ for (ptr = (char *) ret_val; 0 < count--; ptr += size) {
+ size = psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp));
+ zval ele;
- if (set->inner && set->inner->count) {
- /* explicit member casts */
- for (i = 0; i < set->inner->count; ++i) {
- set_value *sub_set = set->inner->vals[i];
- decl_var *sub_var = sub_set->vars->vars[0];
+ ZVAL_NULL(&ele);
+ sub_exp->data.func->handler(&ele, sub_exp, (void *) &ptr, frame);
+ add_next_index_zval(return_value, &ele);
+ }
+}
- sub_set->outer.val = ret_val;
+#include "call.h"
- if (sub_var->arg) {
- impl_val *tmp = NULL, *val;
- zval ztmp;
+/*
+ * set $ivar = to_array(dvar,
+ * $foo = to_int(d_foo),
+ * $bar = to_string(d_bar));
+ */
+void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
+{
+ struct psi_set_exp *sub_exp;
+ struct psi_decl_var *var;
+ impl_val *ret_val;
+ size_t i = 0;
- val = struct_member_ref(sub_var->arg, ret_val, &tmp);
- sub_set->func->handler(&ztmp, sub_set, val);
- add_assoc_zval(return_value, sub_var->name, &ztmp);
+ array_init(return_value);
- if (tmp) {
- free(tmp);
- }
- }
- }
- return;
- }
+ var = psi_set_exp_get_decl_var(set);
+ ret_val = deref_impl_val(r_val, var);
+ if ((intptr_t) ret_val <= (intptr_t) 0) {
+ return;
}
- if (var->arg->var->array_size) {
- /* to_array(foo[NUMBER]) */
- for (i = 0; i < var->arg->var->array_size; ++i) {
- size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t);
- impl_val *ptr = iterate(ret_val->ptr, size, i, &tmp);
- zval ele;
-
- switch (t) {
- case PSI_T_FLOAT:
- ZVAL_DOUBLE(&ele, (double) ptr->fval);
- break;
- case PSI_T_DOUBLE:
- ZVAL_DOUBLE(&ele, ptr->dval);
- break;
- default:
- ZVAL_LONG(&ele, ptr->lval);
- break;
- }
-
- add_next_index_zval(return_value, &ele);
- }
- return;
- } else if (set->num) {
- /* to_array(arr_var, num_expr, to_int(*arr_var)) */
- zval ele;
- char *ptr;
- zend_long i, n = psi_long_num_exp(set->num, set->outer.val);
- size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
- set_value *sub_set = set->inner->vals[0];
-
- sub_set->outer.val = set->outer.val;
- for (i = 0; i < n; ++i) {
- ptr = (char *) ret_val->ptr + i * size;
- sub_set->func->handler(&ele, sub_set, (void *) ptr);
- add_next_index_zval(return_value, &ele);
- }
- } else {
- /* to_array(arr_var, to_int(*arr_var)) */
+ while (psi_plist_get(set->inner, i++, &sub_exp)) {
zval ele;
- char *ptr = ret_val->ptr;
- size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
- set_value *sub_set = set->inner->vals[0];
-
- sub_set->outer.val = set->outer.val;
- while (*(void **) ptr) {
- sub_set->func->handler(&ele, sub_set, (void *) ptr);
- add_next_index_zval(return_value, &ele);
- ptr += size;
- }
- }
-}
+ struct psi_decl_var *dvar = psi_set_exp_get_decl_var(sub_exp);
+ struct psi_impl_var *ivar = psi_set_exp_get_impl_var(sub_exp);
+ struct psi_call_frame_symbol *sym;
-impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
-{
- decl_type *real = real_decl_type(spec);
- HashTable *arr;
- zval *zv;
- size_t i, sz;
- decl_arg tmp_arg = {0};
-
- if (impl_type != PSI_T_ARRAY) {
- SEPARATE_ARG_IF_REF(zvalue);
- convert_to_array(zvalue);
- }
- arr = HASH_OF(zvalue);
+ sym = psi_call_frame_fetch_symbol(frame, dvar);
+ sym->ptr = ((char *) ret_val) + dvar->arg->layout->pos;
- switch (real->type) {
- case PSI_T_STRUCT:
- *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
- break;
- case PSI_T_UNION:
- *to_free = tmp = psi_array_to_union(real->real.unn, arr);
- break;
- default:
- sz = psi_t_size(real->type);
- tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
- tmp_arg.type = spec;
- tmp_arg.var = spec_var;
- ZEND_HASH_FOREACH_VAL_IND(arr, zv)
- {
- void *ptr = ((char *) tmp) + (i++ * sz);
- psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
- }
- ZEND_HASH_FOREACH_END();
+ ZVAL_NULL(&ele);
+ psi_set_exp_exec_ex(sub_exp, &ele, sym->ptr, frame);
+ add_assoc_zval(return_value, ivar->name + 1, &ele);
}
-
- return tmp;
}
-impl_val *psi_let_count(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+//impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+//{
+// decl_type *real = real_decl_type(spec);
+// HashTable *arr;
+// zval *zv;
+// size_t i, sz;
+// decl_arg tmp_arg = {0};
+//
+// if (impl_type != PSI_T_ARRAY) {
+// SEPARATE_ARG_IF_REF(zvalue);
+// convert_to_array(zvalue);
+// }
+// arr = HASH_OF(zvalue);
+//
+// switch (real->type) {
+// case PSI_T_STRUCT:
+// *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
+// break;
+// case PSI_T_UNION:
+// *to_free = tmp = psi_array_to_union(real->real.unn, arr);
+// break;
+// default:
+// sz = psi_t_size(real->type);
+// tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
+// tmp_arg.type = spec;
+// tmp_arg.var = spec_var;
+// ZEND_HASH_FOREACH_VAL_IND(arr, zv)
+// {
+// void *ptr = ((char *) tmp) + (i++ * sz);
+// psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
+// }
+// ZEND_HASH_FOREACH_END();
+// }
+//
+// return tmp;
+//}
+
+/*
+ * let dvar = count($ivar)
+ */
+impl_val *psi_let_count(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
{
- return psi_val_intval(tmp, real_decl_type(spec)->type, psi_zval_count(zvalue));
+ return psi_val_intval(tmp, psi_decl_type_get_real(spec)->type, psi_zval_count(zvalue));
}
-
-void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
+/*
+ * set $ivar = to_object(dvar)
+ */
+void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
{
- decl_var *var = set->vars->vars[0];
+ struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
impl_val *ret_val = deref_impl_val(r_val, var);
if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
}
}
-impl_val *psi_let_objval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = objval($ivar)
+ */
+impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
{
psi_object *obj;
-#ifndef _PSI_MARSHAL_H
-#define _PSI_MARSHAL_H
-
-typedef void (*psi_marshal_set)(zval *return_value, set_value *set, impl_val *ret_val);
-typedef impl_val *(*psi_marshal_let)(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-
-void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val);
-void psi_to_array(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_object(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_zval(zval *return_value, set_value *set, impl_val *ret_val);
-
-void *psi_array_to_union(decl_union *u, HashTable *arr);
-void *psi_array_to_struct(decl_struct *s, HashTable *arr);
-
-typedef void (*psi_marshal_zval)(void *cb_ctx, impl_val **ptr, decl_arg *spec, token_t cast, zval *zv, void **tmp);
-
-void psi_from_zval_ex(void *cb_ctx, impl_val **ptr, decl_arg *spec, token_t cast, zval *zv, void **tmp);
-
-void *psi_array_to_struct_ex(decl_struct *s, HashTable *arr, psi_marshal_zval cb, void *cb_ctx);
-void *psi_array_to_union_ex(decl_union *u, HashTable *arr, psi_marshal_zval cb, void *cb_ctx);
-
-impl_val *psi_let_void(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_boolval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_intval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_floatval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_strval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_pathval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_strlen(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_objval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_zval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_count(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free);
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_MARSHAL_H
+#define PSI_MARSHAL_H
+
+#include "impl_val.h"
+#include "Zend/zend_types.h"
+
+struct psi_let_exp;
+struct psi_set_exp;
+struct psi_decl_type;
+struct psi_call_frame;
+struct psi_impl;
+struct psi_impl_type;
+
+zend_long psi_zval_count(zval *zvalue);
+zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl);
+int psi_internal_type(struct psi_impl_type *type);
+
+typedef void (*psi_marshal_set)(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+typedef impl_val *(*psi_marshal_let)(impl_val *tmp, struct psi_decl_type *psi_decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+
+void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_recursive(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame);
+void psi_set_to_array_simple(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+
+impl_val *psi_let_void(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_count(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free);
+
#endif
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
#include "php.h"
#include "php_ini.h"
return psi_class_entry;
}
-void psi_error_wrapper(void *context, struct psi_token *t, int type, const char *msg, ...)
-{
- va_list argv;
- const char *fn = NULL;
- unsigned ln = 0;
-
- if (context) {
- if (PSI_DATA(context)->flags & PSI_PARSER_SILENT) {
- return;
- }
- }
-
- if (t) {
- fn = t->file;
- ln = t->line;
- } else if (zend_is_executing()) {
- fn = zend_get_executed_filename();
- ln = zend_get_executed_lineno();
- } else if (zend_is_compiling()) {
- fn = zend_get_compiled_filename()->val;
- ln = zend_get_compiled_lineno();
- }
-
- va_start(argv, msg);
- psi_verror(type, fn, ln, msg, argv);
- va_end(argv);
-}
-
-void psi_error(int type, const char *fn, unsigned ln, const char *msg, ...)
-{
- va_list argv;
-
- va_start(argv, msg);
- psi_verror(type, fn, ln, msg, argv);
- va_end(argv);
-}
-
-void psi_verror(int type, const char *fn, unsigned ln, const char *msg, va_list argv)
-{
- zend_error_cb(type, fn, ln, msg, argv);
-}
-
static void psi_object_free(zend_object *o)
{
psi_object *obj = PSI_OBJ(NULL, o);
if (obj->data) {
- /* FIXME: how about registering a destructor?
- // free(obj->data); */
+ if (obj->dtor) {
+ obj->dtor(obj->data);
+ }
obj->data = NULL;
}
zend_object_std_dtor(o);
}
-static zend_object *psi_object_init(zend_class_entry *ce)
+zend_object *psi_object_init_ex(zend_class_entry *ce, void *data, void (*dtor)(void *))
{
- psi_object *o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
+ psi_object *o;
+
+ if (!ce) {
+ ce = psi_class_entry;
+ }
+
+ o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
+
+ o->data = data;
+ o->dtor = dtor;
zend_object_std_init(&o->std, ce);
object_properties_init(&o->std, ce);
return &o->std;
}
+zend_object *psi_object_init(zend_class_entry *ce)
+{
+ return psi_object_init_ex(ce, NULL, NULL);
+}
+
ZEND_BEGIN_ARG_INFO_EX(ai_psi_dump, 0, 0, 0)
ZEND_ARG_INFO(0, stream)
ZEND_END_ARG_INFO();
RETURN_FALSE;
}
}
- psi_context_dump(&PSI_G(context), fd);
+ psi_context_dump(PSI_G(context), fd);
}
ZEND_BEGIN_ARG_INFO_EX(ai_psi_validate, 0, 0, 1)
static PHP_FUNCTION(psi_validate) {
zend_string *file;
struct psi_parser P;
+ struct psi_data D = {0};
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "P", &file)) {
return;
}
psi_parser_parse(&P, NULL);
- if (0 == psi_context_validate_data(NULL, PSI_DATA(&P)) && !P.errors) {
- RETVAL_TRUE;
- } else {
- RETVAL_FALSE;
- }
+ psi_data_ctor(&D, P.error, P.flags);
+ RETVAL_BOOL(psi_data_validate(&D, PSI_DATA(&P)) && !P.errors);
+ psi_data_dtor(&D);
+
psi_parser_dtor(&P);
}
{
struct psi_context_ops *ops = NULL;
zend_class_entry ce = {0};
- unsigned flags = psi_check_env("PSI_DEBUG") ? PSI_PARSER_DEBUG : (
- psi_check_env("PSI_SILENT") ? PSI_PARSER_SILENT : 0);
+ unsigned flags = 0;
+
+ if (psi_check_env("PSI_DEBUG")) {
+ flags |= PSI_DEBUG;
+ }
+ if (psi_check_env("PSI_SILENT")) {
+ flags |= PSI_SILENT;
+ }
REGISTER_INI_ENTRIES();
return FAILURE;
}
- psi_context_init(&PSI_G(context), ops, psi_error_wrapper, flags);
- psi_context_build(&PSI_G(context), PSI_G(directory));
+ PSI_G(context) = psi_context_init(NULL, ops, psi_error_wrapper, flags);
+ psi_context_build(PSI_G(context), PSI_G(directory));
if (psi_check_env("PSI_DUMP")) {
- psi_context_dump(&PSI_G(context), STDOUT_FILENO);
+ psi_context_dump(PSI_G(context), STDOUT_FILENO);
}
return SUCCESS;
static PHP_MSHUTDOWN_FUNCTION(psi)
{
- psi_context_dtor(&PSI_G(context));
+ psi_context_free(&PSI_G(context));
UNREGISTER_INI_ENTRIES();
static PHP_MINFO_FUNCTION(psi)
{
php_info_print_table_start();
- php_info_print_table_header(2, "psi support", "enabled");
+ php_info_print_table_header(2, "PSI Support", "enabled");
+ php_info_print_table_row(2, "Extension Version", PHP_PSI_VERSION);
php_info_print_table_end();
+ php_info_print_table_start();
+ php_info_print_table_header(3, "Used Library", "Compiled", "Linked");
+ php_info_print_table_row(3, "libffi",
+#ifndef PHP_PSI_LIBFFI_VERSION
+# define PHP_PSI_LIBFFI_VERSION "unknown"
+#endif
+#ifdef HAVE_LIBFFI
+ PHP_PSI_LIBFFI_VERSION, "unknown"
+#else
+ "disabled", "disabled"
+#endif
+ );
+ php_info_print_table_row(3, "libjit",
+#ifdef HAVE_LIBJIT
+ "unknown", "unknown"
+#else
+ "disabled", "disabled"
+#endif
+ );
DISPLAY_INI_ENTRIES();
}
-#ifndef _PSI_PARSER_H
-#define _PSI_PARSER_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_PARSER_H
+#define PSI_PARSER_H
-#include <stdio.h>
-#include <stdlib.h>
#include <stdarg.h>
-#include <string.h>
-
-#include "parser_proc.h"
#define BSIZE 256
char *cur, *tok, *lim, *eof, *ctx, *mrk, buf[BSIZE];
};
-#define PSI_PARSER_DEBUG 0x1
-#define PSI_PARSER_SILENT 0x2
-
struct psi_parser *psi_parser_init(struct psi_parser *P, const char *filename, psi_error_cb error, unsigned flags);
void psi_parser_syntax_error(struct psi_parser *P, const char *fn, size_t ln, const char *msg, ...);
ssize_t psi_parser_fill(struct psi_parser *P, size_t n);
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
-#include <stddef.h>
-#include <stdio.h>
+#include "php_psi_stdinc.h"
#include <assert.h>
-#include <errno.h>
-#include <string.h>
-
-#include "parser_proc.h"
#include "parser.h"
fp = fopen(filename, "r");
if (!fp) {
- if (!(flags & PSI_PARSER_SILENT)) {
+ if (!(flags & PSI_SILENT)) {
error(NULL, NULL, PSI_WARNING, "Could not open '%s' for reading: %s",
filename, strerror(errno));
}
}
memset(P, 0, sizeof(*P));
- P->psi.file.fn = strdup(filename);
+ psi_data_ctor_with_dtors(PSI_DATA(P), error, flags);
+ P->file.fn = strdup(filename);
P->fp = fp;
P->col = 1;
P->line = 1;
- P->error = error;
- P->flags = flags;
P->proc = psi_parser_proc_Alloc(malloc);
- if (flags & PSI_PARSER_DEBUG) {
+ if (flags & PSI_DEBUG) {
psi_parser_proc_Trace(stderr, "PSI> ");
}
ssize_t psi_parser_fill(struct psi_parser *P, size_t n)
{
- if (P->flags & PSI_PARSER_DEBUG) {
+ if (P->flags & PSI_DEBUG) {
fprintf(stderr, "PSI> Fill: n=%zu\n", n);
}
if (!n) {
P->eof = P->lim;
}
- if (P->flags & PSI_PARSER_DEBUG) {
+ if (P->flags & PSI_DEBUG) {
fprintf(stderr, "PSI> Fill: consumed=%zu reserved=%zu available=%zu didread=%zu\n",
consumed, reserved, available, didread);
}
}
- if (P->flags & PSI_PARSER_DEBUG) {
+ if (P->flags & PSI_DEBUG) {
fprintf(stderr, "PSI> Fill: avail=%td\n", P->lim - P->cur);
}
return P->lim - P->cur;
#define RETURN(t) do { \
P->num = t; \
- if (P->flags & PSI_PARSER_DEBUG) { \
+ if (P->flags & PSI_DEBUG) { \
fprintf(stderr, "PSI> TOKEN: %d %.*s (EOF=%d %s:%u:%u)\n", \
P->num, (int) (P->cur-P->tok), P->tok, P->num == PSI_T_EOF, \
- P->psi.file.fn, P->line, P->col); \
+ P->file.fn, P->line, P->col); \
} \
return t; \
} while(1)
'ARRAY' {RETURN(PSI_T_ARRAY);}
'OBJECT' {RETURN(PSI_T_OBJECT);}
'CALLBACK' {RETURN(PSI_T_CALLBACK);}
+ 'STATIC' {RETURN(PSI_T_STATIC);}
'FUNCTION' {RETURN(PSI_T_FUNCTION);}
'TYPEDEF' {RETURN(PSI_T_TYPEDEF);}
'STRUCT' {RETURN(PSI_T_STRUCT);}
-#define _CONCAT(x,y) x##y
-#define CONCAT(x,y) _CONCAT(x,y)
-#define COUNTED(x) CONCAT(parse_ ##x## _, __LINE__)
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#define CONCAT2(x,y) x##y
+#define CONCAT1(x,y) CONCAT2(x,y)
+#define COUNTED(x) CONCAT1(parse_ ##x## _, __LINE__)
#ifdef GENERATE
-#define DEF(dn, dv) dn dv
-#define PASS(nt, rule) nt ::= rule.
-#define PARSE(nt, rule) nt ::= rule.
-#define PARSE_NAMED(nt, nt_name, rule) NAMED(nt, nt_name) ::= rule.
-#define PARSE_TYPED(nt, nt_name, rule) TYPED(nt, nt_name) ::= rule.
-#define TOKEN(t) t
-#define NAMED(t, name) t(name)
-#define TYPED(t, name) t(name)
-#define TOKEN_TYPE(token, type_) %type token {type_}
-#define TOKEN_DTOR(token, dtor) %destructor token {dtor}
+# define DEF(dn, dv) dn dv
+# define PASS(nt, rule) nt ::= rule.
+# define PARSE(nt, rule) nt ::= rule.
+# define PARSE_NAMED(nt, nt_name, rule) NAMED(nt, nt_name) ::= rule.
+# define PARSE_TYPED(nt, nt_name, rule) TYPED(nt, nt_name) ::= rule.
+# define TOKEN(t) t
+# define NAMED(t, name) t(name)
+# define TYPED(t, name) t(name)
+# define TOKEN_TYPE(token, type_) %type token {type_}
+# define TOKEN_DTOR(token, dtor) %destructor token {dtor}
#else
-#ifndef TEST
-#include "parser.h"
-#endif
-#define DEF(dn, dv)
-#define PASS(nt, rule) \
+# ifndef TEST
+# include "parser.h"
+# include "plist.h"
+# endif
+# define DEF(dn, dv)
+# define PASS(nt, rule) \
static void COUNTED(nt) (struct psi_parser *P) { \
(void) #rule; \
}
-#define PARSE(nt, rule) \
+# define PARSE(nt, rule) \
static void COUNTED(nt) (struct psi_parser *P rule)
-#define PARSE_NAMED(nt, nt_name, rule) \
+# define PARSE_NAMED(nt, nt_name, rule) \
static void COUNTED(nt) (struct psi_parser *P NAMED(nt, nt_name) rule)
-#define PARSE_TYPED(nt, nt_name, rule) \
+# define PARSE_TYPED(nt, nt_name, rule) \
static void COUNTED(nt) (struct psi_parser *P TYPED(nt, nt_name) rule)
-#define TOKEN(t)
-#define NAMED(t, name) , struct psi_token *name
-#define TYPED(t, name) , TOKEN_TYPE_NAME(t) name
-#define TOKEN_TYPE_NAME(token) ##token##_parse_t
-#define TOKEN_TYPE(token, type) typedef type TOKEN_TYPE_NAME(token);
-#define TOKEN_DTOR(token, dtor)
+# define TOKEN(t)
+# define NAMED(t, name) , struct psi_token *name
+# define TYPED(t, name) , TOKEN_TYPE_NAME(t) name
+# define TOKEN_TYPE_NAME(token) token##_parse_t
+# define TOKEN_TYPE(token, type) typedef type TOKEN_TYPE_NAME(token);
+# define TOKEN_DTOR(token, dtor)
#endif
DEF(%name, psi_parser_proc_)
if (TOKEN && TOKEN->type != PSI_T_EOF) {
psi_error(PSI_WARNING, TOKEN->file, TOKEN->line, "PSI syntax error: Unexpected token '%s' at pos %u", TOKEN->text, TOKEN->col);
} else {
- psi_error(PSI_WARNING, P->psi.file.fn, P->line, "PSI syntax error: Unexpected end of input");
+ psi_error(PSI_WARNING, P->file.fn, P->line, "PSI syntax error: Unexpected end of input");
}
})
DEF(%token_class, set_func_token TO_OBJECT TO_ARRAY TO_STRING TO_INT TO_FLOAT TO_BOOL ZVAL VOID.)
DEF(%token_class, impl_type_token VOID MIXED BOOL INT FLOAT STRING ARRAY OBJECT CALLABLE.)
-TOKEN_TYPE(decl_enum, decl_enum *)
-TOKEN_DTOR(decl_enum, free_decl_enum($$);)
-TOKEN_TYPE(decl_enum_items, decl_enum_items*)
-TOKEN_DTOR(decl_enum_items, free_decl_enum_items($$);)
-TOKEN_TYPE(decl_enum_item, decl_enum_item*)
-TOKEN_DTOR(decl_enum_item, free_decl_enum_item($$);)
-TOKEN_TYPE(decl_struct_args_block, decl_args*)
-TOKEN_DTOR(decl_struct_args_block, free_decl_args($$);) /* there was a typo */
-TOKEN_TYPE(decl_struct_args, decl_args*)
-TOKEN_DTOR(decl_struct_args, free_decl_args($$);)
-TOKEN_TYPE(decl_struct, decl_struct*)
-TOKEN_DTOR(decl_struct, free_decl_struct($$);)
-TOKEN_TYPE(align_and_size, decl_struct_layout)
-TOKEN_TYPE(decl_union, decl_union*)
-TOKEN_DTOR(decl_union, free_decl_union($$);)
-TOKEN_TYPE(const_type, const_type*)
-TOKEN_DTOR(const_type, free_const_type($$);)
-TOKEN_TYPE(constant, constant*)
-TOKEN_DTOR(constant, free_constant($$);)
-TOKEN_TYPE(decl_typedef, decl_arg*)
-TOKEN_DTOR(decl_typedef, free_decl_arg($$);)
-TOKEN_TYPE(decl_typedef_body_ex, decl_arg*)
-TOKEN_DTOR(decl_typedef_body_ex, free_decl_arg($$);)
-TOKEN_TYPE(decl_typedef_body, decl_arg*)
-TOKEN_DTOR(decl_typedef_body, free_decl_arg($$);)
-TOKEN_TYPE(decl_typedef_body_fn_args, decl_args *)
-TOKEN_DTOR(decl_typedef_body_fn_args, free_decl_args($$);)
-TOKEN_TYPE(decl, decl*)
-TOKEN_DTOR(decl, free_decl($$);)
-TOKEN_TYPE(decl_func, decl_arg*)
-TOKEN_DTOR(decl_func, free_decl_arg($$);)
-TOKEN_TYPE(decl_abi, decl_abi*)
-TOKEN_DTOR(decl_abi, free_decl_abi($$);)
-TOKEN_TYPE(decl_var, decl_var*)
-TOKEN_DTOR(decl_var, free_decl_var($$);)
-TOKEN_TYPE(decl_vars, decl_vars*)
-TOKEN_DTOR(decl_vars, free_decl_vars($$);)
-TOKEN_TYPE(decl_arg, decl_arg*)
-TOKEN_DTOR(decl_arg, free_decl_arg($$);)
-TOKEN_TYPE(decl_args, decl_args*)
-TOKEN_DTOR(decl_args, free_decl_args($$);)
-TOKEN_TYPE(struct_args, decl_args*)
-TOKEN_DTOR(struct_args, free_decl_args($$);)
-TOKEN_TYPE(struct_arg, decl_arg*)
-TOKEN_DTOR(struct_arg, free_decl_arg($$);)
-TOKEN_TYPE(struct_layout, decl_struct_layout*)
-TOKEN_DTOR(struct_layout, free_decl_struct_layout($$);)
-TOKEN_TYPE(decl_type, decl_type*)
-TOKEN_DTOR(decl_type, free_decl_type($$);)
-TOKEN_TYPE(const_decl_type, decl_type*)
-TOKEN_DTOR(const_decl_type, free_decl_type($$);)
-TOKEN_TYPE(impl, impl*)
-TOKEN_DTOR(impl, free_impl($$);)
-TOKEN_TYPE(impl_func, impl_func*)
-TOKEN_DTOR(impl_func, free_impl_func($$);)
-TOKEN_TYPE(impl_def_val, impl_def_val*)
-TOKEN_DTOR(impl_def_val, free_impl_def_val($$);)
-TOKEN_TYPE(impl_var, impl_var*)
-TOKEN_DTOR(impl_var, free_impl_var($$);)
-TOKEN_TYPE(impl_arg, impl_arg*)
-TOKEN_DTOR(impl_arg, free_impl_arg($$);)
-TOKEN_TYPE(impl_args, impl_args*)
-TOKEN_DTOR(impl_args, free_impl_args($$);)
-TOKEN_TYPE(impl_vararg, impl_arg*)
-TOKEN_DTOR(impl_vararg, free_impl_arg($$);)
-TOKEN_TYPE(impl_arg_list, impl_args*)
-TOKEN_DTOR(impl_arg_list, free_impl_args($$);)
-TOKEN_TYPE(impl_stmts, impl_stmts*)
-TOKEN_DTOR(impl_stmts, free_impl_stmts($$);)
-TOKEN_TYPE(impl_stmt, impl_stmt*)
-TOKEN_DTOR(impl_stmt, free_impl_stmt($$);)
-TOKEN_TYPE(num_exp, num_exp*)
-TOKEN_DTOR(num_exp, free_num_exp($$);)
-TOKEN_TYPE(let_stmt, let_stmt*)
-TOKEN_DTOR(let_stmt, free_let_stmt($$);)
-TOKEN_TYPE(let_calloc, let_calloc*)
-TOKEN_DTOR(let_calloc, free_let_calloc($$);)
-TOKEN_TYPE(let_func, let_func*)
-TOKEN_DTOR(let_func, free_let_func($$);)
-TOKEN_TYPE(callback_arg_list, set_values *)
-TOKEN_DTOR(callback_arg_list, free_set_values($$);)
-TOKEN_TYPE(callback_args, set_values *)
-TOKEN_DTOR(callback_args, free_set_values($$);)
-TOKEN_TYPE(let_val, let_val*)
-TOKEN_DTOR(let_val, free_let_val($$);)
-TOKEN_TYPE(let_vals, let_vals*)
-TOKEN_DTOR(let_vals, free_let_vals($$);)
-TOKEN_TYPE(set_stmt, set_stmt*)
-TOKEN_DTOR(set_stmt, free_set_stmt($$);)
-TOKEN_TYPE(set_value, set_value*)
-TOKEN_DTOR(set_value, free_set_value($$);)
-TOKEN_TYPE(set_vals, set_value*)
-TOKEN_DTOR(set_vals, free_set_value($$);)
-TOKEN_TYPE(set_func, set_func*)
-TOKEN_DTOR(set_func, free_set_func($$);)
-TOKEN_TYPE(return_stmt, return_stmt*)
-TOKEN_DTOR(return_stmt, free_return_stmt($$);)
-TOKEN_TYPE(free_stmt, free_stmt*)
-TOKEN_DTOR(free_stmt, free_free_stmt($$);)
-TOKEN_TYPE(free_calls, free_calls*)
-TOKEN_DTOR(free_calls, free_free_calls($$);)
-TOKEN_TYPE(free_call, free_call*)
-TOKEN_DTOR(free_call, free_free_call($$);)
-TOKEN_TYPE(impl_type, impl_type*)
-TOKEN_DTOR(impl_type, free_impl_type($$);)
+TOKEN_TYPE(decl_enum, struct psi_decl_enum *)
+TOKEN_DTOR(decl_enum, psi_decl_enum_free(&$$);)
+TOKEN_TYPE(decl_enum_items, struct psi_plist*)
+TOKEN_DTOR(decl_enum_items, psi_plist_free($$);)
+TOKEN_TYPE(decl_enum_item, struct psi_decl_enum_item*)
+TOKEN_DTOR(decl_enum_item, psi_decl_enum_item_free(&$$);)
+TOKEN_TYPE(decl_struct_args_block, struct psi_plist*)
+TOKEN_DTOR(decl_struct_args_block, psi_plist_free($$);) /* there was a typo */
+TOKEN_TYPE(decl_struct_args, struct psi_plist*)
+TOKEN_DTOR(decl_struct_args, psi_plist_free($$);)
+TOKEN_TYPE(decl_struct, struct psi_decl_struct*)
+TOKEN_DTOR(decl_struct, psi_decl_struct_free(&$$);)
+TOKEN_TYPE(align_and_size, struct psi_layout)
+TOKEN_TYPE(decl_union, struct psi_decl_union*)
+TOKEN_DTOR(decl_union, psi_decl_union_free(&$$);)
+TOKEN_TYPE(const_type, struct psi_const_type*)
+TOKEN_DTOR(const_type, psi_const_type_free(&$$);)
+TOKEN_TYPE(constant, struct psi_const*)
+TOKEN_DTOR(constant, psi_const_free(&$$);)
+TOKEN_TYPE(decl_typedef, struct psi_decl_arg*)
+TOKEN_DTOR(decl_typedef, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_typedef_body_ex, struct psi_decl_arg*)
+TOKEN_DTOR(decl_typedef_body_ex, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_typedef_body, struct psi_decl_arg*)
+TOKEN_DTOR(decl_typedef_body, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_typedef_body_fn_args, struct psi_plist*)
+TOKEN_DTOR(decl_typedef_body_fn_args, psi_plist_free($$);)
+TOKEN_TYPE(decl, struct psi_decl*)
+TOKEN_DTOR(decl, psi_decl_free(&$$);)
+TOKEN_TYPE(decl_func, struct psi_decl_arg*)
+TOKEN_DTOR(decl_func, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_abi, struct psi_decl_abi*)
+TOKEN_DTOR(decl_abi, psi_decl_abi_free(&$$);)
+TOKEN_TYPE(decl_var, struct psi_decl_var*)
+TOKEN_DTOR(decl_var, psi_decl_var_free(&$$);)
+TOKEN_TYPE(decl_vars, struct psi_plist*)
+TOKEN_DTOR(decl_vars, psi_plist_free($$);)
+TOKEN_TYPE(decl_arg, struct psi_decl_arg*)
+TOKEN_DTOR(decl_arg, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_args, struct psi_plist*)
+TOKEN_DTOR(decl_args, psi_plist_free($$);)
+TOKEN_TYPE(struct_args, struct psi_plist*)
+TOKEN_DTOR(struct_args, psi_plist_free($$);)
+TOKEN_TYPE(struct_arg, struct psi_decl_arg*)
+TOKEN_DTOR(struct_arg, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_layout, struct psi_layout*)
+TOKEN_DTOR(decl_layout, psi_layout_free(&$$);)
+TOKEN_TYPE(decl_type, struct psi_decl_type*)
+TOKEN_DTOR(decl_type, psi_decl_type_free(&$$);)
+TOKEN_TYPE(const_decl_type, struct psi_decl_type*)
+TOKEN_DTOR(const_decl_type, psi_decl_type_free(&$$);)
+TOKEN_TYPE(impl, struct psi_impl*)
+TOKEN_DTOR(impl, psi_impl_free(&$$);)
+TOKEN_TYPE(impl_func, struct psi_impl_func*)
+TOKEN_DTOR(impl_func, psi_impl_func_free(&$$);)
+TOKEN_TYPE(impl_def_val, struct psi_impl_def_val*)
+TOKEN_DTOR(impl_def_val, psi_impl_def_val_free(&$$);)
+TOKEN_TYPE(impl_var, struct psi_impl_var*)
+TOKEN_DTOR(impl_var, psi_impl_var_free(&$$);)
+TOKEN_TYPE(impl_arg, struct psi_impl_arg*)
+TOKEN_DTOR(impl_arg, psi_impl_arg_free(&$$);)
+TOKEN_TYPE(impl_args, struct psi_plist*)
+TOKEN_DTOR(impl_args, psi_plist_free($$);)
+TOKEN_TYPE(impl_vararg, struct psi_impl_arg*)
+TOKEN_DTOR(impl_vararg, psi_impl_arg_free(&$$);)
+TOKEN_TYPE(impl_stmts, struct psi_plist*)
+TOKEN_DTOR(impl_stmts, psi_plist_free($$);)
+TOKEN_TYPE(impl_stmt, struct psi_token**)
+TOKEN_DTOR(impl_stmt, psi_impl_stmt_free(&$$);)
+TOKEN_TYPE(num_exp, struct psi_num_exp*)
+TOKEN_DTOR(num_exp, psi_num_exp_free(&$$);)
+TOKEN_TYPE(let_stmt, struct psi_let_stmt*)
+TOKEN_DTOR(let_stmt, psi_let_stmt_free(&$$);)
+TOKEN_TYPE(let_calloc, struct psi_let_calloc*)
+TOKEN_DTOR(let_calloc, psi_let_calloc_free(&$$);)
+TOKEN_TYPE(let_func, struct psi_let_func*)
+TOKEN_DTOR(let_func, psi_let_func_free(&$$);)
+TOKEN_TYPE(callback_arg_list, struct psi_plist *)
+TOKEN_DTOR(callback_arg_list, psi_plist_free($$);)
+TOKEN_TYPE(callback_args, struct psi_plist *)
+TOKEN_DTOR(callback_args, psi_plist_free($$);)
+TOKEN_TYPE(let_callback, struct psi_let_callback*)
+TOKEN_DTOR(let_callback, psi_let_callback_free(&$$);)
+TOKEN_TYPE(let_exp, struct psi_let_exp*)
+TOKEN_DTOR(let_exp, psi_let_exp_free(&$$);)
+TOKEN_TYPE(let_exps, struct psi_plist*)
+TOKEN_DTOR(let_exps, psi_plist_free($$);)
+TOKEN_TYPE(set_stmt, struct psi_set_stmt*)
+TOKEN_DTOR(set_stmt, psi_set_stmt_free(&$$);)
+TOKEN_TYPE(set_exp, struct psi_set_exp*)
+TOKEN_DTOR(set_exp, psi_set_exp_free(&$$);)
+TOKEN_TYPE(set_exps, struct psi_plist*)
+TOKEN_DTOR(set_exps, psi_plist_free($$);)
+TOKEN_TYPE(set_func, struct psi_set_func*)
+TOKEN_DTOR(set_func, psi_set_func_free(&$$);)
+TOKEN_TYPE(return_stmt, struct psi_return_stmt*)
+TOKEN_DTOR(return_stmt, psi_return_stmt_free(&$$);)
+TOKEN_TYPE(free_stmt, struct psi_free_stmt*)
+TOKEN_DTOR(free_stmt, psi_free_stmt_free(&$$);)
+TOKEN_TYPE(free_exps, struct psi_plist*)
+TOKEN_DTOR(free_exps, psi_plist_free($$);)
+TOKEN_TYPE(free_exp, struct psi_free_exp*)
+TOKEN_DTOR(free_exp, psi_free_exp_free(&$$);)
+TOKEN_TYPE(impl_type, struct psi_impl_type*)
+TOKEN_DTOR(impl_type, psi_impl_type_free(&$$);)
TOKEN_TYPE(reference, char)
TOKEN_TYPE(indirection, unsigned)
TOKEN_TYPE(pointers, unsigned)
PASS(block, EOF)
PASS(block, EOS)
+/*
+ * lib: LIB "soname" ;
+ */
PARSE(block, NAMED(LIB, token) NAMED(QUOTED_STRING, libname) TOKEN(EOS)) {
- if (P->psi.file.ln) {
- P->error(P, token, PSI_WARNING, "Extra 'lib %s' statement has no effect", libname->text);
+ if (P->file.ln) {
+ P->error(PSI_DATA(P), token, PSI_WARNING, "Extra 'lib %s' statement has no effect", libname->text);
} else {
- P->psi.file.ln = strndup(libname->text + 1, libname->size - 2);
+ P->file.ln = strndup(libname->text + 1, libname->size - 2);
}
free(libname);
free(token);
}
+
PARSE(block, TYPED(decl, decl)) {
- P->decls = add_decl(P->decls, decl);
+ if (!P->decls) {
+ P->decls = psi_plist_init((psi_plist_dtor) psi_decl_free);
+ }
+ P->decls = psi_plist_add(P->decls, &decl);
}
PARSE(block, TYPED(impl, impl)) {
- P->impls = add_impl(P->impls, impl);
+ if (!P->impls) {
+ P->impls = psi_plist_init((psi_plist_dtor) psi_impl_free);
+ }
+ P->impls = psi_plist_add(P->impls, &impl);
}
PARSE(block, TYPED(decl_typedef, def)) {
- P->defs = add_decl_typedef(P->defs, def);
+ if (!P->types) {
+ P->types = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+ }
+ P->types = psi_plist_add(P->types, &def);
+
switch (def->type->type) {
case PSI_T_STRUCT:
if (def->type->real.strct) {
- P->structs = add_decl_struct(P->structs, def->type->real.strct);
+ if (!P->structs) {
+ P->structs = psi_plist_init((psi_plist_dtor) psi_decl_struct_free);
+ }
+ P->structs = psi_plist_add(P->structs, &def->type->real.strct);
}
break;
case PSI_T_UNION:
if (def->type->real.unn) {
- P->unions = add_decl_union(P->unions, def->type->real.unn);
+ if (!P->unions) {
+ P->unions = psi_plist_init((psi_plist_dtor) psi_decl_union_free);
+ }
+ P->unions = psi_plist_add(P->unions, &def->type->real.unn);
}
break;
case PSI_T_ENUM:
if (def->type->real.enm) {
- P->enums = add_decl_enum(P->enums, def->type->real.enm);
+ if (!P->enums) {
+ P->enums = psi_plist_init((psi_plist_dtor) psi_decl_enum_free);
+ }
+ P->enums = psi_plist_add(P->enums, &def->type->real.enm);
}
break;
}
}
PARSE(block, TYPED(constant, constant)) {
- P->consts = add_constant(P->consts, constant);
+ if (!P->consts) {
+ P->consts = psi_plist_init((psi_plist_dtor) psi_const_free);
+ }
+ P->consts = psi_plist_add(P->consts, &constant);
}
PARSE(block, TYPED(decl_struct, strct)) {
- P->structs = add_decl_struct(P->structs, strct);
+ if (!P->structs) {
+ P->structs = psi_plist_init((psi_plist_dtor) psi_decl_struct_free);
+ }
+ P->structs = psi_plist_add(P->structs, &strct);
}
PARSE(block, TYPED(decl_union, u)) {
- P->unions = add_decl_union(P->unions, u);
+ if (!P->unions) {
+ P->unions = psi_plist_init((psi_plist_dtor) psi_decl_union_free);
+ }
+ P->unions = psi_plist_add(P->unions, &u);
}
PARSE(block, TYPED(decl_enum, e)) {
- P->enums = add_decl_enum(P->enums, e);
+ if (!P->enums) {
+ P->enums = psi_plist_init((psi_plist_dtor) psi_decl_enum_free);
+ }
+ P->enums = psi_plist_add(P->enums, &e);
}
+/*
+ * optional_name: <empty>
+ */
PARSE_NAMED(optional_name, n, ) {
n = NULL;
}
+/*
+ * optional_name: NAME
+ */
PARSE_NAMED(optional_name, n,
NAMED(NAME, N)) {
n = N;
}
+/*
+ * align_and_size: <empty>
+ */
+PARSE_TYPED(align_and_size, as, ) {
+ as.pos = 0;
+ as.len = 0;
+}
+
+/*
+ * align_and_size: :: ( NUMBER , NUMBER )
+ */
+PARSE_TYPED(align_and_size, as,
+ TOKEN(COLON)
+ TOKEN(COLON)
+ TOKEN(LPAREN)
+ NAMED(NUMBER, A)
+ TOKEN(COMMA)
+ NAMED(NUMBER, S)
+ TOKEN(RPAREN)) {
+ as.pos = atol(A->text);
+ as.len = atol(S->text);
+ free(A);
+ free(S);
+}
+
+/*
+ * enum_name: ENUM optional_name
+ */
PARSE_NAMED(enum_name, n,
- NAMED(ENUM, E) NAMED(optional_name, N)) {
+ NAMED(ENUM, E)
+ NAMED(optional_name, N)) {
if (N) {
n = N;
free(E);
}
}
+/*
+ * struct_name: STRUCT optional_name
+ */
+PARSE_NAMED(struct_name, n,
+ NAMED(STRUCT, S)
+ NAMED(optional_name, N)) {
+ if (N) {
+ n = N;
+ free(S);
+ } else {
+ char digest[17];
+
+ psi_token_hash(S, digest);
+ n = psi_token_translit(psi_token_append(S, 1, digest), " ", "@");
+ }
+}
+
+/*
+ * union_name: UNION optional_name
+ */
+PARSE_NAMED(union_name, n,
+ NAMED(UNION, U)
+ NAMED(optional_name, N)) {
+ if (N) {
+ n = N;
+ free(U);
+ } else {
+ char digest[17];
+
+ psi_token_hash(U, digest);
+ n = psi_token_translit(psi_token_append(U, 1, digest), " ", "@");
+ }
+}
+
+/*
+ * decl_enum: enum_name { items }
+ */
PARSE_TYPED(decl_enum, e,
NAMED(enum_name, N)
TOKEN(LBRACE)
TYPED(decl_enum_items, list)
TOKEN(RBRACE)) {
- e = init_decl_enum(N->text, list);
+ e = psi_decl_enum_init(N->text, list);
e->token = N;
}
+/*
+ * decl_enum_items: item
+ */
PARSE_TYPED(decl_enum_items, l,
TYPED(decl_enum_item, i)) {
- l = init_decl_enum_items(i);
+ l = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_decl_enum_item_free),
+ &i);
}
+
+/*
+ * decl_enum_items: items , item
+ */
PARSE_TYPED(decl_enum_items, l,
TYPED(decl_enum_items, l_)
TOKEN(COMMA)
TYPED(decl_enum_item, i)) {
- l = add_decl_enum_item(l_, i);
+ l = psi_plist_add(l_, &i);
}
+/*
+ * decl_enum_item: name = num_exp
+ */
PARSE_TYPED(decl_enum_item, i,
NAMED(NAME, N)
TOKEN(EQUALS)
TYPED(num_exp, num)) {
- i = init_decl_enum_item(N->text, num);
+ i = psi_decl_enum_item_init(N->text, num);
i->token = N;
}
+
+/*
+ * decl_enum_item: name
+ */
PARSE_TYPED(decl_enum_item, i,
NAMED(NAME, N)) {
- i = init_decl_enum_item(N->text, NULL);
+ i = psi_decl_enum_item_init(N->text, NULL);
i->token = N;
}
-PARSE_NAMED(union_name, n,
- NAMED(UNION, U)
- NAMED(optional_name, N)) {
- if (N) {
- n = N;
- free(U);
- } else {
- char digest[17];
-
- psi_token_hash(U, digest);
- n = psi_token_translit(psi_token_append(U, 1, digest), " ", "@");
- }
-}
-
-PARSE_NAMED(struct_name, n,
- NAMED(STRUCT, S)
- NAMED(optional_name, N)) {
- if (N) {
- n = N;
- free(S);
- } else {
- char digest[17];
-
- psi_token_hash(S, digest);
- n = psi_token_translit(psi_token_append(S, 1, digest), " ", "@");
- }
-}
+/*
+ * decl_struct_args_block: { args }
+ */
PARSE_TYPED(decl_struct_args_block, args_,
TOKEN(LBRACE)
TYPED(struct_args, args)
args_ = args;
}
+/*
+ * decl_struct_args: args_block
+ */
PARSE_TYPED(decl_struct_args, args_,
TYPED(decl_struct_args_block, args)) {
args_ = args;
}
+
+/*
+ * decl_struct_args: ;
+ */
PARSE_TYPED(decl_struct_args, args_,
TOKEN(EOS)) {
- args_ = init_decl_args(NULL);
+ args_ = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
}
+/*
+ * decl_struct: STRUCT name align_and_size struct_args
+ */
PARSE_TYPED(decl_struct, strct,
TOKEN(STRUCT)
NAMED(NAME, N)
TYPED(align_and_size, as)
TYPED(decl_struct_args, args)) {
- strct = init_decl_struct(N->text, args);
+ strct = psi_decl_struct_init(N->text, args);
strct->align = as.pos;
strct->size = as.len;
strct->token = N;
}
-PARSE_TYPED(align_and_size, as, ) {
- as.pos = 0;
- as.len = 0;
-}
-PARSE_TYPED(align_and_size, as,
- TOKEN(COLON)
- TOKEN(COLON)
- TOKEN(LPAREN)
- NAMED(NUMBER, A)
- TOKEN(COMMA)
- NAMED(NUMBER, S)
- TOKEN(RPAREN)) {
- as.pos = atol(A->text);
- as.len = atol(S->text);
- free(A);
- free(S);
-}
-
+/*
+ * decl_union: UNION name align_and_size struct_args
+ */
PARSE_TYPED(decl_union, u,
TOKEN(UNION)
NAMED(NAME, N)
TYPED(align_and_size, as)
TYPED(decl_struct_args, args)) {
- u = init_decl_union(N->text, args);
+ u = psi_decl_union_init(N->text, args);
u->align = as.pos;
u->size = as.len;
u->token = N;
}
+/*
+ * const_type: const_type_token
+ */
PARSE_TYPED(const_type, type_,
NAMED(const_type_token, T)) {
- type_ = init_const_type(T->type, T->text);
+ type_ = psi_const_type_init(T->type, T->text);
free(T);
}
+/*
+ * constant: CONST const_type NSNAME = def_val ;
+ */
PARSE_TYPED(constant, constant,
TOKEN(CONST)
TYPED(const_type, type)
TOKEN(EQUALS)
TYPED(impl_def_val, val)
TOKEN(EOS)) {
- constant = init_constant(type, T->text, val);
- free(T);
+ constant = psi_const_init(type, T->text, val);
+ constant->token = T;
}
+/*
+ * decl_typdef: TYPEDEF typedef_body ;
+ */
PARSE_TYPED(decl_typedef, def,
NAMED(TYPEDEF, T)
TYPED(decl_typedef_body, def_)
def->token = T;
}
+/*
+ * decl_typedef_body_ex: struct_name align_and_size struct_args_block decl_var
+ */
PARSE_TYPED(decl_typedef_body_ex, def,
NAMED(struct_name, N)
TYPED(align_and_size, as)
TYPED(decl_struct_args_block, args)
TYPED(decl_var, var)) {
- def = init_decl_arg(init_decl_type(PSI_T_STRUCT, N->text), var);
+ def = psi_decl_arg_init(psi_decl_type_init(PSI_T_STRUCT, N->text), var);
def->type->token = psi_token_copy(N);
- def->type->real.strct = init_decl_struct(N->text, args);
+ def->type->real.strct = psi_decl_struct_init(N->text, args);
def->type->real.strct->token = N;
def->type->real.strct->align = as.pos;
def->type->real.strct->size = as.len;
}
+
+/*
+ * decl_typedef_body_ex: union_name align_and_size struct_args_block decl_var
+ */
PARSE_TYPED(decl_typedef_body_ex, def,
NAMED(union_name, N)
TYPED(align_and_size, as)
TYPED(decl_struct_args_block, args)
TYPED(decl_var, var)) {
- def = init_decl_arg(init_decl_type(PSI_T_UNION, N->text), var);
+ def = psi_decl_arg_init(psi_decl_type_init(PSI_T_UNION, N->text), var);
def->type->token = psi_token_copy(N);
- def->type->real.unn = init_decl_union(N->text, args);
+ def->type->real.unn = psi_decl_union_init(N->text, args);
def->type->real.unn->token = N;
def->type->real.unn->align = as.pos;
def->type->real.unn->size = as.len;
}
+
+/*
+ * decl_typedef_body_ex: decl_enum NAME
+ */
PARSE_TYPED(decl_typedef_body_ex, def,
TYPED(decl_enum, e)
NAMED(NAME, ALIAS)) {
- def = init_decl_arg(init_decl_type(PSI_T_ENUM, e->name), init_decl_var(ALIAS->text, 0, 0));
+ def = psi_decl_arg_init(psi_decl_type_init(PSI_T_ENUM, e->name), psi_decl_var_init(ALIAS->text, 0, 0));
def->var->token = ALIAS;
def->type->token = psi_token_copy(e->token);
def->type->real.enm = e;
}
+/*
+ * decl_typedef_body: decl_typedef_body_ex
+ */
PARSE_TYPED(decl_typedef_body, def,
TYPED(decl_typedef_body_ex, def_)) {
def = def_;
}
+/*
+ * decl_typedef_body_fn_args: ( decl_args )
+ */
PARSE_TYPED(decl_typedef_body_fn_args, args,
TOKEN(LPAREN)
TYPED(decl_args, args_)
TOKEN(RPAREN)) {
args = args_;
}
+
+/*
+ * decl_typedef_body: decl_func decl_typedef_body_fn_args
+ */
PARSE_TYPED(decl_typedef_body, def,
TYPED(decl_func, func_)
TYPED(decl_typedef_body_fn_args, args)) {
- def = init_decl_arg(init_decl_type(PSI_T_FUNCTION, func_->var->name), copy_decl_var(func_->var));
+ def = psi_decl_arg_init(psi_decl_type_init(PSI_T_FUNCTION, func_->var->name), psi_decl_var_copy(func_->var));
def->type->token = psi_token_copy(func_->token);
- def->type->real.func = init_decl(init_decl_abi("default"), func_, args);
+ def->type->real.func = psi_decl_init(psi_decl_abi_init("default"), func_, args);
}
+
+/*
+ * decl_typedef_body: decl_arg
+ */
PARSE_TYPED(decl_typedef_body, def,
TYPED(decl_arg, arg)) {
def = arg;
}
+/*
+ * decl: decl_abi decl_func ( decl_args ) ;
+ */
+PARSE_TYPED(decl, decl,
+ TYPED(decl_abi, abi)
+ TYPED(decl_func, func)
+ TOKEN(LPAREN)
+ TYPED(decl_args, args)
+ TOKEN(RPAREN)
+ TOKEN(EOS)) {
+ decl = psi_decl_init(abi, func, args);
+}
+
+/*
+ * decl: decl_abi decl_func ( decl_args , ... ) ;
+ */
PARSE_TYPED(decl, decl,
TYPED(decl_abi, abi)
TYPED(decl_func, func)
TOKEN(LPAREN)
TYPED(decl_args, args)
+ TOKEN(COMMA)
+ TOKEN(ELLIPSIS)
TOKEN(RPAREN)
TOKEN(EOS)) {
- decl = init_decl(abi,&n