diff --git a/processor/dispatch.m4 b/processor/dispatch.m4 index 637b461..e1eaa0a 100644 --- a/processor/dispatch.m4 +++ b/processor/dispatch.m4 @@ -27,3 +27,32 @@ define(`DISPATCH', ` , `', `', `m4_errprint(`Unknown type "$1"')' ) ') +dnl {{{ DISPATCH_ARRAY(1:count, 2:type, 3:elm) +define(`DISPATCH_ARRAY', ` + if (src->$3) { + int i; + IFDASM(` + zval *arr; + ALLOC_INIT_ZVAL(arr); + array_init(arr); + for (i = 0; i < src->$1; i ++) { + ifelse( + `$2', `zend_bool', `add_assoc_bool_ex(arr, ZEND_STRS("$3"), src->$3[i] ? 1 : 0);' + , `', `', `add_assoc_long_ex(arr, ZEND_STRS("$3"), src->$3[i]);') + } + add_assoc_zval_ex(dst, ZEND_STRS("$3"), arr); + ', ` + COPY_N_EX($@) + for (i = 0; i < src->$1; i ++) { + DISABLECHECK(` + DISPATCH(`$2', `$3[i]', `$4') + ') + } + ')dnl IFDASM + DONE(`$3') + } + else { + COPYNULL(`$3') + } +') +dnl }}} diff --git a/processor/head.m4 b/processor/head.m4 index 112756e..72c7cc3 100644 --- a/processor/head.m4 +++ b/processor/head.m4 @@ -68,13 +68,15 @@ struct _xc_processor_t { const xc_entry_data_php_t *php_dst; const xc_cache_t *cache; const zend_class_entry *cache_ce; - zend_uint cache_class_num; + zend_uint cache_class_index; const zend_op *active_opcodes_src; zend_op *active_opcodes_dst; const zend_class_entry *active_class_entry_src; zend_class_entry *active_class_entry_dst; - zend_uint active_class_num; + zend_uint active_class_index; + zend_uint active_op_array_index; + const xc_op_array_info_t *active_op_array_infos_src; zend_bool readonly_protection; /* wheather it's present */ IFASSERT(xc_stack_t allocsizes;) @@ -185,28 +187,30 @@ static zend_ulong xc_get_class_num(xc_processor_t *processor, zend_class_entry * zend_class_entry *ceptr; if (processor->cache_ce == ce) { - return processor->cache_class_num; + return processor->cache_class_index + 1; } for (i = 0; i < php->classinfo_cnt; i ++) { ceptr = CestToCePtr(php->classinfos[i].cest); if (ZCEP_REFCOUNT_PTR(ceptr) == ZCEP_REFCOUNT_PTR(ce)) { processor->cache_ce = ceptr; - processor->cache_class_num = i + 1; + processor->cache_class_index = i + 1; return i + 1; } } assert(0); return (zend_ulong) -1; } +define(`xc_get_class_num', `xc_get_class_numNOTDEFINED') /* }}} */ /* {{{ xc_get_class */ #ifdef ZEND_ENGINE_2 static zend_class_entry *xc_get_class(xc_processor_t *processor, zend_ulong class_num) { /* must be parent or currrent class */ - assert(class_num <= processor->active_class_num); + assert(class_num <= processor->active_class_index + 1); return CestToCePtr(processor->php_dst->classinfos[class_num - 1].cest); } #endif +define(`xc_get_class', `xc_get_classNOTDEFINED') /* }}} */ #ifdef ZEND_ENGINE_2 /* fix method on store */ diff --git a/processor/main.m4 b/processor/main.m4 index 787dca9..abdd767 100644 --- a/processor/main.m4 +++ b/processor/main.m4 @@ -149,11 +149,25 @@ dnl }}} dnl {{{ COPY define(`COPY', `IFNOTMEMCPY(`IFCOPY(`dst->$1 = src->$1;')')DONE(`$1')') dnl }}} +dnl {{{ COPY_N_EX +define(`COPY_N_EX', ` + ALLOC(`dst->$3', `$2', `src->$1') + IFCOPY(` + memcpy(dst->$3, src->$3, sizeof(dst->$3[0]) * src->$1); + ') +') +dnl }}} +dnl {{{ COPY_N +define(`COPY_N', `COPY_N_EX(`$1',`$2')DONE(`$1')') +dnl }}} dnl {{{ COPYPOINTER define(`COPYPOINTER', `COPY(`$1')') dnl }}} +dnl {{{ COPYARRAY_EX +define(`COPYARRAY_EX', `IFNOTMEMCPY(`IFCOPY(`memcpy(dst->$1, src->$1, sizeof(dst->$1));')')') +dnl }}} dnl {{{ COPYARRAY -define(`COPYARRAY', `IFNOTMEMCPY(`IFCOPY(`memcpy(dst->$1, src->$1, sizeof(dst->$1));')')DONE(`$1')') +define(`COPYARRAY', `COPYARRAY_EX(`$1',`$2')DONE(`$1')') dnl }}} dnl {{{ SETNULL_EX define(`SETNULL_EX', `IFCOPY(`$1 = NULL;')') @@ -243,8 +257,12 @@ include(srcdir`/processor/head.m4') define(`IFNOTMEMCPY', `ifdef(`USEMEMCPY', `', `$1')') REDEF(`KIND', `calc') include(srcdir`/processor/processor.m4') +pushdef(`xc_get_class_num', ``xc_get_class_num'($@)') REDEF(`KIND', `store') include(srcdir`/processor/processor.m4') +popdef(`xc_get_class_num') +pushdef(`xc_get_class', ``xc_get_class'($@)') REDEF(`KIND', `restore') include(srcdir`/processor/processor.m4') +popdef(`xc_get_class') REDEF(`IFNOTMEMCPY', `$1') #ifdef HAVE_XCACHE_DPRINT diff --git a/processor/processor.m4 b/processor/processor.m4 index 0172611..0b7d178 100644 --- a/processor/processor.m4 +++ b/processor/processor.m4 @@ -338,6 +338,7 @@ DEF_STRUCT_P_FUNC(`zend_class_entry', , `dnl {{{ IFDASM(` if (src->num_interfaces) { /* + int i; zval *arr; ALLOC_INIT_ZVAL(arr); array_init(arr); @@ -498,40 +499,55 @@ DEF_STRUCT_P_FUNC(`zend_op', , `dnl {{{ dnl }}} DEF_STRUCT_P_FUNC(`zend_op_array', , `dnl {{{ IFRESTORE(` + const xc_op_array_info_t *op_array_info = &processor->active_op_array_infos_src[processor->active_op_array_index]; dnl shadow copy must NOT meet: dnl readonly_protection=on dnl main op_array && have early binding - zend_uint ii; #ifdef ZEND_COMPILE_DELAYED_BINDING zend_bool need_early_binding = 0; #else zend_bool need_early_binding = processor->php_src->have_early_binding; #endif - if (!processor->readonly_protection && !(src == processor->php_src->op_array && need_early_binding)) { + zend_bool shallow_copy = !processor->readonly_protection && !(src == processor->php_src->op_array && need_early_binding); + if (shallow_copy) { + zend_bool gc_arg_info = 0; + int gc_opcodes = 0; /* really fast shallow copy */ memcpy(dst, src, sizeof(src[0])); dst->refcount[0] = 1000; /* deep */ STRUCT_P(HashTable, static_variables, HashTable_zval_ptr) #ifdef ZEND_ENGINE_2 - STRUCT_ARRAY_I(num_args, zend_arg_info, arg_info) - xc_gc_add_op_array(dst TSRMLS_CC); + STRUCT_ARRAY(num_args, zend_arg_info, arg_info) + gc_arg_info = 1; +#endif + if (op_array_info->oplineinfo_cnt) { + gc_opcodes = 1; + COPY_N_EX(last, zend_op, opcodes) + } + if (gc_arg_info || gc_opcodes) { + xc_gc_op_array_t gc_op_array; +#ifdef ZEND_ENGINE_2 + gc_op_array.num_args = gc_arg_info ? dst->num_args : 0; + gc_op_array.arg_info = gc_arg_info ? dst->arg_info : NULL; #endif + gc_op_array.last = gc_opcodes > 1 ? dst->last : 0; + gc_op_array.opcodes = gc_opcodes ? dst->opcodes : NULL; + xc_gc_add_op_array(&gc_op_array TSRMLS_CC); + } define(`SKIPASSERT_ONCE') } else ') do { dnl RESTORE is done above! - zend_uint ii; - int i; /* Common elements */ DISPATCH(zend_uchar, type) PROC_ZSTRING(, function_name) #ifdef ZEND_ENGINE_2 DISPATCH(zend_uint, fn_flags) - STRUCT_ARRAY_I(num_args, zend_arg_info, arg_info) + STRUCT_ARRAY(num_args, zend_arg_info, arg_info) DISPATCH(zend_uint, num_args) DISPATCH(zend_uint, required_num_args) DISPATCH(zend_bool, pass_rest_by_reference) @@ -540,7 +556,6 @@ DEF_STRUCT_P_FUNC(`zend_op_array', , `dnl {{{ ALLOC(dst->arg_types, zend_uchar, src->arg_types[0] + 1) IFCOPY(`memcpy(dst->arg_types, src->arg_types, sizeof(src->arg_types[0]) * (src->arg_types[0]+1));') IFDASM(`do { - zend_uint ii; int i; zval *zv; ALLOC_INIT_ZVAL(zv); @@ -580,7 +595,7 @@ DEF_STRUCT_P_FUNC(`zend_op_array', , `dnl {{{ processor->active_opcodes_dst = dst->opcodes; processor->active_opcodes_src = src->opcodes; ')') - STRUCT_ARRAY_I(last, zend_op, opcodes) + STRUCT_ARRAY(last, zend_op, opcodes) popdef(`AFTER_ALLOC') DISPATCH(zend_uint, last) IFCOPY(`dst->size = src->last;DONE(size)', `DISPATCH(zend_uint, size)') @@ -598,7 +613,7 @@ DEF_STRUCT_P_FUNC(`zend_op_array', , `dnl {{{ DISPATCH(zend_uint, T) - STRUCT_ARRAY_I(last_brk_cont, zend_brk_cont_element, brk_cont_array) + STRUCT_ARRAY(last_brk_cont, zend_brk_cont_element, brk_cont_array) DISPATCH(zend_uint, last_brk_cont) DISPATCH(zend_uint, current_brk_cont) #ifndef ZEND_ENGINE_2 @@ -648,6 +663,7 @@ DEF_STRUCT_P_FUNC(`zend_op_array', , `dnl {{{ DISPATCH(zend_bool, created_by_eval) #endif } while (0); + IFRESTORE(`xc_fix_op_array_info(processor->php_src, dst, !shallow_copy, op_array_info TSRMLS_CC);') #ifdef ZEND_ENGINE_2 dnl mark it as -1 on store, and lookup parent on restore @@ -712,6 +728,11 @@ DEF_STRUCT_P_FUNC(`xc_constinfo_t', , `dnl {{{ ') dnl }}} #endif +DEF_STRUCT_P_FUNC(`xc_op_array_info_t', , `dnl {{{ + DISPATCH(zend_uint, oplineinfo_cnt) + DISPATCH_ARRAY(oplineinfo_cnt, int, oplineinfos) +') +dnl }}} DEF_STRUCT_P_FUNC(`xc_funcinfo_t', , `dnl {{{ DISPATCH(zend_uint, key_size) #ifdef IS_UNICODE @@ -721,6 +742,13 @@ DEF_STRUCT_P_FUNC(`xc_funcinfo_t', , `dnl {{{ PROC_ZSTRING_N(type, key, key_size) ') DISPATCH(ulong, h) + IFRESTORE(`COPY(op_array_info)', ` + STRUCT(xc_op_array_info_t, op_array_info) + ') + IFRESTORE(` + processor->active_op_array_infos_src = &dst->op_array_info; + processor->active_op_array_index = 0; + ') STRUCT(zend_function, func) ') dnl }}} @@ -733,6 +761,14 @@ DEF_STRUCT_P_FUNC(`xc_classinfo_t', , `dnl {{{ PROC_ZSTRING_N(type, key, key_size) ') DISPATCH(ulong, h) + DISPATCH(zend_uint, methodinfo_cnt) + IFRESTORE(`COPY(methodinfos)', ` + STRUCT_ARRAY(methodinfo_cnt, xc_op_array_info_t, methodinfos) + ') + IFRESTORE(` + processor->active_op_array_infos_src = dst->methodinfos; + processor->active_op_array_index = 0; + ') #ifdef ZEND_ENGINE_2 STRUCT_P(zend_class_entry, cest) #else @@ -766,8 +802,6 @@ DEF_STRUCT_P_FUNC(`xc_compilererror_t', , `dnl {{{ dnl }}} #endif DEF_STRUCT_P_FUNC(`xc_entry_data_php_t', , `dnl {{{ - zend_uint i; - IFCOPY(` processor->php_dst = dst; processor->php_src = src; @@ -784,6 +818,24 @@ DEF_STRUCT_P_FUNC(`xc_entry_data_php_t', , `dnl {{{ DISPATCH(zend_ulong, hits) DISPATCH(size_t, size) + DISPATCH(int, filepath_len) + IFRESTORE(`COPY(filepath)', `PROC_STRING_L(filepath, filepath_len)') + DISPATCH(int, dirpath_len) + IFRESTORE(`COPY(dirpath)', `PROC_STRING_L(dirpath, dirpath_len)') +#ifdef IS_UNICODE + DISPATCH(int, ufilepath_len) + IFRESTORE(`COPY(ufilepath)', `PROC_USTRING_L(ufilepath, ufilepath_len)') + DISPATCH(int, udirpath_len) + IFRESTORE(`COPY(udirpath)', `PROC_USTRING_L(udirpath, udirpath_len)') +#endif + + IFRESTORE(`COPY(op_array_info)', ` + STRUCT(xc_op_array_info_t, op_array_info) + ') + IFRESTORE(` + processor->active_op_array_infos_src = &dst->op_array_info; + processor->active_op_array_index = 0; + ') STRUCT_P(zend_op_array, op_array) #ifdef HAVE_XCACHE_CONSTANT @@ -795,13 +847,7 @@ DEF_STRUCT_P_FUNC(`xc_entry_data_php_t', , `dnl {{{ STRUCT_ARRAY(funcinfo_cnt, xc_funcinfo_t, funcinfos) DISPATCH(zend_uint, classinfo_cnt) - pushdef(`BEFORE_LOOP', ` - IFCOPY(` - processor->active_class_num = i + 1; - ') - ') - STRUCT_ARRAY(classinfo_cnt, xc_classinfo_t, classinfos) - popdef(`BEFORE_LOOP') + STRUCT_ARRAY(classinfo_cnt, xc_classinfo_t, classinfos, , IFRESTORE(`processor->active_class_index')) #ifdef ZEND_ENGINE_2_1 DISPATCH(zend_uint, autoglobal_cnt) IFRESTORE(` @@ -878,7 +924,7 @@ DEF_STRUCT_P_FUNC(`xc_entry_t', , ` DISABLECHECK(` switch (src->type) { case XC_TYPE_PHP: - IFCALCCOPY(`DONE(data.php)', `STRUCT_P(xc_entry_data_php_t, data.php)') + IFCALCCOPY(`COPY(data.php)', `STRUCT_P(xc_entry_data_php_t, data.php)') break; case XC_TYPE_VAR: diff --git a/processor/string.m4 b/processor/string.m4 index b391642..65c2e1c 100644 --- a/processor/string.m4 +++ b/processor/string.m4 @@ -6,12 +6,12 @@ define(`PROC_STRING_N_EX', ` STRTYPE, `char', `char', STRTYPE, `zstr_char', `char', `', `', `UChar')) - pushdef(`ISTYPE', ifelse(STRTYPE,`zstr_uchar',IS_UNICODE,IS_STRING)) + pushdef(`ISTYPE', ifelse(PTRTYPE,`UChar',IS_UNICODE,IS_STRING)) pushdef(`UNI_STRLEN', ifelse( STRTYPE, `zstr_uchar', `xc_zstrlen_uchar', STRTYPE, `zstr_char', `xc_zstrlen_char', `', `', `strlen')) - pushdef(`SRCSTR', ifelse(STRTYPE,`char',`ZSTR($2)',`$2')) + pushdef(`SRCSTR', ifelse(STRTYPE,`char',`ZSTR($2)',STRTYPE,`UChar',`ZSTR($2)',`$2')) pushdef(`SRCPTR', ifelse( STRTYPE, `zstr_uchar', `ZSTR_U($2)', STRTYPE, `zstr_char', `ZSTR_S($2)', @@ -87,9 +87,12 @@ define(`PROC_STRING_N_EX', ` dnl }}} dnl PROC_STRING_N(1:name, 2:size, 3:type) define(`PROC_STRING_N', `DBG(`$0($*)') DONE(`$1')`'PROC_STRING_N_EX(`dst->$1', `src->$1', `src->$2', `$1', `char')') +define(`PROC_USTRING_N', `DBG(`$0($*)') DONE(`$1')`'PROC_STRING_N_EX(`dst->$1', `src->$1', `src->$2', `$1', `UChar')') define(`PROC_STRING_L', `DBG(`$0($*)') PROC_STRING_N(`$1', `$2 + 1')') +define(`PROC_USTRING_L', `DBG(`$0($*)') PROC_USTRING_N(`$1', `$2 + 1')') define(`PROC_STRING', `DBG(`$0($*)') DONE(`$1')`'PROC_STRING_N_EX(`dst->$1', `src->$1', `strlen(src->$1) + 1', `$1', `char')') +define(`PROC_USTRING', `DBG(`$0($*)') DONE(`$1')`'PROC_STRING_N_EX(`dst->$1', `src->$1', `strlen(src->$1) + 1', `$1', `UChar')') dnl {{{ PROC_ZSTRING_N(1:type, 2:name, 3:size, 4:size_type) define(`PROC_ZSTRING_N', ` diff --git a/processor/struct.m4 b/processor/struct.m4 index e38dc99..c50705a 100644 --- a/processor/struct.m4 +++ b/processor/struct.m4 @@ -164,42 +164,38 @@ define(`STRUCT', ` DONE(`$2') ') dnl }}} -dnl {{{ STRUCT_ARRAY_I(1:count, 2:type, 3:elm, 4:name=type) -define(`STRUCT_ARRAY_I', ` -pushdef(`i', `ii') -STRUCT_ARRAY(`$1', `$2', `$3', `$4') -popdef(`i') -') -dnl }}} -dnl {{{ STRUCT_ARRAY(1:count, 2:type, 3:elm, 4:name=type) +dnl {{{ STRUCT_ARRAY(1:count, 2:type, 3:elm, 4:name=type, 5:loopcounter) define(`STRUCT_ARRAY', ` if (src->$3) { + ifelse( + `$5', `', `int i; pushdef(`LOOPCOUNTER', `i')', + `', `', `pushdef(`LOOPCOUNTER', `$5')') pushdefFUNC_NAME(`$2', `$4') IFDASM(` zval *arr; ALLOC_INIT_ZVAL(arr); array_init(arr); - for (i = 0; i < src->$1; i ++) { + for (LOOPCOUNTER = 0; LOOPCOUNTER < src->$1; LOOPCOUNTER ++) { zval *zv; ALLOC_INIT_ZVAL(zv); array_init(zv); - FUNC_NAME (zv, &(src->$3[i]) TSRMLS_CC); + FUNC_NAME (zv, &(src->$3[LOOPCOUNTER]) TSRMLS_CC); add_next_index_zval(arr, zv); } add_assoc_zval_ex(dst, ZEND_STRS("$3"), arr); ', ` ALLOC(`dst->$3', `$2', `src->$1') ifdef(`AFTER_ALLOC', AFTER_ALLOC) - for (i = 0; i < src->$1; i ++) { + for (LOOPCOUNTER = 0; LOOPCOUNTER < src->$1; LOOPCOUNTER ++) { DISABLECHECK(` - ifdef(`BEFORE_LOOP', `BEFORE_LOOP') - STRUCT(`$2', `$3[i]', `$4') + STRUCT(`$2', `$3[LOOPCOUNTER]', `$4') ') } ')dnl IFDASM DONE(`$3') popdef(`FUNC_NAME') + popdef(`LOOPCOUNTER') } else { COPYNULL(`$3') diff --git a/utils.h b/utils.h index 9005692..d9554c9 100644 --- a/utils.h +++ b/utils.h @@ -37,9 +37,6 @@ static inline int TRACE_DUMMY(const char *fmt, ...) # endif /* ZEND_WIN32 */ # define IFDEBUG(x) do { } while (0) -# ifndef NDEBUG -# define NDEBUG -# endif #endif /* XCACHE_DEBUG */ #include @@ -131,3 +128,52 @@ void xc_zend_constant_ctor(zend_constant *c); void xc_zend_constant_dtor(zend_constant *c); void xc_copy_internal_zend_constants(HashTable *target, HashTable *source); #endif + +typedef struct { + zend_uint size; + zend_uint cnt; + void *data; +} xc_vector_t; + +#define xc_vector_init(type, vector) do { \ + (vector)->cnt = 0; \ + (vector)->size = 0; \ + (vector)->data = NULL; \ +} while (0) + +#define xc_vector_add(type, vector, value) do { \ + if ((vector)->cnt == (vector)->size) { \ + if ((vector)->size) { \ + (vector)->size <<= 1; \ + (vector)->data = erealloc((vector)->data, sizeof(type) * (vector)->size); \ + } \ + else { \ + (vector)->size = 8; \ + (vector)->data = emalloc(sizeof(type) * (vector)->size); \ + } \ + } \ + ((type *) (vector)->data)[(vector)->cnt++] = value; \ +} while (0) + +static inline void *xc_vector_detach_impl(xc_vector_t *vector) +{ + void *data = vector->data; + vector->data = NULL; + vector->size = 0; + vector->cnt = 0; + return data; +} + +#define xc_vector_detach(type, vector) ((type *) xc_vector_detach_impl(vector)) + +static inline void xc_vector_free_impl(xc_vector_t *vector TSRMLS_DC) +{ + if (vector->data) { + efree(vector->data); + } + vector->size = 0; + vector->cnt = 0; +} + +#define xc_vector_free(type, vector) xc_vector_free_impl(vector TSRMLS_CC) + diff --git a/xcache.c b/xcache.c index 6b70034..5e6992b 100644 --- a/xcache.c +++ b/xcache.c @@ -37,6 +37,14 @@ #include "opcode_spec.h" #include "utils.h" +#ifndef ZEND_ENGINE_2_3 +ZEND_API size_t zend_dirname(char *path, size_t len) +{ + php_dirname(path, len); + return strlen(path); +} +#endif + #define VAR_ENTRY_EXPIRED(pentry) ((pentry)->ttl && XG(request_time) > pentry->ctime + (pentry)->ttl) #define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0) #define LOCK(x) xc_lock(x->lck) @@ -1004,6 +1012,7 @@ stat_done: #endif { /* hash on filename, let's expand it to real path */ + /* FIXME */ filename = expand_filepath(filename, opened_path_buffer TSRMLS_CC); if (filename == NULL) { return FAILURE; @@ -1107,14 +1116,211 @@ static void xc_cache_early_binding_class_cb(zend_op *opline, int oplineno, void } /* }}} */ #endif + +/* {{{ Constant Usage */ +#define xcache_op1_is_file 1 +#define xcache_op1_is_dir 2 +#define xcache_op2_is_file 4 +#define xcache_op2_is_dir 8 +typedef struct { + zend_bool filepath_used; + zend_bool dirpath_used; + zend_bool ufilepath_used; + zend_bool udirpath_used; +} xc_const_usage_t; +/* }}} */ +static void xc_collect_op_array_info(xc_entry_data_php_t *php, xc_const_usage_t *usage, xc_op_array_info_t *op_array_info, zend_op_array *op_array TSRMLS_DC) /* {{{ */ +{ + int oplineno; + xc_vector_t vector_int; + + xc_vector_init(int, &vector_int); + +#define XCACHE_CHECK_OP(type, op) \ + if (zend_binary_strcmp(Z_STRVAL(opline->op.u.constant), Z_STRLEN(opline->op.u.constant), php->type##path, php->type##path_len) == 0) { \ + usage->type##path_used = 1; \ + oplineinfo |= xcache_##op##_is_##type; \ + } + +#define XCACHE_U_CHECK_OP(type, op) \ + if (zend_u_##binary_strcmp(Z_USTRVAL(opline->op.u.constant), Z_USTRLEN(opline->op.u.constant), php->u##type##path, php->u##type##path_len) == 0) { \ + usage->u##type##path_used = 1; \ + oplineinfo |= xcache_##op##_is_##type; \ + } + + for (oplineno = 0; oplineno < op_array->last; oplineno++) { + zend_op *opline = &op_array->opcodes[oplineno]; + int oplineinfo = 0; + if (opline->op1.op_type == IS_CONST) { + if (Z_TYPE(opline->op1.u.constant) == IS_STRING) { + XCACHE_CHECK_OP(file, op1) + else XCACHE_CHECK_OP(dir, op1) + } + +#ifdef IS_UNICODE + else if (Z_TYPE(opline->op1.u.constant) == IS_UNICODE) { + XCACHE_U_CHECK_OP(file, op1) + else XCACHE_U_CHECK_OP(dir, op1) + } +#endif + } + if (opline->op2.op_type == IS_CONST) { + if (Z_TYPE(opline->op2.u.constant) == IS_STRING) { + XCACHE_CHECK_OP(file, op2) + else XCACHE_CHECK_OP(dir, op2) + } + +#ifdef IS_UNICODE + else if (Z_TYPE(opline->op2.u.constant) == IS_UNICODE) { + XCACHE_U_CHECK_OP(file, op2) + else XCACHE_U_CHECK_OP(dir, op2) + } +#endif + } + if (oplineinfo) { + xc_vector_add(int, &vector_int, oplineno); + xc_vector_add(int, &vector_int, oplineinfo); + } + } + + op_array_info->oplineinfo_cnt = vector_int.cnt; + op_array_info->oplineinfos = xc_vector_detach(int, &vector_int); + xc_vector_free(int, &vector_int); +} +/* }}} */ +void xc_fix_op_array_info(const xc_entry_data_php_t *php, zend_op_array *op_array, int copy, const xc_op_array_info_t *op_array_info TSRMLS_DC) /* {{{ */ +{ + int i; + if (!op_array_info->oplineinfo_cnt) { + return; + } + + for (i = 0; i < op_array_info->oplineinfo_cnt; i += 2) { + int oplineno = op_array_info->oplineinfos[i]; + int oplineinfo = op_array_info->oplineinfos[i + 1]; + zend_op *opline = &op_array->opcodes[oplineno]; + if ((oplineinfo & xcache_op1_is_file)) { + assert(opline->op1.op_type == IS_CONST); + if (copy) { + efree(Z_STRVAL(opline->op1.u.constant)); + } + if (Z_TYPE(opline->op1.u.constant) == IS_STRING) { + assert(php->filepath); + ZVAL_STRINGL(&opline->op1.u.constant, php->filepath, php->filepath_len, copy); + } +#ifdef IS_UNICODE + else if (Z_TYPE(opline->op1.u.constant) == IS_UNICODE) { + assert(php->ufilepath); + ZVAL_UNICODEL(&opline->op1.u.constant, php->ufilepath, php->ufilepath_len, copy); + } +#endif + else { + assert(0); + } + } + else if ((oplineinfo & xcache_op1_is_dir)) { + assert(opline->op1.op_type == IS_CONST); + if (copy) { + efree(Z_STRVAL(opline->op1.u.constant)); + } + if (Z_TYPE(opline->op1.u.constant) == IS_STRING) { + assert(php->dirpath); + ZVAL_STRINGL(&opline->op1.u.constant, php->dirpath, php->dirpath_len, copy); + } +#ifdef IS_UNICODE + else if (Z_TYPE(opline->op1.u.constant) == IS_UNICODE) { + assert(!php->udirpath); + ZVAL_UNICODEL(&opline->op1.u.constant, php->udirpath, php->udirpath_len, copy); + } +#endif + else { + assert(0); + } + } + + if ((oplineinfo & xcache_op2_is_file)) { + assert(opline->op2.op_type == IS_CONST); + if (copy) { + efree(Z_STRVAL(opline->op2.u.constant)); + } + if (Z_TYPE(opline->op2.u.constant) == IS_STRING) { + assert(php->filepath); + ZVAL_STRINGL(&opline->op2.u.constant, php->filepath, php->filepath_len, copy); + } +#ifdef IS_UNICODE + else if (Z_TYPE(opline->op2.u.constant) == IS_UNICODE) { + assert(php->ufilepath); + ZVAL_UNICODEL(&opline->op2.u.constant, php->ufilepath, php->ufilepath_len, copy); + } +#endif + else { + assert(0); + } + } + else if ((oplineinfo & xcache_op2_is_dir)) { + assert(opline->op2.op_type == IS_CONST); + if (copy) { + efree(Z_STRVAL(opline->op2.u.constant)); + } + if (Z_TYPE(opline->op2.u.constant) == IS_STRING) { + assert(!php->dirpath); + ZVAL_STRINGL(&opline->op2.u.constant, php->dirpath, php->dirpath_len, copy); + } +#ifdef IS_UNICODE + else if (Z_TYPE(opline->op2.u.constant) == IS_UNICODE) { + assert(!php->udirpath); + ZVAL_UNICODEL(&opline->op2.u.constant, php->udirpath, php->udirpath_len, copy); + } +#endif + else { + assert(0); + } + } + } +} +/* }}} */ +static void xc_free_op_array_info(xc_op_array_info_t *op_array_info TSRMLS_DC) /* {{{ */ +{ + if (op_array_info->oplineinfos) { + efree(op_array_info->oplineinfos); + } +} +/* }}} */ static void xc_free_php(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */ { + int i; + if (php->classinfos) { + for (i = 0; i < php->classinfo_cnt; i ++) { + xc_classinfo_t *classinfo = &php->classinfos[i]; + int j; + for (j = 0; j < classinfo->methodinfo_cnt; j ++) { + xc_free_op_array_info(&classinfo->methodinfos[j] TSRMLS_CC); + } + + if (classinfo->methodinfos) { + efree(classinfo->methodinfos); + } + } + } + if (php->funcinfos) { + for (i = 0; i < php->funcinfo_cnt; i ++) { + xc_free_op_array_info(&php->funcinfos[i].op_array_info TSRMLS_CC); + } + } + xc_free_op_array_info(&php->op_array_info TSRMLS_CC); + #define X_FREE(var) do {\ if (php->var) { \ efree(php->var); \ } \ } while (0) + X_FREE(dirpath); +#ifdef IS_UNICODE + X_FREE(ufilepath); + X_FREE(udirpath); +#endif + #ifdef ZEND_ENGINE_2_1 X_FREE(autoglobals); #endif @@ -1131,6 +1337,7 @@ static zend_op_array *xc_compile_php(xc_entry_data_php_t *php, zend_file_handle zend_op_array *op_array; int old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt; zend_bool catched = 0; + xc_const_usage_t const_usage; /* {{{ compile */ TRACE("compiling %s", h->opened_path ? h->opened_path : h->filename); @@ -1161,6 +1368,7 @@ static zend_op_array *xc_compile_php(xc_entry_data_php_t *php, zend_file_handle /* }}} */ /* {{{ prepare */ + zend_restore_compiled_filename(h->opened_path ? h->opened_path : h->filename TSRMLS_CC); php->op_array = op_array; #ifdef HAVE_XCACHE_CONSTANT @@ -1206,6 +1414,18 @@ static zend_op_array *xc_compile_php(xc_entry_data_php_t *php, zend_file_handle #endif #undef X_ALLOC /* }}} */ + + /* {{{ file/dir path init */ + memset(&const_usage, 0, sizeof(const_usage)); + php->filepath = zend_get_compiled_filename(TSRMLS_C); + php->filepath_len = strlen(php->filepath); + php->dirpath = estrndup(php->filepath, php->filepath_len); + php->dirpath_len = zend_dirname(php->dirpath, php->filepath_len); +#ifdef IS_UNICODE + zend_string_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &php->ufilepath, &php->ufilepath_len, php->filepath, php->filepath_len TSRMLS_CC); + zend_string_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &php->udirpath, &php->udirpath_len, php->dirpath, php->dirpath_len TSRMLS_CC); +#endif + /* }}} */ /* {{{ shallow copy, pointers only */ { Bucket *b; unsigned int i; @@ -1241,6 +1461,33 @@ static zend_op_array *xc_compile_php(xc_entry_data_php_t *php, zend_file_handle b = CG(function_table)->pListHead; COPY_H(xc_funcinfo_t, funcinfos, funcinfo_cnt, func, zend_function); b = CG(class_table)->pListHead; COPY_H(xc_classinfo_t, classinfos, classinfo_cnt, cest, xc_cest_t); + for (i = 0; i < php->classinfo_cnt; i ++) { + xc_classinfo_t *classinfo = &php->classinfos[i]; + zend_class_entry *ce = CestToCePtr(classinfo->cest); + classinfo->methodinfo_cnt = ce->function_table.nTableSize; + if (classinfo->methodinfo_cnt) { + int j; + + ECALLOC_N(classinfo->methodinfos, classinfo->methodinfo_cnt); + if (!classinfo->methodinfos) { + goto err_alloc; + } + + for (j = 0, b = ce->function_table.pListHead; b; j ++, b = b->pListNext) { + xc_collect_op_array_info(php, &const_usage, &classinfo->methodinfos[j], (zend_op_array *) b->pData TSRMLS_CC); + } + } + else { + classinfo->methodinfos = NULL; + } + } + + for (i = 0; i < php->funcinfo_cnt; i ++) { + xc_collect_op_array_info(php, &const_usage, &php->funcinfos[i].op_array_info, (zend_op_array *) &php->funcinfos[i].func TSRMLS_CC); + } + + xc_collect_op_array_info(php, &const_usage, &php->op_array_info, php->op_array TSRMLS_CC); + #undef COPY_H /* for ZE1, cest need to be fixed inside store */ @@ -1270,6 +1517,24 @@ static zend_op_array *xc_compile_php(xc_entry_data_php_t *php, zend_file_handle #endif } /* }}} */ + /* {{{ file/dir path free unused */ +#define X_FREE_UNUSED(var) \ + if (!const_usage.var##path_used) { \ + efree(php->var##path); \ + php->var##path = NULL; \ + php->var##path_len = 0; \ + } + if (!const_usage.filepath_used) { + php->filepath = NULL; + php->filepath_len = 0; + } + X_FREE_UNUSED(dir) +#ifdef IS_UNICODE + X_FREE_UNUSED(ufile) + X_FREE_UNUSED(udir) +#endif +#undef X_FREE_UNUSED + /* }}} */ #ifdef E_STRICT php->compilererrors = ((xc_sandbox_t *) XG(sandbox))->compilererrors; php->compilererror_cnt = ((xc_sandbox_t *) XG(sandbox))->compilererror_cnt; @@ -1466,6 +1731,8 @@ static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) / #ifdef ZEND_ENGINE_2_1 php.autoglobals = NULL; #endif + memset(&php.op_array_info, 0, sizeof(php.op_array_info)); + zend_try { op_array = xc_compile_php(&php, h, type TSRMLS_CC); } zend_catch { @@ -1637,27 +1904,16 @@ int xc_is_shm(const void *p) /* {{{ */ } /* }}} */ -#ifdef ZEND_ENGINE_2 -/* {{{ xc_gc_op_array_t */ -typedef struct { - zend_uint num_args; - zend_arg_info *arg_info; -} xc_gc_op_array_t; -/* }}} */ -void xc_gc_add_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */ +void xc_gc_add_op_array(xc_gc_op_array_t *gc_op_array TSRMLS_DC) /* {{{ */ { - xc_gc_op_array_t gc_op_array; - gc_op_array.num_args = op_array->num_args; - gc_op_array.arg_info = op_array->arg_info; -#ifdef ZEND_ENGINE_2 - zend_llist_add_element(&XG(gc_op_arrays), (void *) &gc_op_array); -#endif + zend_llist_add_element(&XG(gc_op_arrays), (void *) gc_op_array); } /* }}} */ static void xc_gc_op_array(void *pDest) /* {{{ */ { xc_gc_op_array_t *op_array = (xc_gc_op_array_t *) pDest; zend_uint i; +#ifdef ZEND_ENGINE_2 if (op_array->arg_info) { for (i = 0; i < op_array->num_args; i++) { efree((char *) ZSTR_V(op_array->arg_info[i].name)); @@ -1667,9 +1923,12 @@ static void xc_gc_op_array(void *pDest) /* {{{ */ } efree(op_array->arg_info); } +#endif + if (op_array->opcodes) { + efree(op_array->opcodes); + } } /* }}} */ -#endif /* module helper function */ static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */ diff --git a/xcache.h b/xcache.h index 4f17678..c6b474a 100644 --- a/xcache.h +++ b/xcache.h @@ -63,6 +63,10 @@ # define IS_CONSTANT_TYPE_MASK (~IS_CONSTANT_INDEX) #endif +#ifndef ZEND_ENGINE_2_3 +#define zend_dirname(path, len) xc_dirname(path, len) +#endif + /* {{{ dirty fix for PHP 6 */ #ifdef add_assoc_long_ex static inline void my_add_assoc_long_ex(zval *arg, char *key, uint key_len, long value) @@ -237,6 +241,12 @@ typedef struct { zend_ulong hits_by_second[5]; } xc_cache_t; /* }}} */ +/* {{{ xc_op_array_info_t */ +typedef struct { + zend_uint oplineinfo_cnt; + int *oplineinfos; +} xc_op_array_info_t; +/* }}} */ /* {{{ xc_classinfo_t */ typedef struct { #ifdef IS_UNICODE @@ -245,6 +255,8 @@ typedef struct { zstr key; zend_uint key_size; ulong h; + zend_uint methodinfo_cnt; + xc_op_array_info_t *methodinfos; xc_cest_t cest; #ifndef ZEND_COMPILE_DELAYED_BINDING int oplineno; @@ -272,6 +284,7 @@ typedef struct { zstr key; zend_uint key_size; ulong h; + xc_op_array_info_t op_array_info; zend_function func; } xc_funcinfo_t; /* }}} */ @@ -310,6 +323,18 @@ struct _xc_entry_data_php_t { zend_ulong hits; /* hits of this php */ size_t size; + int filepath_len; + char *filepath; + int dirpath_len; + char *dirpath; +#ifdef IS_UNICODE + UChar *ufilepath; + int ufilepath_len; + UChar *udirpath; + int udirpath_len; +#endif + + xc_op_array_info_t op_array_info; zend_op_array *op_array; #ifdef HAVE_XCACHE_CONSTANT @@ -386,6 +411,17 @@ extern zend_module_entry xcache_module_entry; int xc_is_rw(const void *p); int xc_is_ro(const void *p); int xc_is_shm(const void *p); -void xc_gc_add_op_array(zend_op_array *op_array TSRMLS_DC); +/* {{{ xc_gc_op_array_t */ +typedef struct { +#ifdef ZEND_ENGINE_2 + zend_uint num_args; + zend_arg_info *arg_info; +#endif + zend_uint last; + zend_op *opcodes; +} xc_gc_op_array_t; +/* }}} */ +void xc_gc_add_op_array(xc_gc_op_array_t *gc_op_array TSRMLS_DC); +void xc_fix_op_array_info(const xc_entry_data_php_t *php, zend_op_array *op_array, int shallow_copied, const xc_op_array_info_t *op_array_info TSRMLS_DC); #endif /* __XCACHE_H */ diff --git a/xcache_globals.h b/xcache_globals.h index 248bde3..b4d5043 100644 --- a/xcache_globals.h +++ b/xcache_globals.h @@ -17,9 +17,7 @@ ZEND_BEGIN_MODULE_GLOBALS(xcache) time_t request_time; long var_ttl; -#ifdef ZEND_ENGINE_2 zend_llist gc_op_arrays; -#endif #ifdef HAVE_XCACHE_CONSTANT HashTable internal_constant_table;