mirror of
https://github.com/php/php-src.git
synced 2025-01-24 12:43:38 +08:00
Merge Zend Optimizer+
git-subtree-dir: ext/opcache git-subtree-mainline:b1dbfb7357
git-subtree-split:8d35170c5f
This commit is contained in:
commit
34d3202eda
87
ext/opcache/.gitignore
vendored
Normal file
87
ext/opcache/.gitignore
vendored
Normal file
@ -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
|
14
ext/opcache/.travis.yml
Normal file
14
ext/opcache/.travis.yml
Normal file
@ -0,0 +1,14 @@
|
||||
language: php
|
||||
php:
|
||||
- 5.2
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
|
||||
before_script:
|
||||
- phpize
|
||||
- ./configure --enable-optimizer-plus
|
||||
- make
|
||||
|
||||
script:
|
||||
- php -d zend_extension=`pwd`/modules/ZendOptimizerPlus.so -m | grep "Zend Optimizer+"
|
68
ext/opcache/LICENSE
Normal file
68
ext/opcache/LICENSE
Normal file
@ -0,0 +1,68 @@
|
||||
--------------------------------------------------------------------
|
||||
The PHP License, version 3.01
|
||||
Copyright (c) 1999 - 2012 The PHP Group. All rights reserved.
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, is permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
3. The name "PHP" must not be used to endorse or promote products
|
||||
derived from this software without prior written permission. For
|
||||
written permission, please contact group@php.net.
|
||||
|
||||
4. Products derived from this software may not be called "PHP", nor
|
||||
may "PHP" appear in their name, without prior written permission
|
||||
from group@php.net. You may indicate that your software works in
|
||||
conjunction with PHP by saying "Foo for PHP" instead of calling
|
||||
it "PHP Foo" or "phpfoo"
|
||||
|
||||
5. The PHP Group may publish revised and/or new versions of the
|
||||
license from time to time. Each version will be given a
|
||||
distinguishing version number.
|
||||
Once covered code has been published under a particular version
|
||||
of the license, you may always continue to use it under the terms
|
||||
of that version. You may also choose to use such covered code
|
||||
under the terms of any subsequent version of the license
|
||||
published by the PHP Group. No one other than the PHP Group has
|
||||
the right to modify the terms applicable to covered code created
|
||||
under this License.
|
||||
|
||||
6. Redistributions of any form whatsoever must retain the following
|
||||
acknowledgment:
|
||||
"This product includes PHP software, freely available from
|
||||
<http://www.php.net/software/>".
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
|
||||
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
|
||||
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
This software consists of voluntary contributions made by many
|
||||
individuals on behalf of the PHP Group.
|
||||
|
||||
The PHP Group can be contacted via Email at group@php.net.
|
||||
|
||||
For more information on the PHP Group and the PHP project,
|
||||
please see <http://www.php.net>.
|
||||
|
||||
PHP includes the Zend Engine, freely available at
|
||||
<http://www.zend.com>.
|
2024
ext/opcache/Optimizer/block_pass.c
Normal file
2024
ext/opcache/Optimizer/block_pass.c
Normal file
File diff suppressed because it is too large
Load Diff
126
ext/opcache/Optimizer/nop_removal.c
Normal file
126
ext/opcache/Optimizer/nop_removal.c
Normal 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 (j = 0; j < op_array->last_brk_cont; j++) {
|
||||
op_array->brk_cont_array[j].brk -= shiftlist[op_array->brk_cont_array[j].brk];
|
||||
op_array->brk_cont_array[j].cont -= shiftlist[op_array->brk_cont_array[j].cont];
|
||||
op_array->brk_cont_array[j].start -= shiftlist[op_array->brk_cont_array[j].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 != (zend_uint)-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 != (zend_uint)-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
FREE_ALLOCA(shiftlist);
|
||||
}
|
222
ext/opcache/Optimizer/optimize_temp_vars_5.c
Normal file
222
ext/opcache/Optimizer/optimize_temp_vars_5.c
Normal file
@ -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 "operands", 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;
|
||||
}
|
3
ext/opcache/Optimizer/pass10.c
Normal file
3
ext/opcache/Optimizer/pass10.c
Normal file
@ -0,0 +1,3 @@
|
||||
if (((ZEND_OPTIMIZER_PASS_10|ZEND_OPTIMIZER_PASS_5) & OPTIMIZATION_LEVEL) == ZEND_OPTIMIZER_PASS_10) {
|
||||
nop_removal(op_array);
|
||||
}
|
391
ext/opcache/Optimizer/pass1_5.c
Normal file
391
ext/opcache/Optimizer/pass1_5.c
Normal file
@ -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 with 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_optimizer_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_optimizer_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_optimizer_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_optimizer_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 removal 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_optimizer_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)) {
|
||||
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_optimizer_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++;
|
||||
}
|
||||
}
|
211
ext/opcache/Optimizer/pass2.c
Normal file
211
ext/opcache/Optimizer/pass2.c
Normal file
@ -0,0 +1,211 @@
|
||||
/* 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 (0 && /* FIXME: temporary disable unsafe pattern */
|
||||
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++;
|
||||
}
|
||||
}
|
442
ext/opcache/Optimizer/pass3.c
Normal file
442
ext/opcache/Optimizer/pass3.c
Normal file
@ -0,0 +1,442 @@
|
||||
/* 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);
|
||||
}
|
3
ext/opcache/Optimizer/pass5.c
Normal file
3
ext/opcache/Optimizer/pass5.c
Normal file
@ -0,0 +1,3 @@
|
||||
if (ZEND_OPTIMIZER_PASS_5 & OPTIMIZATION_LEVEL) {
|
||||
zend_block_optimization(op_array TSRMLS_CC);
|
||||
}
|
8
ext/opcache/Optimizer/pass9.c
Normal file
8
ext/opcache/Optimizer/pass9.c
Normal file
@ -0,0 +1,8 @@
|
||||
/* pass 9
|
||||
*
|
||||
* - optimize usage of temporary variables
|
||||
*/
|
||||
|
||||
if (ZEND_OPTIMIZER_PASS_9 & OPTIMIZATION_LEVEL) {
|
||||
optimize_temporary_variables(op_array);
|
||||
}
|
139
ext/opcache/Optimizer/zend_optimizer.c
Normal file
139
ext/opcache/Optimizer/zend_optimizer.c
Normal file
@ -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_optimizer_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_optimizer_add_literal(op_array, &_c TSRMLS_CC); \
|
||||
} while (0)
|
||||
|
||||
# define LITERAL_BOOL(op, val) do { \
|
||||
zval _c; \
|
||||
ZVAL_BOOL(&_c, val); \
|
||||
op.constant = zend_optimizer_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"
|
||||
}
|
49
ext/opcache/Optimizer/zend_optimizer.h
Normal file
49
ext/opcache/Optimizer/zend_optimizer.h
Normal 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_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 jumps */
|
||||
#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
|
83
ext/opcache/Optimizer/zend_optimizer_internal.h
Normal file
83
ext/opcache/Optimizer/zend_optimizer_internal.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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) ((zend_uint)(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_bool protected; /* don't merge this block with others */
|
||||
};
|
||||
|
||||
typedef struct _zend_cfg {
|
||||
zend_code_block *blocks;
|
||||
zend_code_block **try;
|
||||
zend_code_block **catch;
|
||||
zend_code_block **loop_start;
|
||||
zend_code_block **loop_cont;
|
||||
zend_code_block **loop_brk;
|
||||
} zend_cfg;
|
||||
|
||||
struct _zend_block_source {
|
||||
zend_code_block *from;
|
||||
zend_block_source *next;
|
||||
};
|
||||
|
||||
#endif
|
202
ext/opcache/README
Normal file
202
ext/opcache/README
Normal file
@ -0,0 +1,202 @@
|
||||
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
|
||||
|
||||
$PHP_DIR/bin/phpize
|
||||
./configure \
|
||||
--with-php-config=$PHP_DIR/bin/php-config
|
||||
make
|
||||
|
||||
- Install
|
||||
|
||||
make install # this will copy opcache.so into PHP extension directory
|
||||
|
||||
- Edit php.ini
|
||||
|
||||
zend_extension=/...full path.../opcache.so
|
||||
|
||||
NOTE: In case you are going to use Zend Optimizer+ together with Xdebug,
|
||||
be sure that Xdebug is loaded after Optimizer+. "php -v" must show Xdebug
|
||||
after Optimizer+.
|
||||
|
||||
- Restart PHP
|
||||
|
||||
Speed Tuning
|
||||
-------------
|
||||
|
||||
We recommend the following configuration options for best performance.
|
||||
|
||||
opcache.memory_consumption=128
|
||||
opcache.interned_strings_buffer=8
|
||||
opcache.max_accelerated_files=4000
|
||||
opcache.revalidate_freq=60
|
||||
opcache.fast_shutdown=1
|
||||
opcache.enable_cli=1
|
||||
|
||||
You also may add the following, but it may break some applications and
|
||||
frameworks. Please, read description of these directives and add them on your
|
||||
own risk.
|
||||
|
||||
opcache.save_comments=0
|
||||
opcache.enable_file_override=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
|
||||
------------------------
|
||||
|
||||
opcache.enable (default "1")
|
||||
Optimizer+ On/Off switch. When set to Off, code is not optimized.
|
||||
|
||||
opcache.memory_consumption (default "64")
|
||||
The Optimizer+ shared memory storage size. The amount of memory for storing
|
||||
precompiled PHP code in Mbytes.
|
||||
|
||||
opcache.interned_strings_buffer (default "4")
|
||||
The amount of memory for interned strings in Mbytes.
|
||||
|
||||
opcache.max_accelerated_files (default "2000")
|
||||
The maximum number of keys (scripts) in the Optimizer+ hash table.
|
||||
The number is actually 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.
|
||||
|
||||
opcache.max_wasted_percentage (default "5")
|
||||
The maximum percentage of "wasted" memory until a restart is scheduled.
|
||||
|
||||
opcache.use_cwd (default "1")
|
||||
When this directive is enabled, the Optimizer+ appends the current working
|
||||
directory to the script key, thus eliminating possible collisions between
|
||||
files with the same name (basename). Disabling the directive improves
|
||||
performance, but may break existing applications.
|
||||
|
||||
opcache.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 frequency of the check is controlled by the directive
|
||||
"opcache.revalidate_freq".
|
||||
|
||||
opcache.revalidate_freq (default "2")
|
||||
How often (in seconds) to check file timestamps for changes to the shared
|
||||
memory storage allocation. ("1" means validate once per second, but only
|
||||
once per request. "0" means always validate)
|
||||
|
||||
opcache.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.
|
||||
|
||||
opcache.save_comments (default "1")
|
||||
If disabled, all PHPDoc comments are dropped from the code to reduce the
|
||||
size of the optimized code. Disabling "Doc Comments" may break some
|
||||
existing applications and frameworks (e.g. Doctrine, ZF2, PHPUnit)
|
||||
|
||||
opcache.load_comments (default "1")
|
||||
If disabled, PHPDoc comments are not loaded from SHM, so "Doc Comments"
|
||||
may be always stored (save_comments=1), but not loaded by applications
|
||||
that don't need them anyway.
|
||||
|
||||
opcache.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.
|
||||
|
||||
opcache.enable_file_override (default "0")
|
||||
Allow file existence override (file_exists, etc.) performance feature.
|
||||
|
||||
opcache.optimization_level (default "0xffffffff")
|
||||
A bitmask, where each bit enables or disables the appropriate Optimizer+
|
||||
passes
|
||||
|
||||
opcache.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.
|
||||
|
||||
opcache.dups_fix (default "0")
|
||||
Enable this hack as a workaround for "Cannot redeclare class" errors.
|
||||
|
||||
opcache.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.
|
||||
|
||||
opcache.max_file_size (default "0")
|
||||
Allows exclusion of large files from being cached. By default all files
|
||||
are cached.
|
||||
|
||||
opcache.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.
|
||||
|
||||
opcache.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.
|
||||
|
||||
opcache.error_log
|
||||
Optimizer+ error_log file name. Empty string assumes "stderr".
|
||||
|
||||
opcache.log_verbosity_level (default "1")
|
||||
All 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 messages (level 4).
|
||||
|
||||
opcache.preferred_memory_model
|
||||
Preferred Shared Memory back-end. Leave empty and let the system decide.
|
||||
|
||||
opcache.protect_memory (default "0")
|
||||
Protect the shared memory from unexpected writing during script execution.
|
||||
Useful for internal debugging only.
|
||||
|
||||
opcache.mmap_base
|
||||
Mapping base of shared memory segments (for Windows only). All the PHP
|
||||
processes have to map shared memory into the same address space. This
|
||||
directive allows to manually fix the "Unable to reattach to base address"
|
||||
errors.
|
2625
ext/opcache/ZendAccelerator.c
Normal file
2625
ext/opcache/ZendAccelerator.c
Normal file
File diff suppressed because it is too large
Load Diff
370
ext/opcache/ZendAccelerator.h
Normal file
370
ext/opcache/ZendAccelerator.h
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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.1-dev"
|
||||
/* 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 embedded 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)
|
||||
# elif defined(__GNUC__) && __GNUC__ >= 4
|
||||
# define ZEND_EXT_API __attribute__ ((visibility("default")))
|
||||
# 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 */
|
||||
unsigned 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 load_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;
|
||||
long max_file_size;
|
||||
#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 cache */
|
||||
/* initially it contains only internal functions */
|
||||
HashTable function_table;
|
||||
int internal_functions_count;
|
||||
int counted; /* the process uses shared memory */
|
||||
zend_bool enabled;
|
||||
zend_bool locked; /* thread obtained exclusive lock */
|
||||
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 length */
|
||||
char *include_path_key; /* one letter key of current "include_path" */
|
||||
char *include_path; /* current section of "include_path" directive */
|
||||
int include_path_len; /* "include_path" string length */
|
||||
int include_path_check;
|
||||
time_t request_time;
|
||||
/* 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_bool accel_startup_ok;
|
||||
|
||||
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 */
|
346
ext/opcache/config.m4
Normal file
346
ext/opcache/config.m4
Normal file
@ -0,0 +1,346 @@
|
||||
dnl
|
||||
dnl $Id$
|
||||
dnl
|
||||
|
||||
PHP_ARG_ENABLE(opcache, whether to enable Zend Optimizer+ support,
|
||||
[ --enable-opcache Enable Zend Optimizer+ support])
|
||||
|
||||
if test "$PHP_OPCACHE" != "no"; then
|
||||
|
||||
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(opcache,
|
||||
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,
|
||||
shared,,,,yes)
|
||||
|
||||
PHP_ADD_BUILD_DIR([$ext_builddir/Optimizer], 1)
|
||||
fi
|
27
ext/opcache/config.w32
Normal file
27
ext/opcache/config.w32
Normal file
@ -0,0 +1,27 @@
|
||||
ARG_ENABLE("opcache", "whether to enable Zend Optimizer+ support", "yes");
|
||||
|
||||
if (PHP_OPCACHE != "no") {
|
||||
|
||||
PHP_PGI = "no"; // workaround
|
||||
PHP_PGO = "no"; // workaround
|
||||
|
||||
EXTENSION('opcache', "\
|
||||
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(configure_module_dirname + "/Optimizer", "zend_optimizer.c", "opcache", "OptimizerObj");
|
||||
|
||||
|
||||
ADD_FLAG('CFLAGS_OPCACHE', "/I " + configure_module_dirname);
|
||||
|
||||
ADD_FLAG('CFLAGS_OPCACHE', "/Dregexec=php_regexec /Dregerror=php_regerror /Dregfree=php_regfree /Dregcomp=php_regcomp /Iext/ereg/regex");
|
||||
|
||||
}
|
134
ext/opcache/package.xml
Normal file
134
ext/opcache/package.xml
Normal file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<package
|
||||
packagerversion="1.9.4" version="2.0"
|
||||
xmlns="http://pear.php.net/dtd/package-2.0"
|
||||
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<name>zendoptimizerplus</name>
|
||||
<channel>pecl.php.net</channel>
|
||||
<summary>The Zend Optimizer+ provides faster PHP execution through opcode caching and optimization.</summary>
|
||||
<description>
|
||||
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.
|
||||
</description>
|
||||
<lead>
|
||||
<name>Dmitry Stogov</name>
|
||||
<user>dmitry</user>
|
||||
<email>dmitry@zend.com</email>
|
||||
<active>yes</active>
|
||||
</lead>
|
||||
<lead>
|
||||
<name>Zeev Suraski</name>
|
||||
<user>zeev</user>
|
||||
<email>zeev@zend.com</email>
|
||||
<active>yes</active>
|
||||
</lead>
|
||||
<lead>
|
||||
<name>Hannes Magnusson</name>
|
||||
<user>bjori</user>
|
||||
<email>bjori@php.net</email>
|
||||
<active>yes</active>
|
||||
</lead>
|
||||
<lead>
|
||||
<name>Xinchen Hui</name>
|
||||
<user>laruence</user>
|
||||
<email>laruence@php.net</email>
|
||||
<active>yes</active>
|
||||
</lead>
|
||||
<date>2013-03-04</date>
|
||||
<time>19:40:00</time>
|
||||
<version>
|
||||
<release>7.0.0</release>
|
||||
<api>7.0.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>beta</release>
|
||||
<api>beta</api>
|
||||
</stability>
|
||||
<license uri="http://www.php.net/license">PHP License</license>
|
||||
<notes>
|
||||
- Initial release
|
||||
</notes>
|
||||
<contents>
|
||||
<dir name="/">
|
||||
<file role="doc" name="README"/>
|
||||
<file role="doc" name="LICENSE"/>
|
||||
<file role="src" name="config.w32"/>
|
||||
<file role="src" name="config.m4"/>
|
||||
<file role="src" name="zend_accelerator_util_funcs.c"/>
|
||||
<file role="src" name="zend_persist_calc.c"/>
|
||||
<file role="src" name="ZendAccelerator.c"/>
|
||||
<file role="src" name="shared_alloc_mmap.c"/>
|
||||
<file role="src" name="zend_accelerator_debug.c"/>
|
||||
<file role="src" name="zend_accelerator_blacklist.c"/>
|
||||
<file role="src" name="shared_alloc_shm.c"/>
|
||||
<file role="src" name="zend_accelerator_util_funcs.h"/>
|
||||
<file role="src" name="zend_accelerator_module.h"/>
|
||||
<file role="src" name="zend_shared_alloc.h"/>
|
||||
<file role="src" name="zend_persist.h"/>
|
||||
<file role="src" name="shared_alloc_win32.c"/>
|
||||
<file role="src" name="zend_shared_alloc.c"/>
|
||||
<file role="src" name="ZendAccelerator.h"/>
|
||||
<file role="src" name="zend_persist.c"/>
|
||||
<file role="src" name="shared_alloc_posix.c"/>
|
||||
<file role="src" name="zend_accelerator_module.c"/>
|
||||
<file role="src" name="zend_accelerator_blacklist.h"/>
|
||||
<file role="src" name="zend_accelerator_hash.c"/>
|
||||
<file role="src" name="zend_accelerator_debug.h"/>
|
||||
<file role="src" name="zend_accelerator_hash.h"/>
|
||||
<dir name="Optimizer">
|
||||
<file role="src" name="pass3.c"/>
|
||||
<file role="src" name="zend_optimizer.h"/>
|
||||
<file role="src" name="nop_removal.c"/>
|
||||
<file role="src" name="pass10.c"/>
|
||||
<file role="src" name="optimize_temp_vars_5.c"/>
|
||||
<file role="src" name="zend_optimizer_internal.h"/>
|
||||
<file role="src" name="pass2.c"/>
|
||||
<file role="src" name="zend_optimizer.c"/>
|
||||
<file role="src" name="pass9.c"/>
|
||||
<file role="src" name="pass1_5.c"/>
|
||||
<file role="src" name="block_pass.c"/>
|
||||
<file role="src" name="pass5.c"/>
|
||||
</dir> <!-- Optimizer -->
|
||||
<dir name="tests">
|
||||
<file role="src" name="001_cli.phpt"/>
|
||||
<file role="src" name="skipif.inc"/>
|
||||
<file role="src" name="bug64353.phpt"/>
|
||||
<file role="src" name="issue0057.phpt"/>
|
||||
</dir> <!-- tests -->
|
||||
</dir> <!-- / -->
|
||||
</contents>
|
||||
<dependencies>
|
||||
<required>
|
||||
<php>
|
||||
<min>5.2.0</min>
|
||||
</php>
|
||||
<pearinstaller>
|
||||
<min>1.4.0b1</min>
|
||||
</pearinstaller>
|
||||
</required>
|
||||
</dependencies>
|
||||
<providesextension>zendoptimizerplus</providesextension>
|
||||
<zendextsrcrelease />
|
||||
<changelog>
|
||||
<release>
|
||||
<version>
|
||||
<release>7.0.0</release>
|
||||
<api>7.0.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>beta</release>
|
||||
<api>beta</api>
|
||||
</stability>
|
||||
<date>2013-03-04</date>
|
||||
<license uri="http://www.php.net/license">PHP License</license>
|
||||
<notes>
|
||||
- Initial release.
|
||||
</notes>
|
||||
</release>
|
||||
</changelog>
|
||||
</package>
|
78
ext/opcache/shared_alloc_mmap.c
Normal file
78
ext/opcache/shared_alloc_mmap.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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_shared_alloc.h"
|
||||
|
||||
#ifdef USE_MMAP
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.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 *));
|
||||
if (!*shared_segments_p) {
|
||||
*error_in = "calloc";
|
||||
return ALLOC_FAILURE;
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
#endif /* USE_MMAP */
|
98
ext/opcache/shared_alloc_posix.c
Normal file
98
ext/opcache/shared_alloc_posix.c
Normal file
@ -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> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "zend_shared_alloc.h"
|
||||
|
||||
#ifdef USE_SHM_OPEN
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.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 *));
|
||||
if (!*shared_segments_p) {
|
||||
*error_in = "calloc";
|
||||
return ALLOC_FAILURE;
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
#endif /* USE_SHM_OPEN */
|
145
ext/opcache/shared_alloc_shm.c
Normal file
145
ext/opcache/shared_alloc_shm.c
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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_shared_alloc.h"
|
||||
|
||||
#ifdef USE_SHM
|
||||
|
||||
#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>
|
||||
|
||||
#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));
|
||||
if (!*shared_segments_p) {
|
||||
*error_in = "calloc";
|
||||
return ALLOC_FAILURE;
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
#endif /* USE_SHM */
|
340
ext/opcache/shared_alloc_win32.c
Normal file
340
ext/opcache/shared_alloc_win32.c
Normal file
@ -0,0 +1,340 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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;
|
||||
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(void)
|
||||
{
|
||||
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));
|
||||
if (!memory_mutex) {
|
||||
zend_accel_error(ACCEL_LOG_FATAL, "Cannot create mutex");
|
||||
return;
|
||||
}
|
||||
ReleaseMutex(memory_mutex);
|
||||
}
|
||||
|
||||
void zend_shared_alloc_lock_win32(void)
|
||||
{
|
||||
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(void)
|
||||
{
|
||||
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";
|
||||
fclose(fp);
|
||||
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();
|
||||
|
||||
zend_shared_alloc_lock_win32();
|
||||
/* 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 {
|
||||
zend_shared_alloc_unlock_win32();
|
||||
return ret;
|
||||
}
|
||||
} while (++map_retries < MAX_MAP_RETRIES);
|
||||
|
||||
if (map_retries == MAX_MAP_RETRIES) {
|
||||
zend_shared_alloc_unlock_win32();
|
||||
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 *));
|
||||
if (!*shared_segments_p) {
|
||||
zend_shared_alloc_unlock_win32();
|
||||
zend_win_error_message(ACCEL_LOG_FATAL, "calloc() failed", GetLastError());
|
||||
*error_in = "calloc";
|
||||
return ALLOC_FAILURE;
|
||||
}
|
||||
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_shared_alloc_unlock_win32();
|
||||
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_shared_alloc_unlock_win32();
|
||||
zend_win_error_message(ACCEL_LOG_FATAL, "Bad mapping address specified in opcache.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_shared_alloc_unlock_win32();
|
||||
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_shared_alloc_unlock_win32();
|
||||
zend_win_error_message(ACCEL_LOG_WARNING, mmap_base_file, err);
|
||||
zend_win_error_message(ACCEL_LOG_FATAL, "Unable to write base address", err);
|
||||
return ALLOC_FAILURE;
|
||||
}
|
||||
fprintf(fp, "%p\n", mapping_base);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
shared_segment->pos = 0;
|
||||
shared_segment->size = requested_size;
|
||||
|
||||
zend_shared_alloc_unlock_win32();
|
||||
|
||||
return ALLOC_SUCCESS;
|
||||
}
|
||||
|
||||
static int detach_segment(zend_shared_segment *shared_segment)
|
||||
{
|
||||
zend_shared_alloc_lock_win32();
|
||||
if (mapping_base) {
|
||||
UnmapViewOfFile(mapping_base);
|
||||
}
|
||||
CloseHandle(memfile);
|
||||
zend_shared_alloc_unlock_win32();
|
||||
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
|
||||
};
|
19
ext/opcache/tests/001_cli.phpt
Normal file
19
ext/opcache/tests/001_cli.phpt
Normal file
@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
001: O+ works in CLI
|
||||
--INI--
|
||||
zend_optimizerplus.enable=1
|
||||
zend_optimizerplus.enable_cli=1
|
||||
--SKIPIF--
|
||||
<?php require_once('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$config = accelerator_get_configuration();
|
||||
$status = accelerator_get_status();
|
||||
var_dump($config["directives"]["zend_optimizerplus.enable"]);
|
||||
var_dump($config["directives"]["zend_optimizerplus.enable_cli"]);
|
||||
var_dump($status["accelerator_enabled"]);
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
29
ext/opcache/tests/bug64353.phpt
Normal file
29
ext/opcache/tests/bug64353.phpt
Normal file
@ -0,0 +1,29 @@
|
||||
--TEST--
|
||||
Bug #64353 (Built-in classes can be unavailable with dynamic includes and Optimizer+)
|
||||
--INI--
|
||||
allow_url_include=1
|
||||
zend_optimizerplus.enable=1
|
||||
zend_optimizerplus.enable_cli=1
|
||||
--SKIPIF--
|
||||
<?php require_once('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
class BugLoader extends php_user_filter {
|
||||
public function filter($in, $out, &$consumed, $closing) {
|
||||
if (!class_exists("Test")) {
|
||||
eval("class Test extends ArrayObject {}");
|
||||
}
|
||||
while ($bucket = stream_bucket_make_writeable($in)) {
|
||||
$consumed += $bucket->datalen;
|
||||
stream_bucket_append($out, $bucket);
|
||||
}
|
||||
return PSFS_PASS_ON;
|
||||
}
|
||||
}
|
||||
|
||||
stream_filter_register('bug.test', 'BugLoader');
|
||||
include "php://filter/read=bug.test/resource=data://text/plain,<?php\n";
|
||||
echo "OK\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
OK
|
38
ext/opcache/tests/issue0057.phpt
Normal file
38
ext/opcache/tests/issue0057.phpt
Normal file
@ -0,0 +1,38 @@
|
||||
--TEST--
|
||||
ISSUE #57 (segfaults in drupal7)
|
||||
--INI--
|
||||
zend_optimizerplus.enable=1
|
||||
zend_optimizerplus.enable_cli=1
|
||||
zend_optimizerplus.optimization_level=-1
|
||||
--SKIPIF--
|
||||
<?php require_once('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class ZException extends Exception {
|
||||
}
|
||||
|
||||
function dummy($query) {
|
||||
try {
|
||||
switch ($query) {
|
||||
case 1;
|
||||
break;
|
||||
case 2;
|
||||
break;
|
||||
default:
|
||||
throw new Exception('exception');
|
||||
}
|
||||
} catch (ZException $e) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
dummy(0);
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
exception
|
3
ext/opcache/tests/skipif.inc
Normal file
3
ext/opcache/tests/skipif.inc
Normal file
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
if (!extension_loaded('Zend Optimizer+')) die('skip ZendOptimizerPlus extension not available');
|
||||
?>
|
261
ext/opcache/zend_accelerator_blacklist.c
Normal file
261
ext/opcache/zend_accelerator_blacklist.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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);
|
||||
if (!blacklist->entries) {
|
||||
zend_accel_error(ACCEL_LOG_FATAL, "Blacklist initialization: no memory\n");
|
||||
return;
|
||||
}
|
||||
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);
|
||||
if (!errbuf) {
|
||||
zend_accel_error(ACCEL_LOG_ERROR, "Blacklist compilation: no memory\n");
|
||||
return;
|
||||
}
|
||||
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)
|
||||
{
|
||||
char *regexp;
|
||||
int i, j, clen, reg_err, end = 0, rlen = 6;
|
||||
zend_regexp_list **regexp_list_it, *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);
|
||||
if (!regexp) {
|
||||
zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed\n");
|
||||
return;
|
||||
}
|
||||
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';
|
||||
|
||||
it = (zend_regexp_list*)malloc(sizeof(zend_regexp_list));
|
||||
if (!it) {
|
||||
zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed\n");
|
||||
return;
|
||||
}
|
||||
it->next = NULL;
|
||||
|
||||
if ((reg_err = regcomp(&it->comp_regex, regexp, REGEX_MODE)) != 0) {
|
||||
blacklist_report_regexp_error(&it->comp_regex, reg_err);
|
||||
}
|
||||
/* prepare for the next iteration */
|
||||
free(regexp);
|
||||
end = i + 1;
|
||||
rlen = 6;
|
||||
*regexp_list_it = it;
|
||||
regexp_list_it = &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 (path_length > 0 && buf[path_length - 1] == '\n') {
|
||||
buf[--path_length] = 0;
|
||||
if (path_length > 0 && 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);
|
||||
if (!blacklist->entries[blacklist->pos].path) {
|
||||
zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed\n");
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
49
ext/opcache/zend_accelerator_blacklist.h
Normal file
49
ext/opcache/zend_accelerator_blacklist.h
Normal 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_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 */
|
99
ext/opcache/zend_accelerator_debug.c
Normal file
99
ext/opcache/zend_accelerator_debug.c
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ZTS
|
||||
fprintf(fLog, "%s (%lu): ", time_string, (unsigned long)tsrm_thread_id());
|
||||
#else
|
||||
fprintf(fLog, "%s (%d): ", time_string, 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);
|
||||
}
|
||||
}
|
33
ext/opcache/zend_accelerator_debug.h
Normal file
33
ext/opcache/zend_accelerator_debug.h
Normal file
@ -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 */
|
224
ext/opcache/zend_accelerator_hash.c
Normal file
224
ext/opcache/zend_accelerator_hash.c
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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!");
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
98
ext/opcache/zend_accelerator_hash.h
Normal file
98
ext/opcache/zend_accelerator_hash.h
Normal file
@ -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' entries, 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 */
|
608
ext/opcache/zend_accelerator_module.c
Normal file
608
ext/opcache/zend_accelerator_module.c
Normal file
@ -0,0 +1,608 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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(opcache_reset);
|
||||
|
||||
/* Private functions */
|
||||
static ZEND_FUNCTION(opcache_get_status);
|
||||
static ZEND_FUNCTION(opcache_get_configuration);
|
||||
|
||||
static zend_function_entry accel_functions[] = {
|
||||
/* User functions */
|
||||
ZEND_FE(opcache_reset, NULL)
|
||||
/* Private functions */
|
||||
ZEND_FE(opcache_get_configuration, NULL)
|
||||
ZEND_FE(opcache_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, "opcache.memory_consumption is set below the required 8MB.\n");
|
||||
zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the minimal 8MB configuration.\n");
|
||||
|
||||
if (zend_hash_find(EG(ini_directives),
|
||||
"opcache.memory_consumption",
|
||||
sizeof("opcache.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, "opcache.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 configuration.\n");
|
||||
}
|
||||
if (size > MAX_ACCEL_FILES) {
|
||||
size = MAX_ACCEL_FILES;
|
||||
new_new_value = TOKENTOSTR(MAX_ACCEL_FILES);
|
||||
zend_accel_error(ACCEL_LOG_WARNING, "opcache.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 configuration.\n");
|
||||
}
|
||||
if (zend_hash_find(EG(ini_directives),
|
||||
"opcache.max_accelerated_files",
|
||||
sizeof("opcache.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, "opcache.max_wasted_percentage must be set between 1 and 50.\n");
|
||||
zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use 5%.\n");
|
||||
if (zend_hash_find(EG(ini_directives),
|
||||
"opcache.max_wasted_percentage",
|
||||
sizeof("opcache.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("opcache.enable" , "1", PHP_INI_SYSTEM, OnUpdateBool, enabled , zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_BOOLEAN("opcache.use_cwd" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.use_cwd , zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_BOOLEAN("opcache.validate_timestamps", "1", PHP_INI_ALL , OnUpdateBool, accel_directives.validate_timestamps, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_BOOLEAN("opcache.inherited_hack" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.inherited_hack , zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_BOOLEAN("opcache.dups_fix" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.ignore_dups , zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_BOOLEAN("opcache.revalidate_path" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.revalidate_path , zend_accel_globals, accel_globals)
|
||||
|
||||
STD_PHP_INI_ENTRY("opcache.log_verbosity_level" , "1" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.log_verbosity_level, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.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("opcache.interned_strings_buffer", "4" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals)
|
||||
#endif
|
||||
STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "2000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.max_wasted_percentage" , "5" , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage, accel_directives.max_wasted_percentage, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateLong, accel_directives.consistency_checks, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.force_restart_timeout, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.revalidate_freq" , "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.revalidate_freq, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.preferred_memory_model", "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.memory_model, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.blacklist_filename" , "" , PHP_INI_SYSTEM, OnUpdateAccelBlacklist, accel_directives.user_blacklist_filename, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.max_file_size" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.max_file_size, zend_accel_globals, accel_globals)
|
||||
|
||||
STD_PHP_INI_ENTRY("opcache.protect_memory" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.protect_memory, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.save_comments" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.save_comments, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.load_comments" , "1" , PHP_INI_ALL, OnUpdateBool, accel_directives.load_comments, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.fast_shutdown" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.fast_shutdown, zend_accel_globals, accel_globals)
|
||||
|
||||
STD_PHP_INI_ENTRY("opcache.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_BOOLEAN("opcache.enable_file_override" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_override_enabled, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals)
|
||||
STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals)
|
||||
|
||||
#ifdef ZEND_WIN32
|
||||
STD_PHP_INI_ENTRY("opcache.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);
|
||||
#elif ZEND_EXTENSION_API_NO == PHP_5_3_X_API_NO
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
#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(enabled) && accel_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(enabled) && accel_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) && accel_startup_ok && ZCSG(accelerator_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(enabled)) {
|
||||
if (!accel_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(void)
|
||||
{
|
||||
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(enabled) || !accel_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(opcache_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 ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
array_init(return_value);
|
||||
|
||||
/* Trivia */
|
||||
add_assoc_bool(return_value, "opcache_enabled", 1 /*ZCG(enabled) && accel_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, "num_cached_keys", ZCSG(hash).num_entries);
|
||||
add_assoc_long(statistics, "max_cached_keys", 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, "opcache_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0);
|
||||
add_assoc_zval(return_value, "opcache_statistics", statistics);
|
||||
|
||||
/* accelerated 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(opcache_get_configuration)
|
||||
{
|
||||
zval *directives,*version,*blacklist;
|
||||
|
||||
/* keep the compiler happy */
|
||||
(void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used;
|
||||
|
||||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
array_init(return_value);
|
||||
|
||||
/* directives */
|
||||
MAKE_STD_ZVAL(directives);
|
||||
array_init(directives);
|
||||
add_assoc_bool(directives, "opcache.enable", ZCG(enabled));
|
||||
add_assoc_bool(directives, "opcache.enable_cli", ZCG(accel_directives).enable_cli);
|
||||
add_assoc_bool(directives, "opcache.use_cwd", ZCG(accel_directives).use_cwd);
|
||||
add_assoc_bool(directives, "opcache.validate_timestamps", ZCG(accel_directives).validate_timestamps);
|
||||
add_assoc_bool(directives, "opcache.inherited_hack", ZCG(accel_directives).inherited_hack);
|
||||
add_assoc_bool(directives, "opcache.dups_fix", ZCG(accel_directives).ignore_dups);
|
||||
add_assoc_bool(directives, "opcache.revalidate_path", ZCG(accel_directives).revalidate_path);
|
||||
|
||||
add_assoc_long(directives, "opcache.log_verbosity_level", ZCG(accel_directives).log_verbosity_level);
|
||||
add_assoc_long(directives, "opcache.memory_consumption", ZCG(accel_directives).memory_consumption);
|
||||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
|
||||
add_assoc_long(directives, "opcache.interned_strings_buffer",ZCG(accel_directives).interned_strings_buffer);
|
||||
#endif
|
||||
add_assoc_long(directives, "opcache.max_accelerated_files", ZCG(accel_directives).max_accelerated_files);
|
||||
add_assoc_double(directives, "opcache.max_wasted_percentage", ZCG(accel_directives).max_wasted_percentage);
|
||||
add_assoc_long(directives, "opcache.consistency_checks", ZCG(accel_directives).consistency_checks);
|
||||
add_assoc_long(directives, "opcache.force_restart_timeout", ZCG(accel_directives).force_restart_timeout);
|
||||
add_assoc_long(directives, "opcache.revalidate_freq", ZCG(accel_directives).revalidate_freq);
|
||||
add_assoc_string(directives, "opcache.preferred_memory_model", STRING_NOT_NULL(ZCG(accel_directives).memory_model), 1);
|
||||
add_assoc_string(directives, "opcache.blacklist_filename", STRING_NOT_NULL(ZCG(accel_directives).user_blacklist_filename), 1);
|
||||
add_assoc_long(directives, "opcache.max_file_size", ZCG(accel_directives).max_file_size);
|
||||
add_assoc_string(directives, "opcache.error_log", STRING_NOT_NULL(ZCG(accel_directives).error_log), 1);
|
||||
|
||||
add_assoc_bool(directives, "opcache.protect_memory", ZCG(accel_directives).protect_memory);
|
||||
add_assoc_bool(directives, "opcache.save_comments", ZCG(accel_directives).save_comments);
|
||||
add_assoc_bool(directives, "opcache.load_comments", ZCG(accel_directives).load_comments);
|
||||
add_assoc_bool(directives, "opcache.fast_shutdown", ZCG(accel_directives).fast_shutdown);
|
||||
add_assoc_bool(directives, "opcache.enable_file_override", ZCG(accel_directives).file_override_enabled);
|
||||
add_assoc_long(directives, "opcache.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, "opcache_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(opcache_reset)
|
||||
{
|
||||
/* keep the compiler happy */
|
||||
(void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used;
|
||||
|
||||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
zend_accel_schedule_restart(TSRMLS_C);
|
||||
RETURN_TRUE;
|
||||
}
|
28
ext/opcache/zend_accelerator_module.h
Normal file
28
ext/opcache/zend_accelerator_module.h
Normal file
@ -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_ACCELERATOR_MODULE_H
|
||||
#define ZEND_ACCELERATOR_MODULE_H
|
||||
|
||||
int start_accel_module(void);
|
||||
void zend_accel_override_file_functions(TSRMLS_D);
|
||||
|
||||
#endif /* _ZEND_ACCELERATOR_MODULE_H */
|
1007
ext/opcache/zend_accelerator_util_funcs.c
Normal file
1007
ext/opcache/zend_accelerator_util_funcs.c
Normal file
File diff suppressed because it is too large
Load Diff
49
ext/opcache/zend_accelerator_util_funcs.h
Normal file
49
ext/opcache/zend_accelerator_util_funcs.h
Normal 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:
|
||||
*/
|
680
ext/opcache/zend_persist.c
Normal file
680
ext/opcache/zend_persist.c
Normal file
@ -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 jumps 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;
|
||||
}
|
29
ext/opcache/zend_persist.h
Normal file
29
ext/opcache/zend_persist.h
Normal file
@ -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 */
|
343
ext/opcache/zend_persist_calc.c
Normal file
343
ext/opcache/zend_persist_calc.c
Normal file
@ -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();
|
||||
}
|
489
ext/opcache/zend_shared_alloc.c
Normal file
489
ext/opcache/zend_shared_alloc.c
Normal file
@ -0,0 +1,489 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 */
|
||||
/* 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
|
||||
#ifdef ZTS
|
||||
static MUTEX_T zts_lock;
|
||||
#endif
|
||||
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[] = {
|
||||
#ifdef USE_MMAP
|
||||
{ "mmap", &zend_alloc_mmap_handlers },
|
||||
#endif
|
||||
#ifdef USE_SHM
|
||||
{ "shm", &zend_alloc_shm_handlers },
|
||||
#endif
|
||||
#ifdef 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;
|
||||
|
||||
#ifdef ZTS
|
||||
zts_lock = tsrm_mutex_alloc();
|
||||
#endif
|
||||
|
||||
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", sizeof("cgi")) == 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 */
|
||||
ZCG(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));
|
||||
ZCG(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
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
#define MIN_FREE_MEMORY 64*1024
|
||||
|
||||
#define SHARED_ALLOC_FAILED() do { \
|
||||
zend_accel_error(ACCEL_LOG_WARNING, "Not enough free shared space to allocate %ld bytes (%ld bytes free)", (long)size, (long)ZSMMG(shared_free)); \
|
||||
if (zend_shared_alloc_get_largest_free_block() < MIN_FREE_MEMORY) { \
|
||||
ZSMMG(memory_exhausted) = 1; \
|
||||
zend_accel_schedule_restart(TSRMLS_C); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void *zend_shared_alloc(size_t size)
|
||||
{
|
||||
int i;
|
||||
unsigned int block_size = size + sizeof(zend_shared_memory_block_header);
|
||||
TSRMLS_FETCH();
|
||||
|
||||
#if 1
|
||||
if (!ZCG(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 (ZCG(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
|
||||
|
||||
#ifdef ZTS
|
||||
tsrm_mutex_lock(zts_lock);
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
ZCG(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);
|
||||
|
||||
ZCG(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);
|
||||
}
|
||||
#ifdef ZTS
|
||||
tsrm_mutex_unlock(zts_lock);
|
||||
#endif
|
||||
#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);
|
||||
}
|
||||
|
||||
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(void)
|
||||
{
|
||||
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
|
||||
}
|
186
ext/opcache/zend_shared_alloc.h
Normal file
186
ext/opcache/zend_shared_alloc.h
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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"
|
||||
#include "ZendAccelerator.h"
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__) /* darwin */
|
||||
# ifdef HAVE_SHM_MMAP_POSIX
|
||||
# define USE_SHM_OPEN 1
|
||||
# endif
|
||||
# ifdef HAVE_SHM_MMAP_ANON
|
||||
# define USE_MMAP 1
|
||||
# endif
|
||||
#elif defined(__linux__) || defined(_AIX)
|
||||
# ifdef HAVE_SHM_IPC
|
||||
# define USE_SHM 1
|
||||
# endif
|
||||
# ifdef HAVE_SHM_MMAP_ANON
|
||||
# define USE_MMAP 1
|
||||
# endif
|
||||
#elif defined(__sparc) || defined(__sun)
|
||||
# ifdef HAVE_SHM_MMAP_POSIX
|
||||
# define USE_SHM_OPEN 1
|
||||
# endif
|
||||
# ifdef HAVE_SHM_IPC
|
||||
# define USE_SHM 1
|
||||
# endif
|
||||
# if defined(__i386)
|
||||
# ifdef HAVE_SHM_MMAP_ANON
|
||||
# define USE_MMAP 1
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
# ifdef HAVE_SHM_MMAP_POSIX
|
||||
# define USE_SHM_OPEN 1
|
||||
# endif
|
||||
# ifdef HAVE_SHM_MMAP_ANON
|
||||
# define USE_MMAP 1
|
||||
# endif
|
||||
# ifdef HAVE_SHM_IPC
|
||||
# define USE_SHM 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);
|
||||
const char *zend_accel_get_shared_model(void);
|
||||
|
||||
/* 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);
|
||||
void zend_shared_alloc_lock_win32(void);
|
||||
void zend_shared_alloc_unlock_win32(void);
|
||||
#endif
|
||||
|
||||
#endif /* ZEND_SHARED_ALLOC_H */
|
Loading…
Reference in New Issue
Block a user