diff options
Diffstat (limited to 'ext/opcache/ZendAccelerator.c')
-rw-r--r-- | ext/opcache/ZendAccelerator.c | 741 |
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; |