git-svn-id: svn://svn.lighttpd.net/xcache/trunk@1 c26eb9a1-5813-0410-bd6c-c2e55f420ca71.1
@ -0,0 +1,2 @@ | |||
au FileType m4 setlocal ts=2 sw=2 fdm=marker |
@ -0,0 +1,26 @@ | |||
# vim:ts=4:sw=4 | |||
Installtion: | |||
$ phpize --clean && phpize | |||
$ ./configure --help | |||
$ CFLAGS='your cflags' ./configure --enable-xcache --enable... | |||
$ make | |||
$ su | |||
# make install | |||
(update php.ini, restart php) | |||
Reinstall: | |||
$ mv config.nice conf | |||
$ make distclean && phpize --clean && phpize | |||
$ mv conf config.nice | |||
$ ./config.nice | |||
$ make | |||
$ su | |||
# make install | |||
(update php.ini, restart php) | |||
Update php.ini: | |||
$ su | |||
# cat xcache.ini >> /etc/php.ini | |||
# $EDITOR /etc/php.ini |
@ -0,0 +1,28 @@ | |||
XCACHE_PROC_SRC=$(srcdir)/processor/main.m4 | |||
XCACHE_PROC_OUT=$(builddir)/processor.out | |||
XCACHE_PROC_C=$(builddir)/processor_real.c | |||
XCACHE_PROC_H=$(builddir)/processor.h | |||
XCACHE_INCLUDES_SRC=$(srcdir)/includes.c | |||
XCACHE_INCLUDES_I=$(builddir)/includes.i | |||
XCACHE_STRUCT_OUT=$(builddir)/structinfo.m4 | |||
$(XCACHE_INCLUDES_I): $(XCACHE_INCLUDES_SRC) $(srcdir)/xcache.h | |||
$(CC) -I. -I$(srcdir) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) -E $(XCACHE_INCLUDES_SRC) -o $(XCACHE_INCLUDES_I) | |||
$(XCACHE_STRUCT_OUT): $(XCACHE_INCLUDES_I) $(srcdir)/mkstructinfo.awk | |||
$(AWK) -f $(srcdir)/mkstructinfo.awk < $(XCACHE_INCLUDES_I) > $(XCACHE_STRUCT_OUT) | |||
$(XCACHE_PROC_OUT): $(XCACHE_PROC_SRC) $(XCACHE_STRUCT_OUT) $(XCACHE_PROC_SOURCES) | |||
m4 -I$(srcdir)/processor/ -I$(builddir)/ -I$(srcdir)/ $(XCACHE_ENABLE_TEST) -E $(XCACHE_PROC_SRC) > $(XCACHE_PROC_OUT).tmp && mv -f $(XCACHE_PROC_OUT).tmp $(XCACHE_PROC_OUT) | |||
$(XCACHE_PROC_H): $(XCACHE_PROC_OUT) | |||
grep -F 'export: ' $(XCACHE_PROC_OUT) | sed -r 's/.*export:(.*):export.*/\1/g' | $(XCACHE_INDENT) > $(XCACHE_PROC_H).tmp && mv -f $(XCACHE_PROC_H).tmp $(XCACHE_PROC_H) | |||
$(XCACHE_PROC_C): $(XCACHE_PROC_OUT) $(XCACHE_PROC_H) | |||
cat $(XCACHE_PROC_OUT) | $(XCACHE_INDENT) > $(XCACHE_PROC_C).tmp && mv -f $(XCACHE_PROC_C).tmp $(XCACHE_PROC_C) | |||
$(builddir)/processor.lo: $(XCACHE_PROC_C) $(XCACHE_PROC_H) $(srcdir)/processor.c | |||
$(builddir)/disassembler.lo: $(XCACHE_PROC_H) $(srcdir)/processor.c | |||
$(builddir)/xcache.lo: $(XCACHE_PROC_H) $(srcdir)/myshm.h $(srcdir)/stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.c |
@ -0,0 +1,18 @@ | |||
#ifndef __ALIGN_H | |||
#define __ALIGN_H | |||
typedef union align_union { | |||
double d; | |||
void *v; | |||
int (*func)(int); | |||
long l; | |||
} align_union; | |||
#if (defined (__GNUC__) && __GNUC__ >= 2) | |||
#define XCACHE_PLATFORM_ALIGNMENT (__alignof__ (align_union)) | |||
#else | |||
#define XCACHE_PLATFORM_ALIGNMENT (sizeof(align_union)) | |||
#endif | |||
#define ALIGN(n) ((((size_t)(n)-1) & ~(XCACHE_PLATFORM_ALIGNMENT-1)) + XCACHE_PLATFORM_ALIGNMENT) | |||
#endif /* __ALIGN_H */ |
@ -0,0 +1,61 @@ | |||
dnl | |||
dnl $Id:$ | |||
dnl vim:ts=2:sw=2:expandtab | |||
AC_DEFUN([XCACHE_OPTION], [ | |||
PHP_ARG_ENABLE(xcache-$1, for XCACHE $1, | |||
[ --enable-xcache-$2 XCACHE: $4], no, no) | |||
if test "$PHP_$3" = "yes"; then | |||
xcache_sources="$xcache_sources $1.c" | |||
AC_DEFINE([HAVE_$3], 1, [Define for XCACHE: $4]) | |||
fi | |||
])dnl | |||
PHP_ARG_ENABLE(xcache, for XCACHE support, | |||
[ --enable-xcache Include XCACHE support.]) | |||
if test "$PHP_XCACHE" != "no"; then | |||
xcache_sources="processor.c \ | |||
xcache.c \ | |||
mmap.c \ | |||
mem.c \ | |||
const_string.c \ | |||
opcode_spec.c \ | |||
stack.c \ | |||
utils.c \ | |||
lock.c \ | |||
" | |||
XCACHE_OPTION([optimizer], [optimizer ], [XCACHE_OPTIMIZER], [(N/A)]) | |||
XCACHE_OPTION([coverage], [coverage ], [XCACHE_COVERAGE], [Enable code coverage dumper, NOT for production server]) | |||
XCACHE_OPTION([assembler], [assembler ], [XCACHE_ASSEMBLER], [(N/A)]) | |||
XCACHE_OPTION([disassembler], [disassembler], [XCACHE_DISASSEMBLER], [Enable opcode to php variable dumper, NOT for production server]) | |||
XCACHE_OPTION([encoder], [encoder ], [XCACHE_ENCODER], [(N/A)]) | |||
XCACHE_OPTION([decoder], [decoder ], [XCACHE_DECODER], [(N/A)]) | |||
PHP_NEW_EXTENSION(xcache, $xcache_sources, $ext_shared) | |||
PHP_ADD_MAKEFILE_FRAGMENT() | |||
PHP_ARG_ENABLE(xcache-test, for XCACHE self test, | |||
[ --enable-xcache-test XCACHE: Enable self test - FOR DEVELOPERS ONLY!!], no, no) | |||
if test "$PHP_XCACHE_TEST" = "yes"; then | |||
XCACHE_ENABLE_TEST=-DXCACHE_ENABLE_TEST | |||
AC_DEFINE([HAVE_XCACHE_TEST], 1, [Define to enable XCACHE self test]) | |||
else | |||
XCACHE_ENABLE_TEST= | |||
fi | |||
PHP_SUBST([XCACHE_ENABLE_TEST]) | |||
AC_PATH_PROGS(INDENT, [indent cat]) | |||
case $INDENT in | |||
*/indent[)] | |||
XCACHE_INDENT="$INDENT -kr --use-tabs --tab-size 4 -sob -nce" | |||
;; | |||
*[)] | |||
XCACHE_INDENT=cat | |||
;; | |||
esac | |||
PHP_SUBST([XCACHE_INDENT]) | |||
XCACHE_PROC_SOURCES=`ls $ac_srcdir/processor/*.m4` | |||
PHP_SUBST([XCACHE_PROC_SOURCES]) | |||
fi |
@ -0,0 +1,114 @@ | |||
#include "xcache.h" | |||
#include "const_string.h" | |||
/* {{{ xc_get_op_type */ | |||
static const char *const op_type_names[] = { | |||
/* 0 */ "NULL?", | |||
/* 1 */ "IS_CONST", | |||
/* 2 */ "IS_TMP_VAR", | |||
/* 3 */ NULL, | |||
/* 4 */ "IS_VAR", | |||
/* 5 */ NULL, | |||
/* 6 */ NULL, | |||
/* 7 */ NULL, | |||
/* 8 */ "IS_UNUSED", | |||
#ifdef IS_CV | |||
/* 9 */ NULL, | |||
/* 10 */ NULL, | |||
/* 11 */ NULL, | |||
/* 12 */ NULL, | |||
/* 13 */ NULL, | |||
/* 14 */ NULL, | |||
/* 15 */ NULL, | |||
/* 16 */ "IS_CV" | |||
#endif | |||
}; | |||
int xc_get_op_type_count() | |||
{ | |||
return sizeof(op_type_names) / sizeof(op_type_names[0]); | |||
} | |||
const char *xc_get_op_type(zend_uchar op_type) | |||
{ | |||
assert(op_type < xc_get_op_type_count()); | |||
return op_type_names[op_type]; | |||
} | |||
/* }}} */ | |||
/* {{{ xc_get_data_type */ | |||
static const char *const data_type_names[] = { | |||
/* 0 */ "IS_NULL", | |||
/* 1 */ "IS_LONG", | |||
/* 2 */ "IS_DOUBLE", | |||
/* 3 */ "IS_BOOL", | |||
/* 4 */ "IS_ARRAY", | |||
/* 5 */ "IS_OBJECT", | |||
/* 6 */ "IS_STRING", | |||
/* 7 */ "IS_RESOURCE", | |||
/* 8 */ "IS_CONSTANT", | |||
/* 9 */ "IS_CONSTANT_ARRAY", | |||
/* 10 */ "IS_UNICODE", | |||
#if 0 | |||
/* 11 */ "", | |||
/* 12 */ "", | |||
/* 13 */ "", | |||
/* 14 */ "", | |||
/* 15 */ "", "", "", "", "", | |||
/* IS_CONSTANT_INDEX */ | |||
/* 20 */ "CIDX IS_NULL", | |||
/* 21 */ "CIDX IS_LONG", | |||
/* 22 */ "CIDX IS_DOUBLE", | |||
/* 23 */ "CIDX IS_BOOL", | |||
/* 24 */ "CIDX IS_ARRAY", | |||
/* 25 */ "CIDX IS_OBJECT", | |||
/* 26 */ "CIDX IS_STRING", | |||
/* 27 */ "CIDX IS_RESOURCE", | |||
/* 28 */ "CIDX IS_CONSTANT", | |||
/* 29 */ "CIDX IS_CONSTANT_ARRAY" | |||
/* 20 */ "CIDX IS_UNICODE", | |||
#endif | |||
}; | |||
int xc_get_data_type_count() | |||
{ | |||
return sizeof(data_type_names) / sizeof(data_type_names[0]); | |||
} | |||
const char *xc_get_data_type(zend_uchar data_type) | |||
{ | |||
#if 0 | |||
if (data_type & IS_CONSTANT_INDEX) { | |||
data_type = (data_type & ~IS_CONSTANT_INDEX) + 20; | |||
} | |||
#endif | |||
data_type &= ~IS_CONSTANT_INDEX; | |||
return data_type_names[data_type]; | |||
} | |||
/* }}} */ | |||
/* {{{ xc_get_opcode */ | |||
#if PHP_MAJAR_VERSION >= 6 | |||
# include "const_string_opcodes_php6.x.h" | |||
#else | |||
# ifdef ZEND_ENGINE_2_1 | |||
# include "const_string_opcodes_php5.1.h" | |||
# else | |||
# ifdef ZEND_ENGINE_2 | |||
# include "const_string_opcodes_php5.0.h" | |||
# else | |||
# include "const_string_opcodes_php4.x.h" | |||
# endif | |||
# endif | |||
#endif | |||
int xc_get_opcode_count() | |||
{ | |||
return sizeof(xc_opcode_names) / sizeof(xc_opcode_names[0]); | |||
} | |||
const char *xc_get_opcode(zend_uchar opcode) | |||
{ | |||
assert(opcode < xc_get_opcode_count()); | |||
return xc_opcode_names[opcode]; | |||
} | |||
/* }}} */ |
@ -0,0 +1,8 @@ | |||
#include "php.h" | |||
int xc_get_op_type_count(); | |||
const char *xc_get_op_type(zend_uchar op_type); | |||
int xc_get_data_type_count(); | |||
const char *xc_get_data_type(zend_uchar data_type); | |||
int xc_get_opcode_count(); | |||
const char *xc_get_opcode(zend_uchar opcode); |
@ -0,0 +1,116 @@ | |||
/* size = 112 */ | |||
static const char *const xc_opcode_names[] = { | |||
/* 0 */ "NOP", | |||
/* 1 */ "ADD", | |||
/* 2 */ "SUB", | |||
/* 3 */ "MUL", | |||
/* 4 */ "DIV", | |||
/* 5 */ "MOD", | |||
/* 6 */ "SL", | |||
/* 7 */ "SR", | |||
/* 8 */ "CONCAT", | |||
/* 9 */ "BW_OR", | |||
/* 10 */ "BW_AND", | |||
/* 11 */ "BW_XOR", | |||
/* 12 */ "BW_NOT", | |||
/* 13 */ "BOOL_NOT", | |||
/* 14 */ "BOOL_XOR", | |||
/* 15 */ "IS_IDENTICAL", | |||
/* 16 */ "IS_NOT_IDENTICAL", | |||
/* 17 */ "IS_EQUAL", | |||
/* 18 */ "IS_NOT_EQUAL", | |||
/* 19 */ "IS_SMALLER", | |||
/* 20 */ "IS_SMALLER_OR_EQUAL", | |||
/* 21 */ "CAST", | |||
/* 22 */ "QM_ASSIGN", | |||
/* 23 */ "ASSIGN_ADD", | |||
/* 24 */ "ASSIGN_SUB", | |||
/* 25 */ "ASSIGN_MUL", | |||
/* 26 */ "ASSIGN_DIV", | |||
/* 27 */ "ASSIGN_MOD", | |||
/* 28 */ "ASSIGN_SL", | |||
/* 29 */ "ASSIGN_SR", | |||
/* 30 */ "ASSIGN_CONCAT", | |||
/* 31 */ "ASSIGN_BW_OR", | |||
/* 32 */ "ASSIGN_BW_AND", | |||
/* 33 */ "ASSIGN_BW_XOR", | |||
/* 34 */ "PRE_INC", | |||
/* 35 */ "PRE_DEC", | |||
/* 36 */ "POST_INC", | |||
/* 37 */ "POST_DEC", | |||
/* 38 */ "ASSIGN", | |||
/* 39 */ "ASSIGN_REF", | |||
/* 40 */ "ECHO", | |||
/* 41 */ "PRINT", | |||
/* 42 */ "JMP", | |||
/* 43 */ "JMPZ", | |||
/* 44 */ "JMPNZ", | |||
/* 45 */ "JMPZNZ", | |||
/* 46 */ "JMPZ_EX", | |||
/* 47 */ "JMPNZ_EX", | |||
/* 48 */ "CASE", | |||
/* 49 */ "SWITCH_FREE", | |||
/* 50 */ "BRK", | |||
/* 51 */ "CONT", | |||
/* 52 */ "BOOL", | |||
/* 53 */ "INIT_STRING", | |||
/* 54 */ "ADD_CHAR", | |||
/* 55 */ "ADD_STRING", | |||
/* 56 */ "ADD_VAR", | |||
/* 57 */ "BEGIN_SILENCE", | |||
/* 58 */ "END_SILENCE", | |||
/* 59 */ "INIT_FCALL_BY_NAME", | |||
/* 60 */ "DO_FCALL", | |||
/* 61 */ "DO_FCALL_BY_NAME", | |||
/* 62 */ "RETURN", | |||
/* 63 */ "RECV", | |||
/* 64 */ "RECV_INIT", | |||
/* 65 */ "SEND_VAL", | |||
/* 66 */ "SEND_VAR", | |||
/* 67 */ "SEND_REF", | |||
/* 68 */ "NEW", | |||
/* 69 */ "JMP_NO_CTOR", | |||
/* 70 */ "FREE", | |||
/* 71 */ "INIT_ARRAY", | |||
/* 72 */ "ADD_ARRAY_ELEMENT", | |||
/* 73 */ "INCLUDE_OR_EVAL", | |||
/* 74 */ "UNSET_VAR", | |||
/* 75 */ "UNSET_DIM_OBJ", | |||
/* 76 */ "ISSET_ISEMPTY", | |||
/* 77 */ "FE_RESET", | |||
/* 78 */ "FE_FETCH", | |||
/* 79 */ "EXIT", | |||
/* 80 */ "FETCH_R", | |||
/* 81 */ "FETCH_DIM_R", | |||
/* 82 */ "FETCH_OBJ_R", | |||
/* 83 */ "FETCH_W", | |||
/* 84 */ "FETCH_DIM_W", | |||
/* 85 */ "FETCH_OBJ_W", | |||
/* 86 */ "FETCH_RW", | |||
/* 87 */ "FETCH_DIM_RW", | |||
/* 88 */ "FETCH_OBJ_RW", | |||
/* 89 */ "FETCH_IS", | |||
/* 90 */ "FETCH_DIM_IS", | |||
/* 91 */ "FETCH_OBJ_IS", | |||
/* 92 */ "FETCH_FUNC_ARG", | |||
/* 93 */ "FETCH_DIM_FUNC_ARG", | |||
/* 94 */ "FETCH_OBJ_FUNC_ARG", | |||
/* 95 */ "FETCH_UNSET", | |||
/* 96 */ "FETCH_DIM_UNSET", | |||
/* 97 */ "FETCH_OBJ_UNSET", | |||
/* 98 */ "FETCH_DIM_TMP_VAR", | |||
/* 99 */ "FETCH_CONSTANT", | |||
/* 100 */ "DECLARE_FUNCTION_OR_CLASS", | |||
/* 101 */ "EXT_STMT", | |||
/* 102 */ "EXT_FCALL_BEGIN", | |||
/* 103 */ "EXT_FCALL_END", | |||
/* 104 */ "EXT_NOP", | |||
/* 105 */ "TICKS", | |||
/* 106 */ "SEND_VAR_NO_REF", | |||
/* 107 */ "UNDEF", | |||
/* 108 */ "UNDEF", | |||
/* 109 */ "UNDEF", | |||
/* 110 */ "DO_FCALL_BY_FUNC", | |||
/* 111 */ "INIT_FCALL_BY_FUNC", | |||
/* 112 */ "UNDEF" | |||
}; |
@ -0,0 +1,154 @@ | |||
/* size = 150 */ | |||
static const char *const xc_opcode_names[] = { | |||
/* 0 */ "NOP", | |||
/* 1 */ "ADD", | |||
/* 2 */ "SUB", | |||
/* 3 */ "MUL", | |||
/* 4 */ "DIV", | |||
/* 5 */ "MOD", | |||
/* 6 */ "SL", | |||
/* 7 */ "SR", | |||
/* 8 */ "CONCAT", | |||
/* 9 */ "BW_OR", | |||
/* 10 */ "BW_AND", | |||
/* 11 */ "BW_XOR", | |||
/* 12 */ "BW_NOT", | |||
/* 13 */ "BOOL_NOT", | |||
/* 14 */ "BOOL_XOR", | |||
/* 15 */ "IS_IDENTICAL", | |||
/* 16 */ "IS_NOT_IDENTICAL", | |||
/* 17 */ "IS_EQUAL", | |||
/* 18 */ "IS_NOT_EQUAL", | |||
/* 19 */ "IS_SMALLER", | |||
/* 20 */ "IS_SMALLER_OR_EQUAL", | |||
/* 21 */ "CAST", | |||
/* 22 */ "QM_ASSIGN", | |||
/* 23 */ "ASSIGN_ADD", | |||
/* 24 */ "ASSIGN_SUB", | |||
/* 25 */ "ASSIGN_MUL", | |||
/* 26 */ "ASSIGN_DIV", | |||
/* 27 */ "ASSIGN_MOD", | |||
/* 28 */ "ASSIGN_SL", | |||
/* 29 */ "ASSIGN_SR", | |||
/* 30 */ "ASSIGN_CONCAT", | |||
/* 31 */ "ASSIGN_BW_OR", | |||
/* 32 */ "ASSIGN_BW_AND", | |||
/* 33 */ "ASSIGN_BW_XOR", | |||
/* 34 */ "PRE_INC", | |||
/* 35 */ "PRE_DEC", | |||
/* 36 */ "POST_INC", | |||
/* 37 */ "POST_DEC", | |||
/* 38 */ "ASSIGN", | |||
/* 39 */ "ASSIGN_REF", | |||
/* 40 */ "ECHO", | |||
/* 41 */ "PRINT", | |||
/* 42 */ "JMP", | |||
/* 43 */ "JMPZ", | |||
/* 44 */ "JMPNZ", | |||
/* 45 */ "JMPZNZ", | |||
/* 46 */ "JMPZ_EX", | |||
/* 47 */ "JMPNZ_EX", | |||
/* 48 */ "CASE", | |||
/* 49 */ "SWITCH_FREE", | |||
/* 50 */ "BRK", | |||
/* 51 */ "CONT", | |||
/* 52 */ "BOOL", | |||
/* 53 */ "INIT_STRING", | |||
/* 54 */ "ADD_CHAR", | |||
/* 55 */ "ADD_STRING", | |||
/* 56 */ "ADD_VAR", | |||
/* 57 */ "BEGIN_SILENCE", | |||
/* 58 */ "END_SILENCE", | |||
/* 59 */ "INIT_FCALL_BY_NAME", | |||
/* 60 */ "DO_FCALL", | |||
/* 61 */ "DO_FCALL_BY_NAME", | |||
/* 62 */ "RETURN", | |||
/* 63 */ "RECV", | |||
/* 64 */ "RECV_INIT", | |||
/* 65 */ "SEND_VAL", | |||
/* 66 */ "SEND_VAR", | |||
/* 67 */ "SEND_REF", | |||
/* 68 */ "NEW", | |||
/* 69 */ "UNDEF", | |||
/* 70 */ "FREE", | |||
/* 71 */ "INIT_ARRAY", | |||
/* 72 */ "ADD_ARRAY_ELEMENT", | |||
/* 73 */ "INCLUDE_OR_EVAL", | |||
/* 74 */ "UNSET_VAR", | |||
/* 75 */ "UNSET_DIM", | |||
/* 76 */ "UNSET_OBJ", | |||
/* 77 */ "FE_RESET", | |||
/* 78 */ "FE_FETCH", | |||
/* 79 */ "EXIT", | |||
/* 80 */ "FETCH_R", | |||
/* 81 */ "FETCH_DIM_R", | |||
/* 82 */ "FETCH_OBJ_R", | |||
/* 83 */ "FETCH_W", | |||
/* 84 */ "FETCH_DIM_W", | |||
/* 85 */ "FETCH_OBJ_W", | |||
/* 86 */ "FETCH_RW", | |||
/* 87 */ "FETCH_DIM_RW", | |||
/* 88 */ "FETCH_OBJ_RW", | |||
/* 89 */ "FETCH_IS", | |||
/* 90 */ "FETCH_DIM_IS", | |||
/* 91 */ "FETCH_OBJ_IS", | |||
/* 92 */ "FETCH_FUNC_ARG", | |||
/* 93 */ "FETCH_DIM_FUNC_ARG", | |||
/* 94 */ "FETCH_OBJ_FUNC_ARG", | |||
/* 95 */ "FETCH_UNSET", | |||
/* 96 */ "FETCH_DIM_UNSET", | |||
/* 97 */ "FETCH_OBJ_UNSET", | |||
/* 98 */ "FETCH_DIM_TMP_VAR", | |||
/* 99 */ "FETCH_CONSTANT", | |||
/* 100 */ "UNDEF", | |||
/* 101 */ "EXT_STMT", | |||
/* 102 */ "EXT_FCALL_BEGIN", | |||
/* 103 */ "EXT_FCALL_END", | |||
/* 104 */ "EXT_NOP", | |||
/* 105 */ "TICKS", | |||
/* 106 */ "SEND_VAR_NO_REF", | |||
/* 107 */ "CATCH", | |||
/* 108 */ "THROW", | |||
/* 109 */ "FETCH_CLASS", | |||
/* 110 */ "CLONE", | |||
/* 111 */ "UNDEF", | |||
/* 112 */ "INIT_METHOD_CALL", | |||
/* 113 */ "INIT_STATIC_METHOD_CALL", | |||
/* 114 */ "ISSET_ISEMPTY_VAR", | |||
/* 115 */ "ISSET_ISEMPTY_DIM_OBJ", | |||
/* 116 */ "UNDEF", | |||
/* 117 */ "UNDEF", | |||
/* 118 */ "UNDEF", | |||
/* 119 */ "UNDEF", | |||
/* 120 */ "UNDEF", | |||
/* 121 */ "UNDEF", | |||
/* 122 */ "UNDEF", | |||
/* 123 */ "UNDEF", | |||
/* 124 */ "UNDEF", | |||
/* 125 */ "UNDEF", | |||
/* 126 */ "UNDEF", | |||
/* 127 */ "UNDEF", | |||
/* 128 */ "UNDEF", | |||
/* 129 */ "UNDEF", | |||
/* 130 */ "UNDEF", | |||
/* 131 */ "UNDEF", | |||
/* 132 */ "PRE_INC_OBJ", | |||
/* 133 */ "PRE_DEC_OBJ", | |||
/* 134 */ "POST_INC_OBJ", | |||
/* 135 */ "POST_DEC_OBJ", | |||
/* 136 */ "ASSIGN_OBJ", | |||
/* 137 */ "OP_DATA", | |||
/* 138 */ "INSTANCEOF", | |||
/* 139 */ "DECLARE_CLASS", | |||
/* 140 */ "DECLARE_INHERITED_CLASS", | |||
/* 141 */ "DECLARE_FUNCTION", | |||
/* 142 */ "RAISE_ABSTRACT_ERROR", | |||
/* 143 */ "UNDEF", | |||
/* 144 */ "ADD_INTERFACE", | |||
/* 145 */ "UNDEF", | |||
/* 146 */ "VERIFY_ABSTRACT_CLASS", | |||
/* 147 */ "ASSIGN_DIM", | |||
/* 148 */ "ISSET_ISEMPTY_PROP_OBJ", | |||
/* 149 */ "HANDLE_EXCEPTION", | |||
/* 150 */ "USER_OPCODE" | |||
}; |
@ -0,0 +1,155 @@ | |||
/* size = 151 */ | |||
static const char *const xc_opcode_names[] = { | |||
/* 0 */ "NOP", | |||
/* 1 */ "ADD", | |||
/* 2 */ "SUB", | |||
/* 3 */ "MUL", | |||
/* 4 */ "DIV", | |||
/* 5 */ "MOD", | |||
/* 6 */ "SL", | |||
/* 7 */ "SR", | |||
/* 8 */ "CONCAT", | |||
/* 9 */ "BW_OR", | |||
/* 10 */ "BW_AND", | |||
/* 11 */ "BW_XOR", | |||
/* 12 */ "BW_NOT", | |||
/* 13 */ "BOOL_NOT", | |||
/* 14 */ "BOOL_XOR", | |||
/* 15 */ "IS_IDENTICAL", | |||
/* 16 */ "IS_NOT_IDENTICAL", | |||
/* 17 */ "IS_EQUAL", | |||
/* 18 */ "IS_NOT_EQUAL", | |||
/* 19 */ "IS_SMALLER", | |||
/* 20 */ "IS_SMALLER_OR_EQUAL", | |||
/* 21 */ "CAST", | |||
/* 22 */ "QM_ASSIGN", | |||
/* 23 */ "ASSIGN_ADD", | |||
/* 24 */ "ASSIGN_SUB", | |||
/* 25 */ "ASSIGN_MUL", | |||
/* 26 */ "ASSIGN_DIV", | |||
/* 27 */ "ASSIGN_MOD", | |||
/* 28 */ "ASSIGN_SL", | |||
/* 29 */ "ASSIGN_SR", | |||
/* 30 */ "ASSIGN_CONCAT", | |||
/* 31 */ "ASSIGN_BW_OR", | |||
/* 32 */ "ASSIGN_BW_AND", | |||
/* 33 */ "ASSIGN_BW_XOR", | |||
/* 34 */ "PRE_INC", | |||
/* 35 */ "PRE_DEC", | |||
/* 36 */ "POST_INC", | |||
/* 37 */ "POST_DEC", | |||
/* 38 */ "ASSIGN", | |||
/* 39 */ "ASSIGN_REF", | |||
/* 40 */ "ECHO", | |||
/* 41 */ "PRINT", | |||
/* 42 */ "JMP", | |||
/* 43 */ "JMPZ", | |||
/* 44 */ "JMPNZ", | |||
/* 45 */ "JMPZNZ", | |||
/* 46 */ "JMPZ_EX", | |||
/* 47 */ "JMPNZ_EX", | |||
/* 48 */ "CASE", | |||
/* 49 */ "SWITCH_FREE", | |||
/* 50 */ "BRK", | |||
/* 51 */ "CONT", | |||
/* 52 */ "BOOL", | |||
/* 53 */ "INIT_STRING", | |||
/* 54 */ "ADD_CHAR", | |||
/* 55 */ "ADD_STRING", | |||
/* 56 */ "ADD_VAR", | |||
/* 57 */ "BEGIN_SILENCE", | |||
/* 58 */ "END_SILENCE", | |||
/* 59 */ "INIT_FCALL_BY_NAME", | |||
/* 60 */ "DO_FCALL", | |||
/* 61 */ "DO_FCALL_BY_NAME", | |||
/* 62 */ "RETURN", | |||
/* 63 */ "RECV", | |||
/* 64 */ "RECV_INIT", | |||
/* 65 */ "SEND_VAL", | |||
/* 66 */ "SEND_VAR", | |||
/* 67 */ "SEND_REF", | |||
/* 68 */ "NEW", | |||
/* 69 */ "UNDEF", | |||
/* 70 */ "FREE", | |||
/* 71 */ "INIT_ARRAY", | |||
/* 72 */ "ADD_ARRAY_ELEMENT", | |||
/* 73 */ "INCLUDE_OR_EVAL", | |||
/* 74 */ "UNSET_VAR", | |||
/* 75 */ "UNSET_DIM", | |||
/* 76 */ "UNSET_OBJ", | |||
/* 77 */ "FE_RESET", | |||
/* 78 */ "FE_FETCH", | |||
/* 79 */ "EXIT", | |||
/* 80 */ "FETCH_R", | |||
/* 81 */ "FETCH_DIM_R", | |||
/* 82 */ "FETCH_OBJ_R", | |||
/* 83 */ "FETCH_W", | |||
/* 84 */ "FETCH_DIM_W", | |||
/* 85 */ "FETCH_OBJ_W", | |||
/* 86 */ "FETCH_RW", | |||
/* 87 */ "FETCH_DIM_RW", | |||
/* 88 */ "FETCH_OBJ_RW", | |||
/* 89 */ "FETCH_IS", | |||
/* 90 */ "FETCH_DIM_IS", | |||
/* 91 */ "FETCH_OBJ_IS", | |||
/* 92 */ "FETCH_FUNC_ARG", | |||
/* 93 */ "FETCH_DIM_FUNC_ARG", | |||
/* 94 */ "FETCH_OBJ_FUNC_ARG", | |||
/* 95 */ "FETCH_UNSET", | |||
/* 96 */ "FETCH_DIM_UNSET", | |||
/* 97 */ "FETCH_OBJ_UNSET", | |||
/* 98 */ "FETCH_DIM_TMP_VAR", | |||
/* 99 */ "FETCH_CONSTANT", | |||
/* 100 */ "UNDEF", | |||
/* 101 */ "EXT_STMT", | |||
/* 102 */ "EXT_FCALL_BEGIN", | |||
/* 103 */ "EXT_FCALL_END", | |||
/* 104 */ "EXT_NOP", | |||
/* 105 */ "TICKS", | |||
/* 106 */ "SEND_VAR_NO_REF", | |||
/* 107 */ "CATCH", | |||
/* 108 */ "THROW", | |||
/* 109 */ "FETCH_CLASS", | |||
/* 110 */ "CLONE", | |||
/* 111 */ "UNDEF", | |||
/* 112 */ "INIT_METHOD_CALL", | |||
/* 113 */ "INIT_STATIC_METHOD_CALL", | |||
/* 114 */ "ISSET_ISEMPTY_VAR", | |||
/* 115 */ "ISSET_ISEMPTY_DIM_OBJ", | |||
/* 116 */ "UNDEF", | |||
/* 117 */ "UNDEF", | |||
/* 118 */ "UNDEF", | |||
/* 119 */ "UNDEF", | |||
/* 120 */ "UNDEF", | |||
/* 121 */ "UNDEF", | |||
/* 122 */ "UNDEF", | |||
/* 123 */ "UNDEF", | |||
/* 124 */ "UNDEF", | |||
/* 125 */ "UNDEF", | |||
/* 126 */ "UNDEF", | |||
/* 127 */ "UNDEF", | |||
/* 128 */ "UNDEF", | |||
/* 129 */ "UNDEF", | |||
/* 130 */ "UNDEF", | |||
/* 131 */ "UNDEF", | |||
/* 132 */ "PRE_INC_OBJ", | |||
/* 133 */ "PRE_DEC_OBJ", | |||
/* 134 */ "POST_INC_OBJ", | |||
/* 135 */ "POST_DEC_OBJ", | |||
/* 136 */ "ASSIGN_OBJ", | |||
/* 137 */ "OP_DATA", | |||
/* 138 */ "INSTANCEOF", | |||
/* 139 */ "DECLARE_CLASS", | |||
/* 140 */ "DECLARE_INHERITED_CLASS", | |||
/* 141 */ "DECLARE_FUNCTION", | |||
/* 142 */ "RAISE_ABSTRACT_ERROR", | |||
/* 143 */ "UNDEF", | |||
/* 144 */ "ADD_INTERFACE", | |||
/* 145 */ "UNDEF", | |||
/* 146 */ "VERIFY_ABSTRACT_CLASS", | |||
/* 147 */ "ASSIGN_DIM", | |||
/* 148 */ "ISSET_ISEMPTY_PROP_OBJ", | |||
/* 149 */ "HANDLE_EXCEPTION", | |||
/* 150 */ "USER_OPCODE", | |||
/* 151 */ "U_NORMALIZE" | |||
}; |
@ -0,0 +1,425 @@ | |||
#include <stdio.h> | |||
#include "xcache.h" | |||
#include "ext/standard/flock_compat.h" | |||
#ifdef HAVE_SYS_FILE_H | |||
# include <sys/file.h> | |||
#endif | |||
#include "stack.h" | |||
#include "xcache_globals.h" | |||
#include "coverage.h" | |||
#include "utils.h" | |||
typedef HashTable *coverage_t; | |||
#define PCOV_HEADER_MAGIC 0x564f4350 | |||
char *xc_coveragedump_dir = NULL; | |||
static zend_compile_file_t *origin_compile_file; | |||
#undef DEBUG | |||
/* dumper */ | |||
static void xc_destroy_coverage(void *pDest) /* {{{ */ | |||
{ | |||
coverage_t cov = *(coverage_t*) pDest; | |||
#ifdef DEBUG | |||
fprintf(stderr, "destroy %p\n", cov); | |||
#endif | |||
zend_hash_destroy(cov); | |||
efree(cov); | |||
} | |||
/* }}} */ | |||
PHPAPI void xcache_mkdirs_ex(char *root, int rootlen, char *path, int pathlen TSRMLS_DC) /* {{{ */ | |||
{ | |||
char *fullpath; | |||
struct stat st; | |||
#ifdef DEBUG | |||
fprintf(stderr, "mkdirs %s %d %s %d\n", root, rootlen, path, pathlen); | |||
#endif | |||
fullpath = do_alloca(rootlen + pathlen + 1); | |||
memcpy(fullpath, root, rootlen); | |||
memcpy(fullpath + rootlen, path, pathlen); | |||
fullpath[rootlen + pathlen] = '\0'; | |||
if (stat(fullpath, &st) != 0) { | |||
char *chr; | |||
chr = strrchr(path, PHP_DIR_SEPARATOR); | |||
if (chr && chr != path) { | |||
*chr = '\0'; | |||
xcache_mkdirs_ex(root, rootlen, path, chr - path TSRMLS_CC); | |||
*chr = PHP_DIR_SEPARATOR; | |||
} | |||
#ifdef DEBUG | |||
fprintf(stderr, "mkdir %s\n", fullpath); | |||
#endif | |||
php_stream_mkdir(fullpath, 0700, REPORT_ERRORS, NULL); | |||
} | |||
free_alloca(fullpath); | |||
} | |||
/* }}} */ | |||
static void xc_coverage_save_cov(char *srcfile, char *outfilename, coverage_t cov TSRMLS_DC) /* {{{ */ | |||
{ | |||
long *buf = NULL, *p; | |||
long covlines, *phits; | |||
int fd = -1; | |||
int size; | |||
int newfile; | |||
struct stat srcstat, outstat; | |||
HashPosition pos; | |||
char *contents = NULL; | |||
long len; | |||
if (stat(srcfile, &srcstat) != 0) { | |||
return; | |||
} | |||
newfile = 0; | |||
if (stat(outfilename, &outstat) != 0) { | |||
newfile = 1; | |||
} | |||
else { | |||
if (srcstat.st_mtime > outstat.st_mtime) { | |||
newfile = 1; | |||
} | |||
} | |||
fd = open(outfilename, O_RDWR | O_CREAT, 0600); | |||
if (fd < 0) { | |||
char *chr; | |||
chr = strrchr(srcfile, PHP_DIR_SEPARATOR); | |||
if (chr) { | |||
*chr = '\0'; | |||
xcache_mkdirs_ex(xc_coveragedump_dir, strlen(xc_coveragedump_dir), srcfile, chr - srcfile TSRMLS_CC); | |||
*chr = PHP_DIR_SEPARATOR; | |||
} | |||
fd = open(outfilename, O_RDWR | O_CREAT, 0600); | |||
if (fd < 0) { | |||
goto bailout; | |||
} | |||
} | |||
if (flock(fd, LOCK_EX) != SUCCESS) { | |||
goto bailout; | |||
} | |||
if (newfile) { | |||
#ifdef DEBUG | |||
fprintf(stderr, "new file\n"); | |||
#endif | |||
} | |||
else if (outstat.st_size) { | |||
len = outstat.st_size; | |||
contents = emalloc(len); | |||
if (read(fd, (void *) contents, len) != len) { | |||
goto bailout; | |||
} | |||
#ifdef DEBUG | |||
fprintf(stderr, "oldsize %d\n", (int) len); | |||
#endif | |||
do { | |||
p = (long *) contents; | |||
len -= sizeof(long); | |||
if (len < 0) { | |||
break; | |||
} | |||
if (*p++ != PCOV_HEADER_MAGIC) { | |||
#ifdef DEBUG | |||
fprintf(stderr, "wrong magic in file %s\n", outfilename); | |||
#endif | |||
break; | |||
} | |||
p += 2; /* skip covliens */ | |||
len -= sizeof(long) * 2; | |||
if (len < 0) { | |||
break; | |||
} | |||
for (; len >= sizeof(long) * 2; len -= sizeof(long) * 2, p += 2) { | |||
if (zend_hash_index_find(cov, p[0], (void**)&phits) == SUCCESS) { | |||
if (p[1] <= 0) { | |||
/* already marked */ | |||
continue; | |||
} | |||
if (*phits > 0) { | |||
p[1] += *phits; | |||
} | |||
} | |||
zend_hash_index_update(cov, p[0], &p[1], sizeof(p[1]), NULL); | |||
} | |||
} while (0); | |||
efree(contents); | |||
contents = NULL; | |||
} | |||
/* serialize */ | |||
size = (zend_hash_num_elements(cov) + 1) * sizeof(long) * 2 + sizeof(long); | |||
p = buf = emalloc(size); | |||
*p++ = PCOV_HEADER_MAGIC; | |||
p += 2; /* for covlines */ | |||
covlines = 0; | |||
zend_hash_internal_pointer_reset_ex(cov, &pos); | |||
while (zend_hash_get_current_data_ex(cov, (void**)&phits, &pos) == SUCCESS) { | |||
*p++ = pos->h; | |||
if (*phits <= 0) { | |||
*p++ = 0; | |||
} | |||
else { | |||
*p++ = *phits; | |||
covlines ++; | |||
} | |||
zend_hash_move_forward_ex(cov, &pos); | |||
} | |||
p = buf + 1; | |||
p[0] = 0; | |||
p[1] = covlines; | |||
ftruncate(fd, 0); | |||
lseek(fd, 0, SEEK_SET); | |||
write(fd, (char *) buf, size); | |||
bailout: | |||
if (contents) efree(contents); | |||
if (fd >= 0) close(fd); | |||
if (buf) efree(buf); | |||
} | |||
/* }}} */ | |||
void xc_coverage_request_init(TSRMLS_D) /* {{{ */ | |||
{ | |||
if (XG(coveragedumper)) { | |||
XG(coverages) = emalloc(sizeof(HashTable)); | |||
zend_hash_init(XG(coverages), 0, NULL, xc_destroy_coverage, 0); | |||
} | |||
} | |||
/* }}} */ | |||
void xc_coverage_request_shutdown(TSRMLS_D) /* {{{ */ | |||
{ | |||
coverage_t *pcov; | |||
zstr s; | |||
char *outfilename; | |||
int dumpdir_len, outfilelen, size, alloc_len = 0; | |||
if (!XG(coverages)) { | |||
return; | |||
} | |||
if (XG(coveragedumper)) { | |||
dumpdir_len = strlen(xc_coveragedump_dir); | |||
alloc_len = dumpdir_len + 1 + 128; | |||
outfilename = emalloc(alloc_len); | |||
strcpy(outfilename, xc_coveragedump_dir); | |||
zend_hash_internal_pointer_reset(XG(coverages)); | |||
while (zend_hash_get_current_data(XG(coverages), (void **) &pcov) == SUCCESS) { | |||
zend_hash_get_current_key_ex(XG(coverages), &s, &size, NULL, 0, NULL); | |||
outfilelen = dumpdir_len + size + 5; | |||
if (alloc_len < outfilelen) { | |||
alloc_len = outfilelen + 128; | |||
outfilename = erealloc(outfilename, alloc_len); | |||
} | |||
strcpy(outfilename + dumpdir_len, ZSTR_S(s)); | |||
strcpy(outfilename + dumpdir_len + size - 1, ".pcov"); | |||
#ifdef DEBUG | |||
fprintf(stderr, "outfilename %s\n", outfilename); | |||
#endif | |||
xc_coverage_save_cov(ZSTR_S(s), outfilename, *pcov TSRMLS_CC); | |||
zend_hash_move_forward(XG(coverages)); | |||
} | |||
} | |||
zend_hash_destroy(XG(coverages)); | |||
efree(XG(coverages)); | |||
XG(coverages) = NULL; | |||
} | |||
/* }}} */ | |||
/* helper func to store hits into coverages */ | |||
static coverage_t xc_coverage_get(char *filename TSRMLS_DC) /* {{{ */ | |||
{ | |||
int len = strlen(filename) + 1; | |||
coverage_t cov, *pcov; | |||
if (zend_hash_find(XG(coverages), filename, len, (void **) &pcov) == SUCCESS) { | |||
#ifdef DEBUG | |||
fprintf(stderr, "got coverage %s %p\n", filename, *pcov); | |||
#endif | |||
return *pcov; | |||
} | |||
else { | |||
cov = emalloc(sizeof(HashTable)); | |||
zend_hash_init(cov, 0, NULL, NULL, 0); | |||
zend_hash_add(XG(coverages), filename, len, (void **) &cov, sizeof(cov), NULL); | |||
#ifdef DEBUG | |||
fprintf(stderr, "new coverage %s %p\n", filename, cov); | |||
#endif | |||
return cov; | |||
} | |||
} | |||
/* }}} */ | |||
static void xc_coverage_add_hits(HashTable *cov, long line, long hits TSRMLS_DC) /* {{{ */ | |||
{ | |||
long *poldhits; | |||
if (line == 0) { | |||
return; | |||
} | |||
if (zend_hash_index_find(cov, line, (void**)&poldhits) == SUCCESS) { | |||
if (hits == -1) { | |||
/* already marked */ | |||
return; | |||
} | |||
if (*poldhits != -1) { | |||
hits += *poldhits; | |||
} | |||
} | |||
zend_hash_index_update(cov, line, &hits, sizeof(hits), NULL); | |||
} | |||
/* }}} */ | |||
static int xc_coverage_get_op_array_size_no_tail(zend_op_array *op_array) /* {{{ */ | |||
{ | |||
zend_uint size; | |||
size = op_array->size; | |||
#ifdef ZEND_ENGINE_2 | |||
if (op_array->opcodes[size - 1].opcode == ZEND_HANDLE_EXCEPTION) { | |||
size --; | |||
#endif | |||
if (op_array->opcodes[size - 1].opcode == ZEND_RETURN) { | |||
size --; | |||
/* it's not real php statement */ | |||
if (op_array->opcodes[size - 1].opcode == ZEND_EXT_STMT) { | |||
size --; | |||
} | |||
} | |||
#ifdef ZEND_ENGINE_2 | |||
} | |||
#endif | |||
return size; | |||
} | |||
/* }}} */ | |||
/* prefill */ | |||
static int xc_coverage_init_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */ | |||
{ | |||
zend_uint size; | |||
coverage_t cov; | |||
int i; | |||
if (op_array->type != ZEND_USER_FUNCTION) { | |||
return 0; | |||
} | |||
size = xc_coverage_get_op_array_size_no_tail(op_array); | |||
cov = xc_coverage_get(op_array->filename); | |||
for (i = 0; i < size; i++) { | |||
switch (op_array->opcodes[i].opcode) { | |||
case ZEND_EXT_STMT: | |||
#if 0 | |||
case ZEND_EXT_FCALL_BEGIN: | |||
case ZEND_EXT_FCALL_END: | |||
#endif | |||
xc_coverage_add_hits(cov, op_array->opcodes[i].lineno, -1 TSRMLS_CC); | |||
break; | |||
} | |||
} | |||
return 0; | |||
} | |||
/* }}} */ | |||
static void xc_coverage_init_compile_result(zend_op_array *op_array TSRMLS_DC) /* {{{ */ | |||
{ | |||
xc_compile_result_t cr; | |||
xc_compile_result_init_cur(&cr, op_array TSRMLS_CC); | |||
xc_apply_op_array(&cr, (apply_func_t) xc_coverage_init_op_array TSRMLS_CC); | |||
xc_compile_result_free(&cr); | |||
} | |||
/* }}} */ | |||
static zend_op_array *xc_compile_file_for_coverage(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */ | |||
{ | |||
zend_op_array *op_array; | |||
op_array = origin_compile_file(h, type TSRMLS_CC); | |||
if (XG(coveragedumper) && XG(coverages)) { | |||
xc_coverage_init_compile_result(op_array TSRMLS_CC); | |||
} | |||
return op_array; | |||
} | |||
/* }}} */ | |||
/* hits */ | |||
void xc_coverage_handle_ext_stmt(zend_op_array *op_array, zend_uchar op) /* {{{ */ | |||
{ | |||
if (XG(coveragedumper) && XG(coverages)) { | |||
TSRMLS_FETCH(); | |||
int size = xc_coverage_get_op_array_size_no_tail(op_array); | |||
int oplineno = (*EG(opline_ptr)) - op_array->opcodes; | |||
if (oplineno < size) { | |||
xc_coverage_add_hits(xc_coverage_get(op_array->filename), (*EG(opline_ptr))->lineno, 1 TSRMLS_CC); | |||
} | |||
} | |||
} | |||
/* }}} */ | |||
/* init/destroy */ | |||
int xc_coverage_init(int module_number TSRMLS_DC) /* {{{ */ | |||
{ | |||
if (xc_coveragedump_dir) { | |||
int len = strlen(xc_coveragedump_dir); | |||
if (len) { | |||
if (xc_coveragedump_dir[len - 1] == '/') { | |||
xc_coveragedump_dir[len - 1] = '\0'; | |||
} | |||
} | |||
} | |||
if (xc_coveragedump_dir && xc_coveragedump_dir[0]) { | |||
origin_compile_file = zend_compile_file; | |||
zend_compile_file = xc_compile_file_for_coverage; | |||
CG(extended_info) = 1; | |||
} | |||
return SUCCESS; | |||
} | |||
/* }}} */ | |||
void xc_coverage_destroy() /* {{{ */ | |||
{ | |||
if (origin_compile_file == xc_compile_file_for_coverage) { | |||
zend_compile_file = origin_compile_file; | |||
} | |||
if (xc_coveragedump_dir) { | |||
pefree(xc_coveragedump_dir, 1); | |||
xc_coveragedump_dir = NULL; | |||
} | |||
} | |||
/* }}} */ | |||
/* user api */ | |||
PHP_FUNCTION(xcache_coverage_decode) /* {{{ */ | |||
{ | |||
char *str; | |||
int len; | |||
long *p; | |||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE) { | |||
return; | |||
} | |||
array_init(return_value); | |||
p = (long*) str; | |||
len -= sizeof(long); | |||
if (len < 0) { | |||
return; | |||
} | |||
if (*p++ != PCOV_HEADER_MAGIC) { | |||
#ifdef DEBUG | |||
fprintf(stderr, "wrong magic in xcache_coverage_decode"); | |||
#endif | |||
return; | |||
} | |||
for (; len >= sizeof(long) * 2; len -= sizeof(long) * 2, p += 2) { | |||
add_index_long(return_value, p[0], p[1]); | |||
} | |||
} | |||
/* }}} */ | |||
@ -0,0 +1,11 @@ | |||
#include "php.h" | |||
#include "xcache.h" | |||
extern char *xc_coveragedump_dir; | |||
void xc_coverage_handle_ext_stmt(zend_op_array *op_array, zend_uchar op); | |||
int xc_coverage_init(int module_number TSRMLS_DC); | |||
void xc_coverage_destroy(); | |||
void xc_coverage_request_init(TSRMLS_D); | |||
void xc_coverage_request_shutdown(TSRMLS_D); | |||
PHP_FUNCTION(xcache_coverage_decode); |
@ -0,0 +1,154 @@ | |||
#include "disassembler.h" | |||
#include "xcache.h" | |||
#include "utils.h" | |||
#include "processor.h" | |||
#define return_value dst | |||
static void xc_dasm(zval *dst, zend_op_array *op_array TSRMLS_DC) /* {{{ */ | |||
{ | |||
Bucket *b; | |||
zval *zv, *list; | |||
xc_compile_result_t cr; | |||
int bufsize = 2; | |||
char *buf; | |||
int keysize; | |||
xc_compile_result_init_cur(&cr, op_array TSRMLS_CC); | |||
xc_apply_op_array(&cr, (apply_func_t) xc_undo_pass_two TSRMLS_CC); | |||
xc_apply_op_array(&cr, (apply_func_t) xc_fix_opcode TSRMLS_CC); | |||
/* go */ | |||
array_init(dst); | |||
ALLOC_INIT_ZVAL(zv); | |||
array_init(zv); | |||
xc_dasm_zend_op_array(zv, op_array TSRMLS_CC); | |||
add_assoc_zval_ex(dst, ZEND_STRS("op_array"), zv); | |||
ALLOC_INIT_ZVAL(list); | |||
array_init(list); | |||
xc_dasm_HashTable_zend_function(list, CG(function_table) TSRMLS_CC); | |||
add_assoc_zval_ex(dst, ZEND_STRS("function_table"), list); | |||
buf = emalloc(bufsize); | |||
ALLOC_INIT_ZVAL(list); | |||
array_init(list); | |||
for (b = CG(class_table)->pListHead; b; b = b->pListNext) { | |||
ALLOC_INIT_ZVAL(zv); | |||
array_init(zv); | |||
xc_dasm_zend_class_entry(zv, CestToCePtr(*(xc_cest_t *)b->pData) TSRMLS_CC); | |||
keysize = BUCKET_KEY_SIZE(b) + 2; | |||
if (keysize > bufsize) { | |||
do { | |||
bufsize *= 2; | |||
} while (keysize > bufsize); | |||
buf = erealloc(buf, bufsize); | |||
} | |||
memcpy(buf, BUCKET_KEY(b), keysize); | |||
buf[keysize - 2] = buf[keysize - 1] = ""[0]; | |||
keysize = b->nKeyLength; | |||
#ifdef IS_UNICODE | |||
if (BUCKET_KEY_TYPE(b) == IS_UNICODE) { | |||
if (buf[0] == ""[0] && buf[1] == ""[0]) { | |||
keysize ++; | |||
} | |||
} else | |||
#endif | |||
{ | |||
if (buf[0] == ""[0]) { | |||
keysize ++; | |||
} | |||
} | |||
add_u_assoc_zval_ex(list, BUCKET_KEY_TYPE(b), buf, b->nKeyLength, zv); | |||
} | |||
efree(buf); | |||
add_assoc_zval_ex(dst, ZEND_STRS("class_table"), list); | |||
/*xc_apply_op_array(&cr, (apply_func_t) xc_redo_pass_two TSRMLS_CC);*/ | |||
xc_compile_result_free(&cr); | |||
return; | |||
} | |||
/* }}} */ | |||
void xc_dasm_string(zval *dst, zval *source TSRMLS_DC) /* {{{ */ | |||
{ | |||
int catched; | |||
zend_op_array *op_array = NULL; | |||
xc_sandbox_t sandbox; | |||
char *eval_name = zend_make_compiled_string_description("runtime-created function" TSRMLS_CC); | |||
xc_sandbox_init(&sandbox, eval_name TSRMLS_CC); | |||
catched = 0; | |||
zend_try { | |||
op_array = compile_string(source, eval_name TSRMLS_CC); | |||
} zend_catch { | |||
catched = 1; | |||
} zend_end_try(); | |||
if (catched || !op_array) { | |||
goto err_compile; | |||
} | |||
xc_dasm(dst, op_array TSRMLS_CC); | |||
/* free */ | |||
efree(eval_name); | |||
destroy_op_array(op_array TSRMLS_CC); | |||
efree(op_array); | |||
xc_sandbox_free(&sandbox, 0 TSRMLS_CC); | |||
return; | |||
err_compile: | |||
efree(eval_name); | |||
xc_sandbox_free(&sandbox, 0 TSRMLS_CC); | |||
RETURN_FALSE; | |||
} | |||
/* }}} */ | |||
void xc_dasm_file(zval *dst, const char *filename TSRMLS_DC) /* {{{ */ | |||
{ | |||
int catched; | |||
zend_op_array *op_array = NULL; | |||
xc_sandbox_t sandbox; | |||
zval *zfilename; | |||
MAKE_STD_ZVAL(zfilename); | |||
zfilename->value.str.val = estrdup(filename); | |||
zfilename->value.str.len = strlen(filename); | |||
zfilename->type = IS_STRING; | |||
xc_sandbox_init(&sandbox, zfilename->value.str.val TSRMLS_CC); | |||
catched = 0; | |||
zend_try { | |||
op_array = compile_filename(ZEND_REQUIRE, zfilename TSRMLS_CC); | |||
} zend_catch { | |||
catched = 1; | |||
} zend_end_try(); | |||
if (catched || !op_array) { | |||
goto err_compile; | |||
} | |||
xc_dasm(dst, op_array TSRMLS_CC); | |||
/* free */ | |||
destroy_op_array(op_array TSRMLS_CC); | |||
efree(op_array); | |||
xc_sandbox_free(&sandbox, 0 TSRMLS_CC); | |||
zval_dtor(zfilename); | |||
FREE_ZVAL(zfilename); | |||
return; | |||
err_compile: | |||
xc_sandbox_free(&sandbox, 0 TSRMLS_CC); | |||
zval_dtor(zfilename); | |||
FREE_ZVAL(zfilename); | |||
RETURN_FALSE; | |||
} | |||
/* }}} */ |
@ -0,0 +1,4 @@ | |||
#include "php.h" | |||
void xc_dasm_string(zval *return_value, zval *code TSRMLS_DC); | |||
void xc_dasm_file(zval *return_value, const char *filename TSRMLS_DC); |
@ -0,0 +1,2 @@ | |||
#include "xcache.h" | |||
#include "zend_compile.h" |
@ -0,0 +1,129 @@ | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <malloc.h> | |||
#include <php.h> | |||
#ifndef ZEND_WIN32 | |||
typedef int HANDLE; | |||
#endif | |||
#include "lock.h" | |||
struct _xc_lock_t { | |||
HANDLE fd; | |||
char *pathname; | |||
}; | |||
#ifndef ZEND_WIN32 | |||
# include <unistd.h> | |||
# include <fcntl.h> | |||
# include <errno.h> | |||
static inline int dolock(xc_lock_t *lck, int type) /* {{{ */ | |||
{ | |||
int ret; | |||
struct flock lock; | |||
lock.l_type = type; | |||
lock.l_start = 0; | |||
lock.l_whence = SEEK_SET; | |||
lock.l_len = 1; | |||
lock.l_pid = 0; | |||
do { | |||
ret = fcntl(lck->fd, F_SETLKW, &lock); | |||
} while (ret < 0 && errno == EINTR); | |||
return ret; | |||
} | |||
/* }}} */ | |||
#define LCK_WR F_WRLCK | |||
#define LCK_RD F_RDLCK | |||
#define LCK_UN F_UNLCK | |||
#define LCK_NB 0 | |||
#else | |||
# include <win32/flock.h> | |||
# include <io.h> | |||
# include <fcntl.h> | |||
# include <sys/types.h> | |||
# include <sys/stat.h> | |||
# define errno GetLastError() | |||
static inline int dolock(xc_lock_t *lck, int type) /* {{{ */ | |||
{ | |||
static OVERLAPPED offset = {0, 0, 0, 0, NULL}; | |||
if (type == LCK_UN) { | |||
return UnlockFileEx((HANDLE)fd, 0, 1, 0, &offset); | |||
} | |||
else { | |||
return LockFileEx((HANDLE)fd, type, 0, 1, 0, &offset); | |||
} | |||
} | |||
/* }}} */ | |||
#define LCK_WR LOCKFILE_EXCLUSIVE_LOCK | |||
#define LCK_RD 0 | |||
#define LCK_UN 0 | |||
#define LCK_NB LOCKFILE_FAIL_IMMEDIATELY | |||
#endif | |||
xc_lock_t *xc_fcntl_init(const char *pathname) /* {{{ */ | |||
{ | |||
HANDLE fd; | |||
char myname[sizeof("/tmp/.xcache.lock") - 1 + 20]; | |||
if (pathname == NULL) { | |||
static int i = 0; | |||
snprintf(myname, sizeof(myname) - 1, "/tmp/.xcache.%d.%d.lock", (int) getuid(), i ++); | |||
pathname = myname; | |||
} | |||
fd = open(pathname, O_RDWR|O_CREAT, 0666); | |||
if (fd > 0) { | |||
xc_lock_t *lck = malloc(sizeof(lck[0])); | |||
int size; | |||
#ifndef __CYGWIN__ | |||
unlink(pathname); | |||
#endif | |||
lck->fd = fd; | |||
size = strlen(pathname) + 1; | |||
lck->pathname = malloc(size); | |||
memcpy(lck->pathname, pathname, size); | |||
return lck; | |||
} | |||
else { | |||
fprintf(stderr, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname); | |||
return NULL; | |||
} | |||
} | |||
/* }}} */ | |||
void xc_fcntl_destroy(xc_lock_t *lck) /* {{{ */ | |||
{ | |||
close(lck->fd); | |||
#ifdef __CYGWIN__ | |||
unlink(lck->pathname); | |||
#endif | |||
free(lck->pathname); | |||
free(lck); | |||
} | |||
/* }}} */ | |||
void xc_fcntl_lock(xc_lock_t *lck) /* {{{ */ | |||
{ | |||
if (dolock(lck, LCK_WR) < 0) { | |||
fprintf(stderr, "xc_fcntl_lock failed errno:%d", errno); | |||
} | |||
} | |||
/* }}} */ | |||
void xc_fcntl_rdlock(xc_lock_t *lck) /* {{{ */ | |||
{ | |||
if (dolock(lck, LCK_RD) < 0) { | |||
fprintf(stderr, "xc_fcntl_lock failed errno:%d", errno); | |||
} | |||
} | |||
/* }}} */ | |||
void xc_fcntl_unlock(xc_lock_t *lck) /* {{{ */ | |||
{ | |||
if (dolock(lck, LCK_UN) < 0) { | |||
fprintf(stderr, "xc_fcntl_unlock failed errno:%d", errno); | |||
} | |||
} | |||
/* }}} */ |
@ -0,0 +1,11 @@ | |||
typedef struct _xc_lock_t xc_lock_t; | |||
xc_lock_t *xc_fcntl_init(const char *pathname); | |||
void xc_fcntl_destroy(xc_lock_t *lck); | |||
void xc_fcntl_lock(xc_lock_t *lck); | |||
void xc_fcntl_unlock(xc_lock_t *lck); | |||
#define xc_lock_init(name) xc_fcntl_init(name) | |||
#define xc_lock_destroy(fd) xc_fcntl_destroy(fd) | |||
#define xc_lock(fd) xc_fcntl_lock(fd) | |||
#define xc_unlock(fd) xc_fcntl_unlock(fd) |
@ -0,0 +1,43 @@ | |||
#!/usr/bin/make -if | |||
# vim:syntax=make | |||
SELF=MAKELEVEL=0 ./make.devel | |||
# You should copy make.inc from make.inc.default | |||
include make.inc | |||
all: opcode_spec_def const_string tags | |||
clean: clean_const_string | |||
rm -f tags opcode_spec_def.h | |||
const_string: | |||
@-$(SELF) const_string_opcodes_php4.x.h | |||
@-$(SELF) const_string_opcodes_php5.0.h | |||
@-$(SELF) const_string_opcodes_php5.1.h | |||
@-$(SELF) const_string_opcodes_php6.x.h | |||
clean_const_string: | |||
rm -f const_string_opcodes_php4.x.h const_string_opcodes_php5.0.h const_string_opcodes_php5.1.h const_string_opcodes_php6.x.h | |||
const_string_opcodes_php4.x.h: $(PHP4_x_DIR)/Zend/zend_compile.h | |||
./mkopcode.awk < $(PHP4_x_DIR)/Zend/zend_compile.h > const_string_opcodes_php4.x.h | |||
const_string_opcodes_php5.0.h: $(PHP5_0_DIR)/Zend/zend_vm_def.h | |||
./mkopcode.awk < $(PHP5_0_DIR)/Zend/zend_vm_def.h > const_string_opcodes_php5.0.h | |||
const_string_opcodes_php5.1.h: $(PHP5_1_DIR)/Zend/zend_vm_def.h | |||
./mkopcode.awk < $(PHP5_1_DIR)/Zend/zend_vm_def.h > const_string_opcodes_php5.1.h | |||
const_string_opcodes_php6.x.h: $(PHP6_x_DIR)/Zend/zend_vm_def.h | |||
./mkopcode.awk < $(PHP6_x_DIR)/Zend/zend_vm_def.h > const_string_opcodes_php6.x.h | |||
tags: | |||
test -d $(PHP_DEVEL_DIR) && ctags -R . $(PHP_DEVEL_DIR)/main $(PHP_DEVEL_DIR)/Zend $(PHP_DEVEL_DIR)/TSRM $(PHP_DEVEL_DIR)/ext/standard || ctags -R . | |||
opcode_spec_def: | |||
@-$(SELF) opcode_spec_def.h | |||
opcode_spec_def.h: $(EA_DIR)/opcodes.c | |||
./mkopcode_spec.awk < $(EA_DIR)/opcodes.c > opcode_spec_def.h \ | |||
.PHONY: const_string opcode_spec_def |
@ -0,0 +1,7 @@ | |||
# copy this file to make.inc before modifying | |||
PHP4_x_DIR= | |||
PHP5_0_DIR= | |||
PHP5_1_DIR= | |||
PHP6_x_DIR= | |||
PHP_DEVEL_DIR= |
@ -0,0 +1,268 @@ | |||
#include <php.h> | |||
#include <stdlib.h> | |||
#include "mem.h" | |||
#include "align.h" | |||
#define PADD(p, a) (((char*)p) + a) | |||
// {{{ mem | |||
struct _xc_block_t { | |||
#ifdef ALLOC_DEBUG | |||
unsigned int magic; | |||
#endif | |||
xc_memsize_t size; /* reserved even after alloc */ | |||
xc_block_t *next; /* not used after alloc */ | |||
}; | |||
struct _xc_mem_t { | |||
xc_memsize_t size; | |||
xc_memsize_t avail; /* total free */ | |||
xc_block_t headblock[1]; /* just as a pointer to first block*/ | |||
}; | |||
#ifndef offsetof | |||
# define offsetof(type, field) ((int) ((char *) &((type *) 0)->field)) | |||
#endif | |||
#define SizeOf(type, field) sizeof( ((type *) 0)->field ) | |||
#define BLOCK_HEADER_SIZE() (ALIGN( offsetof(xc_block_t, size) + SizeOf(xc_block_t, size) )) | |||
#define BLOCK_MAGIC ((unsigned int) 0x87655678) | |||
/* }}} */ | |||
static inline void xc_block_setup(xc_block_t *b, xc_memsize_t size, xc_block_t *next) /* {{{ */ | |||
{ | |||
#ifdef ALLOC_DEBUG | |||
b->magic = BLOCK_MAGIC; | |||
#endif | |||
b->size = size; | |||
b->next = next; | |||
} | |||
/* }}} */ | |||
#ifdef ALLOC_DEBUG | |||
static void xc_block_check(xc_block_t *b) /* {{{ */ | |||
{ | |||
if (b->magic != BLOCK_MAGIC) { | |||
fprintf(stderr, "0x%X != 0x%X magic wrong \n", b->magic, BLOCK_MAGIC); | |||
} | |||
} | |||
/* }}} */ | |||
#else | |||
# define xc_block_check(b) do { } while(0) | |||
#endif | |||
void *xc_mem_malloc(xc_mem_t *mem, xc_memsize_t size) /* {{{ */ | |||
{ | |||
xc_block_t *prev, *cur; | |||
xc_block_t *newb, *b; | |||
xc_memsize_t realsize; | |||
xc_memsize_t minsize; | |||
void *p; | |||
/* [xc_block_t:size|size] */ | |||
realsize = BLOCK_HEADER_SIZE() + size; | |||
/* realsize is ALIGNed so next block start at ALIGNed address */ | |||
realsize = ALIGN(realsize); | |||
do { | |||
p = NULL; | |||
if (mem->avail < realsize) { | |||
break; | |||
} | |||
b = NULL; | |||
minsize = INT_MAX; | |||
/* prev|cur */ | |||
for (prev = mem->headblock; prev->next; prev = cur) { | |||
/* while (prev->next != 0) { */ | |||
cur = prev->next; | |||
xc_block_check(cur); | |||
if (cur->size == realsize) { | |||
/* found a perfect fit, stop searching */ | |||
b = prev; | |||
break; | |||
} | |||
/* make sure we can split on the block */ | |||
else if (cur->size > (sizeof(xc_block_t) + realsize) && | |||
cur->size < minsize) { | |||
/* cur is acceptable and memller */ | |||
b = prev; | |||
minsize = cur->size; | |||
} | |||
prev = cur; | |||
} | |||
if (b == NULL) { | |||
break; | |||
} | |||
prev = b; | |||
cur = prev->next; | |||
p = PADD(cur, BLOCK_HEADER_SIZE()); | |||
/* update the block header */ | |||
mem->avail -= realsize; | |||
/*perfect fit, just unlink */ | |||
if (cur->size == realsize) { | |||
prev->next = cur->next; | |||
break; | |||
} | |||
/* make new free block after alloced space */ | |||
/* save, as it might be overwrited by newb (cur->size is ok) */ | |||
b = cur->next; | |||
/* prev|cur |next=b */ | |||
newb = (xc_block_t *)PADD(cur, realsize); | |||
xc_block_setup(newb, cur->size - realsize, b); | |||
cur->size = realsize; | |||
/* prev|cur|newb|next | |||
* `--^ | |||
*/ | |||
#ifdef ALLOC_DEBUG | |||
fprintf(stderr, "avail: %d (%dKB). size: %d %d (%dKB) new next: %p offset: %d %dKB\n" | |||
, mem->avail, mem->avail/1024 | |||
, size | |||
, realsize, realsize/1024 | |||
, newb | |||
, ((char*)newb - mem->rw), ((char*)newb - mem->rw) / 1024 | |||
); | |||
#endif | |||
prev->next = newb; | |||
/* prev|cur|newb|next | |||
* `-----^ | |||
*/ | |||