From fc8d6b679786cdfebc692b74cdaf4e508a916a3e Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 22 Aug 2018 13:45:56 +0300 Subject: [PATCH] Introduced ZEND_COMPILE_IGNORE_OTHER_FILES compiler option, to allow "separate" file compilation (unaffected but previously compiled files), without CG(function_table)/CG(class_table) manipulation. --- Zend/zend_compile.c | 10 +++-- Zend/zend_compile.h | 3 ++ ext/opcache/ZendAccelerator.c | 48 ++++++----------------- ext/opcache/ZendAccelerator.h | 4 -- ext/opcache/zend_accelerator_util_funcs.c | 39 +++--------------- ext/opcache/zend_accelerator_util_funcs.h | 5 +-- 6 files changed, 27 insertions(+), 82 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 3fd4ca60cc..c5afd1e893 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1186,9 +1186,11 @@ void zend_do_early_binding(void) /* {{{ */ zend_class_entry *ce; parent_name = CT_CONSTANT(opline->op2); - if (((ce = zend_lookup_class_ex(Z_STR_P(parent_name), parent_name + 1, 0)) == NULL) || - ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) && - (ce->type == ZEND_INTERNAL_CLASS))) { + ce = zend_lookup_class_ex(Z_STR_P(parent_name), parent_name + 1, 0); + if (!ce + || ((ce->type == ZEND_INTERNAL_CLASS) && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES)) + || ((ce->type == ZEND_USER_CLASS) && (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) && (ce->info.user.filename != CG(active_op_array)->filename)) + ) { if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) { CG(active_op_array)->fn_flags |= ZEND_ACC_EARLY_BINDING; opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED; @@ -3540,6 +3542,7 @@ static int zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, uint32_t if (!fbc || (fbc->type == ZEND_INTERNAL_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS)) || (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)) + || (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) && fbc->op_array.filename != CG(active_op_array)->filename) ) { zend_string_release_ex(lcname, 0); return FAILURE; @@ -4016,6 +4019,7 @@ void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ if (!fbc || (fbc->type == ZEND_INTERNAL_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS)) || (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)) + || (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) && fbc->op_array.filename != CG(active_op_array)->filename) ) { zend_string_release_ex(lcname, 0); zend_compile_dynamic_call(result, &name_node, args_ast); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a2f4d906c5..eead395b23 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -1048,6 +1048,9 @@ END_EXTERN_C() /* result of compilation may be stored in file cache */ #define ZEND_COMPILE_WITH_FILE_CACHE (1<<11) +/* ignore functions and classes declared in other files */ +#define ZEND_COMPILE_IGNORE_OTHER_FILES (1<<12) + /* The default value for CG(compiler_options) */ #define ZEND_COMPILE_DEFAULT ZEND_COMPILE_HANDLE_OP_ARRAY diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 2519adbf5d..bbdda94893 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -1660,7 +1660,7 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl { zend_persistent_script *new_persistent_script; zend_op_array *orig_active_op_array; - HashTable *orig_function_table, *orig_class_table; + HashTable *orig_class_table; zval orig_user_error_handler; zend_op_array *op_array; int do_bailout = 0; @@ -1724,12 +1724,10 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl /* Save the original values for the op_array, function table and class table */ orig_active_op_array = CG(active_op_array); - orig_function_table = CG(function_table); orig_class_table = CG(class_table); ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler)); /* Override them with ours */ - CG(function_table) = &ZCG(function_table); EG(class_table) = CG(class_table) = &new_persistent_script->script.class_table; ZVAL_UNDEF(&EG(user_error_handler)); @@ -1739,6 +1737,7 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES; CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING; CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION; + CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES; #ifdef HAVE_OPCACHE_FILE_CACHE if (ZCG(accel_directives).file_cache) { CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE; @@ -1754,14 +1753,12 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl /* Restore originals */ CG(active_op_array) = orig_active_op_array; - CG(function_table) = orig_function_table; EG(class_table) = CG(class_table) = orig_class_table; EG(user_error_handler) = orig_user_error_handler; if (!op_array) { /* compilation failed */ free_persistent_script(new_persistent_script, 1); - zend_accel_free_user_functions(&ZCG(function_table)); if (do_bailout) { zend_bailout(); } @@ -1772,12 +1769,12 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl Here we aren't sure we would store it, but we will need it further anyway. */ - zend_accel_move_user_functions(&ZCG(function_table), &new_persistent_script->script.function_table); + new_persistent_script->script.main_op_array = *op_array; + zend_accel_move_user_functions(CG(function_table), &new_persistent_script->script); new_persistent_script->script.first_early_binding_opline = (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) ? zend_build_delayed_early_binding_list(op_array) : (uint32_t)-1; - new_persistent_script->script.main_op_array = *op_array; efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */ @@ -2304,11 +2301,6 @@ static void accel_activate(void) return; } - if (!ZCG(function_table).nTableSize) { - zend_hash_init(&ZCG(function_table), zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1); - zend_accel_copy_internal_functions(); - } - /* PHP-5.4 and above return "double", but we use 1 sec precision */ ZCG(auto_globals_mask) = 0; ZCG(request_time) = (time_t)sapi_get_request_time(); @@ -2317,11 +2309,6 @@ static void accel_activate(void) ZCG(include_path_key_len) = 0; ZCG(include_path_check) = 1; - /* check if ZCG(function_table) wasn't somehow polluted on the way */ - if (ZCG(internal_functions_count) != (zend_long)zend_hash_num_elements(&ZCG(function_table))) { - zend_accel_error(ACCEL_LOG_WARNING, "Internal functions count changed - was %d, now %d", ZCG(internal_functions_count), zend_hash_num_elements(&ZCG(function_table))); - } - ZCG(cwd) = NULL; ZCG(cwd_key_len) = 0; ZCG(cwd_check) = 1; @@ -2605,14 +2592,6 @@ static void accel_globals_ctor(zend_accel_globals *accel_globals) accel_gen_system_id(); } -static void accel_globals_dtor(zend_accel_globals *accel_globals) -{ - if (accel_globals->function_table.nTableSize) { - accel_globals->function_table.pDestructor = NULL; - zend_hash_destroy(&accel_globals->function_table); - } -} - #define ZEND_BIN_ID "BIN_" ZEND_TOSTR(SIZEOF_CHAR) ZEND_TOSTR(SIZEOF_INT) ZEND_TOSTR(SIZEOF_LONG) ZEND_TOSTR(SIZEOF_SIZE_T) ZEND_TOSTR(SIZEOF_ZEND_LONG) ZEND_TOSTR(ZEND_MM_ALIGNMENT) static void accel_gen_system_id(void) @@ -2752,7 +2731,7 @@ static void accel_move_code_to_huge_pages(void) static int accel_startup(zend_extension *extension) { #ifdef ZTS - accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, (ts_allocate_dtor) accel_globals_dtor); + accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, NULL); #else accel_globals_ctor(&accel_globals); #endif @@ -2941,15 +2920,6 @@ file_cache_fallback: return SUCCESS; } -static void accel_free_ts_resources() -{ -#ifndef ZTS - accel_globals_dtor(&accel_globals); -#else - ts_free_id(accel_globals_id); -#endif -} - void accel_shutdown(void) { zend_ini_entry *ini_entry; @@ -2960,7 +2930,9 @@ void accel_shutdown(void) zend_accel_blacklist_shutdown(&accel_blacklist); if (!ZCG(enabled) || !accel_startup_ok) { - accel_free_ts_resources(); +#ifdef ZTS + ts_free_id(accel_globals_id); +#endif return; } @@ -2970,7 +2942,9 @@ void accel_shutdown(void) accel_reset_pcre_cache(); - accel_free_ts_resources(); +#ifdef ZTS + ts_free_id(accel_globals_id); +#endif if (!_file_cache_only) { zend_shared_alloc_shutdown(); diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index d6660dd2d6..26dc0a6e8f 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -215,10 +215,6 @@ typedef struct _zend_accel_directives { } zend_accel_directives; typedef struct _zend_accel_globals { - /* copy of CG(function_table) used for compilation scripts into cache */ - /* initially it contains only internal functions */ - HashTable function_table; - int internal_functions_count; int counted; /* the process uses shared memory */ zend_bool enabled; zend_bool locked; /* thread obtained exclusive lock */ diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index c803c605a7..2295b257af 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -72,27 +72,11 @@ void free_persistent_script(zend_persistent_script *persistent_script, int destr efree(persistent_script); } -void zend_accel_free_user_functions(HashTable *ht) -{ - Bucket *p; - dtor_func_t orig_dtor = ht->pDestructor; - - ht->pDestructor = NULL; - ZEND_HASH_REVERSE_FOREACH_BUCKET(ht, p) { - zend_function *function = Z_PTR(p->val); - - if (EXPECTED(function->type == ZEND_USER_FUNCTION)) { - zend_hash_del_bucket(ht, p); - } else { - break; - } - } ZEND_HASH_FOREACH_END(); - ht->pDestructor = orig_dtor; -} - -void zend_accel_move_user_functions(HashTable *src, HashTable *dst) +void zend_accel_move_user_functions(HashTable *src, zend_script *script) { Bucket *p; + HashTable *dst = &script->function_table; + zend_string *filename = script->main_op_array.filename; dtor_func_t orig_dtor = src->pDestructor; src->pDestructor = NULL; @@ -100,7 +84,8 @@ void zend_accel_move_user_functions(HashTable *src, HashTable *dst) ZEND_HASH_REVERSE_FOREACH_BUCKET(src, p) { zend_function *function = Z_PTR(p->val); - if (EXPECTED(function->type == ZEND_USER_FUNCTION)) { + if (EXPECTED(function->type == ZEND_USER_FUNCTION) + && EXPECTED(function->op_array.filename == filename)) { _zend_hash_append_ptr(dst, p->key, function); zend_hash_del_bucket(src, p); } else { @@ -110,20 +95,6 @@ void zend_accel_move_user_functions(HashTable *src, HashTable *dst) src->pDestructor = orig_dtor; } -void zend_accel_copy_internal_functions(void) -{ - zend_string *key; - zval *val; - - ZEND_HASH_FOREACH_STR_KEY_VAL(CG(function_table), key, val) { - zend_internal_function *function = Z_PTR_P(val); - if (function->type == ZEND_INTERNAL_FUNCTION) { - zend_hash_add_new_ptr(&ZCG(function_table), key, function); - } - } ZEND_HASH_FOREACH_END(); - ZCG(internal_functions_count) = zend_hash_num_elements(&ZCG(function_table)); -} - static inline void zend_clone_zval(zval *src) { void *ptr; diff --git a/ext/opcache/zend_accelerator_util_funcs.h b/ext/opcache/zend_accelerator_util_funcs.h index 5d7834abe7..014bee4fd1 100644 --- a/ext/opcache/zend_accelerator_util_funcs.h +++ b/ext/opcache/zend_accelerator_util_funcs.h @@ -25,13 +25,10 @@ #include "zend.h" #include "ZendAccelerator.h" -void zend_accel_copy_internal_functions(void); - zend_persistent_script* create_persistent_script(void); void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements); -void zend_accel_free_user_functions(HashTable *ht); -void zend_accel_move_user_functions(HashTable *str, HashTable *dst); +void zend_accel_move_user_functions(HashTable *str, zend_script *script); zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory); -- 2.49.0