commit
528006a3b4
37 changed files with 11919 additions and 0 deletions
-
87.gitignore
-
1967Optimizer/block_pass.c
-
126Optimizer/nop_removal.c
-
222Optimizer/optimize_temp_vars_5.c
-
3Optimizer/pass10.c
-
391Optimizer/pass1_5.c
-
210Optimizer/pass2.c
-
443Optimizer/pass3.c
-
3Optimizer/pass5.c
-
8Optimizer/pass9.c
-
139Optimizer/zend_optimizer.c
-
49Optimizer/zend_optimizer.h
-
76Optimizer/zend_optimizer_internal.h
-
171README
-
2510ZendAccelerator.c
-
364ZendAccelerator.h
-
345config.m4
-
28config.w32
-
70shared_alloc_mmap.c
-
90shared_alloc_posix.c
-
137shared_alloc_shm.c
-
315shared_alloc_win32.c
-
241zend_accelerator_blacklist.c
-
49zend_accelerator_blacklist.h
-
101zend_accelerator_debug.c
-
33zend_accelerator_debug.h
-
222zend_accelerator_hash.c
-
98zend_accelerator_hash.h
-
574zend_accelerator_module.c
-
28zend_accelerator_module.h
-
1079zend_accelerator_util_funcs.c
-
49zend_accelerator_util_funcs.h
-
680zend_persist.c
-
29zend_persist.h
-
343zend_persist_calc.c
-
473zend_shared_alloc.c
-
166zend_shared_alloc.h
@ -0,0 +1,87 @@ |
|||
# General Ignores |
|||
*~ |
|||
.#* |
|||
*. |
|||
*.slo |
|||
*.mk |
|||
*.mem |
|||
*.gcda |
|||
*.gcno |
|||
*.la |
|||
*.lo |
|||
*.o |
|||
*.a |
|||
*.ncb |
|||
*.opt |
|||
*.plg |
|||
*swp |
|||
*.patch |
|||
*.tgz |
|||
*.tar.gz |
|||
*.tar.bz2 |
|||
.FBCIndex |
|||
.FBCLockFolder |
|||
.deps |
|||
.libs |
|||
phpt.* |
|||
core |
|||
dynlib.m4 |
|||
Debug |
|||
Debug_TS |
|||
Makefile |
|||
Makefile.fragments |
|||
Makefile.objects |
|||
Makefile.global |
|||
Release |
|||
Release_TS |
|||
Release_TSDbg |
|||
Release_TS_inline |
|||
Release_inline |
|||
ZendEngine1 |
|||
_libs |
|||
acconfig.h |
|||
aclocal.m4 |
|||
acinclude.m4 |
|||
autom4te.cache |
|||
bsd_converted |
|||
buildconf.stamp |
|||
buildmk.stamp |
|||
confdefs.h |
|||
config.h |
|||
config.guess |
|||
config.cache |
|||
config.h.in |
|||
config.log |
|||
config.nice |
|||
config.nice.bat |
|||
config.status |
|||
config.sub |
|||
config_vars.mk |
|||
configuration-parser.c |
|||
configuration-parser.h |
|||
configuration-parser.output |
|||
configuration-scanner.c |
|||
configure |
|||
configure.in |
|||
configure.bat |
|||
configure.js |
|||
conftest |
|||
conftest.c |
|||
debug.log |
|||
diff |
|||
generated_lists |
|||
include |
|||
install-sh |
|||
internal_functions.c |
|||
lcov_data |
|||
lcov_html |
|||
libs |
|||
libtool |
|||
ltmain.sh |
|||
meta_cc |
|||
meta_ccld |
|||
missing |
|||
mkinstalldirs |
|||
modules |
|||
build |
|||
run-tests.php |
|||
1967
Optimizer/block_pass.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,126 @@ |
|||
/* pass 10: |
|||
* - remove NOPs |
|||
*/ |
|||
|
|||
static void nop_removal(zend_op_array *op_array) |
|||
{ |
|||
zend_op *end, *opline; |
|||
zend_uint new_count, i, shift; |
|||
int j; |
|||
zend_uint *shiftlist; |
|||
ALLOCA_FLAG(use_heap); |
|||
|
|||
shiftlist = (zend_uint *)DO_ALLOCA(sizeof(zend_uint) * op_array->last); |
|||
i = new_count = shift = 0; |
|||
end = op_array->opcodes+op_array->last; |
|||
for (opline = op_array->opcodes; opline < end; opline++) { |
|||
|
|||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO |
|||
/* GOTO target is unresolved yet. We can't optimize. */ |
|||
if (opline->opcode == ZEND_GOTO && |
|||
Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) { |
|||
/* TODO: in general we can avoid this restriction */ |
|||
FREE_ALLOCA(shiftlist); |
|||
return; |
|||
} |
|||
#endif |
|||
|
|||
/* Kill JMP-over-NOP-s */ |
|||
if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) { |
|||
/* check if there are only NOPs under the branch */ |
|||
zend_op *target = op_array->opcodes + ZEND_OP1(opline).opline_num - 1; |
|||
|
|||
while (target->opcode == ZEND_NOP) { |
|||
target--; |
|||
} |
|||
if (target == opline) { |
|||
/* only NOPs */ |
|||
opline->opcode = ZEND_NOP; |
|||
} |
|||
} |
|||
|
|||
shiftlist[i++] = shift; |
|||
if (opline->opcode == ZEND_NOP) { |
|||
shift++; |
|||
} else { |
|||
if (shift) { |
|||
op_array->opcodes[new_count] = *opline; |
|||
} |
|||
new_count++; |
|||
} |
|||
} |
|||
|
|||
if (shift) { |
|||
op_array->last = new_count; |
|||
end = op_array->opcodes + op_array->last; |
|||
|
|||
/* update JMPs */ |
|||
for (opline = op_array->opcodes; opline<end; opline++) { |
|||
switch (opline->opcode) { |
|||
case ZEND_JMP: |
|||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO |
|||
case ZEND_GOTO: |
|||
#endif |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
case ZEND_FAST_CALL: |
|||
#endif |
|||
ZEND_OP1(opline).opline_num -= shiftlist[ZEND_OP1(opline).opline_num]; |
|||
break; |
|||
case ZEND_JMPZ: |
|||
case ZEND_JMPNZ: |
|||
case ZEND_JMPZ_EX: |
|||
case ZEND_JMPNZ_EX: |
|||
case ZEND_FE_FETCH: |
|||
case ZEND_FE_RESET: |
|||
case ZEND_NEW: |
|||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO |
|||
case ZEND_JMP_SET: |
|||
#endif |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
case ZEND_JMP_SET_VAR: |
|||
#endif |
|||
ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num]; |
|||
break; |
|||
case ZEND_JMPZNZ: |
|||
ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num]; |
|||
opline->extended_value -= shiftlist[opline->extended_value]; |
|||
break; |
|||
case ZEND_CATCH: |
|||
opline->extended_value -= shiftlist[opline->extended_value]; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
/* update brk/cont array */ |
|||
for (i=0; i<op_array->last_brk_cont; i++) { |
|||
op_array->brk_cont_array[i].brk -= shiftlist[op_array->brk_cont_array[i].brk]; |
|||
op_array->brk_cont_array[i].cont -= shiftlist[op_array->brk_cont_array[i].cont]; |
|||
op_array->brk_cont_array[i].start -= shiftlist[op_array->brk_cont_array[i].start]; |
|||
} |
|||
|
|||
/* update try/catch array */ |
|||
for (j=0; j<op_array->last_try_catch; j++) { |
|||
op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op]; |
|||
op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op]; |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
if (op_array->try_catch_array[j].finally_op) { |
|||
op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op]; |
|||
op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end]; |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO |
|||
/* update early binding list */ |
|||
if (op_array->early_binding != -1) { |
|||
zend_uint *opline_num = &op_array->early_binding; |
|||
|
|||
do { |
|||
*opline_num -= shiftlist[*opline_num]; |
|||
opline_num = &ZEND_RESULT(&op_array->opcodes[*opline_num]).opline_num; |
|||
} while (*opline_num != -1); |
|||
} |
|||
#endif |
|||
} |
|||
FREE_ALLOCA(shiftlist); |
|||
} |
|||
@ -0,0 +1,222 @@ |
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
|
|||
/* ops that use CLs: |
|||
op1: |
|||
ZEND_FETCH_CONSTANT: |
|||
ZEND_INIT_CTOR_CALL: |
|||
ZEND_INIT_STATIC_METHOD_CALL: |
|||
ZEND_INIT_METHOD_CALL: |
|||
ZEND_IMPORT_CLASS: |
|||
ZEND_IMPORT_FUNCTION: |
|||
ZEND_IMPORT_CONST: |
|||
ZEND_ADD_INTERFACE: |
|||
ZEND_VERIFY_ABSTRACT_CLASS: |
|||
ZEND_NEW: |
|||
ZEND_CATCH: |
|||
ZEND_INIT_FCALL_BY_NAME: |
|||
|
|||
op2: |
|||
ZEND_UNSET_VAR: |
|||
ZEND_ISSET_ISEMPTY_VAR: |
|||
ZEND_FETCH_UNSET: |
|||
ZEND_FETCH_IS: |
|||
ZEND_FETCH_R: |
|||
ZEND_FETCH_W: |
|||
ZEND_FETCH_RW: |
|||
ZEND_FETCH_FUNC_ARG: |
|||
ZEND_ADD_INTERFACE: |
|||
ZEND_INSTANCEOF: |
|||
|
|||
extended_value: |
|||
ZEND_DECLARE_INHERITED_CLASS: |
|||
|
|||
ignore result |
|||
INIT_METHOD_CALL: |
|||
*/ |
|||
|
|||
#define OP1_CONST_IS_CLASS 1 |
|||
#define OP2_CONST_IS_CLASS 2 |
|||
#define EXT_CONST_IS_CLASS 4 |
|||
#define RESULT_IS_UNUSED 8 |
|||
|
|||
static const char op_const_means_class[256] = { |
|||
/* 0 */ |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|||
/* 32 */ |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, |
|||
/* 64 */ |
|||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, |
|||
/* 96 */ |
|||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 9, 1, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|||
/* 128 */ |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|||
/* 160 */ |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|||
/* 192 */ |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|||
/* 224 */ |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
|||
}; |
|||
#endif |
|||
|
|||
#define GET_AVAILABLE_T() \ |
|||
for (i=0; i<T; i++) { \ |
|||
if (!taken_T[i]) { \ |
|||
break; \ |
|||
} \ |
|||
} \ |
|||
taken_T[i] = 1; \ |
|||
if (i > max) { \ |
|||
max = i; \ |
|||
} |
|||
|
|||
static void optimize_temporary_variables(zend_op_array *op_array) |
|||
{ |
|||
int T = op_array->T; |
|||
char *taken_T; /* T index in use */ |
|||
zend_op **start_of_T; /* opline where T is first used */ |
|||
char *valid_T; /* Is the map_T valid */ |
|||
int *map_T; /* Map's the T to its new index */ |
|||
zend_op *opline, *end; |
|||
int currT; |
|||
int i; |
|||
int max = -1; |
|||
int var_to_free = -1; |
|||
|
|||
taken_T = (char *) emalloc(T); |
|||
start_of_T = (zend_op **) emalloc(T*sizeof(zend_op *)); |
|||
valid_T = (char *) emalloc(T); |
|||
map_T = (int *) emalloc(T*sizeof(int)); |
|||
|
|||
end = op_array->opcodes; |
|||
opline = &op_array->opcodes[op_array->last-1]; |
|||
|
|||
/* Find T definition points */ |
|||
while (opline >= end) { |
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) { |
|||
if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) { |
|||
start_of_T[VAR_NUM(ZEND_RESULT(opline).var)] = opline; |
|||
} |
|||
} |
|||
#else |
|||
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) { |
|||
start_of_T[VAR_NUM(ZEND_RESULT(opline).var)] = opline; |
|||
} |
|||
#endif |
|||
opline--; |
|||
} |
|||
|
|||
memset(valid_T, 0, T); |
|||
memset(taken_T, 0, T); |
|||
|
|||
end = op_array->opcodes; |
|||
opline = &op_array->opcodes[op_array->last-1]; |
|||
|
|||
while (opline >= end) { |
|||
if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) |
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
|| ((op_const_means_class[opline->opcode] & OP1_CONST_IS_CLASS) && ZEND_OP1_TYPE(opline) == IS_CONST) |
|||
#endif |
|||
) { |
|||
currT = VAR_NUM(ZEND_OP1(opline).var); |
|||
if (!valid_T[currT]) { |
|||
GET_AVAILABLE_T(); |
|||
map_T[currT] = i; |
|||
valid_T[currT] = 1; |
|||
} |
|||
ZEND_OP1(opline).var = NUM_VAR(map_T[currT]); |
|||
} |
|||
|
|||
/* Skip OP_DATA */ |
|||
if (opline->opcode == ZEND_OP_DATA && |
|||
(opline-1)->opcode == ZEND_ASSIGN_DIM) { |
|||
opline--; |
|||
continue; |
|||
} |
|||
|
|||
if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) |
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
|| ((op_const_means_class[opline->opcode] & OP2_CONST_IS_CLASS) && ZEND_OP2_TYPE(opline) == IS_CONST) |
|||
#endif |
|||
) { |
|||
currT = VAR_NUM(ZEND_OP2(opline).var); |
|||
if (!valid_T[currT]) { |
|||
GET_AVAILABLE_T(); |
|||
map_T[currT] = i; |
|||
valid_T[currT] = 1; |
|||
} |
|||
ZEND_OP2(opline).var = NUM_VAR(map_T[currT]); |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
if ((op_const_means_class[opline->opcode] & EXT_CONST_IS_CLASS)) { |
|||
#else |
|||
if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS || |
|||
opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) { |
|||
#endif |
|||
currT = VAR_NUM(opline->extended_value); |
|||
if (!valid_T[currT]) { |
|||
GET_AVAILABLE_T(); |
|||
map_T[currT] = i; |
|||
valid_T[currT] = 1; |
|||
} |
|||
opline->extended_value = NUM_VAR(map_T[currT]); |
|||
} |
|||
|
|||
/* Allocate OP_DATA->op2 after "opernds", but before "result" */ |
|||
if (opline->opcode == ZEND_ASSIGN_DIM && |
|||
(opline+1)->opcode == ZEND_OP_DATA && |
|||
ZEND_OP2_TYPE(opline+1) & (IS_VAR | IS_TMP_VAR)) { |
|||
currT = VAR_NUM(ZEND_OP2(opline+1).var); |
|||
GET_AVAILABLE_T(); |
|||
map_T[currT] = i; |
|||
valid_T[currT] = 1; |
|||
taken_T[i] = 0; |
|||
ZEND_OP2(opline+1).var = NUM_VAR(i); |
|||
var_to_free = i; |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) { |
|||
if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) { |
|||
#else |
|||
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) { |
|||
#endif |
|||
currT = VAR_NUM(ZEND_RESULT(opline).var); |
|||
if (valid_T[currT]) { |
|||
if (start_of_T[currT] == opline) { |
|||
taken_T[map_T[currT]] = 0; |
|||
} |
|||
ZEND_RESULT(opline).var = NUM_VAR(map_T[currT]); |
|||
} else { /* Au still needs to be assigned a T which is a bit dumb. Should consider changing Zend */ |
|||
GET_AVAILABLE_T(); |
|||
|
|||
if (RESULT_UNUSED(opline)) { |
|||
taken_T[i] = 0; |
|||
} else { |
|||
/* Code which gets here is using a wrongly built opcode such as RECV() */ |
|||
map_T[currT] = i; |
|||
valid_T[currT] = 1; |
|||
} |
|||
ZEND_RESULT(opline).var = NUM_VAR(i); |
|||
} |
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
if (var_to_free >= 0) { |
|||
taken_T[var_to_free] = 0; |
|||
var_to_free = -1; |
|||
} |
|||
|
|||
opline--; |
|||
} |
|||
|
|||
efree(taken_T); |
|||
efree(start_of_T); |
|||
efree(valid_T); |
|||
efree(map_T); |
|||
op_array->T = max+1; |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
if (((ZEND_OPTIMIZER_PASS_10|ZEND_OPTIMIZER_PASS_5) & OPTIMIZATION_LEVEL) == ZEND_OPTIMIZER_PASS_10) { |
|||
nop_removal(op_array); |
|||
} |
|||
@ -0,0 +1,391 @@ |
|||
/* pass 1 |
|||
* - substitute persistent constants (true, false, null, etc) |
|||
* - perform compile-time evaluation of constant binary and unary operations |
|||
* - optimize series of ADD_STRING and/or ADD_CHAR |
|||
* - convert CAST(IS_BOOL,x) into BOOL(x) |
|||
* - convert INTI_FCALL_BY_NAME, DO_FCALL_BY_NAME into DO_FCALL |
|||
*/ |
|||
|
|||
if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { |
|||
int i=0; |
|||
zend_op *opline = op_array->opcodes; |
|||
zend_op *end = opline + op_array->last; |
|||
|
|||
while (opline<end) { |
|||
switch (opline->opcode) { |
|||
case ZEND_ADD: |
|||
case ZEND_SUB: |
|||
case ZEND_MUL: |
|||
case ZEND_DIV: |
|||
case ZEND_MOD: |
|||
case ZEND_SL: |
|||
case ZEND_SR: |
|||
case ZEND_CONCAT: |
|||
case ZEND_IS_EQUAL: |
|||
case ZEND_IS_NOT_EQUAL: |
|||
case ZEND_IS_SMALLER: |
|||
case ZEND_IS_SMALLER_OR_EQUAL: |
|||
case ZEND_IS_IDENTICAL: |
|||
case ZEND_IS_NOT_IDENTICAL: |
|||
case ZEND_BW_OR: |
|||
case ZEND_BW_AND: |
|||
case ZEND_BW_XOR: |
|||
case ZEND_BOOL_XOR: |
|||
if (ZEND_OP1_TYPE(opline)==IS_CONST |
|||
&& ZEND_OP2_TYPE(opline)==IS_CONST) { |
|||
/* binary operation wheit constant operands */ |
|||
int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC) = get_binary_op(opline->opcode); |
|||
zend_uint tv = ZEND_RESULT(opline).var; /* temporary variable */ |
|||
zval result; |
|||
zend_op *tmp_opline; |
|||
int er; |
|||
|
|||
if (opline->opcode == ZEND_DIV && |
|||
Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_LONG && |
|||
Z_LVAL(ZEND_OP2_LITERAL(opline)) == 0) { |
|||
/* div by 0 */ |
|||
break; |
|||
} |
|||
er = EG(error_reporting); |
|||
EG(error_reporting) = 0; |
|||
/* evaluate constant expression */ |
|||
if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline) TSRMLS_CC) != SUCCESS) { |
|||
EG(error_reporting) = er; |
|||
break; |
|||
} |
|||
EG(error_reporting) = er; |
|||
PZ_SET_REFCOUNT_P(&result, 1); |
|||
PZ_UNSET_ISREF_P(&result); |
|||
|
|||
literal_dtor(&ZEND_OP1_LITERAL(opline)); |
|||
literal_dtor(&ZEND_OP2_LITERAL(opline)); |
|||
MAKE_NOP(opline); |
|||
|
|||
/* substitute the following TMP_VAR usage with constant */ |
|||
for (tmp_opline=opline+1; tmp_opline<end; tmp_opline++) { |
|||
if (ZEND_OP1_TYPE(tmp_opline)== IS_TMP_VAR |
|||
&& ZEND_OP1(tmp_opline).var == tv) { |
|||
if (tmp_opline->opcode==ZEND_FREE) { |
|||
MAKE_NOP(tmp_opline); |
|||
zval_dtor(&result); |
|||
} else { |
|||
ZEND_OP1_TYPE(tmp_opline) = IS_CONST; |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
tmp_opline->op1.constant = zend_add_literal(op_array, &result TSRMLS_CC); |
|||
if (Z_TYPE(result) == IS_STRING) { |
|||
Z_HASH_P(&ZEND_OP1_LITERAL(tmp_opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(tmp_opline)), Z_STRLEN(ZEND_OP1_LITERAL(tmp_opline))+1); |
|||
if (tmp_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || |
|||
tmp_opline->opcode == ZEND_DO_FCALL || |
|||
tmp_opline->opcode == ZEND_CATCH || |
|||
tmp_opline->opcode == ZEND_FETCH_CONSTANT) { |
|||
op_array->literals[tmp_opline->op1.constant].cache_slot = op_array->last_cache_slot++; |
|||
} |
|||
} |
|||
#else |
|||
ZEND_OP1_LITERAL(tmp_opline) = result; |
|||
#endif |
|||
} |
|||
/* TMP_VAR my be used only once */ |
|||
break; |
|||
} |
|||
if (ZEND_OP2_TYPE(tmp_opline)== IS_TMP_VAR |
|||
&& ZEND_OP2(tmp_opline).var == tv) { |
|||
ZEND_OP2_TYPE(tmp_opline) = IS_CONST; |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
tmp_opline->op2.constant = zend_add_literal(op_array, &result TSRMLS_CC); |
|||
if (Z_TYPE(result) == IS_STRING) { |
|||
Z_HASH_P(&ZEND_OP2_LITERAL(tmp_opline)) = zend_hash_func(Z_STRVAL(ZEND_OP2_LITERAL(tmp_opline)), Z_STRLEN(ZEND_OP2_LITERAL(tmp_opline))+1); |
|||
if (tmp_opline->opcode == ZEND_FETCH_R || |
|||
tmp_opline->opcode == ZEND_FETCH_W || |
|||
tmp_opline->opcode == ZEND_FETCH_RW || |
|||
tmp_opline->opcode == ZEND_FETCH_IS || |
|||
tmp_opline->opcode == ZEND_FETCH_UNSET || |
|||
tmp_opline->opcode == ZEND_FETCH_FUNC_ARG || |
|||
tmp_opline->opcode == ZEND_FETCH_CLASS || |
|||
tmp_opline->opcode == ZEND_INIT_FCALL_BY_NAME || |
|||
tmp_opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || |
|||
tmp_opline->opcode == ZEND_UNSET_VAR || |
|||
tmp_opline->opcode == ZEND_ISSET_ISEMPTY_VAR || |
|||
tmp_opline->opcode == ZEND_ADD_INTERFACE || |
|||
tmp_opline->opcode == ZEND_ADD_TRAIT) { |
|||
op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot++; |
|||
} else if (tmp_opline->opcode == ZEND_INIT_METHOD_CALL || |
|||
tmp_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || |
|||
tmp_opline->opcode == ZEND_FETCH_CONSTANT || |
|||
tmp_opline->opcode == ZEND_ASSIGN_OBJ || |
|||
tmp_opline->opcode == ZEND_FETCH_OBJ_R || |
|||
tmp_opline->opcode == ZEND_FETCH_OBJ_W || |
|||
tmp_opline->opcode == ZEND_FETCH_OBJ_RW || |
|||
tmp_opline->opcode == ZEND_FETCH_OBJ_IS || |
|||
tmp_opline->opcode == ZEND_FETCH_OBJ_UNSET || |
|||
tmp_opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG || |
|||
tmp_opline->opcode == ZEND_UNSET_OBJ || |
|||
tmp_opline->opcode == ZEND_PRE_INC_OBJ || |
|||
tmp_opline->opcode == ZEND_PRE_DEC_OBJ || |
|||
tmp_opline->opcode == ZEND_POST_INC_OBJ || |
|||
tmp_opline->opcode == ZEND_POST_DEC_OBJ || |
|||
tmp_opline->opcode == ZEND_ISSET_ISEMPTY_PROP_OBJ) { |
|||
op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot; |
|||
op_array->last_cache_slot += 2; |
|||
} else if (tmp_opline->opcode == ZEND_ASSIGN_ADD || |
|||
tmp_opline->opcode == ZEND_ASSIGN_SUB || |
|||
tmp_opline->opcode == ZEND_ASSIGN_MUL || |
|||
tmp_opline->opcode == ZEND_ASSIGN_DIV || |
|||
tmp_opline->opcode == ZEND_ASSIGN_MOD || |
|||
tmp_opline->opcode == ZEND_ASSIGN_SL || |
|||
tmp_opline->opcode == ZEND_ASSIGN_SR || |
|||
tmp_opline->opcode == ZEND_ASSIGN_CONCAT || |
|||
tmp_opline->opcode == ZEND_ASSIGN_BW_OR || |
|||
tmp_opline->opcode == ZEND_ASSIGN_BW_AND || |
|||
tmp_opline->opcode == ZEND_ASSIGN_BW_XOR) { |
|||
if (tmp_opline->extended_value == ZEND_ASSIGN_OBJ) { |
|||
op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot; |
|||
op_array->last_cache_slot += 2; |
|||
} |
|||
} |
|||
} |
|||
#else |
|||
ZEND_OP2_LITERAL(tmp_opline) = result; |
|||
#endif |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case ZEND_CAST: |
|||
if (ZEND_OP1_TYPE(opline)==IS_CONST && |
|||
opline->extended_value != IS_ARRAY && |
|||
opline->extended_value != IS_OBJECT && |
|||
opline->extended_value != IS_RESOURCE) { |
|||
/* cast of constant operand */ |
|||
zval res; |
|||
res = ZEND_OP1_LITERAL(opline); |
|||
zval_copy_ctor(&res); |
|||
switch (opline->extended_value) { |
|||
case IS_NULL: |
|||
convert_to_null(&res); |
|||
break; |
|||
case IS_BOOL: |
|||
convert_to_boolean(&res); |
|||
break; |
|||
case IS_LONG: |
|||
convert_to_long(&res); |
|||
break; |
|||
case IS_DOUBLE: |
|||
convert_to_double(&res); |
|||
break; |
|||
case IS_STRING: |
|||
convert_to_string(&res); |
|||
break; |
|||
} |
|||
literal_dtor(&ZEND_OP1_LITERAL(opline)); |
|||
opline->opcode = ZEND_QM_ASSIGN; |
|||
opline->extended_value = 0; |
|||
ZEND_OP1_LITERAL(opline) = res; |
|||
SET_UNUSED(opline->op2); |
|||
} else if (opline->extended_value == IS_BOOL) { |
|||
/* T = CAST(X, IS_BOOL) => T = BOOL(X) */ |
|||
opline->opcode = ZEND_BOOL; |
|||
opline->extended_value = 0; |
|||
} |
|||
break; |
|||
|
|||
case ZEND_BW_NOT: |
|||
case ZEND_BOOL_NOT: |
|||
if (ZEND_OP1_TYPE(opline)==IS_CONST) { |
|||
/* unary operation on constant operand */ |
|||
unary_op_type unary_op = get_unary_op(opline->opcode); |
|||
zval result; |
|||
zend_op *tmp_opline; |
|||
zend_uint tv = ZEND_RESULT(opline).var; /* temporary variable */ |
|||
int er; |
|||
|
|||
er = EG(error_reporting); |
|||
EG(error_reporting) = 0; |
|||
if (unary_op(&result, &ZEND_OP1_LITERAL(opline) TSRMLS_CC) != SUCCESS) { |
|||
EG(error_reporting) = er; |
|||
break; |
|||
} |
|||
EG(error_reporting) = er; |
|||
PZ_SET_REFCOUNT_P(&result, 1); |
|||
PZ_UNSET_ISREF_P(&result); |
|||
|
|||
literal_dtor(&ZEND_OP1_LITERAL(opline)); |
|||
MAKE_NOP(opline); |
|||
|
|||
/* substitute the following TMP_VAR usage with constant */ |
|||
for (tmp_opline=opline+1; tmp_opline<end; tmp_opline++) { |
|||
if (ZEND_OP1_TYPE(tmp_opline)== IS_TMP_VAR |
|||
&& ZEND_OP1(tmp_opline).var == tv) { |
|||
if (tmp_opline->opcode==ZEND_FREE) { |
|||
MAKE_NOP(tmp_opline); |
|||
zval_dtor(&result); |
|||
} else { |
|||
ZEND_OP1_TYPE(tmp_opline) = IS_CONST; |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
tmp_opline->op1.constant = zend_add_literal(op_array, &result TSRMLS_CC); |
|||
#else |
|||
ZEND_OP1_LITERAL(tmp_opline) = result; |
|||
#endif |
|||
} |
|||
break; |
|||
} |
|||
if (ZEND_OP2_TYPE(tmp_opline)== IS_TMP_VAR |
|||
&& ZEND_OP2(tmp_opline).var == tv) { |
|||
ZEND_OP2_TYPE(tmp_opline) = IS_CONST; |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
tmp_opline->op2.constant = zend_add_literal(op_array, &result TSRMLS_CC); |
|||
#else |
|||
ZEND_OP2_LITERAL(tmp_opline) = result; |
|||
#endif |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case ZEND_ADD_STRING: |
|||
case ZEND_ADD_CHAR: |
|||
{ |
|||
zend_op *next_op = opline+1; |
|||
int requires_conversion = (opline->opcode==ZEND_ADD_CHAR?1:0); |
|||
size_t final_length = 0; |
|||
char *ptr; |
|||
zend_op *last_op; |
|||
|
|||
/* There is always a ZEND_RETURN at the end |
|||
if (next_op>=end) { |
|||
break; |
|||
} |
|||
*/ |
|||
while (next_op->opcode == ZEND_ADD_STRING || next_op->opcode == ZEND_ADD_CHAR) { |
|||
if (ZEND_RESULT(opline).var != ZEND_RESULT(next_op).var) { |
|||
break; |
|||
} |
|||
if (next_op->opcode == ZEND_ADD_CHAR) { |
|||
final_length += 1; |
|||
} else { /* ZEND_ADD_STRING */ |
|||
final_length += ZEND_OP2_LITERAL(next_op).value.str.len; |
|||
} |
|||
next_op++; |
|||
} |
|||
if (final_length == 0) { |
|||
break; |
|||
} |
|||
last_op = next_op; |
|||
final_length += (requires_conversion ? 1 : ZEND_OP2_LITERAL(opline).value.str.len); |
|||
ptr = (char *) emalloc(final_length+1); |
|||
ptr[final_length] = '\0'; |
|||
if (requires_conversion) { /* ZEND_ADD_CHAR */ |
|||
char chval = (char)ZEND_OP2_LITERAL(opline).value.lval; |
|||
|
|||
ZEND_OP2_LITERAL(opline).value.str.val = ptr; |
|||
ptr[0] = chval; |
|||
ZEND_OP2_LITERAL(opline).type = IS_STRING; |
|||
opline->opcode = ZEND_ADD_STRING; |
|||
ptr++; |
|||
} else { /* ZEND_ADD_STRING */ |
|||
memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline))); |
|||
if (!IS_INTERNED(Z_STRVAL(ZEND_OP2_LITERAL(opline)))) { |
|||
efree(Z_STRVAL(ZEND_OP2_LITERAL(opline))); |
|||
} |
|||
Z_STRVAL(ZEND_OP2_LITERAL(opline)) = ptr; |
|||
ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline)); |
|||
} |
|||
ZEND_OP2_LITERAL(opline).value.str.len = final_length; |
|||
next_op = opline+1; |
|||
while (next_op < last_op) { |
|||
if (next_op->opcode == ZEND_ADD_STRING) { |
|||
memcpy(ptr, ZEND_OP2_LITERAL(next_op).value.str.val, ZEND_OP2_LITERAL(next_op).value.str.len); |
|||
ptr += ZEND_OP2_LITERAL(next_op).value.str.len; |
|||
literal_dtor(&ZEND_OP2_LITERAL(next_op)); |
|||
} else { /* ZEND_ADD_CHAR */ |
|||
*ptr = (char)ZEND_OP2_LITERAL(next_op).value.lval; |
|||
ptr++; |
|||
} |
|||
MAKE_NOP(next_op); |
|||
next_op++; |
|||
} |
|||
if (!((ZEND_OPTIMIZER_PASS_5|ZEND_OPTIMIZER_PASS_10) & OPTIMIZATION_LEVEL)) { |
|||
/* NOP removel is disabled => insert JMP over NOPs */ |
|||
if (last_op-opline >= 3) { /* If we have more than 2 NOPS then JMP over them */ |
|||
(opline+1)->opcode = ZEND_JMP; |
|||
ZEND_OP1(opline+1).opline_num = last_op - op_array->opcodes; /* that's OK even for ZE2, since opline_num's are resolved in pass 2 later */ |
|||
} |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case ZEND_FETCH_CONSTANT: |
|||
if (ZEND_OP1_TYPE(opline) == IS_UNUSED && |
|||
ZEND_OP2_TYPE(opline) == IS_CONST && |
|||
Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING && |
|||
Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__")-1 && |
|||
memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1) == 0) { |
|||
/* substitute __COMPILER_HALT_OFFSET__ constant */ |
|||
zend_bool orig_in_execution = EG(in_execution); |
|||
zend_op_array *orig_op_array = EG(active_op_array); |
|||
zval offset; |
|||
|
|||
EG(in_execution) = 1; |
|||
EG(active_op_array) = op_array; |
|||
if (zend_get_constant("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1, &offset TSRMLS_CC)) { |
|||
literal_dtor(&ZEND_OP2_LITERAL(opline)); |
|||
ZEND_OP1_TYPE(opline) = IS_CONST; |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
opline->op1.constant = zend_add_literal(op_array, &offset TSRMLS_CC); |
|||
#else |
|||
ZEND_OP1_LITERAL(opline) = offset; |
|||
#endif |
|||
SET_UNUSED(opline->op2); |
|||
opline->opcode = ZEND_QM_ASSIGN; |
|||
} |
|||
EG(active_op_array) = orig_op_array; |
|||
EG(in_execution) = orig_in_execution; |
|||
break; |
|||
} |
|||
|
|||
if (ZEND_OP1_TYPE(opline) == IS_UNUSED && |
|||
ZEND_OP2_TYPE(opline) == IS_CONST && |
|||
ZEND_OP2_LITERAL(opline).type == IS_STRING) { |
|||
/* substitute persistent constants */ |
|||
zval c; |
|||
|
|||
if(zend_get_persistent_constant(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), &c, 1 TSRMLS_CC) == 0) { |
|||
break; |
|||
} |
|||
literal_dtor(&ZEND_OP2_LITERAL(opline)); |
|||
ZEND_OP1_TYPE(opline) = IS_CONST; |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
opline->op1.constant = zend_add_literal(op_array, &c TSRMLS_CC); |
|||
#else |
|||
ZEND_OP1_LITERAL(opline) = c; |
|||
#endif |
|||
SET_UNUSED(opline->op2); |
|||
opline->opcode = ZEND_QM_ASSIGN; |
|||
} |
|||
break; |
|||
|
|||
case ZEND_INIT_FCALL_BY_NAME: |
|||
if(opline->extended_value == 0 /* not method */ && |
|||
ZEND_OP1_TYPE(opline) == IS_UNUSED && |
|||
ZEND_OP2_TYPE(opline) == IS_CONST) { |
|||
if((opline+1)->opcode == ZEND_DO_FCALL_BY_NAME && |
|||
(opline+1)->extended_value == 0) { |
|||
(opline+1)->opcode = ZEND_DO_FCALL; |
|||
COPY_NODE((opline+1)->op1, opline->op2); |
|||
zend_str_tolower(Z_STRVAL(ZEND_OP1_LITERAL(opline+1)), Z_STRLEN(ZEND_OP1_LITERAL(opline+1))); |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
Z_HASH_P(&ZEND_OP1_LITERAL(opline+1)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline+1)), Z_STRLEN(ZEND_OP1_LITERAL(opline+1))+1); |
|||
op_array->literals[(opline+1)->op1.constant].cache_slot = op_array->last_cache_slot++; |
|||
#endif |
|||
MAKE_NOP(opline); |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
opline++; |
|||
i++; |
|||
} |
|||
} |
|||
@ -0,0 +1,210 @@ |
|||
/* pass 2: |
|||
* - convert non-numeric constants to numeric constants in numeric operators |
|||
* - optimize constant conditional JMPs |
|||
* - optimize static BRKs and CONTs |
|||
*/ |
|||
|
|||
if (ZEND_OPTIMIZER_PASS_2 & OPTIMIZATION_LEVEL) { |
|||
zend_op *opline; |
|||
zend_op *end = op_array->opcodes+op_array->last; |
|||
|
|||
opline = op_array->opcodes; |
|||
while (opline<end) { |
|||
switch (opline->opcode) { |
|||
case ZEND_ADD: |
|||
case ZEND_SUB: |
|||
case ZEND_MUL: |
|||
case ZEND_DIV: |
|||
if (ZEND_OP1_TYPE(opline) == IS_CONST) { |
|||
if (ZEND_OP1_LITERAL(opline).type == IS_STRING) { |
|||
convert_scalar_to_number(&ZEND_OP1_LITERAL(opline) TSRMLS_CC); |
|||
} |
|||
} |
|||
/* break missing *intentionally* - the assign_op's may only optimize op2 */ |
|||
case ZEND_ASSIGN_ADD: |
|||
case ZEND_ASSIGN_SUB: |
|||
case ZEND_ASSIGN_MUL: |
|||
case ZEND_ASSIGN_DIV: |
|||
if(opline->extended_value != 0) { |
|||
/* object tristate op - don't attempt to optimize it! */ |
|||
break; |
|||
} |
|||
if (ZEND_OP2_TYPE(opline) == IS_CONST) { |
|||
if (ZEND_OP2_LITERAL(opline).type == IS_STRING) { |
|||
convert_scalar_to_number(&ZEND_OP2_LITERAL(opline) TSRMLS_CC); |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case ZEND_MOD: |
|||
case ZEND_SL: |
|||
case ZEND_SR: |
|||
if (ZEND_OP1_TYPE(opline) == IS_CONST) { |
|||
if (ZEND_OP1_LITERAL(opline).type != IS_LONG) { |
|||
convert_to_long(&ZEND_OP1_LITERAL(opline)); |
|||
} |
|||
} |
|||
/* break missing *intentionally - the assign_op's may only optimize op2 */ |
|||
case ZEND_ASSIGN_MOD: |
|||
case ZEND_ASSIGN_SL: |
|||
case ZEND_ASSIGN_SR: |
|||
if(opline->extended_value != 0) { |
|||
/* object tristate op - don't attempt to optimize it! */ |
|||
break; |
|||
} |
|||
if (ZEND_OP2_TYPE(opline) == IS_CONST) { |
|||
if (ZEND_OP2_LITERAL(opline).type != IS_LONG) { |
|||
convert_to_long(&ZEND_OP2_LITERAL(opline)); |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case ZEND_CONCAT: |
|||
if (ZEND_OP1_TYPE(opline) == IS_CONST) { |
|||
if (ZEND_OP1_LITERAL(opline).type != IS_STRING) { |
|||
convert_to_string(&ZEND_OP1_LITERAL(opline)); |
|||
} |
|||
} |
|||
/* break missing *intentionally - the assign_op's may only optimize op2 */ |
|||
case ZEND_ASSIGN_CONCAT: |
|||
if(opline->extended_value != 0) { |
|||
/* object tristate op - don't attempt to optimize it! */ |
|||
break; |
|||
} |
|||
if (ZEND_OP2_TYPE(opline) == IS_CONST) { |
|||
if (ZEND_OP2_LITERAL(opline).type != IS_STRING) { |
|||
convert_to_string(&ZEND_OP2_LITERAL(opline)); |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case ZEND_JMPZ_EX: |
|||
case ZEND_JMPNZ_EX: |
|||
/* convert Ti = JMPZ_EX(Ti, L) to JMPZ(Ti, L) */ |
|||
if (ZEND_OP1_TYPE(opline) == IS_TMP_VAR && |
|||
ZEND_RESULT_TYPE(opline) == IS_TMP_VAR && |
|||
ZEND_OP1(opline).var == ZEND_RESULT(opline).var) { |
|||
opline->opcode -= 3; |
|||
/* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C) |
|||
in case we know it wouldn't jump */ |
|||
} else if (ZEND_OP1_TYPE(opline) == IS_CONST) { |
|||
int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline)); |
|||
if (opline->opcode == ZEND_JMPZ_EX) { |
|||
should_jmp = !should_jmp; |
|||
} |
|||
if (!should_jmp) { |
|||
opline->opcode = ZEND_QM_ASSIGN; |
|||
SET_UNUSED(opline->op2); |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case ZEND_JMPZ: |
|||
case ZEND_JMPNZ: |
|||
if (ZEND_OP1_TYPE(opline) == IS_CONST) { |
|||
int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline)); |
|||
|
|||
if (opline->opcode == ZEND_JMPZ) { |
|||
should_jmp = !should_jmp; |
|||
} |
|||
literal_dtor(&ZEND_OP1_LITERAL(opline)); |
|||
ZEND_OP1_TYPE(opline) = IS_UNUSED; |
|||
if (should_jmp) { |
|||
opline->opcode = ZEND_JMP; |
|||
COPY_NODE(opline->op1, opline->op2); |
|||
} else { |
|||
MAKE_NOP(opline); |
|||
} |
|||
break; |
|||
} |
|||
if ((opline+1)->opcode == ZEND_JMP) { |
|||
/* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */ |
|||
/* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */ |
|||
if (ZEND_OP2(opline).opline_num == ZEND_OP1(opline+1).opline_num) { |
|||
/* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */ |
|||
MAKE_NOP(opline); |
|||
} else { |
|||
if (opline->opcode == ZEND_JMPZ) { |
|||
opline->extended_value = ZEND_OP1(opline+1).opline_num; |
|||
} else { |
|||
opline->extended_value = ZEND_OP2(opline).opline_num; |
|||
COPY_NODE(opline->op2, (opline+1)->op1); |
|||
} |
|||
opline->opcode = ZEND_JMPZNZ; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case ZEND_JMPZNZ: |
|||
if (ZEND_OP1_TYPE(opline) == IS_CONST) { |
|||
int opline_num; |
|||
|
|||
if (zend_is_true(&ZEND_OP1_LITERAL(opline))) { |
|||
opline_num = opline->extended_value; /* JMPNZ */ |
|||
} else { |
|||
opline_num = ZEND_OP2(opline).opline_num; /* JMPZ */ |
|||
} |
|||
literal_dtor(&ZEND_OP1_LITERAL(opline)); |
|||
ZEND_OP1(opline).opline_num = opline_num; |
|||
ZEND_OP1_TYPE(opline) = IS_UNUSED; |
|||
opline->opcode = ZEND_JMP; |
|||
} |
|||
break; |
|||
|
|||
case ZEND_BRK: |
|||
case ZEND_CONT: |
|||
{ |
|||
zend_brk_cont_element *jmp_to; |
|||
int array_offset; |
|||
int nest_levels; |
|||
int dont_optimize=0; |
|||
|
|||
if (ZEND_OP2_TYPE(opline) != IS_CONST) { |
|||
break; |
|||
} |
|||
convert_to_long(&ZEND_OP2_LITERAL(opline)); |
|||
nest_levels = ZEND_OP2_LITERAL(opline).value.lval; |
|||
|
|||
array_offset = ZEND_OP1(opline).opline_num; |
|||
while (1) { |
|||
if (array_offset==-1) { |
|||
dont_optimize=1; /* don't optimize this bogus break/continue, let the executor shout */ |
|||
break; |
|||
} |
|||
jmp_to = &op_array->brk_cont_array[array_offset]; |
|||
array_offset = jmp_to->parent; |
|||
if (--nest_levels > 0) { |
|||
if (opline->opcode == ZEND_BRK && |
|||
(op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE || |
|||
op_array->opcodes[jmp_to->brk].opcode == ZEND_SWITCH_FREE)) { |
|||
dont_optimize=1; |
|||
break; |
|||
} |
|||
} else { |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (dont_optimize) { |
|||
break; |
|||
} |
|||
|
|||
/* optimize - convert to a JMP */ |
|||
switch (opline->opcode) { |
|||
case ZEND_BRK: |
|||
MAKE_NOP(opline); |
|||
ZEND_OP1(opline).opline_num = jmp_to->brk; |
|||
break; |
|||
case ZEND_CONT: |
|||
MAKE_NOP(opline); |
|||
ZEND_OP1(opline).opline_num = jmp_to->cont; |
|||
break; |
|||
} |
|||
opline->opcode = ZEND_JMP; |
|||
/* MAKE_NOP() already set op1 and op2 to IS_UNUSED */ |
|||
} |
|||
break; |
|||
} |
|||
opline++; |
|||
} |
|||
} |
|||
@ -0,0 +1,443 @@ |
|||
/* pass 3: |
|||
* - optimize $i = $i+expr to $i+=expr |
|||
* - optimize series of JMPs |
|||
* - change $i++ to ++$i where possible |
|||
*/ |
|||
|
|||
/* compares opcodes with allowing oc1 be _EX of oc2 */ |
|||
#define SAME_OPCODE_EX(oc1, oc2) ((oc1 == oc2) || (oc1 == ZEND_JMPZ_EX && oc2 == ZEND_JMPZ) || (oc1 == ZEND_JMPNZ_EX && oc2 == ZEND_JMPNZ)) |
|||
|
|||
/* we use "jmp_hitlist" to avoid infinity loops during jmp optimization */ |
|||
#define CHECK_JMP(target, label) \ |
|||
for (i=0; i<jmp_hitlist_count; i++) { \ |
|||
if (jmp_hitlist[i] == ZEND_OP1(&op_array->opcodes[target]).opline_num) { \ |
|||
goto label; \ |
|||
} \ |
|||
} \ |
|||
jmp_hitlist[jmp_hitlist_count++] = ZEND_OP1(&op_array->opcodes[target]).opline_num; |
|||
|
|||
#define CHECK_JMP2(target, label) \ |
|||
for (i=0; i<jmp_hitlist_count; i++) { \ |
|||
if (jmp_hitlist[i] == ZEND_OP2(&op_array->opcodes[target]).opline_num) { \ |
|||
goto label; \ |
|||
} \ |
|||
} \ |
|||
jmp_hitlist[jmp_hitlist_count++] = ZEND_OP2(&op_array->opcodes[target]).opline_num; |
|||
|
|||
if(ZEND_OPTIMIZER_PASS_3 & OPTIMIZATION_LEVEL) { |
|||
zend_op *opline; |
|||
zend_op *end = op_array->opcodes+op_array->last; |
|||
zend_uint *jmp_hitlist; |
|||
int jmp_hitlist_count; |
|||
int i; |
|||
zend_uint opline_num = 0; |
|||
ALLOCA_FLAG(use_heap); |
|||
|
|||
jmp_hitlist = (zend_uint *) DO_ALLOCA(sizeof(zend_uint)*op_array->last); |
|||
opline = op_array->opcodes; |
|||
|
|||
while (opline<end) { |
|||
jmp_hitlist_count = 0; |
|||
|
|||
switch (opline->opcode) { |
|||
case ZEND_ADD: |
|||
case ZEND_SUB: |
|||
case ZEND_MUL: |
|||
case ZEND_DIV: |
|||
case ZEND_MOD: |
|||
case ZEND_CONCAT: |
|||
case ZEND_SL: |
|||
case ZEND_SR: |
|||
case ZEND_BW_OR: |
|||
case ZEND_BW_AND: |
|||
case ZEND_BW_XOR: |
|||
{ |
|||
zend_op *next_opline = opline+1; |
|||
|
|||
while (next_opline < end && next_opline->opcode == ZEND_NOP) { |
|||
++next_opline; |
|||
} |
|||
|
|||
if (next_opline >= end || next_opline->opcode != ZEND_ASSIGN) { |
|||
break; |
|||
} |
|||
|
|||
if ((ZEND_OP2_TYPE(opline)==IS_VAR || ZEND_OP2_TYPE(opline)==IS_CV) |
|||
&& ZEND_OP2(opline).var == ZEND_OP1(next_opline).var && |
|||
(opline->opcode == ZEND_ADD || |
|||
opline->opcode == ZEND_MUL || |
|||
opline->opcode == ZEND_BW_OR || |
|||
opline->opcode == ZEND_BW_AND || |
|||
opline->opcode == ZEND_BW_XOR)) { |
|||
/* change $i=expr+$i to $i=$i+expr so that the next |
|||
* optimization works on it |
|||
*/ |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
zend_uchar tmp_type=opline->op1_type; |
|||
znode_op tmp=opline->op1; |
|||
#else |
|||
znode tmp=opline->op1; |
|||
#endif |
|||
|
|||
if(opline->opcode != ZEND_ADD || ZEND_OP1_TYPE(opline) == IS_CONST) { |
|||
/* protection from array add: $a = array + $a is not commutative! */ |
|||
COPY_NODE(opline->op1, opline->op2); |
|||
COPY_NODE(opline->op2, tmp); |
|||
} |
|||
} |
|||
if ((ZEND_OP1_TYPE(opline)==IS_VAR || ZEND_OP1_TYPE(opline)==IS_CV) |
|||
&& ZEND_OP1(opline).var == ZEND_OP1(next_opline).var |
|||
&& ZEND_OP1_TYPE(opline) == ZEND_OP1_TYPE(next_opline)) { |
|||
switch (opline->opcode) { |
|||
case ZEND_ADD: |
|||
opline->opcode = ZEND_ASSIGN_ADD; |
|||
break; |
|||
case ZEND_SUB: |
|||
opline->opcode = ZEND_ASSIGN_SUB; |
|||
break; |
|||
case ZEND_MUL: |
|||
opline->opcode = ZEND_ASSIGN_MUL; |
|||
break; |
|||
case ZEND_DIV: |
|||
opline->opcode = ZEND_ASSIGN_DIV; |
|||
break; |
|||
case ZEND_MOD: |
|||
opline->opcode = ZEND_ASSIGN_MOD; |
|||
break; |
|||
case ZEND_CONCAT: |
|||
opline->opcode = ZEND_ASSIGN_CONCAT; |
|||
break; |
|||
case ZEND_SL: |
|||
opline->opcode = ZEND_ASSIGN_SL; |
|||
break; |
|||
case ZEND_SR: |
|||
opline->opcode = ZEND_ASSIGN_SR; |
|||
break; |
|||
case ZEND_BW_OR: |
|||
opline->opcode = ZEND_ASSIGN_BW_OR; |
|||
break; |
|||
case ZEND_BW_AND: |
|||
opline->opcode = ZEND_ASSIGN_BW_AND; |
|||
break; |
|||
case ZEND_BW_XOR: |
|||
opline->opcode = ZEND_ASSIGN_BW_XOR; |
|||
break; |
|||
} |
|||
COPY_NODE(opline->result, next_opline->result); |
|||
MAKE_NOP(next_opline); |
|||
opline++; |
|||
opline_num++; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case ZEND_JMP: |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
if (op_array->has_finally_block) { |
|||
break; |
|||
} |
|||
#endif |
|||
|
|||
/* convert L: JMP L+1 to NOP */ |
|||
if(ZEND_OP1(opline).opline_num == opline_num + 1) { |
|||
MAKE_NOP(opline); |
|||
goto done_jmp_optimization; |
|||
} |
|||
|
|||
/* convert JMP L1 ... L1: JMP L2 to JMP L2 .. L1: JMP L2 */ |
|||
while (ZEND_OP1(opline).opline_num<op_array->last |
|||
&& op_array->opcodes[ZEND_OP1(opline).opline_num].opcode == ZEND_JMP) { |
|||
int target = ZEND_OP1(opline).opline_num; |
|||
CHECK_JMP(target, done_jmp_optimization); |
|||
ZEND_OP1(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num; |
|||
} |
|||
break; |
|||
|
|||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO |
|||
case ZEND_JMP_SET: |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
case ZEND_JMP_SET_VAR: |
|||
#endif |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
if (op_array->has_finally_block) { |
|||
break; |
|||
} |
|||
#endif |
|||
|
|||
while (ZEND_OP2(opline).opline_num<op_array->last) { |
|||
int target = ZEND_OP2(opline).opline_num; |
|||
if (op_array->opcodes[target].opcode == ZEND_JMP) { |
|||
ZEND_OP2(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num; |
|||
} else { |
|||
break; |
|||
} |
|||
} |
|||
break; |
|||
#endif |
|||
|
|||
case ZEND_JMPZ: |
|||
case ZEND_JMPNZ: |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
if (op_array->has_finally_block) { |
|||
break; |
|||
} |
|||
#endif |
|||
|
|||
/* convert L: JMPZ L+1 to NOP */ |
|||
if(ZEND_OP2(opline).opline_num == opline_num + 1) { |
|||
MAKE_NOP(opline); |
|||
goto done_jmp_optimization; |
|||
} |
|||
|
|||
while (ZEND_OP2(opline).opline_num<op_array->last) { |
|||
int target = ZEND_OP2(opline).opline_num; |
|||
|
|||
if (op_array->opcodes[target].opcode == ZEND_JMP) { |
|||
/* plain JMP */ |
|||
/* JMPZ(X,L1), L1: JMP(L2) => JMPZ(X,L2), L1: JMP(L2) */ |
|||
CHECK_JMP(target, done_jmp_optimization); |
|||
ZEND_OP2(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num; |
|||
} else if (op_array->opcodes[target].opcode == opline->opcode && |
|||
SAME_VAR(opline->op1, op_array->opcodes[target].op1)) { |
|||
/* same opcode and same var as this opcode */ |
|||
/* JMPZ(X,L1), L1: JMPZ(X,L2) => JMPZ(X,L2), L1: JMPZ(X,L2) */ |
|||
CHECK_JMP2(target, done_jmp_optimization); |
|||
ZEND_OP2(opline).opline_num = ZEND_OP2(&op_array->opcodes[target]).opline_num; |
|||
} else if (op_array->opcodes[target].opcode == opline->opcode+3 && |
|||
SAME_VAR(opline->op1, op_array->opcodes[target].op1)) { |
|||
/* convert JMPZ(X,L1), L1: T JMPZ_EX(X,L2) to |
|||
T = JMPZ_EX(X, L2) */ |
|||
ZEND_OP2(opline).opline_num = ZEND_OP2(&op_array->opcodes[target]).opline_num;opline->opcode += 3; |
|||
COPY_NODE(opline->result, op_array->opcodes[target].result); |
|||
break; |
|||
} else if (op_array->opcodes[target].opcode == INV_COND(opline->opcode) && |
|||
SAME_VAR(opline->op1, op_array->opcodes[target].op1)) { |
|||
/* convert JMPZ(X,L1), L1: JMPNZ(X,L2) to |
|||
JMPZ(X,L1+1) */ |
|||
ZEND_OP2(opline).opline_num = target+1; |
|||
break; |
|||
} else if (op_array->opcodes[target].opcode == INV_COND_EX(opline->opcode) && |
|||
SAME_VAR(opline->op1, op_array->opcodes[target].op1)) { |
|||
/* convert JMPZ(X,L1), L1: T = JMPNZ_EX(X,L2) to |
|||
T = JMPZ_EX(X,L1+1) */ |
|||
ZEND_OP2(opline).opline_num = target+1; |
|||
opline->opcode += 3; |
|||
COPY_NODE(opline->result, op_array->opcodes[target].result); |
|||
break; |
|||
} else { |
|||
break; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case ZEND_JMPZ_EX: |
|||
case ZEND_JMPNZ_EX: { |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
zend_uchar T_type = opline->result_type; |
|||
znode_op T = opline->result; |
|||
#else |
|||
znode T = opline->result; |
|||
#endif |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
if (op_array->has_finally_block) { |
|||
break; |
|||
} |
|||
#endif |
|||
/* convert L: T = JMPZ_EX X,L+1 to T = BOOL(X) */ |
|||
/* convert L: T = JMPZ_EX T,L+1 to NOP */ |
|||
if(ZEND_OP2(opline).opline_num == opline_num + 1) { |
|||
if(ZEND_OP1(opline).var == ZEND_RESULT(opline).var) { |
|||
MAKE_NOP(opline); |
|||
} else { |
|||
opline->opcode = ZEND_BOOL; |
|||
SET_UNUSED(opline->op2); |
|||
} |
|||
goto done_jmp_optimization; |
|||
} |
|||
|
|||
while (ZEND_OP2(opline).opline_num<op_array->last) { |
|||
int target = ZEND_OP2(opline).opline_num; |
|||
if(SAME_OPCODE_EX(opline->opcode, op_array->opcodes[target].opcode) && |
|||
SAME_VAR(op_array->opcodes[target].op1, T)) { |
|||
/* Check for JMPZ_EX to JMPZ[_EX] with the same condition, either with _EX or not */ |
|||
if(op_array->opcodes[target].opcode == opline->opcode) { |
|||
/* change T only if we have _EX opcode there */ |
|||
COPY_NODE(T, op_array->opcodes[target].result); |
|||
} |
|||
CHECK_JMP2(target, continue_jmp_ex_optimization); |
|||
ZEND_OP2(opline).opline_num = ZEND_OP2(&op_array->opcodes[target]).opline_num; |
|||
} else if(op_array->opcodes[target].opcode == ZEND_JMPZNZ && |
|||
SAME_VAR(op_array->opcodes[target].op1, T)) { |
|||
/* Check for JMPZNZ with same cond variable */ |
|||
int new_target; |
|||
CHECK_JMP2(target, continue_jmp_ex_optimization); |
|||
if(opline->opcode == ZEND_JMPZ_EX) { |
|||
new_target = ZEND_OP2(&op_array->opcodes[target]).opline_num; |
|||
} else { |
|||
/* JMPNZ_EX */ |
|||
new_target = op_array->opcodes[target].extended_value; |
|||
} |
|||
ZEND_OP2(opline).opline_num = new_target; |
|||
} else if((op_array->opcodes[target].opcode == INV_EX_COND_EX(opline->opcode) || |
|||
op_array->opcodes[target].opcode == INV_EX_COND(opline->opcode) |
|||
) && |
|||
SAME_VAR(opline->op1, op_array->opcodes[target].op1)) { |
|||
/* convert JMPZ_EX(X,L1), L1: JMPNZ_EX(X,L2) to |
|||
JMPZ_EX(X,L1+1) */ |
|||
ZEND_OP2(opline).opline_num = target+1; |
|||
break; |
|||
} else { |
|||
break; |
|||
} |
|||
} /* while */ |
|||
continue_jmp_ex_optimization: |
|||
break; |
|||
#if 0 |
|||
/* If Ti = JMPZ_EX(X, L) and Ti is not used, convert to JMPZ(X, L) */ |
|||
{ |
|||
zend_op *op; |
|||
for(op = opline+1; op<end; op++) { |
|||
if(ZEND_RESULT_TYPE(op) == IS_TMP_VAR && |
|||
ZEND_RESULT(op).var == ZEND_RESULT(opline).var) { |
|||
break; /* can pass to part 2 */ |
|||
} |
|||
|
|||
if(op->opcode == ZEND_JMP || |
|||
op->opcode == ZEND_JMPZ || |
|||
op->opcode == ZEND_JMPZ_EX || |
|||
op->opcode == ZEND_JMPNZ || |
|||
op->opcode == ZEND_JMPNZ_EX || |
|||
op->opcode == ZEND_JMPZNZ || |
|||
op->opcode == ZEND_BRK || |
|||
op->opcode == ZEND_CONT || |
|||
op->opcode == ZEND_CASE || |
|||
op->opcode == ZEND_RETURN || |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
op->opcode == ZEND_RETURN_BY_REF || |
|||
#endif |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
op->opcode == ZEND_FAST_RET || |
|||
#endif |
|||
op->opcode == ZEND_FE_FETCH || |
|||
op->opcode == ZEND_EXIT) { |
|||
break; |
|||
} |
|||
|
|||
if(ZEND_OP1_TYPE(op) == IS_TMP_VAR && |
|||
ZEND_OP1(op).var == ZEND_RESULT(opline).var) { |
|||
goto done_jmp_optimization; |
|||
} |
|||
|
|||
if(ZEND_OP2_TYPE(op) == IS_TMP_VAR && |
|||
ZEND_OP2(op).var == ZEND_RESULT(opline).var) { |
|||
goto done_jmp_optimization; |
|||
} |
|||
} /* for */ |
|||
|
|||
for(op = &op_array->opcodes[ZEND_OP2(opline).opline_num]; op<end; op++) { |
|||
|
|||
if(ZEND_RESULT_TYPE(op) == IS_TMP_VAR && |
|||
ZEND_RESULT(op).var == ZEND_RESULT(opline).var) { |
|||
break; /* can pass to optimization */ |
|||
} |
|||
|
|||
if(op->opcode == ZEND_JMP || |
|||
op->opcode == ZEND_JMPZ || |
|||
op->opcode == ZEND_JMPZ_EX || |
|||
op->opcode == ZEND_JMPNZ || |
|||
op->opcode == ZEND_JMPNZ_EX || |
|||
op->opcode == ZEND_JMPZNZ || |
|||
op->opcode == ZEND_BRK || |
|||
op->opcode == ZEND_CONT || |
|||
op->opcode == ZEND_CASE || |
|||
op->opcode == ZEND_RETURN || |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
op->opcode == ZEND_RETURN_BY_REF || |
|||
#endif |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
op->opcode == ZEND_FAST_RET || |
|||
#endif |
|||
op->opcode == ZEND_FE_FETCH || |
|||
op->opcode == ZEND_EXIT) { |
|||
break; |
|||
} |
|||
|
|||
if(ZEND_OP1_TYPE(op) == IS_TMP_VAR && |
|||
ZEND_OP1(op).var == ZEND_RESULT(opline).var) { |
|||
goto done_jmp_optimization; |
|||
} |
|||
|
|||
if(ZEND_OP2_TYPE(op) == IS_TMP_VAR && |
|||
ZEND_OP2(op).var == ZEND_RESULT(opline).var) { |
|||
goto done_jmp_optimization; |
|||
} |
|||
} |
|||
|
|||
opline->opcode = opline->opcode-3; /* JMP_EX -> JMP */ |
|||
SET_UNUSED(opline->result); |
|||
break; |
|||
} |
|||
#endif |
|||
} |
|||
break; |
|||
|
|||
case ZEND_JMPZNZ: |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
if (op_array->has_finally_block) { |
|||
break; |
|||
} |
|||
#endif |
|||
/* JMPZNZ(X,L1,L2), L1: JMP(L3) => JMPZNZ(X,L3,L2), L1: JMP(L3) */ |
|||
while (ZEND_OP2(opline).opline_num < op_array->last |
|||
&& op_array->opcodes[ZEND_OP2(opline).opline_num].opcode == ZEND_JMP) { |
|||
int target = ZEND_OP2(opline).opline_num; |
|||
CHECK_JMP(target, continue_jmpznz_optimization); |
|||
ZEND_OP2(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num; |
|||
} |
|||
continue_jmpznz_optimization: |
|||
/* JMPZNZ(X,L1,L2), L2: JMP(L3) => JMPZNZ(X,L1,L3), L2: JMP(L3) */ |
|||
while (opline->extended_value < op_array->last |
|||
&& op_array->opcodes[opline->extended_value].opcode == ZEND_JMP) { |
|||
int target = opline->extended_value; |
|||
CHECK_JMP(target, done_jmp_optimization); |
|||
opline->extended_value = ZEND_OP1(&op_array->opcodes[target]).opline_num; |
|||
} |
|||
break; |
|||
|
|||
case ZEND_POST_INC: |
|||
case ZEND_POST_DEC: { |
|||
/* POST_INC, FREE => PRE_INC */ |
|||
zend_op *next_op = opline+1; |
|||
|
|||
if (next_op>=end) { |
|||
break; |
|||
} |
|||
if (next_op->opcode == ZEND_FREE |
|||
&& ZEND_OP1(next_op).var == ZEND_RESULT(opline).var) { |
|||
MAKE_NOP(next_op); |
|||
switch (opline->opcode) { |
|||
case ZEND_POST_INC: |
|||
opline->opcode = ZEND_PRE_INC; |
|||
break; |
|||
case ZEND_POST_DEC: |
|||
opline->opcode = ZEND_PRE_DEC; |
|||
break; |
|||
} |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
ZEND_RESULT_TYPE(opline) = IS_VAR | EXT_TYPE_UNUSED; |
|||
#else |
|||
ZEND_RESULT_TYPE(opline) = IS_VAR; |
|||
ZEND_RESULT(opline).EA.type = 0; |
|||
ZEND_RESULT(opline).EA.type |= EXT_TYPE_UNUSED; |
|||
#endif |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
done_jmp_optimization: |
|||
opline++; |
|||
opline_num++; |
|||
} |
|||
FREE_ALLOCA(jmp_hitlist); |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
if (ZEND_OPTIMIZER_PASS_5 & OPTIMIZATION_LEVEL) { |
|||
zend_block_optimization(op_array TSRMLS_CC); |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
/* pass 9 |
|||
* |
|||
* - optimize usage of temporary variables |
|||
*/ |
|||
|
|||
if (ZEND_OPTIMIZER_PASS_9 & OPTIMIZATION_LEVEL) { |
|||
optimize_temporary_variables(op_array); |
|||
} |
|||
@ -0,0 +1,139 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include "Optimizer/zend_optimizer.h" |
|||
#include "Optimizer/zend_optimizer_internal.h" |
|||
#include "zend_API.h" |
|||
#include "zend_constants.h" |
|||
#include "zend_execute.h" |
|||
|
|||
#define OPTIMIZATION_LEVEL \ |
|||
ZCG(accel_directives).optimization_level |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) |
|||
{ |
|||
int i = op_array->last_literal; |
|||
op_array->last_literal++; |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
{ |
|||
if (i >= CG(context).literals_size) { |
|||
CG(context).literals_size += 16; /* FIXME */ |
|||
op_array->literals = (zend_literal*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zend_literal)); |
|||
} |
|||
} |
|||
#else |
|||
if (i >= op_array->size_literal) { |
|||
op_array->size_literal += 16; /* FIXME */ |
|||
op_array->literals = (zend_literal*)erealloc(op_array->literals, op_array->size_literal * sizeof(zend_literal)); |
|||
} |
|||
#endif |
|||
op_array->literals[i].constant = *zv; |
|||
Z_SET_REFCOUNT(op_array->literals[i].constant, 2); |
|||
Z_SET_ISREF(op_array->literals[i].constant); |
|||
return i; |
|||
} |
|||
|
|||
# define LITERAL_LONG(op, val) do { \ |
|||
zval _c; \ |
|||
ZVAL_LONG(&_c, val); \ |
|||
op.constant = zend_add_literal(op_array, &_c TSRMLS_CC); \ |
|||
} while (0) |
|||
|
|||
# define LITERAL_BOOL(op, val) do { \ |
|||
zval _c; \ |
|||
ZVAL_BOOL(&_c, val); \ |
|||
op.constant = zend_add_literal(op_array, &_c TSRMLS_CC); \ |
|||
} while (0) |
|||
|
|||
# define literal_dtor(zv) do { \ |
|||
zval_dtor(zv); \ |
|||
Z_TYPE_P(zv) = IS_NULL; \ |
|||
} while (0) |
|||
|
|||
#define COPY_NODE(target, src) do { \ |
|||
target ## _type = src ## _type; \ |
|||
target = src; \ |
|||
} while (0) |
|||
|
|||
#else |
|||
|
|||
# define LITERAL_LONG(op, val) ZVAL_LONG(&op.u.constant, val) |
|||
|
|||
# define LITERAL_BOOL(op, val) ZVAL_BOOL(&op.u.constant, val) |
|||
|
|||
# define literal_dtor(zv) zval_dtor(zv) |
|||
|
|||
#define COPY_NODE(target, src) do { \ |
|||
target = src; \ |
|||
} while (0) |
|||
|
|||
#endif |
|||
|
|||
#include "Optimizer/nop_removal.c" |
|||
#include "Optimizer/block_pass.c" |
|||
#include "Optimizer/optimize_temp_vars_5.c" |
|||
|
|||
void zend_optimizer(zend_op_array *op_array TSRMLS_DC) |
|||
{ |
|||
if (op_array->type == ZEND_EVAL_CODE || |
|||
(op_array->fn_flags & ZEND_ACC_INTERACTIVE)) { |
|||
return; |
|||
} |
|||
|
|||
/* pass 1 |
|||
* - substitute persistent constants (true, false, null, etc) |
|||
* - perform compile-time evaluation of constant binary and unary operations |
|||
* - optimize series of ADD_STRING and/or ADD_CHAR |
|||
* - convert CAST(IS_BOOL,x) into BOOL(x) |
|||
* - convert INTI_FCALL_BY_NAME + DO_FCALL_BY_NAME into DO_FCALL |
|||
*/ |
|||
#include "Optimizer/pass1_5.c" |
|||
|
|||
/* pass 2: |
|||
* - convert non-numeric constants to numeric constants in numeric operators |
|||
* - optimize constant conditional JMPs |
|||
* - optimize static BRKs and CONTs |
|||
*/ |
|||
#include "Optimizer/pass2.c" |
|||
|
|||
/* pass 3: |
|||
* - optimize $i = $i+expr to $i+=expr |
|||
* - optimize series of JMPs |
|||
* - change $i++ to ++$i where possible |
|||
*/ |
|||
#include "Optimizer/pass3.c" |
|||
|
|||
/* pass 5: |
|||
* - CFG optimization |
|||
*/ |
|||
#include "Optimizer/pass5.c" |
|||
|
|||
/* pass 9: |
|||
* - Optimize temp variables usage |
|||
*/ |
|||
#include "Optimizer/pass9.c" |
|||
|
|||
/* pass 10: |
|||
* - remove NOPs |
|||
*/ |
|||
#include "Optimizer/pass10.c" |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef ZEND_OPTIMIZER_H |
|||
#define ZEND_OPTIMIZER_H |
|||
|
|||
#include "zend.h" |
|||
#include "zend_compile.h" |
|||
|
|||
#define ZEND_OPTIMIZER_PASS_1 (1<<0) /* CSE, STRING construction */ |
|||
#define ZEND_OPTIMIZER_PASS_2 (1<<1) /* Constant conversion and jums */ |
|||
#define ZEND_OPTIMIZER_PASS_3 (1<<2) /* ++, +=, series of jumps */ |
|||
#define ZEND_OPTIMIZER_PASS_4 (1<<3) |
|||
#define ZEND_OPTIMIZER_PASS_5 (1<<4) /* CFG based optimization */ |
|||
#define ZEND_OPTIMIZER_PASS_6 (1<<5) |
|||
#define ZEND_OPTIMIZER_PASS_7 (1<<6) |
|||
#define ZEND_OPTIMIZER_PASS_8 (1<<7) |
|||
#define ZEND_OPTIMIZER_PASS_9 (1<<8) /* TMP VAR usage */ |
|||
#define ZEND_OPTIMIZER_PASS_10 (1<<9) /* NOP removal */ |
|||
#define ZEND_OPTIMIZER_PASS_11 (1<<10) |
|||
#define ZEND_OPTIMIZER_PASS_12 (1<<11) |
|||
#define ZEND_OPTIMIZER_PASS_13 (1<<12) |
|||
#define ZEND_OPTIMIZER_PASS_14 (1<<13) |
|||
|
|||
#define ZEND_OPTIMIZER_ALL_PASSES 0xFFFFFFFF |
|||
|
|||
#define DEFAULT_OPTIMIZATION_LEVEL "0xFFFFFFFF" |
|||
|
|||
void zend_optimizer(zend_op_array *op_array TSRMLS_DC); |
|||
|
|||
#endif |
|||
@ -0,0 +1,76 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef ZEND_OPTIMIZER_INTERNAL_H |
|||
#define ZEND_OPTIMIZER_INTERNAL_H |
|||
|
|||
#include "ZendAccelerator.h" |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
# define VAR_NUM(v) (EX_TMP_VAR_NUM(0, 0) - EX_TMP_VAR(0, v)) |
|||
# define NUM_VAR(v) ((zend_uint)EX_TMP_VAR_NUM(0, v)) |
|||
#else |
|||
# define VAR_NUM(v) ((v)/(sizeof(temp_variable))) |
|||
# define NUM_VAR(v) ((v)*(sizeof(temp_variable))) |
|||
#endif |
|||
|
|||
#define INV_COND(op) ((op) == ZEND_JMPZ ? ZEND_JMPNZ : ZEND_JMPZ) |
|||
#define INV_EX_COND(op) ((op) == ZEND_JMPZ_EX ? ZEND_JMPNZ : ZEND_JMPZ) |
|||
#define INV_COND_EX(op) ((op) == ZEND_JMPZ ? ZEND_JMPNZ_EX : ZEND_JMPZ_EX) |
|||
#define INV_EX_COND_EX(op) ((op) == ZEND_JMPZ_EX ? ZEND_JMPNZ_EX : ZEND_JMPZ_EX) |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
# define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(opline->result)); memset(&opline->op1,0,sizeof(opline->op1)); memset(&opline->op2,0,sizeof(opline->op2)); opline->result_type=opline->op1_type=opline->op2_type=IS_UNUSED; opline->handler = zend_opcode_handlers[ZEND_NOP]; } |
|||
# define RESULT_USED(op) (((op->result_type & IS_VAR) && !(op->result_type & EXT_TYPE_UNUSED)) || op->result_type == IS_TMP_VAR) |
|||
# define RESULT_UNUSED(op) ((op->result_type & EXT_TYPE_UNUSED) != 0) |
|||
# define SAME_VAR(op1, op2) ((((op1 ## _type & IS_VAR) && (op2 ## _type & IS_VAR)) || (op1 ## _type == IS_TMP_VAR && op2 ## _type == IS_TMP_VAR)) && op1.var == op2.var) |
|||
#else |
|||
# define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(znode)); memset(&opline->op1,0,sizeof(znode)); memset(&opline->op2,0,sizeof(znode)); opline->result.op_type=opline->op1.op_type=opline->op2.op_type=IS_UNUSED; opline->handler = zend_opcode_handlers[ZEND_NOP]; } |
|||
# define RESULT_USED(op) ((op->result.op_type == IS_VAR && (op->result.u.EA.type & EXT_TYPE_UNUSED) == 0) || (op->result.op_type == IS_TMP_VAR)) |
|||
# define RESULT_UNUSED(op) ((op->result.op_type == IS_VAR) && (op->result.u.EA.type == EXT_TYPE_UNUSED)) |
|||
# define SAME_VAR(op1, op2) (((op1.op_type == IS_VAR && op2.op_type == IS_VAR) || (op1.op_type == IS_TMP_VAR && op2.op_type == IS_TMP_VAR)) && op1.u.var == op2.u.var) |
|||
#endif |
|||
|
|||
typedef struct _zend_code_block zend_code_block; |
|||
typedef struct _zend_block_source zend_block_source; |
|||
|
|||
struct _zend_code_block { |
|||
int access; |
|||
zend_op *start_opline; |
|||
int start_opline_no; |
|||
int len; |
|||
zend_code_block *op1_to; |
|||
zend_code_block *op2_to; |
|||
zend_code_block *ext_to; |
|||
zend_code_block *follow_to; |
|||
zend_code_block *next; |
|||
zend_block_source *sources; |
|||
zend_code_block **try; |
|||
zend_code_block **catch; |
|||
zend_bool is_try; |
|||
}; |
|||
|
|||
struct _zend_block_source { |
|||
zend_code_block *from; |
|||
zend_block_source *next; |
|||
}; |
|||
|
|||
#endif |
|||
@ -0,0 +1,171 @@ |
|||
The Zend Optimizer+ |
|||
=================== |
|||
|
|||
The Zend Optimizer+ provides faster PHP execution through opcode caching and |
|||
optimization. It improves PHP performance by storing precompiled script |
|||
bytecode in the shared memory. This eliminates the stages of reading code from |
|||
the disk and compiling it on future access. In addition it applies a few |
|||
bytecode optimization patterns that make code execution faster. |
|||
|
|||
Compatibility |
|||
------------- |
|||
|
|||
This version of Zend Optimizer+ is compatible with PHP 5.2.*, 5.3.*, 5.4.* |
|||
and PHP-5.5 development branch. PHP 5.2 support may be removed in the future. |
|||
|
|||
Quick Install |
|||
------------- |
|||
|
|||
- Compile |
|||
|
|||
export PHP_DIR=/usr/local/php5.5 |
|||
PHP_AUTOCONF=autoconf $PHP_DIR/bin/phpize |
|||
./configure \ |
|||
--enable-optimizer-plus \ |
|||
--with-php-config=$PHP_DIR/bin/php-config |
|||
make |
|||
|
|||
- Install |
|||
|
|||
cp .libs/ZendOptimizerPlus.so $PHP_DIR/lib/ZendOptimizerPlus.so |
|||
|
|||
- Edit php.ini |
|||
|
|||
zend_extensin=/...full path.../ZendOptimizerPlus.so |
|||
|
|||
- Restart PHP |
|||
|
|||
Speed Tunning |
|||
------------- |
|||
|
|||
We reccomend the following configuration options for best performance. |
|||
|
|||
zend_optimizerplus.memory_consumption=128 |
|||
zend_optimizerplus.interned_strings_buffer=8 |
|||
zend_optimizerplus.max_accelerated_files=4000 |
|||
zend_optimizerplus.revalidate_freq=60 |
|||
zend_optimizerplus.save_comments=0 |
|||
zend_optimizerplus.fast_shutdown=1 |
|||
zend_optimizerplus.enable_file_override=1 |
|||
zend_optimizerplus.enable_cli=1 |
|||
|
|||
In some cases you may like to prefer enabling/disabling some features |
|||
to avoid incompatibilities at the cost of some performance degradation. |
|||
|
|||
Configuration Directives |
|||
------------------------ |
|||
|
|||
zend_optimizerplus.enable (default "1") |
|||
Optimizer+ On/Off switch. When set to Off, code is not optimized. |
|||
|
|||
zend_optimizerplus.memory_consumption (default "64") |
|||
The Optimizer+ shared memory storage size. The amount of memory for storing |
|||
precompiled PHP code in Mbytes. |
|||
|
|||
zend_optimizerplus.interned_strings_buffer (default "4") |
|||
The amount of memory for interned strings in Mbytes. |
|||
|
|||
zend_optimizerplus.max_accelerated_files (default "2000") |
|||
The maximum number of keys (scripts) in the Optimizer+ hash table. |
|||
The number is actually the the first one in the following set of prime |
|||
numbers that is bigger than the one supplied: { 223, 463, 983, 1979, 3907, |
|||
7963, 16229, 32531, 65407, 130987 }. Only numbers between 200 and 100000 |
|||
are allowed. |
|||
|
|||
zend_optimizerplus.max_wasted_percentage (default "5") |
|||
The maximum percentage of "wasted" memory until a restart is scheduled |
|||
|
|||
zend_optimizerplus.use_cwd (default "1") |
|||
When this directive is enabled, the Optimizer+ appends the current working |
|||
directory to the script key, thus elminating possible collisions between |
|||
files with the same name (basename). Disablingthe directive improves |
|||
performance, but may break existing applications. |
|||
|
|||
zend_optimizerplus.validate_timestamps (default "1") |
|||
When disabled, you must reset the Optimizer+ manually or restart the |
|||
webserver for changes to the filesystem to take effect. |
|||
The frequancy of the check is controlled by the directive |
|||
"zend_optimizerplus.revalidate_freq" |
|||
|
|||
zend_optimizerplus.revalidate_freq (default "2") |
|||
How often (in seconds) to check file timestamps for changes to the shared |
|||
memory storage allocation. |
|||
|
|||
zend_optimizerplus.revalidate_path (default "0") |
|||
Enables or disables file search in include_path optimization |
|||
If the file search is disabled and a cached file is found that uses |
|||
the same include_path, the file is not searched again. Thus, if a file |
|||
with the same name appears somewhere else in include_path, it |
|||
won't be found. Enable this directive if this optimization has an effect on |
|||
your applications. The default for this directive is disabled, which means |
|||
that optimization is active. |
|||
|
|||
zend_optimizerplus.save_comments (default "1") |
|||
If disabled, all PHPDoc comments are dropped from the code to reduce the |
|||
size of the optimized code. |
|||
|
|||
zend_optimizerplus.fast_shutdown (default "0") |
|||
If enabled, a fast shutdown sequence is used for the accelerated code |
|||
The fast shutdown sequence doesn't free each allocated block, but lets |
|||
the Zend Engine Memory Manager do the work. |
|||
|
|||
zend_optimizerplus.enable_file_override (default "0") |
|||
Allow file existance override (file_exists, etc.) performance feature |
|||
|
|||
zend_optimizerplus.optimization_level (default "0xffffffff") |
|||
A bitmask, where each bit enables or disables the appropriate Optimizer+ |
|||
passes |
|||
|
|||
zend_optimizerplus.inherited_hack (default "1") |
|||
Enable this hack as a workaround for "can't redeclare class" errors. |
|||
The Optimizer+ stores the places where DECLARE_CLASS opcodes use |
|||
inheritance (These are the only opcodes that can be executed by PHP, |
|||
but which may not be executed because the parent class is missing due to |
|||
optimization). When the file is loaded, Optimizer+ tries to bind the |
|||
inherited classes by using the current environment. The problem with this |
|||
scenario is that, while the DECLARE_CLASS opcode may not be needed for the |
|||
current script, if the script requires that the opcode at least be defined, |
|||
it may not run. The default for this directive is disabled, which means |
|||
that optimization is active. In php-5.3 and above this hack is not needed |
|||
anymore and this setting has no effect. |
|||
|
|||
zend_optimizerplus.dups_fix (default "0") |
|||
Enable this hack as a workaround for "duplicate definition" errors |
|||
|
|||
zend_optimizerplus.blacklist_filename |
|||
The location of the Optimizer+ blacklist file |
|||
The Optimizer+ blacklist file is a text file that holds the names of files |
|||
that should not be accelerated. The file format is to add each filename |
|||
to a new line. The filename may be a full path or just a file prefix |
|||
(i.e., /var/www/x blacklists all the files and directories in /var/www |
|||
that start with 'x'). Files are usually triggered by one of the following |
|||
three reasons: |
|||
1) Directories that contain auto generated code, like Smarty or ZFW cache. |
|||
2) Code that does not work well when accelerated, due to some delayed |
|||
compile time evaluation. |
|||
3) Code that triggers an Optimizer+ bug. |
|||
|
|||
zend_optimizerplus.consistency_checks (default "0") |
|||
Check the cache checksum each N requests. |
|||
The default value of "0" means that the checks are disabled. |
|||
Because calculating the checksum impairs performance, this directive should |
|||
be enabled only as part of a debugging process. |
|||
|
|||
zend_optimizerplus.force_restart_timeout (default "180") |
|||
How long to wait (in seconds) for a scheduled restart to begin if the cache |
|||
is not being accessed. |
|||
The Optimizer+ uses this directive to identify a situation where there may |
|||
be a problem with a process. After this time period has passed, the |
|||
Optimizer+ assumes that something has happened and starts killing the |
|||
processes that still hold the locks that are preventing a restart. |
|||
If the log level is 3 or above, a "killed locker" error is recorded |
|||
in the Apache logs when this happens. |
|||
|
|||
zend_optimizerplus.error_log |
|||
Optimizer+ error_log file name. Empty string assumes "stderr" |
|||
|
|||
zend_optimizerplus.log_verbosity_level (default "1") |
|||
Alll Optimizer+ errors go to the Web server log. |
|||
By default, only fatal errors (level 0) or errors (level 1) are logged. |
|||
You can also enable warnings (level 2), info messages (level 3) or |
|||
debug messesges (level 4). |
|||
2510
ZendAccelerator.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,364 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef ZEND_ACCELERATOR_H |
|||
#define ZEND_ACCELERATOR_H |
|||
|
|||
#ifdef HAVE_CONFIG_H |
|||
# include <config.h> |
|||
#endif |
|||
|
|||
#define ACCELERATOR_PRODUCT_NAME "Zend Optimizer+" |
|||
#define ACCELERATOR_VERSION "7.0.0" |
|||
/* 2 - added Profiler support, on 20010712 */ |
|||
/* 3 - added support for Optimizer's encoded-only-files mode */ |
|||
/* 4 - works with the new Optimizer, that supports the file format with licenses */ |
|||
/* 5 - API 4 didn't really work with the license-enabled file format. v5 does. */ |
|||
/* 6 - Monitor was removed from ZendPlatform.so, to a module of its own */ |
|||
/* 7 - Optimizer was embeded into Accelerator */ |
|||
/* 8 - Standalone Open Source OptimizerPlus */ |
|||
#define ACCELERATOR_API_NO 8 |
|||
|
|||
#if ZEND_WIN32 |
|||
# include "zend_config.w32.h" |
|||
#else |
|||
#include "zend_config.h" |
|||
# include <sys/time.h> |
|||
# include <sys/resource.h> |
|||
#endif |
|||
|
|||
#if HAVE_UNISTD_H |
|||
# include "unistd.h" |
|||
#endif |
|||
|
|||
#include "zend_extensions.h" |
|||
#include "zend_compile.h" |
|||
|
|||
#include "Optimizer/zend_optimizer.h" |
|||
#include "zend_accelerator_hash.h" |
|||
#include "zend_accelerator_debug.h" |
|||
|
|||
#ifndef PHPAPI |
|||
# ifdef ZEND_WIN32 |
|||
# define PHPAPI __declspec(dllimport) |
|||
# else |
|||
# define PHPAPI |
|||
# endif |
|||
#endif |
|||
|
|||
#ifndef ZEND_EXT_API |
|||
# if WIN32|WINNT |
|||
# define ZEND_EXT_API __declspec(dllexport) |
|||
# else |
|||
# define ZEND_EXT_API |
|||
# endif |
|||
#endif |
|||
|
|||
#ifdef ZEND_WIN32 |
|||
# ifndef MAXPATHLEN |
|||
# define MAXPATHLEN _MAX_PATH |
|||
# endif |
|||
# include <direct.h> |
|||
#else |
|||
# include <sys/param.h> |
|||
#endif |
|||
|
|||
#define PHP_5_0_X_API_NO 220040412 |
|||
#define PHP_5_1_X_API_NO 220051025 |
|||
#define PHP_5_2_X_API_NO 220060519 |
|||
#define PHP_5_3_X_API_NO 220090626 |
|||
#define PHP_5_4_X_API_NO 220100525 |
|||
|
|||
/*** file locking ***/ |
|||
#ifndef ZEND_WIN32 |
|||
extern int lock_file; |
|||
|
|||
# if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__)/* Darwin */) || defined(__OpenBSD__) || defined(__NetBSD__) |
|||
# define FLOCK_STRUCTURE(name, type, whence, start, len) \ |
|||
struct flock name = {start, len, -1, type, whence} |
|||
# elif defined(__svr4__) |
|||
# define FLOCK_STRUCTURE(name, type, whence, start, len) \ |
|||
struct flock name = {type, whence, start, len} |
|||
# elif defined(__linux__) || defined(__hpux) |
|||
# define FLOCK_STRUCTURE(name, type, whence, start, len) \ |
|||
struct flock name = {type, whence, start, len, 0} |
|||
# elif defined(_AIX) |
|||
# if defined(_LARGE_FILES) || defined(__64BIT__) |
|||
# define FLOCK_STRUCTURE(name, type, whence, start, len) \ |
|||
struct flock name = {type, whence, 0, 0, 0, start, len } |
|||
# else |
|||
# define FLOCK_STRUCTURE(name, type, whence, start, len) \ |
|||
struct flock name = {type, whence, start, len} |
|||
# endif |
|||
# else |
|||
# error "Don't know how to define struct flock" |
|||
# endif |
|||
#endif |
|||
|
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
#define Z_REFCOUNT_P(pz) (pz)->refcount |
|||
#define Z_SET_REFCOUNT_P(pz, v) (pz)->refcount = (v) |
|||
#define Z_ADDREF_P(pz) ++((pz)->refcount) |
|||
#define Z_DELREF_P(pz) --((pz)->refcount) |
|||
#define Z_ISREF_P(pz) (pz)->is_ref |
|||
#define Z_SET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 1) |
|||
#define Z_UNSET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 0) |
|||
#define Z_SET_ISREF_TO_P(pz, isref) (pz)->is_ref = (isref) |
|||
#define PZ_REFCOUNT_P(pz) (pz)->refcount |
|||
#define PZ_SET_REFCOUNT_P(pz, v) (pz)->refcount = (v) |
|||
#define PZ_ADDREF_P(pz) ++((pz)->refcount) |
|||
#define PZ_DELREF_P(pz) --((pz)->refcount) |
|||
#define PZ_ISREF_P(pz) (pz)->is_ref |
|||
#define PZ_SET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 1) |
|||
#define PZ_UNSET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 0) |
|||
#define PZ_SET_ISREF_TO_P(pz, isref) (pz)->is_ref = (isref) |
|||
#else |
|||
#define PZ_REFCOUNT_P(pz) (pz)->refcount__gc |
|||
#define PZ_SET_REFCOUNT_P(pz, v) (pz)->refcount__gc = (v) |
|||
#define PZ_ADDREF_P(pz) ++((pz)->refcount__gc) |
|||
#define PZ_DELREF_P(pz) --((pz)->refcount__gc) |
|||
#define PZ_ISREF_P(pz) (pz)->is_ref__gc |
|||
#define PZ_SET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 1) |
|||
#define PZ_UNSET_ISREF_P(pz) Z_SET_ISREF_TO_P(pz, 0) |
|||
#define PZ_SET_ISREF_TO_P(pz, isref) (pz)->is_ref__gc = (isref) |
|||
#endif |
|||
|
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
# ifdef ALLOCA_FLAG |
|||
#define DO_ALLOCA(x) do_alloca_with_limit(x,use_heap) |
|||
#define FREE_ALLOCA(x) free_alloca_with_limit(x,use_heap) |
|||
# else |
|||
#define ALLOCA_FLAG(x) |
|||
#define DO_ALLOCA(x) do_alloca(x) |
|||
#define FREE_ALLOCA(x) free_alloca(x) |
|||
# endif |
|||
#else |
|||
#define DO_ALLOCA(x) do_alloca(x,use_heap) |
|||
#define FREE_ALLOCA(x) free_alloca(x,use_heap) |
|||
#endif |
|||
|
|||
|
|||
#if ZEND_WIN32 |
|||
typedef unsigned __int64 accel_time_t; |
|||
#else |
|||
typedef time_t accel_time_t; |
|||
#endif |
|||
|
|||
typedef struct _zend_persistent_script { |
|||
ulong hash_value; |
|||
char *full_path; /* full real path with resolved symlinks */ |
|||
int full_path_len; |
|||
zend_op_array main_op_array; |
|||
HashTable function_table; |
|||
HashTable class_table; |
|||
long compiler_halt_offset; /* position of __HALT_COMPILER or -1 */ |
|||
int ping_auto_globals_mask; /* which autoglobals are used by the script */ |
|||
accel_time_t timestamp; /* the script modification time */ |
|||
zend_bool corrupted; |
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
zend_uint early_binding; /* the linked list of delayed declarations */ |
|||
#endif |
|||
|
|||
void *mem; /* shared memory area used by script structures */ |
|||
size_t size; /* size of used shared memory */ |
|||
|
|||
/* All entries that shouldn't be counted in the ADLER32 |
|||
* checksum must be declared in this struct |
|||
*/ |
|||
struct zend_persistent_script_dynamic_members { |
|||
time_t last_used; |
|||
ulong hits; |
|||
unsigned int memory_consumption; |
|||
unsigned int checksum; |
|||
time_t revalidate; |
|||
} dynamic_members; |
|||
} zend_persistent_script; |
|||
|
|||
typedef struct _zend_accel_directives { |
|||
long memory_consumption; |
|||
long max_accelerated_files; |
|||
double max_wasted_percentage; |
|||
char *user_blacklist_filename; |
|||
long consistency_checks; |
|||
long force_restart_timeout; |
|||
zend_bool use_cwd; |
|||
zend_bool ignore_dups; |
|||
zend_bool validate_timestamps; |
|||
zend_bool revalidate_path; |
|||
zend_bool save_comments; |
|||
zend_bool fast_shutdown; |
|||
zend_bool protect_memory; |
|||
zend_bool file_override_enabled; |
|||
zend_bool inherited_hack; |
|||
zend_bool enable_cli; |
|||
unsigned long revalidate_freq; |
|||
char *error_log; |
|||
#ifdef ZEND_WIN32 |
|||
char *mmap_base; |
|||
#endif |
|||
char *memory_model; |
|||
long log_verbosity_level; |
|||
|
|||
long optimization_level; |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
long interned_strings_buffer; |
|||
#endif |
|||
} zend_accel_directives; |
|||
|
|||
typedef struct _zend_accel_globals { |
|||
/* copy of CG(function_table) used for compilation scripts into cashe */ |
|||
/* imitially it contains only internal functions */ |
|||
HashTable function_table; |
|||
int internal_functions_count; |
|||
int counted; /* the process uses shatred memory */ |
|||
zend_bool enabled; |
|||
HashTable bind_hash; /* prototype and zval lookup table */ |
|||
zend_accel_directives accel_directives; |
|||
char *cwd; /* current working directory or NULL */ |
|||
int cwd_len; /* "cwd" string lenght */ |
|||
char *include_path_key; /* one letter key of current "include_path" */ |
|||
char *include_path; /* current settion of "include_path" directive */ |
|||
int include_path_len; /* "include_path" string lenght */ |
|||
int include_path_check; |
|||
time_t request_time; |
|||
zend_bool startup_ok; |
|||
/* preallocated shared-memory block to save current script */ |
|||
void *mem; |
|||
/* cache to save hash lookup on the same INCLUDE opcode */ |
|||
zend_op *cache_opline; |
|||
zend_persistent_script *cache_persistent_script; |
|||
/* preallocated buffer for keys */ |
|||
int key_len; |
|||
char key[MAXPATHLEN * 8]; |
|||
} zend_accel_globals; |
|||
|
|||
typedef struct _zend_accel_shared_globals { |
|||
/* Cache Data Structures */ |
|||
unsigned long hits; |
|||
unsigned long misses; |
|||
unsigned long blacklist_misses; |
|||
zend_accel_hash hash; /* hash table for cached scripts */ |
|||
zend_accel_hash include_paths; /* used "include_path" values */ |
|||
|
|||
/* Directives & Maintenance */ |
|||
time_t last_restart_time; |
|||
time_t force_restart_time; |
|||
zend_bool accelerator_enabled; |
|||
zend_bool restart_pending; |
|||
zend_bool cache_status_before_restart; |
|||
#ifdef ZEND_WIN32 |
|||
unsigned long mem_usage; |
|||
unsigned long restart_in; |
|||
#endif |
|||
zend_bool restart_in_progress; |
|||
time_t revalidate_at; |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
/* Interned Strings Support */ |
|||
char *interned_strings_start; |
|||
char *interned_strings_top; |
|||
char *interned_strings_end; |
|||
HashTable interned_strings; |
|||
struct { |
|||
Bucket **arBuckets; |
|||
Bucket *pListHead; |
|||
Bucket *pListTail; |
|||
char *top; |
|||
} interned_strings_saved_state; |
|||
#endif |
|||
} zend_accel_shared_globals; |
|||
|
|||
extern zend_accel_shared_globals *accel_shared_globals; |
|||
#define ZCSG(element) (accel_shared_globals->element) |
|||
|
|||
#ifdef ZTS |
|||
# define ZCG(v) TSRMG(accel_globals_id, zend_accel_globals *, v) |
|||
extern int accel_globals_id; |
|||
#else |
|||
# define ZCG(v) (accel_globals.v) |
|||
extern zend_accel_globals accel_globals; |
|||
#endif |
|||
|
|||
extern char *zps_api_failure_reason; |
|||
|
|||
void zend_accel_schedule_restart(TSRMLS_D); |
|||
int accelerator_shm_read_lock(TSRMLS_D); |
|||
void accelerator_shm_read_unlock(TSRMLS_D); |
|||
|
|||
char *accel_make_persistent_key_ex(zend_file_handle *file_handle, int path_length, int *key_len TSRMLS_DC); |
|||
|
|||
#if !defined(ZEND_DECLARE_INHERITED_CLASS_DELAYED) |
|||
# define ZEND_DECLARE_INHERITED_CLASS_DELAYED 145 |
|||
#endif |
|||
|
|||
#define ZEND_DECLARE_INHERITED_CLASS_DELAYED_FLAG 0x80 |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
|
|||
const char *accel_new_interned_string(const char *arKey, int nKeyLength, int free_src TSRMLS_DC); |
|||
|
|||
# define interned_free(s) do { \ |
|||
if (!IS_INTERNED(s)) { \ |
|||
free(s); \ |
|||
} \ |
|||
} while (0) |
|||
# define interned_efree(s) do { \ |
|||
if (!IS_INTERNED(s)) { \ |
|||
efree(s); \ |
|||
} \ |
|||
} while (0) |
|||
# define interned_estrndup(s, n) \ |
|||
(IS_INTERNED(s) ? (s) : estrndup(s, n)) |
|||
# define ZEND_RESULT_TYPE(opline) (opline)->result_type |
|||
# define ZEND_RESULT(opline) (opline)->result |
|||
# define ZEND_OP1_TYPE(opline) (opline)->op1_type |
|||
# define ZEND_OP1(opline) (opline)->op1 |
|||
# define ZEND_OP1_CONST(opline) (*(opline)->op1.zv) |
|||
# define ZEND_OP1_LITERAL(opline) (op_array)->literals[(opline)->op1.constant].constant |
|||
# define ZEND_OP2_TYPE(opline) (opline)->op2_type |
|||
# define ZEND_OP2(opline) (opline)->op2 |
|||
# define ZEND_OP2_CONST(opline) (*(opline)->op2.zv) |
|||
# define ZEND_OP2_LITERAL(opline) (op_array)->literals[(opline)->op2.constant].constant |
|||
# define ZEND_DONE_PASS_TWO(op_array) (((op_array)->fn_flags & ZEND_ACC_DONE_PASS_TWO) != 0) |
|||
# define ZEND_CE_FILENAME(ce) (ce)->info.user.filename |
|||
# define ZEND_CE_DOC_COMMENT(ce) (ce)->info.user.doc_comment |
|||
# define ZEND_CE_DOC_COMMENT_LEN(ce) (ce)->info.user.doc_comment_len |
|||
#else |
|||
# define IS_INTERNED(s) 0 |
|||
# define interned_free(s) free(s) |
|||
# define interned_efree(s) efree(s) |
|||
# define interned_estrndup(s, n) estrndup(s, n) |
|||
# define ZEND_RESULT_TYPE(opline) (opline)->result.op_type |
|||
# define ZEND_RESULT(opline) (opline)->result.u |
|||
# define ZEND_OP1_TYPE(opline) (opline)->op1.op_type |
|||
# define ZEND_OP1(opline) (opline)->op1.u |
|||
# define ZEND_OP1_CONST(opline) (opline)->op1.u.constant |
|||
# define ZEND_OP1_LITERAL(opline) (opline)->op1.u.constant |
|||
# define ZEND_OP2_TYPE(opline) (opline)->op2.op_type |
|||
# define ZEND_OP2(opline) (opline)->op2.u |
|||
# define ZEND_OP2_CONST(opline) (opline)->op2.u.constant |
|||
# define ZEND_OP2_LITERAL(opline) (opline)->op2.u.constant |
|||
# define ZEND_DONE_PASS_TWO(op_array) ((op_array)->done_pass_two != 0) |
|||
# define ZEND_CE_FILENAME(ce) (ce)->filename |
|||
# define ZEND_CE_DOC_COMMENT(ce) (ce)->doc_comment |
|||
# define ZEND_CE_DOC_COMMENT_LEN(ce) (ce)->doc_comment_len |
|||
#endif |
|||
|
|||
#endif /* ZEND_ACCELERATOR_H */ |
|||
@ -0,0 +1,345 @@ |
|||
dnl |
|||
dnl $Id$ |
|||
dnl |
|||
|
|||
PHP_ARG_ENABLE(optimizer-plus, whether to enable Zend OptimizerPlus support, |
|||
[ --enable-optimizer-plus Enable Zend OptimizerPlus support]) |
|||
|
|||
if test "$PHP_OPTIMIZER_PLUS" != "no"; then |
|||
AC_DEFINE(HAVE_OPTIMIZER_PLUS, 1, [ ]) |
|||
|
|||
AC_CHECK_FUNC(mprotect,[ |
|||
AC_DEFINE(HAVE_MPROTECT, 1, [Define if you have mprotect() function]) |
|||
]) |
|||
|
|||
AC_MSG_CHECKING(for sysvipc shared memory support) |
|||
AC_TRY_RUN([ |
|||
#include <sys/types.h> |
|||
#include <sys/wait.h> |
|||
#include <sys/ipc.h> |
|||
#include <sys/shm.h> |
|||
#include <unistd.h> |
|||
#include <string.h> |
|||
|
|||
int main() { |
|||
pid_t pid; |
|||
int status; |
|||
int ipc_id; |
|||
char *shm; |
|||
struct shmid_ds shmbuf; |
|||
|
|||
ipc_id = shmget(IPC_PRIVATE, 4096, (IPC_CREAT | SHM_R | SHM_W)); |
|||
if (ipc_id == -1) { |
|||
return 1; |
|||
} |
|||
|
|||
shm = shmat(ipc_id, NULL, 0); |
|||
if (shm == (void *)-1) { |
|||
shmctl(ipc_id, IPC_RMID, NULL); |
|||
return 2; |
|||
} |
|||
|
|||
if (shmctl(ipc_id, IPC_STAT, &shmbuf) != 0) { |
|||
shmdt(shm); |
|||
shmctl(ipc_id, IPC_RMID, NULL); |
|||
return 3; |
|||
} |
|||
|
|||
shmbuf.shm_perm.uid = getuid(); |
|||
shmbuf.shm_perm.gid = getgid(); |
|||
shmbuf.shm_perm.mode = 0600; |
|||
|
|||
if (shmctl(ipc_id, IPC_SET, &shmbuf) != 0) { |
|||
shmdt(shm); |
|||
shmctl(ipc_id, IPC_RMID, NULL); |
|||
return 4; |
|||
} |
|||
|
|||
shmctl(ipc_id, IPC_RMID, NULL); |
|||
|
|||
strcpy(shm, "hello"); |
|||
|
|||
pid = fork(); |
|||
if (pid < 0) { |
|||
return 5; |
|||
} else if (pid == 0) { |
|||
strcpy(shm, "bye"); |
|||
return 6; |
|||
} |
|||
if (wait(&status) != pid) { |
|||
return 7; |
|||
} |
|||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { |
|||
return 8; |
|||
} |
|||
if (strcmp(shm, "bye") != 0) { |
|||
return 9; |
|||
} |
|||
return 0; |
|||
} |
|||
],dnl |
|||
AC_DEFINE(HAVE_SHM_IPC, 1, [Define if you have SysV IPC SHM support]) |
|||
msg=yes,msg=no,msg=no) |
|||
AC_MSG_RESULT([$msg]) |
|||
|
|||
AC_MSG_CHECKING(for mmap() using MAP_ANON shared memory support) |
|||
AC_TRY_RUN([ |
|||
#include <sys/types.h> |
|||
#include <sys/wait.h> |
|||
#include <sys/mman.h> |
|||
#include <unistd.h> |
|||
#include <string.h> |
|||
|
|||
#ifndef MAP_ANON |
|||
# ifdef MAP_ANONYMOUS |
|||
# define MAP_ANON MAP_ANONYMOUS |
|||
# endif |
|||
#endif |
|||
#ifndef MAP_FAILED |
|||
# define MAP_FAILED ((void*)-1) |
|||
#endif |
|||
|
|||
int main() { |
|||
pid_t pid; |
|||
int status; |
|||
char *shm; |
|||
|
|||
shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); |
|||
if (shm == MAP_FAILED) { |
|||
return 1; |
|||
} |
|||
|
|||
strcpy(shm, "hello"); |
|||
|
|||
pid = fork(); |
|||
if (pid < 0) { |
|||
return 5; |
|||
} else if (pid == 0) { |
|||
strcpy(shm, "bye"); |
|||
return 6; |
|||
} |
|||
if (wait(&status) != pid) { |
|||
return 7; |
|||
} |
|||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { |
|||
return 8; |
|||
} |
|||
if (strcmp(shm, "bye") != 0) { |
|||
return 9; |
|||
} |
|||
return 0; |
|||
} |
|||
],dnl |
|||
AC_DEFINE(HAVE_SHM_MMAP_ANON, 1, [Define if you have mmap(MAP_ANON) SHM support]) |
|||
msg=yes,msg=no,msg=no) |
|||
AC_MSG_RESULT([$msg]) |
|||
|
|||
AC_MSG_CHECKING(for mmap() using /dev/zero shared memory support) |
|||
AC_TRY_RUN([ |
|||
#include <sys/types.h> |
|||
#include <sys/wait.h> |
|||
#include <sys/mman.h> |
|||
#include <sys/stat.h> |
|||
#include <fcntl.h> |
|||
#include <unistd.h> |
|||
#include <string.h> |
|||
|
|||
#ifndef MAP_FAILED |
|||
# define MAP_FAILED ((void*)-1) |
|||
#endif |
|||
|
|||
int main() { |
|||
pid_t pid; |
|||
int status; |
|||
int fd; |
|||
char *shm; |
|||
|
|||
fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR); |
|||
if (fd == -1) { |
|||
return 1; |
|||
} |
|||
|
|||
shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
|||
if (shm == MAP_FAILED) { |
|||
return 2; |
|||
} |
|||
|
|||
strcpy(shm, "hello"); |
|||
|
|||
pid = fork(); |
|||
if (pid < 0) { |
|||
return 5; |
|||
} else if (pid == 0) { |
|||
strcpy(shm, "bye"); |
|||
return 6; |
|||
} |
|||
if (wait(&status) != pid) { |
|||
return 7; |
|||
} |
|||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { |
|||
return 8; |
|||
} |
|||
if (strcmp(shm, "bye") != 0) { |
|||
return 9; |
|||
} |
|||
return 0; |
|||
} |
|||
],dnl |
|||
AC_DEFINE(HAVE_SHM_MMAP_ZERO, 1, [Define if you have mmap("/dev/zero") SHM support]) |
|||
msg=yes,msg=no,msg=no) |
|||
AC_MSG_RESULT([$msg]) |
|||
|
|||
AC_MSG_CHECKING(for mmap() using shm_open() shared memory support) |
|||
AC_TRY_RUN([ |
|||
#include <sys/types.h> |
|||
#include <sys/wait.h> |
|||
#include <sys/mman.h> |
|||
#include <sys/stat.h> |
|||
#include <fcntl.h> |
|||
#include <unistd.h> |
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
|
|||
#ifndef MAP_FAILED |
|||
# define MAP_FAILED ((void*)-1) |
|||
#endif |
|||
|
|||
int main() { |
|||
pid_t pid; |
|||
int status; |
|||
int fd; |
|||
char *shm; |
|||
char tmpname[4096]; |
|||
|
|||
sprintf(tmpname,"test.shm.%dXXXXXX", getpid()); |
|||
if (mktemp(tmpname) == NULL) { |
|||
return 1; |
|||
} |
|||
fd = shm_open(tmpname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); |
|||
if (fd == -1) { |
|||
return 2; |
|||
} |
|||
if (ftruncate(fd, 4096) < 0) { |
|||
close(fd); |
|||
shm_unlink(tmpname); |
|||
return 3; |
|||
} |
|||
|
|||
shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
|||
if (shm == MAP_FAILED) { |
|||
return 4; |
|||
} |
|||
shm_unlink(tmpname); |
|||
close(fd); |
|||
|
|||
strcpy(shm, "hello"); |
|||
|
|||
pid = fork(); |
|||
if (pid < 0) { |
|||
return 5; |
|||
} else if (pid == 0) { |
|||
strcpy(shm, "bye"); |
|||
return 6; |
|||
} |
|||
if (wait(&status) != pid) { |
|||
return 7; |
|||
} |
|||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { |
|||
return 8; |
|||
} |
|||
if (strcmp(shm, "bye") != 0) { |
|||
return 9; |
|||
} |
|||
return 0; |
|||
} |
|||
],dnl |
|||
AC_DEFINE(HAVE_SHM_MMAP_POSIX, 1, [Define if you have POSIX mmap() SHM support]) |
|||
msg=yes,msg=no,msg=no) |
|||
AC_MSG_RESULT([$msg]) |
|||
|
|||
AC_MSG_CHECKING(for mmap() using regular file shared memory support) |
|||
AC_TRY_RUN([ |
|||
#include <sys/types.h> |
|||
#include <sys/wait.h> |
|||
#include <sys/mman.h> |
|||
#include <sys/stat.h> |
|||
#include <fcntl.h> |
|||
#include <unistd.h> |
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
|
|||
#ifndef MAP_FAILED |
|||
# define MAP_FAILED ((void*)-1) |
|||
#endif |
|||
|
|||
int main() { |
|||
pid_t pid; |
|||
int status; |
|||
int fd; |
|||
char *shm; |
|||
char tmpname[4096]; |
|||
|
|||
sprintf(tmpname,"test.shm.%dXXXXXX", getpid()); |
|||
if (mktemp(tmpname) == NULL) { |
|||
return 1; |
|||
} |
|||
fd = open(tmpname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); |
|||
if (fd == -1) { |
|||
return 2; |
|||
} |
|||
if (ftruncate(fd, 4096) < 0) { |
|||
close(fd); |
|||
unlink(tmpname); |
|||
return 3; |
|||
} |
|||
|
|||
shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
|||
if (shm == MAP_FAILED) { |
|||
return 4; |
|||
} |
|||
unlink(tmpname); |
|||
close(fd); |
|||
|
|||
strcpy(shm, "hello"); |
|||
|
|||
pid = fork(); |
|||
if (pid < 0) { |
|||
return 5; |
|||
} else if (pid == 0) { |
|||
strcpy(shm, "bye"); |
|||
return 6; |
|||
} |
|||
if (wait(&status) != pid) { |
|||
return 7; |
|||
} |
|||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 6) { |
|||
return 8; |
|||
} |
|||
if (strcmp(shm, "bye") != 0) { |
|||
return 9; |
|||
} |
|||
return 0; |
|||
} |
|||
],dnl |
|||
AC_DEFINE(HAVE_SHM_MMAP_FILE, 1, [Define if you have mmap() SHM support]) |
|||
msg=yes,msg=no,msg=no) |
|||
AC_MSG_RESULT([$msg]) |
|||
|
|||
PHP_NEW_EXTENSION(ZendOptimizerPlus, |
|||
ZendAccelerator.c \ |
|||
zend_accelerator_blacklist.c \ |
|||
zend_accelerator_debug.c \ |
|||
zend_accelerator_hash.c \ |
|||
zend_accelerator_module.c \ |
|||
zend_persist.c \ |
|||
zend_persist_calc.c \ |
|||
zend_shared_alloc.c \ |
|||
zend_accelerator_util_funcs.c \ |
|||
shared_alloc_shm.c \ |
|||
shared_alloc_mmap.c \ |
|||
shared_alloc_posix.c \ |
|||
Optimizer/zend_optimizer.c, |
|||
$ext_shared) |
|||
fi |
|||
@ -0,0 +1,28 @@ |
|||
ARG_ENABLE("optimizer-plus", "whether to enable Zend OptimizerPlus support", "yes"); |
|||
|
|||
if (PHP_OPTIMIZER_PLUS != "no") { |
|||
|
|||
PHP_PGI = "no"; // workaround |
|||
PHP_PGO = "no"; // workaround |
|||
|
|||
EXTENSION('ZendOptimizerPlus', "\ |
|||
ZendAccelerator.c \ |
|||
zend_accelerator_blacklist.c \ |
|||
zend_accelerator_debug.c \ |
|||
zend_accelerator_hash.c \ |
|||
zend_accelerator_module.c \ |
|||
zend_accelerator_util_funcs.c \ |
|||
zend_persist.c \ |
|||
zend_persist_calc.c \ |
|||
zend_shared_alloc.c \ |
|||
shared_alloc_win32.c", true); |
|||
|
|||
ADD_SOURCES("Optimizer", "zend_optimizer.c", "ZendOptimizerPlus", "OptimizerObj"); |
|||
|
|||
|
|||
ADD_FLAG('CFLAGS_ZENDOPTIMIZERPLUS', "/I ."); |
|||
ADD_FLAG('CFLAGS_ZENDOPTIMIZERPLUS', "/D HAVE_OPTIMIZER_PLUS=1"); |
|||
|
|||
ADD_FLAG('CFLAGS_ZENDOPTIMIZERPLUS', "/Dregexec=php_regexec /Dregerror=php_regerror /Dregfree=php_regfree /Dregcomp=php_regcomp /Iext/ereg/regex"); |
|||
|
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <sys/mman.h> |
|||
|
|||
#include "zend_shared_alloc.h" |
|||
|
|||
#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) |
|||
# define MAP_ANONYMOUS MAP_ANON |
|||
#endif |
|||
|
|||
static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in) |
|||
{ |
|||
zend_shared_segment *shared_segment; |
|||
|
|||
*shared_segments_count = 1; |
|||
*shared_segments_p = (zend_shared_segment **) calloc(1, sizeof(zend_shared_segment)+sizeof(void *)); |
|||
shared_segment = (zend_shared_segment *)((char *)(*shared_segments_p) + sizeof(void *)); |
|||
(*shared_segments_p)[0] = shared_segment; |
|||
|
|||
shared_segment->p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); |
|||
if(shared_segment->p == MAP_FAILED) { |
|||
*error_in = "mmap"; |
|||
return ALLOC_FAILURE; |
|||
} |
|||
|
|||
shared_segment->pos = 0; |
|||
shared_segment->size = requested_size; |
|||
|
|||
return ALLOC_SUCCESS; |
|||
} |
|||
|
|||
static int detach_segment(zend_shared_segment *shared_segment) |
|||
{ |
|||
munmap(shared_segment->p, shared_segment->size); |
|||
return 0; |
|||
} |
|||
|
|||
static size_t segment_type_size(void) |
|||
{ |
|||
return sizeof(zend_shared_segment); |
|||
} |
|||
|
|||
zend_shared_memory_handlers zend_alloc_mmap_handlers = { |
|||
create_segments, |
|||
detach_segment, |
|||
segment_type_size |
|||
}; |
|||
@ -0,0 +1,90 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <stdio.h> |
|||
#include <fcntl.h> |
|||
#include <sys/mman.h> |
|||
#include <unistd.h> |
|||
#include <stdlib.h> |
|||
|
|||
#include "zend_shared_alloc.h" |
|||
|
|||
typedef struct { |
|||
zend_shared_segment common; |
|||
int shm_fd; |
|||
} zend_shared_segment_posix; |
|||
|
|||
static int create_segments(size_t requested_size, zend_shared_segment_posix ***shared_segments_p, int *shared_segments_count, char **error_in) |
|||
{ |
|||
zend_shared_segment_posix *shared_segment; |
|||
char shared_segment_name[sizeof("/ZendAccelerator.")+20]; |
|||
|
|||
*shared_segments_count = 1; |
|||
*shared_segments_p = (zend_shared_segment_posix **) calloc(1, sizeof(zend_shared_segment_posix)+sizeof(void *)); |
|||
shared_segment = (zend_shared_segment_posix *)((char *)(*shared_segments_p) + sizeof(void *)); |
|||
(*shared_segments_p)[0] = shared_segment; |
|||
|
|||
sprintf(shared_segment_name, "/ZendAccelerator.%d", getpid()); |
|||
shared_segment->shm_fd = shm_open(shared_segment_name, O_RDWR|O_CREAT|O_TRUNC, 0600); |
|||
if(shared_segment->shm_fd == -1) { |
|||
*error_in = "shm_open"; |
|||
return ALLOC_FAILURE; |
|||
} |
|||
|
|||
if(ftruncate(shared_segment->shm_fd, requested_size) != 0) { |
|||
*error_in = "ftruncate"; |
|||
shm_unlink(shared_segment_name); |
|||
return ALLOC_FAILURE; |
|||
} |
|||
|
|||
shared_segment->common.p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED, shared_segment->shm_fd, 0); |
|||
if(shared_segment->common.p == MAP_FAILED) { |
|||
*error_in = "mmap"; |
|||
shm_unlink(shared_segment_name); |
|||
return ALLOC_FAILURE; |
|||
} |
|||
shm_unlink(shared_segment_name); |
|||
|
|||
shared_segment->common.pos = 0; |
|||
shared_segment->common.size = requested_size; |
|||
|
|||
return ALLOC_SUCCESS; |
|||
} |
|||
|
|||
static int detach_segment(zend_shared_segment_posix *shared_segment) |
|||
{ |
|||
munmap(shared_segment->common.p, shared_segment->common.size); |
|||
close(shared_segment->shm_fd); |
|||
return 0; |
|||
} |
|||
|
|||
static size_t segment_type_size(void) |
|||
{ |
|||
return sizeof(zend_shared_segment_posix); |
|||
} |
|||
|
|||
zend_shared_memory_handlers zend_alloc_posix_handlers = { |
|||
(create_segments_t)create_segments, |
|||
(detach_segment_t)detach_segment, |
|||
segment_type_size |
|||
}; |
|||
@ -0,0 +1,137 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#if defined(__FreeBSD__) |
|||
# include <machine/param.h> |
|||
#endif |
|||
#include <sys/types.h> |
|||
#include <sys/shm.h> |
|||
#include <sys/ipc.h> |
|||
#include <dirent.h> |
|||
#include <signal.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <unistd.h> |
|||
#include <errno.h> |
|||
|
|||
#include <sys/stat.h> |
|||
#include <fcntl.h> |
|||
|
|||
#include "zend_shared_alloc.h" |
|||
|
|||
#ifndef MIN |
|||
# define MIN(x, y) ((x) > (y)? (y) : (x)) |
|||
#endif |
|||
|
|||
#define SEG_ALLOC_SIZE_MAX 32*1024*1024 |
|||
#define SEG_ALLOC_SIZE_MIN 2*1024*1024 |
|||
|
|||
typedef struct { |
|||
zend_shared_segment common; |
|||
int shm_id; |
|||
} zend_shared_segment_shm; |
|||
|
|||
static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, char **error_in) |
|||
{ |
|||
int i; |
|||
unsigned int allocate_size=0, remaining_bytes=requested_size, seg_allocate_size; |
|||
int first_segment_id=-1; |
|||
key_t first_segment_key = -1; |
|||
struct shmid_ds sds; |
|||
int shmget_flags; |
|||
zend_shared_segment_shm *shared_segments; |
|||
|
|||
seg_allocate_size = SEG_ALLOC_SIZE_MAX; |
|||
/* determine segment size we _really_ need: |
|||
* no more than to include requested_size |
|||
*/ |
|||
while (requested_size*2 <= seg_allocate_size && seg_allocate_size > SEG_ALLOC_SIZE_MIN) { |
|||
seg_allocate_size >>= 1; |
|||
} |
|||
|
|||
shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL; |
|||
|
|||
/* try allocating this much, if not - try shrinking */ |
|||
while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) { |
|||
allocate_size = MIN(requested_size, seg_allocate_size); |
|||
first_segment_id = shmget(first_segment_key, allocate_size, shmget_flags); |
|||
if (first_segment_id != -1) { |
|||
break; |
|||
} |
|||
seg_allocate_size >>= 1; /* shrink the allocated block */ |
|||
} |
|||
|
|||
if (first_segment_id == -1) { |
|||
*error_in = "shmget"; |
|||
return ALLOC_FAILURE; |
|||
} |
|||
|
|||
*shared_segments_count = ((requested_size-1)/seg_allocate_size) + 1; |
|||
*shared_segments_p = (zend_shared_segment_shm **) calloc(1, (*shared_segments_count)*sizeof(zend_shared_segment_shm)+sizeof(void *)*(*shared_segments_count)); |
|||
shared_segments = (zend_shared_segment_shm *)((char *)(*shared_segments_p) + sizeof(void *)*(*shared_segments_count)); |
|||
for(i=0; i<*shared_segments_count; i++) { |
|||
(*shared_segments_p)[i] = shared_segments+i; |
|||
} |
|||
|
|||
remaining_bytes = requested_size; |
|||
for (i=0; i<*shared_segments_count; i++) { |
|||
allocate_size = MIN(remaining_bytes, seg_allocate_size); |
|||
if (i != 0) { |
|||
shared_segments[i].shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags); |
|||
} else { |
|||
shared_segments[i].shm_id = first_segment_id; |
|||
} |
|||
|
|||
if (shared_segments[i].shm_id==-1) { |
|||
return ALLOC_FAILURE; |
|||
} |
|||
|
|||
shared_segments[i].common.p = shmat(shared_segments[i].shm_id, NULL, 0); |
|||
if (((int) shared_segments[i].common.p) == -1) { |
|||
*error_in = "shmat"; |
|||
shmctl(shared_segments[i].shm_id, IPC_RMID, &sds); |
|||
return ALLOC_FAILURE; |
|||
} |
|||
shmctl(shared_segments[i].shm_id, IPC_RMID, &sds); |
|||
|
|||
shared_segments[i].common.pos = 0; |
|||
shared_segments[i].common.size = allocate_size; |
|||
remaining_bytes -= allocate_size; |
|||
} |
|||
return ALLOC_SUCCESS; |
|||
} |
|||
|
|||
static int detach_segment(zend_shared_segment_shm *shared_segment) |
|||
{ |
|||
shmdt(shared_segment->common.p); |
|||
return 0; |
|||
} |
|||
|
|||
static size_t segment_type_size(void) |
|||
{ |
|||
return sizeof(zend_shared_segment_shm); |
|||
} |
|||
|
|||
zend_shared_memory_handlers zend_alloc_shm_handlers = { |
|||
(create_segments_t)create_segments, |
|||
(detach_segment_t)detach_segment, |
|||
segment_type_size |
|||
}; |
|||
@ -0,0 +1,315 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include "ZendAccelerator.h" |
|||
#include "zend_shared_alloc.h" |
|||
#include "zend_accelerator_util_funcs.h" |
|||
#include <winbase.h> |
|||
#include <process.h> |
|||
#include <LMCONS.H> |
|||
|
|||
#define ACCEL_FILEMAP_NAME "ZendOptimizer+.SharedMemoryArea" |
|||
#define ACCEL_MUTEX_NAME "ZendOptimizer+.SharedMemoryMutex" |
|||
#define ACCEL_FILEMAP_BASE_DEFAULT 0x01000000 |
|||
#define ACCEL_FILEMAP_BASE "ZendOptimizer+.MemoryBase" |
|||
#define ACCEL_EVENT_SOURCE "Zend Optimizer+" |
|||
|
|||
static HANDLE memfile = NULL, memory_mutex = NULL; |
|||
static void *mapping_base; |
|||
|
|||
#define MAX_MAP_RETRIES 25 |
|||
|
|||
static void zend_win_error_message(int type, char *msg, int err) |
|||
{ |
|||
LPVOID lpMsgBuf; |
|||
FILE *fp; |
|||
HANDLE h; |
|||
char *ev_msgs[2]; |
|||
|
|||
FormatMessage( |
|||
FORMAT_MESSAGE_ALLOCATE_BUFFER | |
|||
FORMAT_MESSAGE_FROM_SYSTEM | |
|||
FORMAT_MESSAGE_IGNORE_INSERTS, |
|||
NULL, |
|||
err, |
|||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language |
|||
(LPTSTR) &lpMsgBuf, |
|||
0, |
|||
NULL |
|||
); |
|||
|
|||
h = RegisterEventSource(NULL, TEXT(ACCEL_EVENT_SOURCE)); |
|||
ev_msgs[0] = msg; |
|||
ev_msgs[1] = lpMsgBuf; |
|||
ReportEvent(h, // event log handle |
|||
EVENTLOG_ERROR_TYPE, // event type |
|||
0, // category zero |
|||
err, // event identifier |
|||
NULL, // no user security identifier |
|||
2, // one substitution string |
|||
0, // no data |
|||
ev_msgs, // pointer to string array |
|||
NULL); // pointer to data |
|||
DeregisterEventSource(h); |
|||
|
|||
LocalFree( lpMsgBuf ); |
|||
|
|||
zend_accel_error(type, msg); |
|||
} |
|||
|
|||
static char *create_name_with_username(char *name) |
|||
{ |
|||
static char newname[MAXPATHLEN+UNLEN+4]; |
|||
char uname[UNLEN+1]; |
|||
DWORD unsize = UNLEN; |
|||
|
|||
GetUserName(uname, &unsize); |
|||
snprintf(newname, sizeof(newname)-1, "%s@%s", name, uname); |
|||
return newname; |
|||
} |
|||
|
|||
static char *get_mmap_base_file() |
|||
{ |
|||
static char windir[MAXPATHLEN+UNLEN+3+sizeof("\\\\@")]; |
|||
char uname[UNLEN+1]; |
|||
DWORD unsize = UNLEN; |
|||
int l; |
|||
|
|||
GetTempPath(MAXPATHLEN, windir); |
|||
GetUserName(uname, &unsize); |
|||
l = strlen(windir); |
|||
snprintf(windir+l, sizeof(windir)-l-1, "\\%s@%s", ACCEL_FILEMAP_BASE, uname); |
|||
return windir; |
|||
} |
|||
|
|||
void zend_shared_alloc_create_lock(void) |
|||
{ |
|||
memory_mutex = CreateMutex(NULL, FALSE, create_name_with_username(ACCEL_MUTEX_NAME)); |
|||
ReleaseMutex(memory_mutex); |
|||
} |
|||
|
|||
void zend_shared_alloc_lock_win32() |
|||
{ |
|||
DWORD waitRes = WaitForSingleObject(memory_mutex, INFINITE); |
|||
|
|||
if(waitRes == WAIT_FAILED) { |
|||
zend_accel_error(ACCEL_LOG_ERROR, "Cannot lock mutex"); |
|||
} |
|||
} |
|||
|
|||
void zend_shared_alloc_unlock_win32(TSRMLS_D) |
|||
{ |
|||
ReleaseMutex(memory_mutex); |
|||
} |
|||
|
|||
static int zend_shared_alloc_reattach(size_t requested_size, char **error_in) |
|||
{ |
|||
int err; |
|||
void *wanted_mapping_base; |
|||
char *mmap_base_file = get_mmap_base_file(); |
|||
FILE *fp = fopen(mmap_base_file, "r"); |
|||
MEMORY_BASIC_INFORMATION info; |
|||
|
|||
err = GetLastError(); |
|||
if(!fp) { |
|||
zend_win_error_message(ACCEL_LOG_WARNING, mmap_base_file, err); |
|||
zend_win_error_message(ACCEL_LOG_FATAL, "Unable to open base address file", err); |
|||
*error_in="fopen"; |
|||
return ALLOC_FAILURE; |
|||
} |
|||
if(!fscanf(fp, "%p", &wanted_mapping_base)) { |
|||
err = GetLastError(); |
|||
zend_win_error_message(ACCEL_LOG_FATAL, "Unable to read base address", err); |
|||
*error_in="read mapping base"; |
|||
return ALLOC_FAILURE; |
|||
} |
|||
fclose(fp); |
|||
|
|||
/* Check if the requested address space is free */ |
|||
if (VirtualQuery(wanted_mapping_base, &info, sizeof(info)) == 0 || |
|||
info.State != MEM_FREE || |
|||
info.RegionSize < requested_size) { |
|||
err = ERROR_INVALID_ADDRESS; |
|||
zend_win_error_message(ACCEL_LOG_FATAL, "Unable to reattach to base address", err); |
|||
return ALLOC_FAILURE; |
|||
} |
|||
|
|||
mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, wanted_mapping_base); |
|||
err = GetLastError(); |
|||
|
|||
if(mapping_base == NULL) { |
|||
if (err == ERROR_INVALID_ADDRESS) { |
|||
zend_win_error_message(ACCEL_LOG_FATAL, "Unable to reattach to base address", err); |
|||
return ALLOC_FAILURE; |
|||
} |
|||
return ALLOC_FAIL_MAPPING; |
|||
} |
|||
smm_shared_globals = (zend_smm_shared_globals *) (((char *) mapping_base) + sizeof(zend_shared_memory_block_header)); |
|||
|
|||
return SUCCESSFULLY_REATTACHED; |
|||
} |
|||
|
|||
static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in) |
|||
{ |
|||
int err, ret; |
|||
zend_shared_segment *shared_segment; |
|||
int map_retries = 0; |
|||
void *default_mapping_base_set[] = { 0, 0 }; |
|||
void *vista_mapping_base_set[] = { (void *)0x20000000, (void *)0x21000000, (void *)0x30000000, (void *)0x31000000, (void *)0x50000000, 0 }; |
|||
void **wanted_mapping_base = default_mapping_base_set; |
|||
TSRMLS_FETCH(); |
|||
|
|||
/* Mapping retries: When Apache2 restarts, the parent process startup routine |
|||
can be called before the child process is killed. In this case, the map will fail |
|||
and we have to sleep some time (until the child releases the mapping object) and retry.*/ |
|||
do { |
|||
memfile = OpenFileMapping(FILE_MAP_WRITE, 0, create_name_with_username(ACCEL_FILEMAP_NAME)); |
|||
err = GetLastError(); |
|||
if (memfile == NULL) |
|||
break; |
|||
|
|||
ret = zend_shared_alloc_reattach(requested_size, error_in); |
|||
err = GetLastError(); |
|||
if (ret == ALLOC_FAIL_MAPPING) { |
|||
/* Mapping failed, wait for mapping object to get freed and retry */ |
|||
CloseHandle(memfile); |
|||
memfile = NULL; |
|||
Sleep(1000*(map_retries+1)); |
|||
} else { |
|||
return ret; |
|||
} |
|||
} while(++map_retries < MAX_MAP_RETRIES); |
|||
|
|||
if(map_retries == MAX_MAP_RETRIES) { |
|||
zend_win_error_message(ACCEL_LOG_FATAL, "Unable to open file mapping", err); |
|||
*error_in = "OpenFileMapping"; |
|||
return ALLOC_FAILURE; |
|||
} |
|||
|
|||
/* creating segment here */ |
|||
*shared_segments_count = 1; |
|||
*shared_segments_p = (zend_shared_segment **) calloc(1, sizeof(zend_shared_segment)+sizeof(void *)); |
|||
shared_segment = (zend_shared_segment *)((char *)(*shared_segments_p) + sizeof(void *)); |
|||
(*shared_segments_p)[0] = shared_segment; |
|||
|
|||
memfile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, requested_size, |
|||
create_name_with_username(ACCEL_FILEMAP_NAME)); |
|||
err = GetLastError(); |
|||
if(memfile == NULL) { |
|||
zend_win_error_message(ACCEL_LOG_FATAL, "Unable to create file mapping", err); |
|||
*error_in = "CreateFileMapping"; |
|||
return ALLOC_FAILURE; |
|||
} |
|||
|
|||
/* Starting from windows Vista, heap randomization occurs which might cause our mapping base to |
|||
be taken (fail to map). So under Vista, we try to map into a hard coded predefined addresses |
|||
in high memory. */ |
|||
if (!ZCG(accel_directives).mmap_base || !*ZCG(accel_directives).mmap_base) { |
|||
do { |
|||
OSVERSIONINFOEX osvi; |
|||
SYSTEM_INFO si; |
|||
|
|||
ZeroMemory(&si, sizeof(SYSTEM_INFO)); |
|||
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); |
|||
|
|||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); |
|||
|
|||
if (! GetVersionEx ((OSVERSIONINFO *) &osvi)) { |
|||
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); |
|||
if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) |
|||
break; |
|||
} |
|||
|
|||
GetSystemInfo(&si); |
|||
|
|||
/* Are we running Vista ? */ |
|||
if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion == 6 ) { |
|||
/* Assert that platform is 32 bit (for 64 bit we need to test a different set */ |
|||
if(si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) |
|||
DebugBreak(); |
|||
|
|||
wanted_mapping_base = vista_mapping_base_set; |
|||
} |
|||
} while (0); |
|||
} else { |
|||
char *s = ZCG(accel_directives).mmap_base; |
|||
|
|||
/* skip leading 0x, %p assumes hexdeciaml format anyway */ |
|||
if (*s == '0' && *(s+1) == 'x') { |
|||
s += 2; |
|||
} |
|||
if (sscanf(s, "%p", &default_mapping_base_set[0]) != 1) { |
|||
zend_win_error_message(ACCEL_LOG_FATAL, "Bad mapping address specified in zend_optimizerplus.mmap_base", err); |
|||
return ALLOC_FAILURE; |
|||
} |
|||
} |
|||
|
|||
do { |
|||
shared_segment->p = mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, *wanted_mapping_base); |
|||
if(*wanted_mapping_base == NULL) /* Auto address (NULL) is the last option on the array */ |
|||
break; |
|||
wanted_mapping_base++; |
|||
} while (!mapping_base); |
|||
|
|||
err = GetLastError(); |
|||
if(mapping_base == NULL) { |
|||
zend_win_error_message(ACCEL_LOG_FATAL, "Unable to create view for file mapping", err); |
|||
*error_in = "MapViewOfFile"; |
|||
return ALLOC_FAILURE; |
|||
} else { |
|||
char *mmap_base_file = get_mmap_base_file(); |
|||
FILE *fp = fopen(mmap_base_file, "w"); |
|||
err = GetLastError(); |
|||
if(!fp) { |
|||
zend_win_error_message(ACCEL_LOG_WARNING, mmap_base_file, err); |
|||
zend_win_error_message(ACCEL_LOG_FATAL, "Unable to write base address", err); |
|||
} |
|||
fprintf(fp, "%p\n", mapping_base); |
|||
fclose(fp); |
|||
} |
|||
|
|||
shared_segment->pos = 0; |
|||
shared_segment->size = requested_size; |
|||
|
|||
return ALLOC_SUCCESS; |
|||
} |
|||
|
|||
static int detach_segment(zend_shared_segment *shared_segment) |
|||
{ |
|||
if(mapping_base) { |
|||
UnmapViewOfFile(mapping_base); |
|||
} |
|||
CloseHandle(memfile); |
|||
ReleaseMutex(memory_mutex); |
|||
CloseHandle(memory_mutex); |
|||
return 0; |
|||
} |
|||
|
|||
static size_t segment_type_size(void) |
|||
{ |
|||
return sizeof(zend_shared_segment); |
|||
} |
|||
|
|||
zend_shared_memory_handlers zend_alloc_win32_handlers = { |
|||
create_segments, |
|||
detach_segment, |
|||
segment_type_size |
|||
}; |
|||
@ -0,0 +1,241 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include "main/php.h" |
|||
#include "main/fopen_wrappers.h" |
|||
#include "ZendAccelerator.h" |
|||
#include "zend_accelerator_blacklist.h" |
|||
|
|||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO |
|||
# include "ext/ereg/php_regex.h" |
|||
#else |
|||
# include "main/php_regex.h" |
|||
#endif |
|||
|
|||
#ifdef ZEND_WIN32 |
|||
# define REGEX_MODE (REG_EXTENDED|REG_NOSUB|REG_ICASE) |
|||
#else |
|||
# define REGEX_MODE (REG_EXTENDED|REG_NOSUB) |
|||
#endif |
|||
|
|||
#define ZEND_BLACKLIST_BLOCK_SIZE 32 |
|||
|
|||
struct _zend_regexp_list { |
|||
regex_t comp_regex; |
|||
zend_regexp_list *next; |
|||
}; |
|||
|
|||
zend_blacklist accel_blacklist; |
|||
|
|||
void zend_accel_blacklist_init(zend_blacklist *blacklist) |
|||
{ |
|||
blacklist->pos = 0; |
|||
blacklist->size = ZEND_BLACKLIST_BLOCK_SIZE; |
|||
|
|||
if( blacklist->entries != NULL ){ |
|||
zend_accel_blacklist_shutdown(blacklist); |
|||
} |
|||
|
|||
blacklist->entries = (zend_blacklist_entry *) calloc(sizeof(zend_blacklist_entry), blacklist->size); |
|||
blacklist->regexp_list = NULL; |
|||
} |
|||
|
|||
static void blacklist_report_regexp_error(regex_t *comp_regex, int reg_err) |
|||
{ |
|||
char *errbuf; |
|||
int errsize = regerror(reg_err, comp_regex, NULL, 0); |
|||
errbuf = malloc(errsize); |
|||
|
|||
regerror(reg_err, comp_regex, errbuf, errsize); |
|||
zend_accel_error(ACCEL_LOG_ERROR, "Blacklist compilation: %s\n", errbuf); |
|||
free(errbuf); |
|||
} |
|||
|
|||
static void zend_accel_blacklist_update_regexp(zend_blacklist *blacklist) |
|||
{ |
|||
int i, end=0, j, rlen=6, clen, reg_err; |
|||
char *regexp; |
|||
zend_regexp_list **regexp_list_it; |
|||
|
|||
if (blacklist->pos == 0) { |
|||
/* we have no blacklist to talk about */ |
|||
return; |
|||
} |
|||
|
|||
regexp_list_it = &(blacklist->regexp_list); |
|||
for (i=0; i<blacklist->pos; i++) { |
|||
rlen += blacklist->entries[i].path_length*2+2; |
|||
|
|||
/* don't create a regexp buffer bigger than 12K)*/ |
|||
if((i+1 == blacklist->pos) || ((rlen+blacklist->entries[i+1].path_length*2+2)>(12*1024) ) ) { |
|||
regexp = (char *)malloc(rlen); |
|||
regexp[0] = '^'; |
|||
regexp[1] = '('; |
|||
|
|||
clen=2; |
|||
for (j=end; j<=i ;j++) { |
|||
|
|||
int c; |
|||
if (j!=end) { |
|||
regexp[clen++] = '|'; |
|||
} |
|||
/* copy mangled filename */ |
|||
for(c=0; c<blacklist->entries[j].path_length; c++) { |
|||
if(strchr("^.[]$()|*+?{}\\", blacklist->entries[j].path[c])) { |
|||
regexp[clen++] = '\\'; |
|||
} |
|||
regexp[clen++] = blacklist->entries[j].path[c]; |
|||
} |
|||
} |
|||
regexp[clen++] = ')'; |
|||
regexp[clen] = '\0'; |
|||
|
|||
(*regexp_list_it) = malloc(sizeof(zend_regexp_list)); |
|||
(*regexp_list_it)->next = NULL; |
|||
|
|||
if ((reg_err = regcomp(&((*regexp_list_it)->comp_regex), regexp, REGEX_MODE)) != 0) { |
|||
blacklist_report_regexp_error(&((*regexp_list_it)->comp_regex), reg_err); |
|||
} |
|||
/* prepare for the next iteration */ |
|||
free(regexp); |
|||
end = i+1; |
|||
rlen = 6; |
|||
regexp_list_it = &((*regexp_list_it)->next); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void zend_accel_blacklist_shutdown(zend_blacklist *blacklist) |
|||
{ |
|||
zend_blacklist_entry *p = blacklist->entries, *end = blacklist->entries + blacklist->pos; |
|||
|
|||
while (p<end) { |
|||
free(p->path); |
|||
p++; |
|||
} |
|||
free(blacklist->entries); |
|||
blacklist->entries = NULL; |
|||
if (blacklist->regexp_list) { |
|||
zend_regexp_list *temp, *it = blacklist->regexp_list; |
|||
while( it ){ |
|||
regfree(&it->comp_regex); |
|||
temp = it; |
|||
it = it->next; |
|||
free(temp); |
|||
} |
|||
} |
|||
} |
|||
|
|||
static inline void zend_accel_blacklist_allocate(zend_blacklist *blacklist) |
|||
{ |
|||
if (blacklist->pos==blacklist->size) { |
|||
blacklist->size += ZEND_BLACKLIST_BLOCK_SIZE; |
|||
blacklist->entries = (zend_blacklist_entry *) realloc(blacklist->entries, sizeof(zend_blacklist_entry)*blacklist->size); |
|||
} |
|||
} |
|||
|
|||
void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename) |
|||
{ |
|||
char buf[MAXPATHLEN+1], real_path[MAXPATHLEN+1]; |
|||
FILE *fp; |
|||
int path_length; |
|||
TSRMLS_FETCH(); |
|||
|
|||
if ((fp=fopen(filename, "r"))==NULL) { |
|||
zend_accel_error(ACCEL_LOG_WARNING, "Cannot load blacklist file: %s\n", filename); |
|||
return; |
|||
} |
|||
|
|||
zend_accel_error(ACCEL_LOG_DEBUG,"Loading blacklist file: '%s'", filename); |
|||
|
|||
memset(buf, 0, sizeof(buf)); |
|||
memset(real_path, 0, sizeof(real_path)); |
|||
|
|||
while (fgets(buf, MAXPATHLEN, fp)!=NULL) { |
|||
char *path_dup, *pbuf; |
|||
path_length = strlen(buf); |
|||
if (buf[path_length-1]=='\n') { |
|||
buf[--path_length] = 0; |
|||
if (buf[path_length-1]=='\r') { |
|||
buf[--path_length] = 0; |
|||
} |
|||
} |
|||
|
|||
/* Strip ctrl-m prefix */ |
|||
pbuf = &buf[0]; |
|||
while(*pbuf == '\r') { |
|||
*pbuf++ = 0; |
|||
path_length--; |
|||
} |
|||
|
|||
/* strip \" */ |
|||
if( pbuf[0] == '\"' && pbuf[path_length-1]== '\"' ){ |
|||
*pbuf++ = 0; |
|||
path_length-=2; |
|||
} |
|||
|
|||
if (path_length==0) { |
|||
continue; |
|||
} |
|||
|
|||
path_dup = zend_strndup(pbuf, path_length); |
|||
expand_filepath(path_dup, real_path TSRMLS_CC); |
|||
path_length = strlen(real_path); |
|||
|
|||
free(path_dup); |
|||
|
|||
zend_accel_blacklist_allocate(blacklist); |
|||
blacklist->entries[blacklist->pos].path_length = path_length; |
|||
blacklist->entries[blacklist->pos].path = (char *) malloc(path_length+1); |
|||
blacklist->entries[blacklist->pos].id = blacklist->pos; |
|||
memcpy(blacklist->entries[blacklist->pos].path, real_path, path_length+1); |
|||
blacklist->pos++; |
|||
} |
|||
fclose(fp); |
|||
zend_accel_blacklist_update_regexp(blacklist); |
|||
} |
|||
|
|||
zend_bool zend_accel_blacklist_is_blacklisted(zend_blacklist *blacklist, char *verify_path) |
|||
{ |
|||
int ret = 0; |
|||
zend_regexp_list *regexp_list_it = blacklist->regexp_list; |
|||
|
|||
if (regexp_list_it == NULL) { |
|||
return 0; |
|||
} |
|||
while (regexp_list_it != NULL) { |
|||
if (regexec(&(regexp_list_it->comp_regex), verify_path, 0, NULL, 0) == 0) { |
|||
ret = 1; |
|||
break; |
|||
} |
|||
regexp_list_it = regexp_list_it->next; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
void zend_accel_blacklist_apply(zend_blacklist *blacklist, apply_func_arg_t func, void *argument TSRMLS_DC) |
|||
{ |
|||
int i; |
|||
|
|||
for(i=0; i<blacklist->pos; i++) { |
|||
func(&blacklist->entries[i], argument TSRMLS_CC); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef ZEND_ACCELERATOR_BLACKLIST_H |
|||
#define ZEND_ACCELERATOR_BLACKLIST_H |
|||
|
|||
typedef struct _zend_regexp_list zend_regexp_list; |
|||
|
|||
typedef struct _zend_blacklist_entry { |
|||
char *path; |
|||
int path_length; |
|||
int id; |
|||
} zend_blacklist_entry; |
|||
|
|||
typedef struct _zend_blacklist { |
|||
zend_blacklist_entry *entries; |
|||
int size; |
|||
int pos; |
|||
zend_regexp_list *regexp_list; |
|||
} zend_blacklist; |
|||
|
|||
extern zend_blacklist accel_blacklist; |
|||
|
|||
void zend_accel_blacklist_init(zend_blacklist *blacklist); |
|||
void zend_accel_blacklist_shutdown(zend_blacklist *blacklist); |
|||
|
|||
void zend_accel_blacklist_load(zend_blacklist *blacklist, char *filename); |
|||
zend_bool zend_accel_blacklist_is_blacklisted(zend_blacklist *blacklist, char *verify_path); |
|||
void zend_accel_blacklist_apply(zend_blacklist *blacklist, apply_func_arg_t func, void *argument TSRMLS_DC); |
|||
|
|||
#endif /* ZEND_ACCELERATOR_BLACKLIST_H */ |
|||
@ -0,0 +1,101 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <stdarg.h> |
|||
#include <time.h> |
|||
#ifdef ZEND_WIN32 |
|||
# include <process.h> |
|||
#endif |
|||
#include "ZendAccelerator.h" |
|||
|
|||
void zend_accel_error(int type, const char *format, ...) |
|||
{ |
|||
va_list args; |
|||
time_t timestamp; |
|||
char *time_string; |
|||
FILE * fLog = NULL; |
|||
TSRMLS_FETCH(); |
|||
|
|||
if (type > ZCG(accel_directives).log_verbosity_level) { |
|||
return; |
|||
} |
|||
|
|||
timestamp = time(NULL); |
|||
time_string = asctime(localtime(×tamp)); |
|||
time_string[24] = 0; |
|||
|
|||
if (!ZCG(accel_directives).error_log || |
|||
!*ZCG(accel_directives).error_log || |
|||
strcmp(ZCG(accel_directives).error_log, "stderr") == 0) { |
|||
|
|||
fLog = stderr; |
|||
} else { |
|||
fLog = fopen(ZCG(accel_directives).error_log, "a+"); |
|||
if (!fLog) { |
|||
fLog = stderr; |
|||
} |
|||
} |
|||
|
|||
fprintf(fLog, "%s (%d): ", time_string, |
|||
#ifdef ZTS |
|||
tsrm_thread_id() |
|||
#else |
|||
getpid() |
|||
#endif |
|||
); |
|||
|
|||
switch (type) { |
|||
case ACCEL_LOG_FATAL: |
|||
fprintf(fLog, "Fatal Error "); |
|||
break; |
|||
case ACCEL_LOG_ERROR: |
|||
fprintf(fLog, "Error "); |
|||
break; |
|||
case ACCEL_LOG_WARNING: |
|||
fprintf(fLog, "Warning "); |
|||
break; |
|||
case ACCEL_LOG_INFO: |
|||
fprintf(fLog, "Message "); |
|||
break; |
|||
case ACCEL_LOG_DEBUG: |
|||
fprintf(fLog, "Debug "); |
|||
break; |
|||
} |
|||
|
|||
va_start(args, format); |
|||
vfprintf(fLog, format, args); |
|||
va_end(args); |
|||
fprintf(fLog, "\n"); |
|||
switch (type) { |
|||
case ACCEL_LOG_ERROR: |
|||
zend_bailout(); |
|||
break; |
|||
case ACCEL_LOG_FATAL: |
|||
exit(-2); |
|||
break; |
|||
} |
|||
fflush(fLog); |
|||
if (fLog != stderr) { |
|||
fclose(fLog); |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef ZEND_ACCELERATOR_DEBUG_H |
|||
#define ZEND_ACCELERATOR_DEBUG_H |
|||
|
|||
#define ACCEL_LOG_FATAL 0 |
|||
#define ACCEL_LOG_ERROR 1 |
|||
#define ACCEL_LOG_WARNING 2 |
|||
#define ACCEL_LOG_INFO 3 |
|||
#define ACCEL_LOG_DEBUG 4 |
|||
|
|||
void zend_accel_error(int type, const char *format, ...); |
|||
|
|||
#endif /* _ZEND_ACCELERATOR_DEBUG_H */ |
|||
@ -0,0 +1,222 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include "ZendAccelerator.h" |
|||
#include "zend_accelerator_hash.h" |
|||
#include "zend_hash.h" |
|||
#include "zend_shared_alloc.h" |
|||
|
|||
/* Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */ |
|||
static uint prime_numbers[] = |
|||
{5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }; |
|||
static uint num_prime_numbers = sizeof(prime_numbers) / sizeof(uint); |
|||
|
|||
void zend_accel_hash_clean(zend_accel_hash *accel_hash) |
|||
{ |
|||
accel_hash->num_entries = 0; |
|||
accel_hash->num_direct_entries = 0; |
|||
memset(accel_hash->hash_table, 0, sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries); |
|||
} |
|||
|
|||
void zend_accel_hash_init(zend_accel_hash *accel_hash, zend_uint hash_size) |
|||
{ |
|||
uint i; |
|||
|
|||
for (i=0; i<num_prime_numbers; i++) { |
|||
if (hash_size <= prime_numbers[i]) { |
|||
hash_size = prime_numbers[i]; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
accel_hash->num_entries = 0; |
|||
accel_hash->num_direct_entries = 0; |
|||
accel_hash->max_num_entries = hash_size; |
|||
|
|||
/* set up hash pointers table */ |
|||
accel_hash->hash_table = zend_shared_alloc(sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries); |
|||
if (!accel_hash->hash_table) { |
|||
zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); |
|||
} |
|||
|
|||
/* set up hash values table */ |
|||
accel_hash->hash_entries = zend_shared_alloc(sizeof(zend_accel_hash_entry)*accel_hash->max_num_entries); |
|||
if (!accel_hash->hash_entries) { |
|||
zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); |
|||
} |
|||
memset(accel_hash->hash_table, 0, sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries); |
|||
} |
|||
|
|||
/* Returns NULL if hash is full |
|||
* Returns pointer the actual hash entry on success |
|||
* key needs to be already allocated as it is not copied |
|||
*/ |
|||
zend_accel_hash_entry* zend_accel_hash_update(zend_accel_hash *accel_hash, char *key, zend_uint key_length, zend_bool indirect, void *data) |
|||
{ |
|||
zend_ulong hash_value; |
|||
zend_ulong index; |
|||
zend_accel_hash_entry *entry; |
|||
zend_accel_hash_entry *indirect_bucket = NULL; |
|||
|
|||
if (indirect) { |
|||
indirect_bucket = (zend_accel_hash_entry*)data; |
|||
while (indirect_bucket->indirect) { |
|||
indirect_bucket = (zend_accel_hash_entry*)indirect_bucket->data; |
|||
} |
|||
} |
|||
|
|||
hash_value = zend_inline_hash_func(key, key_length); |
|||
index = hash_value % accel_hash->max_num_entries; |
|||
|
|||
/* try to see if the element already exists in the hash */ |
|||
entry = accel_hash->hash_table[index]; |
|||
while (entry) { |
|||
if (entry->hash_value == hash_value |
|||
&& entry->key_length == key_length |
|||
&& !memcmp(entry->key, key, key_length)) { |
|||
|
|||
if (entry->indirect) { |
|||
if (indirect_bucket) { |
|||
entry->data = indirect_bucket; |
|||
} else { |
|||
((zend_accel_hash_entry*)entry->data)->data = data; |
|||
} |
|||
} else { |
|||
if (indirect_bucket) { |
|||
accel_hash->num_direct_entries--; |
|||
entry->data = indirect_bucket; |
|||
entry->indirect = 1; |
|||
} else { |
|||
entry->data = data; |
|||
} |
|||
} |
|||
return entry; |
|||
} |
|||
entry = entry->next; |
|||
} |
|||
|
|||
/* Does not exist, add a new entry */ |
|||
if (accel_hash->num_entries == accel_hash->max_num_entries) { |
|||
return NULL; |
|||
} |
|||
|
|||
entry = &accel_hash->hash_entries[accel_hash->num_entries++]; |
|||
if (indirect) { |
|||
entry->data = indirect_bucket; |
|||
entry->indirect = 1; |
|||
} else { |
|||
accel_hash->num_direct_entries++; |
|||
entry->data = data; |
|||
entry->indirect = 0; |
|||
} |
|||
entry->hash_value = hash_value; |
|||
entry->key = key; |
|||
entry->key_length = key_length; |
|||
entry->next = accel_hash->hash_table[index]; |
|||
accel_hash->hash_table[index] = entry; |
|||
return entry; |
|||
} |
|||
|
|||
/* Returns the data associated with key on success |
|||
* Returns NULL if data doesn't exist |
|||
*/ |
|||
void* zend_accel_hash_find(zend_accel_hash *accel_hash, char *key, zend_uint key_length) |
|||
{ |
|||
zend_ulong hash_value; |
|||
zend_ulong index; |
|||
zend_accel_hash_entry *entry; |
|||
|
|||
hash_value = zend_inline_hash_func(key, key_length); |
|||
index = hash_value % accel_hash->max_num_entries; |
|||
|
|||
entry = accel_hash->hash_table[index]; |
|||
while (entry) { |
|||
if (entry->hash_value == hash_value |
|||
&& entry->key_length == key_length |
|||
&& !memcmp(entry->key, key, key_length)) { |
|||
if (entry->indirect) { |
|||
return ((zend_accel_hash_entry *) entry->data)->data; |
|||
} else { |
|||
return entry->data; |
|||
} |
|||
} |
|||
entry = entry->next; |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
/* Returns the hash entry associated with key on success |
|||
* Returns NULL if it doesn't exist |
|||
*/ |
|||
zend_accel_hash_entry* zend_accel_hash_find_entry(zend_accel_hash *accel_hash, char *key, zend_uint key_length) |
|||
{ |
|||
zend_ulong hash_value; |
|||
zend_ulong index; |
|||
zend_accel_hash_entry *entry; |
|||
|
|||
hash_value = zend_inline_hash_func(key, key_length); |
|||
index = hash_value % accel_hash->max_num_entries; |
|||
|
|||
entry = accel_hash->hash_table[index]; |
|||
while (entry) { |
|||
if (entry->hash_value == hash_value |
|||
&& entry->key_length == key_length |
|||
&& !memcmp(entry->key, key, key_length)) { |
|||
if (entry->indirect) { |
|||
return (zend_accel_hash_entry *) entry->data; |
|||
} else { |
|||
return entry; |
|||
} |
|||
} |
|||
entry = entry->next; |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
int zend_accel_hash_unlink(zend_accel_hash *accel_hash, char *key, zend_uint key_length) |
|||
{ |
|||
zend_ulong hash_value; |
|||
zend_ulong index; |
|||
zend_accel_hash_entry *entry, *last_entry=NULL; |
|||
|
|||
hash_value = zend_inline_hash_func(key, key_length); |
|||
index = hash_value % accel_hash->max_num_entries; |
|||
|
|||
entry = accel_hash->hash_table[index]; |
|||
while (entry) { |
|||
if (entry->hash_value == hash_value |
|||
&& entry->key_length == key_length |
|||
&& !memcmp(entry->key, key, key_length)) { |
|||
if (!entry->indirect) { |
|||
accel_hash->num_direct_entries--; |
|||
} |
|||
if (last_entry) { |
|||
last_entry->next = entry->next; |
|||
} else { |
|||
accel_hash->hash_table[index] = entry->next; |
|||
} |
|||
return SUCCESS; |
|||
} |
|||
last_entry = entry; |
|||
entry = entry->next; |
|||
} |
|||
return FAILURE; |
|||
} |
|||
@ -0,0 +1,98 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef ZEND_ACCELERATOR_HASH_H |
|||
#define ZEND_ACCELERATOR_HASH_H |
|||
|
|||
#include "zend.h" |
|||
|
|||
/* |
|||
zend_accel_hash - is a hash table allocated in shared memory and |
|||
distributed across simultaneously running processes. The hash tables have |
|||
fixed sizen selected during construction by zend_accel_hash_init(). All the |
|||
hash entries are preallocated in the 'hash_entries' array. 'num_entries' is |
|||
initialized by zero and grows when new data is added. |
|||
zend_accel_hash_update() just takes the next entry from 'hash_entries' |
|||
array and puts it into appropriate place of 'hash_table'. |
|||
Hash collisions are resolved by separate chaining with linked lists, |
|||
however, entries are still taken from the same 'hash_entries' array. |
|||
'key' and 'data' passed to zend_accel_hash_update() must be already |
|||
allocated in shared memory. Few keys may be resolved to the same data. |
|||
using 'indirect' emtries, that point to other entries ('data' is actually |
|||
a pointer to another zend_accel_hash_entry). |
|||
zend_accel_hash_update() requires exclusive lock, however, |
|||
zend_accel_hash_find() does not. |
|||
*/ |
|||
|
|||
typedef struct _zend_accel_hash_entry zend_accel_hash_entry; |
|||
|
|||
struct _zend_accel_hash_entry { |
|||
zend_ulong hash_value; |
|||
char *key; |
|||
zend_uint key_length; |
|||
zend_accel_hash_entry *next; |
|||
void *data; |
|||
zend_bool indirect; |
|||
}; |
|||
|
|||
typedef struct _zend_accel_hash { |
|||
zend_accel_hash_entry **hash_table; |
|||
zend_accel_hash_entry *hash_entries; |
|||
zend_uint num_entries; |
|||
zend_uint max_num_entries; |
|||
zend_uint num_direct_entries; |
|||
} zend_accel_hash; |
|||
|
|||
void zend_accel_hash_init(zend_accel_hash *accel_hash, zend_uint hash_size); |
|||
void zend_accel_hash_clean(zend_accel_hash *accel_hash); |
|||
|
|||
zend_accel_hash_entry* zend_accel_hash_update( |
|||
zend_accel_hash *accel_hash, |
|||
char *key, |
|||
zend_uint key_length, |
|||
zend_bool indirect, |
|||
void *data); |
|||
|
|||
void* zend_accel_hash_find( |
|||
zend_accel_hash *accel_hash, |
|||
char *key, |
|||
zend_uint key_length); |
|||
|
|||
zend_accel_hash_entry* zend_accel_hash_find_entry( |
|||
zend_accel_hash *accel_hash, |
|||
char *key, |
|||
zend_uint key_length); |
|||
|
|||
int zend_accel_hash_unlink( |
|||
zend_accel_hash *accel_hash, |
|||
char *key, |
|||
zend_uint key_length); |
|||
|
|||
static inline zend_bool zend_accel_hash_is_full(zend_accel_hash *accel_hash) |
|||
{ |
|||
if (accel_hash->num_entries == accel_hash->max_num_entries) { |
|||
return 1; |
|||
} else { |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
#endif /* ZEND_ACCELERATOR_HASH_H */ |
|||
@ -0,0 +1,574 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include <time.h> |
|||
|
|||
#include "php.h" |
|||
#include "ZendAccelerator.h" |
|||
#include "zend_API.h" |
|||
#include "zend_shared_alloc.h" |
|||
#include "zend_accelerator_blacklist.h" |
|||
#include "php_ini.h" |
|||
#include "SAPI.h" |
|||
#include "TSRM/tsrm_virtual_cwd.h" |
|||
#include "ext/standard/info.h" |
|||
#include "ext/standard/php_filestat.h" |
|||
|
|||
#define STRING_NOT_NULL(s) (NULL == (s)?"":s) |
|||
#define MIN_ACCEL_FILES 200 |
|||
#define MAX_ACCEL_FILES 100000 |
|||
#define TOKENTOSTR(X) #X |
|||
|
|||
/* User functions */ |
|||
static ZEND_FUNCTION(accelerator_reset); |
|||
|
|||
/* Private functions */ |
|||
static ZEND_FUNCTION(accelerator_get_status); |
|||
static ZEND_FUNCTION(accelerator_get_configuration); |
|||
|
|||
static zend_function_entry accel_functions[] = { |
|||
/* User functions */ |
|||
ZEND_FE(accelerator_reset, NULL) |
|||
/* Private functions */ |
|||
ZEND_FE(accelerator_get_configuration, NULL) |
|||
ZEND_FE(accelerator_get_status, NULL) |
|||
{ NULL, NULL, NULL, 0, 0 } |
|||
}; |
|||
|
|||
static ZEND_INI_MH(OnUpdateMemoryConsumption) |
|||
{ |
|||
long *p; |
|||
long memsize; |
|||
#ifndef ZTS |
|||
char *base = (char *) mh_arg2; |
|||
#else |
|||
char *base = (char *) ts_resource(*((int *) mh_arg2)); |
|||
#endif |
|||
|
|||
/* keep the compiler happy */ |
|||
(void)entry; (void)new_value_length; (void)mh_arg2; (void)mh_arg3; (void)stage; |
|||
|
|||
p = (long *) (base+(size_t) mh_arg1); |
|||
memsize = atoi(new_value); |
|||
/* sanity check we must use at least 8 MB */ |
|||
if (memsize < 8) { |
|||
const char *new_new_value = "8"; |
|||
zend_ini_entry *ini_entry; |
|||
|
|||
memsize = 8; |
|||
zend_accel_error(ACCEL_LOG_WARNING,"zend_optimizerplus.memory_consumption is set below the required 8MB.\n" ); |
|||
zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the minimal 8MB cofiguration.\n" ); |
|||
|
|||
if (zend_hash_find(EG(ini_directives), |
|||
"zend_optimizerplus.memory_consumption", |
|||
sizeof("zend_optimizerplus.memory_consumption"), |
|||
(void *) &ini_entry)==FAILURE) { |
|||
return FAILURE; |
|||
} |
|||
|
|||
ini_entry->value = strdup(new_new_value); |
|||
ini_entry->value_length = strlen(new_new_value); |
|||
} |
|||
*p = memsize * (1024 * 1024); |
|||
return SUCCESS; |
|||
} |
|||
|
|||
static ZEND_INI_MH(OnUpdateMaxAcceleratedFiles) |
|||
{ |
|||
long *p; |
|||
long size; |
|||
#ifndef ZTS |
|||
char *base = (char *) mh_arg2; |
|||
#else |
|||
char *base = (char *) ts_resource(*((int *) mh_arg2)); |
|||
#endif |
|||
|
|||
/* keep the compiler happy */ |
|||
(void)entry; (void)new_value_length; (void)mh_arg2; (void)mh_arg3; (void)stage; |
|||
|
|||
p = (long *) (base+(size_t) mh_arg1); |
|||
size = atoi(new_value); |
|||
/* sanity check we must use a value between MIN_ACCEL_FILES and MAX_ACCEL_FILES */ |
|||
|
|||
if (size < MIN_ACCEL_FILES || size > MAX_ACCEL_FILES) { |
|||
const char *new_new_value; |
|||
zend_ini_entry *ini_entry; |
|||
|
|||
if(size < MIN_ACCEL_FILES){ |
|||
size = MIN_ACCEL_FILES; |
|||
new_new_value = TOKENTOSTR(MIN_ACCEL_FILES); |
|||
zend_accel_error(ACCEL_LOG_WARNING,"zend_optimizerplus.max_accelerated_files is set below the required minimum (%d).\n", MIN_ACCEL_FILES ); |
|||
zend_accel_error(ACCEL_LOG_WARNING,ACCELERATOR_PRODUCT_NAME " will use the minimal cofiguration.\n" ); |
|||
} |
|||
if(size > MAX_ACCEL_FILES){ |
|||
size = MAX_ACCEL_FILES; |
|||
new_new_value = TOKENTOSTR(MAX_ACCEL_FILES); |
|||
zend_accel_error(ACCEL_LOG_WARNING,"zend_optimizerplus.max_accelerated_files is set above the limit (%d).\n", MAX_ACCEL_FILES ); |
|||
zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the maximal cofiguration.\n" ); |
|||
} |
|||
if (zend_hash_find(EG(ini_directives), |
|||
"zend_optimizerplus.max_accelerated_files", |
|||
sizeof("zend_optimizerplus.max_accelerated_files"), |
|||
(void *) &ini_entry)==FAILURE) { |
|||
return FAILURE; |
|||
} |
|||
ini_entry->value = strdup(new_new_value); |
|||
ini_entry->value_length = strlen(new_new_value); |
|||
} |
|||
*p = size; |
|||
return SUCCESS; |
|||
} |
|||
|
|||
static ZEND_INI_MH(OnUpdateMaxWastedPercentage) |
|||
{ |
|||
double *p; |
|||
long percentage; |
|||
#ifndef ZTS |
|||
char *base = (char *) mh_arg2; |
|||
#else |
|||
char *base = (char *) ts_resource(*((int *) mh_arg2)); |
|||
#endif |
|||
|
|||
/* keep the compiler happy */ |
|||
(void)entry; (void)new_value_length; (void)mh_arg2; (void)mh_arg3; (void)stage; |
|||
|
|||
p = (double *) (base+(size_t) mh_arg1); |
|||
percentage = atoi(new_value); |
|||
|
|||
if (percentage <= 0 || percentage > 50) { |
|||
const char *new_new_value = "5"; |
|||
zend_ini_entry *ini_entry; |
|||
|
|||
percentage = 5; |
|||
zend_accel_error(ACCEL_LOG_WARNING,"zend_optimizerplus.max_wasted_percentage must be ser netweeb 1 and 50.\n"); |
|||
zend_accel_error(ACCEL_LOG_WARNING,ACCELERATOR_PRODUCT_NAME " will use 5%.\n" ); |
|||
if (zend_hash_find(EG(ini_directives), |
|||
"zend_optimizerplus.max_wasted_percentage", |
|||
sizeof("zend_optimizerplus.max_wasted_percentage"), |
|||
(void *) &ini_entry)==FAILURE) { |
|||
return FAILURE; |
|||
} |
|||
ini_entry->value = strdup(new_new_value); |
|||
ini_entry->value_length = strlen(new_new_value); |
|||
} |
|||
*p = (double)percentage / 100.0; |
|||
return SUCCESS; |
|||
} |
|||
|
|||
static ZEND_INI_MH(OnUpdateAccelBlacklist) |
|||
{ |
|||
char **p; |
|||
#ifndef ZTS |
|||
char *base = (char *) mh_arg2; |
|||
#else |
|||
char *base = (char *) ts_resource(*((int *) mh_arg2)); |
|||
#endif |
|||
|
|||
/* keep the compiler happy */ |
|||
(void)entry; (void)new_value_length; (void)mh_arg2; (void)mh_arg3; (void)stage; |
|||
|
|||
if (new_value && !new_value[0]) { |
|||
return FAILURE; |
|||
} |
|||
|
|||
p = (char **) (base+(size_t) mh_arg1); |
|||
*p = new_value; |
|||
|
|||
zend_accel_blacklist_init(&accel_blacklist); |
|||
zend_accel_blacklist_load(&accel_blacklist, *p); |
|||
|
|||
return SUCCESS; |
|||
} |
|||
|
|||
ZEND_INI_BEGIN() |
|||
STD_PHP_INI_BOOLEAN("zend_optimizerplus.enable" ,"1", PHP_INI_SYSTEM, OnUpdateBool, enabled , zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_BOOLEAN("zend_optimizerplus.use_cwd" ,"1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.use_cwd , zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_BOOLEAN("zend_optimizerplus.validate_timestamps","1", PHP_INI_ALL , OnUpdateBool, accel_directives.validate_timestamps, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_BOOLEAN("zend_optimizerplus.inherited_hack" ,"1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.inherited_hack , zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_BOOLEAN("zend_optimizerplus.dups_fix" ,"0", PHP_INI_ALL , OnUpdateBool, accel_directives.ignore_dups , zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_BOOLEAN("zend_optimizerplus.revalidate_path" ,"0", PHP_INI_ALL , OnUpdateBool, accel_directives.revalidate_path , zend_accel_globals, accel_globals) |
|||
|
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.log_verbosity_level" , "1" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.log_verbosity_level, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.memory_consumption" , "64" , PHP_INI_SYSTEM, OnUpdateMemoryConsumption, accel_directives.memory_consumption, zend_accel_globals, accel_globals) |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.interned_strings_buffer", "4" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals) |
|||
#endif |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.max_accelerated_files" , "2000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.max_wasted_percentage" , "5" , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage, accel_directives.max_wasted_percentage, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateLong, accel_directives.consistency_checks, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.force_restart_timeout, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.revalidate_freq" , "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.revalidate_freq, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.preferred_memory_model", "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.memory_model, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.blacklist_filename" , "" , PHP_INI_SYSTEM, OnUpdateAccelBlacklist, accel_directives.user_blacklist_filename, zend_accel_globals, accel_globals) |
|||
|
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.protect_memory" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.protect_memory, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.save_comments" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.save_comments, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.fast_shutdown" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.fast_shutdown, zend_accel_globals, accel_globals) |
|||
|
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_BOOLEAN("zend_optimizerplus.enable_file_override" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_override_enabled, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_BOOLEAN("zend_optimizerplus.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals) |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals) |
|||
|
|||
#ifdef ZEND_WIN32 |
|||
STD_PHP_INI_ENTRY("zend_optimizerplus.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals) |
|||
#endif |
|||
ZEND_INI_END() |
|||
|
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
|
|||
#undef EX |
|||
#define EX(element) execute_data->element |
|||
#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset)) |
|||
|
|||
static int ZEND_DECLARE_INHERITED_CLASS_DELAYED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) |
|||
{ |
|||
zend_class_entry **pce, **pce_orig; |
|||
|
|||
if (zend_hash_find(EG(class_table), Z_STRVAL(EX(opline)->op2.u.constant), Z_STRLEN(EX(opline)->op2.u.constant)+1, (void **)&pce) == FAILURE || |
|||
(zend_hash_find(EG(class_table), Z_STRVAL(EX(opline)->op1.u.constant), Z_STRLEN(EX(opline)->op1.u.constant), (void**)&pce_orig) == SUCCESS && |
|||
*pce != *pce_orig)) { |
|||
do_bind_inherited_class(EX(opline), EG(class_table), EX_T(EX(opline)->extended_value).class_entry, 0 TSRMLS_CC); |
|||
} |
|||
EX(opline)++; |
|||
return ZEND_USER_OPCODE_CONTINUE; |
|||
} |
|||
#endif |
|||
|
|||
static int filename_is_in_cache(char *filename, int filename_len TSRMLS_DC) |
|||
{ |
|||
char *key; |
|||
int key_length; |
|||
zend_file_handle handle = {0}; |
|||
zend_persistent_script *persistent_script; |
|||
|
|||
handle.filename = filename; |
|||
handle.type = ZEND_HANDLE_FILENAME; |
|||
|
|||
if (IS_ABSOLUTE_PATH(filename, filename_len)) { |
|||
persistent_script = zend_accel_hash_find(&ZCSG(hash), filename, filename_len+1); |
|||
if (persistent_script) { |
|||
return !persistent_script->corrupted; |
|||
} |
|||
} |
|||
|
|||
if((key = accel_make_persistent_key_ex(&handle, filename_len, &key_length TSRMLS_CC)) != NULL) { |
|||
persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length+1); |
|||
return persistent_script && !persistent_script->corrupted; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static void accel_file_in_cache(int type, INTERNAL_FUNCTION_PARAMETERS) |
|||
{ |
|||
char *filename; |
|||
int filename_len; |
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
zval **zfilename; |
|||
|
|||
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &zfilename) == FAILURE) { |
|||
WRONG_PARAM_COUNT; |
|||
} |
|||
convert_to_string_ex(zfilename); |
|||
filename = Z_STRVAL_PP(zfilename); |
|||
filename_len = Z_STRLEN_PP(zfilename); |
|||
#else |
|||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) { |
|||
return; |
|||
} |
|||
#endif |
|||
if(filename_len > 0) { |
|||
if(filename_is_in_cache(filename, filename_len TSRMLS_CC)) { |
|||
RETURN_TRUE; |
|||
} |
|||
} |
|||
|
|||
php_stat(filename, filename_len, type, return_value TSRMLS_CC); |
|||
} |
|||
|
|||
static void accel_file_exists(INTERNAL_FUNCTION_PARAMETERS) |
|||
{ |
|||
accel_file_in_cache(FS_EXISTS, INTERNAL_FUNCTION_PARAM_PASSTHRU); |
|||
} |
|||
|
|||
static void accel_is_file(INTERNAL_FUNCTION_PARAMETERS) |
|||
{ |
|||
accel_file_in_cache(FS_IS_FILE, INTERNAL_FUNCTION_PARAM_PASSTHRU); |
|||
} |
|||
|
|||
static void accel_is_readable(INTERNAL_FUNCTION_PARAMETERS) |
|||
{ |
|||
accel_file_in_cache(FS_IS_R, INTERNAL_FUNCTION_PARAM_PASSTHRU); |
|||
} |
|||
|
|||
static ZEND_MINIT_FUNCTION(zend_accelerator) |
|||
{ |
|||
(void)type; /* keep the compiler happy */ |
|||
|
|||
/* must be 0 before the ini entry OnUpdate function is called */ |
|||
accel_blacklist.entries = NULL; |
|||
|
|||
REGISTER_INI_ENTRIES(); |
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
zend_set_user_opcode_handler(ZEND_DECLARE_INHERITED_CLASS_DELAYED, ZEND_DECLARE_INHERITED_CLASS_DELAYED_HANDLER); |
|||
#endif |
|||
return SUCCESS; |
|||
} |
|||
|
|||
void zend_accel_override_file_functions(TSRMLS_D) |
|||
{ |
|||
zend_function *old_function; |
|||
if(ZCG(startup_ok) && ZCG(accel_directives).file_override_enabled) { |
|||
/* override file_exists */ |
|||
if(zend_hash_find(CG(function_table), "file_exists", sizeof("file_exists"), (void **)&old_function) == SUCCESS) { |
|||
old_function->internal_function.handler = accel_file_exists; |
|||
} |
|||
if(zend_hash_find(CG(function_table), "is_file", sizeof("is_file"), (void **)&old_function) == SUCCESS) { |
|||
old_function->internal_function.handler = accel_is_file; |
|||
} |
|||
if(zend_hash_find(CG(function_table), "is_readable", sizeof("is_readable"), (void **)&old_function) == SUCCESS) { |
|||
old_function->internal_function.handler = accel_is_readable; |
|||
} |
|||
} |
|||
} |
|||
|
|||
static ZEND_MSHUTDOWN_FUNCTION(zend_accelerator) |
|||
{ |
|||
(void)type; /* keep the compiler happy */ |
|||
|
|||
UNREGISTER_INI_ENTRIES(); |
|||
return SUCCESS; |
|||
} |
|||
|
|||
void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS) |
|||
{ |
|||
php_info_print_table_start(); |
|||
|
|||
if (ZCG(startup_ok) && ZCSG(accelerator_enabled)) { |
|||
php_info_print_table_row(2, "Opcode Caching", "Up and Running"); |
|||
} else { |
|||
php_info_print_table_row(2, "Opcode Caching", "Disabled"); |
|||
} |
|||
if (ZCG(enabled) && ZCG(accel_directives).optimization_level) { |
|||
php_info_print_table_row(2, "Optimization", "Enabled"); |
|||
} else { |
|||
php_info_print_table_row(2, "Optimization", "Disabled"); |
|||
} |
|||
if (!ZCG(startup_ok) || zps_api_failure_reason) { |
|||
php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason); |
|||
} else { |
|||
php_info_print_table_row(2, "Startup", "OK"); |
|||
php_info_print_table_row(2, "Shared memory model", zend_accel_get_shared_model()); |
|||
} |
|||
|
|||
php_info_print_table_end(); |
|||
DISPLAY_INI_ENTRIES(); |
|||
} |
|||
|
|||
static zend_module_entry accel_module_entry = { |
|||
STANDARD_MODULE_HEADER, |
|||
ACCELERATOR_PRODUCT_NAME, |
|||
accel_functions, |
|||
ZEND_MINIT(zend_accelerator), |
|||
ZEND_MSHUTDOWN(zend_accelerator), |
|||
NULL, |
|||
NULL, |
|||
zend_accel_info, |
|||
ACCELERATOR_VERSION "FE", |
|||
STANDARD_MODULE_PROPERTIES |
|||
}; |
|||
|
|||
int start_accel_module() |
|||
{ |
|||
return zend_startup_module(&accel_module_entry); |
|||
} |
|||
|
|||
/* {{{ proto array accelerator_get_scripts() |
|||
Get the scripts which are accelerated by ZendAccelerator */ |
|||
static zval* accelerator_get_scripts(TSRMLS_D) |
|||
{ |
|||
uint i; |
|||
zval *return_value,*persistent_script_report; |
|||
zend_accel_hash_entry *cache_entry; |
|||
struct tm *ta; |
|||
struct timeval exec_time; |
|||
struct timeval fetch_time; |
|||
|
|||
if (!ZCG(startup_ok) || !ZCSG(accelerator_enabled) || accelerator_shm_read_lock(TSRMLS_C) != SUCCESS) { |
|||
return 0; |
|||
} |
|||
|
|||
MAKE_STD_ZVAL(return_value); |
|||
array_init(return_value); |
|||
for (i=0; i<ZCSG(hash).max_num_entries; i++) { |
|||
for (cache_entry=ZCSG(hash).hash_table[i]; cache_entry; cache_entry = cache_entry->next) { |
|||
zend_persistent_script *script; |
|||
|
|||
if (cache_entry->indirect) continue; |
|||
|
|||
script = (zend_persistent_script *)cache_entry->data; |
|||
|
|||
MAKE_STD_ZVAL(persistent_script_report); |
|||
array_init(persistent_script_report); |
|||
add_assoc_stringl(persistent_script_report, "full_path", script->full_path, script->full_path_len, 1); |
|||
add_assoc_long(persistent_script_report, "hits", script->dynamic_members.hits); |
|||
add_assoc_long(persistent_script_report, "memory_consumption", script->dynamic_members.memory_consumption); |
|||
ta = localtime(&script->dynamic_members.last_used); |
|||
add_assoc_string(persistent_script_report, "last_used", asctime(ta), 1); |
|||
add_assoc_long(persistent_script_report, "last_used_timestamp", script->dynamic_members.last_used); |
|||
if (ZCG(accel_directives).validate_timestamps) { |
|||
add_assoc_long(persistent_script_report, "timestamp", (long)script->timestamp); |
|||
} |
|||
timerclear(&exec_time); |
|||
timerclear(&fetch_time); |
|||
|
|||
zend_hash_update(return_value->value.ht, cache_entry->key, cache_entry->key_length, &persistent_script_report, sizeof(zval *), NULL); |
|||
} |
|||
} |
|||
accelerator_shm_read_unlock(TSRMLS_C); |
|||
|
|||
return return_value; |
|||
} |
|||
|
|||
/* {{{ proto array accelerator_get_status() |
|||
Obtain statistics information regarding code acceleration in the Zend Performance Suite */ |
|||
static ZEND_FUNCTION(accelerator_get_status) |
|||
{ |
|||
long reqs; |
|||
zval *memory_usage,*statistics,*scripts; |
|||
|
|||
/* keep the compiler happy */ |
|||
(void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used; |
|||
|
|||
if (!ZCG(startup_ok) || !ZCSG(accelerator_enabled)) { |
|||
RETURN_FALSE; |
|||
} |
|||
|
|||
array_init(return_value); |
|||
|
|||
/* Trivia */ |
|||
add_assoc_long(return_value, "accelerator_enabled", ZCG(startup_ok) && ZCSG(accelerator_enabled)); |
|||
add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted)); |
|||
|
|||
/* Memory usage statistics */ |
|||
MAKE_STD_ZVAL(memory_usage); |
|||
array_init(memory_usage); |
|||
add_assoc_long(memory_usage, "used_memory", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory)); |
|||
add_assoc_long(memory_usage, "free_memory", zend_shared_alloc_get_free_memory()); |
|||
add_assoc_long(memory_usage, "wasted_memory", ZSMMG(wasted_shared_memory)); |
|||
add_assoc_double(memory_usage, "current_wasted_percentage", (((double) ZSMMG(wasted_shared_memory))/ZCG(accel_directives).memory_consumption)*100.0); |
|||
add_assoc_zval(return_value, "memory_usage",memory_usage); |
|||
|
|||
/* Accelerator statistics */ |
|||
MAKE_STD_ZVAL(statistics); |
|||
array_init(statistics); |
|||
add_assoc_long(statistics, "num_cached_scripts", ZCSG(hash).num_direct_entries); |
|||
add_assoc_long(statistics, "max_cached_scripts", ZCSG(hash).max_num_entries); |
|||
add_assoc_long(statistics, "hits", ZCSG(hits)); |
|||
add_assoc_long(statistics, "last_restart_time", ZCSG(last_restart_time)); |
|||
add_assoc_long(statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses)); |
|||
add_assoc_long(statistics, "blacklist_misses", ZCSG(blacklist_misses)); |
|||
reqs = ZCSG(hits)+ZCSG(misses); |
|||
add_assoc_double(statistics, "blacklist_miss_ratio", reqs?(((double) ZCSG(blacklist_misses))/reqs)*100.0:0); |
|||
add_assoc_double(statistics, "accelerator_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0); |
|||
add_assoc_zval(return_value, "accelerator_statistics",statistics); |
|||
|
|||
/* acceleratred scripts */ |
|||
scripts=accelerator_get_scripts(TSRMLS_C); |
|||
if( scripts ){ |
|||
add_assoc_zval(return_value, "scripts",scripts); |
|||
} |
|||
} |
|||
|
|||
static int add_blacklist_path(zend_blacklist_entry *p, zval *return_value TSRMLS_DC) |
|||
{ |
|||
add_next_index_stringl(return_value, p->path, p->path_length, 1); |
|||
return 0; |
|||
} |
|||
|
|||
/* {{{ proto array accelerator_get_configuration() |
|||
Obtain configuration information for the Zend Performance Suite */ |
|||
static ZEND_FUNCTION(accelerator_get_configuration) |
|||
{ |
|||
zval *directives,*version,*blacklist; |
|||
|
|||
/* keep the compiler happy */ |
|||
(void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used; |
|||
|
|||
array_init(return_value); |
|||
|
|||
/* directives */ |
|||
MAKE_STD_ZVAL(directives); |
|||
array_init(directives); |
|||
add_assoc_bool(directives, "zend_optimizerplus.enable", ZCG(enabled)); |
|||
add_assoc_bool(directives, "zend_optimizerplus.use_cwd", ZCG(accel_directives).use_cwd); |
|||
add_assoc_bool(directives, "zend_optimizerplus.validate_timestamps", ZCG(accel_directives).validate_timestamps); |
|||
add_assoc_bool(directives, "zend_optimizerplus.inherited_hack", ZCG(accel_directives).inherited_hack); |
|||
add_assoc_bool(directives, "zend_optimizerplus.dups_fix", ZCG(accel_directives).ignore_dups); |
|||
add_assoc_bool(directives, "zend_optimizerplus.revalidate_path", ZCG(accel_directives).revalidate_path); |
|||
|
|||
add_assoc_long(directives, "zend_optimizerplus.log_verbosity_level", ZCG(accel_directives).log_verbosity_level); |
|||
add_assoc_long(directives, "zend_optimizerplus.memory_consumption", ZCG(accel_directives).memory_consumption); |
|||
add_assoc_long(directives, "zend_optimizerplus.max_accelerated_files", ZCG(accel_directives).max_accelerated_files); |
|||
add_assoc_double(directives, "zend_optimizerplus.max_wasted_percentage", ZCG(accel_directives).max_wasted_percentage); |
|||
add_assoc_long(directives, "zend_optimizerplus.consistency_checks", ZCG(accel_directives).consistency_checks); |
|||
add_assoc_long(directives, "zend_optimizerplus.force_restart_timeout", ZCG(accel_directives).force_restart_timeout); |
|||
add_assoc_long(directives, "zend_optimizerplus.revalidate_freq", ZCG(accel_directives).revalidate_freq); |
|||
add_assoc_string(directives, "zend_optimizerplus.preferred_memory_model", STRING_NOT_NULL(ZCG(accel_directives).memory_model), 1); |
|||
add_assoc_string(directives, "zend_optimizerplus.blacklist_filename", STRING_NOT_NULL(ZCG(accel_directives).user_blacklist_filename), 1); |
|||
|
|||
add_assoc_bool(directives, "zend_optimizerplus.protect_memory", ZCG(accel_directives).protect_memory); |
|||
add_assoc_bool(directives, "zend_optimizerplus.save_comments", ZCG(accel_directives).save_comments); |
|||
add_assoc_bool(directives, "zend_optimizerplus.fast_shutdown", ZCG(accel_directives).fast_shutdown); |
|||
|
|||
add_assoc_long(directives, "zend_optimizerplus.optimization_level", ZCG(accel_directives).optimization_level); |
|||
|
|||
add_assoc_zval(return_value,"directives",directives); |
|||
|
|||
/*version */ |
|||
MAKE_STD_ZVAL(version); |
|||
array_init(version); |
|||
add_assoc_string(version, "version", ACCELERATOR_VERSION, 1); |
|||
add_assoc_string(version, "accelerator_product_name", ACCELERATOR_PRODUCT_NAME, 1); |
|||
add_assoc_zval(return_value,"version",version); |
|||
|
|||
/* blacklist */ |
|||
MAKE_STD_ZVAL(blacklist); |
|||
array_init(blacklist); |
|||
zend_accel_blacklist_apply(&accel_blacklist, (apply_func_arg_t) add_blacklist_path, blacklist TSRMLS_CC); |
|||
add_assoc_zval(return_value,"blacklist",blacklist); |
|||
} |
|||
|
|||
/* {{{ proto void accelerator_reset() |
|||
Request that the contents of the Accelerator module in the ZPS be reset */ |
|||
static ZEND_FUNCTION(accelerator_reset) |
|||
{ |
|||
/* keep the compiler happy */ |
|||
(void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used; |
|||
|
|||
if (!ZCG(startup_ok) || !ZCSG(accelerator_enabled)) { |
|||
RETURN_FALSE; |
|||
} |
|||
|
|||
zend_accel_schedule_restart(TSRMLS_C); |
|||
RETURN_TRUE; |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef ZEND_ACCELERAROR_MODULE_H |
|||
#define ZEND_ACCELERATOR_MODULE_H |
|||
|
|||
int start_accel_module(); |
|||
void zend_accel_override_file_functions(TSRMLS_D); |
|||
|
|||
#endif /* _ZEND_ACCELERATOR_MODULE_H */ |
|||
1079
zend_accelerator_util_funcs.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,49 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef ZEND_ACCELERATOR_UTIL_FUNCS_H |
|||
#define ZEND_ACCELERATOR_UTIL_FUNCS_H |
|||
|
|||
#include "zend.h" |
|||
#include "ZendAccelerator.h" |
|||
|
|||
void zend_accel_copy_internal_functions(TSRMLS_D); |
|||
|
|||
zend_persistent_script* create_persistent_script(void); |
|||
void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements); |
|||
|
|||
void zend_accel_free_user_functions(HashTable *ht TSRMLS_DC); |
|||
void zend_accel_move_user_functions(HashTable *str, HashTable *dst TSRMLS_DC); |
|||
|
|||
zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory TSRMLS_DC); |
|||
|
|||
#define ADLER32_INIT 1 /* initial Adler-32 value */ |
|||
|
|||
unsigned int zend_adler32(unsigned int checksum, signed char *buf, uint len); |
|||
|
|||
#endif /* ZEND_ACCELERATOR_UTIL_FUNCS_H */ |
|||
|
|||
/* |
|||
* Local variables: |
|||
* tab-width: 4 |
|||
* c-basic-offset: 4 |
|||
* End: |
|||
*/ |
|||
@ -0,0 +1,680 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include "zend.h" |
|||
#include "ZendAccelerator.h" |
|||
#include "zend_persist.h" |
|||
#include "zend_extensions.h" |
|||
#include "zend_shared_alloc.h" |
|||
#include "zend_vm.h" |
|||
#include "zend_constants.h" |
|||
#include "zend_operators.h" |
|||
|
|||
#define zend_accel_store(p, size) \ |
|||
(p = _zend_shared_memdup((void*)p, size, 1 TSRMLS_CC)) |
|||
#define zend_accel_memdup(p, size) \ |
|||
_zend_shared_memdup((void*)p, size, 0 TSRMLS_CC) |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
# define zend_accel_memdup_interned_string(str, len) \ |
|||
IS_INTERNED(str) ? str : zend_accel_memdup(str, len) |
|||
|
|||
# define zend_accel_store_interned_string(str, len) do { \ |
|||
if (!IS_INTERNED(str)) { zend_accel_store(str, len); } \ |
|||
} while (0) |
|||
#else |
|||
# define zend_accel_memdup_interned_string(str, len) \ |
|||
zend_accel_memdup(str, len) |
|||
|
|||
# define zend_accel_store_interned_string(str, len) \ |
|||
zend_accel_store(str, len) |
|||
#endif |
|||
|
|||
typedef void (*zend_persist_func_t)(void * TSRMLS_DC); |
|||
|
|||
static void zend_persist_zval_ptr(zval **zp TSRMLS_DC); |
|||
|
|||
static void zend_hash_persist(HashTable *ht, void (*pPersistElement)(void *pElement TSRMLS_DC), size_t el_size TSRMLS_DC) |
|||
{ |
|||
Bucket *p = ht->pListHead; |
|||
uint i; |
|||
|
|||
while (p) { |
|||
Bucket *q = p; |
|||
|
|||
/* persist bucket and key */ |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
p = zend_accel_memdup(p, sizeof(Bucket)); |
|||
if (p->nKeyLength) { |
|||
p->arKey = zend_accel_memdup_interned_string(p->arKey, p->nKeyLength); |
|||
} |
|||
#else |
|||
p = zend_accel_memdup(p, sizeof(Bucket) - 1 + p->nKeyLength); |
|||
#endif |
|||
|
|||
/* persist data pointer in bucket */ |
|||
if (!p->pDataPtr) { |
|||
zend_accel_store(p->pData, el_size); |
|||
} else { |
|||
/* Update p->pData to point to the new p->pDataPtr address, after the bucket relocation */ |
|||
p->pData = &p->pDataPtr; |
|||
} |
|||
|
|||
/* persist the data itself */ |
|||
if (pPersistElement) { |
|||
pPersistElement(p->pData TSRMLS_CC); |
|||
} |
|||
|
|||
/* update linked lists */ |
|||
if (p->pLast) { |
|||
p->pLast->pNext = p; |
|||
} |
|||
if (p->pNext) { |
|||
p->pNext->pLast = p; |
|||
} |
|||
if (p->pListLast) { |
|||
p->pListLast->pListNext = p; |
|||
} |
|||
if (p->pListNext) { |
|||
p->pListNext->pListLast = p; |
|||
} |
|||
|
|||
p = p->pListNext; |
|||
|
|||
/* delete the old non-persistent bucket */ |
|||
efree(q); |
|||
} |
|||
|
|||
/* update linked lists */ |
|||
if (ht->pListHead) { |
|||
ht->pListHead = zend_shared_alloc_get_xlat_entry(ht->pListHead); |
|||
} |
|||
if (ht->pListTail) { |
|||
ht->pListTail = zend_shared_alloc_get_xlat_entry(ht->pListTail); |
|||
} |
|||
if (ht->pInternalPointer) { |
|||
ht->pInternalPointer = zend_shared_alloc_get_xlat_entry(ht->pInternalPointer); |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
/* Check if HastTable is initialized */ |
|||
if (ht->nTableMask) { |
|||
#endif |
|||
if (ht->nNumOfElements) { |
|||
/* update hash table */ |
|||
for (i = 0; i < ht->nTableSize; i++) { |
|||
if (ht->arBuckets[i]) { |
|||
ht->arBuckets[i] = zend_shared_alloc_get_xlat_entry(ht->arBuckets[i]); |
|||
} |
|||
} |
|||
} |
|||
zend_accel_store(ht->arBuckets, sizeof(Bucket*) * ht->nTableSize); |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
} else { |
|||
ht->arBuckets = NULL; |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
static void zend_persist_zval(zval *z TSRMLS_DC) |
|||
{ |
|||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO |
|||
switch (z->type & IS_CONSTANT_TYPE_MASK) { |
|||
#else |
|||
switch (z->type & ~IS_CONSTANT_INDEX) { |
|||
#endif |
|||
case IS_STRING: |
|||
case IS_CONSTANT: |
|||
zend_accel_store_interned_string(z->value.str.val, z->value.str.len + 1); |
|||
break; |
|||
case IS_ARRAY: |
|||
case IS_CONSTANT_ARRAY: |
|||
zend_accel_store(z->value.ht, sizeof(HashTable)); |
|||
zend_hash_persist(z->value.ht, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
static void zend_persist_zval_ptr(zval **zp TSRMLS_DC) |
|||
{ |
|||
zval *new_ptr = zend_shared_alloc_get_xlat_entry(*zp); |
|||
|
|||
if (new_ptr) { |
|||
*zp = new_ptr; |
|||
} else { |
|||
/* Attempt to store only if we didn't store this zval_ptr yet */ |
|||
zend_accel_store(*zp, sizeof(zval)); |
|||
zend_persist_zval(*zp TSRMLS_CC); |
|||
} |
|||
} |
|||
|
|||
static void zend_protect_zval(zval *z TSRMLS_DC) |
|||
{ |
|||
PZ_SET_ISREF_P(z); |
|||
PZ_SET_REFCOUNT_P(z,2); |
|||
} |
|||
|
|||
static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_script* main_persistent_script TSRMLS_DC) |
|||
{ |
|||
zend_op *persist_ptr; |
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
int has_jmp = 0; |
|||
#endif |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
zend_literal *orig_literals = NULL; |
|||
#endif |
|||
|
|||
if (op_array->type != ZEND_USER_FUNCTION) { |
|||
return; |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO <= PHP_5_3_X_API_NO |
|||
op_array->size = op_array->last; |
|||
#endif |
|||
|
|||
if (--(*op_array->refcount) == 0) { |
|||
efree(op_array->refcount); |
|||
} |
|||
op_array->refcount = NULL; |
|||
|
|||
if (op_array->filename) { |
|||
/* do not free! PHP has centralized filename storage, compiler will free it */ |
|||
op_array->filename = zend_accel_memdup(op_array->filename, strlen(op_array->filename) + 1); |
|||
} |
|||
|
|||
if (main_persistent_script) { |
|||
zend_bool orig_in_execution = EG(in_execution); |
|||
zend_op_array *orig_op_array = EG(active_op_array); |
|||
zval offset; |
|||
|
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
main_persistent_script->early_binding = -1; |
|||
#endif |
|||
EG(in_execution) = 1; |
|||
EG(active_op_array) = op_array; |
|||
if (zend_get_constant("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1, &offset TSRMLS_CC)) { |
|||
main_persistent_script->compiler_halt_offset = Z_LVAL(offset); |
|||
} |
|||
EG(active_op_array) = orig_op_array; |
|||
EG(in_execution) = orig_in_execution; |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
if (op_array->literals) { |
|||
orig_literals = zend_shared_alloc_get_xlat_entry(op_array->literals); |
|||
if (orig_literals) { |
|||
op_array->literals = orig_literals; |
|||
} else { |
|||
zend_literal *p = zend_accel_memdup(op_array->literals, sizeof(zend_literal) * op_array->last_literal); |
|||
zend_literal *end = p + op_array->last_literal; |
|||
orig_literals = op_array->literals; |
|||
op_array->literals = p; |
|||
while (p < end) { |
|||
zend_persist_zval(&p->constant TSRMLS_CC); |
|||
zend_protect_zval(&p->constant TSRMLS_CC); |
|||
p++; |
|||
} |
|||
efree(orig_literals); |
|||
} |
|||
} |
|||
#endif |
|||
|
|||
if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->opcodes))) { |
|||
op_array->opcodes = persist_ptr; |
|||
} else { |
|||
zend_op *new_opcodes = zend_accel_memdup(op_array->opcodes, sizeof(zend_op) * op_array->last); |
|||
zend_op *opline = new_opcodes; |
|||
zend_op *end = new_opcodes + op_array->last; |
|||
int offset = 0; |
|||
|
|||
for (;opline<end;opline++, offset++) { |
|||
if (ZEND_OP1_TYPE(opline)==IS_CONST) { |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
opline->op1.zv = (zval*)((char*)opline->op1.zv + ((char*)op_array->literals - (char*)orig_literals)); |
|||
#else |
|||
zend_persist_zval(&opline->op1.u.constant TSRMLS_CC); |
|||
zend_protect_zval(&opline->op1.u.constant TSRMLS_CC); |
|||
#endif |
|||
} |
|||
if (ZEND_OP2_TYPE(opline)==IS_CONST) { |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
opline->op2.zv = (zval*)((char*)opline->op2.zv + ((char*)op_array->literals - (char*)orig_literals)); |
|||
#else |
|||
zend_persist_zval(&opline->op2.u.constant TSRMLS_CC); |
|||
zend_protect_zval(&opline->op2.u.constant TSRMLS_CC); |
|||
#endif |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO |
|||
switch (opline->opcode) { |
|||
case ZEND_JMP: |
|||
has_jmp = 1; |
|||
if (ZEND_DONE_PASS_TWO(op_array)) { |
|||
ZEND_OP1(opline).jmp_addr = &new_opcodes[ZEND_OP1(opline).jmp_addr - op_array->opcodes]; |
|||
} |
|||
break; |
|||
case ZEND_JMPZ: |
|||
case ZEND_JMPNZ: |
|||
case ZEND_JMPZ_EX: |
|||
case ZEND_JMPNZ_EX: |
|||
has_jmp = 1; |
|||
if (ZEND_DONE_PASS_TWO(op_array)) { |
|||
ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes]; |
|||
} |
|||
break; |
|||
case ZEND_JMPZNZ: |
|||
case ZEND_BRK: |
|||
case ZEND_CONT: |
|||
has_jmp = 1; |
|||
break; |
|||
case ZEND_DECLARE_INHERITED_CLASS: |
|||
if (main_persistent_script && ZCG(accel_directives).inherited_hack) { |
|||
if (!has_jmp && |
|||
((opline+2) >= end || |
|||
(opline+1)->opcode != ZEND_FETCH_CLASS || |
|||
(opline+2)->opcode != ZEND_ADD_INTERFACE)) { |
|||
|
|||
zend_uint *opline_num = &main_persistent_script->early_binding; |
|||
|
|||
while ((int)*opline_num != -1) { |
|||
opline_num = &new_opcodes[*opline_num].result.u.opline_num; |
|||
} |
|||
*opline_num = opline - new_opcodes; |
|||
opline->result.op_type = IS_UNUSED; |
|||
opline->result.u.opline_num = -1; |
|||
opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED; |
|||
ZEND_VM_SET_OPCODE_HANDLER(opline); |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
|
|||
#else /* if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO */ |
|||
|
|||
if (ZEND_DONE_PASS_TWO(op_array)) { |
|||
/* fix jmps to point to new array */ |
|||
switch (opline->opcode) { |
|||
case ZEND_JMP: |
|||
case ZEND_GOTO: |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO |
|||
case ZEND_FAST_CALL: |
|||
#endif |
|||
ZEND_OP1(opline).jmp_addr = &new_opcodes[ZEND_OP1(opline).jmp_addr - op_array->opcodes]; |
|||
break; |
|||
case ZEND_JMPZ: |
|||
case ZEND_JMPNZ: |
|||
case ZEND_JMPZ_EX: |
|||
case ZEND_JMPNZ_EX: |
|||
case ZEND_JMP_SET: |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
case ZEND_JMP_SET_VAR: |
|||
#endif |
|||
ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes]; |
|||
break; |
|||
} |
|||
} |
|||
#endif /* if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO */ |
|||
} |
|||
|
|||
efree(op_array->opcodes); |
|||
op_array->opcodes = new_opcodes; |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
if (op_array->run_time_cache) { |
|||
efree(op_array->run_time_cache); |
|||
op_array->run_time_cache = NULL; |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
if (op_array->function_name) { |
|||
char *new_name; |
|||
if ((new_name = zend_shared_alloc_get_xlat_entry(op_array->function_name))) { |
|||
op_array->function_name = new_name; |
|||
} else { |
|||
zend_accel_store(op_array->function_name, strlen(op_array->function_name)+1); |
|||
} |
|||
} |
|||
|
|||
if (op_array->arg_info) { |
|||
zend_arg_info *new_ptr; |
|||
if((new_ptr = zend_shared_alloc_get_xlat_entry(op_array->arg_info))) { |
|||
op_array->arg_info = new_ptr; |
|||
} else { |
|||
zend_uint i; |
|||
|
|||
zend_accel_store(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args); |
|||
for(i=0;i<op_array->num_args;i++) { |
|||
if(op_array->arg_info[i].name) { |
|||
zend_accel_store_interned_string(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1); |
|||
} |
|||
if(op_array->arg_info[i].class_name) { |
|||
zend_accel_store_interned_string(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (op_array->brk_cont_array) { |
|||
zend_accel_store(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont); |
|||
} |
|||
|
|||
if (op_array->static_variables) { |
|||
zend_hash_persist(op_array->static_variables, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC); |
|||
zend_accel_store(op_array->static_variables, sizeof(HashTable)); |
|||
} |
|||
|
|||
if(op_array->scope) { |
|||
op_array->scope = zend_shared_alloc_get_xlat_entry(op_array->scope); |
|||
} |
|||
|
|||
if(op_array->doc_comment) { |
|||
if (ZCG(accel_directives).save_comments) { |
|||
zend_accel_store(op_array->doc_comment, op_array->doc_comment_len + 1); |
|||
} else { |
|||
if(!zend_shared_alloc_get_xlat_entry(op_array->doc_comment)) { |
|||
zend_shared_alloc_register_xlat_entry(op_array->doc_comment, op_array->doc_comment); |
|||
efree((char*)op_array->doc_comment); |
|||
} |
|||
op_array->doc_comment = NULL; |
|||
op_array->doc_comment_len = 0; |
|||
} |
|||
} |
|||
|
|||
if(op_array->try_catch_array) { |
|||
zend_accel_store(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch); |
|||
} |
|||
|
|||
if(op_array->vars) { |
|||
if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars))) { |
|||
op_array->vars = (zend_compiled_variable*)persist_ptr; |
|||
} else { |
|||
int i; |
|||
zend_accel_store(op_array->vars, sizeof(zend_compiled_variable) * op_array->last_var); |
|||
for(i=0; i<op_array->last_var; i++) { |
|||
zend_accel_store_interned_string(op_array->vars[i].name, op_array->vars[i].name_len + 1); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* "prototype" may be undefined if "scope" isn't set */ |
|||
if(op_array->scope && op_array->prototype) { |
|||
if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) { |
|||
op_array->prototype = (union _zend_function*)persist_ptr; |
|||
/* we use refcount to show that op_array is referenced from several places */ |
|||
op_array->prototype->op_array.refcount++; |
|||
} |
|||
} else { |
|||
op_array->prototype = NULL; |
|||
} |
|||
} |
|||
|
|||
static void zend_persist_op_array(zend_op_array *op_array TSRMLS_DC) |
|||
{ |
|||
zend_persist_op_array_ex(op_array, NULL TSRMLS_CC); |
|||
} |
|||
|
|||
static void zend_persist_property_info(zend_property_info *prop TSRMLS_DC) |
|||
{ |
|||
zend_accel_store_interned_string(prop->name, prop->name_length + 1); |
|||
if(prop->doc_comment) { |
|||
if (ZCG(accel_directives).save_comments) { |
|||
zend_accel_store(prop->doc_comment, prop->doc_comment_len + 1); |
|||
} else { |
|||
if(!zend_shared_alloc_get_xlat_entry(prop->doc_comment)) { |
|||
zend_shared_alloc_register_xlat_entry(prop->doc_comment, prop->doc_comment); |
|||
efree((char*)prop->doc_comment); |
|||
} |
|||
prop->doc_comment = NULL; |
|||
prop->doc_comment_len = 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
static void zend_persist_class_entry(zend_class_entry **pce TSRMLS_DC) |
|||
{ |
|||
zend_class_entry *ce = *pce; |
|||
|
|||
if (ce->type == ZEND_USER_CLASS) { |
|||
*pce = zend_accel_store(ce, sizeof(zend_class_entry)); |
|||
zend_accel_store_interned_string(ce->name, ce->name_length + 1); |
|||
zend_hash_persist(&ce->function_table, (zend_persist_func_t) zend_persist_op_array, sizeof(zend_op_array) TSRMLS_CC); |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
if (ce->default_properties_table) { |
|||
int i; |
|||
|
|||
zend_accel_store(ce->default_properties_table, sizeof(zval*) * ce->default_properties_count); |
|||
for (i = 0; i < ce->default_properties_count; i++) { |
|||
if (ce->default_properties_table[i]) { |
|||
zend_persist_zval_ptr(&ce->default_properties_table[i] TSRMLS_CC); |
|||
} |
|||
} |
|||
} |
|||
if (ce->default_static_members_table) { |
|||
int i; |
|||
|
|||
zend_accel_store(ce->default_static_members_table, sizeof(zval*) * ce->default_static_members_count); |
|||
for (i = 0; i < ce->default_static_members_count; i++) { |
|||
if (ce->default_static_members_table[i]) { |
|||
zend_persist_zval_ptr(&ce->default_static_members_table[i] TSRMLS_CC); |
|||
} |
|||
} |
|||
} |
|||
ce->static_members_table = NULL; |
|||
#else |
|||
zend_hash_persist(&ce->default_properties, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC); |
|||
zend_hash_persist(&ce->default_static_members, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC); |
|||
ce->static_members = NULL; |
|||
#endif |
|||
zend_hash_persist(&ce->constants_table, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC); |
|||
|
|||
if(ZEND_CE_FILENAME(ce)) { |
|||
/* do not free! PHP has centralized filename storage, compiler will free it */ |
|||
ZEND_CE_FILENAME(ce) = zend_accel_memdup(ZEND_CE_FILENAME(ce), strlen(ZEND_CE_FILENAME(ce)) + 1); |
|||
} |
|||
if(ZEND_CE_DOC_COMMENT(ce)) { |
|||
if (ZCG(accel_directives).save_comments) { |
|||
zend_accel_store(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT_LEN(ce) + 1); |
|||
} else { |
|||
if(!zend_shared_alloc_get_xlat_entry(ZEND_CE_DOC_COMMENT(ce))) { |
|||
zend_shared_alloc_register_xlat_entry(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT(ce)); |
|||
efree((char*)ZEND_CE_DOC_COMMENT(ce)); |
|||
} |
|||
ZEND_CE_DOC_COMMENT(ce) = NULL; |
|||
ZEND_CE_DOC_COMMENT_LEN(ce) = 0; |
|||
} |
|||
} |
|||
zend_hash_persist(&ce->properties_info, (zend_persist_func_t) zend_persist_property_info, sizeof(zend_property_info) TSRMLS_CC); |
|||
if(ce->num_interfaces && ce->interfaces) { |
|||
efree(ce->interfaces); |
|||
} |
|||
ce->interfaces = NULL; /* will be filled in on fetch */ |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
if (ce->num_traits && ce->traits) { |
|||
efree(ce->traits); |
|||
} |
|||
ce->traits = NULL; |
|||
|
|||
if (ce->trait_aliases) { |
|||
int i = 0; |
|||
while (ce->trait_aliases[i]) { |
|||
if (ce->trait_aliases[i]->trait_method) { |
|||
if (ce->trait_aliases[i]->trait_method->method_name) { |
|||
zend_accel_store(ce->trait_aliases[i]->trait_method->method_name, |
|||
ce->trait_aliases[i]->trait_method->mname_len+1); |
|||
} |
|||
if (ce->trait_aliases[i]->trait_method->class_name) { |
|||
zend_accel_store(ce->trait_aliases[i]->trait_method->class_name, |
|||
ce->trait_aliases[i]->trait_method->cname_len+1); |
|||
} |
|||
ce->trait_aliases[i]->trait_method->ce = NULL; |
|||
zend_accel_store(ce->trait_aliases[i]->trait_method, |
|||
sizeof(zend_trait_method_reference)); |
|||
} |
|||
|
|||
if (ce->trait_aliases[i]->alias) { |
|||
zend_accel_store(ce->trait_aliases[i]->alias, |
|||
ce->trait_aliases[i]->alias_len+1); |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO <= PHP_5_4_X_API_NO |
|||
ce->trait_aliases[i]->function = NULL; |
|||
#endif |
|||
zend_accel_store(ce->trait_aliases[i], sizeof(zend_trait_alias)); |
|||
i++; |
|||
} |
|||
|
|||
zend_accel_store(ce->trait_aliases, sizeof(zend_trait_alias*) * (i + 1)); |
|||
} |
|||
|
|||
if (ce->trait_precedences) { |
|||
int i = 0; |
|||
|
|||
while (ce->trait_precedences[i]) { |
|||
zend_accel_store(ce->trait_precedences[i]->trait_method->method_name, |
|||
ce->trait_precedences[i]->trait_method->mname_len+1); |
|||
zend_accel_store(ce->trait_precedences[i]->trait_method->class_name, |
|||
ce->trait_precedences[i]->trait_method->cname_len+1); |
|||
ce->trait_precedences[i]->trait_method->ce = NULL; |
|||
zend_accel_store(ce->trait_precedences[i]->trait_method, |
|||
sizeof(zend_trait_method_reference)); |
|||
|
|||
if (ce->trait_precedences[i]->exclude_from_classes) { |
|||
int j = 0; |
|||
|
|||
while (ce->trait_precedences[i]->exclude_from_classes[j]) { |
|||
zend_accel_store(ce->trait_precedences[i]->exclude_from_classes[j], |
|||
strlen((char*)ce->trait_precedences[i]->exclude_from_classes[j]) + 1); |
|||
j++; |
|||
} |
|||
zend_accel_store(ce->trait_precedences[i]->exclude_from_classes, |
|||
sizeof(zend_class_entry*) * (j+1)); |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO <= PHP_5_4_X_API_NO |
|||
ce->trait_precedences[i]->function = NULL; |
|||
#endif |
|||
zend_accel_store(ce->trait_precedences[i], sizeof(zend_trait_precedence)); |
|||
i++; |
|||
} |
|||
zend_accel_store( |
|||
ce->trait_precedences, sizeof(zend_trait_precedence*) * (i+1)); |
|||
} |
|||
#endif |
|||
} |
|||
} |
|||
|
|||
static int zend_update_property_info_ce(zend_property_info *prop TSRMLS_DC) |
|||
{ |
|||
prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce); |
|||
return 0; |
|||
} |
|||
|
|||
static int zend_update_parent_ce(zend_class_entry **pce TSRMLS_DC) |
|||
{ |
|||
zend_class_entry *ce = *pce; |
|||
|
|||
if (ce->parent) { |
|||
ce->parent = zend_shared_alloc_get_xlat_entry(ce->parent); |
|||
/* We use refcount to show if the class is used as a parent */ |
|||
ce->parent->refcount++; |
|||
} |
|||
|
|||
/* update methods */ |
|||
if(ce->constructor) { |
|||
ce->constructor = zend_shared_alloc_get_xlat_entry(ce->constructor); |
|||
/* we use refcount to show that op_array is referenced from several places */ |
|||
ce->constructor->op_array.refcount++; |
|||
} |
|||
if(ce->destructor) { |
|||
ce->destructor = zend_shared_alloc_get_xlat_entry(ce->destructor); |
|||
ce->destructor->op_array.refcount++; |
|||
} |
|||
if(ce->clone) { |
|||
ce->clone = zend_shared_alloc_get_xlat_entry(ce->clone); |
|||
ce->clone->op_array.refcount++; |
|||
} |
|||
if(ce->__get) { |
|||
ce->__get = zend_shared_alloc_get_xlat_entry(ce->__get); |
|||
ce->__get->op_array.refcount++; |
|||
} |
|||
if(ce->__set) { |
|||
ce->__set = zend_shared_alloc_get_xlat_entry(ce->__set); |
|||
ce->__set->op_array.refcount++; |
|||
} |
|||
if(ce->__call) { |
|||
ce->__call = zend_shared_alloc_get_xlat_entry(ce->__call); |
|||
ce->__call->op_array.refcount++; |
|||
} |
|||
if(ce->serialize_func) { |
|||
ce->serialize_func = zend_shared_alloc_get_xlat_entry(ce->serialize_func); |
|||
ce->serialize_func->op_array.refcount++; |
|||
} |
|||
if(ce->unserialize_func) { |
|||
ce->unserialize_func = zend_shared_alloc_get_xlat_entry(ce->unserialize_func); |
|||
ce->unserialize_func->op_array.refcount++; |
|||
} |
|||
if(ce->__isset) { |
|||
ce->__isset = zend_shared_alloc_get_xlat_entry(ce->__isset); |
|||
ce->__isset->op_array.refcount++; |
|||
} |
|||
if(ce->__unset) { |
|||
ce->__unset = zend_shared_alloc_get_xlat_entry(ce->__unset); |
|||
ce->__unset->op_array.refcount++; |
|||
} |
|||
if(ce->__tostring) { |
|||
ce->__tostring = zend_shared_alloc_get_xlat_entry(ce->__tostring); |
|||
ce->__tostring->op_array.refcount++; |
|||
} |
|||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO |
|||
if(ce->__callstatic) { |
|||
ce->__callstatic = zend_shared_alloc_get_xlat_entry(ce->__callstatic); |
|||
ce->__callstatic->op_array.refcount++; |
|||
} |
|||
#endif |
|||
zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce TSRMLS_CC); |
|||
return 0; |
|||
} |
|||
|
|||
static void zend_accel_persist_class_table(HashTable *class_table TSRMLS_DC) |
|||
{ |
|||
zend_hash_persist(class_table, (zend_persist_func_t) zend_persist_class_entry, sizeof(zend_class_entry*) TSRMLS_CC); |
|||
zend_hash_apply(class_table, (apply_func_t) zend_update_parent_ce TSRMLS_CC); |
|||
} |
|||
|
|||
zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, char **key, unsigned int key_length TSRMLS_DC) |
|||
{ |
|||
zend_shared_alloc_clear_xlat_table(); |
|||
zend_hash_persist(&script->function_table, (zend_persist_func_t) zend_persist_op_array, sizeof(zend_op_array) TSRMLS_CC); |
|||
zend_accel_persist_class_table(&script->class_table TSRMLS_CC); |
|||
zend_persist_op_array_ex(&script->main_op_array, script TSRMLS_CC); |
|||
*key = zend_accel_memdup(*key, key_length + 1); |
|||
zend_accel_store(script->full_path, script->full_path_len + 1); |
|||
zend_accel_store(script, sizeof(zend_persistent_script)); |
|||
|
|||
return script; |
|||
} |
|||
|
|||
int zend_accel_script_persistable(zend_persistent_script *script) |
|||
{ |
|||
return 1; |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef ZEND_PERSIST_H |
|||
#define ZEND_PERSIST_H |
|||
|
|||
int zend_accel_script_persistable(zend_persistent_script *script); |
|||
uint zend_accel_script_persist_calc(zend_persistent_script *script, char *key, unsigned int key_length TSRMLS_DC); |
|||
zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, char **key, unsigned int key_length TSRMLS_DC); |
|||
|
|||
#endif /* ZEND_PERSIST_H */ |
|||
@ -0,0 +1,343 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include "zend.h" |
|||
#include "ZendAccelerator.h" |
|||
#include "zend_persist.h" |
|||
#include "zend_extensions.h" |
|||
#include "zend_shared_alloc.h" |
|||
#include "zend_operators.h" |
|||
|
|||
#define START_SIZE() uint memory_used = 0 |
|||
#define ADD_DUP_SIZE(m,s) memory_used += zend_shared_memdup_size((void*)m, s) |
|||
#define ADD_SIZE(m) memory_used += ZEND_ALIGNED_SIZE(m) |
|||
#define RETURN_SIZE() return memory_used |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
# define ADD_INTERNED_STRING(str, len) do { \ |
|||
const char *tmp = accel_new_interned_string((str), (len), !IS_INTERNED((str)) TSRMLS_CC); \ |
|||
if (tmp != (str)) { \ |
|||
(str) = (char*)tmp; \ |
|||
} else { \ |
|||
ADD_DUP_SIZE((str), (len)); \ |
|||
} \ |
|||
} while (0) |
|||
#else |
|||
# define ADD_INTERNED_STRING(str, len) ADD_DUP_SIZE((str), (len)) |
|||
#endif |
|||
|
|||
static uint zend_persist_zval_ptr_calc(zval **zp TSRMLS_DC); |
|||
|
|||
static uint zend_hash_persist_calc(HashTable *ht, int (*pPersistElement)(void *pElement TSRMLS_DC), size_t el_size TSRMLS_DC) |
|||
{ |
|||
Bucket *p = ht->pListHead; |
|||
START_SIZE(); |
|||
|
|||
while (p) { |
|||
/* persist bucket and key */ |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
ADD_DUP_SIZE(p, sizeof(Bucket)); |
|||
if (p->nKeyLength) { |
|||
const char *tmp = accel_new_interned_string(p->arKey, p->nKeyLength, 0 TSRMLS_CC); |
|||
if (tmp != p->arKey) { |
|||
p->arKey = tmp; |
|||
} else { |
|||
ADD_DUP_SIZE(p->arKey, p->nKeyLength); |
|||
} |
|||
} |
|||
#else |
|||
ADD_DUP_SIZE(p, sizeof(Bucket) - 1 + p->nKeyLength); |
|||
#endif |
|||
|
|||
/* persist data pointer in bucket */ |
|||
if (!p->pDataPtr) { |
|||
ADD_DUP_SIZE(p->pData, el_size); |
|||
} |
|||
|
|||
/* persist the data itself */ |
|||
if (pPersistElement) { |
|||
ADD_SIZE(pPersistElement(p->pData TSRMLS_CC)); |
|||
} |
|||
|
|||
p = p->pListNext; |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
if (ht->nTableMask) { |
|||
ADD_DUP_SIZE(ht->arBuckets, sizeof(Bucket*) * ht->nTableSize); |
|||
} |
|||
#else |
|||
ADD_DUP_SIZE(ht->arBuckets, sizeof(Bucket*) * ht->nTableSize); |
|||
#endif |
|||
|
|||
RETURN_SIZE(); |
|||
} |
|||
|
|||
static uint zend_persist_zval_calc(zval *z TSRMLS_DC) |
|||
{ |
|||
START_SIZE(); |
|||
|
|||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO |
|||
switch (z->type & IS_CONSTANT_TYPE_MASK) { |
|||
#else |
|||
switch (z->type & ~IS_CONSTANT_INDEX) { |
|||
#endif |
|||
case IS_STRING: |
|||
case IS_CONSTANT: |
|||
ADD_INTERNED_STRING(Z_STRVAL_P(z), Z_STRLEN_P(z) + 1); |
|||
break; |
|||
case IS_ARRAY: |
|||
case IS_CONSTANT_ARRAY: |
|||
ADD_DUP_SIZE(z->value.ht, sizeof(HashTable)); |
|||
ADD_SIZE(zend_hash_persist_calc(z->value.ht, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC)); |
|||
break; |
|||
} |
|||
RETURN_SIZE(); |
|||
} |
|||
|
|||
static uint zend_persist_zval_ptr_calc(zval **zp TSRMLS_DC) |
|||
{ |
|||
START_SIZE(); |
|||
zval *new_ptr = zend_shared_alloc_get_xlat_entry(*zp); |
|||
|
|||
if (!new_ptr) { |
|||
ADD_DUP_SIZE(*zp, sizeof(zval)); |
|||
ADD_SIZE(zend_persist_zval_calc(*zp TSRMLS_CC)); |
|||
} |
|||
RETURN_SIZE(); |
|||
} |
|||
|
|||
static uint zend_persist_op_array_calc(zend_op_array *op_array TSRMLS_DC) |
|||
{ |
|||
START_SIZE(); |
|||
|
|||
if (op_array->type != ZEND_USER_FUNCTION) { |
|||
return 0; |
|||
} |
|||
|
|||
if (op_array->filename) { |
|||
ADD_DUP_SIZE(op_array->filename, strlen(op_array->filename) + 1); |
|||
} |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
if (op_array->literals && !zend_shared_alloc_get_xlat_entry(op_array->literals)) { |
|||
zend_literal *p = op_array->literals; |
|||
zend_literal *end = p + op_array->last_literal; |
|||
ADD_DUP_SIZE(op_array->literals, sizeof(zend_literal) * op_array->last_literal); |
|||
while (p < end) { |
|||
ADD_SIZE(zend_persist_zval_calc(&p->constant TSRMLS_CC)); |
|||
p++; |
|||
} |
|||
} |
|||
#endif |
|||
|
|||
if (!zend_shared_alloc_get_xlat_entry(op_array->opcodes)) { |
|||
#if ZEND_EXTENSION_API_NO <= PHP_5_3_X_API_NO |
|||
zend_op *opline = op_array->opcodes; |
|||
zend_op *end = op_array->opcodes+op_array->last; |
|||
|
|||
ADD_DUP_SIZE(op_array->opcodes, sizeof(zend_op) * op_array->last); |
|||
while (opline<end) { |
|||
if (opline->op1.op_type==IS_CONST) { |
|||
ADD_SIZE(zend_persist_zval_calc(&opline->op1.u.constant TSRMLS_CC)); |
|||
} |
|||
if (opline->op2.op_type==IS_CONST) { |
|||
ADD_SIZE(zend_persist_zval_calc(&opline->op2.u.constant TSRMLS_CC)); |
|||
} |
|||
opline++; |
|||
} |
|||
#else |
|||
ADD_DUP_SIZE(op_array->opcodes, sizeof(zend_op) * op_array->last); |
|||
#endif |
|||
} |
|||
|
|||
if (op_array->function_name) { |
|||
ADD_DUP_SIZE(op_array->function_name, strlen(op_array->function_name) + 1); |
|||
} |
|||
|
|||
if (op_array->arg_info && |
|||
!zend_shared_alloc_get_xlat_entry(op_array->arg_info)) { |
|||
zend_uint i; |
|||
|
|||
ADD_DUP_SIZE(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args); |
|||
for(i=0;i<op_array->num_args;i++) { |
|||
if(op_array->arg_info[i].name) { |
|||
ADD_INTERNED_STRING(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1); |
|||
} |
|||
if(op_array->arg_info[i].class_name) { |
|||
ADD_INTERNED_STRING(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
if (op_array->brk_cont_array) { |
|||
ADD_DUP_SIZE(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont); |
|||
} |
|||
|
|||
if (op_array->static_variables) { |
|||
ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable)); |
|||
ADD_SIZE(zend_hash_persist_calc(op_array->static_variables, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC)); |
|||
} |
|||
|
|||
if(ZCG(accel_directives).save_comments && op_array->doc_comment) { |
|||
ADD_DUP_SIZE(op_array->doc_comment, op_array->doc_comment_len + 1); |
|||
} |
|||
|
|||
if(op_array->try_catch_array) { |
|||
ADD_DUP_SIZE(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch); |
|||
} |
|||
|
|||
if(op_array->vars && !zend_shared_alloc_get_xlat_entry(op_array->vars)) { |
|||
int i; |
|||
|
|||
ADD_DUP_SIZE(op_array->vars, sizeof(zend_compiled_variable) * op_array->last_var); |
|||
for(i=0; i<op_array->last_var; i++) { |
|||
ADD_INTERNED_STRING(op_array->vars[i].name, op_array->vars[i].name_len + 1); |
|||
} |
|||
} |
|||
|
|||
RETURN_SIZE(); |
|||
} |
|||
|
|||
static uint zend_persist_property_info_calc(zend_property_info *prop TSRMLS_DC) |
|||
{ |
|||
START_SIZE(); |
|||
ADD_INTERNED_STRING(prop->name, prop->name_length + 1); |
|||
if(ZCG(accel_directives).save_comments && prop->doc_comment) { |
|||
ADD_DUP_SIZE(prop->doc_comment, prop->doc_comment_len + 1); |
|||
} |
|||
RETURN_SIZE(); |
|||
} |
|||
|
|||
static uint zend_persist_class_entry_calc(zend_class_entry **pce TSRMLS_DC) |
|||
{ |
|||
zend_class_entry *ce = *pce; |
|||
START_SIZE(); |
|||
|
|||
if (ce->type == ZEND_USER_CLASS) { |
|||
ADD_DUP_SIZE(ce, sizeof(zend_class_entry)); |
|||
ADD_INTERNED_STRING(ce->name, ce->name_length + 1); |
|||
ADD_SIZE(zend_hash_persist_calc(&ce->function_table, (int (*)(void* TSRMLS_DC)) zend_persist_op_array_calc, sizeof(zend_op_array) TSRMLS_CC)); |
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
if (ce->default_properties_table) { |
|||
int i; |
|||
|
|||
ADD_SIZE(sizeof(zval*) * ce->default_properties_count); |
|||
for (i = 0; i < ce->default_properties_count; i++) { |
|||
if (ce->default_properties_table[i]) { |
|||
ADD_SIZE(zend_persist_zval_ptr_calc(&ce->default_properties_table[i] TSRMLS_CC)); |
|||
} |
|||
} |
|||
} |
|||
if (ce->default_static_members_table) { |
|||
int i; |
|||
|
|||
ADD_SIZE(sizeof(zval*) * ce->default_static_members_count); |
|||
for (i = 0; i < ce->default_static_members_count; i++) { |
|||
if (ce->default_static_members_table[i]) { |
|||
ADD_SIZE(zend_persist_zval_ptr_calc(&ce->default_static_members_table[i] TSRMLS_CC)); |
|||
} |
|||
} |
|||
} |
|||
#else |
|||
ADD_SIZE(zend_hash_persist_calc(&ce->default_properties, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC)); |
|||
ADD_SIZE(zend_hash_persist_calc(&ce->default_static_members, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC)); |
|||
#endif |
|||
ADD_SIZE(zend_hash_persist_calc(&ce->constants_table, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC)); |
|||
|
|||
if (ZEND_CE_FILENAME(ce)) { |
|||
ADD_DUP_SIZE(ZEND_CE_FILENAME(ce), strlen(ZEND_CE_FILENAME(ce)) + 1); |
|||
} |
|||
if(ZCG(accel_directives).save_comments && ZEND_CE_DOC_COMMENT(ce)) { |
|||
ADD_DUP_SIZE(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT_LEN(ce) + 1); |
|||
} |
|||
|
|||
ADD_SIZE(zend_hash_persist_calc(&ce->properties_info, (int (*)(void* TSRMLS_DC)) zend_persist_property_info_calc, sizeof(zend_property_info) TSRMLS_CC)); |
|||
|
|||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO |
|||
if (ce->trait_aliases) { |
|||
int i = 0; |
|||
while (ce->trait_aliases[i]) { |
|||
if (ce->trait_aliases[i]->trait_method) { |
|||
if (ce->trait_aliases[i]->trait_method->method_name) { |
|||
ADD_SIZE(ce->trait_aliases[i]->trait_method->mname_len+1); |
|||
} |
|||
if (ce->trait_aliases[i]->trait_method->class_name) { |
|||
ADD_SIZE(ce->trait_aliases[i]->trait_method->cname_len+1); |
|||
} |
|||
ADD_SIZE(sizeof(zend_trait_method_reference)); |
|||
} |
|||
|
|||
if (ce->trait_aliases[i]->alias) { |
|||
ADD_SIZE(ce->trait_aliases[i]->alias_len+1); |
|||
} |
|||
ADD_SIZE(sizeof(zend_trait_alias)); |
|||
i++; |
|||
} |
|||
ADD_SIZE(sizeof(zend_trait_alias*) * (i + 1)); |
|||
} |
|||
|
|||
if (ce->trait_precedences) { |
|||
int i = 0; |
|||
|
|||
while (ce->trait_precedences[i]) { |
|||
ADD_SIZE(ce->trait_precedences[i]->trait_method->mname_len+1); |
|||
ADD_SIZE(ce->trait_precedences[i]->trait_method->cname_len+1); |
|||
ADD_SIZE(sizeof(zend_trait_method_reference)); |
|||
|
|||
if (ce->trait_precedences[i]->exclude_from_classes) { |
|||
int j = 0; |
|||
|
|||
while (ce->trait_precedences[i]->exclude_from_classes[j]) { |
|||
ADD_SIZE(strlen((char*)ce->trait_precedences[i]->exclude_from_classes[j]) + 1); |
|||
j++; |
|||
} |
|||
ADD_SIZE(sizeof(zend_class_entry*) * (j+1)); |
|||
} |
|||
ADD_SIZE(sizeof(zend_trait_precedence)); |
|||
i++; |
|||
} |
|||
ADD_SIZE(sizeof(zend_trait_precedence*) * (i+1)); |
|||
} |
|||
#endif |
|||
} |
|||
RETURN_SIZE(); |
|||
} |
|||
|
|||
static uint zend_accel_persist_class_table_calc(HashTable *class_table TSRMLS_DC) |
|||
{ |
|||
return zend_hash_persist_calc(class_table, (int (*)(void* TSRMLS_DC)) zend_persist_class_entry_calc, sizeof(zend_class_entry*) TSRMLS_CC); |
|||
} |
|||
|
|||
uint zend_accel_script_persist_calc(zend_persistent_script *new_persistent_script, char *key, unsigned int key_length TSRMLS_DC) |
|||
{ |
|||
START_SIZE(); |
|||
|
|||
ADD_SIZE(zend_hash_persist_calc(&new_persistent_script->function_table, (int (*)(void* TSRMLS_DC)) zend_persist_op_array_calc, sizeof(zend_op_array) TSRMLS_CC)); |
|||
ADD_SIZE(zend_accel_persist_class_table_calc(&new_persistent_script->class_table TSRMLS_CC)); |
|||
ADD_SIZE(zend_persist_op_array_calc(&new_persistent_script->main_op_array TSRMLS_CC)); |
|||
ADD_DUP_SIZE(key, key_length + 1); |
|||
ADD_DUP_SIZE(new_persistent_script->full_path, new_persistent_script->full_path_len + 1); |
|||
ADD_DUP_SIZE(new_persistent_script, sizeof(zend_persistent_script)); |
|||
|
|||
RETURN_SIZE(); |
|||
} |
|||
@ -0,0 +1,473 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#include <errno.h> |
|||
#include "ZendAccelerator.h" |
|||
#include "zend_shared_alloc.h" |
|||
#ifdef HAVE_UNISTD_H |
|||
# include <unistd.h> |
|||
#endif |
|||
#include <fcntl.h> |
|||
#ifndef ZEND_WIN32 |
|||
# include <sys/types.h> |
|||
# include <dirent.h> |
|||
# include <signal.h> |
|||
# include <sys/stat.h> |
|||
# include <stdio.h> |
|||
#endif |
|||
|
|||
#ifdef HAVE_MPROTECT |
|||
# include "sys/mman.h" |
|||
#endif |
|||
|
|||
#define TMP_DIR "/tmp" |
|||
#define SEM_FILENAME_PREFIX ".ZendSem." |
|||
#define S_H(s) g_shared_alloc_handler->s |
|||
|
|||
/* True globals */ |
|||
static zend_bool locked; |
|||
/* old/new mapping. We can use true global even for ZTS because its usage |
|||
is wrapped with exclusive lock anyway */ |
|||
static HashTable xlat_table; |
|||
static const zend_shared_memory_handlers *g_shared_alloc_handler = NULL; |
|||
static const char *g_shared_model; |
|||
/* pointer to globals allocated in SHM and shared across processes */ |
|||
zend_smm_shared_globals *smm_shared_globals; |
|||
|
|||
#ifndef ZEND_WIN32 |
|||
int lock_file; |
|||
static char lockfile_name[sizeof(TMP_DIR)+sizeof(SEM_FILENAME_PREFIX)+8]; |
|||
#endif |
|||
|
|||
static const zend_shared_memory_handler_entry handler_table[] = { |
|||
#if USE_MMAP |
|||
{ "mmap", &zend_alloc_mmap_handlers }, |
|||
#endif |
|||
#if USE_SHM |
|||
{ "shm", &zend_alloc_shm_handlers }, |
|||
#endif |
|||
#if USE_SHM_OPEN |
|||
{ "posix", &zend_alloc_posix_handlers }, |
|||
#endif |
|||
#ifdef ZEND_WIN32 |
|||
{ "win32", &zend_alloc_win32_handlers }, |
|||
#endif |
|||
{ NULL, NULL} |
|||
}; |
|||
|
|||
#ifndef ZEND_WIN32 |
|||
void zend_shared_alloc_create_lock(void) |
|||
{ |
|||
int val; |
|||
|
|||
sprintf(lockfile_name, "%s/%sXXXXXX", TMP_DIR, SEM_FILENAME_PREFIX); |
|||
lock_file = mkstemp(lockfile_name); |
|||
fchmod(lock_file, 0666); |
|||
|
|||
if (lock_file == -1) { |
|||
zend_accel_error(ACCEL_LOG_FATAL, "Unable to create lock file: %s (%d)", strerror(errno), errno); |
|||
} |
|||
val = fcntl(lock_file, F_GETFD, 0); |
|||
val |= FD_CLOEXEC; |
|||
fcntl(lock_file, F_SETFD, val); |
|||
|
|||
unlink(lockfile_name); |
|||
} |
|||
#endif |
|||
|
|||
static void no_memory_bailout(int allocate_size, char *error) |
|||
{ |
|||
zend_accel_error(ACCEL_LOG_FATAL, "Unable to allocate shared memory segment of %d bytes: %s: %s (%d)", allocate_size, error?error:"unknown", strerror(errno), errno ); |
|||
} |
|||
|
|||
static void copy_shared_segments(void *to, void *from, int count, int size) |
|||
{ |
|||
zend_shared_segment **shared_segments_v = (zend_shared_segment **)to; |
|||
void *shared_segments_to_p = ((char *)to + count*(sizeof(void *))); |
|||
void *shared_segments_from_p = from; |
|||
int i; |
|||
|
|||
for(i=0;i<count;i++) { |
|||
shared_segments_v[i] = shared_segments_to_p; |
|||
memcpy(shared_segments_to_p, shared_segments_from_p, size); |
|||
shared_segments_to_p = ((char *)shared_segments_to_p + size); |
|||
shared_segments_from_p = ((char *)shared_segments_from_p + size); |
|||
} |
|||
} |
|||
|
|||
static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, int requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in) |
|||
{ |
|||
int res; |
|||
g_shared_alloc_handler = he->handler; |
|||
g_shared_model = he->name; |
|||
ZSMMG(shared_segments) = NULL; |
|||
ZSMMG(shared_segments_count) = 0; |
|||
|
|||
res = S_H(create_segments)(requested_size, shared_segments_p, shared_segments_count, error_in); |
|||
|
|||
if( res ) { |
|||
/* this model works! */ |
|||
return res; |
|||
} |
|||
if(*shared_segments_p) { |
|||
int i; |
|||
/* cleanup */ |
|||
for(i=0;i<*shared_segments_count;i++) { |
|||
if((*shared_segments_p)[i]->p && (int)(*shared_segments_p)[i]->p != -1) { |
|||
S_H(detach_segment)((*shared_segments_p)[i]); |
|||
} |
|||
} |
|||
free(*shared_segments_p); |
|||
*shared_segments_p = NULL; |
|||
} |
|||
g_shared_alloc_handler = NULL; |
|||
return ALLOC_FAILURE; |
|||
} |
|||
|
|||
int zend_shared_alloc_startup(int requested_size) |
|||
{ |
|||
zend_shared_segment **tmp_shared_segments; |
|||
size_t shared_segments_array_size; |
|||
zend_smm_shared_globals tmp_shared_globals, *p_tmp_shared_globals; |
|||
char *error_in = NULL; |
|||
const zend_shared_memory_handler_entry *he; |
|||
int res = ALLOC_FAILURE; |
|||
|
|||
TSRMLS_FETCH(); |
|||
|
|||
/* shared_free must be valid before we call zend_shared_alloc() |
|||
* - make it temporarily point to a local variable |
|||
*/ |
|||
smm_shared_globals = &tmp_shared_globals; |
|||
ZSMMG(shared_free) = requested_size; /* goes to tmp_shared_globals.shared_free */ |
|||
|
|||
zend_shared_alloc_create_lock(); |
|||
|
|||
if(ZCG(accel_directives).memory_model && ZCG(accel_directives).memory_model[0]) { |
|||
char* model = ZCG(accel_directives).memory_model; |
|||
/* "cgi" is really "shm"... */ |
|||
if( strncmp(ZCG(accel_directives).memory_model,"cgi",4) == 0 ){ |
|||
model = "shm"; |
|||
} |
|||
|
|||
for(he = handler_table; he->name; he++) { |
|||
if(strcmp(model, he->name) == 0) { |
|||
res=zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in); |
|||
if( res ) { |
|||
/* this model works! */ |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if( res == FAILED_REATTACHED ){ |
|||
smm_shared_globals = NULL; |
|||
return res; |
|||
} |
|||
|
|||
if(!g_shared_alloc_handler) { |
|||
/* try memory handlers in order */ |
|||
for(he = handler_table; he->name; he++) { |
|||
res=zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in); |
|||
if( res ) { |
|||
/* this model works! */ |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if(!g_shared_alloc_handler) { |
|||
no_memory_bailout(requested_size, error_in); |
|||
return ALLOC_FAILURE; |
|||
} |
|||
|
|||
if( res == SUCCESSFULLY_REATTACHED ){ |
|||
return res; |
|||
} |
|||
|
|||
shared_segments_array_size = ZSMMG(shared_segments_count)*S_H(segment_type_size)(); |
|||
|
|||
/* move shared_segments and shared_free to shared memory */ |
|||
locked = 1; /* no need to perform a real lock at this point */ |
|||
p_tmp_shared_globals = (zend_smm_shared_globals *) zend_shared_alloc(sizeof(zend_smm_shared_globals)); |
|||
|
|||
tmp_shared_segments = zend_shared_alloc(shared_segments_array_size+ZSMMG(shared_segments_count)*sizeof(void *)); |
|||
copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)()); |
|||
|
|||
*p_tmp_shared_globals = tmp_shared_globals; |
|||
smm_shared_globals = p_tmp_shared_globals; |
|||
|
|||
free(ZSMMG(shared_segments)); |
|||
ZSMMG(shared_segments) = tmp_shared_segments; |
|||
|
|||
ZSMMG(shared_memory_state).positions = (int *) zend_shared_alloc(sizeof(int)*ZSMMG(shared_segments_count)); |
|||
locked = 0; |
|||
|
|||
return res; |
|||
} |
|||
|
|||
void zend_shared_alloc_shutdown(void) |
|||
{ |
|||
zend_shared_segment **tmp_shared_segments; |
|||
size_t shared_segments_array_size; |
|||
zend_smm_shared_globals tmp_shared_globals; |
|||
int i; |
|||
|
|||
tmp_shared_globals = *smm_shared_globals; |
|||
smm_shared_globals = &tmp_shared_globals; |
|||
shared_segments_array_size = ZSMMG(shared_segments_count)*(S_H(segment_type_size)()+sizeof(void *)); |
|||
tmp_shared_segments = emalloc(shared_segments_array_size); |
|||
copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)()); |
|||
ZSMMG(shared_segments) = tmp_shared_segments; |
|||
|
|||
for(i=0; i<ZSMMG(shared_segments_count); i++) { |
|||
S_H(detach_segment)(ZSMMG(shared_segments)[i]); |
|||
} |
|||
efree(ZSMMG(shared_segments)); |
|||
ZSMMG(shared_segments) = NULL; |
|||
g_shared_alloc_handler = NULL; |
|||
#ifndef ZEND_WIN32 |
|||
close(lock_file); |
|||
#endif |
|||
locked = 0; |
|||
} |
|||
|
|||
#define SHARED_ALLOC_FAILED() { \ |
|||
TSRMLS_FETCH(); \ |
|||
\ |
|||
zend_accel_error(ACCEL_LOG_WARNING, "Not enough free shared space to allocate %ld bytes (%ld bytes free)", (long)size, (long)ZSMMG(shared_free)); \ |
|||
ZSMMG(memory_exhausted) = 1; \ |
|||
zend_accel_schedule_restart(TSRMLS_C); \ |
|||
} |
|||
|
|||
void *zend_shared_alloc(size_t size) |
|||
{ |
|||
int i; |
|||
unsigned int block_size = size+sizeof(zend_shared_memory_block_header); |
|||
|
|||
#if 1 |
|||
if (!locked) { |
|||
zend_accel_error(ACCEL_LOG_ERROR, "Shared memory lock not obtained"); |
|||
} |
|||
#endif |
|||
if (block_size > ZSMMG(shared_free)) { /* No hope to find a big-enough block */ |
|||
SHARED_ALLOC_FAILED(); |
|||
return NULL; |
|||
} |
|||
for (i=0; i<ZSMMG(shared_segments_count); i++) { |
|||
if (ZSMMG(shared_segments)[i]->size-ZSMMG(shared_segments)[i]->pos >= block_size) { /* found a valid block */ |
|||
zend_shared_memory_block_header *p = (zend_shared_memory_block_header *) (((char *) ZSMMG(shared_segments)[i]->p)+ZSMMG(shared_segments)[i]->pos); |
|||
int remainder = block_size % PLATFORM_ALIGNMENT; |
|||
void *retval; |
|||
|
|||
if (remainder!=0) { |
|||
size += PLATFORM_ALIGNMENT-remainder; |
|||
block_size += PLATFORM_ALIGNMENT-remainder; |
|||
} |
|||
ZSMMG(shared_segments)[i]->pos += block_size; |
|||
ZSMMG(shared_free) -= block_size; |
|||
p->size = size; |
|||
retval = ((char *) p)+sizeof(zend_shared_memory_block_header); |
|||
memset(retval, 0, size); |
|||
return retval; |
|||
} |
|||
} |
|||
SHARED_ALLOC_FAILED(); |
|||
return NULL; |
|||
} |
|||
|
|||
int zend_shared_memdup_size(void *source, size_t size) |
|||
{ |
|||
void **old_p; |
|||
|
|||
if (zend_hash_index_find(&xlat_table, (ulong) source, (void **) &old_p)==SUCCESS) { |
|||
/* we already duplicated this pointer */ |
|||
return 0; |
|||
} |
|||
zend_shared_alloc_register_xlat_entry(source, source); |
|||
return ZEND_ALIGNED_SIZE(size); |
|||
} |
|||
|
|||
void *_zend_shared_memdup(void *source, size_t size, zend_bool free_source TSRMLS_DC) |
|||
{ |
|||
void **old_p, *retval; |
|||
|
|||
if (zend_hash_index_find(&xlat_table, (ulong) source, (void **) &old_p)==SUCCESS) { |
|||
/* we already duplicated this pointer */ |
|||
return *old_p; |
|||
} |
|||
retval = ZCG(mem);; |
|||
ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size)); |
|||
memcpy(retval, source, size); |
|||
if (free_source) { |
|||
interned_efree((char*)source); |
|||
} |
|||
zend_shared_alloc_register_xlat_entry(source, retval); |
|||
return retval; |
|||
} |
|||
|
|||
void zend_shared_alloc_safe_unlock(TSRMLS_D) |
|||
{ |
|||
if (locked) { |
|||
zend_shared_alloc_unlock(TSRMLS_C); |
|||
} |
|||
} |
|||
|
|||
#ifndef ZEND_WIN32 |
|||
/* name l_type l_whence l_start l_len */ |
|||
static FLOCK_STRUCTURE(mem_write_lock, F_WRLCK, SEEK_SET, 0, 1); |
|||
static FLOCK_STRUCTURE(mem_write_unlock, F_UNLCK, SEEK_SET, 0, 1); |
|||
#endif |
|||
|
|||
void zend_shared_alloc_lock(TSRMLS_D) |
|||
{ |
|||
#ifndef ZEND_WIN32 |
|||
#if 0 |
|||
/* this will happen once per process, and will un-globalize mem_write_lock */ |
|||
if (mem_write_lock.l_pid == -1) { |
|||
mem_write_lock.l_pid = getpid(); |
|||
} |
|||
#endif |
|||
|
|||
while (1) { |
|||
if (fcntl(lock_file, F_SETLKW, &mem_write_lock) == -1) { |
|||
if (errno == EINTR) { |
|||
continue; |
|||
} |
|||
zend_accel_error(ACCEL_LOG_ERROR, "Cannot create lock - %s (%d)", strerror(errno), errno); |
|||
} |
|||
break; |
|||
} |
|||
#else |
|||
zend_shared_alloc_lock_win32(); |
|||
#endif |
|||
|
|||
locked=1; |
|||
|
|||
/* Prepare translation table |
|||
* |
|||
* Make it persistent so that it uses malloc() and allocated blocks |
|||
* won't be taken from space which is freed by efree in memdup. |
|||
* Otherwise it leads to false matches in memdup check. |
|||
*/ |
|||
zend_hash_init(&xlat_table, 100, NULL, NULL, 1); |
|||
} |
|||
|
|||
void zend_shared_alloc_unlock(TSRMLS_D) |
|||
{ |
|||
/* Destroy translation table */ |
|||
zend_hash_destroy(&xlat_table); |
|||
|
|||
locked=0; |
|||
|
|||
#ifndef ZEND_WIN32 |
|||
if (fcntl(lock_file, F_SETLK, &mem_write_unlock) == -1) { |
|||
zend_accel_error(ACCEL_LOG_ERROR, "Cannot remove lock - %s (%d)", strerror(errno), errno); |
|||
} |
|||
#else |
|||
zend_shared_alloc_unlock_win32(); |
|||
#endif |
|||
} |
|||
|
|||
void zend_shared_alloc_clear_xlat_table(void) |
|||
{ |
|||
zend_hash_clean(&xlat_table); |
|||
} |
|||
|
|||
void zend_shared_alloc_register_xlat_entry(const void *old, const void *new) |
|||
{ |
|||
zend_hash_index_update(&xlat_table, (ulong) old, (void*)&new, sizeof(void *), NULL); |
|||
} |
|||
|
|||
void *zend_shared_alloc_get_xlat_entry(const void *old) |
|||
{ |
|||
void **retval; |
|||
|
|||
if (zend_hash_index_find(&xlat_table, (ulong) old, (void **) &retval)==FAILURE) { |
|||
return NULL; |
|||
} |
|||
return *retval; |
|||
} |
|||
|
|||
size_t zend_shared_alloc_get_free_memory(void) |
|||
{ |
|||
return ZSMMG(shared_free); |
|||
} |
|||
|
|||
size_t zend_shared_alloc_get_largest_free_block(void) |
|||
{ |
|||
int i; |
|||
size_t largest_block_size=0; |
|||
|
|||
for (i=0; i<ZSMMG(shared_segments_count); i++) { |
|||
size_t block_size = ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos; |
|||
|
|||
if (block_size>largest_block_size) { |
|||
largest_block_size = block_size; |
|||
} |
|||
} |
|||
return largest_block_size; |
|||
} |
|||
|
|||
void zend_shared_alloc_save_state(void) |
|||
{ |
|||
int i; |
|||
|
|||
for (i=0; i<ZSMMG(shared_segments_count); i++) { |
|||
ZSMMG(shared_memory_state).positions[i] = ZSMMG(shared_segments)[i]->pos; |
|||
} |
|||
ZSMMG(shared_memory_state).shared_free = ZSMMG(shared_free); |
|||
} |
|||
|
|||
void zend_shared_alloc_restore_state(void) |
|||
{ |
|||
int i; |
|||
|
|||
for (i=0; i<ZSMMG(shared_segments_count); i++) { |
|||
ZSMMG(shared_segments)[i]->pos = ZSMMG(shared_memory_state).positions[i]; |
|||
} |
|||
ZSMMG(shared_free) = ZSMMG(shared_memory_state).shared_free; |
|||
ZSMMG(memory_exhausted) = 0; |
|||
ZSMMG(wasted_shared_memory) = 0; |
|||
} |
|||
|
|||
const char *zend_accel_get_shared_model() |
|||
{ |
|||
return g_shared_model; |
|||
} |
|||
|
|||
void zend_accel_shared_protect(int mode TSRMLS_DC) |
|||
{ |
|||
#ifdef HAVE_MPROTECT |
|||
int i; |
|||
|
|||
if (mode) { |
|||
mode = PROT_READ; |
|||
} else { |
|||
mode = PROT_READ|PROT_WRITE; |
|||
} |
|||
|
|||
for(i=0; i < ZSMMG(shared_segments_count); i++) { |
|||
mprotect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->size, mode); |
|||
} |
|||
#endif |
|||
} |
|||
@ -0,0 +1,166 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| Zend Optimizer+ | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1998-2013 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 3.01 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available through the world-wide-web at the following url: | |
|||
| http://www.php.net/license/3_01.txt | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Andi Gutmans <andi@zend.com> | |
|||
| Zeev Suraski <zeev@zend.com> | |
|||
| Stanislav Malyshev <stas@zend.com> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef ZEND_SHARED_ALLOC_H |
|||
#define ZEND_SHARED_ALLOC_H |
|||
|
|||
#include "zend.h" |
|||
|
|||
#if defined(__APPLE__) && defined(__MACH__) /* darwin */ |
|||
# define USE_SHM_OPEN 1 |
|||
# define USE_MMAP 1 |
|||
#elif defined(__linux__) || defined(_AIX) |
|||
# define USE_SHM 1 |
|||
# define USE_MMAP 1 |
|||
#elif defined(__FreeBSD__) |
|||
# define USE_SHM_OPEN 1 |
|||
# define USE_MMAP 1 |
|||
# define USE_SHM 1 |
|||
#elif defined(__sparc) || defined(__sun) |
|||
# define USE_SHM_OPEN 1 |
|||
# define USE_SHM 1 |
|||
# if defined(__i386) |
|||
# define USE_MMAP 1 |
|||
# endif |
|||
#endif |
|||
|
|||
#define ALLOC_FAILURE 0 |
|||
#define ALLOC_SUCCESS 1 |
|||
#define FAILED_REATTACHED 2 |
|||
#define SUCCESSFULLY_REATTACHED 4 |
|||
#define ALLOC_FAIL_MAPPING 8 |
|||
|
|||
typedef struct _zend_shared_segment { |
|||
size_t size; |
|||
size_t pos; /* position for simple stack allocator */ |
|||
void *p; |
|||
} zend_shared_segment; |
|||
|
|||
typedef int (*create_segments_t)(size_t requested_size, zend_shared_segment ***shared_segments, int *shared_segment_count, char **error_in); |
|||
typedef int (*detach_segment_t)(zend_shared_segment *shared_segment); |
|||
|
|||
typedef struct { |
|||
create_segments_t create_segments; |
|||
detach_segment_t detach_segment; |
|||
size_t (*segment_type_size)(void); |
|||
} zend_shared_memory_handlers; |
|||
|
|||
typedef struct _handler_entry { |
|||
const char *name; |
|||
zend_shared_memory_handlers *handler; |
|||
} zend_shared_memory_handler_entry; |
|||
|
|||
typedef struct _zend_shared_memory_block_header { |
|||
int size; |
|||
} zend_shared_memory_block_header; |
|||
|
|||
typedef struct _zend_shared_memory_state { |
|||
int *positions; /* current positions for each segment */ |
|||
int shared_free; /* amount of free shared memory */ |
|||
} zend_shared_memory_state; |
|||
|
|||
typedef struct _zend_smm_shared_globals { |
|||
/* Shared Memory Manager */ |
|||
zend_shared_segment **shared_segments; |
|||
/* Number of allocated shared segments */ |
|||
int shared_segments_count; |
|||
/* Amount of free shared memory */ |
|||
size_t shared_free; |
|||
/* Amount of shared memory allocated by garbage */ |
|||
int wasted_shared_memory; |
|||
/* No more shared memory flag */ |
|||
zend_bool memory_exhausted; |
|||
/* Saved Shared Allocator State */ |
|||
zend_shared_memory_state shared_memory_state; |
|||
/* Pointer to the application's shared data structures */ |
|||
void *app_shared_globals; |
|||
} zend_smm_shared_globals; |
|||
|
|||
extern zend_smm_shared_globals *smm_shared_globals; |
|||
|
|||
#define ZSMMG(element) (smm_shared_globals->element) |
|||
|
|||
#define SHARED_ALLOC_REATTACHED (SUCCESS+1) |
|||
|
|||
int zend_shared_alloc_startup(int requested_size); |
|||
void zend_shared_alloc_shutdown(void); |
|||
|
|||
/* allocate shared memory block */ |
|||
void *zend_shared_alloc(size_t size); |
|||
|
|||
/* copy into shared memory */ |
|||
void *_zend_shared_memdup(void *p, size_t size, zend_bool free_source TSRMLS_DC); |
|||
int zend_shared_memdup_size(void *p, size_t size); |
|||
|
|||
typedef union _align_test { |
|||
void *ptr; |
|||
double dbl; |
|||
long lng; |
|||
} align_test; |
|||
|
|||
#if ZEND_GCC_VERSION >= 2000 |
|||
# define PLATFORM_ALIGNMENT (__alignof__ (align_test)) |
|||
#else |
|||
# define PLATFORM_ALIGNMENT (sizeof(align_test)) |
|||
#endif |
|||
|
|||
#define ZEND_ALIGNED_SIZE(size) \ |
|||
((size + PLATFORM_ALIGNMENT - 1) & ~(PLATFORM_ALIGNMENT - 1)) |
|||
|
|||
/* exclusive locking */ |
|||
void zend_shared_alloc_lock(TSRMLS_D); |
|||
void zend_shared_alloc_unlock(TSRMLS_D); /* returns the allocated size during lock..unlock */ |
|||
void zend_shared_alloc_safe_unlock(TSRMLS_D); |
|||
|
|||
/* old/new mapping functions */ |
|||
void zend_shared_alloc_clear_xlat_table(void); |
|||
void zend_shared_alloc_register_xlat_entry(const void *old, const void *new); |
|||
void *zend_shared_alloc_get_xlat_entry(const void *old); |
|||
|
|||
size_t zend_shared_alloc_get_free_memory(void); |
|||
void zend_shared_alloc_save_state(void); |
|||
void zend_shared_alloc_restore_state(void); |
|||
size_t zend_shared_alloc_get_largest_free_block(void); |
|||
const char *zend_accel_get_shared_model(); |
|||
|
|||
/* memory write protection */ |
|||
void zend_accel_shared_protect(int mode TSRMLS_DC); |
|||
|
|||
#ifdef USE_MMAP |
|||
extern zend_shared_memory_handlers zend_alloc_mmap_handlers; |
|||
#endif |
|||
|
|||
#ifdef USE_SHM |
|||
extern zend_shared_memory_handlers zend_alloc_shm_handlers; |
|||
#endif |
|||
|
|||
#ifdef USE_SHM_OPEN |
|||
extern zend_shared_memory_handlers zend_alloc_posix_handlers; |
|||
#endif |
|||
|
|||
#ifdef ZEND_WIN32 |
|||
extern zend_shared_memory_handlers zend_alloc_win32_handlers; |
|||
void zend_shared_alloc_create_lock(); |
|||
void zend_shared_alloc_lock_win32(); |
|||
void zend_shared_alloc_unlock_win32(); |
|||
#endif |
|||
|
|||
#endif /* ZEND_SHARED_ALLOC_H */ |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue