summaryrefslogtreecommitdiff
path: root/ext/opcache/ZendAccelerator.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/opcache/ZendAccelerator.c')
-rw-r--r--ext/opcache/ZendAccelerator.c741
1 files changed, 460 insertions, 281 deletions
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 6974307e29..fc24cff389 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -109,17 +109,19 @@ zend_accel_shared_globals *accel_shared_globals = NULL;
#ifdef ZEND_WIN32
char accel_uname_id[32];
#endif
-zend_bool accel_startup_ok = 0;
+bool accel_startup_ok = 0;
static char *zps_failure_reason = NULL;
char *zps_api_failure_reason = NULL;
-zend_bool file_cache_only = 0; /* process uses file cache only */
+bool file_cache_only = 0; /* process uses file cache only */
#if ENABLE_FILE_CACHE_FALLBACK
-zend_bool fallback_process = 0; /* process uses file cache fallback */
+bool fallback_process = 0; /* process uses file cache fallback */
#endif
static zend_op_array *(*accelerator_orig_compile_file)(zend_file_handle *file_handle, int type);
-static zend_result (*accelerator_orig_zend_stream_open_function)(const char *filename, zend_file_handle *handle );
-static zend_string *(*accelerator_orig_zend_resolve_path)(const char *filename, size_t filename_len);
+static zend_class_entry* (*accelerator_orig_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces);
+static zend_class_entry* (*accelerator_orig_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies);
+static zend_result (*accelerator_orig_zend_stream_open_function)(zend_file_handle *handle );
+static zend_string *(*accelerator_orig_zend_resolve_path)(zend_string *filename);
static void (*accelerator_orig_zend_error_cb)(int type, const char *error_filename, const uint32_t error_lineno, zend_string *message);
static zif_handler orig_chdir = NULL;
static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
@@ -503,7 +505,7 @@ zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str)
hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
STRTAB_COLLISION(s) = *hash_slot;
*hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);
- GC_SET_REFCOUNT(s, 1);
+ GC_SET_REFCOUNT(s, 2);
GC_TYPE_INFO(s) = GC_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT);
ZSTR_H(s) = h;
ZSTR_LEN(s) = ZSTR_LEN(str);
@@ -805,7 +807,7 @@ static inline void kill_all_lockers(struct flock *mem_usage_check)
/* errno is not ESRCH or we ran out of tries to kill the locker */
ZCSG(force_restart_time) = time(NULL); /* restore forced restart request */
/* cannot kill the locker, bail out with error */
- zend_accel_error(ACCEL_LOG_ERROR, "Cannot kill process %d!", mem_usage_check->l_pid);
+ zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Cannot kill process %d!", mem_usage_check->l_pid);
}
mem_usage_check->l_type = F_WRLCK;
@@ -950,7 +952,7 @@ accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_
if (sapi_module.get_stat &&
!EG(current_execute_data) &&
- file_handle->filename == SG(request_info).path_translated) {
+ file_handle->primary_script) {
zend_stat_t *tmpbuf = sapi_module.get_stat();
@@ -972,7 +974,7 @@ accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_
switch (file_handle->type) {
case ZEND_HANDLE_FP:
if (zend_fstat(fileno(file_handle->handle.fp), &statbuf) == -1) {
- if (zend_get_stream_timestamp(file_handle->filename, &statbuf) != SUCCESS) {
+ if (zend_get_stream_timestamp(ZSTR_VAL(file_handle->filename), &statbuf) != SUCCESS) {
return 0;
}
}
@@ -991,7 +993,7 @@ accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_
}
}
- if (zend_get_stream_timestamp(file_handle->filename, &statbuf) != SUCCESS) {
+ if (zend_get_stream_timestamp(ZSTR_VAL(file_handle->filename), &statbuf) != SUCCESS) {
return 0;
}
break;
@@ -1037,6 +1039,7 @@ static inline int do_validate_timestamps(zend_persistent_script *persistent_scri
{
zend_file_handle ps_handle;
zend_string *full_path_ptr = NULL;
+ int ret;
/** check that the persistent script is indeed the same file we cached
* (if part of the path is a symlink than it possible that the user will change it)
@@ -1048,7 +1051,7 @@ static inline int do_validate_timestamps(zend_persistent_script *persistent_scri
return FAILURE;
}
} else {
- full_path_ptr = accelerator_orig_zend_resolve_path(file_handle->filename, strlen(file_handle->filename));
+ full_path_ptr = accelerator_orig_zend_resolve_path(file_handle->filename);
if (full_path_ptr &&
persistent_script->script.filename != full_path_ptr &&
!zend_string_equal_content(persistent_script->script.filename, full_path_ptr)) {
@@ -1078,14 +1081,15 @@ static inline int do_validate_timestamps(zend_persistent_script *persistent_scri
file_handle->opened_path = NULL;
}
- zend_stream_init_filename(&ps_handle, ZSTR_VAL(persistent_script->script.filename));
+ zend_stream_init_filename_ex(&ps_handle, persistent_script->script.filename);
ps_handle.opened_path = persistent_script->script.filename;
- if (zend_get_file_handle_timestamp(&ps_handle, NULL) == persistent_script->timestamp) {
- return SUCCESS;
- }
+ ret = zend_get_file_handle_timestamp(&ps_handle, NULL) == persistent_script->timestamp
+ ? SUCCESS : FAILURE;
- return FAILURE;
+ zend_destroy_file_handle(&ps_handle);
+
+ return ret;
}
int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
@@ -1117,23 +1121,25 @@ int validate_timestamp_and_record_ex(zend_persistent_script *persistent_script,
/* 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 */
-char *accel_make_persistent_key(const char *path, size_t path_length, int *key_len)
+zend_string *accel_make_persistent_key(zend_string *str)
{
+ const char *path = ZSTR_VAL(str);
+ size_t path_length = ZSTR_LEN(str);
+ char *key;
int key_length;
+ ZSTR_LEN(&ZCG(key)) = 0;
+
/* CWD and include_path don't matter for absolute file names and streams */
if (IS_ABSOLUTE_PATH(path, path_length)) {
/* pass */
- ZCG(key_len) = 0;
} else if (UNEXPECTED(is_stream_path(path))) {
if (!is_cacheable_stream_path(path)) {
return NULL;
}
/* pass */
- ZCG(key_len) = 0;
} else if (UNEXPECTED(!ZCG(accel_directives).use_cwd)) {
/* pass */
- ZCG(key_len) = 0;
} else {
const char *include_path = NULL, *cwd = NULL;
int include_path_len = 0, cwd_len = 0;
@@ -1231,7 +1237,7 @@ char *accel_make_persistent_key(const char *path, size_t path_length, int *key_l
}
/* Calculate key length */
- if (UNEXPECTED((size_t)(cwd_len + path_length + include_path_len + 2) >= sizeof(ZCG(key)))) {
+ if (UNEXPECTED((size_t)(cwd_len + path_length + include_path_len + 2) >= sizeof(ZCG(_key)))) {
return NULL;
}
@@ -1240,16 +1246,17 @@ char *accel_make_persistent_key(const char *path, size_t path_length, int *key_l
* since in itself, it may include colons (which we use to separate
* different components of the key)
*/
- memcpy(ZCG(key), path, path_length);
- ZCG(key)[path_length] = ':';
+ key = ZSTR_VAL(&ZCG(key));
+ memcpy(key, path, path_length);
+ key[path_length] = ':';
key_length = path_length + 1;
- memcpy(ZCG(key) + key_length, cwd, cwd_len);
+ memcpy(key + key_length, cwd, cwd_len);
key_length += cwd_len;
if (include_path_len) {
- ZCG(key)[key_length] = ':';
+ key[key_length] = ':';
key_length += 1;
- memcpy(ZCG(key) + key_length, include_path, include_path_len);
+ memcpy(key + key_length, include_path, include_path_len);
key_length += include_path_len;
}
@@ -1263,25 +1270,27 @@ char *accel_make_persistent_key(const char *path, size_t path_length, int *key_l
parent_script_len = ZSTR_LEN(parent_script);
while ((--parent_script_len > 0) && !IS_SLASH(ZSTR_VAL(parent_script)[parent_script_len]));
- if (UNEXPECTED((size_t)(key_length + parent_script_len + 1) >= sizeof(ZCG(key)))) {
+ if (UNEXPECTED((size_t)(key_length + parent_script_len + 1) >= sizeof(ZCG(_key)))) {
return NULL;
}
- ZCG(key)[key_length] = ':';
+ key[key_length] = ':';
key_length += 1;
- memcpy(ZCG(key) + key_length, ZSTR_VAL(parent_script), parent_script_len);
+ memcpy(key + key_length, ZSTR_VAL(parent_script), parent_script_len);
key_length += parent_script_len;
}
- ZCG(key)[key_length] = '\0';
- *key_len = ZCG(key_len) = key_length;
- return ZCG(key);
+ key[key_length] = '\0';
+ GC_SET_REFCOUNT(&ZCG(key), 1);
+ GC_TYPE_INFO(&ZCG(key)) = GC_STRING;
+ ZSTR_H(&ZCG(key)) = 0;
+ ZSTR_LEN(&ZCG(key)) = key_length;
+ return &ZCG(key);
}
/* not use_cwd */
- *key_len = path_length;
- return (char*)path;
+ return str;
}
-int zend_accel_invalidate(const char *filename, size_t filename_len, zend_bool force)
+int zend_accel_invalidate(zend_string *filename, bool force)
{
zend_string *realpath;
zend_persistent_script *persistent_script;
@@ -1290,7 +1299,7 @@ int zend_accel_invalidate(const char *filename, size_t filename_len, zend_bool f
return FAILURE;
}
- realpath = accelerator_orig_zend_resolve_path(filename, filename_len);
+ realpath = accelerator_orig_zend_resolve_path(filename);
if (!realpath) {
return FAILURE;
@@ -1303,7 +1312,7 @@ int zend_accel_invalidate(const char *filename, size_t filename_len, zend_bool f
persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath);
if (persistent_script && !persistent_script->corrupted) {
zend_file_handle file_handle;
- zend_stream_init_filename(&file_handle, ZSTR_VAL(realpath));
+ zend_stream_init_filename_ex(&file_handle, realpath);
file_handle.opened_path = realpath;
if (force ||
@@ -1326,6 +1335,9 @@ int zend_accel_invalidate(const char *filename, size_t filename_len, zend_bool f
SHM_PROTECT();
HANDLE_UNBLOCK_INTERRUPTIONS();
}
+
+ file_handle.opened_path = NULL;
+ zend_destroy_file_handle(&file_handle);
}
accelerator_shm_read_unlock();
@@ -1334,20 +1346,38 @@ int zend_accel_invalidate(const char *filename, size_t filename_len, zend_bool f
return SUCCESS;
}
+static zend_string* accel_new_interned_key(zend_string *key)
+{
+ zend_string *new_key;
+
+ GC_ADDREF(key);
+ new_key = accel_new_interned_string(key);
+ if (UNEXPECTED(new_key == key)) {
+ new_key = zend_shared_alloc(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(ZSTR_LEN(key)), 8));
+ if (EXPECTED(new_key)) {
+ GC_SET_REFCOUNT(new_key, 2);
+ GC_TYPE_INFO(new_key) = GC_STRING | (IS_STR_INTERNED << GC_FLAGS_SHIFT);
+ ZSTR_H(new_key) = ZSTR_H(key);
+ ZSTR_LEN(new_key) = ZSTR_LEN(key);
+ memcpy(ZSTR_VAL(new_key), ZSTR_VAL(key), ZSTR_LEN(new_key) + 1);
+ }
+ }
+ return new_key;
+}
+
/* Adds another key for existing cached script */
-static void zend_accel_add_key(const char *key, unsigned int key_length, zend_accel_hash_entry *bucket)
+static void zend_accel_add_key(zend_string *key, zend_accel_hash_entry *bucket)
{
- if (!zend_accel_hash_str_find(&ZCSG(hash), key, key_length)) {
+ if (!zend_accel_hash_find(&ZCSG(hash), key)) {
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);
} else {
- char *new_key = zend_shared_alloc(key_length + 1);
+ zend_string *new_key = accel_new_interned_key(key);
if (new_key) {
- memcpy(new_key, key, key_length + 1);
- if (zend_accel_hash_update(&ZCSG(hash), new_key, key_length, 1, bucket)) {
- zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", new_key);
+ if (zend_accel_hash_update(&ZCSG(hash), new_key, 1, bucket)) {
+ zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", ZSTR_VAL(new_key));
}
} else {
zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
@@ -1356,7 +1386,7 @@ static void zend_accel_add_key(const char *key, unsigned int key_length, zend_ac
}
}
-static zend_always_inline zend_bool is_phar_file(zend_string *filename)
+static zend_always_inline bool is_phar_file(zend_string *filename)
{
return filename && ZSTR_LEN(filename) >= sizeof(".phar") &&
!memcmp(ZSTR_VAL(filename) + ZSTR_LEN(filename) - (sizeof(".phar")-1), ".phar", sizeof(".phar")-1) &&
@@ -1370,7 +1400,7 @@ static zend_persistent_script *store_script_in_file_cache(zend_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, 0);
+ memory_used = zend_accel_script_persist_calc(new_persistent_script, 0);
/* Allocate memory block */
#if defined(__AVX__) || defined(__SSE2__)
@@ -1388,7 +1418,7 @@ static zend_persistent_script *store_script_in_file_cache(zend_persistent_script
zend_shared_alloc_clear_xlat_table();
/* Copy into memory block */
- new_persistent_script = zend_accel_script_persist(new_persistent_script, NULL, 0, 0);
+ new_persistent_script = zend_accel_script_persist(new_persistent_script, 0);
zend_shared_alloc_destroy_xlat_table();
@@ -1428,7 +1458,7 @@ static zend_persistent_script *cache_script_in_file_cache(zend_persistent_script
return store_script_in_file_cache(new_persistent_script);
}
-static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, const char *key, unsigned int key_length, int *from_shared_memory)
+static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, zend_string *key, int *from_shared_memory)
{
zend_accel_hash_entry *bucket;
uint32_t memory_used;
@@ -1458,7 +1488,7 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr
if (key &&
(!ZCG(accel_directives).validate_timestamps ||
(new_persistent_script->timestamp == existing_persistent_script->timestamp))) {
- zend_accel_add_key(key, key_length, bucket);
+ zend_accel_add_key(key, bucket);
}
zend_shared_alloc_unlock();
#if 1
@@ -1487,7 +1517,7 @@ 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, 1);
+ memory_used = zend_accel_script_persist_calc(new_persistent_script, 1);
/* Allocate shared memory */
#if defined(__AVX__) || defined(__SSE2__)
@@ -1545,7 +1575,7 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr
zend_shared_alloc_clear_xlat_table();
/* Copy into shared memory */
- new_persistent_script = zend_accel_script_persist(new_persistent_script, &key, key_length, 1);
+ new_persistent_script = zend_accel_script_persist(new_persistent_script, 1);
zend_shared_alloc_destroy_xlat_table();
@@ -1565,21 +1595,26 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr
new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
/* store script structure in the hash table */
- bucket = zend_accel_hash_update(&ZCSG(hash), ZSTR_VAL(new_persistent_script->script.filename), ZSTR_LEN(new_persistent_script->script.filename), 0, new_persistent_script);
+ bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->script.filename, 0, new_persistent_script);
if (bucket) {
zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", ZSTR_VAL(new_persistent_script->script.filename));
if (key &&
/* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
- memcmp(key, "phar://", sizeof("phar://") - 1) != 0 &&
- (ZSTR_LEN(new_persistent_script->script.filename) != key_length ||
- memcmp(ZSTR_VAL(new_persistent_script->script.filename), key, key_length) != 0)) {
+ memcmp(ZSTR_VAL(key), "phar://", sizeof("phar://") - 1) != 0 &&
+ !zend_string_equals(new_persistent_script->script.filename, key)) {
/* link key to the same persistent script in hash table */
- if (zend_accel_hash_update(&ZCSG(hash), key, key_length, 1, bucket)) {
- zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", key);
+ zend_string *new_key = accel_new_interned_key(key);
+
+ if (new_key) {
+ if (zend_accel_hash_update(&ZCSG(hash), new_key, 1, bucket)) {
+ zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", ZSTR_VAL(key));
+ } else {
+ 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);
+ }
} else {
- 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_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
}
}
}
@@ -1699,7 +1734,7 @@ static void free_recorded_warnings() {
ZCG(num_warnings) = 0;
}
-static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, const char *key, zend_op_array **op_array_p)
+static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, zend_op_array **op_array_p)
{
zend_persistent_script *new_persistent_script;
uint32_t orig_functions_count, orig_class_count;
@@ -1712,13 +1747,13 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl
/* Try to open file */
if (file_handle->type == ZEND_HANDLE_FILENAME) {
- if (accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) != SUCCESS) {
+ if (accelerator_orig_zend_stream_open_function(file_handle) != SUCCESS) {
*op_array_p = NULL;
if (!EG(exception)) {
if (type == ZEND_REQUIRE) {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
+ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
} else {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
+ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
}
}
return NULL;
@@ -1850,7 +1885,7 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl
if (file_handle->opened_path) {
new_persistent_script->script.filename = zend_string_copy(file_handle->opened_path);
} else {
- new_persistent_script->script.filename = zend_string_init(file_handle->filename, strlen(file_handle->filename), 0);
+ new_persistent_script->script.filename = zend_string_copy(file_handle->filename);
}
zend_string_hash_val(new_persistent_script->script.filename);
@@ -1864,19 +1899,19 @@ zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
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)) {
+ if (is_stream_path(ZSTR_VAL(file_handle->filename)) &&
+ !is_cacheable_stream_path(ZSTR_VAL(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) {
+ accelerator_orig_zend_stream_open_function(file_handle) == FAILURE) {
if (!EG(exception)) {
if (type == ZEND_REQUIRE) {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
+ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
} else {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
+ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
}
}
return NULL;
@@ -1912,7 +1947,6 @@ zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
}
}
replay_warnings(persistent_script);
- zend_file_handle_dtor(file_handle);
if (persistent_script->ping_auto_globals_mask) {
zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask);
@@ -1921,7 +1955,7 @@ zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
return zend_accel_load_script(persistent_script, 1);
}
- persistent_script = opcache_compile_file(file_handle, type, NULL, &op_array);
+ persistent_script = opcache_compile_file(file_handle, type, &op_array);
if (persistent_script) {
from_memory = 0;
@@ -1959,8 +1993,7 @@ int check_persistent_script_access(zend_persistent_script *persistent_script)
zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
{
zend_persistent_script *persistent_script = NULL;
- char *key = NULL;
- int key_length;
+ zend_string *key = NULL;
int from_shared_memory; /* if the script we've got is stored in SHM */
if (!file_handle->filename || !ZCG(accelerator_enabled)) {
@@ -1992,7 +2025,7 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
* persistent script already found */
if (ZCG(cache_persistent_script) &&
((!EG(current_execute_data) &&
- file_handle->filename == SG(request_info).path_translated &&
+ file_handle->primary_script &&
ZCG(cache_opline) == NULL) ||
(EG(current_execute_data) &&
EG(current_execute_data)->func &&
@@ -2000,22 +2033,21 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
ZCG(cache_opline) == EG(current_execute_data)->opline))) {
persistent_script = ZCG(cache_persistent_script);
- if (ZCG(key_len)) {
- key = ZCG(key);
- key_length = ZCG(key_len);
+ if (ZSTR_LEN(&ZCG(key))) {
+ key = &ZCG(key);
}
} else {
if (!ZCG(accel_directives).revalidate_path) {
/* try to find cached script by key */
- key = accel_make_persistent_key(file_handle->filename, strlen(file_handle->filename), &key_length);
+ key = accel_make_persistent_key(file_handle->filename);
if (!key) {
ZCG(cache_opline) = NULL;
ZCG(cache_persistent_script) = NULL;
return accelerator_orig_compile_file(file_handle, type);
}
- persistent_script = zend_accel_hash_str_find(&ZCSG(hash), key, key_length);
- } else if (UNEXPECTED(is_stream_path(file_handle->filename) && !is_cacheable_stream_path(file_handle->filename))) {
+ persistent_script = zend_accel_hash_find(&ZCSG(hash), key);
+ } else if (UNEXPECTED(is_stream_path(ZSTR_VAL(file_handle->filename)) && !is_cacheable_stream_path(ZSTR_VAL(file_handle->filename)))) {
ZCG(cache_opline) = NULL;
ZCG(cache_persistent_script) = NULL;
return accelerator_orig_compile_file(file_handle, type);
@@ -2026,13 +2058,13 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
zend_accel_hash_entry *bucket;
/* open file to resolve the path */
- if (file_handle->type == ZEND_HANDLE_FILENAME &&
- accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) == FAILURE) {
+ if (file_handle->type == ZEND_HANDLE_FILENAME
+ && accelerator_orig_zend_stream_open_function(file_handle) == FAILURE) {
if (!EG(exception)) {
if (type == ZEND_REQUIRE) {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
+ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
} else {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
+ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
}
}
return NULL;
@@ -2048,7 +2080,7 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
HANDLE_BLOCK_INTERRUPTIONS();
SHM_UNPROTECT();
zend_shared_alloc_lock();
- zend_accel_add_key(key, key_length, bucket);
+ zend_accel_add_key(key, bucket);
zend_shared_alloc_unlock();
SHM_PROTECT();
HANDLE_UNBLOCK_INTERRUPTIONS();
@@ -2087,9 +2119,9 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
UNEXPECTED(check_persistent_script_access(persistent_script))) {
if (!EG(exception)) {
if (type == ZEND_REQUIRE) {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
+ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
} else {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
+ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
}
}
return NULL;
@@ -2167,7 +2199,7 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
SHM_PROTECT();
HANDLE_UNBLOCK_INTERRUPTIONS();
- persistent_script = opcache_compile_file(file_handle, type, key, &op_array);
+ persistent_script = opcache_compile_file(file_handle, type, &op_array);
HANDLE_BLOCK_INTERRUPTIONS();
SHM_UNPROTECT();
@@ -2176,7 +2208,7 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
*/
from_shared_memory = 0;
if (persistent_script) {
- persistent_script = cache_script_in_shared_memory(persistent_script, key, key ? key_length : 0, &from_shared_memory);
+ persistent_script = cache_script_in_shared_memory(persistent_script, key, &from_shared_memory);
}
/* Caching is disabled, returning op_array;
@@ -2232,7 +2264,6 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
}
}
replay_warnings(persistent_script);
- zend_file_handle_dtor(file_handle);
from_shared_memory = 1;
}
@@ -2249,6 +2280,212 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
return zend_accel_load_script(persistent_script, from_shared_memory);
}
+static zend_always_inline zend_inheritance_cache_entry* zend_accel_inheritance_cache_find(zend_inheritance_cache_entry *entry, zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, bool *needs_autoload_ptr)
+{
+ uint32_t i;
+
+ ZEND_ASSERT(ce->ce_flags & ZEND_ACC_IMMUTABLE);
+ ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
+
+ while (entry) {
+ bool found = 1;
+ bool needs_autoload = 0;
+
+ if (entry->parent != parent) {
+ found = 0;
+ } else {
+ for (i = 0; i < ce->num_traits + ce->num_interfaces; i++) {
+ if (entry->traits_and_interfaces[i] != traits_and_interfaces[i]) {
+ found = 0;
+ break;
+ }
+ }
+ if (found && entry->dependencies) {
+ for (i = 0; i < entry->dependencies_count; i++) {
+ zend_class_entry *ce = zend_lookup_class_ex(entry->dependencies[i].name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
+
+ if (ce != entry->dependencies[i].ce) {
+ if (!ce) {
+ needs_autoload = 1;
+ } else {
+ found = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (found) {
+ *needs_autoload_ptr = needs_autoload;
+ return entry;
+ }
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+static zend_class_entry* zend_accel_inheritance_cache_get(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces)
+{
+ uint32_t i;
+ bool needs_autoload;
+ zend_inheritance_cache_entry *entry = ce->inheritance_cache;
+
+ while (entry) {
+ entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
+ if (entry) {
+ if (!needs_autoload) {
+ if (ZCSG(map_ptr_last) > CG(map_ptr_last)) {
+ zend_map_ptr_extend(ZCSG(map_ptr_last));
+ }
+ return entry->ce;
+ }
+
+ for (i = 0; i < entry->dependencies_count; i++) {
+ zend_class_entry *ce = zend_lookup_class_ex(entry->dependencies[i].name, NULL, 0);
+
+ if (ce == NULL) {
+ return NULL;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies)
+{
+ zend_persistent_script dummy;
+ size_t size;
+ uint32_t i;
+ bool needs_autoload;
+ zend_class_entry *new_ce;
+ zend_inheritance_cache_entry *entry;
+
+ ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_IMMUTABLE));
+ ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
+
+ if (!ZCG(accelerator_enabled) ||
+ (ZCSG(restart_in_progress) && accel_restart_is_active())) {
+ return NULL;
+ }
+
+ if (traits_and_interfaces && dependencies) {
+ for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
+ if (traits_and_interfaces[i]) {
+ zend_hash_del(dependencies, traits_and_interfaces[i]->name);
+ }
+ }
+ }
+
+ SHM_UNPROTECT();
+ zend_shared_alloc_lock();
+
+ entry = ce->inheritance_cache;
+ while (entry) {
+ entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
+ if (entry) {
+ if (!needs_autoload) {
+ zend_shared_alloc_unlock();
+ SHM_PROTECT();
+
+ zend_map_ptr_extend(ZCSG(map_ptr_last));
+ return entry->ce;
+ }
+ ZEND_ASSERT(0); // entry = entry->next; // This shouldn't be posible ???
+ }
+ }
+
+ zend_shared_alloc_init_xlat_table();
+
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.size = ZEND_ALIGNED_SIZE(
+ sizeof(zend_inheritance_cache_entry) -
+ sizeof(void*) +
+ (sizeof(void*) * (proto->num_traits + proto->num_interfaces)));
+ if (dependencies) {
+ dummy.size += ZEND_ALIGNED_SIZE(zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency));
+ }
+ ZCG(current_persistent_script) = &dummy;
+ zend_persist_class_entry_calc(ce);
+ size = dummy.size;
+
+ zend_shared_alloc_clear_xlat_table();
+
+#if ZEND_MM_ALIGNMENT < 8
+ /* Align to 8-byte boundary */
+ ZCG(mem) = zend_shared_alloc(size + 8);
+#else
+ ZCG(mem) = zend_shared_alloc(size);
+#endif
+
+ if (!ZCG(mem)) {
+ zend_shared_alloc_destroy_xlat_table();
+ zend_shared_alloc_unlock();
+ SHM_PROTECT();
+ return NULL;
+ }
+
+#if ZEND_MM_ALIGNMENT < 8
+ /* Align to 8-byte boundary */
+ ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 7L) & ~7L);
+#endif
+
+ memset(ZCG(mem), 0, size);
+ entry = (zend_inheritance_cache_entry*)ZCG(mem);
+ ZCG(mem) = (char*)ZCG(mem) +
+ ZEND_ALIGNED_SIZE(
+ (sizeof(zend_inheritance_cache_entry) -
+ sizeof(void*) +
+ (sizeof(void*) * (proto->num_traits + proto->num_interfaces))));
+ entry->parent = parent;
+ for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
+ entry->traits_and_interfaces[i] = traits_and_interfaces[i];
+ }
+ if (dependencies && zend_hash_num_elements(dependencies)) {
+ zend_string *dep_name;
+ zend_class_entry *dep_ce;
+
+ i = 0;
+ entry->dependencies_count = zend_hash_num_elements(dependencies);
+ entry->dependencies = (zend_class_dependency*)ZCG(mem);
+ ZEND_HASH_FOREACH_STR_KEY_PTR(dependencies, dep_name, dep_ce) {
+#if ZEND_DEBUG
+ ZEND_ASSERT(zend_accel_in_shm(dep_name));
+#endif
+ entry->dependencies[i].name = dep_name;
+ entry->dependencies[i].ce = dep_ce;
+ i++;
+ } ZEND_HASH_FOREACH_END();
+ ZCG(mem) = (char*)ZCG(mem) + zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency);
+ }
+ entry->ce = new_ce = zend_persist_class_entry(ce);
+ zend_update_parent_ce(new_ce);
+ entry->next = proto->inheritance_cache;
+ proto->inheritance_cache = entry;
+
+ zend_shared_alloc_destroy_xlat_table();
+
+ zend_shared_alloc_unlock();
+ SHM_PROTECT();
+
+ /* Consistency check */
+ if ((char*)entry + size != (char*)ZCG(mem)) {
+ zend_accel_error(
+ ((char*)entry + size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
+ "Internal error: wrong class size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
+ ZSTR_VAL(ce->name),
+ (size_t)entry,
+ (size_t)((char *)entry + size),
+ (size_t)ZCG(mem));
+ }
+
+ zend_map_ptr_extend(ZCSG(map_ptr_last));
+
+ return new_ce;
+}
+
#ifdef ZEND_WIN32
static int accel_gen_uname_id(void)
{
@@ -2270,12 +2507,12 @@ static int accel_gen_uname_id(void)
#endif
/* zend_stream_open_function() replacement for PHP 5.3 and above */
-static zend_result persistent_stream_open_function(const char *filename, zend_file_handle *handle)
+static zend_result persistent_stream_open_function(zend_file_handle *handle)
{
if (ZCG(cache_persistent_script)) {
/* check if callback is called from include_once or it's a main request */
if ((!EG(current_execute_data) &&
- filename == SG(request_info).path_translated &&
+ handle->primary_script &&
ZCG(cache_opline) == NULL) ||
(EG(current_execute_data) &&
EG(current_execute_data)->func &&
@@ -2283,25 +2520,23 @@ static zend_result persistent_stream_open_function(const char *filename, zend_fi
ZCG(cache_opline) == EG(current_execute_data)->opline)) {
/* we are in include_once or FastCGI request */
- zend_stream_init_filename(handle, (char*) filename);
handle->opened_path = zend_string_copy(ZCG(cache_persistent_script)->script.filename);
return SUCCESS;
}
ZCG(cache_opline) = NULL;
ZCG(cache_persistent_script) = NULL;
}
- return accelerator_orig_zend_stream_open_function(filename, handle);
+ return accelerator_orig_zend_stream_open_function(handle);
}
/* zend_resolve_path() replacement for PHP 5.3 and above */
-static zend_string* persistent_zend_resolve_path(const char *filename, size_t filename_len)
+static zend_string* persistent_zend_resolve_path(zend_string *filename)
{
if (!file_cache_only &&
ZCG(accelerator_enabled)) {
/* check if callback is called from include_once or it's a main request */
- if ((!EG(current_execute_data) &&
- filename == SG(request_info).path_translated) ||
+ if ((!EG(current_execute_data)) ||
(EG(current_execute_data) &&
EG(current_execute_data)->func &&
ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
@@ -2311,14 +2546,13 @@ static zend_string* persistent_zend_resolve_path(const char *filename, size_t fi
/* we are in include_once or FastCGI request */
zend_string *resolved_path;
- int key_length;
- char *key = NULL;
+ zend_string *key = NULL;
if (!ZCG(accel_directives).revalidate_path) {
/* lookup by "not-real" path */
- key = accel_make_persistent_key(filename, filename_len, &key_length);
+ key = accel_make_persistent_key(filename);
if (key) {
- zend_accel_hash_entry *bucket = zend_accel_hash_str_find_entry(&ZCSG(hash), key, key_length);
+ zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), key);
if (bucket != NULL) {
zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
if (!persistent_script->corrupted) {
@@ -2330,12 +2564,12 @@ static zend_string* persistent_zend_resolve_path(const char *filename, size_t fi
} else {
ZCG(cache_opline) = NULL;
ZCG(cache_persistent_script) = NULL;
- return accelerator_orig_zend_resolve_path(filename, filename_len);
+ return accelerator_orig_zend_resolve_path(filename);
}
}
/* find the full real path */
- resolved_path = accelerator_orig_zend_resolve_path(filename, filename_len);
+ resolved_path = accelerator_orig_zend_resolve_path(filename);
if (resolved_path) {
/* lookup by real path */
@@ -2348,12 +2582,12 @@ static zend_string* persistent_zend_resolve_path(const char *filename, size_t fi
HANDLE_BLOCK_INTERRUPTIONS();
SHM_UNPROTECT();
zend_shared_alloc_lock();
- zend_accel_add_key(key, key_length, bucket);
+ zend_accel_add_key(key, bucket);
zend_shared_alloc_unlock();
SHM_PROTECT();
HANDLE_UNBLOCK_INTERRUPTIONS();
} else {
- ZCG(key_len) = 0;
+ ZSTR_LEN(&ZCG(key)) = 0;
}
ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
ZCG(cache_persistent_script) = persistent_script;
@@ -2369,7 +2603,7 @@ static zend_string* persistent_zend_resolve_path(const char *filename, size_t fi
}
ZCG(cache_opline) = NULL;
ZCG(cache_persistent_script) = NULL;
- return accelerator_orig_zend_resolve_path(filename, filename_len);
+ return accelerator_orig_zend_resolve_path(filename);
}
static void zend_reset_cache_vars(void)
@@ -2642,7 +2876,7 @@ static int zend_accel_init_shm(void)
accel_shared_globals = zend_shared_alloc(sizeof(zend_accel_shared_globals) + sizeof(uint32_t));
}
if (!accel_shared_globals) {
- zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
zend_shared_alloc_unlock();
return FAILURE;
}
@@ -2960,9 +3194,6 @@ static zend_result accel_post_startup(void)
}
}
- /* Initialize zend_func_info_rid */
- zend_optimizer_startup();
-
/********************************************/
/* End of non-SHM dependent initializations */
/********************************************/
@@ -2971,7 +3202,7 @@ static zend_result accel_post_startup(void)
size_t shm_size = ZCG(accel_directives).memory_consumption;
#ifdef HAVE_JIT
size_t jit_size = 0;
- zend_bool reattached = 0;
+ bool reattached = 0;
if (JIT_G(enabled) && JIT_G(buffer_size)
&& zend_jit_check_support() == SUCCESS) {
@@ -2985,7 +3216,7 @@ static zend_result accel_post_startup(void)
page_size = getpagesize();
# endif
if (!page_size || (page_size & (page_size - 1))) {
- zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can't get page size.");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can't get page size.");
abort();
}
jit_size = JIT_G(buffer_size);
@@ -3005,7 +3236,7 @@ static zend_result accel_post_startup(void)
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.");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
return SUCCESS;
case SUCCESSFULLY_REATTACHED:
#if defined(HAVE_JIT) && !defined(ZEND_WIN32)
@@ -3018,7 +3249,7 @@ static zend_result accel_post_startup(void)
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.");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can not reattach to exiting shared memory.");
return SUCCESS;
break;
#if ENABLE_FILE_CACHE_FALLBACK
@@ -3058,7 +3289,7 @@ static zend_result accel_post_startup(void)
SHM_PROTECT();
} 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");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_only is set without a proper setting of opcache.file_cache");
return SUCCESS;
} else {
#ifdef HAVE_JIT
@@ -3122,13 +3353,23 @@ file_cache_fallback:
zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
}
- zend_optimizer_startup();
-
if (!file_cache_only && ZCG(accel_directives).interned_strings_buffer) {
accel_use_shm_interned_strings();
}
- return accel_finish_startup();
+ if (accel_finish_startup() != SUCCESS) {
+ return FAILURE;
+ }
+
+ if (ZCG(enabled) && accel_startup_ok) {
+ /* Override inheritance cache callbaks */
+ accelerator_orig_inheritance_cache_get = zend_inheritance_cache_get;
+ accelerator_orig_inheritance_cache_add = zend_inheritance_cache_add;
+ zend_inheritance_cache_get = zend_accel_inheritance_cache_get;
+ zend_inheritance_cache_add = zend_accel_inheritance_cache_add;
+ }
+
+ return SUCCESS;
}
static void (*orig_post_shutdown_cb)(void);
@@ -3141,14 +3382,12 @@ static void accel_post_shutdown(void)
void accel_shutdown(void)
{
zend_ini_entry *ini_entry;
- zend_bool _file_cache_only = 0;
+ bool _file_cache_only = 0;
#ifdef HAVE_JIT
zend_jit_shutdown();
#endif
- zend_optimizer_shutdown();
-
zend_accel_blacklist_shutdown(&accel_blacklist);
if (!ZCG(enabled) || !accel_startup_ok) {
@@ -3177,6 +3416,8 @@ void accel_shutdown(void)
}
zend_compile_file = accelerator_orig_compile_file;
+ zend_inheritance_cache_get = accelerator_orig_inheritance_cache_get;
+ zend_inheritance_cache_add = accelerator_orig_inheritance_cache_add;
if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
ini_entry->on_modify = orig_include_path_on_modify;
@@ -3304,11 +3545,11 @@ static void preload_activate(void)
static void preload_restart(void)
{
- zend_accel_hash_update(&ZCSG(hash), ZSTR_VAL(ZCSG(preload_script)->script.filename), ZSTR_LEN(ZCSG(preload_script)->script.filename), 0, ZCSG(preload_script));
+ zend_accel_hash_update(&ZCSG(hash), ZCSG(preload_script)->script.filename, 0, ZCSG(preload_script));
if (ZCSG(saved_scripts)) {
zend_persistent_script **p = ZCSG(saved_scripts);
while (*p) {
- zend_accel_hash_update(&ZCSG(hash), ZSTR_VAL((*p)->script.filename), ZSTR_LEN((*p)->script.filename), 0, *p);
+ zend_accel_hash_update(&ZCSG(hash), (*p)->script.filename, 0, *p);
p++;
}
}
@@ -3420,11 +3661,6 @@ static zend_op_array *preload_compile_file(zend_file_handle *file_handle, int ty
//??? efree(op_array->refcount);
op_array->refcount = NULL;
- if (op_array->static_variables &&
- !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
- GC_ADDREF(op_array->static_variables);
- }
-
zend_hash_add_ptr(preload_scripts, script->script.filename, script);
}
@@ -3479,35 +3715,7 @@ try_again:
}
}
-static void get_unresolved_initializer(zend_class_entry *ce, const char **kind, const char **name) {
- zend_string *key;
- zend_class_constant *c;
- zend_property_info *prop;
-
- *kind = "unknown";
- *name = "";
-
- ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
- if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
- *kind = "constant ";
- *name = ZSTR_VAL(key);
- }
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop) {
- zval *val;
- if (prop->flags & ZEND_ACC_STATIC) {
- val = &ce->default_static_members_table[prop->offset];
- } else {
- val = &ce->default_properties_table[OBJ_PROP_TO_NUM(prop->offset)];
- }
- if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
- *kind = (prop->flags & ZEND_ACC_STATIC) ? "static property $" : "property $";
- *name = ZSTR_VAL(key);
- }
- } ZEND_HASH_FOREACH_END();
-}
-
-static zend_bool preload_needed_types_known(zend_class_entry *ce);
+static bool preload_needed_types_known(zend_class_entry *ce);
static void get_unlinked_dependency(zend_class_entry *ce, const char **kind, const char **name) {
zend_class_entry *p;
*kind = "Unknown reason";
@@ -3522,16 +3730,6 @@ static void get_unlinked_dependency(zend_class_entry *ce, const char **kind, con
*name = ZSTR_VAL(ce->parent_name);
return;
}
- if (!(p->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
- *kind = "Parent with unresolved initializers ";
- *name = ZSTR_VAL(ce->parent_name);
- return;
- }
- if (!(p->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
- *kind = "Parent with unresolved property types ";
- *name = ZSTR_VAL(ce->parent_name);
- return;
- }
}
if (ce->num_interfaces) {
@@ -3564,14 +3762,13 @@ static void get_unlinked_dependency(zend_class_entry *ce, const char **kind, con
}
}
-static zend_bool preload_try_resolve_constants(zend_class_entry *ce)
+static bool preload_try_resolve_constants(zend_class_entry *ce)
{
- zend_bool ok, changed;
+ bool ok, changed, was_changed = 0;
zend_class_constant *c;
zval *val;
EG(exception) = (void*)(uintptr_t)-1; /* prevent error reporting */
- CG(in_compilation) = 1; /* prevent autoloading */
do {
ok = 1;
changed = 0;
@@ -3579,68 +3776,71 @@ static zend_bool preload_try_resolve_constants(zend_class_entry *ce)
val = &c->value;
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
if (EXPECTED(zval_update_constant_ex(val, c->ce) == SUCCESS)) {
- changed = 1;
+ was_changed = changed = 1;
} else {
ok = 0;
}
}
} ZEND_HASH_FOREACH_END();
+ if (ok) {
+ ce->ce_flags &= ~ZEND_ACC_HAS_AST_CONSTANTS;
+ }
if (ce->default_properties_count) {
uint32_t i;
+ bool resolved = 1;
+
for (i = 0; i < ce->default_properties_count; i++) {
val = &ce->default_properties_table[i];
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
zend_property_info *prop = ce->properties_info_table[i];
if (UNEXPECTED(zval_update_constant_ex(val, prop->ce) != SUCCESS)) {
- ok = 0;
+ resolved = ok = 0;
}
}
}
+ if (resolved) {
+ ce->ce_flags &= ~ZEND_ACC_HAS_AST_PROPERTIES;
+ }
}
if (ce->default_static_members_count) {
uint32_t count = ce->parent ? ce->default_static_members_count - ce->parent->default_static_members_count : ce->default_static_members_count;
+ bool resolved = 1;
val = ce->default_static_members_table + ce->default_static_members_count - 1;
while (count) {
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) {
- ok = 0;
+ resolved = ok = 0;
}
}
val--;
count--;
}
+ if (resolved) {
+ ce->ce_flags &= ~ZEND_ACC_HAS_AST_STATICS;
+ }
}
} while (changed && !ok);
EG(exception) = NULL;
CG(in_compilation) = 0;
- return ok;
+ if (ok) {
+ ce->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
+ }
+
+ return ok || was_changed;
}
-static zend_class_entry *preload_fetch_resolved_ce(zend_string *name, zend_class_entry *self_ce) {
+static zend_class_entry *preload_fetch_resolved_ce(zend_string *name) {
zend_string *lcname = zend_string_tolower(name);
zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lcname);
zend_string_release(lcname);
- if (!ce) {
- return NULL;
- }
- if (ce == self_ce) {
- /* Ignore the following requirements if this is the class referring to itself */
- return ce;
- }
- if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
- return NULL;
- }
- if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
- return NULL;
- }
return ce;
}
-static zend_bool preload_try_resolve_property_types(zend_class_entry *ce)
+static bool preload_try_resolve_property_types(zend_class_entry *ce)
{
- zend_bool ok = 1;
+ bool ok = 1;
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_property_info *prop;
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
@@ -3648,7 +3848,7 @@ static zend_bool preload_try_resolve_property_types(zend_class_entry *ce)
ZEND_TYPE_FOREACH(prop->type, single_type) {
if (ZEND_TYPE_HAS_NAME(*single_type)) {
zend_class_entry *p =
- preload_fetch_resolved_ce(ZEND_TYPE_NAME(*single_type), ce);
+ preload_fetch_resolved_ce(ZEND_TYPE_NAME(*single_type));
if (!p) {
ok = 0;
continue;
@@ -3657,12 +3857,15 @@ static zend_bool preload_try_resolve_property_types(zend_class_entry *ce)
}
} ZEND_TYPE_FOREACH_END();
} ZEND_HASH_FOREACH_END();
+ if (ok) {
+ ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
+ }
}
return ok;
}
-static zend_bool preload_is_class_type_known(zend_class_entry *ce, zend_string *name) {
+static bool preload_is_class_type_known(zend_class_entry *ce, zend_string *name) {
if (zend_string_equals_literal_ci(name, "self") ||
zend_string_equals_literal_ci(name, "parent") ||
zend_string_equals_ci(name, ce->name)) {
@@ -3670,12 +3873,12 @@ static zend_bool preload_is_class_type_known(zend_class_entry *ce, zend_string *
}
zend_string *lcname = zend_string_tolower(name);
- zend_bool known = zend_hash_exists(EG(class_table), lcname);
+ bool known = zend_hash_exists(EG(class_table), lcname);
zend_string_release(lcname);
return known;
}
-static zend_bool preload_is_type_known(zend_class_entry *ce, zend_type *type) {
+static bool preload_is_type_known(zend_class_entry *ce, zend_type *type) {
zend_type *single_type;
ZEND_TYPE_FOREACH(*type, single_type) {
if (ZEND_TYPE_HAS_NAME(*single_type)) {
@@ -3687,7 +3890,7 @@ static zend_bool preload_is_type_known(zend_class_entry *ce, zend_type *type) {
return 1;
}
-static zend_bool preload_is_method_maybe_override(zend_class_entry *ce, zend_string *lcname) {
+static bool preload_is_method_maybe_override(zend_class_entry *ce, zend_string *lcname) {
zend_class_entry *p;
if (ce->trait_aliases || ce->trait_precedences) {
return 1;
@@ -3725,7 +3928,7 @@ static zend_bool preload_is_method_maybe_override(zend_class_entry *ce, zend_str
return 0;
}
-static zend_bool preload_needed_types_known(zend_class_entry *ce) {
+static bool preload_needed_types_known(zend_class_entry *ce) {
zend_function *fptr;
zend_string *lcname;
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, lcname, fptr) {
@@ -3752,7 +3955,7 @@ static void preload_link(void)
zend_persistent_script *script;
zend_class_entry *ce, *parent, *p;
zend_string *key;
- zend_bool found, changed;
+ bool found, changed;
uint32_t i;
dtor_func_t orig_dtor;
zend_function *function;
@@ -3785,12 +3988,6 @@ static void preload_link(void)
parent = zend_hash_find_ptr(EG(class_table), key);
zend_string_release(key);
if (!parent) continue;
- if (!(parent->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
- continue;
- }
- if (!(parent->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
- continue;
- }
}
if (ce->num_interfaces) {
@@ -3801,10 +3998,6 @@ static void preload_link(void)
found = 0;
break;
}
- if (!(p->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
- found = 0;
- break;
- }
}
if (!found) continue;
}
@@ -3829,11 +4022,8 @@ static void preload_link(void)
continue;
}
- {
- zend_string *key = zend_string_tolower(ce->name);
- zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, key);
- zend_string_release(key);
- }
+ key = zend_string_tolower(ce->name);
+ zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, key);
if (EXPECTED(zv)) {
/* Set filename & lineno information for inheritance errors */
@@ -3849,7 +4039,8 @@ static void preload_link(void)
} else {
CG(zend_lineno) = ce->info.user.line_start;
}
- if (zend_do_link_class(ce, NULL) == FAILURE) {
+ ce = zend_do_link_class(ce, NULL, key);
+ if (!ce) {
ZEND_ASSERT(0 && "Class linking failed?");
}
CG(in_compilation) = 0;
@@ -3857,22 +4048,41 @@ static void preload_link(void)
changed = 1;
}
+
+ zend_string_release(key);
}
- if (ce->ce_flags & ZEND_ACC_LINKED) {
- if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
- if ((ce->ce_flags & ZEND_ACC_TRAIT) /* don't update traits */
- || preload_try_resolve_constants(ce)) {
- ce->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
- changed = 1;
- }
- }
+ } ZEND_HASH_FOREACH_END();
+ } while (changed);
- if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
- if ((ce->ce_flags & ZEND_ACC_TRAIT) /* don't update traits */
- || preload_try_resolve_property_types(ce)) {
- ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
+ /* Resolve property types */
+ ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
+ ce = Z_PTR_P(zv);
+ if (ce->type == ZEND_INTERNAL_CLASS) {
+ break;
+ }
+ if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
+ if (!(ce->ce_flags & ZEND_ACC_TRAIT)) {
+ preload_try_resolve_property_types(ce);
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+
+
+ do {
+ changed = 0;
+
+ ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
+ ce = Z_PTR_P(zv);
+ if (ce->type == ZEND_INTERNAL_CLASS) {
+ break;
+ }
+ if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
+ if (!(ce->ce_flags & ZEND_ACC_TRAIT)) { /* don't update traits */
+ CG(in_compilation) = 1; /* prevent autoloading */
+ if (preload_try_resolve_constants(ce)) {
changed = 1;
}
+ CG(in_compilation) = 0;
}
}
} ZEND_HASH_FOREACH_END();
@@ -3902,18 +4112,6 @@ static void preload_link(void)
ZSTR_VAL(ce->name), kind, name);
}
zend_string_release(key);
- } else if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
- const char *kind, *name;
- get_unresolved_initializer(ce, &kind, &name);
- zend_error_at(
- E_WARNING, ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start,
- "Can't preload class %s with unresolved initializer for %s%s",
- ZSTR_VAL(ce->name), kind, name);
- } else if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
- zend_error_at(
- E_WARNING, ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start,
- "Can't preload class %s with unresolved property types",
- ZSTR_VAL(ce->name));
} else {
continue;
}
@@ -3967,7 +4165,7 @@ static inline int preload_update_class_constants(zend_class_entry *ce) {
* maybe-uninitialized analysis. */
int result;
zend_try {
- result = zend_update_class_constants(ce);
+ result = preload_try_resolve_constants(ce) ? SUCCESS : FAILURE;
} zend_catch {
result = FAILURE;
} zend_end_try();
@@ -3983,13 +4181,6 @@ static zend_class_entry *preload_load_prop_type(zend_property_info *prop, zend_s
} else {
ce = zend_lookup_class(name);
}
- if (ce) {
- return ce;
- }
-
- zend_error_noreturn(E_ERROR,
- "Failed to load class %s used by typed property %s::$%s during preloading",
- ZSTR_VAL(name), ZSTR_VAL(prop->ce->name), zend_get_unmangled_property_name(prop->name));
return ce;
}
@@ -4015,12 +4206,7 @@ static void preload_ensure_classes_loadable() {
}
if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
- if (preload_update_class_constants(ce) == FAILURE) {
- zend_error_noreturn(E_ERROR,
- "Failed to resolve initializers of class %s during preloading",
- ZSTR_VAL(ce->name));
- }
- ZEND_ASSERT(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED);
+ preload_update_class_constants(ce);
}
if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
@@ -4032,7 +4218,9 @@ static void preload_ensure_classes_loadable() {
if (ZEND_TYPE_HAS_NAME(*single_type)) {
zend_class_entry *ce = preload_load_prop_type(
prop, ZEND_TYPE_NAME(*single_type));
- ZEND_TYPE_SET_CE(*single_type, ce);
+ if (ce) {
+ ZEND_TYPE_SET_CE(*single_type, ce);
+ }
}
} ZEND_TYPE_FOREACH_END();
} ZEND_HASH_FOREACH_END();
@@ -4049,13 +4237,13 @@ static zend_string *preload_resolve_path(zend_string *filename)
if (is_stream_path(ZSTR_VAL(filename))) {
return NULL;
}
- return zend_resolve_path(ZSTR_VAL(filename), ZSTR_LEN(filename));
+ return zend_resolve_path(filename);
}
static void preload_remove_empty_includes(void)
{
zend_persistent_script *script;
- zend_bool changed;
+ bool changed;
/* mark all as empty */
ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
@@ -4224,14 +4412,14 @@ static zend_persistent_script* preload_script_in_shared_memory(zend_persistent_s
uint32_t checkpoint;
if (zend_accel_hash_is_full(&ZCSG(hash))) {
- zend_accel_error(ACCEL_LOG_FATAL, "Not enough entries in hash table for preloading. Consider increasing the value for the opcache.max_accelerated_files directive in php.ini.");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Not enough entries in hash table for preloading. Consider increasing the value for the opcache.max_accelerated_files directive in php.ini.");
return NULL;
}
checkpoint = zend_shared_alloc_checkpoint_xlat_table();
/* Calculate the required memory size */
- memory_used = zend_accel_script_persist_calc(new_persistent_script, NULL, 0, 1);
+ memory_used = zend_accel_script_persist_calc(new_persistent_script, 1);
/* Allocate shared memory */
#if defined(__AVX__) || defined(__SSE2__)
@@ -4276,14 +4464,14 @@ static zend_persistent_script* preload_script_in_shared_memory(zend_persistent_s
}
#endif
if (!ZCG(mem)) {
- zend_accel_error(ACCEL_LOG_FATAL, "Not enough shared memory for preloading. Consider increasing the value for the opcache.memory_consumption directive in php.ini.");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Not enough shared memory for preloading. Consider increasing the value for the opcache.memory_consumption directive in php.ini.");
return NULL;
}
zend_shared_alloc_restore_xlat_table(checkpoint);
/* Copy into shared memory */
- new_persistent_script = zend_accel_script_persist(new_persistent_script, NULL, 0, 1);
+ new_persistent_script = zend_accel_script_persist(new_persistent_script, 1);
new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
@@ -4301,7 +4489,7 @@ static zend_persistent_script* preload_script_in_shared_memory(zend_persistent_s
new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
/* store script structure in the hash table */
- bucket = zend_accel_hash_update(&ZCSG(hash), ZSTR_VAL(new_persistent_script->script.filename), ZSTR_LEN(new_persistent_script->script.filename), 0, new_persistent_script);
+ bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->script.filename, 0, new_persistent_script);
if (bucket) {
zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", ZSTR_VAL(new_persistent_script->script.filename));
}
@@ -4362,7 +4550,7 @@ static zend_result preload_autoload(zend_string *filename)
zend_op_array *op_array;
zend_execute_data *old_execute_data;
zend_class_entry *old_fake_scope;
- zend_bool do_bailout = 0;
+ bool do_bailout = 0;
int ret = SUCCESS;
if (zend_hash_exists(&EG(included_files), filename)) {
@@ -4425,7 +4613,7 @@ static zend_result preload_autoload(zend_string *filename)
return ret;
}
-static int accel_preload(const char *config, zend_bool in_child)
+static int accel_preload(const char *config, bool in_child)
{
zend_file_handle file_handle;
int ret;
@@ -4565,15 +4753,8 @@ static int accel_preload(const char *config, zend_bool in_child)
ZEND_ASSERT(ce->ce_flags & ZEND_ACC_PRELOADED);
if (ce->default_static_members_count) {
zend_cleanup_internal_class_data(ce);
- if (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) {
- int i;
-
- for (i = 0; i < ce->default_static_members_count; i++) {
- if (Z_TYPE(ce->default_static_members_table[i]) == IS_CONSTANT_AST) {
- ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
- break;
- }
- }
+ if (ce->ce_flags & ZEND_ACC_HAS_AST_STATICS) {
+ ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
}
}
if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
@@ -4598,7 +4779,7 @@ static int accel_preload(const char *config, zend_bool in_child)
CG(map_ptr_last) = orig_map_ptr_last;
if (EG(full_tables_cleanup)) {
- zend_accel_error(ACCEL_LOG_FATAL, "Preloading is not compatible with dl() function.");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading is not compatible with dl() function.");
ret = FAILURE;
goto finish;
}
@@ -4681,7 +4862,7 @@ static int accel_preload(const char *config, zend_bool in_child)
zend_hash_sort_ex(&script->script.class_table, preload_sort_classes, NULL, 0);
if (preload_optimize(script) != SUCCESS) {
- zend_accel_error(ACCEL_LOG_FATAL, "Optimization error during preloading!");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Optimization error during preloading!");
return FAILURE;
}
@@ -4708,8 +4889,6 @@ static int accel_preload(const char *config, zend_bool in_child)
SHM_PROTECT();
HANDLE_UNBLOCK_INTERRUPTIONS();
- ZEND_ASSERT(ZCSG(preload_script)->arena_size == 0);
-
preload_load();
/* Store individual scripts with unlinked classes */
@@ -4780,7 +4959,7 @@ static int accel_finish_startup(void)
if (ZCG(accel_directives).preload && *ZCG(accel_directives).preload) {
#ifdef ZEND_WIN32
- zend_accel_error(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
+ zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
return FAILURE;
#else
int in_child = 0;
@@ -4798,7 +4977,7 @@ static int accel_finish_startup(void)
size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
void (*orig_flush)(void *server_context) = sapi_module.flush;
#ifdef ZEND_SIGNALS
- zend_bool old_reset_signals = SIGG(reset);
+ bool old_reset_signals = SIGG(reset);
#endif
if (UNEXPECTED(file_cache_only)) {
@@ -4823,21 +5002,21 @@ static int accel_finish_startup(void)
if (!ZCG(accel_directives).preload_user
|| !*ZCG(accel_directives).preload_user) {
zend_shared_alloc_unlock();
- zend_accel_error(ACCEL_LOG_FATAL, "\"opcache.preload_user\" has not been defined");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "\"opcache.preload_user\" has not been defined");
return FAILURE;
}
pw = getpwnam(ZCG(accel_directives).preload_user);
if (pw == NULL) {
zend_shared_alloc_unlock();
- zend_accel_error(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
return FAILURE;
}
pid = fork();
if (pid == -1) {
zend_shared_alloc_unlock();
- zend_accel_error(ACCEL_LOG_FATAL, "Preloading failed to fork()");
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to fork()");
return FAILURE;
} else if (pid == 0) { /* children */
if (setgid(pw->pw_gid) < 0) {
@@ -4858,7 +5037,7 @@ static int accel_finish_startup(void)
if (waitpid(pid, &status, 0) < 0) {
zend_shared_alloc_unlock();
- zend_accel_error(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
+ zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
return FAILURE;
}
@@ -4904,7 +5083,7 @@ static int accel_finish_startup(void)
EG(error_reporting) = orig_error_reporting;
if (rc == SUCCESS) {
- zend_bool orig_report_memleaks;
+ bool orig_report_memleaks;
/* don't send headers */
SG(headers_sent) = 1;