summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-05-06 23:46:49 +0300
committerDmitry Stogov <dmitry@zend.com>2015-05-06 23:46:49 +0300
commit3abde432314787f697533c88e7afd64946676306 (patch)
treeebcba1326f8844a0f90c41ffdd28bf5c9092644c
parent500b884f17d76629cb066da55145a83659b8acfb (diff)
downloadphp-git-3abde432314787f697533c88e7afd64946676306.tar.gz
Added experimental (disabled by default) file based opcode cache.
-rw-r--r--NEWS2
-rw-r--r--ext/opcache/ZendAccelerator.c400
-rw-r--r--ext/opcache/ZendAccelerator.h10
-rw-r--r--ext/opcache/config.m48
-rw-r--r--ext/opcache/config.w327
-rw-r--r--ext/opcache/tests/001_cli.phpt1
-rw-r--r--ext/opcache/tests/blacklist-win32.phpt1
-rw-r--r--ext/opcache/tests/blacklist.phpt1
-rw-r--r--ext/opcache/tests/bug69281.phpt1
-rw-r--r--ext/opcache/tests/is_script_cached.phpt1
-rw-r--r--ext/opcache/zend_accelerator_module.c74
-rw-r--r--ext/opcache/zend_accelerator_util_funcs.c25
-rw-r--r--ext/opcache/zend_accelerator_util_funcs.h2
-rw-r--r--ext/opcache/zend_file_cache.c1301
-rw-r--r--ext/opcache/zend_file_cache.h26
-rw-r--r--ext/opcache/zend_persist.c2
-rw-r--r--ext/opcache/zend_shared_alloc.c40
-rw-r--r--ext/opcache/zend_shared_alloc.h2
-rw-r--r--ext/phar/tests/create_new_and_modify.phpt2
-rw-r--r--ext/phar/tests/tar/create_new_and_modify.phpt2
-rw-r--r--ext/phar/tests/zip/create_new_and_modify.phpt2
-rwxr-xr-xrun-tests.php15
22 files changed, 1815 insertions, 110 deletions
diff --git a/NEWS b/NEWS
index 83d456dad5..81032f978f 100644
--- a/NEWS
+++ b/NEWS
@@ -141,6 +141,8 @@
. Removed mcrypt_ecb(), mcrypt_cbc(), mcrypt_cfb(), mcrypt_ofb(). (Nikita)
- Opcache:
+ . Added experimental (disabled by default) file based opcode cache.
+ (Dmitry, Laruence, Anatol)
. Fixed bug with try blocks being removed when extended_info opcode
generation is turned on. (Laruence)
. Fixed bug #68644 (strlen incorrect : mbstring + func_overload=2 +UTF-8
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index ede6efd94c..847746b01f 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -41,6 +41,11 @@
#include "zend_accelerator_hash.h"
#include "ext/pcre/php_pcre.h"
+#ifdef HAVE_OPCACHE_FILE_CACHE
+# include "zend_file_cache.h"
+# include "ext/standard/md5.h"
+#endif
+
#ifndef ZEND_WIN32
#include <netdb.h>
#endif
@@ -311,6 +316,12 @@ zend_string *accel_new_interned_string(zend_string *str)
uint idx;
Bucket *p;
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ if (ZCG(accel_directives).file_cache_only) {
+ return str;
+ }
+#endif
+
if (IS_ACCEL_INTERNED(str)) {
/* this is already an interned string */
return str;
@@ -727,7 +738,7 @@ static accel_time_t zend_get_file_handle_timestamp_win(zend_file_handle *file_ha
}
#endif
-static accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size)
+accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size)
{
zend_stat_t statbuf;
#ifdef ZEND_WIN32
@@ -896,29 +907,6 @@ int validate_timestamp_and_record(zend_persistent_script *persistent_script, zen
}
}
-static unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script)
-{
- signed char *mem = (signed char*)persistent_script->mem;
- size_t size = persistent_script->size;
- size_t persistent_script_check_block_size = ((char *)&(persistent_script->dynamic_members)) - (char *)persistent_script;
- unsigned int checksum = ADLER32_INIT;
-
- if (mem < (signed char*)persistent_script) {
- checksum = zend_adler32(checksum, mem, (signed char*)persistent_script - mem);
- size -= (signed char*)persistent_script - mem;
- mem += (signed char*)persistent_script - mem;
- }
-
- zend_adler32(checksum, mem, persistent_script_check_block_size);
- mem += sizeof(*persistent_script);
- size -= sizeof(*persistent_script);
-
- if (size > 0) {
- checksum = zend_adler32(checksum, mem, size);
- }
- return checksum;
-}
-
/* Instead of resolving full real path name each time we need to identify file,
* we create a key that consist from requested file name, current working
* directory, current include_path, etc */
@@ -1080,6 +1068,15 @@ int zend_accel_invalidate(const char *filename, int filename_len, zend_bool forc
zend_persistent_script *persistent_script;
if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ if (ZCG(accel_directives).file_cache) {
+ realpath = accelerator_orig_zend_resolve_path(filename, filename_len);
+ if (realpath) {
+ zend_file_cache_invalidate(realpath);
+ zend_string_release(realpath);
+ }
+ }
+#endif
return FAILURE;
}
@@ -1089,6 +1086,12 @@ int zend_accel_invalidate(const char *filename, int filename_len, zend_bool forc
return FAILURE;
}
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ if (ZCG(accel_directives).file_cache) {
+ zend_file_cache_invalidate(realpath);
+ }
+#endif
+
persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath);
if (persistent_script && !persistent_script->corrupted) {
zend_file_handle file_handle;
@@ -1118,7 +1121,7 @@ int zend_accel_invalidate(const char *filename, int filename_len, zend_bool forc
}
accelerator_shm_read_unlock();
- efree(realpath);
+ zend_string_release(realpath);
return SUCCESS;
}
@@ -1145,6 +1148,64 @@ static void zend_accel_add_key(char *key, unsigned int key_length, zend_accel_ha
}
}
+#ifdef HAVE_OPCACHE_FILE_CACHE
+static zend_persistent_script *cache_script_in_file_cache(zend_persistent_script *new_persistent_script, int *from_shared_memory)
+{
+ uint memory_used;
+
+ /* Check if script may be stored in shared memory */
+ if (!zend_accel_script_persistable(new_persistent_script)) {
+ return new_persistent_script;
+ }
+
+ if (!zend_accel_script_optimize(new_persistent_script)) {
+ return new_persistent_script;
+ }
+
+ zend_shared_alloc_init_xlat_table();
+
+ /* Calculate the required memory size */
+ memory_used = zend_accel_script_persist_calc(new_persistent_script, NULL, 0);
+
+ /* Allocate memory block */
+#ifdef __SSE2__
+ /* Align to 64-byte boundary */
+ ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 64);
+ ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
+#else
+ ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used);
+#endif
+
+ /* Copy into shared memory */
+ new_persistent_script = zend_accel_script_persist(new_persistent_script, NULL, 0);
+
+ zend_shared_alloc_destroy_xlat_table();
+
+ new_persistent_script->is_phar =
+ new_persistent_script->full_path &&
+ strstr(new_persistent_script->full_path->val, ".phar") &&
+ !strstr(new_persistent_script->full_path->val, "://");
+
+ /* Consistency check */
+ if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
+ zend_accel_error(
+ ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
+ "Internal error: wrong size calculation: %s start=0x%08x, end=0x%08x, real=0x%08x\n",
+ new_persistent_script->full_path->val,
+ new_persistent_script->mem,
+ (char *)new_persistent_script->mem + new_persistent_script->size,
+ ZCG(mem));
+ }
+
+ new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
+
+ zend_file_cache_script_store(new_persistent_script);
+
+ *from_shared_memory = 1;
+ return new_persistent_script;
+}
+#endif
+
static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, char *key, unsigned int key_length, int *from_shared_memory)
{
zend_accel_hash_entry *bucket;
@@ -1188,6 +1249,9 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr
}
}
+
+ zend_shared_alloc_init_xlat_table();
+
/* Calculate the required memory size */
memory_used = zend_accel_script_persist_calc(new_persistent_script, key, key_length);
@@ -1200,6 +1264,7 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr
ZCG(mem) = zend_shared_alloc(memory_used);
#endif
if (!ZCG(mem)) {
+ zend_shared_alloc_destroy_xlat_table();
zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
zend_shared_alloc_unlock();
return new_persistent_script;
@@ -1208,6 +1273,8 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr
/* Copy into shared memory */
new_persistent_script = zend_accel_script_persist(new_persistent_script, &key, key_length);
+ zend_shared_alloc_destroy_xlat_table();
+
new_persistent_script->is_phar =
new_persistent_script->full_path &&
strstr(new_persistent_script->full_path->val, ".phar") &&
@@ -1250,6 +1317,14 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr
zend_shared_alloc_unlock();
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ if (ZCG(accel_directives).file_cache) {
+ SHM_PROTECT();
+ zend_file_cache_script_store(new_persistent_script);
+ SHM_UNPROTECT();
+ }
+#endif
+
*from_shared_memory = 1;
return new_persistent_script;
}
@@ -1315,7 +1390,7 @@ static void zend_accel_init_auto_globals(void)
}
}
-static zend_persistent_script *compile_and_cache_file(zend_file_handle *file_handle, int type, char *key, unsigned int key_length, zend_op_array **op_array_p, int *from_shared_memory)
+static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, char *key, unsigned int key_length, zend_op_array **op_array_p)
{
zend_persistent_script *new_persistent_script;
zend_op_array *orig_active_op_array;
@@ -1460,9 +1535,81 @@ static zend_persistent_script *compile_and_cache_file(zend_file_handle *file_han
zend_string_hash_val(new_persistent_script->full_path);
/* Now persistent_script structure is ready in process memory */
- return cache_script_in_shared_memory(new_persistent_script, key, key_length, from_shared_memory);
+ return new_persistent_script;
}
+#ifdef HAVE_OPCACHE_FILE_CACHE
+zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
+{
+ zend_persistent_script *persistent_script;
+ zend_op_array *op_array = NULL;
+ int from_memory; /* if the script we've got is stored in SHM */
+
+ if (is_stream_path(file_handle->filename) &&
+ !is_cacheable_stream_path(file_handle->filename)) {
+ return accelerator_orig_compile_file(file_handle, type);
+ }
+
+ if (!file_handle->opened_path) {
+ if (file_handle->type == ZEND_HANDLE_FILENAME &&
+ accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) == FAILURE) {
+ if (type == ZEND_REQUIRE) {
+ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
+ zend_bailout();
+ } else {
+ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
+ }
+ return NULL;
+ }
+ }
+
+ persistent_script = zend_file_cache_script_load(file_handle);
+ if (persistent_script) {
+ /* see bug #15471 (old BTS) */
+ if (persistent_script->full_path) {
+ if (!EG(current_execute_data) || !EG(current_execute_data)->opline ||
+ !EG(current_execute_data)->func ||
+ !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
+ EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
+ (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
+ EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
+ if (zend_hash_add_empty_element(&EG(included_files), persistent_script->full_path) != NULL) {
+ /* ext/phar has to load phar's metadata into memory */
+ if (persistent_script->is_phar) {
+ php_stream_statbuf ssb;
+ char *fname = emalloc(sizeof("phar://") + persistent_script->full_path->len);
+
+ memcpy(fname, "phar://", sizeof("phar://") - 1);
+ memcpy(fname + sizeof("phar://") - 1, persistent_script->full_path->val, persistent_script->full_path->len + 1);
+ php_stream_stat_path(fname, &ssb);
+ efree(fname);
+ }
+ }
+ }
+ }
+ zend_file_handle_dtor(file_handle);
+
+ persistent_script->dynamic_members.last_used = ZCG(request_time);
+
+ if (persistent_script->ping_auto_globals_mask) {
+ zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask);
+ }
+
+ return zend_accel_load_script(persistent_script, 1);
+ }
+
+ persistent_script = opcache_compile_file(file_handle, type, NULL, 0, &op_array);
+
+ if (persistent_script) {
+ from_memory = 0;
+ persistent_script = cache_script_in_file_cache(persistent_script, &from_memory);
+ return zend_accel_load_script(persistent_script, from_memory);
+ }
+
+ return op_array;
+}
+#endif
+
/* zend_compile() replacement */
zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
{
@@ -1471,11 +1618,21 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
int key_length;
int from_shared_memory; /* if the script we've got is stored in SHM */
- if (!file_handle->filename || !ZCG(enabled) || !accel_startup_ok ||
- (!ZCG(counted) && !ZCSG(accelerator_enabled)) ||
- (ZCSG(restart_in_progress) && accel_restart_is_active())) {
+ if (!file_handle->filename || !ZCG(enabled) || !accel_startup_ok) {
/* The Accelerator is disabled, act as if without the Accelerator */
return accelerator_orig_compile_file(file_handle, type);
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ } else if (ZCG(accel_directives).file_cache_only) {
+ return file_cache_compile_file(file_handle, type);
+#endif
+ } else if ((!ZCG(counted) && !ZCSG(accelerator_enabled)) ||
+ (ZCSG(restart_in_progress) && accel_restart_is_active())) {
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ if (ZCG(accel_directives).file_cache) {
+ return file_cache_compile_file(file_handle, type);
+ }
+#endif
+ return accelerator_orig_compile_file(file_handle, type);
}
/* In case this callback is called from include_once, require_once or it's
@@ -1602,6 +1759,13 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
}
}
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ /* Check the second level cache */
+ if (!persistent_script && ZCG(accel_directives).file_cache) {
+ persistent_script = zend_file_cache_script_load(file_handle);
+ }
+#endif
+
/* If script was not found or invalidated by validate_timestamps */
if (!persistent_script) {
uint32_t old_const_num = zend_hash_next_free_element(EG(zend_constants));
@@ -1620,7 +1784,10 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
* If it isn't compile_and_cache_file() changes the flag to 0
*/
from_shared_memory = 0;
- persistent_script = compile_and_cache_file(file_handle, type, key, key_length, &op_array, &from_shared_memory);
+ persistent_script = opcache_compile_file(file_handle, type, key, key ? key_length : 0, &op_array);
+ if (persistent_script) {
+ persistent_script = cache_script_in_shared_memory(persistent_script, key, key ? key_length : 0, &from_shared_memory);
+ }
/* Caching is disabled, returning op_array;
* or something went wrong during compilation, returning NULL
@@ -1830,7 +1997,6 @@ static void accel_activate(void)
zend_accel_copy_internal_functions();
}
- SHM_UNPROTECT();
/* PHP-5.4 and above return "double", but we use 1 sec precision */
ZCG(auto_globals_mask) = 0;
ZCG(request_time) = (time_t)sapi_get_request_time();
@@ -1839,6 +2005,23 @@ static void accel_activate(void)
ZCG(include_path_key_len) = 0;
ZCG(include_path_check) = 1;
+ /* check if ZCG(function_table) wasn't somehow polluted on the way */
+ if (ZCG(internal_functions_count) != zend_hash_num_elements(&ZCG(function_table))) {
+ zend_accel_error(ACCEL_LOG_WARNING, "Internal functions count changed - was %d, now %d", ZCG(internal_functions_count), zend_hash_num_elements(&ZCG(function_table)));
+ }
+
+ ZCG(cwd) = NULL;
+ ZCG(cwd_key_len) = 0;
+ ZCG(cwd_check) = 1;
+
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ if (ZCG(accel_directives).file_cache_only) {
+ return;
+ }
+#endif
+
+ SHM_UNPROTECT();
+
if (ZCG(counted)) {
#ifdef ZTS
zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for thread id %d", tsrm_thread_id());
@@ -1894,15 +2077,6 @@ static void accel_activate(void)
zend_shared_alloc_unlock();
}
- /* check if ZCG(function_table) wasn't somehow polluted on the way */
- if (ZCG(internal_functions_count) != zend_hash_num_elements(&ZCG(function_table))) {
- zend_accel_error(ACCEL_LOG_WARNING, "Internal functions count changed - was %d, now %d", ZCG(internal_functions_count), zend_hash_num_elements(&ZCG(function_table)));
- }
-
- ZCG(cwd) = NULL;
- ZCG(cwd_key_len) = 0;
- ZCG(cwd_check) = 1;
-
SHM_PROTECT();
if (ZCSG(last_restart_time) != ZCG(last_restart_time)) {
@@ -2285,6 +2459,38 @@ static void accel_globals_dtor(zend_accel_globals *accel_globals)
}
}
+#ifdef HAVE_OPCACHE_FILE_CACHE
+
+#define ZEND_BIN_ID "BIN_" ZEND_TOSTR(SIZEOF_CHAR) ZEND_TOSTR(SIZEOF_INT) ZEND_TOSTR(SIZEOF_LONG) ZEND_TOSTR(SIZEOF_SIZE_T) ZEND_TOSTR(SIZEOF_ZEND_LONG) ZEND_TOSTR(ZEND_MM_ALIGNMENT)
+
+static void accel_gen_system_id(void)
+{
+ PHP_MD5_CTX context;
+ unsigned char digest[16], c;
+ char *md5str = ZCG(system_id);
+ int i;
+
+ PHP_MD5Init(&context);
+ PHP_MD5Update(&context, PHP_VERSION, sizeof(PHP_VERSION)-1);
+ PHP_MD5Update(&context, ZEND_EXTENSION_BUILD_ID, sizeof(ZEND_EXTENSION_BUILD_ID)-1);
+ PHP_MD5Update(&context, ZEND_BIN_ID, sizeof(ZEND_BIN_ID)-1);
+ if (strstr(PHP_VERSION, "-dev") != 0) {
+ /* Development versions may be changed from build to build */
+ PHP_MD5Update(&context, __DATE__, sizeof(__DATE__)-1);
+ PHP_MD5Update(&context, __TIME__, sizeof(__TIME__)-1);
+ }
+ PHP_MD5Final(digest, &context);
+ for (i = 0; i < 16; i++) {
+ c = digest[i] >> 4;
+ c = (c <= 9) ? c + '0' : c - 10 + 'a';
+ md5str[i * 2] = c;
+ c = digest[i] & 0x0f;
+ c = (c <= 9) ? c + '0' : c - 10 + 'a';
+ md5str[(i * 2) + 1] = c;
+ }
+}
+#endif
+
static int accel_startup(zend_extension *extension)
{
zend_function *func;
@@ -2306,6 +2512,10 @@ static int accel_startup(zend_extension *extension)
return FAILURE;
}
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ accel_gen_system_id();
+#endif
+
/* no supported SAPI found - disable acceleration and stop initialization */
if (accel_find_sapi() == FAILURE) {
accel_startup_ok = 0;
@@ -2321,49 +2531,73 @@ static int accel_startup(zend_extension *extension)
if (ZCG(enabled) == 0) {
return SUCCESS ;
}
+
/********************************************/
/* End of non-SHM dependent initializations */
/********************************************/
- switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
- case ALLOC_SUCCESS:
- if (zend_accel_init_shm() == FAILURE) {
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ if (!ZCG(accel_directives).file_cache_only) {
+#else
+ if (1) {
+#endif
+ switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
+ case ALLOC_SUCCESS:
+ if (zend_accel_init_shm() == FAILURE) {
+ accel_startup_ok = 0;
+ return FAILURE;
+ }
+ break;
+ case ALLOC_FAILURE:
accel_startup_ok = 0;
- return FAILURE;
- }
- break;
- case ALLOC_FAILURE:
- accel_startup_ok = 0;
- zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
- return SUCCESS;
- case SUCCESSFULLY_REATTACHED:
- accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
- zend_shared_alloc_lock();
- orig_new_interned_string = zend_new_interned_string;
- orig_interned_strings_snapshot = zend_interned_strings_snapshot;
- orig_interned_strings_restore = zend_interned_strings_restore;
-
- zend_new_interned_string = accel_new_interned_string_for_php;
- zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
- zend_interned_strings_restore = accel_interned_strings_restore_for_php;
+ zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
+ return SUCCESS;
+ case SUCCESSFULLY_REATTACHED:
+ accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
+ zend_shared_alloc_lock();
+ orig_new_interned_string = zend_new_interned_string;
+ orig_interned_strings_snapshot = zend_interned_strings_snapshot;
+ orig_interned_strings_restore = zend_interned_strings_restore;
+
+ zend_new_interned_string = accel_new_interned_string_for_php;
+ zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
+ zend_interned_strings_restore = accel_interned_strings_restore_for_php;
#ifndef ZTS
- accel_use_shm_interned_strings();
+ accel_use_shm_interned_strings();
#endif
- zend_shared_alloc_unlock();
- break;
- case FAILED_REATTACHED:
- accel_startup_ok = 0;
- zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can not reattach to exiting shared memory.");
- return SUCCESS;
- break;
- }
+ zend_shared_alloc_unlock();
+ break;
+ case FAILED_REATTACHED:
+ accel_startup_ok = 0;
+ zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can not reattach to exiting shared memory.");
+ return SUCCESS;
+ break;
+ }
- /* remeber the last restart time in the process memory */
- ZCG(last_restart_time) = ZCSG(last_restart_time);
+ /* from this point further, shared memory is supposed to be OK */
- /* from this point further, shared memory is supposed to be OK */
+ /* remeber the last restart time in the process memory */
+ ZCG(last_restart_time) = ZCSG(last_restart_time);
+
+ /* Init auto-global strings */
+ zend_accel_init_auto_globals();
+
+ zend_shared_alloc_lock();
+ zend_shared_alloc_save_state();
+ zend_shared_alloc_unlock();
+
+ SHM_PROTECT();
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ } else if (!ZCG(accel_directives).file_cache) {
+ accel_startup_ok = 0;
+ zend_accel_error(ACCEL_LOG_FATAL, "opcache.file_cache_only is set without a proper setting of opcache.file_cache");
+ return SUCCESS;
+ } else {
+ accel_shared_globals = calloc(1, sizeof(zend_accel_shared_globals));
- /* Init auto-global strings */
- zend_accel_init_auto_globals();
+ /* Init auto-global strings */
+ zend_accel_init_auto_globals();
+#endif
+ }
/* Override compiler */
accelerator_orig_compile_file = zend_compile_file;
@@ -2395,12 +2629,6 @@ static int accel_startup(zend_extension *extension)
ini_entry->on_modify = accel_include_path_on_modify;
}
- zend_shared_alloc_lock();
- zend_shared_alloc_save_state();
- zend_shared_alloc_unlock();
-
- SHM_PROTECT();
-
accel_startup_ok = 1;
/* Override file_exists(), is_file() and is_readable() */
@@ -2430,6 +2658,7 @@ static void accel_free_ts_resources()
void accel_shutdown(void)
{
zend_ini_entry *ini_entry;
+ zend_bool file_cache_only = 0;
zend_accel_blacklist_shutdown(&accel_blacklist);
@@ -2453,8 +2682,15 @@ void accel_shutdown(void)
zend_interned_strings_snapshot = orig_interned_strings_snapshot;
zend_interned_strings_restore = orig_interned_strings_restore;
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ file_cache_only = ZCG(accel_directives).file_cache_only;
+#endif
+
accel_free_ts_resources();
- zend_shared_alloc_shutdown();
+
+ if (!file_cache_only) {
+ zend_shared_alloc_shutdown();
+ }
zend_compile_file = accelerator_orig_compile_file;
if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h
index a41d0a94d0..2c6584a1e2 100644
--- a/ext/opcache/ZendAccelerator.h
+++ b/ext/opcache/ZendAccelerator.h
@@ -215,6 +215,11 @@ typedef struct _zend_accel_directives {
zend_long max_file_size;
zend_long interned_strings_buffer;
char *restrict_api;
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ char *file_cache;
+ zend_bool file_cache_only;
+ zend_bool file_cache_consistency_checks;
+#endif
} zend_accel_directives;
typedef struct _zend_accel_globals {
@@ -238,6 +243,10 @@ typedef struct _zend_accel_globals {
int auto_globals_mask;
time_t request_time;
time_t last_restart_time; /* used to synchronize SHM and in-process caches */
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ char system_id[32];
+#endif
+ HashTable xlat_table;
/* preallocated shared-memory block to save current script */
void *mem;
void *arena_mem;
@@ -302,6 +311,7 @@ extern char *zps_api_failure_reason;
void accel_shutdown(void);
void zend_accel_schedule_restart(zend_accel_restart_reason reason);
void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason);
+accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size);
int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle);
int zend_accel_invalidate(const char *filename, int filename_len, zend_bool force);
int zend_accel_script_optimize(zend_persistent_script *persistent_script);
diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4
index b10567b468..856f24ab58 100644
--- a/ext/opcache/config.m4
+++ b/ext/opcache/config.m4
@@ -5,8 +5,15 @@ dnl
PHP_ARG_ENABLE(opcache, whether to enable Zend OPcache support,
[ --disable-opcache Disable Zend OPcache support], yes)
+PHP_ARG_ENABLE(opcache-file, whether to enable file based caching (experimental),
+[ --enable-opcache-file Enable file based caching], no)
+
if test "$PHP_OPCACHE" != "no"; then
+ if test "$PHP_OPCACHE_FILE" == "yes"; then
+ AC_DEFINE(HAVE_OPCACHE_FILE_CACHE, 1, [Define to enable file based caching (experimental)])
+ fi
+
AC_CHECK_FUNC(mprotect,[
AC_DEFINE(HAVE_MPROTECT, 1, [Define if you have mprotect() function])
])
@@ -371,6 +378,7 @@ fi
zend_accelerator_module.c \
zend_persist.c \
zend_persist_calc.c \
+ zend_file_cache.c \
zend_shared_alloc.c \
zend_accelerator_util_funcs.c \
shared_alloc_shm.c \
diff --git a/ext/opcache/config.w32 b/ext/opcache/config.w32
index edcbc320c6..dcc2501ffc 100644
--- a/ext/opcache/config.w32
+++ b/ext/opcache/config.w32
@@ -1,9 +1,15 @@
ARG_ENABLE("opcache", "whether to enable Zend OPcache support", "yes");
+ARG_ENABLE("opcache-file", "whether to enable file based caching (experimental)", "no");
+
var PHP_OPCACHE_PGO = false;
if (PHP_OPCACHE != "no") {
+ if (PHP_OPCACHE_FILE == "yes") {
+ AC_DEFINE('HAVE_OPCACHE_FILE_CACHE', 1, 'Define to enable file based caching (experimental)');
+ }
+
EXTENSION('opcache', "\
ZendAccelerator.c \
zend_accelerator_blacklist.c \
@@ -13,6 +19,7 @@ if (PHP_OPCACHE != "no") {
zend_accelerator_util_funcs.c \
zend_persist.c \
zend_persist_calc.c \
+ zend_file_cache.c \
zend_shared_alloc.c \
shared_alloc_win32.c", true, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
diff --git a/ext/opcache/tests/001_cli.phpt b/ext/opcache/tests/001_cli.phpt
index c51db23f56..3be1a52228 100644
--- a/ext/opcache/tests/001_cli.phpt
+++ b/ext/opcache/tests/001_cli.phpt
@@ -3,6 +3,7 @@
--INI--
opcache.enable=1
opcache.enable_cli=1
+opcache.file_cache_only=0
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
diff --git a/ext/opcache/tests/blacklist-win32.phpt b/ext/opcache/tests/blacklist-win32.phpt
index 909c695fcd..1e479b6c2e 100644
--- a/ext/opcache/tests/blacklist-win32.phpt
+++ b/ext/opcache/tests/blacklist-win32.phpt
@@ -5,6 +5,7 @@ opcache.enable=1
opcache.enable_cli=1
opcache.blacklist_filename={PWD}/opcache-*.blacklist
opcache.file_update_protection=0
+opcache.file_cache_only=0
--SKIPIF--
<?php require_once('skipif.inc'); ?>
<?php if (substr(PHP_OS, 0, 3) != 'WIN') { die('skip only for Windows'); } ?>
diff --git a/ext/opcache/tests/blacklist.phpt b/ext/opcache/tests/blacklist.phpt
index 0c60425dac..4e9a0f16fc 100644
--- a/ext/opcache/tests/blacklist.phpt
+++ b/ext/opcache/tests/blacklist.phpt
@@ -5,6 +5,7 @@ opcache.enable=1
opcache.enable_cli=1
opcache.blacklist_filename={PWD}/opcache-*.blacklist
opcache.file_update_protection=0
+opcache.file_cache_only=0
--SKIPIF--
<?php require_once('skipif.inc'); ?>
<?php if (substr(PHP_OS, 0, 3) == 'WIN') { die('skip not for Windows'); } ?>
diff --git a/ext/opcache/tests/bug69281.phpt b/ext/opcache/tests/bug69281.phpt
index 4d68d5007b..506f466ac8 100644
--- a/ext/opcache/tests/bug69281.phpt
+++ b/ext/opcache/tests/bug69281.phpt
@@ -5,6 +5,7 @@ opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.validate_timestamps=0
+opcache.file_cache_only=0
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
diff --git a/ext/opcache/tests/is_script_cached.phpt b/ext/opcache/tests/is_script_cached.phpt
index bac561103f..c3ab054251 100644
--- a/ext/opcache/tests/is_script_cached.phpt
+++ b/ext/opcache/tests/is_script_cached.phpt
@@ -5,6 +5,7 @@ opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.validate_timestamps=1
+opcache.file_cache_only=0
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c
index b79816b8f9..11c0635090 100644
--- a/ext/opcache/zend_accelerator_module.c
+++ b/ext/opcache/zend_accelerator_module.c
@@ -241,6 +241,38 @@ static ZEND_INI_MH(OnEnable)
}
}
+#ifdef HAVE_OPCACHE_FILE_CACHE
+
+#ifndef S_ISDIR
+# define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
+#endif
+
+static ZEND_INI_MH(OnUpdateFileCache)
+{
+ if (new_value) {
+ if (!new_value->len) {
+ new_value = NULL;
+ } else {
+ zend_stat_t buf;
+
+ if (!IS_ABSOLUTE_PATH(new_value->val, new_value->len) ||
+ zend_stat(new_value->val, &buf) != 0 ||
+ !S_ISDIR(buf.st_mode) ||
+#ifndef ZEND_WIN32
+ access(new_value->val, R_OK | W_OK | X_OK) != 0) {
+#else
+ _access(new_value->val, 06) != 0) {
+#endif
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache.file_cache must be a full path of accessable directory.\n");
+ new_value = NULL;
+ }
+ }
+ }
+ OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
+ return SUCCESS;
+}
+#endif
+
ZEND_INI_BEGIN()
STD_PHP_INI_BOOLEAN("opcache.enable" , "1", PHP_INI_ALL, OnEnable, 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)
@@ -276,6 +308,12 @@ ZEND_INI_BEGIN()
#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
+
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals)
+#endif
ZEND_INI_END()
static int filename_is_in_cache(zend_string *filename)
@@ -395,6 +433,25 @@ void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
} else {
php_info_print_table_row(2, "Optimization", "Disabled");
}
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ if (!ZCG(accel_directives).file_cache_only) {
+ php_info_print_table_row(2, "SHM Cache", "Enabled");
+ } else {
+ php_info_print_table_row(2, "SHM Cache", "Disabled");
+ }
+ if (ZCG(accel_directives).file_cache) {
+ php_info_print_table_row(2, "File Cache", "Enabled");
+ } else {
+ php_info_print_table_row(2, "File Cache", "Disabled");
+ }
+ if (ZCG(accel_directives).file_cache_only) {
+ 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");
+ }
+ } else
+#endif
if (ZCG(enabled)) {
if (!accel_startup_ok || zps_api_failure_reason) {
php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
@@ -529,6 +586,17 @@ static ZEND_FUNCTION(opcache_get_status)
/* Trivia */
add_assoc_bool(return_value, "opcache_enabled", ZCG(enabled) && (ZCG(counted) || ZCSG(accelerator_enabled)));
+
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ if (ZCG(accel_directives).file_cache) {
+ add_assoc_string(return_value, "file_cache", ZCG(accel_directives).file_cache);
+ }
+ if (ZCG(accel_directives).file_cache_only) {
+ add_assoc_bool(return_value, "file_cache_only", 1);
+ return;
+ }
+#endif
+
add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted));
add_assoc_bool(return_value, "restart_pending", ZCSG(restart_pending));
add_assoc_bool(return_value, "restart_in_progress", ZCSG(restart_in_progress));
@@ -630,6 +698,12 @@ static ZEND_FUNCTION(opcache_get_configuration)
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);
+#ifdef HAVE_OPCACHE_FILE_CACHE
+ add_assoc_string(&directives, "opcache.file_cache", ZCG(accel_directives).file_cache ? ZCG(accel_directives).file_cache : "");
+ add_assoc_bool(&directives, "opcache.file_cache_only", ZCG(accel_directives).file_cache_only);
+ add_assoc_bool(&directives, "opcache.file_cache_consistency_checks", ZCG(accel_directives).file_cache_consistency_checks);
+#endif
+
add_assoc_zval(return_value, "directives", &directives);
/*version */
diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c
index 92ada0b17f..9407b2ec39 100644
--- a/ext/opcache/zend_accelerator_util_funcs.c
+++ b/ext/opcache/zend_accelerator_util_funcs.c
@@ -97,7 +97,7 @@ void free_persistent_script(zend_persistent_script *persistent_script, int destr
zend_hash_destroy(&persistent_script->class_table);
if (persistent_script->full_path) {
- efree(persistent_script->full_path);
+ zend_string_release(persistent_script->full_path);
}
efree(persistent_script);
@@ -929,3 +929,26 @@ unsigned int zend_adler32(unsigned int checksum, signed char *buf, uint len)
return (s2 << 16) | s1;
}
+
+unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script)
+{
+ signed char *mem = (signed char*)persistent_script->mem;
+ size_t size = persistent_script->size;
+ size_t persistent_script_check_block_size = ((char *)&(persistent_script->dynamic_members)) - (char *)persistent_script;
+ unsigned int checksum = ADLER32_INIT;
+
+ if (mem < (signed char*)persistent_script) {
+ checksum = zend_adler32(checksum, mem, (signed char*)persistent_script - mem);
+ size -= (signed char*)persistent_script - mem;
+ mem += (signed char*)persistent_script - mem;
+ }
+
+ zend_adler32(checksum, mem, persistent_script_check_block_size);
+ mem += sizeof(*persistent_script);
+ size -= sizeof(*persistent_script);
+
+ if (size > 0) {
+ checksum = zend_adler32(checksum, mem, size);
+ }
+ return checksum;
+}
diff --git a/ext/opcache/zend_accelerator_util_funcs.h b/ext/opcache/zend_accelerator_util_funcs.h
index 2ef1595849..e2d8433145 100644
--- a/ext/opcache/zend_accelerator_util_funcs.h
+++ b/ext/opcache/zend_accelerator_util_funcs.h
@@ -39,6 +39,8 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script,
unsigned int zend_adler32(unsigned int checksum, signed char *buf, uint len);
+unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script);
+
#endif /* ZEND_ACCELERATOR_UTIL_FUNCS_H */
/*
diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c
new file mode 100644
index 0000000000..61c20695ff
--- /dev/null
+++ b/ext/opcache/zend_file_cache.c
@@ -0,0 +1,1301 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2015 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: Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "zend.h"
+#include "zend_virtual_cwd.h"
+#include "zend_compile.h"
+#include "zend_vm.h"
+
+#include "php.h"
+
+#ifdef HAVE_OPCACHE_FILE_CACHE
+
+#include "ZendAccelerator.h"
+#include "zend_file_cache.h"
+#include "zend_shared_alloc.h"
+#include "zend_accelerator_util_funcs.h"
+#include "zend_accelerator_hash.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
+
+#ifdef HAVE_SYS_FILE_H
+# include <sys/file.h>
+#endif
+
+#ifdef ZEND_WIN32
+# define LOCK_SH 0
+# define LOCK_EX 1
+# define LOCK_UN 2
+static int zend_file_cache_flock(int fd, int op)
+{
+ OVERLAPPED offset = {0,0,0,0,NULL};
+ if (op == LOCK_EX) {
+ if (LockFileEx((HANDLE)_get_osfhandle(fd),
+ LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &offset) == TRUE) {
+ return 0;
+ }
+ } else if (op == LOCK_SH) {
+ if (LockFileEx((HANDLE)_get_osfhandle(fd),
+ 0, 0, 1, 0, &offset) == TRUE) {
+ return 0;
+ }
+ } else if (op == LOCK_UN) {
+ if (UnlockFileEx((HANDLE)_get_osfhandle(fd),
+ 0, 1, 0, &offset) == TRUE) {
+ return 0;
+ }
+ }
+ return -1;
+}
+#elif defined(HAVE_FLOCK)
+# define zend_file_cache_flock flock
+#else
+# define LOCK_SH 0
+# define LOCK_EX 1
+# define LOCK_UN 2
+static int zend_file_cache_flock(int fd, int type)
+{
+ return 0;
+}
+#endif
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+#define SUFFIX ".bin"
+
+#define IS_SERIALIZED_INTERNED(ptr) \
+ ((size_t)(ptr) & Z_UL(1))
+#define IS_SERIALIZED(ptr) \
+ ((char*)(ptr) < (char*)script->size)
+#define IS_UNSERIALIZED(ptr) \
+ (((char*)(ptr) >= (char*)script->mem && (char*)(ptr) < (char*)script->mem + script->size) || \
+ IS_ACCEL_INTERNED(ptr))
+#define SERIALIZE_PTR(ptr) do { \
+ if (ptr) { \
+ if (IS_ACCEL_INTERNED(ptr)) { \
+ (ptr) = zend_file_cache_serialize_interned((zend_string*)(ptr), info); \
+ } else { \
+ ZEND_ASSERT(IS_UNSERIALIZED(ptr)); \
+ (ptr) = (void*)((char*)(ptr) - (char*)script->mem); \
+ } \
+ } \
+ } while (0)
+#define UNSERIALIZE_PTR(ptr) do { \
+ if (ptr) { \
+ if (IS_SERIALIZED_INTERNED(ptr)) { \
+ (ptr) = (void*)zend_file_cache_unserialize_interned((zend_string*)(ptr)); \
+ } else { \
+ ZEND_ASSERT(IS_SERIALIZED(ptr)); \
+ (ptr) = (void*)((char*)buf + (size_t)(ptr)); \
+ } \
+ } \
+ } while (0)
+
+static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
+ {HT_INVALID_IDX, HT_INVALID_IDX};
+
+typedef struct _zend_file_cache_metainfo {
+ char magic[8];
+ char system_id[32];
+ size_t mem_size;
+ size_t str_size;
+ size_t script_offset;
+ accel_time_t timestamp;
+ uint32_t checksum;
+} zend_file_cache_metainfo;
+
+static int zend_file_cache_mkdir(char *filename, size_t start)
+{
+ char *s = filename + start;
+
+ while (*s) {
+ if (IS_SLASH(*s)) {
+ char old = *s;
+ *s = '\000';
+ if (mkdir(filename, S_IRWXU) < 0 && errno != EEXIST) {
+ *s = old;
+ return FAILURE;
+ }
+ *s = old;
+ }
+ s++;
+ }
+ return SUCCESS;
+}
+
+typedef void (*serialize_callback_t)(zval *zv,
+ zend_persistent_script *script,
+ zend_file_cache_metainfo *info,
+ void *buf);
+
+typedef void (*unserialize_callback_t)(zval *zv,
+ zend_persistent_script *script,
+ void *buf);
+
+static void zend_file_cache_serialize_zval(zval *zv,
+ zend_persistent_script *script,
+ zend_file_cache_metainfo *info,
+ void *buf);
+static void zend_file_cache_unserialize_zval(zval *zv,
+ zend_persistent_script *script,
+ void *buf);
+
+static void *zend_file_cache_serialize_interned(zend_string *str,
+ zend_file_cache_metainfo *info)
+{
+ size_t len;
+ void *ret;
+
+ /* check if the same interned string was already stored */
+ ret = zend_shared_alloc_get_xlat_entry(str);
+ if (ret) {
+ return ret;
+ }
+
+ len = ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + str->len + 1);
+ ret = (void*)(info->str_size | Z_UL(1));
+ zend_shared_alloc_register_xlat_entry(str, ret);
+ if (info->str_size + len > ((zend_string*)ZCG(mem))->len) {
+ size_t new_len = info->str_size + len;
+ ZCG(mem) = (void*)zend_string_realloc(
+ (zend_string*)ZCG(mem),
+ ((_STR_HEADER_SIZE + 1 + new_len + 4095) & ~0xfff) - (_STR_HEADER_SIZE + 1),
+ 0);
+ }
+ memcpy(((zend_string*)ZCG(mem))->val + info->str_size, str, len);
+ info->str_size += len;
+ return ret;
+}
+
+static void *zend_file_cache_unserialize_interned(zend_string *str)
+{
+ zend_string *ret;
+
+ str = (zend_string*)((char*)ZCG(mem) + ((size_t)(str) & ~Z_UL(1)));
+ ret = accel_new_interned_string(str);
+ if (ret == str) {
+ /* String wasn't interned but we will use it as interned anyway */
+ GC_FLAGS(ret) |= IS_STR_INTERNED | IS_STR_PERMANENT;
+ }
+ return ret;
+}
+
+static void zend_file_cache_serialize_hash(HashTable *ht,
+ zend_persistent_script *script,
+ zend_file_cache_metainfo *info,
+ void *buf,
+ serialize_callback_t func)
+{
+ Bucket *p, *end;
+
+ if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
+ ht->arData = NULL;
+ return;
+ }
+ if (IS_SERIALIZED(ht->arData)) {
+ return;
+ }
+ SERIALIZE_PTR(ht->arData);
+ p = ht->arData;
+ UNSERIALIZE_PTR(p);
+ end = p + ht->nNumUsed;
+ while (p < end) {
+ if (Z_TYPE(p->val) != IS_UNDEF) {
+ SERIALIZE_PTR(p->key);
+ func(&p->val, script, info, buf);
+ }
+ p++;
+ }
+}
+
+static zend_ast *zend_file_cache_serialize_ast(zend_ast *ast,
+ zend_persistent_script *script,
+ zend_file_cache_metainfo *info,
+ void *buf)
+{
+ uint32_t i;
+ zend_ast *ret;
+
+ SERIALIZE_PTR(ast);
+ ret = ast;
+ UNSERIALIZE_PTR(ast);
+
+ if (ast->kind == ZEND_AST_ZVAL) {
+ zend_file_cache_serialize_zval(&((zend_ast_zval*)ast)->val, script, info, buf);
+ } else if (zend_ast_is_list(ast)) {
+ zend_ast_list *list = zend_ast_get_list(ast);
+ for (i = 0; i < list->children; i++) {
+ if (list->child[i]) {
+ list->child[i] = zend_file_cache_serialize_ast(list->child[i], script, info, buf);
+ }
+ }
+ } else {
+ uint32_t children = zend_ast_get_num_children(ast);
+ for (i = 0; i < children; i++) {
+ if (ast->child[i]) {
+ ast->child[i] = zend_file_cache_serialize_ast(ast->child[i], script, info, buf);
+ }
+ }
+ }
+ return ret;
+}
+
+static void zend_file_cache_serialize_zval(zval *zv,
+ zend_persistent_script *script,
+ zend_file_cache_metainfo *info,
+ void *buf)
+{
+ switch (Z_TYPE_P(zv)) {
+ case IS_STRING:
+ case IS_CONSTANT:
+ if (!IS_SERIALIZED(Z_STR_P(zv))) {
+ SERIALIZE_PTR(Z_STR_P(zv));
+ }
+ break;
+ case IS_ARRAY:
+ if (!IS_SERIALIZED(Z_ARR_P(zv))) {
+ HashTable *ht;
+
+ SERIALIZE_PTR(Z_ARR_P(zv));
+ ht = Z_ARR_P(zv);
+ UNSERIALIZE_PTR(ht);
+ zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval);
+ }
+ break;
+ case IS_REFERENCE:
+ if (!IS_SERIALIZED(Z_REF_P(zv))) {
+ zend_reference *ref;
+
+ SERIALIZE_PTR(Z_REF_P(zv));
+ ref = Z_REF_P(zv);
+ UNSERIALIZE_PTR(ref);
+ zend_file_cache_serialize_zval(&ref->val, script, info, buf);
+ }
+ break;
+ case IS_CONSTANT_AST:
+ if (!IS_SERIALIZED(Z_AST_P(zv))) {
+ zend_ast_ref *ast;
+
+ SERIALIZE_PTR(Z_AST_P(zv));
+ ast = Z_AST_P(zv);
+ UNSERIALIZE_PTR(ast);
+ if (!IS_SERIALIZED(ast->ast)) {
+ ast->ast = zend_file_cache_serialize_ast(ast->ast, script, info, buf);
+ }
+ }
+ break;
+ }
+}
+
+static void zend_file_cache_serialize_op_array(zend_op_array *op_array,
+ zend_persistent_script *script,
+ zend_file_cache_metainfo *info,
+ void *buf)
+{
+ if (op_array->static_variables && !IS_SERIALIZED(op_array->static_variables)) {
+ HashTable *ht;
+
+ SERIALIZE_PTR(op_array->static_variables);
+ ht = op_array->static_variables;
+ UNSERIALIZE_PTR(ht);
+ zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval);
+ }
+
+ if (op_array->literals && !IS_SERIALIZED(op_array->literals)) {
+ zval *p, *end;
+
+ SERIALIZE_PTR(op_array->literals);
+ p = op_array->literals;
+ UNSERIALIZE_PTR(p);
+ end = p + op_array->last_literal;
+ while (p < end) {
+ zend_file_cache_serialize_zval(p, script, info, buf);
+ p++;
+ }
+ }
+
+ if (!IS_SERIALIZED(op_array->opcodes)) {
+#if ZEND_USE_ABS_CONST_ADDR || ZEND_USE_ABS_JMP_ADDR
+ zend_op *opline, *end;
+
+ SERIALIZE_PTR(op_array->opcodes);
+ opline = op_array->opcodes;
+ UNSERIALIZE_PTR(opline);
+ end = opline + op_array->last;
+ while (opline < end) {
+# if ZEND_USE_ABS_CONST_ADDR
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+ SERIALIZE_PTR(opline->op1.zv);
+ }
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+ SERIALIZE_PTR(opline->op2.zv);
+ }
+# endif
+# if ZEND_USE_ABS_JMP_ADDR
+ switch (opline->opcode) {
+ case ZEND_JMP:
+ case ZEND_GOTO:
+ case ZEND_FAST_CALL:
+ SERIALIZE_PTR(opline->op1.jmp_addr);
+ break;
+ case ZEND_JMPZNZ:
+ /* relative extended_value don't have to be changed */
+ /* break omitted intentionally */
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ case ZEND_NEW:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ case ZEND_ASSERT_CHECK:
+ SERIALIZE_PTR(opline->op2.jmp_addr);
+ break;
+ }
+# endif
+ opline++;
+ }
+#else
+ SERIALIZE_PTR(op_array->opcodes);
+#endif
+
+ if (op_array->arg_info) {
+ zend_arg_info *p, *end;
+ SERIALIZE_PTR(op_array->arg_info);
+ p = op_array->arg_info;
+ UNSERIALIZE_PTR(p);
+ end = p + op_array->num_args;
+ if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ p--;
+ }
+ if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
+ end++;
+ }
+ while (p < end) {
+ if (!IS_SERIALIZED(p->name)) {
+ SERIALIZE_PTR(p->name);
+ }
+ if (!IS_SERIALIZED(p->class_name)) {
+ SERIALIZE_PTR(p->class_name);
+ }
+ p++;
+ }
+ }
+
+ if (op_array->vars) {
+ zend_string **p, **end;
+
+ SERIALIZE_PTR(op_array->vars);
+ p = op_array->vars;
+ UNSERIALIZE_PTR(p);
+ end = p + op_array->last_var;
+ while (p < end) {
+ if (!IS_SERIALIZED(*p)) {
+ SERIALIZE_PTR(*p);
+ }
+ p++;
+ }
+ }
+
+ SERIALIZE_PTR(op_array->function_name);
+ SERIALIZE_PTR(op_array->filename);
+ SERIALIZE_PTR(op_array->brk_cont_array);
+ SERIALIZE_PTR(op_array->scope);
+ SERIALIZE_PTR(op_array->doc_comment);
+ SERIALIZE_PTR(op_array->try_catch_array);
+ SERIALIZE_PTR(op_array->prototype);
+ }
+}
+
+static void zend_file_cache_serialize_func(zval *zv,
+ zend_persistent_script *script,
+ zend_file_cache_metainfo *info,
+ void *buf)
+{
+ zend_op_array *op_array;
+
+ SERIALIZE_PTR(Z_PTR_P(zv));
+ op_array = Z_PTR_P(zv);
+ UNSERIALIZE_PTR(op_array);
+ zend_file_cache_serialize_op_array(op_array, script, info, buf);
+}
+
+static void zend_file_cache_serialize_prop_info(zval *zv,
+ zend_persistent_script *script,
+ zend_file_cache_metainfo *info,
+ void *buf)
+{
+ if (!IS_SERIALIZED(Z_PTR_P(zv))) {
+ zend_property_info *prop;
+
+ SERIALIZE_PTR(Z_PTR_P(zv));
+ prop = Z_PTR_P(zv);
+ UNSERIALIZE_PTR(prop);
+
+ if (prop->ce && !IS_SERIALIZED(prop->ce)) {
+ SERIALIZE_PTR(prop->ce);
+ }
+ if (prop->name && !IS_SERIALIZED(prop->name)) {
+ SERIALIZE_PTR(prop->name);
+ }
+ if (prop->doc_comment && !IS_SERIALIZED(prop->doc_comment)) {
+ SERIALIZE_PTR(prop->doc_comment);
+ }
+ }
+}
+
+static void zend_file_cache_serialize_class(zval *zv,
+ zend_persistent_script *script,
+ zend_file_cache_metainfo *info,
+ void *buf)
+{
+ zend_class_entry *ce;
+
+ SERIALIZE_PTR(Z_PTR_P(zv));
+ ce = Z_PTR_P(zv);
+ UNSERIALIZE_PTR(ce);
+
+ SERIALIZE_PTR(ce->name);
+ zend_file_cache_serialize_hash(&ce->function_table, script, info, buf, zend_file_cache_serialize_func);
+ if (ce->default_properties_table) {
+ zval *p, *end;
+
+ SERIALIZE_PTR(ce->default_properties_table);
+ p = ce->default_properties_table;
+ UNSERIALIZE_PTR(p);
+ end = p + ce->default_properties_count;
+ while (p < end) {
+ zend_file_cache_serialize_zval(p, script, info, buf);
+ p++;
+ }
+ }
+ if (ce->default_static_members_table) {
+ zval *p, *end;
+
+ SERIALIZE_PTR(ce->default_static_members_table);
+ p = ce->default_static_members_table;
+ UNSERIALIZE_PTR(p);
+ end = p + ce->default_static_members_count;
+ while (p < end) {
+ zend_file_cache_serialize_zval(p, script, info, buf);
+ p++;
+ }
+ }
+ zend_file_cache_serialize_hash(&ce->constants_table, script, info, buf, zend_file_cache_serialize_zval);
+ SERIALIZE_PTR(ZEND_CE_FILENAME(ce));
+ SERIALIZE_PTR(ZEND_CE_DOC_COMMENT(ce));
+ zend_file_cache_serialize_hash(&ce->properties_info, script, info, buf, zend_file_cache_serialize_prop_info);
+
+ if (ce->trait_aliases) {
+ zend_trait_alias **p, *q;
+
+ SERIALIZE_PTR(ce->trait_aliases);
+ p = ce->trait_aliases;
+ UNSERIALIZE_PTR(p);
+
+ while (*p) {
+ SERIALIZE_PTR(*p);
+ q = *p;
+ UNSERIALIZE_PTR(q);
+
+ if (q->trait_method) {
+ zend_trait_method_reference *m;
+
+ SERIALIZE_PTR(q->trait_method);
+ m = q->trait_method;
+ UNSERIALIZE_PTR(m);
+
+ if (m->method_name) {
+ SERIALIZE_PTR(m->method_name);
+ }
+ if (m->class_name) {
+ SERIALIZE_PTR(m->class_name);
+ }
+ }
+
+ if (q->alias) {
+ SERIALIZE_PTR(q->alias);
+ }
+ p++;
+ }
+ }
+
+ if (ce->trait_precedences) {
+ zend_trait_precedence **p, *q;
+
+ SERIALIZE_PTR(ce->trait_precedences);
+ p = ce->trait_precedences;
+ UNSERIALIZE_PTR(p);
+
+ while (*p) {
+ SERIALIZE_PTR(*p);
+ q = *p;
+ UNSERIALIZE_PTR(q);
+
+ if (q->trait_method) {
+ zend_trait_method_reference *m;
+
+ SERIALIZE_PTR(q->trait_method);
+ m = q->trait_method;
+ UNSERIALIZE_PTR(m);
+
+ if (m->method_name) {
+ SERIALIZE_PTR(m->method_name);
+ }
+ if (m->class_name) {
+ SERIALIZE_PTR(m->class_name);
+ }
+ }
+
+ if (q->exclude_from_classes) {
+ zend_string **s;
+
+ SERIALIZE_PTR(q->exclude_from_classes);
+ s = (zend_string**)q->exclude_from_classes;
+ UNSERIALIZE_PTR(s);
+
+ while (*s) {
+ SERIALIZE_PTR(*s);
+ s++;
+ }
+ }
+ p++;
+ }
+ }
+
+ SERIALIZE_PTR(ce->parent);
+ SERIALIZE_PTR(ce->constructor);
+ SERIALIZE_PTR(ce->destructor);
+ SERIALIZE_PTR(ce->clone);
+ SERIALIZE_PTR(ce->__get);
+ SERIALIZE_PTR(ce->__set);
+ SERIALIZE_PTR(ce->__call);
+ SERIALIZE_PTR(ce->serialize_func);
+ SERIALIZE_PTR(ce->unserialize_func);
+ SERIALIZE_PTR(ce->__isset);
+ SERIALIZE_PTR(ce->__unset);
+ SERIALIZE_PTR(ce->__tostring);
+ SERIALIZE_PTR(ce->__callstatic);
+ SERIALIZE_PTR(ce->__debugInfo);
+}
+
+static void zend_file_cache_serialize(zend_persistent_script *script,
+ zend_file_cache_metainfo *info,
+ void *buf)
+{
+ zend_persistent_script *new_script;
+
+ memcpy(info->magic, "OPCACHE", 8);
+ memcpy(info->system_id, ZCG(system_id), 32);
+ info->mem_size = script->size;
+ info->str_size = 0;
+ info->script_offset = (char*)script - (char*)script->mem;
+ info->timestamp = script->timestamp;
+
+ memcpy(buf, script->mem, script->size);
+
+ new_script = (zend_persistent_script*)((char*)buf + info->script_offset);
+ SERIALIZE_PTR(new_script->full_path);
+
+ zend_file_cache_serialize_hash(&new_script->class_table, script, info, buf, zend_file_cache_serialize_class);
+ zend_file_cache_serialize_hash(&new_script->function_table, script, info, buf, zend_file_cache_serialize_func);
+ zend_file_cache_serialize_op_array(&new_script->main_op_array, script, info, buf);
+
+ SERIALIZE_PTR(new_script->arena_mem);
+ new_script->mem = NULL;
+}
+
+int zend_file_cache_script_store(zend_persistent_script *script)
+{
+ size_t len;
+ int fd;
+ char *filename;
+ zend_file_cache_metainfo info;
+#ifndef ZEND_WIN32
+ struct iovec vec[3];
+#endif
+ void *mem, *buf;
+
+ len = strlen(ZCG(accel_directives).file_cache);
+ filename = emalloc(len + 33 + script->full_path->len + sizeof(SUFFIX));
+ memcpy(filename, ZCG(accel_directives).file_cache, len);
+ filename[len] = '/';
+ memcpy(filename + len + 1, ZCG(system_id), 32);
+ memcpy(filename + len + 33, script->full_path->val, script->full_path->len);
+ memcpy(filename + len + 33 + script->full_path->len, SUFFIX, sizeof(SUFFIX));
+
+ if (zend_file_cache_mkdir(filename, len) != SUCCESS) {
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot create directory for file '%s'\n", filename);
+ efree(filename);
+ return FAILURE;
+ }
+
+#ifndef ZEND_WIN32
+ fd = open(filename, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
+#else
+ fd = open(filename, O_CREAT | O_EXCL | O_RDWR | O_BINARY, _S_IREAD | _S_IWRITE);
+#endif
+ if (fd < 0) {
+ if (errno != EEXIST) {
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot create file '%s'\n", filename);
+ }
+ efree(filename);
+ return FAILURE;
+ }
+
+ if (zend_file_cache_flock(fd, LOCK_EX) != 0) {
+ close(fd);
+ efree(filename);
+ return FAILURE;
+ }
+
+#ifdef __SSE2__
+ /* Align to 64-byte boundary */
+ mem = emalloc(script->size + 64);
+ buf = (void*)(((zend_uintptr_t)mem + 63L) & ~63L);
+#else
+ mem = buf = emalloc(script->size);
+#endif
+
+ ZCG(mem) = zend_string_alloc(4096 - (_STR_HEADER_SIZE + 1), 0);
+
+ zend_shared_alloc_init_xlat_table();
+ zend_file_cache_serialize(script, &info, buf);
+ zend_shared_alloc_destroy_xlat_table();
+
+ info.checksum = zend_adler32(ADLER32_INIT, buf, script->size);
+ info.checksum = zend_adler32(info.checksum, (signed char*)((zend_string*)ZCG(mem))->val, info.str_size);
+
+#ifndef ZEND_WIN32
+ vec[0].iov_base = &info;
+ vec[0].iov_len = sizeof(info);
+ vec[1].iov_base = buf;
+ vec[1].iov_len = script->size;
+ vec[2].iov_base = ((zend_string*)ZCG(mem))->val;
+ vec[2].iov_len = info.str_size;
+
+ if (writev(fd, vec, 3) != (ssize_t)(sizeof(info) + script->size + info.str_size)) {
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot write to file '%s'\n", filename);
+ zend_string_release((zend_string*)ZCG(mem));
+ efree(mem);
+ unlink(filename);
+ efree(filename);
+ return FAILURE;
+ }
+#else
+ if (ZEND_LONG_MAX < (zend_long)(sizeof(info) + script->size + info.str_size) ||
+ write(fd, &info, sizeof(info)) != sizeof(info) ||
+ write(fd, buf, script->size) != script->size ||
+ write(fd, ((zend_string*)ZCG(mem))->val, info.str_size) != info.str_size
+ ) {
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot write to file '%s'\n", filename);
+ zend_string_release((zend_string*)ZCG(mem));
+ efree(mem);
+ unlink(filename);
+ efree(filename);
+ return FAILURE;
+ }
+#endif
+
+ zend_string_release((zend_string*)ZCG(mem));
+ efree(mem);
+ if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
+ }
+ close(fd);
+ efree(filename);
+
+ return SUCCESS;
+}
+
+static void zend_file_cache_unserialize_hash(HashTable *ht,
+ zend_persistent_script *script,
+ void *buf,
+ unserialize_callback_t func)
+{
+ Bucket *p, *end;
+
+ if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
+ HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
+ return;
+ }
+ if (IS_UNSERIALIZED(ht->arData)) {
+ return;
+ }
+ UNSERIALIZE_PTR(ht->arData);
+ p = ht->arData;
+ end = p + ht->nNumUsed;
+ while (p < end) {
+ if (Z_TYPE(p->val) != IS_UNDEF) {
+ UNSERIALIZE_PTR(p->key);
+ func(&p->val, script, buf);
+ }
+ p++;
+ }
+}
+
+static zend_ast *zend_file_cache_unserialize_ast(zend_ast *ast,
+ zend_persistent_script *script,
+ void *buf)
+{
+ uint32_t i;
+
+ UNSERIALIZE_PTR(ast);
+
+ if (ast->kind == ZEND_AST_ZVAL) {
+ zend_file_cache_unserialize_zval(&((zend_ast_zval*)ast)->val, script, buf);
+ } else if (zend_ast_is_list(ast)) {
+ zend_ast_list *list = zend_ast_get_list(ast);
+ for (i = 0; i < list->children; i++) {
+ if (list->child[i]) {
+ list->child[i] = zend_file_cache_unserialize_ast(list->child[i], script, buf);
+ }
+ }
+ } else {
+ uint32_t children = zend_ast_get_num_children(ast);
+ for (i = 0; i < children; i++) {
+ if (ast->child[i]) {
+ ast->child[i] = zend_file_cache_unserialize_ast(ast->child[i], script, buf);
+ }
+ }
+ }
+ return ast;
+}
+
+static void zend_file_cache_unserialize_zval(zval *zv,
+ zend_persistent_script *script,
+ void *buf)
+{
+ switch (Z_TYPE_P(zv)) {
+ case IS_STRING:
+ case IS_CONSTANT:
+ if (!IS_UNSERIALIZED(Z_STR_P(zv))) {
+ UNSERIALIZE_PTR(Z_STR_P(zv));
+ }
+ break;
+ case IS_ARRAY:
+ if (!IS_UNSERIALIZED(Z_ARR_P(zv))) {
+ HashTable *ht;
+
+ UNSERIALIZE_PTR(Z_ARR_P(zv));
+ ht = Z_ARR_P(zv);
+ zend_file_cache_unserialize_hash(ht, script, buf, zend_file_cache_unserialize_zval);
+ }
+ break;
+ case IS_REFERENCE:
+ if (!IS_UNSERIALIZED(Z_REF_P(zv))) {
+ zend_reference *ref;
+
+ UNSERIALIZE_PTR(Z_REF_P(zv));
+ ref = Z_REF_P(zv);
+ zend_file_cache_unserialize_zval(&ref->val, script, buf);
+ }
+ break;
+ case IS_CONSTANT_AST:
+ if (!IS_UNSERIALIZED(Z_AST_P(zv))) {
+ zend_ast_ref *ast;
+
+ UNSERIALIZE_PTR(Z_AST_P(zv));
+ ast = Z_AST_P(zv);
+ if (!IS_UNSERIALIZED(ast->ast)) {
+ ast->ast = zend_file_cache_unserialize_ast(ast->ast, script, buf);
+ }
+ }
+ break;
+ }
+}
+
+static void zend_file_cache_unserialize_op_array(zend_op_array *op_array,
+ zend_persistent_script *script,
+ void *buf)
+{
+ if (op_array->static_variables && !IS_UNSERIALIZED(op_array->static_variables)) {
+ HashTable *ht;
+
+ UNSERIALIZE_PTR(op_array->static_variables);
+ ht = op_array->static_variables;
+ zend_file_cache_unserialize_hash(ht, script, buf, zend_file_cache_unserialize_zval);
+ }
+
+ if (op_array->literals && !IS_UNSERIALIZED(op_array->literals)) {
+ zval *p, *end;
+
+ UNSERIALIZE_PTR(op_array->literals);
+ p = op_array->literals;
+ end = p + op_array->last_literal;
+ while (p < end) {
+ zend_file_cache_unserialize_zval(p, script, buf);
+ p++;
+ }
+ }
+
+ if (!IS_UNSERIALIZED(op_array->opcodes)) {
+ zend_op *opline, *end;
+
+ UNSERIALIZE_PTR(op_array->opcodes);
+ opline = op_array->opcodes;
+ end = opline + op_array->last;
+ while (opline < end) {
+# if ZEND_USE_ABS_CONST_ADDR
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+ UNSERIALIZE_PTR(opline->op1.zv);
+ }
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+ UNSERIALIZE_PTR(opline->op2.zv);
+ }
+# endif
+# if ZEND_USE_ABS_JMP_ADDR
+ switch (opline->opcode) {
+ case ZEND_JMP:
+ case ZEND_GOTO:
+ case ZEND_FAST_CALL:
+ UNSERIALIZE_PTR(opline->op1.jmp_addr);
+ break;
+ case ZEND_JMPZNZ:
+ /* relative extended_value don't have to be changed */
+ /* break omitted intentionally */
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ case ZEND_NEW:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ case ZEND_ASSERT_CHECK:
+ UNSERIALIZE_PTR(opline->op2.jmp_addr);
+ break;
+ }
+# endif
+ ZEND_VM_SET_OPCODE_HANDLER(opline);
+ opline++;
+ }
+
+ if (op_array->arg_info) {
+ zend_arg_info *p, *end;
+ UNSERIALIZE_PTR(op_array->arg_info);
+ p = op_array->arg_info;
+ end = p + op_array->num_args;
+ if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ p--;
+ }
+ if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
+ end++;
+ }
+ while (p < end) {
+ if (!IS_UNSERIALIZED(p->name)) {
+ UNSERIALIZE_PTR(p->name);
+ }
+ if (!IS_UNSERIALIZED(p->class_name)) {
+ UNSERIALIZE_PTR(p->class_name);
+ }
+ p++;
+ }
+ }
+
+ if (op_array->vars) {
+ zend_string **p, **end;
+
+ UNSERIALIZE_PTR(op_array->vars);
+ p = op_array->vars;
+ end = p + op_array->last_var;
+ while (p < end) {
+ if (!IS_UNSERIALIZED(*p)) {
+ UNSERIALIZE_PTR(*p);
+ }
+ p++;
+ }
+ }
+
+ UNSERIALIZE_PTR(op_array->function_name);
+ UNSERIALIZE_PTR(op_array->filename);
+ UNSERIALIZE_PTR(op_array->brk_cont_array);
+ UNSERIALIZE_PTR(op_array->scope);
+ UNSERIALIZE_PTR(op_array->doc_comment);
+ UNSERIALIZE_PTR(op_array->try_catch_array);
+ UNSERIALIZE_PTR(op_array->prototype);
+ }
+}
+
+static void zend_file_cache_unserialize_func(zval *zv,
+ zend_persistent_script *script,
+ void *buf)
+{
+ zend_op_array *op_array;
+
+ UNSERIALIZE_PTR(Z_PTR_P(zv));
+ op_array = Z_PTR_P(zv);
+ zend_file_cache_unserialize_op_array(op_array, script, buf);
+}
+
+static void zend_file_cache_unserialize_prop_info(zval *zv,
+ zend_persistent_script *script,
+ void *buf)
+{
+ if (!IS_UNSERIALIZED(Z_PTR_P(zv))) {
+ zend_property_info *prop;
+
+ UNSERIALIZE_PTR(Z_PTR_P(zv));
+ prop = Z_PTR_P(zv);
+
+ if (prop->ce && !IS_UNSERIALIZED(prop->ce)) {
+ UNSERIALIZE_PTR(prop->ce);
+ }
+ if (prop->name && !IS_UNSERIALIZED(prop->name)) {
+ UNSERIALIZE_PTR(prop->name);
+ }
+ if (prop->doc_comment && !IS_UNSERIALIZED(prop->doc_comment)) {
+ UNSERIALIZE_PTR(prop->doc_comment);
+ }
+ }
+}
+
+static void zend_file_cache_unserialize_class(zval *zv,
+ zend_persistent_script *script,
+ void *buf)
+{
+ zend_class_entry *ce;
+
+ UNSERIALIZE_PTR(Z_PTR_P(zv));
+ ce = Z_PTR_P(zv);
+
+ UNSERIALIZE_PTR(ce->name);
+ zend_file_cache_unserialize_hash(&ce->function_table, script, buf, zend_file_cache_unserialize_func);
+ if (ce->default_properties_table) {
+ zval *p, *end;
+
+ UNSERIALIZE_PTR(ce->default_properties_table);
+ p = ce->default_properties_table;
+ end = p + ce->default_properties_count;
+ while (p < end) {
+ zend_file_cache_unserialize_zval(p, script, buf);
+ p++;
+ }
+ }
+ if (ce->default_static_members_table) {
+ zval *p, *end;
+
+ UNSERIALIZE_PTR(ce->default_static_members_table);
+ p = ce->default_static_members_table;
+ end = p + ce->default_static_members_count;
+ while (p < end) {
+ zend_file_cache_unserialize_zval(p, script, buf);
+ p++;
+ }
+ }
+ zend_file_cache_unserialize_hash(&ce->constants_table, script, buf, zend_file_cache_unserialize_zval);
+ UNSERIALIZE_PTR(ZEND_CE_FILENAME(ce));
+ UNSERIALIZE_PTR(ZEND_CE_DOC_COMMENT(ce));
+ zend_file_cache_unserialize_hash(&ce->properties_info, script, buf, zend_file_cache_unserialize_prop_info);
+
+ if (ce->trait_aliases) {
+ zend_trait_alias **p, *q;
+
+ UNSERIALIZE_PTR(ce->trait_aliases);
+ p = ce->trait_aliases;
+
+ while (*p) {
+ UNSERIALIZE_PTR(*p);
+ q = *p;
+
+ if (q->trait_method) {
+ zend_trait_method_reference *m;
+
+ UNSERIALIZE_PTR(q->trait_method);
+ m = q->trait_method;
+
+ if (m->method_name) {
+ UNSERIALIZE_PTR(m->method_name);
+ }
+ if (m->class_name) {
+ UNSERIALIZE_PTR(m->class_name);
+ }
+ }
+
+ if (q->alias) {
+ UNSERIALIZE_PTR(q->alias);
+ }
+ p++;
+ }
+ }
+
+ if (ce->trait_precedences) {
+ zend_trait_precedence **p, *q;
+
+ UNSERIALIZE_PTR(ce->trait_precedences);
+ p = ce->trait_precedences;
+
+ while (*p) {
+ UNSERIALIZE_PTR(*p);
+ q = *p;
+
+ if (q->trait_method) {
+ zend_trait_method_reference *m;
+
+ UNSERIALIZE_PTR(q->trait_method);
+ m = q->trait_method;
+
+ if (m->method_name) {
+ UNSERIALIZE_PTR(m->method_name);
+ }
+ if (m->class_name) {
+ UNSERIALIZE_PTR(m->class_name);
+ }
+ }
+
+ if (q->exclude_from_classes) {
+ zend_string **s;
+
+ UNSERIALIZE_PTR(q->exclude_from_classes);
+ s = (zend_string**)q->exclude_from_classes;
+
+ while (*s) {
+ UNSERIALIZE_PTR(*s);
+ s++;
+ }
+ }
+ p++;
+ }
+ }
+
+ UNSERIALIZE_PTR(ce->parent);
+ UNSERIALIZE_PTR(ce->constructor);
+ UNSERIALIZE_PTR(ce->destructor);
+ UNSERIALIZE_PTR(ce->clone);
+ UNSERIALIZE_PTR(ce->__get);
+ UNSERIALIZE_PTR(ce->__set);
+ UNSERIALIZE_PTR(ce->__call);
+ UNSERIALIZE_PTR(ce->serialize_func);
+ UNSERIALIZE_PTR(ce->unserialize_func);
+ UNSERIALIZE_PTR(ce->__isset);
+ UNSERIALIZE_PTR(ce->__unset);
+ UNSERIALIZE_PTR(ce->__tostring);
+ UNSERIALIZE_PTR(ce->__callstatic);
+ UNSERIALIZE_PTR(ce->__debugInfo);
+}
+
+static void zend_file_cache_unserialize(zend_persistent_script *script,
+ void *buf)
+{
+ script->mem = buf;
+
+ UNSERIALIZE_PTR(script->full_path);
+
+ zend_file_cache_unserialize_hash(&script->class_table, script, buf, zend_file_cache_unserialize_class);
+ zend_file_cache_unserialize_hash(&script->function_table, script, buf, zend_file_cache_unserialize_func);
+ zend_file_cache_unserialize_op_array(&script->main_op_array, script, buf);
+
+ UNSERIALIZE_PTR(script->arena_mem);
+}
+
+zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle)
+{
+ zend_string *full_path = file_handle->opened_path;
+ size_t len;
+ int fd;
+ char *filename;
+ zend_persistent_script *script;
+ zend_file_cache_metainfo info;
+ zend_accel_hash_entry *bucket;
+ void *mem, *checkpoint, *buf;
+ int cache_it = 1;
+
+ if (!full_path) {
+ return NULL;
+ }
+ len = strlen(ZCG(accel_directives).file_cache);
+ filename = emalloc(len + 33 + full_path->len + sizeof(SUFFIX));
+ memcpy(filename, ZCG(accel_directives).file_cache, len);
+ filename[len] = '/';
+ memcpy(filename + len + 1, ZCG(system_id), 32);
+ memcpy(filename + len + 33, full_path->val, full_path->len);
+ memcpy(filename + len + 33 + full_path->len, SUFFIX, sizeof(SUFFIX));
+
+ fd = open(filename, O_RDONLY | O_BINARY);
+ if (fd < 0) {
+ efree(filename);
+ return NULL;
+ }
+
+ if (zend_file_cache_flock(fd, LOCK_SH) != 0) {
+ close(fd);
+ efree(filename);
+ return NULL;
+ }
+
+ if (read(fd, &info, sizeof(info)) != sizeof(info)) {
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s'\n", filename);
+ zend_file_cache_flock(fd, LOCK_UN);
+ close(fd);
+ unlink(filename);
+ efree(filename);
+ return NULL;
+ }
+
+ /* verify header */
+ if (memcmp(info.magic, "OPCACHE", 8) != 0 ||
+ memcmp(info.system_id, ZCG(system_id), 32) != 0) {
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s'\n", filename);
+ zend_file_cache_flock(fd, LOCK_UN);
+ close(fd);
+ unlink(filename);
+ efree(filename);
+ return NULL;
+ }
+
+ /* verify timestamp */
+ if (ZCG(accel_directives).validate_timestamps &&
+ zend_get_file_handle_timestamp(file_handle, NULL) != info.timestamp) {
+ if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
+ }
+ close(fd);
+ unlink(filename);
+ efree(filename);
+ return NULL;
+ }
+
+ checkpoint = zend_arena_checkpoint(CG(arena));
+#ifdef __SSE2__
+ /* Align to 64-byte boundary */
+ mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size + 64);
+ mem = (void*)(((zend_uintptr_t)mem + 63L) & ~63L);
+#else
+ mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size);
+#endif
+
+ if (read(fd, mem, info.mem_size + info.str_size) != (ssize_t)(info.mem_size + info.str_size)) {
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s'\n", filename);
+ zend_file_cache_flock(fd, LOCK_UN);
+ close(fd);
+ unlink(filename);
+ zend_arena_release(&CG(arena), checkpoint);
+ efree(filename);
+ return NULL;
+ }
+ if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
+ zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
+ }
+ close(fd);
+
+ /* verify checksum */
+ if (ZCG(accel_directives).file_cache_consistency_checks &&
+ zend_adler32(ADLER32_INIT, mem, info.mem_size + info.str_size) != info.checksum) {
+ zend_accel_error(ACCEL_LOG_WARNING, "corrupted file '%s'\n", filename);
+ unlink(filename);
+ zend_arena_release(&CG(arena), checkpoint);
+ efree(filename);
+ return NULL;
+ }
+
+ if (!ZCG(accel_directives).file_cache_only) {
+ /* exclusive lock */
+ zend_shared_alloc_lock();
+
+ /* Check if we still need to put the file into the cache (may be it was
+ * already stored by another process. This final check is done under
+ * exclusive lock) */
+ bucket = zend_accel_hash_find_entry(&ZCSG(hash), full_path);
+ if (bucket) {
+ script = (zend_persistent_script *)bucket->data;
+ if (!script->corrupted) {
+ zend_shared_alloc_unlock();
+ zend_arena_release(&CG(arena), checkpoint);
+ efree(filename);
+ return script;
+ }
+ }
+
+ if (zend_accel_hash_is_full(&ZCSG(hash))) {
+ zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
+ ZSMMG(memory_exhausted) = 1;
+ zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
+ zend_shared_alloc_unlock();
+ goto use_process_mem;
+ }
+
+#ifdef __SSE2__
+ /* Align to 64-byte boundary */
+ buf = zend_shared_alloc(info.mem_size + 64);
+ buf = (void*)(((zend_uintptr_t)buf + 63L) & ~63L);
+#else
+ buf = zend_shared_alloc(info.mem_size);
+#endif
+
+ if (!buf) {
+ zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
+ zend_shared_alloc_unlock();
+ goto use_process_mem;
+ }
+ memcpy(buf, mem, info.mem_size);
+ } else {
+use_process_mem:
+ buf = mem;
+ cache_it = 0;
+ }
+
+ ZCG(mem) = ((char*)mem + info.mem_size);
+ script = (zend_persistent_script*)((char*)buf + info.script_offset);
+ zend_file_cache_unserialize(script, buf);
+
+ if (cache_it) {
+ script->dynamic_members.checksum = zend_accel_script_checksum(script);
+
+ zend_accel_hash_update(&ZCSG(hash), script->full_path->val, script->full_path->len, 0, script);
+
+ zend_shared_alloc_unlock();
+ zend_arena_release(&CG(arena), checkpoint);
+ }
+ efree(filename);
+
+ return script;
+}
+
+void zend_file_cache_invalidate(zend_string *full_path)
+{
+ size_t len;
+ char *filename;
+
+ len = strlen(ZCG(accel_directives).file_cache);
+ filename = emalloc(len + 33 + full_path->len + sizeof(SUFFIX));
+ memcpy(filename, ZCG(accel_directives).file_cache, len);
+ filename[len] = '/';
+ memcpy(filename + len + 1, ZCG(system_id), 32);
+ memcpy(filename + len + 33, full_path->val, full_path->len);
+ memcpy(filename + len + 33 + full_path->len, SUFFIX, sizeof(SUFFIX));
+
+ unlink(filename);
+ efree(filename);
+}
+
+#endif /* HAVE_OPCACHE_FILE_CACHE */
diff --git a/ext/opcache/zend_file_cache.h b/ext/opcache/zend_file_cache.h
new file mode 100644
index 0000000000..0660bfbc6f
--- /dev/null
+++ b/ext/opcache/zend_file_cache.h
@@ -0,0 +1,26 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend OPcache |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998-2015 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: Dmitry Stogov <dmitry@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_FILE_CACHE_H
+#define ZEND_FILE_CACHE_H
+
+int zend_file_cache_script_store(zend_persistent_script *script);
+zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle);
+void zend_file_cache_invalidate(zend_string *full_path);
+
+#endif /* ZEND_FILE_CACHE_H */
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
index 5597d382e8..4aee6fb628 100644
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@ -870,7 +870,7 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script
zend_shared_alloc_clear_xlat_table();
zend_accel_store(script, sizeof(zend_persistent_script));
- if (*key) {
+ if (key && *key) {
*key = zend_accel_memdup(*key, key_length + 1);
}
zend_accel_store_string(script->full_path);
diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c
index d1925446fa..19b51e7c59 100644
--- a/ext/opcache/zend_shared_alloc.c
+++ b/ext/opcache/zend_shared_alloc.c
@@ -45,7 +45,6 @@
/* 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 */
@@ -325,7 +324,7 @@ int zend_shared_memdup_size(void *source, size_t size)
{
void *old_p;
- if ((old_p = zend_hash_index_find_ptr(&xlat_table, (zend_ulong)source)) != NULL) {
+ if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), (zend_ulong)source)) != NULL) {
/* we already duplicated this pointer */
return 0;
}
@@ -337,7 +336,7 @@ void *_zend_shared_memdup(void *source, size_t size, zend_bool free_source)
{
void *old_p, *retval;
- if ((old_p = zend_hash_index_find_ptr(&xlat_table, (zend_ulong)source)) != NULL) {
+ if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), (zend_ulong)source)) != NULL) {
/* we already duplicated this pointer */
return old_p;
}
@@ -393,21 +392,10 @@ void zend_shared_alloc_lock(void)
#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, 128, NULL, NULL, 1);
}
void zend_shared_alloc_unlock(void)
{
- /* Destroy translation table */
- zend_hash_destroy(&xlat_table);
-
ZCG(locked) = 0;
#ifndef ZEND_WIN32
@@ -422,21 +410,39 @@ void zend_shared_alloc_unlock(void)
#endif
}
+void zend_shared_alloc_init_xlat_table(void)
+{
+
+ /* 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(&ZCG(xlat_table), 128, NULL, NULL, 1);
+}
+
+void zend_shared_alloc_destroy_xlat_table(void)
+{
+ /* Destroy translation table */
+ zend_hash_destroy(&ZCG(xlat_table));
+}
+
void zend_shared_alloc_clear_xlat_table(void)
{
- zend_hash_clean(&xlat_table);
+ zend_hash_clean(&ZCG(xlat_table));
}
void zend_shared_alloc_register_xlat_entry(const void *old, const void *new)
{
- zend_hash_index_update_ptr(&xlat_table, (zend_ulong)old, (void*)new);
+ zend_hash_index_update_ptr(&ZCG(xlat_table), (zend_ulong)old, (void*)new);
}
void *zend_shared_alloc_get_xlat_entry(const void *old)
{
void *retval;
- if ((retval = zend_hash_index_find_ptr(&xlat_table, (zend_ulong)old)) == NULL) {
+ if ((retval = zend_hash_index_find_ptr(&ZCG(xlat_table), (zend_ulong)old)) == NULL) {
return NULL;
}
return retval;
diff --git a/ext/opcache/zend_shared_alloc.h b/ext/opcache/zend_shared_alloc.h
index 1dbe6f8557..63947169b4 100644
--- a/ext/opcache/zend_shared_alloc.h
+++ b/ext/opcache/zend_shared_alloc.h
@@ -148,6 +148,8 @@ void zend_shared_alloc_unlock(void); /* returns the allocated size during lock..
void zend_shared_alloc_safe_unlock(void);
/* old/new mapping functions */
+void zend_shared_alloc_init_xlat_table(void);
+void zend_shared_alloc_destroy_xlat_table(void);
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);
diff --git a/ext/phar/tests/create_new_and_modify.phpt b/ext/phar/tests/create_new_and_modify.phpt
index c03576cb2c..c924d74c68 100644
--- a/ext/phar/tests/create_new_and_modify.phpt
+++ b/ext/phar/tests/create_new_and_modify.phpt
@@ -23,7 +23,7 @@ include $pname . '/a.php';
if (function_exists("opcache_get_status")) {
$status = opcache_get_status();
- if ($status["opcache_enabled"]) {
+ if ($status["opcache_enabled"] || (isset($status["file_cache_only"]) && $status["file_cache_only"])) {
ini_set("opcache.revalidate_freq", "0");
sleep(2);
}
diff --git a/ext/phar/tests/tar/create_new_and_modify.phpt b/ext/phar/tests/tar/create_new_and_modify.phpt
index 905bfabc82..7d8bcb17da 100644
--- a/ext/phar/tests/tar/create_new_and_modify.phpt
+++ b/ext/phar/tests/tar/create_new_and_modify.phpt
@@ -17,7 +17,7 @@ file_put_contents($pname . '/a.php', "brand new!\n");
if (function_exists("opcache_get_status")) {
$status = opcache_get_status();
- if ($status["opcache_enabled"]) {
+ if ($status["opcache_enabled"] || (isset($status["file_cache_only"]) && $status["file_cache_only"])) {
ini_set("opcache.revalidate_freq", "0");
sleep(2);
}
diff --git a/ext/phar/tests/zip/create_new_and_modify.phpt b/ext/phar/tests/zip/create_new_and_modify.phpt
index 55d69cca0e..c49ec513ff 100644
--- a/ext/phar/tests/zip/create_new_and_modify.phpt
+++ b/ext/phar/tests/zip/create_new_and_modify.phpt
@@ -17,7 +17,7 @@ file_put_contents($pname . '/a.php', "brand new!\n");
if (function_exists("opcache_get_status")) {
$status = opcache_get_status();
- if ($status["opcache_enabled"]) {
+ if ($status["opcache_enabled"] || (isset($status["file_cache_only"]) && $status["file_cache_only"])) {
ini_set("opcache.revalidate_freq", "0");
sleep(2);
}
diff --git a/run-tests.php b/run-tests.php
index 72781e9559..897500a58b 100755
--- a/run-tests.php
+++ b/run-tests.php
@@ -243,9 +243,11 @@ $ini_overwrites = array(
'opcache.file_update_protection=0',
);
+$no_file_cache = '-d opcache.file_cache= -d opcache.file_cache_only=0';
+
function write_information($show_html)
{
- global $cwd, $php, $php_cgi, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $leak_check, $valgrind_header;
+ global $cwd, $php, $php_cgi, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $leak_check, $valgrind_header, $no_file_cache;
// Get info from php
$info_file = __DIR__ . '/run-test-info.php';
@@ -261,11 +263,11 @@ More .INIs : " , (function_exists(\'php_ini_scanned_files\') ? str_replace("\n"
$info_params = array();
settings2array($ini_overwrites, $info_params);
settings2params($info_params);
- $php_info = `$php $pass_options $info_params "$info_file"`;
+ $php_info = `$php $pass_options $info_params $no_file_cache "$info_file"`;
define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`);
if ($php_cgi && $php != $php_cgi) {
- $php_info_cgi = `$php_cgi $pass_options $info_params -q "$info_file"`;
+ $php_info_cgi = `$php_cgi $pass_options $info_params $no_file_cache -q "$info_file"`;
$php_info_sep = "\n---------------------------------------------------------------------";
$php_cgi_info = "$php_info_sep\nPHP : $php_cgi $php_info_cgi$php_info_sep";
} else {
@@ -276,7 +278,7 @@ More .INIs : " , (function_exists(\'php_ini_scanned_files\') ? str_replace("\n"
// load list of enabled extensions
save_text($info_file, '<?php echo join(",", get_loaded_extensions()); ?>');
- $exts_to_test = explode(',',`$php $pass_options $info_params "$info_file"`);
+ $exts_to_test = explode(',',`$php $pass_options $info_params $no_file_cache "$info_file"`);
// check for extensions that need special handling and regenerate
$info_params_ex = array(
'session' => array('session.auto_start=0'),
@@ -1195,6 +1197,7 @@ function run_test($php, $file, $env)
global $valgrind_version;
global $JUNIT;
global $SHOW_ONLY_GROUPS;
+ global $no_file_cache;
$temp_filenames = null;
$org_file = $file;
@@ -1519,7 +1522,7 @@ TEST $file
junit_start_timer($shortname);
- $output = system_with_timeout("$extra $php $pass_options -q $ini_settings -d display_errors=0 \"$test_skipif\"", $env);
+ $output = system_with_timeout("$extra $php $pass_options -q $ini_settings $no_file_cache -d display_errors=0 \"$test_skipif\"", $env);
junit_finish_timer($shortname);
@@ -1835,7 +1838,7 @@ COMMAND $cmd
settings2params($clean_params);
$extra = substr(PHP_OS, 0, 3) !== "WIN" ?
"unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;": "";
- system_with_timeout("$extra $php $pass_options -q $clean_params \"$test_clean\"", $env);
+ system_with_timeout("$extra $php $pass_options -q $clean_params $no_file_cache \"$test_clean\"", $env);
}
if (!$cfg['keep']['clean']) {