From 94099586ec599117581ca01c15b1f6c5f749e23a Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 15 Oct 2018 23:34:01 +0300 Subject: [PATCH] Immutable clases and op_arrays --- UPGRADING.INTERNALS | 15 ++ Zend/zend.c | 126 ++++++++++++--- Zend/zend.h | 11 +- Zend/zend_API.c | 22 ++- Zend/zend_API.h | 9 +- Zend/zend_builtin_functions.c | 2 +- Zend/zend_closures.c | 50 ++++-- Zend/zend_compile.c | 13 +- Zend/zend_compile.h | 13 +- Zend/zend_execute.c | 77 +++++----- Zend/zend_execute_API.c | 4 +- Zend/zend_extensions.c | 6 + Zend/zend_extensions.h | 3 + Zend/zend_globals.h | 7 +- Zend/zend_inheritance.c | 59 ++++--- Zend/zend_interfaces.c | 126 +++++++++++---- Zend/zend_map_ptr.h | 89 +++++++++++ Zend/zend_object_handlers.c | 16 +- Zend/zend_object_handlers.h | 1 + Zend/zend_opcode.c | 51 ++++--- Zend/zend_vm_def.h | 46 +++--- Zend/zend_vm_execute.h | 120 +++++++-------- ext/opcache/Optimizer/compact_literals.c | 3 +- ext/opcache/ZendAccelerator.c | 7 +- ext/opcache/ZendAccelerator.h | 3 + ext/opcache/zend_accelerator_util_funcs.c | 77 +++++++--- ext/opcache/zend_file_cache.c | 44 ++++++ ext/opcache/zend_persist.c | 178 ++++++++++++++++++---- ext/opcache/zend_persist_calc.c | 62 ++++++-- ext/opcache/zend_shared_alloc.c | 43 ++++-- ext/opcache/zend_shared_alloc.h | 4 + ext/reflection/php_reflection.c | 18 ++- ext/spl/spl_array.c | 25 +-- ext/spl/spl_fixedarray.c | 24 +-- ext/spl/spl_iterators.c | 22 +-- ext/spl/spl_observer.c | 24 ++- 36 files changed, 979 insertions(+), 421 deletions(-) create mode 100644 Zend/zend_map_ptr.h diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 505b3686aa9..455c9f8f2e7 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -7,6 +7,7 @@ PHP 7.4 INTERNALS UPGRADE NOTES d. Removed zend_check_private() e. php_win32_error_to_msg() memory management f. get_properties_for() handler / Z_OBJDEBUG_P + g. Immutable classes and op_arrays 2. Build system changes a. Abstract @@ -98,6 +99,20 @@ PHP 7.4 INTERNALS UPGRADE NOTES // ... zend_release_properties(ht); + g. Opcache may make classes and op_arrays immutable. Such classes are marked + by ZEND_ACC_IMMUTABLE flag, they are not going to be copied from opcache + shard memory to process memory and must not be modified at all. + Few related data structures were changed to allow addressing mutable data + structures from immutable ones. This access is implemented through + ZEND_MAP_PTR... abstraction macros and, basically, uses additional level of + indirection. op_array->run_time_cache, op_array->static_variables_ptr, + class_entry->static_members_table and class_entry->iterator_funcs_ptr now + have to be access through ZEND_MAP_PTR... macros. + It's also not allowed to change op_array->reserved[] handles of immutable + op_arrays. Instead, now you have to reserve op_array handle using + zend_get_op_array_extension_handle() during MINIT and access its value + using ZEND_OP_ARRAY_EXTENSION(op_array, handle). + ======================== 2. Build system changes ======================== diff --git a/Zend/zend.c b/Zend/zend.c index 6836e5af0c9..5962a276b05 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -33,6 +33,8 @@ #include "zend_smart_string.h" #include "zend_cpuinfo.h" +static size_t global_map_ptr_last = 0; + #ifdef ZTS ZEND_API int compiler_globals_id; ZEND_API int executor_globals_id; @@ -41,7 +43,6 @@ static HashTable *global_class_table = NULL; static HashTable *global_constants_table = NULL; static HashTable *global_auto_globals_table = NULL; static HashTable *global_persistent_list = NULL; -static zend_uintptr_t global_last_static_member = 0; ZEND_TSRMLS_CACHE_DEFINE() # define GLOBAL_FUNCTION_TABLE global_function_table # define GLOBAL_CLASS_TABLE global_class_table @@ -626,13 +627,22 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{ zend_hash_init_ex(compiler_globals->auto_globals, 8, NULL, auto_global_dtor, 1, 0); zend_hash_copy(compiler_globals->auto_globals, global_auto_globals_table, auto_global_copy_ctor); - compiler_globals->last_static_member = global_last_static_member; - if (compiler_globals->last_static_member) { - compiler_globals->static_members_table = calloc(compiler_globals->last_static_member + 1, sizeof(zval*)); - } else { - compiler_globals->static_members_table = NULL; - } compiler_globals->script_encoding_list = NULL; + +#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET + /* Map region is going to be created and resized at run-time. */ + compiler_globals->map_ptr_base = NULL; + compiler_globals->map_ptr_size = 0; + compiler_globals->map_ptr_last = global_map_ptr_last; + if (compiler_globals->map_ptr_last) { + /* Allocate map_ptr table */ + compiler_globals->map_ptr_size = ZEND_MM_ALIGNED_SIZE_EX(compiler_globals->map_ptr_last, 4096); + compiler_globals->map_ptr_base = pemalloc(compiler_globals->map_ptr_size * sizeof(void*), 1); + memset(compiler_globals->map_ptr_base, 0, compiler_globals->map_ptr_last * sizeof(void*)); + } +#else +# error "Unknown ZEND_MAP_PTR_KIND" +#endif } /* }}} */ @@ -650,13 +660,14 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{ zend_hash_destroy(compiler_globals->auto_globals); free(compiler_globals->auto_globals); } - if (compiler_globals->static_members_table) { - free(compiler_globals->static_members_table); - } if (compiler_globals->script_encoding_list) { pefree((char*)compiler_globals->script_encoding_list, 1); } - compiler_globals->last_static_member = 0; + if (compiler_globals->map_ptr_base) { + free(compiler_globals->map_ptr_base); + compiler_globals->map_ptr_base = NULL; + compiler_globals->map_ptr_size = 0; + } } /* }}} */ @@ -879,6 +890,22 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions) / #ifdef ZEND_WIN32 zend_get_windows_version_info(&EG(windows_version_info)); #endif +# if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR + /* Create a map region, used for indirect pointers from shared to + * process memory. It's allocatred once and never resized. + * All processes must map it into the same address space. + */ + CG(map_ptr_size) = 1024 * 1024; // TODO: initial size ??? + CG(map_ptr_last) = 0; + CG(map_ptr_base) = pemalloc(CG(map_ptr_size) * sizeof(void*), 1); +# elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET + /* Map region is going to be created and resized at run-time. */ + CG(map_ptr_base) = NULL; + CG(map_ptr_size) = 0; + CG(map_ptr_last) = 0; +# else +# error "Unknown ZEND_MAP_PTR_KIND" +# endif #endif EG(error_reporting) = E_ALL & ~E_NOTICE; @@ -931,7 +958,7 @@ int zend_post_startup(void) /* {{{ */ *GLOBAL_FUNCTION_TABLE = *compiler_globals->function_table; *GLOBAL_CLASS_TABLE = *compiler_globals->class_table; *GLOBAL_CONSTANTS_TABLE = *executor_globals->zend_constants; - global_last_static_member = compiler_globals->last_static_member; + global_map_ptr_last = compiler_globals->map_ptr_last; short_tags_default = CG(short_tags); compiler_options_default = CG(compiler_options); @@ -950,6 +977,8 @@ int zend_post_startup(void) /* {{{ */ executor_globals_ctor(executor_globals); global_persistent_list = &EG(persistent_list); zend_copy_ini_directives(); +#else + global_map_ptr_last = CG(map_ptr_last); #endif if (zend_post_startup_cb) { @@ -996,6 +1025,12 @@ void zend_shutdown(void) /* {{{ */ GLOBAL_CLASS_TABLE = NULL; GLOBAL_AUTO_GLOBALS_TABLE = NULL; GLOBAL_CONSTANTS_TABLE = NULL; +#else + if (CG(map_ptr_base)) { + free(CG(map_ptr_base)); + CG(map_ptr_base) = NULL; + CG(map_ptr_size) = 0; + } #endif zend_destroy_rsrc_list_dtors(); } @@ -1077,17 +1112,12 @@ ZEND_API void zend_activate(void) /* {{{ */ init_compiler(); init_executor(); startup_scanner(); + if (CG(map_ptr_last)) { + memset(CG(map_ptr_base), 0, CG(map_ptr_last) * sizeof(void*)); + } } /* }}} */ -#ifdef ZTS -void zend_reset_internal_classes(void) /* {{{ */ -{ - CG(last_static_member) = global_last_static_member; -} -/* }}} */ -#endif - void zend_call_destructors(void) /* {{{ */ { zend_try { @@ -1619,6 +1649,62 @@ void free_estring(char **str_p) /* {{{ */ } /* }}} */ +ZEND_API void zend_map_ptr_reset(void) +{ + CG(map_ptr_last) = global_map_ptr_last; +} + +ZEND_API void *zend_map_ptr_new(void) +{ + void **ptr; + + if (CG(map_ptr_last) >= CG(map_ptr_size)) { +#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR + // TODO: error ??? + ZEND_ASSERT(0); +#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET + /* Grow map_ptr table */ + CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(CG(map_ptr_last) + 1, 4096); + CG(map_ptr_base) = perealloc(CG(map_ptr_base), CG(map_ptr_size) * sizeof(void*), 1); +#else +# error "Unknown ZEND_MAP_PTR_KIND" +#endif + } + ptr = (void**)CG(map_ptr_base) + CG(map_ptr_last); + *ptr = NULL; + CG(map_ptr_last)++; +#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR + return ptr; +#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET + return (void*)((CG(map_ptr_last) * sizeof(void*)) - (sizeof(void*) - 1)); +#else +# error "Unknown ZEND_MAP_PTR_KIND" +#endif +} + +ZEND_API void zend_map_ptr_extend(size_t last) +{ + if (last > CG(map_ptr_last)) { + void **ptr; + + if (last >= CG(map_ptr_size)) { +#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR + /* This may never happen */ + ZEND_ASSERT(0); +#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET + /* Grow map_ptr table */ + CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(last, 4096); + CG(map_ptr_base) = perealloc(CG(map_ptr_base), CG(map_ptr_size) * sizeof(void*), 1); +#else +# error "Unknown ZEND_MAP_PTR_KIND" +#endif + } + ptr = (void**)CG(map_ptr_base) + CG(map_ptr_last); + memset(ptr, 0, (last - CG(map_ptr_last)) * sizeof(void*)); + CG(map_ptr_last) = last; + } +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend.h b/Zend/zend.h index d6d427ccdbe..4e0bb07b000 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -25,6 +25,7 @@ #define ZEND_ENGINE_3 #include "zend_types.h" +#include "zend_map_ptr.h" #include "zend_errors.h" #include "zend_alloc.h" #include "zend_llist.h" @@ -127,10 +128,7 @@ struct _zend_class_entry { int default_static_members_count; zval *default_properties_table; zval *default_static_members_table; - union { - zval *static_members_table; - zend_uintptr_t static_members_table_idx; - }; + ZEND_MAP_PTR_DEF(zval *, static_members_table); HashTable function_table; HashTable properties_info; HashTable constants_table; @@ -150,7 +148,7 @@ struct _zend_class_entry { zend_function *unserialize_func; /* allocated only if class implements Iterator or IteratorAggregate interface */ - zend_class_iterator_funcs *iterator_funcs_ptr; + ZEND_MAP_PTR_DEF(zend_class_iterator_funcs *, iterator_funcs_ptr); /* handlers */ union { @@ -271,9 +269,8 @@ ZEND_API void zend_activate_modules(void); ZEND_API void zend_deactivate_modules(void); ZEND_API void zend_post_deactivate_modules(void); -void zend_reset_internal_classes(void); - ZEND_API void free_estring(char **str_p); + END_EXTERN_C() /* output support */ diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 81a4ee76986..144983ddbbf 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2795,7 +2795,9 @@ ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zen ce = zend_hash_add_ptr(CG(class_table), lcname, ce); zend_string_release_ex(lcname, 0); if (ce) { - ce->refcount++; + if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) { + ce->refcount++; + } return SUCCESS; } return FAILURE; @@ -3696,18 +3698,14 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS); } ZVAL_COPY_VALUE(&ce->default_static_members_table[property_info->offset], property); - if (ce->type == ZEND_USER_CLASS) { - ce->static_members_table = ce->default_static_members_table; -#ifdef ZTS - } else if (!ce->static_members_table_idx) { - CG(last_static_member)++; - ce->static_members_table_idx = CG(last_static_member); - if (CG(static_members_table)) { - /* Support for run-time declaration: dl() */ - CG(static_members_table) = realloc(CG(static_members_table), (CG(last_static_member) + 1) * sizeof(zval*)); - CG(static_members_table)[ce->static_members_table_idx] = NULL; + if (!ZEND_MAP_PTR(ce->static_members_table)) { + ZEND_ASSERT(ce->type == ZEND_INTERNAL_CLASS); + if (!EG(current_execute_data)) { + ZEND_MAP_PTR_NEW(ce->static_members_table); + } else { + /* internal class loaded by dl() */ + ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); } -#endif } } else { if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL && diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 54344fe0aae..8ba9d737580 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -219,7 +219,7 @@ typedef struct _zend_fcall_info_cache { class_container.trait_precedences = NULL; \ class_container.interfaces = NULL; \ class_container.get_iterator = NULL; \ - class_container.iterator_funcs_ptr = NULL; \ + ZEND_MAP_PTR_INIT(class_container.iterator_funcs_ptr, NULL); \ class_container.info.internal.module = NULL; \ class_container.info.internal.builtin_functions = functions; \ } @@ -228,11 +228,8 @@ typedef struct _zend_fcall_info_cache { #define INIT_NS_CLASS_ENTRY(class_container, ns, class_name, functions) \ INIT_CLASS_ENTRY(class_container, ZEND_NS_NAME(ns, class_name), functions) -#ifdef ZTS -# define CE_STATIC_MEMBERS(ce) (((ce)->type==ZEND_USER_CLASS)?(ce)->static_members_table:CG(static_members_table)[(ce)->static_members_table_idx]) -#else -# define CE_STATIC_MEMBERS(ce) ((ce)->static_members_table) -#endif +#define CE_STATIC_MEMBERS(ce) \ + ((zval*)ZEND_MAP_PTR_GET((ce)->static_members_table)) #define ZEND_FCI_INITIALIZED(fci) ((fci).size != 0) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 364d478ab73..5c79691ff2a 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1770,7 +1770,7 @@ static int copy_class_or_interface_name(zval *el, int num_args, va_list args, ze if ((hash_key->key && ZSTR_VAL(hash_key->key)[0] != 0) && (comply_mask == (ce->ce_flags & mask))) { - if (ce->refcount > 1 && + if ((ce->refcount > 1 || (ce->ce_flags & ZEND_ACC_IMMUTABLE)) && !same_name(hash_key->key, ce->name)) { add_next_index_str(array, zend_string_copy(hash_key->key)); } else { diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 7ad9327a324..a5e2123db1e 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -151,9 +151,14 @@ ZEND_METHOD(Closure, call) if (ZEND_USER_CODE(my_function.type) && (closure->func.common.scope != Z_OBJCE_P(newthis) || (closure->func.common.fn_flags & ZEND_ACC_HEAP_RT_CACHE))) { - my_function.op_array.run_time_cache = emalloc(my_function.op_array.cache_size); + void *ptr; + my_function.op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE; - memset(my_function.op_array.run_time_cache, 0, my_function.op_array.cache_size); + ptr = emalloc(sizeof(void*) + my_function.op_array.cache_size); + ZEND_MAP_PTR_INIT(my_function.op_array.run_time_cache, ptr); + ptr = (char*)ptr + sizeof(void*); + ZEND_MAP_PTR_SET(my_function.op_array.run_time_cache, ptr); + memset(ptr, 0, my_function.op_array.cache_size); } } @@ -176,7 +181,7 @@ ZEND_METHOD(Closure, call) /* copied upon generator creation */ GC_DELREF(&closure->std); } else if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_HEAP_RT_CACHE) { - efree(my_function.op_array.run_time_cache); + efree(ZEND_MAP_PTR(my_function.op_array.run_time_cache)); } } /* }}} */ @@ -501,7 +506,8 @@ static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp) /* {{{ debug_info = zend_new_array(8); if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) { - HashTable *static_variables = closure->func.op_array.static_variables; + HashTable *static_variables = + ZEND_MAP_PTR_GET(closure->func.op_array.static_variables_ptr); ZVAL_ARR(&val, zend_array_dup(static_variables)); zend_hash_update(debug_info, ZSTR_KNOWN(ZEND_STR_STATIC), &val); } @@ -559,7 +565,7 @@ static HashTable *zend_closure_get_gc(zval *obj, zval **table, int *n) /* {{{ */ *table = Z_TYPE(closure->this_ptr) != IS_NULL ? &closure->this_ptr : NULL; *n = Z_TYPE(closure->this_ptr) != IS_NULL ? 1 : 0; return (closure->func.type == ZEND_USER_FUNCTION) ? - closure->func.op_array.static_variables : NULL; + ZEND_MAP_PTR_GET(closure->func.op_array.static_variables_ptr) : NULL; } /* }}} */ @@ -654,28 +660,44 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent if (func->type == ZEND_USER_FUNCTION) { memcpy(&closure->func, func, sizeof(zend_op_array)); closure->func.common.fn_flags |= ZEND_ACC_CLOSURE; + closure->func.common.fn_flags &= ~ZEND_ACC_IMMUTABLE; + if (closure->func.op_array.static_variables) { closure->func.op_array.static_variables = zend_array_dup(closure->func.op_array.static_variables); } + ZEND_MAP_PTR_INIT(closure->func.op_array.static_variables_ptr, + &closure->func.op_array.static_variables); /* Runtime cache is scope-dependent, so we cannot reuse it if the scope changed */ - if (!closure->func.op_array.run_time_cache + if (!ZEND_MAP_PTR_GET(closure->func.op_array.run_time_cache) || func->common.scope != scope || (func->common.fn_flags & ZEND_ACC_HEAP_RT_CACHE) ) { - if (!func->op_array.run_time_cache && (func->common.fn_flags & ZEND_ACC_CLOSURE)) { + void *ptr; + + if (!ZEND_MAP_PTR_GET(func->op_array.run_time_cache) + && (func->common.fn_flags & ZEND_ACC_CLOSURE) + && (func->common.scope == scope || + !(func->common.fn_flags & ZEND_ACC_IMMUTABLE))) { /* If a real closure is used for the first time, we create a shared runtime cache * and remember which scope it is for. */ - func->common.scope = scope; - func->op_array.run_time_cache = zend_arena_alloc(&CG(arena), func->op_array.cache_size); - closure->func.op_array.run_time_cache = func->op_array.run_time_cache; + if (func->common.scope != scope) { + func->common.scope = scope; + } + closure->func.op_array.fn_flags &= ~ZEND_ACC_HEAP_RT_CACHE; + ptr = zend_arena_alloc(&CG(arena), func->op_array.cache_size); + ZEND_MAP_PTR_SET(func->op_array.run_time_cache, ptr); + ZEND_MAP_PTR_SET(closure->func.op_array.run_time_cache, ptr); } else { /* Otherwise, we use a non-shared runtime cache */ - closure->func.op_array.run_time_cache = emalloc(func->op_array.cache_size); closure->func.op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE; + ptr = emalloc(sizeof(void*) + func->op_array.cache_size); + ZEND_MAP_PTR_INIT(closure->func.op_array.run_time_cache, ptr); + ptr = (char*)ptr + sizeof(void*); + ZEND_MAP_PTR_SET(closure->func.op_array.run_time_cache, ptr); } - memset(closure->func.op_array.run_time_cache, 0, func->op_array.cache_size); + memset(ptr, 0, func->op_array.cache_size); } if (closure->func.op_array.refcount) { (*closure->func.op_array.refcount)++; @@ -728,7 +750,7 @@ ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_clas void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var) /* {{{ */ { zend_closure *closure = (zend_closure *) Z_OBJ_P(closure_zv); - HashTable *static_variables = closure->func.op_array.static_variables; + HashTable *static_variables = ZEND_MAP_PTR_GET(closure->func.op_array.static_variables_ptr); zend_hash_update(static_variables, var_name, var); } /* }}} */ @@ -736,7 +758,7 @@ void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var) / void zend_closure_bind_var_ex(zval *closure_zv, uint32_t offset, zval *val) /* {{{ */ { zend_closure *closure = (zend_closure *) Z_OBJ_P(closure_zv); - HashTable *static_variables = closure->func.op_array.static_variables; + HashTable *static_variables = ZEND_MAP_PTR_GET(closure->func.op_array.static_variables_ptr); zval *var = (zval*)((char*)static_variables->arData + offset); zval_ptr_dtor(var); ZVAL_COPY_VALUE(var, val); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index daaf00c9b13..6861af32a67 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1021,7 +1021,9 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */ GC_ADDREF(op_array->static_variables); } } - op_array->run_time_cache = NULL; + ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables); + ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*))); + ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL); } else if (function->type == ZEND_INTERNAL_FUNCTION) { if (function->common.function_name) { zend_string_addref(function->common.function_name); @@ -1614,9 +1616,9 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify zend_hash_init_ex(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0); if (ce->type == ZEND_INTERNAL_CLASS) { - ce->static_members_table = NULL; + ZEND_MAP_PTR_INIT(ce->static_members_table, NULL); } else { - ce->static_members_table = ce->default_static_members_table; + ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); ce->info.user.doc_comment = NULL; } @@ -1636,7 +1638,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify ce->__tostring = NULL; ce->create_object = NULL; ce->get_iterator = NULL; - ce->iterator_funcs_ptr = NULL; + ZEND_MAP_PTR_INIT(ce->iterator_funcs_ptr, NULL); ce->get_static_method = NULL; ce->parent = NULL; ce->parent_name = NULL; @@ -5867,6 +5869,9 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /* init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE); + ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*))); + ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL); + op_array->fn_flags |= (orig_op_array->fn_flags & ZEND_ACC_STRICT_TYPES); op_array->fn_flags |= decl->flags; op_array->line_start = decl->start_lineno; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 0f44be816c1..034199f2e25 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -389,7 +389,8 @@ struct _zend_op_array { uint32_t last; /* number of opcodes */ zend_op *opcodes; - void **run_time_cache; + ZEND_MAP_PTR_DEF(void **, run_time_cache); + ZEND_MAP_PTR_DEF(HashTable *, static_variables_ptr); HashTable *static_variables; zend_string **vars; /* names of CV variables */ @@ -660,19 +661,25 @@ struct _zend_execute_data { (node).constant = RT_CONSTANT(opline, node) - (op_array)->literals; \ } while (0) +#define RUN_TIME_CACHE(op_array) \ + ZEND_MAP_PTR_GET((op_array)->run_time_cache) + +#define ZEND_OP_ARRAY_EXTENSION(op_array, handle) \ + RUN_TIME_CACHE(op_array)[handle] + #if ZEND_EX_USE_RUN_TIME_CACHE # define EX_RUN_TIME_CACHE() \ EX(run_time_cache) # define EX_LOAD_RUN_TIME_CACHE(op_array) do { \ - EX(run_time_cache) = (op_array)->run_time_cache; \ + EX(run_time_cache) = RUN_TIME_CACHE(op_array); \ } while (0) #else # define EX_RUN_TIME_CACHE() \ - EX(func)->op_array.run_time_cache + RUN_TIME_CACHE(&EX(func)->op_array) # define EX_LOAD_RUN_TIME_CACHE(op_array) do { \ } while (0) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index cbaa53f4e10..baf54b09bfd 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2504,39 +2504,20 @@ static zend_always_inline void i_init_func_execute_data(zend_op_array *op_array, } /* }}} */ -static zend_never_inline void ZEND_FASTCALL init_func_run_time_cache(zend_op_array *op_array) /* {{{ */ -{ - ZEND_ASSERT(op_array->run_time_cache == NULL); - op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size); - memset(op_array->run_time_cache, 0, op_array->cache_size); -} -/* }}} */ - -static zend_always_inline zend_function* ZEND_FASTCALL init_func_run_time_cache_i(zval *zv) /* {{{ */ +static zend_always_inline void init_func_run_time_cache_i(zend_op_array *op_array) /* {{{ */ { - zend_op_array *op_array = Z_PTR_P(zv); - - ZEND_ASSERT(op_array->run_time_cache == NULL); - if (op_array->fn_flags & ZEND_ACC_IMMUTABLE) { - zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array) + op_array->cache_size); + void **run_time_cache; - Z_PTR_P(zv) = new_op_array; - memcpy(new_op_array, op_array, sizeof(zend_op_array)); - new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE; - new_op_array->run_time_cache = (void**)(new_op_array + 1); - memset(new_op_array->run_time_cache, 0, new_op_array->cache_size); - return (zend_function*)new_op_array; - } else { - op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size); - memset(op_array->run_time_cache, 0, op_array->cache_size); - return (zend_function*)op_array; - } + ZEND_ASSERT(RUN_TIME_CACHE(op_array) == NULL); + run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size); + memset(run_time_cache, 0, op_array->cache_size); + ZEND_MAP_PTR_SET(op_array->run_time_cache, run_time_cache); } /* }}} */ -static zend_never_inline zend_function* init_func_run_time_cache_ex(zval *zv) /* {{{ */ +static zend_never_inline void ZEND_FASTCALL init_func_run_time_cache(zend_op_array *op_array) /* {{{ */ { - return init_func_run_time_cache_i(zv); + init_func_run_time_cache_i(op_array); } /* }}} */ @@ -2547,8 +2528,8 @@ ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name) /* if (EXPECTED(zv != NULL)) { zend_function *fbc = Z_FUNC_P(zv); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = (zend_function*)init_func_run_time_cache_i(zv); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache_i(&fbc->op_array); } return fbc; } @@ -2562,8 +2543,8 @@ ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, if (EXPECTED(zv != NULL)) { zend_function *fbc = Z_FUNC_P(zv); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = (zend_function*)init_func_run_time_cache_i(zv); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache_i(&fbc->op_array); } return fbc; } @@ -2580,10 +2561,15 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu zend_attach_symbol_table(execute_data); - if (!op_array->run_time_cache) { + if (!ZEND_MAP_PTR(op_array->run_time_cache)) { + void *ptr; + ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE); - op_array->run_time_cache = emalloc(op_array->cache_size); - memset(op_array->run_time_cache, 0, op_array->cache_size); + ptr = emalloc(op_array->cache_size + sizeof(void*)); + ZEND_MAP_PTR_INIT(op_array->run_time_cache, ptr); + ptr = (char*)ptr + sizeof(void*); + ZEND_MAP_PTR_SET(op_array->run_time_cache, ptr); + memset(ptr, 0, op_array->cache_size); } EX_LOAD_RUN_TIME_CACHE(op_array); @@ -2602,7 +2588,7 @@ ZEND_API void zend_init_func_execute_data(zend_execute_data *ex, zend_op_array * #endif EX(prev_execute_data) = EG(current_execute_data); - if (!op_array->run_time_cache) { + if (!RUN_TIME_CACHE(op_array)) { init_func_run_time_cache(op_array); } i_init_func_execute_data(op_array, return_value, 1 EXECUTE_DATA_CC); @@ -2618,10 +2604,15 @@ ZEND_API void zend_init_func_execute_data(zend_execute_data *ex, zend_op_array * ZEND_API void zend_init_code_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */ { EX(prev_execute_data) = EG(current_execute_data); - if (!op_array->run_time_cache) { + if (!ZEND_MAP_PTR(op_array->run_time_cache)) { + void *ptr; + ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE); - op_array->run_time_cache = emalloc(op_array->cache_size); - memset(op_array->run_time_cache, 0, op_array->cache_size); + ptr = emalloc(op_array->cache_size + sizeof(void*)); + ZEND_MAP_PTR_INIT(op_array->run_time_cache, ptr); + ptr = (char*)ptr + sizeof(void*); + ZEND_MAP_PTR_SET(op_array->run_time_cache, ptr); + memset(ptr, 0, op_array->cache_size); } i_init_code_execute_data(execute_data, op_array, return_value); } @@ -2964,7 +2955,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s return NULL; } } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } else { @@ -2982,8 +2973,8 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s zend_string_release_ex(lcname, 0); fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = init_func_run_time_cache_ex(func); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache(&fbc->op_array); } called_scope = NULL; } @@ -3019,7 +3010,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zval * return NULL; } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } @@ -3106,7 +3097,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar return NULL; } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 2ade3e38186..d321485ad3a 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -318,9 +318,6 @@ void shutdown_executor(void) /* {{{ */ zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full); zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full); zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full); -#ifdef ZTS - zend_reset_internal_classes(); -#endif } else { ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) { zend_constant *c = Z_PTR_P(zv); @@ -334,6 +331,7 @@ void shutdown_executor(void) /* {{{ */ efree(c); zend_string_release_ex(key, 0); } ZEND_HASH_FOREACH_END_DEL(); + ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(function_table), key, zv) { zend_function *func = Z_PTR_P(zv); if (_idx == EG(persistent_functions_count)) { diff --git a/Zend/zend_extensions.c b/Zend/zend_extensions.c index a2db4f590f0..076dcee5b58 100644 --- a/Zend/zend_extensions.c +++ b/Zend/zend_extensions.c @@ -21,6 +21,7 @@ ZEND_API zend_llist zend_extensions; ZEND_API uint32_t zend_extension_flags = 0; +ZEND_API int zend_op_array_extension_handles = 0; static int last_resource_number; int zend_load_extension(const char *path) @@ -198,6 +199,7 @@ int zend_startup_extensions_mechanism() { /* Startup extensions mechanism */ zend_llist_init(&zend_extensions, sizeof(zend_extension), (void (*)(void *)) zend_extension_dtor, 1); + zend_op_array_extension_handles = 0; last_resource_number = 0; return SUCCESS; } @@ -257,6 +259,10 @@ ZEND_API int zend_get_resource_handle(zend_extension *extension) } } +ZEND_API int zend_get_op_array_extension_handle(void) +{ + return zend_op_array_extension_handles++; +} ZEND_API zend_extension *zend_get_extension(const char *extension_name) { diff --git a/Zend/zend_extensions.h b/Zend/zend_extensions.h index 866f8521417..8258aee276d 100644 --- a/Zend/zend_extensions.h +++ b/Zend/zend_extensions.h @@ -111,7 +111,10 @@ struct _zend_extension { }; BEGIN_EXTERN_C() +extern ZEND_API int zend_op_array_extension_handles; + ZEND_API int zend_get_resource_handle(zend_extension *extension); +ZEND_API int zend_get_op_array_extension_handle(void); ZEND_API void zend_extension_dispatch_message(int message, void *arg); END_EXTERN_C() diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 9412801c1b0..f3d775af2e6 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -117,10 +117,9 @@ struct _zend_compiler_globals { zend_stack delayed_oplines_stack; -#ifdef ZTS - zval **static_members_table; - zend_uintptr_t last_static_member; -#endif + void *map_ptr_base; + size_t map_ptr_size; + size_t map_ptr_last; }; diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 9a4efed9b9e..a3eed785656 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -64,11 +64,16 @@ static zend_function *zend_duplicate_function(zend_function *func, zend_class_en /* reuse the same op_array structure */ return func; } - if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) { - GC_ADDREF(func->op_array.static_variables); - } new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); memcpy(new_function, func, sizeof(zend_op_array)); + if (ZEND_MAP_PTR_GET(func->op_array.static_variables_ptr)) { + /* See: Zend/tests/method_static_var.phpt */ + new_function->op_array.static_variables = ZEND_MAP_PTR_GET(func->op_array.static_variables_ptr); + } + if (!(GC_FLAGS(new_function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) { + GC_ADDREF(new_function->op_array.static_variables); + } + ZEND_MAP_PTR_INIT(new_function->op_array.static_variables_ptr, &new_function->op_array.static_variables); } return new_function; } @@ -87,23 +92,9 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */ if (EXPECTED(!ce->get_iterator)) { ce->get_iterator = parent->get_iterator; } - if (EXPECTED(!ce->iterator_funcs_ptr) && UNEXPECTED(parent->iterator_funcs_ptr)) { - if (ce->type == ZEND_INTERNAL_CLASS) { - ce->iterator_funcs_ptr = calloc(1, sizeof(zend_class_iterator_funcs)); - if (parent->iterator_funcs_ptr->zf_new_iterator) { - ce->iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&ce->function_table, "getiterator", sizeof("getiterator") - 1); - } - if (parent->iterator_funcs_ptr->zf_current) { - ce->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&ce->function_table, "rewind", sizeof("rewind") - 1); - ce->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&ce->function_table, "valid", sizeof("valid") - 1); - ce->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&ce->function_table, "key", sizeof("key") - 1); - ce->iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&ce->function_table, "current", sizeof("current") - 1); - ce->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&ce->function_table, "next", sizeof("next") - 1); - } - } else { - ce->iterator_funcs_ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs)); - memset(ce->iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); - } + if (ZEND_MAP_PTR(parent->iterator_funcs_ptr)) { + /* Must be initialized through iface->interface_gets_implemented() */ + ZEND_ASSERT(ZEND_MAP_PTR(ce->iterator_funcs_ptr) && ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr)); } if (EXPECTED(!ce->__get)) { ce->__get = parent->__get; @@ -910,7 +901,11 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent } } while (dst != end); } else if (ce->type == ZEND_USER_CLASS) { - src = parent_ce->default_static_members_table + parent_ce->default_static_members_count; + if (UNEXPECTED(CE_STATIC_MEMBERS(parent_ce) == NULL)) { + ZEND_ASSERT(parent_ce->type == ZEND_INTERNAL_CLASS || (parent_ce->ce_flags & ZEND_ACC_IMMUTABLE)); + zend_class_init_statics(parent_ce); + } + src = CE_STATIC_MEMBERS(parent_ce) + parent_ce->default_static_members_count; do { dst--; src--; @@ -936,18 +931,14 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent } while (dst != end); } ce->default_static_members_count += parent_ce->default_static_members_count; - if (ce->type == ZEND_USER_CLASS) { - ce->static_members_table = ce->default_static_members_table; -#ifdef ZTS - } else if (!ce->static_members_table_idx) { - CG(last_static_member)++; - ce->static_members_table_idx = CG(last_static_member); - if (CG(static_members_table)) { - /* Support for run-time declaration: dl() */ - CG(static_members_table) = realloc(CG(static_members_table), (CG(last_static_member) + 1) * sizeof(zval*)); - CG(static_members_table)[ce->static_members_table_idx] = NULL; + if (!ZEND_MAP_PTR(ce->static_members_table)) { + ZEND_ASSERT(ce->type == ZEND_INTERNAL_CLASS); + if (!EG(current_execute_data)) { + ZEND_MAP_PTR_NEW(ce->static_members_table); + } else { + /* internal class loaded by dl() */ + ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); } -#endif } } @@ -1315,6 +1306,10 @@ static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_s } else { new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); memcpy(new_fn, fn, sizeof(zend_op_array)); + new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE; + ZEND_MAP_PTR_INIT(new_fn->op_array.run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*))); + ZEND_MAP_PTR_SET(new_fn->op_array.run_time_cache, NULL); + ZEND_MAP_PTR_INIT(new_fn->op_array.static_variables_ptr, &new_fn->op_array.static_variables); } fn = zend_hash_update_ptr(&ce->function_table, key, new_fn); zend_add_magic_methods(ce, key, fn); diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index 2e7f70c7952..906f5840edc 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -119,12 +119,36 @@ ZEND_API zval* zend_call_method(zval *object, zend_class_entry *obj_ce, zend_fun } /* }}} */ +typedef struct _zend_class_iterator_funcs_ptr { + zend_class_iterator_funcs *ptr; + zend_class_iterator_funcs data; +} zend_class_iterator_funcs_ptr; + /* iterator interface, c-level functions used by engine */ +static zend_never_inline zend_class_iterator_funcs* zend_alloc_iterator_funcs_ptr(zend_class_entry *ce) /* {{{ */ +{ + zend_class_iterator_funcs *ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs)); + memset(ptr, 0, sizeof(zend_class_iterator_funcs)); + ZEND_MAP_PTR_SET(ce->iterator_funcs_ptr, ptr); + return ptr; +} +/* }}} */ + +static zend_always_inline zend_class_iterator_funcs* zend_get_iterator_funcs_ptr(zend_class_entry *ce) /* {{{ */ +{ + if (ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr)) { + return ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr); + } else { + return zend_alloc_iterator_funcs_ptr(ce); + } +} +/* }}} */ /* {{{ zend_user_it_new_iterator */ ZEND_API void zend_user_it_new_iterator(zend_class_entry *ce, zval *object, zval *retval) { - zend_call_method_with_0_params(object, ce, &ce->iterator_funcs_ptr->zf_new_iterator, "getiterator", retval); + zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce); + zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_new_iterator, "getiterator", retval); } /* }}} */ @@ -159,8 +183,10 @@ ZEND_API int zend_user_it_valid(zend_object_iterator *_iter) zval *object = &iter->it.data; zval more; int result; + zend_class_entry *ce = iter->ce; + zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce); - zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs_ptr->zf_valid, "valid", &more); + zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_valid, "valid", &more); result = i_zend_is_true(&more); zval_ptr_dtor(&more); return result ? SUCCESS : FAILURE; @@ -176,7 +202,10 @@ ZEND_API zval *zend_user_it_get_current_data(zend_object_iterator *_iter) zval *object = &iter->it.data; if (Z_ISUNDEF(iter->value)) { - zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs_ptr->zf_current, "current", &iter->value); + zend_class_entry *ce = iter->ce; + zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce); + + zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_current, "current", &iter->value); } return &iter->value; } @@ -188,8 +217,10 @@ ZEND_API void zend_user_it_get_current_key(zend_object_iterator *_iter, zval *ke zend_user_iterator *iter = (zend_user_iterator*)_iter; zval *object = &iter->it.data; zval retval; + zend_class_entry *ce = iter->ce; + zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce); - zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs_ptr->zf_key, "key", &retval); + zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_key, "key", &retval); if (Z_TYPE(retval) != IS_UNDEF) { ZVAL_ZVAL(key, &retval, 1, 1); @@ -208,9 +239,11 @@ ZEND_API void zend_user_it_move_forward(zend_object_iterator *_iter) { zend_user_iterator *iter = (zend_user_iterator*)_iter; zval *object = &iter->it.data; + zend_class_entry *ce = iter->ce; + zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce); zend_user_it_invalidate_current(_iter); - zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs_ptr->zf_next, "next", NULL); + zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_next, "next", NULL); } /* }}} */ @@ -219,9 +252,11 @@ ZEND_API void zend_user_it_rewind(zend_object_iterator *_iter) { zend_user_iterator *iter = (zend_user_iterator*)_iter; zval *object = &iter->it.data; + zend_class_entry *ce = iter->ce; + zend_class_iterator_funcs *iterator_funcs_ptr = zend_get_iterator_funcs_ptr(ce); zend_user_it_invalidate_current(_iter); - zend_call_method_with_0_params(object, iter->ce, &iter->ce->iterator_funcs_ptr->zf_rewind, "rewind", NULL); + zend_call_method_with_0_params(object, ce, &iterator_funcs_ptr->zf_rewind, "rewind", NULL); } /* }}} */ @@ -312,6 +347,7 @@ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entr { uint32_t i; int t = -1; + zend_class_iterator_funcs *iterator_funcs_ptr; if (class_type->get_iterator) { if (class_type->type == ZEND_INTERNAL_CLASS) { @@ -340,17 +376,31 @@ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entr } } class_type->get_iterator = zend_user_it_get_new_iterator; - if (class_type->iterator_funcs_ptr != NULL) { - class_type->iterator_funcs_ptr->zf_new_iterator = NULL; + if (ZEND_MAP_PTR(class_type->iterator_funcs_ptr)) { + iterator_funcs_ptr = ZEND_MAP_PTR_GET(class_type->iterator_funcs_ptr); + ZEND_ASSERT(iterator_funcs_ptr); + if (class_type->type == ZEND_USER_CLASS) { + iterator_funcs_ptr->zf_new_iterator = NULL; + return SUCCESS; + } } else if (class_type->type == ZEND_INTERNAL_CLASS) { - class_type->iterator_funcs_ptr = calloc(1, sizeof(zend_class_iterator_funcs)); + /* We can use pointer even in ZTS mode, because this structure is read-only */ + zend_class_iterator_funcs_ptr *iterator_funcs_ptr_ptr = + calloc(1, sizeof(zend_class_iterator_funcs_ptr)); + ZEND_MAP_PTR_INIT(class_type->iterator_funcs_ptr, &iterator_funcs_ptr_ptr->ptr); + iterator_funcs_ptr = &iterator_funcs_ptr_ptr->data; + iterator_funcs_ptr_ptr->ptr = iterator_funcs_ptr; } else { - class_type->iterator_funcs_ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs)); - memset(class_type->iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); - } - if (class_type->type == ZEND_INTERNAL_CLASS) { - class_type->iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&class_type->function_table, "getiterator", sizeof("getiterator") - 1); + zend_class_iterator_funcs_ptr *iterator_funcs_ptr_ptr = + zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs_ptr)); + iterator_funcs_ptr_ptr->ptr = &iterator_funcs_ptr_ptr->data; + ZEND_MAP_PTR_INIT(class_type->iterator_funcs_ptr, &iterator_funcs_ptr_ptr->ptr); + iterator_funcs_ptr = &iterator_funcs_ptr_ptr->data; + iterator_funcs_ptr_ptr->ptr = iterator_funcs_ptr; + memset(iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); + return SUCCESS; } + iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&class_type->function_table, "getiterator", sizeof("getiterator") - 1); return SUCCESS; } /* }}} */ @@ -358,6 +408,8 @@ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entr /* {{{ zend_implement_iterator */ static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry *class_type) { + zend_class_iterator_funcs *iterator_funcs_ptr; + if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_iterator) { if (class_type->type == ZEND_INTERNAL_CLASS) { /* inheritance ensures the class has the necessary userland methods */ @@ -374,25 +426,39 @@ static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry } } class_type->get_iterator = zend_user_it_get_iterator; - if (class_type->iterator_funcs_ptr != NULL) { - class_type->iterator_funcs_ptr->zf_valid = NULL; - class_type->iterator_funcs_ptr->zf_current = NULL; - class_type->iterator_funcs_ptr->zf_key = NULL; - class_type->iterator_funcs_ptr->zf_next = NULL; - class_type->iterator_funcs_ptr->zf_rewind = NULL; + if (ZEND_MAP_PTR(class_type->iterator_funcs_ptr)) { + iterator_funcs_ptr = ZEND_MAP_PTR_GET(class_type->iterator_funcs_ptr); + ZEND_ASSERT(iterator_funcs_ptr); + if (class_type->type == ZEND_USER_CLASS) { + iterator_funcs_ptr->zf_valid = NULL; + iterator_funcs_ptr->zf_current = NULL; + iterator_funcs_ptr->zf_key = NULL; + iterator_funcs_ptr->zf_next = NULL; + iterator_funcs_ptr->zf_rewind = NULL; + return SUCCESS; + } } else if (class_type->type == ZEND_INTERNAL_CLASS) { - class_type->iterator_funcs_ptr = calloc(1, sizeof(zend_class_iterator_funcs)); + /* We can use pointer even in ZTS mode, because this structure is read-only */ + zend_class_iterator_funcs_ptr *iterator_funcs_ptr_ptr = + calloc(1, sizeof(zend_class_iterator_funcs_ptr)); + ZEND_MAP_PTR_INIT(class_type->iterator_funcs_ptr, &iterator_funcs_ptr_ptr->ptr); + iterator_funcs_ptr = &iterator_funcs_ptr_ptr->data; + iterator_funcs_ptr_ptr->ptr = iterator_funcs_ptr; } else { - class_type->iterator_funcs_ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs)); - memset(class_type->iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); - } - if (class_type->type == ZEND_INTERNAL_CLASS) { - class_type->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1); - class_type->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1); - class_type->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1); - class_type->iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1); - class_type->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1); + zend_class_iterator_funcs_ptr *iterator_funcs_ptr_ptr = + zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs_ptr)); + iterator_funcs_ptr_ptr->ptr = &iterator_funcs_ptr_ptr->data; + ZEND_MAP_PTR_INIT(class_type->iterator_funcs_ptr, &iterator_funcs_ptr_ptr->ptr); + iterator_funcs_ptr = &iterator_funcs_ptr_ptr->data; + iterator_funcs_ptr_ptr->ptr = iterator_funcs_ptr; + memset(iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); + return SUCCESS; } + iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1); + iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1); + iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1); + iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1); + iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1); return SUCCESS; } /* }}} */ diff --git a/Zend/zend_map_ptr.h b/Zend/zend_map_ptr.h new file mode 100644 index 00000000000..0d5b8acd253 --- /dev/null +++ b/Zend/zend_map_ptr.h @@ -0,0 +1,89 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Dmitry Stogov | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_MAP_PTR_H +#define ZEND_MAP_PTR_H + +#include "zend_portability.h" + +#define ZEND_MAP_PTR_KIND_PTR 0 +#define ZEND_MAP_PTR_KIND_PTR_OR_OFFSET 1 + +//#if defined(ZTS) || defined(TSRM_WIN32) +# define ZEND_MAP_PTR_KIND ZEND_MAP_PTR_KIND_PTR_OR_OFFSET +//#else +//# define ZEND_MAP_PTR_KIND ZEND_MAP_PTR_KIND_PTR +//#endif + +#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR +# define ZEND_MAP_PTR(ptr) \ + ptr ## __ptr +# define ZEND_MAP_PTR_DEF(type, name) \ + type * ZEND_MAP_PTR(name) +# define ZEND_MAP_PTR_GET(ptr) \ + (*(ZEND_MAP_PTR(ptr))) +# define ZEND_MAP_PTR_SET(ptr, val) do { \ + (*(ZEND_MAP_PTR(ptr))) = (val); \ + } while (0) +# define ZEND_MAP_PTR_INIT(ptr, val) do { \ + ZEND_MAP_PTR(ptr) = (val); \ + } while (0) +# define ZEND_MAP_PTR_NEW(ptr) do { \ + ZEND_MAP_PTR(ptr) = zend_map_ptr_new(); \ + } while (0) +#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET +# define ZEND_MAP_PTR(ptr) \ + ptr ## __ptr +# define ZEND_MAP_PTR_DEF(type, name) \ + type * ZEND_MAP_PTR(name) +# define ZEND_MAP_PTR_GET(ptr) \ + ((((uintptr_t)ZEND_MAP_PTR(ptr)) & 1L) ? \ + *(void**)((char*)CG(map_ptr_base) + (uintptr_t)ZEND_MAP_PTR(ptr) - 1) : \ + (void*)(*(ZEND_MAP_PTR(ptr)))) +# define ZEND_MAP_PTR_SET(ptr, val) do { \ + if (((uintptr_t)ZEND_MAP_PTR(ptr)) & 1L) { \ + *(void**)((char*)CG(map_ptr_base) + (uintptr_t)ZEND_MAP_PTR(ptr) - 1) = (val); \ + } else { \ + *(ZEND_MAP_PTR(ptr)) = (val); \ + } \ + } while (0) +# define ZEND_MAP_PTR_INIT(ptr, val) do { \ + ZEND_MAP_PTR(ptr) = (val); \ + } while (0) +# define ZEND_MAP_PTR_NEW(ptr) do { \ + ZEND_MAP_PTR(ptr) = zend_map_ptr_new(); \ + } while (0) +#else +# error "Unknown ZEND_MAP_PTR_KIND" +#endif + +ZEND_API void zend_map_ptr_reset(void); +ZEND_API void *zend_map_ptr_new(void); +ZEND_API void zend_map_ptr_extend(size_t last); + +#endif /* ZEND_MAP_PTR_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 21e47bc164f..0cdd3242d70 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1139,6 +1139,7 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend size_t mname_len; zend_op_array *func; zend_function *fbc = is_static ? ce->__callstatic : ce->__call; + static const void *dummy = (void*)(intptr_t)2; ZEND_ASSERT(fbc); @@ -1157,7 +1158,7 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend func->fn_flags |= ZEND_ACC_STATIC; } func->opcodes = &EG(call_trampoline_op); - func->run_time_cache = (void*)(intptr_t)-1; + ZEND_MAP_PTR_INIT(func->run_time_cache, (void***)&dummy); func->scope = fbc->common.scope; /* reserve space for arguments, local and temorary variables */ func->T = (fbc->type == ZEND_USER_FUNCTION)? MAX(fbc->op_array.last_var + fbc->op_array.T, 2) : 2; @@ -1352,11 +1353,7 @@ static void zend_intenal_class_init_statics(zend_class_entry *class_type) /* {{{ zend_intenal_class_init_statics(class_type->parent); } -#if ZTS - CG(static_members_table)[class_type->static_members_table_idx] = emalloc(sizeof(zval) * class_type->default_static_members_count); -#else - class_type->static_members_table = emalloc(sizeof(zval) * class_type->default_static_members_count); -#endif + ZEND_MAP_PTR_SET(class_type->static_members_table, emalloc(sizeof(zval) * class_type->default_static_members_count)); for (i = 0; i < class_type->default_static_members_count; i++) { p = &class_type->default_static_members_table[i]; if (Z_TYPE_P(p) == IS_INDIRECT) { @@ -1370,6 +1367,11 @@ static void zend_intenal_class_init_statics(zend_class_entry *class_type) /* {{{ } } /* }}} */ +ZEND_API void zend_class_init_statics(zend_class_entry *class_type) /* {{{ */ +{ + zend_intenal_class_init_statics(class_type); +} /* }}} */ + ZEND_API zval *zend_std_get_static_property(zend_class_entry *ce, zend_string *property_name, zend_bool silent) /* {{{ */ { zend_property_info *property_info = zend_hash_find_ptr(&ce->properties_info, property_name); @@ -1409,7 +1411,7 @@ ZEND_API zval *zend_std_get_static_property(zend_class_entry *ce, zend_string *p /* check if static properties were destroyed */ if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) { - if (ce->type == ZEND_INTERNAL_CLASS) { + if (ce->type == ZEND_INTERNAL_CLASS || (ce->ce_flags & ZEND_ACC_IMMUTABLE)) { zend_intenal_class_init_statics(ce); } else { undeclared_property: diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 83a22c4d2b3..753e8460e42 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -198,6 +198,7 @@ extern const ZEND_API zend_object_handlers std_object_handlers; #define ZEND_PROPERTY_NOT_EMPTY ZEND_ISEMPTY /* Property is not empty */ #define ZEND_PROPERTY_EXISTS 0x2 /* Property exists */ +ZEND_API void zend_class_init_statics(zend_class_entry *ce); ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_string *function_name_strval, const zval *key); ZEND_API zval *zend_std_get_static_property(zend_class_entry *ce, zend_string *property_name, zend_bool silent); ZEND_API ZEND_COLD zend_bool zend_std_unset_static_property(zend_class_entry *ce, zend_string *property_name); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index f348b0b5892..18ff8872a1d 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -76,6 +76,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->last_live_range = 0; op_array->static_variables = NULL; + ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables); op_array->last_try_catch = 0; op_array->fn_flags = 0; @@ -83,8 +84,8 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->last_literal = 0; op_array->literals = NULL; - op_array->run_time_cache = NULL; - op_array->cache_size = 0; + ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL); + op_array->cache_size = zend_op_array_extension_handles * sizeof(void*); memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*)); @@ -145,11 +146,7 @@ ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce) zval *p = static_members; zval *end = p + ce->default_static_members_count; -#ifdef ZTS - CG(static_members_table)[ce->static_members_table_idx] = NULL; -#else - ce->static_members_table = NULL; -#endif + ZEND_MAP_PTR_SET(ce->static_members_table, NULL); while (p != end) { i_zval_ptr_dtor(p); p++; @@ -213,7 +210,21 @@ ZEND_API void destroy_zend_class(zval *zv) zend_class_entry *ce = Z_PTR_P(zv); zend_function *fn; - if (--ce->refcount > 0) { + if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { + zend_op_array *op_array; + + if (ce->default_static_members_count) { + zend_cleanup_internal_class_data(ce); + } + if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) { + ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) { + if (op_array->type == ZEND_USER_FUNCTION) { + destroy_op_array(op_array); + } + } ZEND_HASH_FOREACH_END(); + } + return; + } else if (--ce->refcount > 0) { return; } switch (ce->type) { @@ -305,6 +316,9 @@ ZEND_API void destroy_zend_class(zval *zv) p++; } free(ce->default_static_members_table); + if (ZEND_MAP_PTR(ce->static_members_table) != &ce->default_static_members_table) { + zend_cleanup_internal_class_data(ce); + } } zend_hash_destroy(&ce->properties_info); zend_string_release_ex(ce->name, 1); @@ -333,8 +347,8 @@ ZEND_API void destroy_zend_class(zval *zv) } ZEND_HASH_FOREACH_END(); zend_hash_destroy(&ce->constants_table); } - if (ce->iterator_funcs_ptr) { - free(ce->iterator_funcs_ptr); + if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { + free(ZEND_MAP_PTR(ce->iterator_funcs_ptr)); } if (ce->num_interfaces > 0) { free(ce->interfaces); @@ -355,17 +369,18 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) { uint32_t i; - if (op_array->static_variables && - !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) { - if (GC_DELREF(op_array->static_variables) == 0) { - zend_array_destroy(op_array->static_variables); + if (op_array->static_variables) { + HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr); + if (ht && !(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { + if (GC_DELREF(ht) == 0) { + zend_array_destroy(ht); + } } } - if (op_array->run_time_cache - && (op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE)) { - efree(op_array->run_time_cache); - op_array->run_time_cache = NULL; + if ((op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE) + && ZEND_MAP_PTR(op_array->run_time_cache)) { + efree(ZEND_MAP_PTR(op_array->run_time_cache)); } if (!op_array->refcount || --(*op_array->refcount) > 0) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 36fb9a1779b..854134f520c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3099,7 +3099,7 @@ ZEND_VM_HOT_OBJ_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -3220,7 +3220,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (OP2_TYPE != IS_CONST) { @@ -3236,7 +3236,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -3289,8 +3289,8 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT) ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper, function_name, function_name); } fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = init_func_run_time_cache_ex(func); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache(&fbc->op_array); } CACHE_PTR(opline->result.num, fbc); } @@ -3410,7 +3410,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) HANDLE_EXCEPTION(); } - if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!func->op_array.run_time_cache)) { + if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&func->op_array))) { init_func_run_time_cache(&func->op_array); } } else { @@ -3453,8 +3453,8 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT) } } fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = init_func_run_time_cache_ex(func); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache(&fbc->op_array); } CACHE_PTR(opline->result.num, fbc); } @@ -3484,8 +3484,8 @@ ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT) ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper, function_name, fname); } fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = init_func_run_time_cache_ex(func); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache(&fbc->op_array); } CACHE_PTR(opline->result.num, fbc); } @@ -4963,7 +4963,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, N ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL, NULL); } else { - if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!constructor->op_array.run_time_cache)) { + if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); } /* We are not handling overloaded classes right now */ @@ -6993,20 +6993,10 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED) zval *zfunc; zval *object; zend_class_entry *called_scope; - zend_function *fbc; zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1); ZEND_ASSERT(zfunc != NULL && Z_FUNC_P(zfunc)->type == ZEND_USER_FUNCTION); - fbc = Z_PTR_P(zfunc); - if (fbc->common.fn_flags & ZEND_ACC_IMMUTABLE) { - zend_function *new_func = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); - - memcpy(new_func, fbc, sizeof(zend_op_array)); - new_func->common.fn_flags &= ~ZEND_ACC_IMMUTABLE; - Z_PTR_P(zfunc) = fbc = new_func; - } - if (Z_TYPE(EX(This)) == IS_OBJECT) { called_scope = Z_OBJCE(EX(This)); if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) || @@ -7655,7 +7645,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) fbc = call->func; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { - if (UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } execute_data = call; @@ -7781,13 +7771,17 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF) variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); zval_ptr_dtor(variable_ptr); - ht = EX(func)->op_array.static_variables; - ZEND_ASSERT(ht != NULL); - if (GC_REFCOUNT(ht) > 1) { + ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr); + if (!ht) { + ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_IMMUTABLE); + ht = zend_array_dup(EX(func)->op_array.static_variables); + ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht); + } else if (GC_REFCOUNT(ht) > 1) { if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { GC_DELREF(ht); } - EX(func)->op_array.static_variables = ht = zend_array_dup(ht); + ht = zend_array_dup(ht); + ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht); } value = (zval*)((char*)ht->arData + (opline->extended_value & ~ZEND_BIND_REF)); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 03d767247b6..ea3b58537dc 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1908,7 +1908,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z fbc = call->func; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { - if (UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } execute_data = call; @@ -2026,8 +2026,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME ZEND_VM_TAIL_CALL(zend_undefined_function_helper_SPEC(function_name ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = init_func_run_time_cache_ex(func); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache(&fbc->op_array); } CACHE_PTR(opline->result.num, fbc); } @@ -2115,8 +2115,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_N } } fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = init_func_run_time_cache_ex(func); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache(&fbc->op_array); } CACHE_PTR(opline->result.num, fbc); } @@ -2146,8 +2146,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_SPEC_CO ZEND_VM_TAIL_CALL(zend_undefined_function_helper_SPEC(fname ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { - fbc = init_func_run_time_cache_ex(func); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { + init_func_run_time_cache(&fbc->op_array); } CACHE_PTR(opline->result.num, fbc); } @@ -5066,7 +5066,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_ EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -5186,7 +5186,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (IS_CONST != IS_CONST) { @@ -5202,7 +5202,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -5290,7 +5290,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS HANDLE_EXCEPTION(); } - if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!func->op_array.run_time_cache)) { + if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&func->op_array))) { init_func_run_time_cache(&func->op_array); } } else { @@ -7242,7 +7242,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_ EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -7362,7 +7362,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { @@ -7378,7 +7378,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -7467,7 +7467,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV HANDLE_EXCEPTION(); } - if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!func->op_array.run_time_cache)) { + if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&func->op_array))) { init_func_run_time_cache(&func->op_array); } } else { @@ -8595,7 +8595,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (IS_UNUSED != IS_CONST) { @@ -8611,7 +8611,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -8753,7 +8753,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_CONST_UNUSED_HANDLER( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL, NULL); } else { - if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!constructor->op_array.run_time_cache)) { + if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); } /* We are not handling overloaded classes right now */ @@ -9102,20 +9102,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_C zval *zfunc; zval *object; zend_class_entry *called_scope; - zend_function *fbc; zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1); ZEND_ASSERT(zfunc != NULL && Z_FUNC_P(zfunc)->type == ZEND_USER_FUNCTION); - fbc = Z_PTR_P(zfunc); - if (fbc->common.fn_flags & ZEND_ACC_IMMUTABLE) { - zend_function *new_func = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); - - memcpy(new_func, fbc, sizeof(zend_op_array)); - new_func->common.fn_flags &= ~ZEND_ACC_IMMUTABLE; - Z_PTR_P(zfunc) = fbc = new_func; - } - if (Z_TYPE(EX(This)) == IS_OBJECT) { called_scope = Z_OBJCE(EX(This)); if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) || @@ -10338,7 +10328,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_ EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -10458,7 +10448,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (IS_CV != IS_CONST) { @@ -10474,7 +10464,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -10562,7 +10552,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H HANDLE_EXCEPTION(); } - if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!func->op_array.run_time_cache)) { + if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&func->op_array))) { init_func_run_time_cache(&func->op_array); } } else { @@ -14056,7 +14046,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -15666,7 +15656,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_T EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -17543,7 +17533,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -23691,7 +23681,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (IS_CONST != IS_CONST) { @@ -23707,7 +23697,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -26005,7 +25995,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { @@ -26021,7 +26011,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -27564,7 +27554,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (IS_UNUSED != IS_CONST) { @@ -27580,7 +27570,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -27722,7 +27712,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_VAR_UNUSED_HANDLER(ZE ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL, NULL); } else { - if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!constructor->op_array.run_time_cache)) { + if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); } /* We are not handling overloaded classes right now */ @@ -30002,7 +29992,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (IS_CV != IS_CONST) { @@ -30018,7 +30008,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -31969,7 +31959,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_S EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -32089,7 +32079,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (IS_CONST != IS_CONST) { @@ -32105,7 +32095,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -33700,7 +33690,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_T EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -33820,7 +33810,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { @@ -33836,7 +33826,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -34358,7 +34348,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (IS_UNUSED != IS_CONST) { @@ -34374,7 +34364,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -34516,7 +34506,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_UNUSED_UNUSED_HANDLER ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL, NULL); } else { - if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!constructor->op_array.run_time_cache)) { + if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); } /* We are not handling overloaded classes right now */ @@ -36075,7 +36065,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -36195,7 +36185,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) { CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } if (IS_CV != IS_CONST) { @@ -36211,7 +36201,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U HANDLE_EXCEPTION(); } fbc = ce->constructor; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -41082,7 +41072,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_S EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -44796,7 +44786,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVA EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } @@ -47556,13 +47546,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN variable_ptr = EX_VAR(opline->op1.var); zval_ptr_dtor(variable_ptr); - ht = EX(func)->op_array.static_variables; - ZEND_ASSERT(ht != NULL); - if (GC_REFCOUNT(ht) > 1) { + ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr); + if (!ht) { + ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_IMMUTABLE); + ht = zend_array_dup(EX(func)->op_array.static_variables); + ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht); + } else if (GC_REFCOUNT(ht) > 1) { if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { GC_DELREF(ht); } - EX(func)->op_array.static_variables = ht = zend_array_dup(ht); + ht = zend_array_dup(ht); + ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht); } value = (zval*)((char*)ht->arData + (opline->extended_value & ~ZEND_BIND_REF)); @@ -50643,7 +50637,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HA EXPECTED(obj == orig_obj)) { CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc); } - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) { + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } } diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c index f2cd7b4442f..7e24dbea31f 100644 --- a/ext/opcache/Optimizer/compact_literals.c +++ b/ext/opcache/Optimizer/compact_literals.c @@ -28,6 +28,7 @@ #include "zend_constants.h" #include "zend_execute.h" #include "zend_vm.h" +#include "zend_extensions.h" #define DEBUG_COMPACT_LITERALS 0 @@ -505,7 +506,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx method_slot = property_slot + j; /* Update opcodes to use new literals table */ - cache_size = 0; + cache_size = zend_op_array_extension_handles * sizeof(void*); opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index fdaa9aecc0a..f00d15119fd 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -1374,6 +1374,8 @@ static zend_persistent_script *store_script_in_file_cache(zend_persistent_script ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used); #endif + zend_shared_alloc_clear_xlat_table(); + /* Copy into memory block */ new_persistent_script = zend_accel_script_persist(new_persistent_script, NULL, 0, 0); @@ -1539,6 +1541,8 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr return new_persistent_script; } + zend_shared_alloc_clear_xlat_table(); + /* Copy into shared memory */ new_persistent_script = zend_accel_script_persist(new_persistent_script, &key, key_length, 1); @@ -2278,6 +2282,7 @@ static void zend_reset_cache_vars(void) ZSMMG(wasted_shared_memory) = 0; ZCSG(restart_pending) = 0; ZCSG(force_restart_time) = 0; + ZCSG(map_ptr_last) = CG(map_ptr_last); } static void accel_reset_pcre_cache(void) @@ -2374,6 +2379,7 @@ int accel_activate(INIT_FUNC_ARGS) } accel_restart_enter(); + zend_map_ptr_reset(); zend_reset_cache_vars(); zend_accel_hash_clean(&ZCSG(hash)); @@ -2561,7 +2567,6 @@ static int zend_accel_init_shm(void) ZCSG(last_restart_time) = 0; ZCSG(restart_in_progress) = 0; - for (i = 0; i < -HT_MIN_MASK; i++) { ZCSG(uninitialized_bucket)[i] = HT_INVALID_IDX; } diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index f48c3779f28..7e06047200e 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -240,6 +240,7 @@ typedef struct _zend_accel_globals { void *mem; void *arena_mem; zend_persistent_script *current_persistent_script; + zend_bool is_immutable_class; /* cache to save hash lookup on the same INCLUDE opcode */ const zend_op *cache_opline; zend_persistent_script *cache_persistent_script; @@ -267,6 +268,8 @@ typedef struct _zend_accel_shared_globals { zend_ulong manual_restarts; /* number of restarts scheduled by opcache_reset() */ zend_accel_hash hash; /* hash table for cached scripts */ + size_t map_ptr_last; + /* Directives & Maintenance */ time_t start_time; time_t last_restart_time; diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index 4db2c34fbcd..66964e2ef72 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -126,11 +126,14 @@ static void zend_hash_clone_constants(HashTable *ht, HashTable *source) end = p + ht->nNumUsed; for (; p != end; p++) { ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF); - c = ARENA_REALLOC(Z_PTR(p->val)); - Z_PTR(p->val) = c; + c = Z_PTR(p->val); + if (IN_ARENA(c)) { + c = ARENA_REALLOC(c); + Z_PTR(p->val) = c; - if (IN_ARENA(c->ce)) { - c->ce = ARENA_REALLOC(c->ce); + if (IN_ARENA(c->ce)) { + c->ce = ARENA_REALLOC(c->ce); + } } } } @@ -162,16 +165,21 @@ static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class end = p + ht->nNumUsed; for (; p != end; p++) { ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF); - new_entry = ARENA_REALLOC(Z_PTR(p->val)); - Z_PTR(p->val) = new_entry; + new_entry = Z_PTR(p->val); + if (IN_ARENA(new_entry)) { + new_entry = ARENA_REALLOC(new_entry); + Z_PTR(p->val) = new_entry; - if (IN_ARENA(new_entry->scope)) { - new_entry->scope = ARENA_REALLOC(new_entry->scope); + if (IN_ARENA(new_entry->scope)) { + new_entry->scope = ARENA_REALLOC(new_entry->scope); - /* update prototype */ - if (new_entry->prototype) { - new_entry->prototype = ARENA_REALLOC(new_entry->prototype); + /* update prototype */ + if (IN_ARENA(new_entry->prototype)) { + new_entry->prototype = ARENA_REALLOC(new_entry->prototype); + } } + ZEND_MAP_PTR_INIT(new_entry->run_time_cache, ARENA_REALLOC(ZEND_MAP_PTR(new_entry->run_time_cache))); + ZEND_MAP_PTR_INIT(new_entry->static_variables_ptr, &new_entry->static_variables); } } } @@ -203,11 +211,14 @@ static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_cla end = p + ht->nNumUsed; for (; p != end; p++) { ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF); - prop_info = ARENA_REALLOC(Z_PTR(p->val)); - Z_PTR(p->val) = prop_info; + prop_info = Z_PTR(p->val); + if (IN_ARENA(prop_info)) { + prop_info = ARENA_REALLOC(prop_info); + Z_PTR(p->val) = prop_info; - if (IN_ARENA(prop_info->ce)) { - prop_info->ce = ARENA_REALLOC(prop_info->ce); + if (IN_ARENA(prop_info->ce)) { + prop_info->ce = ARENA_REALLOC(prop_info->ce); + } } } } @@ -229,7 +240,7 @@ static void zend_class_copy_ctor(zend_class_entry **pce) *pce = ce = ARENA_REALLOC(old_ce); ce->refcount = 1; - if (ce->parent && (ce->ce_flags & ZEND_ACC_LINKED)) { + if ((ce->ce_flags & ZEND_ACC_LINKED) && IN_ARENA(ce->parent)) { ce->parent = ARENA_REALLOC(ce->parent); } @@ -271,7 +282,7 @@ static void zend_class_copy_ctor(zend_class_entry **pce) parent = parent->parent; } } - ce->static_members_table = ce->default_static_members_table; + ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); /* properties_info */ zend_hash_clone_prop_info(&ce->properties_info, &old_ce->properties_info, old_ce); @@ -282,10 +293,23 @@ static void zend_class_copy_ctor(zend_class_entry **pce) if (ce->num_interfaces) { zend_class_name *interface_names; - ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED)); - interface_names = emalloc(sizeof(zend_class_name) * ce->num_interfaces); - memcpy(interface_names, ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces); - ce->interface_names = interface_names; + if (!(ce->ce_flags & ZEND_ACC_LINKED)) { + interface_names = emalloc(sizeof(zend_class_name) * ce->num_interfaces); + memcpy(interface_names, ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces); + ce->interface_names = interface_names; + } else { + zend_class_entry **interfaces = emalloc(sizeof(zend_class_entry*) * ce->num_interfaces); + uint32_t i; + + for (i = 0; i < ce->num_interfaces; i++) { + if (IN_ARENA(ce->interfaces[i])) { + interfaces[i] = ARENA_REALLOC(ce->interfaces[i]); + } else { + interfaces[i] = ce->interfaces[i]; + } + } + ce->interfaces = interfaces; + } } zend_update_inherited_handler(constructor); @@ -349,6 +373,11 @@ static void zend_class_copy_ctor(zend_class_entry **pce) ce->trait_precedences = trait_precedences; } } + + if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { + ZEND_MAP_PTR_INIT(ce->iterator_funcs_ptr, ARENA_REALLOC(ZEND_MAP_PTR(ce->iterator_funcs_ptr))); + ZEND_MAP_PTR_SET(ce->iterator_funcs_ptr, ARENA_REALLOC(ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr))); + } } static void zend_accel_function_hash_copy(HashTable *target, HashTable *source) @@ -507,7 +536,9 @@ static void zend_accel_class_hash_copy_from_shm(HashTable *target, HashTable *so } } else { t = _zend_hash_append_ptr_ex(target, p->key, Z_PTR(p->val), 1); - zend_class_copy_ctor((zend_class_entry**)&Z_PTR_P(t)); + if (!(((zend_class_entry*)Z_PTR_P(t))->ce_flags & ZEND_ACC_IMMUTABLE)) { + zend_class_copy_ctor((zend_class_entry**)&Z_PTR_P(t)); + } } } target->nInternalPointer = 0; @@ -668,6 +699,7 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, op_array = (zend_op_array *) emalloc(sizeof(zend_op_array)); *op_array = persistent_script->script.main_op_array; + ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables); if (EXPECTED(from_shared_memory)) { zend_hash_init(&ZCG(bind_hash), 10, NULL, NULL, 0); @@ -712,6 +744,7 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, zend_hash_destroy(&ZCG(bind_hash)); ZCG(current_persistent_script) = NULL; + zend_map_ptr_extend(ZCSG(map_ptr_last)); } else /* if (!from_shared_memory) */ { if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) { zend_accel_function_hash_copy(CG(function_table), &persistent_script->script.function_table); diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index f6ed2fc9187..50082931572 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -534,6 +534,13 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra SERIALIZE_STR(op_array->doc_comment); SERIALIZE_PTR(op_array->try_catch_array); SERIALIZE_PTR(op_array->prototype); + + ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables); + if (op_array->fn_flags & ZEND_ACC_IMMUTABLE) { + ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL); + } else { + SERIALIZE_PTR(ZEND_MAP_PTR(op_array->run_time_cache)); + } } } @@ -749,6 +756,15 @@ static void zend_file_cache_serialize_class(zval *zv, SERIALIZE_PTR(ce->__tostring); SERIALIZE_PTR(ce->__callstatic); SERIALIZE_PTR(ce->__debugInfo); + + ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); + if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { + if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { + ZEND_MAP_PTR_INIT(ce->iterator_funcs_ptr, (void*)(uintptr_t)1); + } else { + SERIALIZE_PTR(ZEND_MAP_PTR(ce->iterator_funcs_ptr)); + } + } } static void zend_file_cache_serialize(zend_persistent_script *script, @@ -1183,6 +1199,18 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr UNSERIALIZE_STR(op_array->doc_comment); UNSERIALIZE_PTR(op_array->try_catch_array); UNSERIALIZE_PTR(op_array->prototype); + + if (op_array->fn_flags & ZEND_ACC_IMMUTABLE) { + if (op_array->static_variables) { + ZEND_MAP_PTR_NEW(op_array->static_variables_ptr); + } else { + ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables); + } + ZEND_MAP_PTR_NEW(op_array->run_time_cache); + } else { + ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables); + UNSERIALIZE_PTR(ZEND_MAP_PTR(op_array->run_time_cache)); + } } } @@ -1384,6 +1412,20 @@ static void zend_file_cache_unserialize_class(zval *zv, ce->serialize = zend_class_serialize_deny; ce->unserialize = zend_class_unserialize_deny; } + + if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { + if (ce->default_static_members_table) { + ZEND_MAP_PTR_NEW(ce->static_members_table); + } else { + ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); + } + if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { + ZEND_MAP_PTR_NEW(ce->iterator_funcs_ptr); + } + } else { + ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); + UNSERIALIZE_PTR(ZEND_MAP_PTR(ce->iterator_funcs_ptr)); + } } static void zend_file_cache_unserialize(zend_persistent_script *script, @@ -1546,6 +1588,7 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl goto use_process_mem; } memcpy(buf, mem, info.mem_size); + zend_map_ptr_extend(ZCSG(map_ptr_last)); } else { use_process_mem: buf = mem; @@ -1576,6 +1619,7 @@ use_process_mem: script->corrupted = 0; if (cache_it) { + ZCSG(map_ptr_last) = CG(map_ptr_last); script->dynamic_members.checksum = zend_accel_script_checksum(script); script->dynamic_members.last_used = ZCG(request_time); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 6b3413324c6..e325c495bb0 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -391,9 +391,14 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << GC_FLAGS_SHIFT); } } + ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables); if (op_array->scope) { - op_array->scope = zend_shared_alloc_get_xlat_entry(op_array->scope); + zend_class_entry *scope = zend_shared_alloc_get_xlat_entry(op_array->scope); + + if (scope) { + op_array->scope = scope; + } if (op_array->prototype) { zend_function *ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype); @@ -557,7 +562,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc efree(op_array->opcodes); op_array->opcodes = new_opcodes; - op_array->run_time_cache = NULL; + ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL); } if (op_array->function_name && !IS_ACCEL_INTERNED(op_array->function_name)) { @@ -633,11 +638,19 @@ static void zend_persist_op_array(zval *zv) zend_op_array *op_array = Z_PTR_P(zv); ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION); - memcpy(ZCG(mem), Z_PTR_P(zv), sizeof(zend_op_array)); - Z_PTR_P(zv) = ZCG(mem); - ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(sizeof(zend_op_array))); - zend_persist_op_array_ex(Z_PTR_P(zv), NULL); - ((zend_op_array*)Z_PTR_P(zv))->fn_flags |= ZEND_ACC_IMMUTABLE; + op_array = Z_PTR_P(zv) = zend_shared_memdup(Z_PTR_P(zv), sizeof(zend_op_array)); + zend_persist_op_array_ex(op_array, NULL); + if (!ZCG(current_persistent_script)->corrupted) { + op_array->fn_flags |= ZEND_ACC_IMMUTABLE; + ZEND_MAP_PTR_NEW(op_array->run_time_cache); + if (op_array->static_variables) { + ZEND_MAP_PTR_NEW(op_array->static_variables_ptr); + } + } else { + ZEND_MAP_PTR_INIT(op_array->run_time_cache, ZCG(arena_mem)); + ZCG(arena_mem) = (void*)(((char*)ZCG(arena_mem)) + ZEND_ALIGNED_SIZE(sizeof(void*))); + ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL); + } } static void zend_persist_class_method(zval *zv) @@ -645,7 +658,35 @@ static void zend_persist_class_method(zval *zv) zend_op_array *op_array = Z_PTR_P(zv); zend_op_array *old_op_array; - ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION); + if (op_array->type != ZEND_USER_FUNCTION) { + ZEND_ASSERT(op_array->type == ZEND_INTERNAL_FUNCTION); + if (op_array->fn_flags & ZEND_ACC_ARENA_ALLOCATED) { + old_op_array = zend_shared_alloc_get_xlat_entry(op_array); + if (old_op_array) { + Z_PTR_P(zv) = old_op_array; + } else { + if (ZCG(is_immutable_class)) { + op_array = Z_PTR_P(zv) = zend_shared_memdup_put(op_array, sizeof(zend_internal_function)); + } else { + op_array = Z_PTR_P(zv) = zend_shared_memdup_arena_put(op_array, sizeof(zend_internal_function)); + } + if (op_array->scope) { + void *persist_ptr; + + if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->scope))) { + op_array->scope = (zend_class_entry*)persist_ptr; + } + if (op_array->prototype) { + if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) { + op_array->prototype = (zend_function*)persist_ptr; + } + } + } + } + } + return; + } + old_op_array = zend_shared_alloc_get_xlat_entry(op_array); if (old_op_array) { Z_PTR_P(zv) = old_op_array; @@ -654,11 +695,23 @@ static void zend_persist_class_method(zval *zv) } return; } - memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_op_array)); - zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem)); - Z_PTR_P(zv) = ZCG(arena_mem); - ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_op_array))); - zend_persist_op_array_ex(Z_PTR_P(zv), NULL); + if (ZCG(is_immutable_class)) { + op_array = Z_PTR_P(zv) = zend_shared_memdup_put(op_array, sizeof(zend_op_array)); + } else { + op_array = Z_PTR_P(zv) = zend_shared_memdup_arena_put(op_array, sizeof(zend_op_array)); + } + zend_persist_op_array_ex(op_array, NULL); + if (ZCG(is_immutable_class)) { + op_array->fn_flags |= ZEND_ACC_IMMUTABLE; + ZEND_MAP_PTR_NEW(op_array->run_time_cache); + if (op_array->static_variables) { + ZEND_MAP_PTR_NEW(op_array->static_variables_ptr); + } + } else { + ZEND_MAP_PTR_INIT(op_array->run_time_cache, ZCG(arena_mem)); + ZCG(arena_mem) = (void*)(((char*)ZCG(arena_mem)) + ZEND_ALIGNED_SIZE(sizeof(void*))); + ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL); + } } static void zend_persist_property_info(zval *zv) @@ -669,10 +722,11 @@ static void zend_persist_property_info(zval *zv) Z_PTR_P(zv) = prop; return; } - memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_property_info)); - zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem)); - prop = Z_PTR_P(zv) = ZCG(arena_mem); - ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_property_info))); + if (ZCG(is_immutable_class)) { + prop = Z_PTR_P(zv) = zend_shared_memdup_put(Z_PTR_P(zv), sizeof(zend_property_info)); + } else { + prop = Z_PTR_P(zv) = zend_shared_memdup_arena_put(Z_PTR_P(zv), sizeof(zend_property_info)); + } prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce); zend_accel_store_interned_string(prop->name); if (prop->doc_comment) { @@ -696,10 +750,11 @@ static void zend_persist_class_constant(zval *zv) Z_PTR_P(zv) = c; return; } - memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_class_constant)); - zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem)); - c = Z_PTR_P(zv) = ZCG(arena_mem); - ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_class_constant))); + if (ZCG(is_immutable_class)) { + c = Z_PTR_P(zv) = zend_shared_memdup_put(Z_PTR_P(zv), sizeof(zend_class_constant)); + } else { + c = Z_PTR_P(zv) = zend_shared_memdup_arena_put(Z_PTR_P(zv), sizeof(zend_class_constant)); + } zend_persist_zval(&c->value); c->ce = zend_shared_alloc_get_xlat_entry(c->ce); if (c->doc_comment) { @@ -726,10 +781,16 @@ static void zend_persist_class_entry(zval *zv) zend_class_entry *ce = Z_PTR_P(zv); if (ce->type == ZEND_USER_CLASS) { - memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_class_entry)); - zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem)); - ce = Z_PTR_P(zv) = ZCG(arena_mem); - ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_class_entry))); + if ((ce->ce_flags & ZEND_ACC_LINKED) + && (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) + && !ZCG(current_persistent_script)->corrupted) { + ZCG(is_immutable_class) = 1; + ce = Z_PTR_P(zv) = zend_shared_memdup_put(ce, sizeof(zend_class_entry)); + ce->ce_flags |= ZEND_ACC_IMMUTABLE; + } else { + ZCG(is_immutable_class) = 0; + ce = Z_PTR_P(zv) = zend_shared_memdup_arena_put(ce, sizeof(zend_class_entry)); + } zend_accel_store_interned_string(ce->name); if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) { zend_accel_store_interned_string(ce->parent_name); @@ -754,8 +815,14 @@ static void zend_persist_class_entry(zval *zv) for (; i < ce->default_static_members_count; i++) { zend_persist_zval(&ce->default_static_members_table[i]); } + if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { + ZEND_MAP_PTR_NEW(ce->static_members_table); + } else { + ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); + } + } else { + ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); } - ce->static_members_table = NULL; zend_hash_persist(&ce->constants_table, zend_persist_class_constant); HT_FLAGS(&ce->constants_table) &= (HASH_FLAG_INITIALIZED | HASH_FLAG_STATIC_KEYS); @@ -778,10 +845,9 @@ static void zend_persist_class_entry(zval *zv) zend_hash_persist(&ce->properties_info, zend_persist_property_info); HT_FLAGS(&ce->properties_info) &= (HASH_FLAG_INITIALIZED | HASH_FLAG_STATIC_KEYS); - if (ce->num_interfaces) { + if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_LINKED)) { uint32_t i = 0; - ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED)); for (i = 0; i < ce->num_interfaces; i++) { zend_accel_store_interned_string(ce->interface_names[i].name); zend_accel_store_interned_string(ce->interface_names[i].lc_name); @@ -838,6 +904,16 @@ static void zend_persist_class_entry(zval *zv) ce->trait_precedences, sizeof(zend_trait_precedence*) * (i + 1)); } } + + if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { + if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { + ZEND_MAP_PTR_NEW(ce->iterator_funcs_ptr); + } else { + ZEND_MAP_PTR_INIT(ce->iterator_funcs_ptr, ZCG(arena_mem)); + ZCG(arena_mem) = (void*)(((char*)ZCG(arena_mem)) + ZEND_ALIGNED_SIZE(sizeof(void*))); + ZEND_MAP_PTR_SET(ce->iterator_funcs_ptr, zend_shared_memdup_arena(ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr), sizeof(zend_class_iterator_funcs))); + } + } } } @@ -853,8 +929,45 @@ static int zend_update_parent_ce(zval *zv) { zend_class_entry *ce = Z_PTR_P(zv); - if (ce->parent && (ce->ce_flags & ZEND_ACC_LINKED)) { - ce->parent = zend_shared_alloc_get_xlat_entry(ce->parent); + if (ce->ce_flags & ZEND_ACC_LINKED) { + if (ce->parent) { + int i, end; + zend_class_entry *parent = ce->parent; + + if (parent->type == ZEND_USER_CLASS) { + zend_class_entry *p = zend_shared_alloc_get_xlat_entry(parent); + + if (p) { + ce->parent = parent = p; + } + } + + /* Create indirections to static properties from parent classes */ + i = parent->default_static_members_count - 1; + while (parent && parent->default_static_members_table) { + end = parent->parent ? parent->parent->default_static_members_count : 0; + for (; i >= end; i--) { + zval *p = &ce->default_static_members_table[i]; + ZVAL_INDIRECT(p, &parent->default_static_members_table[i]); + } + + parent = parent->parent; + } + } + + if (ce->num_interfaces) { + uint32_t i = 0; + + ce->interfaces = zend_shared_memdup_free(ce->interfaces, sizeof(zend_class_entry*) * ce->num_interfaces); + for (i = 0; i < ce->num_interfaces; i++) { + if (ce->interfaces[i]->type == ZEND_USER_CLASS) { + zend_class_entry *tmp = zend_shared_alloc_get_xlat_entry(ce->interfaces[i]); + if (tmp != NULL) { + ce->interfaces[i] = tmp; + } + } + } + } } /* update methods */ @@ -912,7 +1025,6 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script script->mem = ZCG(mem); ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */ - zend_shared_alloc_clear_xlat_table(); script = zend_shared_memdup_free(script, sizeof(zend_persistent_script)); if (key && *key) { @@ -939,10 +1051,14 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script script->arena_mem = ZCG(arena_mem) = ZCG(mem); ZCG(mem) = (void*)((char*)ZCG(mem) + script->arena_size); + zend_map_ptr_extend(ZCSG(map_ptr_last)); + zend_accel_persist_class_table(&script->script.class_table); zend_hash_persist(&script->script.function_table, zend_persist_op_array); zend_persist_op_array_ex(&script->script.main_op_array, script); + ZCSG(map_ptr_last) = CG(map_ptr_last); + script->corrupted = 0; ZCG(current_persistent_script) = NULL; diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index fcd5db58a7e..e7a4db0d831 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -28,8 +28,15 @@ #define ADD_DUP_SIZE(m,s) ZCG(current_persistent_script)->size += zend_shared_memdup_size((void*)m, s) #define ADD_SIZE(m) ZCG(current_persistent_script)->size += ZEND_ALIGNED_SIZE(m) +#define ADD_ARENA_SIZE(m) ZCG(current_persistent_script)->arena_size += ZEND_ALIGNED_SIZE(m) -#define ADD_ARENA_SIZE(m) ZCG(current_persistent_script)->arena_size += ZEND_ALIGNED_SIZE(m) +#define ADD_SIZE_EX(m) do { \ + if (ZCG(is_immutable_class)) { \ + ADD_SIZE(m); \ + } else { \ + ADD_ARENA_SIZE(m); \ + } \ + } while (0) # define ADD_STRING(str) ADD_DUP_SIZE((str), _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))) @@ -258,6 +265,9 @@ static void zend_persist_op_array_calc(zval *zv) ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION); ADD_SIZE(sizeof(zend_op_array)); zend_persist_op_array_calc_ex(Z_PTR_P(zv)); + if (ZCG(current_persistent_script)->corrupted) { + ADD_ARENA_SIZE(sizeof(void*)); + } } static void zend_persist_class_method_calc(zval *zv) @@ -265,12 +275,26 @@ static void zend_persist_class_method_calc(zval *zv) zend_op_array *op_array = Z_PTR_P(zv); zend_op_array *old_op_array; - ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION); + if (op_array->type != ZEND_USER_FUNCTION) { + ZEND_ASSERT(op_array->type == ZEND_INTERNAL_FUNCTION); + if (op_array->fn_flags & ZEND_ACC_ARENA_ALLOCATED) { + old_op_array = zend_shared_alloc_get_xlat_entry(op_array); + if (!old_op_array) { + ADD_SIZE_EX(sizeof(zend_internal_function)); + zend_shared_alloc_register_xlat_entry(op_array, Z_PTR_P(zv)); + } + } + return; + } + old_op_array = zend_shared_alloc_get_xlat_entry(op_array); if (!old_op_array) { - ADD_ARENA_SIZE(sizeof(zend_op_array)); + ADD_SIZE_EX(sizeof(zend_op_array)); zend_persist_op_array_calc_ex(Z_PTR_P(zv)); zend_shared_alloc_register_xlat_entry(op_array, Z_PTR_P(zv)); + if (!ZCG(is_immutable_class)) { + ADD_ARENA_SIZE(sizeof(void*)); + } } } @@ -280,7 +304,7 @@ static void zend_persist_property_info_calc(zval *zv) if (!zend_shared_alloc_get_xlat_entry(prop)) { zend_shared_alloc_register_xlat_entry(prop, prop); - ADD_ARENA_SIZE(sizeof(zend_property_info)); + ADD_SIZE_EX(sizeof(zend_property_info)); ADD_INTERNED_STRING(prop->name, 0); if (ZCG(accel_directives).save_comments && prop->doc_comment) { ADD_STRING(prop->doc_comment); @@ -294,7 +318,7 @@ static void zend_persist_class_constant_calc(zval *zv) if (!zend_shared_alloc_get_xlat_entry(c)) { zend_shared_alloc_register_xlat_entry(c, c); - ADD_ARENA_SIZE(sizeof(zend_class_constant)); + ADD_SIZE_EX(sizeof(zend_class_constant)); zend_persist_zval_calc(&c->value); if (ZCG(accel_directives).save_comments && c->doc_comment) { ADD_STRING(c->doc_comment); @@ -302,13 +326,17 @@ static void zend_persist_class_constant_calc(zval *zv) } } - static void zend_persist_class_entry_calc(zval *zv) { zend_class_entry *ce = Z_PTR_P(zv); if (ce->type == ZEND_USER_CLASS) { - ADD_ARENA_SIZE(sizeof(zend_class_entry)); + ZCG(is_immutable_class) = + (ce->ce_flags & ZEND_ACC_LINKED) && + (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) && + !ZCG(current_persistent_script)->corrupted; + + ADD_SIZE_EX(sizeof(zend_class_entry)); ADD_INTERNED_STRING(ce->name, 0); if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) { ADD_INTERNED_STRING(ce->parent_name, 0); @@ -346,12 +374,15 @@ static void zend_persist_class_entry_calc(zval *zv) if (ce->num_interfaces) { uint32_t i; - ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED)); - for (i = 0; i < ce->num_interfaces; i++) { - ADD_INTERNED_STRING(ce->interface_names[i].name, 0); - ADD_INTERNED_STRING(ce->interface_names[i].lc_name, 0); + if (!(ce->ce_flags & ZEND_ACC_LINKED)) { + for (i = 0; i < ce->num_interfaces; i++) { + ADD_INTERNED_STRING(ce->interface_names[i].name, 0); + ADD_INTERNED_STRING(ce->interface_names[i].lc_name, 0); + } + ADD_SIZE(sizeof(zend_class_name) * ce->num_interfaces); + } else { + ADD_SIZE(sizeof(zend_class_entry*) * ce->num_interfaces); } - ADD_SIZE(sizeof(zend_class_name) * ce->num_interfaces); } if (ce->num_traits) { @@ -399,6 +430,13 @@ static void zend_persist_class_entry_calc(zval *zv) ADD_SIZE(sizeof(zend_trait_precedence*) * (i + 1)); } } + + if (ZEND_MAP_PTR(ce->iterator_funcs_ptr)) { + if (!ZCG(is_immutable_class)) { + ADD_ARENA_SIZE(sizeof(void*)); + ADD_ARENA_SIZE(sizeof(zend_class_iterator_funcs)); + } + } } } diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c index 8d4d792bb32..fe8d470d585 100644 --- a/ext/opcache/zend_shared_alloc.c +++ b/ext/opcache/zend_shared_alloc.c @@ -347,7 +347,7 @@ int zend_shared_memdup_size(void *source, size_t size) return ZEND_ALIGNED_SIZE(size); } -static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, zend_bool get_xlat, zend_bool set_xlat, zend_bool free_source) +static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, zend_bool arena, zend_bool get_xlat, zend_bool set_xlat, zend_bool free_source) { void *old_p, *retval; zend_ulong key; @@ -360,8 +360,13 @@ static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, z return old_p; } } - retval = ZCG(mem); - ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size)); + if (arena) { + retval = ZCG(arena_mem); + ZCG(arena_mem) = (void*)(((char*)ZCG(arena_mem)) + ZEND_ALIGNED_SIZE(size)); + } else { + retval = ZCG(mem); + ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size)); + } memcpy(retval, source, size); if (set_xlat) { if (!get_xlat) { @@ -378,32 +383,42 @@ static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, z void *zend_shared_memdup_get_put_free(void *source, size_t size) { - return _zend_shared_memdup(source, size, 1, 1, 1); + return _zend_shared_memdup(source, size, 0, 1, 1, 1); } void *zend_shared_memdup_put_free(void *source, size_t size) { - return _zend_shared_memdup(source, size, 0, 1, 1); + return _zend_shared_memdup(source, size, 0, 0, 1, 1); } void *zend_shared_memdup_free(void *source, size_t size) { - return _zend_shared_memdup(source, size, 0, 0, 1); + return _zend_shared_memdup(source, size, 0, 0, 0, 1); } void *zend_shared_memdup_get_put(void *source, size_t size) { - return _zend_shared_memdup(source, size, 1, 1, 0); + return _zend_shared_memdup(source, size, 0, 1, 1, 0); } void *zend_shared_memdup_put(void *source, size_t size) { - return _zend_shared_memdup(source, size, 0, 1, 0); + return _zend_shared_memdup(source, size, 0, 0, 1, 0); } void *zend_shared_memdup(void *source, size_t size) { - return _zend_shared_memdup(source, size, 0, 0, 0); + return _zend_shared_memdup(source, size, 0, 0, 0, 0); +} + +void *zend_shared_memdup_arena_put(void *source, size_t size) +{ + return _zend_shared_memdup(source, size, 1, 0, 1, 0); +} + +void *zend_shared_memdup_arena(void *source, size_t size) +{ + return _zend_shared_memdup(source, size, 1, 0, 0, 0); } void zend_shared_alloc_safe_unlock(void) @@ -483,6 +498,16 @@ void zend_shared_alloc_clear_xlat_table(void) zend_hash_clean(&ZCG(xlat_table)); } +uint32_t zend_shared_alloc_checkpoint_xlat_table(void) +{ + return ZCG(xlat_table).nNumUsed; +} + +void zend_shared_alloc_restore_xlat_table(uint32_t checkpoint) +{ + zend_hash_discard(&ZCG(xlat_table), checkpoint); +} + void zend_shared_alloc_register_xlat_entry(const void *old, const void *new) { zend_ulong key = (zend_ulong)old; diff --git a/ext/opcache/zend_shared_alloc.h b/ext/opcache/zend_shared_alloc.h index fd71529b76c..f784c5e48df 100644 --- a/ext/opcache/zend_shared_alloc.h +++ b/ext/opcache/zend_shared_alloc.h @@ -131,6 +131,8 @@ void *zend_shared_memdup_free(void *source, size_t size); void *zend_shared_memdup_get_put(void *source, size_t size); void *zend_shared_memdup_put(void *source, size_t size); void *zend_shared_memdup(void *source, size_t size); +void *zend_shared_memdup_arena_put(void *source, size_t size); +void *zend_shared_memdup_arena(void *source, size_t size); int zend_shared_memdup_size(void *p, size_t size); @@ -160,6 +162,8 @@ void zend_shared_alloc_safe_unlock(void); void zend_shared_alloc_init_xlat_table(void); void zend_shared_alloc_destroy_xlat_table(void); void zend_shared_alloc_clear_xlat_table(void); +uint32_t zend_shared_alloc_checkpoint_xlat_table(void); +void zend_shared_alloc_restore_xlat_table(uint32_t checkpoint); void zend_shared_alloc_register_xlat_entry(const void *old, const void *new); void *zend_shared_alloc_get_xlat_entry(const void *old); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 8114625e683..8c5dd73f5ae 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -685,7 +685,7 @@ static void _function_closure_string(smart_str *str, zend_function *fptr, char* return; } - static_variables = fptr->op_array.static_variables; + static_variables = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr); count = zend_hash_num_elements(static_variables); if (!count) { @@ -1790,19 +1790,21 @@ ZEND_METHOD(reflection_function, getStaticVariables) /* Return an empty array in case no static variables exist */ if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) { + HashTable *ht; + array_init(return_value); - if (GC_REFCOUNT(fptr->op_array.static_variables) > 1) { - if (!(GC_FLAGS(fptr->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) { - GC_DELREF(fptr->op_array.static_variables); - } - fptr->op_array.static_variables = zend_array_dup(fptr->op_array.static_variables); + ht = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr); + if (!ht) { + ZEND_ASSERT(fptr->op_array.fn_flags & ZEND_ACC_IMMUTABLE); + ht = zend_array_dup(fptr->op_array.static_variables); + ZEND_MAP_PTR_SET(fptr->op_array.static_variables_ptr, ht); } - ZEND_HASH_FOREACH_VAL(fptr->op_array.static_variables, val) { + ZEND_HASH_FOREACH_VAL(ht, val) { if (UNEXPECTED(zval_update_constant_ex(val, fptr->common.scope) != SUCCESS)) { return; } } ZEND_HASH_FOREACH_END(); - zend_hash_copy(Z_ARRVAL_P(return_value), fptr->op_array.static_variables, zval_add_ref); + zend_hash_copy(Z_ARRVAL_P(return_value), ht, zval_add_ref); } else { ZVAL_EMPTY_ARRAY(return_value); } diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 04e73bf26e6..ba0614cf7a2 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -243,19 +243,22 @@ static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zval * /* Cache iterator functions if ArrayIterator or derived. Check current's */ /* cache since only current is always required */ if (intern->std.handlers == &spl_handler_ArrayIterator) { - if (!class_type->iterator_funcs_ptr->zf_current) { - class_type->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1); - class_type->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1); - class_type->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1); - class_type->iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1); - class_type->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1); + zend_class_iterator_funcs *iterator_funcs_ptr = + ZEND_MAP_PTR_GET(class_type->iterator_funcs_ptr); + + if (!iterator_funcs_ptr->zf_current) { + iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1); + iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1); + iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1); + iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1); + iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1); } if (inherited) { - if (class_type->iterator_funcs_ptr->zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND; - if (class_type->iterator_funcs_ptr->zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID; - if (class_type->iterator_funcs_ptr->zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY; - if (class_type->iterator_funcs_ptr->zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT; - if (class_type->iterator_funcs_ptr->zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT; + if (iterator_funcs_ptr->zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND; + if (iterator_funcs_ptr->zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID; + if (iterator_funcs_ptr->zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY; + if (iterator_funcs_ptr->zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT; + if (iterator_funcs_ptr->zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT; } } diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 392175f781f..9b92f885522 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -207,6 +207,7 @@ static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, z spl_fixedarray_object *intern; zend_class_entry *parent = class_type; int inherited = 0; + zend_class_iterator_funcs *iterator_funcs_ptr; intern = zend_object_alloc(sizeof(spl_fixedarray_object), parent); @@ -238,27 +239,28 @@ static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, z php_error_docref(NULL, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplFixedArray"); } - if (!class_type->iterator_funcs_ptr->zf_current) { - class_type->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1); - class_type->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1); - class_type->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1); - class_type->iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1); - class_type->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1); + iterator_funcs_ptr = ZEND_MAP_PTR_GET(class_type->iterator_funcs_ptr); + if (!iterator_funcs_ptr->zf_current) { + iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1); + iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1); + iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1); + iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1); + iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1); } if (inherited) { - if (class_type->iterator_funcs_ptr->zf_rewind->common.scope != parent) { + if (iterator_funcs_ptr->zf_rewind->common.scope != parent) { intern->flags |= SPL_FIXEDARRAY_OVERLOADED_REWIND; } - if (class_type->iterator_funcs_ptr->zf_valid->common.scope != parent) { + if (iterator_funcs_ptr->zf_valid->common.scope != parent) { intern->flags |= SPL_FIXEDARRAY_OVERLOADED_VALID; } - if (class_type->iterator_funcs_ptr->zf_key->common.scope != parent) { + if (iterator_funcs_ptr->zf_key->common.scope != parent) { intern->flags |= SPL_FIXEDARRAY_OVERLOADED_KEY; } - if (class_type->iterator_funcs_ptr->zf_current->common.scope != parent) { + if (iterator_funcs_ptr->zf_current->common.scope != parent) { intern->flags |= SPL_FIXEDARRAY_OVERLOADED_CURRENT; } - if (class_type->iterator_funcs_ptr->zf_next->common.scope != parent) { + if (iterator_funcs_ptr->zf_next->common.scope != parent) { intern->flags |= SPL_FIXEDARRAY_OVERLOADED_NEXT; } diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index f1688dbf16f..debdbd8a3c5 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -494,7 +494,8 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "o|lzl", &iterator, &flags, &user_caching_it_flags, &mode) == SUCCESS) { if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) { - zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &Z_OBJCE_P(iterator)->iterator_funcs_ptr->zf_new_iterator, "getiterator", &aggregate_retval); + zend_class_iterator_funcs *iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(iterator)->iterator_funcs_ptr); + zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &iterator_funcs_ptr->zf_new_iterator, "getiterator", &aggregate_retval); iterator = &aggregate_retval; } else { Z_ADDREF_P(iterator); @@ -522,7 +523,8 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "o|ll", &iterator, &mode, &flags) == SUCCESS) { if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate)) { - zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &Z_OBJCE_P(iterator)->iterator_funcs_ptr->zf_new_iterator, "getiterator", &aggregate_retval); + zend_class_iterator_funcs *iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(iterator)->iterator_funcs_ptr); + zend_call_method_with_0_params(iterator, Z_OBJCE_P(iterator), &iterator_funcs_ptr->zf_new_iterator, "getiterator", &aggregate_retval); iterator = &aggregate_retval; } else { Z_ADDREF_P(iterator); @@ -1348,19 +1350,6 @@ static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = { PHP_FE_END }; -#if MBO_0 -static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type) -{ - class_type->iterator_funcs_ptr->zf_valid = NULL; - class_type->iterator_funcs_ptr->zf_current = NULL; - class_type->iterator_funcs_ptr->zf_key = NULL; - class_type->iterator_funcs_ptr->zf_next = NULL; - class_type->iterator_funcs_ptr->zf_rewind = NULL; - - return SUCCESS; -} -#endif - static zend_function *spl_dual_it_get_method(zend_object **object, zend_string *method, const zval *key) { zend_function *function_handler; @@ -1513,7 +1502,8 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z ce = ce_cast; } if (instanceof_function(ce, zend_ce_aggregate)) { - zend_call_method_with_0_params(zobject, ce, &ce->iterator_funcs_ptr->zf_new_iterator, "getiterator", &retval); + zend_class_iterator_funcs *iterator_funcs_ptr = ZEND_MAP_PTR_GET(ce->iterator_funcs_ptr); + zend_call_method_with_0_params(zobject, ce, &iterator_funcs_ptr->zf_new_iterator, "getiterator", &retval); if (EG(exception)) { zval_ptr_dtor(&retval); return NULL; diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index 0dd755e07f7..c61f31b4ff4 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -1028,8 +1028,11 @@ SPL_METHOD(MultipleIterator, rewind) zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) { + zend_class_iterator_funcs *iterator_funcs_ptr; + it = &element->obj; - zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_rewind, "rewind", NULL); + iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(it)->iterator_funcs_ptr); + zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->zf_rewind, "rewind", NULL); zend_hash_move_forward_ex(&intern->storage, &intern->pos); } } @@ -1051,8 +1054,11 @@ SPL_METHOD(MultipleIterator, next) zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) { + zend_class_iterator_funcs *iterator_funcs_ptr; + it = &element->obj; - zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_next, "next", NULL); + iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(it)->iterator_funcs_ptr); + zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->zf_next, "next", NULL); zend_hash_move_forward_ex(&intern->storage, &intern->pos); } } @@ -1081,8 +1087,11 @@ SPL_METHOD(MultipleIterator, valid) zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) { + zend_class_iterator_funcs *iterator_funcs_ptr; + it = &element->obj; - zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_valid, "valid", &retval); + iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(it)->iterator_funcs_ptr); + zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->zf_valid, "valid", &retval); if (!Z_ISUNDEF(retval)) { valid = (Z_TYPE(retval) == IS_TRUE); @@ -1117,8 +1126,11 @@ static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) { + zend_class_iterator_funcs *iterator_funcs_ptr; + it = &element->obj; - zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_valid, "valid", &retval); + iterator_funcs_ptr = ZEND_MAP_PTR_GET(Z_OBJCE_P(it)->iterator_funcs_ptr); + zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->zf_valid, "valid", &retval); if (!Z_ISUNDEF(retval)) { valid = Z_TYPE(retval) == IS_TRUE; @@ -1129,9 +1141,9 @@ static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_ if (valid) { if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) { - zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_current, "current", &retval); + zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->zf_current, "current", &retval); } else { - zend_call_method_with_0_params(it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs_ptr->zf_key, "key", &retval); + zend_call_method_with_0_params(it, Z_OBJCE_P(it), &iterator_funcs_ptr->zf_key, "key", &retval); } if (Z_ISUNDEF(retval)) { zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0);