diff --git a/Zend/tests/return_types/inheritance001.phpt b/Zend/tests/return_types/inheritance001.phpt index 5f706efbc9e..6618afa868b 100644 --- a/Zend/tests/return_types/inheritance001.phpt +++ b/Zend/tests/return_types/inheritance001.phpt @@ -8,8 +8,8 @@ class A { } class B extends A { - function foo(): StdClass {} + function foo(): stdClass {} } ?> --EXPECTF-- -Fatal error: Declaration of B::foo(): StdClass must be compatible with A::foo(): A in %s on line %d +Fatal error: Declaration of B::foo(): stdClass must be compatible with A::foo(): A in %s on line %d diff --git a/Zend/tests/return_types/inheritance002.phpt b/Zend/tests/return_types/inheritance002.phpt index 1b91af8596e..d70c9bb222f 100644 --- a/Zend/tests/return_types/inheritance002.phpt +++ b/Zend/tests/return_types/inheritance002.phpt @@ -8,8 +8,8 @@ abstract class A { } class B extends A { - function foo(): StdClass {} + function foo(): stdClass {} } ?> --EXPECTF-- -Fatal error: Declaration of B::foo(): StdClass must be compatible with A::foo(): A in %s on line %d +Fatal error: Declaration of B::foo(): stdClass must be compatible with A::foo(): A in %s on line %d diff --git a/Zend/tests/return_types/inheritance003.phpt b/Zend/tests/return_types/inheritance003.phpt index b097dba91a3..6e6f319804d 100644 --- a/Zend/tests/return_types/inheritance003.phpt +++ b/Zend/tests/return_types/inheritance003.phpt @@ -8,8 +8,8 @@ interface A { } class B implements A { - function foo(): StdClass {} + function foo(): stdClass {} } ?> --EXPECTF-- -Fatal error: Declaration of B::foo(): StdClass must be compatible with A::foo(): A in %s on line %d +Fatal error: Declaration of B::foo(): stdClass must be compatible with A::foo(): A in %s on line %d diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 2a2e67a8ce1..3dd4345a401 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -995,6 +995,13 @@ static inline void class_exists_impl(INTERNAL_FUNCTION_PARAMETERS, int flags, in Z_PARAM_BOOL(autoload) ZEND_PARSE_PARAMETERS_END(); + if (ZSTR_HAS_CE_CACHE(name)) { + ce = ZSTR_GET_CE_CACHE(name); + if (ce) { + RETURN_BOOL(((ce->ce_flags & flags) == flags) && !(ce->ce_flags & skip_flags)); + } + } + if (!autoload) { if (ZSTR_VAL(name)[0] == '\\') { /* Ignore leading "\" */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ff72d7d5281..8aeca71cd10 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1197,9 +1197,11 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop if (ZEND_TYPE_HAS_CE(*list_type)) { str = add_type_string(str, ZEND_TYPE_CE(*list_type)->name); } else { - if (ZEND_TYPE_HAS_CE_CACHE(*list_type) - && ZEND_TYPE_CE_CACHE(*list_type)) { - zend_class_entry *ce = ZEND_TYPE_CE_CACHE(*list_type); + zend_string *name = ZEND_TYPE_NAME(*list_type); + + if (ZSTR_HAS_CE_CACHE(name) + && ZSTR_GET_CE_CACHE(name)) { + zend_class_entry *ce = ZSTR_GET_CE_CACHE(name); if (ce->ce_flags & ZEND_ACC_ANON_CLASS) { zend_string *tmp = zend_string_init(ZSTR_VAL(ce->name), strlen(ZSTR_VAL(ce->name)), 0); str = add_type_string(str, tmp); @@ -1207,23 +1209,25 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop str = add_type_string(str, ce->name); } } else { - zend_string *resolved = resolve_class_name(ZEND_TYPE_NAME(*list_type), scope); + zend_string *resolved = resolve_class_name(name, scope); str = add_type_string(str, resolved); zend_string_release(resolved); } } } ZEND_TYPE_LIST_FOREACH_END(); } else if (ZEND_TYPE_HAS_NAME(type)) { - if (ZEND_TYPE_HAS_CE_CACHE(type) - && ZEND_TYPE_CE_CACHE(type)) { - zend_class_entry *ce = ZEND_TYPE_CE_CACHE(type); + zend_string *name = ZEND_TYPE_NAME(type); + + if (ZSTR_HAS_CE_CACHE(name) + && ZSTR_GET_CE_CACHE(name)) { + zend_class_entry *ce = ZSTR_GET_CE_CACHE(name); if (ce->ce_flags & ZEND_ACC_ANON_CLASS) { str = zend_string_init(ZSTR_VAL(ce->name), strlen(ZSTR_VAL(ce->name)), 0); } else { str = zend_string_copy(ce->name); } } else { - str = resolve_class_name(ZEND_TYPE_NAME(type), scope); + str = resolve_class_name(name, scope); } } else if (ZEND_TYPE_HAS_CE(type)) { str = zend_string_copy(ZEND_TYPE_CE(type)->name); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 88593e3a5cc..ee4ee4df45d 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -852,24 +852,25 @@ static bool zend_check_and_resolve_property_class_type( zend_type *list_type; ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(info->type), list_type) { if (ZEND_TYPE_HAS_NAME(*list_type)) { - if (ZEND_TYPE_HAS_CE_CACHE(*list_type)) { - ce = ZEND_TYPE_CE_CACHE(*list_type); + zend_string *name = ZEND_TYPE_NAME(*list_type); + + if (ZSTR_HAS_CE_CACHE(name)) { + ce = ZSTR_GET_CE_CACHE(name); if (!ce) { - zend_string *name = ZEND_TYPE_NAME(*list_type); - ce = resolve_single_class_type(name, info->ce); + ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD); if (UNEXPECTED(!ce)) { continue; } - ZEND_TYPE_SET_CE_CACHE(*list_type, ce); } } else { - zend_string *name = ZEND_TYPE_NAME(*list_type); ce = resolve_single_class_type(name, info->ce); if (!ce) { continue; } - zend_string_release(name); - ZEND_TYPE_SET_CE(*list_type, ce); + if (!(info->ce->ce_flags & ZEND_ACC_IMMUTABLE)) { + zend_string_release(name); + ZEND_TYPE_SET_CE(*list_type, ce); + } } } else { ce = ZEND_TYPE_CE(*list_type); @@ -881,25 +882,25 @@ static bool zend_check_and_resolve_property_class_type( return 0; } else { if (UNEXPECTED(ZEND_TYPE_HAS_NAME(info->type))) { - if (ZEND_TYPE_HAS_CE_CACHE(info->type)) { - ce = ZEND_TYPE_CE_CACHE(info->type); + zend_string *name = ZEND_TYPE_NAME(info->type); + + if (ZSTR_HAS_CE_CACHE(name)) { + ce = ZSTR_GET_CE_CACHE(name); if (!ce) { - zend_string *name = ZEND_TYPE_NAME(info->type); - ce = resolve_single_class_type(name, info->ce); + ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD); if (UNEXPECTED(!ce)) { return 0; } - ZEND_TYPE_SET_CE_CACHE(info->type, ce); } } else { - zend_string *name = ZEND_TYPE_NAME(info->type); ce = resolve_single_class_type(name, info->ce); if (UNEXPECTED(!ce)) { return 0; } - - zend_string_release(name); - ZEND_TYPE_SET_CE(info->type, ce); + if (!(info->ce->ce_flags & ZEND_ACC_IMMUTABLE)) { + zend_string_release(name); + ZEND_TYPE_SET_CE(info->type, ce); + } } } else { ce = ZEND_TYPE_CE(info->type); @@ -989,26 +990,33 @@ static zend_always_inline bool zend_check_type_slow( ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) { if (HAVE_CACHE_SLOT && *cache_slot) { ce = *cache_slot; - } else if (ZEND_TYPE_HAS_CE_CACHE(*list_type) && ZEND_TYPE_CE_CACHE(*list_type)) { - ce = ZEND_TYPE_CE_CACHE(*list_type); - if (HAVE_CACHE_SLOT) { - *cache_slot = ce; - } } else { - ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type), - ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT); - if (!ce) { - if (HAVE_CACHE_SLOT) { - cache_slot++; + zend_string *name = ZEND_TYPE_NAME(*list_type); + + if (ZSTR_HAS_CE_CACHE(name)) { + ce = ZSTR_GET_CE_CACHE(name); + if (!ce) { + ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD); + if (!ce) { + if (HAVE_CACHE_SLOT) { + cache_slot++; + } + continue; + } + } + } else { + ce = zend_fetch_class(name, + ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT); + if (!ce) { + if (HAVE_CACHE_SLOT) { + cache_slot++; + } + continue; } - continue; } if (HAVE_CACHE_SLOT) { *cache_slot = ce; } - if (ZEND_TYPE_HAS_CE_CACHE(*list_type)) { - ZEND_TYPE_SET_CE_CACHE(*list_type, ce); - } } if (instanceof_function(Z_OBJCE_P(arg), ce)) { return 1; @@ -1020,23 +1028,27 @@ static zend_always_inline bool zend_check_type_slow( } else { if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) { ce = (zend_class_entry *) *cache_slot; - } else if (ZEND_TYPE_HAS_CE_CACHE(*type) && ZEND_TYPE_CE_CACHE(*type)) { - ce = ZEND_TYPE_CE_CACHE(*type); - if (HAVE_CACHE_SLOT) { - *cache_slot = ce; - } } else { - ce = zend_fetch_class(ZEND_TYPE_NAME(*type), - ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT); - if (UNEXPECTED(!ce)) { - goto builtin_types; + zend_string *name = ZEND_TYPE_NAME(*type); + + if (ZSTR_HAS_CE_CACHE(name)) { + ce = ZSTR_GET_CE_CACHE(name); + if (!ce) { + ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD); + if (UNEXPECTED(!ce)) { + goto builtin_types; + } + } + } else { + ce = zend_fetch_class(name, + ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT); + if (UNEXPECTED(!ce)) { + goto builtin_types; + } } if (HAVE_CACHE_SLOT) { *cache_slot = (void *) ce; } - if (ZEND_TYPE_HAS_CE_CACHE(*type)) { - ZEND_TYPE_SET_CE_CACHE(*type, ce); - } } if (instanceof_function(Z_OBJCE_P(arg), ce)) { return 1; diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index af3c8cc6704..854d8030209 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1054,6 +1054,13 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * zend_string *lc_name; zend_string *autoload_name; + if (ZSTR_HAS_CE_CACHE(name)) { + ce = ZSTR_GET_CE_CACHE(name); + if (ce) { + return ce; + } + } + if (key) { lc_name = key; } else { @@ -1092,6 +1099,9 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * } return NULL; } + if (ZSTR_HAS_CE_CACHE(name)) { + ZSTR_SET_CE_CACHE(name, ce); + } return ce; } @@ -1144,6 +1154,11 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * if (!key) { zend_string_release_ex(lc_name, 0); } + if (ce) { + if (ZSTR_HAS_CE_CACHE(name)) { + ZSTR_SET_CE_CACHE(name, ce); + } + } return ce; } /* }}} */ diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 2efdf38092e..dff25db31d6 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -2682,6 +2682,9 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string } zv = zend_hash_find_ex(CG(class_table), key, 1); Z_CE_P(zv) = ret; + if (ZSTR_HAS_CE_CACHE(ret->name)) { + ZSTR_SET_CE_CACHE(ret->name, ret); + } return ret; } } else { @@ -2803,6 +2806,10 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string free_alloca(traits_and_interfaces, use_heap); } + if (ZSTR_HAS_CE_CACHE(ce->name)) { + ZSTR_SET_CE_CACHE(ce->name, ce); + } + return ce; } /* }}} */ @@ -2875,6 +2882,9 @@ zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *pa return NULL; } } + if (ZSTR_HAS_CE_CACHE(ret->name)) { + ZSTR_SET_CE_CACHE(ret->name, ret); + } return ret; } } else { @@ -2942,6 +2952,10 @@ zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *pa } } + if (ZSTR_HAS_CE_CACHE(ce->name)) { + ZSTR_SET_CE_CACHE(ce->name, ce); + } + return ce; } return NULL; diff --git a/Zend/zend_map_ptr.h b/Zend/zend_map_ptr.h index c014f225a3a..5e039267bd1 100644 --- a/Zend/zend_map_ptr.h +++ b/Zend/zend_map_ptr.h @@ -55,8 +55,8 @@ # define ZEND_MAP_PTR_SET_REAL_BASE(base, ptr) do { \ base = (ptr); \ } while (0) -# define ZEND_MAP_PTR_OFFSET2PTR(ptr) \ - ((void**)((char*)CG(map_ptr_base) + (uintptr_t)ZEND_MAP_PTR(ptr))) +# define ZEND_MAP_PTR_OFFSET2PTR(offset) \ + ((void**)((char*)CG(map_ptr_base) + offset)) #elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET # define ZEND_MAP_PTR(ptr) \ ptr ## __ptr @@ -64,25 +64,25 @@ type * ZEND_MAP_PTR(name) # define ZEND_MAP_PTR_IS_OFFSET(ptr) \ (((uintptr_t)ZEND_MAP_PTR(ptr)) & 1L) -# define ZEND_MAP_PTR_OFFSET2PTR(ptr) \ - ((void**)((char*)CG(map_ptr_base) + (uintptr_t)ZEND_MAP_PTR(ptr))) +# define ZEND_MAP_PTR_OFFSET2PTR(offset) \ + ((void**)((char*)CG(map_ptr_base) + offset)) # define ZEND_MAP_PTR_PTR2OFFSET(ptr) \ ((void*)(((char*)(ptr)) - ((char*)CG(map_ptr_base)))) # define ZEND_MAP_PTR_GET(ptr) \ (*(ZEND_MAP_PTR_IS_OFFSET(ptr) ? \ - ZEND_MAP_PTR_OFFSET2PTR(ptr) : \ + ZEND_MAP_PTR_OFFSET2PTR((uintptr_t)ZEND_MAP_PTR(ptr)) : \ ((void**)(ZEND_MAP_PTR(ptr))))) # define ZEND_MAP_PTR_GET_IMM(ptr) \ - (*ZEND_MAP_PTR_OFFSET2PTR(ptr)) + (*ZEND_MAP_PTR_OFFSET2PTR((uintptr_t)ZEND_MAP_PTR(ptr))) # define ZEND_MAP_PTR_SET(ptr, val) do { \ void **__p = (void**)(ZEND_MAP_PTR(ptr)); \ if (ZEND_MAP_PTR_IS_OFFSET(ptr)) { \ - __p = ZEND_MAP_PTR_OFFSET2PTR(ptr); \ + __p = ZEND_MAP_PTR_OFFSET2PTR((uintptr_t)ZEND_MAP_PTR(ptr)); \ } \ *__p = (val); \ } while (0) # define ZEND_MAP_PTR_SET_IMM(ptr, val) do { \ - void **__p = ZEND_MAP_PTR_OFFSET2PTR(ptr); \ + void **__p = ZEND_MAP_PTR_OFFSET2PTR((uintptr_t)ZEND_MAP_PTR(ptr)); \ *__p = (val); \ } while (0) # define ZEND_MAP_PTR_INIT(ptr, val) do { \ diff --git a/Zend/zend_types.h b/Zend/zend_types.h index dbe2df23dee..958eaa31dd4 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -130,7 +130,7 @@ typedef struct { * are only supported since C++20). */ void *ptr; uint32_t type_mask; - uint32_t ce_cache__ptr; /* map_ptr offset */ + /* TODO: We could use the extra 32-bit of padding on 64-bit systems. */ } zend_type; typedef struct { @@ -145,8 +145,7 @@ typedef struct { #define _ZEND_TYPE_CE_BIT (1u << 23) #define _ZEND_TYPE_LIST_BIT (1u << 22) #define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_CE_BIT|_ZEND_TYPE_NAME_BIT) -/* CE cached in map_ptr area */ -#define _ZEND_TYPE_CACHE_BIT (1u << 21) +/* TODO: bit 21 is not used */ /* Whether the type list is arena allocated */ #define _ZEND_TYPE_ARENA_BIT (1u << 20) /* Type mask excluding the flags above. */ @@ -169,9 +168,6 @@ typedef struct { #define ZEND_TYPE_HAS_LIST(t) \ ((((t).type_mask) & _ZEND_TYPE_LIST_BIT) != 0) -#define ZEND_TYPE_HAS_CE_CACHE(t) \ - ((((t).type_mask) & _ZEND_TYPE_CACHE_BIT) != 0) - #define ZEND_TYPE_USES_ARENA(t) \ ((((t).type_mask) & _ZEND_TYPE_ARENA_BIT) != 0) @@ -190,13 +186,6 @@ typedef struct { #define ZEND_TYPE_LIST(t) \ ((zend_type_list *) (t).ptr) -#define ZEND_TYPE_CE_CACHE(t) \ - (*(zend_class_entry **)ZEND_MAP_PTR_OFFSET2PTR((t).ce_cache)) - -#define ZEND_TYPE_SET_CE_CACHE(t, ce) do { \ - *((zend_class_entry **)ZEND_MAP_PTR_OFFSET2PTR((t).ce_cache)) = ce; \ - } while (0) - #define ZEND_TYPE_LIST_SIZE(num_types) \ (sizeof(zend_type_list) + ((num_types) - 1) * sizeof(zend_type)) @@ -266,10 +255,10 @@ typedef struct { (((t).type_mask & _ZEND_TYPE_NULLABLE_BIT) != 0) #define ZEND_TYPE_INIT_NONE(extra_flags) \ - { NULL, (extra_flags), 0 } + { NULL, (extra_flags) } #define ZEND_TYPE_INIT_MASK(_type_mask) \ - { NULL, (_type_mask), 0 } + { NULL, (_type_mask) } #define ZEND_TYPE_INIT_CODE(code, allow_null, extra_flags) \ ZEND_TYPE_INIT_MASK(((code) == _IS_BOOL ? MAY_BE_BOOL : ((code) == IS_MIXED ? MAY_BE_ANY : (1 << (code)))) \ @@ -277,10 +266,10 @@ typedef struct { #define ZEND_TYPE_INIT_PTR(ptr, type_kind, allow_null, extra_flags) \ { (void *) (ptr), \ - (type_kind) | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags), 0 } + (type_kind) | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags) } #define ZEND_TYPE_INIT_PTR_MASK(ptr, type_mask) \ - { (void *) (ptr), (type_mask), 0 } + { (void *) (ptr), (type_mask) } #define ZEND_TYPE_INIT_CE(_ce, allow_null, extra_flags) \ ZEND_TYPE_INIT_PTR(_ce, _ZEND_TYPE_CE_BIT, allow_null, extra_flags) @@ -707,6 +696,7 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #define IS_CONSTANT_AST_EX (IS_CONSTANT_AST | (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) /* string flags (zval.value->gc.u.flags) */ +#define IS_STR_CLASS_NAME_MAP_PTR GC_PROTECTED /* refcount is a map_ptr offset of class_entry */ #define IS_STR_INTERNED GC_IMMUTABLE /* interned string */ #define IS_STR_PERSISTENT GC_PERSISTENT /* allocated using malloc */ #define IS_STR_PERMANENT (1<<8) /* relives request boundary */ @@ -723,6 +713,14 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #define OBJ_FLAGS(obj) GC_FLAGS(obj) +/* Fast class cache */ +#define ZSTR_HAS_CE_CACHE(s) (GC_FLAGS(s) & IS_STR_CLASS_NAME_MAP_PTR) +#define ZSTR_GET_CE_CACHE(s) \ + (*(zend_class_entry **)ZEND_MAP_PTR_OFFSET2PTR(GC_REFCOUNT(s))) +#define ZSTR_SET_CE_CACHE(s, ce) do { \ + *((zend_class_entry **)ZEND_MAP_PTR_OFFSET2PTR(GC_REFCOUNT(s))) = ce; \ + } while (0) + /* Recursion protection macros must be used only for arrays and objects */ #define GC_IS_RECURSIVE(p) \ (GC_FLAGS(p) & GC_PROTECTED) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 547272820a6..0e460d8af82 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -742,6 +742,20 @@ static zend_string* ZEND_FASTCALL accel_replace_string_by_shm_permanent(zend_str return str; } +static void accel_allocate_ce_cache_slots(void) +{ + Bucket *p; + + ZEND_HASH_FOREACH_BUCKET(CG(class_table), p) { + zend_class_entry *ce; + + ce = (zend_class_entry*)Z_PTR(p->val); + if (ce->name) { + zend_accel_get_class_name_map_ptr(ce->name, ce); + } + } ZEND_HASH_FOREACH_END(); +} + static void accel_use_shm_interned_strings(void) { HANDLE_BLOCK_INTERRUPTIONS(); @@ -750,6 +764,7 @@ static void accel_use_shm_interned_strings(void) if (ZCSG(interned_strings).saved_top == NULL) { accel_copy_permanent_strings(accel_new_interned_string); + accel_allocate_ce_cache_slots(); } else { ZCG(counted) = 1; accel_copy_permanent_strings(accel_replace_string_by_shm_permanent); diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index fab1b716666..091c1b22940 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -329,7 +329,7 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type); zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str); -uint32_t zend_accel_get_type_map_ptr(zend_string *type_name, zend_class_entry *scope); +uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name, zend_class_entry *scope); /* memory write protection */ #define SHM_PROTECT() \ diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 4b59545b312..9ed28ed3e2b 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1349,20 +1349,27 @@ static zend_always_inline bool zend_jit_verify_type_common(zval *arg, zend_arg_i ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(arg_info->type), list_type) { if (*cache_slot) { ce = *cache_slot; - } else if (ZEND_TYPE_HAS_CE_CACHE(*list_type) && ZEND_TYPE_CE_CACHE(*list_type)) { - ce = ZEND_TYPE_CE_CACHE(*list_type); - *cache_slot = ce; } else { - ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type), - ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT); - if (!ce) { - cache_slot++; - continue; + zend_string *name = ZEND_TYPE_NAME(*list_type); + + if (ZSTR_HAS_CE_CACHE(name)) { + ce = ZSTR_GET_CE_CACHE(name); + if (!ce) { + ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD); + if (!ce) { + cache_slot++; + continue; + } + } + } else { + ce = zend_fetch_class(name, + ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT); + if (!ce) { + cache_slot++; + continue; + } } *cache_slot = ce; - if (ZEND_TYPE_HAS_CE_CACHE(*list_type)) { - ZEND_TYPE_SET_CE_CACHE(*list_type, ce); - } } if (instanceof_function(Z_OBJCE_P(arg), ce)) { return 1; @@ -1372,19 +1379,25 @@ static zend_always_inline bool zend_jit_verify_type_common(zval *arg, zend_arg_i } else { if (EXPECTED(*cache_slot)) { ce = (zend_class_entry *) *cache_slot; - } else if (ZEND_TYPE_HAS_CE_CACHE(arg_info->type) && ZEND_TYPE_CE_CACHE(arg_info->type)) { - ce = ZEND_TYPE_CE_CACHE(arg_info->type); - *cache_slot = ce; } else { - ce = zend_fetch_class(ZEND_TYPE_NAME(arg_info->type), - ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT); - if (UNEXPECTED(!ce)) { - goto builtin_types; + zend_string *name = ZEND_TYPE_NAME(arg_info->type); + + if (ZSTR_HAS_CE_CACHE(name)) { + ce = ZSTR_GET_CE_CACHE(name); + if (!ce) { + ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD); + if (UNEXPECTED(!ce)) { + goto builtin_types; + } + } + } else { + ce = zend_fetch_class(name, + ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT); + if (UNEXPECTED(!ce)) { + goto builtin_types; + } } *cache_slot = (void *) ce; - if (ZEND_TYPE_HAS_CE_CACHE(arg_info->type)) { - ZEND_TYPE_SET_CE_CACHE(arg_info->type, ce); - } } if (instanceof_function(Z_OBJCE_P(arg), ce)) { return 1; diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 835ec5ac152..2b2f4b23a3c 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -1230,17 +1230,8 @@ static void zend_file_cache_unserialize_type( zend_string *type_name = ZEND_TYPE_NAME(*type); UNSERIALIZE_STR(type_name); ZEND_TYPE_SET_PTR(*type, type_name); - if (!(script->corrupted)) { - uint32_t ptr = zend_accel_get_type_map_ptr(type_name, scope); - - if (ptr) { - type->type_mask |= _ZEND_TYPE_CACHE_BIT; - type->ce_cache__ptr = ptr; - } else { - type->type_mask &= ~_ZEND_TYPE_CACHE_BIT; - } - } else { - type->type_mask &= ~_ZEND_TYPE_CACHE_BIT; + if (!script->corrupted) { + zend_accel_get_class_name_map_ptr(type_name, scope); } } else if (ZEND_TYPE_HAS_CE(*type)) { zend_class_entry *ce = ZEND_TYPE_CE(*type); @@ -1504,6 +1495,10 @@ static void zend_file_cache_unserialize_class(zval *zv, ce = Z_PTR_P(zv); UNSERIALIZE_STR(ce->name); + if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS) + && !script->corrupted) { + zend_accel_get_class_name_map_ptr(ce->name, ce); + } if (ce->parent) { if (!(ce->ce_flags & ZEND_ACC_LINKED)) { UNSERIALIZE_STR(ce->parent_name); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 52d961c4288..4216f0446cc 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -292,7 +292,7 @@ static HashTable *zend_persist_attributes(HashTable *attributes) return ptr; } -uint32_t zend_accel_get_type_map_ptr(zend_string *type_name, zend_class_entry *scope) +uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name, zend_class_entry *scope) { uint32_t ret; @@ -312,18 +312,22 @@ uint32_t zend_accel_get_type_map_ptr(zend_string *type_name, zend_class_entry *s } } - ZEND_ASSERT(GC_FLAGS(type_name) & GC_IMMUTABLE); - ZEND_ASSERT(GC_FLAGS(type_name) & IS_STR_PERMANENT); - ret = GC_REFCOUNT(type_name); - /* We use type.name.gc.refcount to keep map_ptr of corresponding type */ - if (ret <= 2) { + if (ZSTR_HAS_CE_CACHE(type_name)) { + return GC_REFCOUNT(type_name); + } + + if ((GC_FLAGS(type_name) & GC_IMMUTABLE) + && (GC_FLAGS(type_name) & IS_STR_PERMANENT)) { do { ret = (uint32_t)(uintptr_t)zend_map_ptr_new(); } while (ret <= 2); + GC_ADD_FLAGS(type_name, IS_STR_CLASS_NAME_MAP_PTR); GC_SET_REFCOUNT(type_name, ret); + return ret; } - return ret; + + return 0; } static HashTable *zend_persist_backed_enum_table(HashTable *backed_enum_table) @@ -365,12 +369,7 @@ static void zend_persist_type(zend_type *type, zend_class_entry *scope) { zend_accel_store_interned_string(type_name); ZEND_TYPE_SET_PTR(*single_type, type_name); if (!ZCG(current_persistent_script)->corrupted) { - uint32_t ptr = zend_accel_get_type_map_ptr(type_name, scope); - - if (ptr) { - single_type->type_mask |= _ZEND_TYPE_CACHE_BIT; - single_type->ce_cache__ptr = ptr; - } + zend_accel_get_class_name_map_ptr(type_name, scope); } } } ZEND_TYPE_FOREACH_END(); @@ -882,6 +881,14 @@ zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce) if (!(ce->ce_flags & ZEND_ACC_CACHED)) { zend_accel_store_interned_string(ce->name); + if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS) + && !ZCG(current_persistent_script)->corrupted) { + if (ZSTR_HAS_CE_CACHE(ce->name)) { + ZSTR_SET_CE_CACHE(ce->name, NULL); + } else { + zend_accel_get_class_name_map_ptr(ce->name, ce); + } + } if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) { zend_accel_store_interned_string(ce->parent_name); } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index a2ffaa34f12..0e14f225708 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2993,13 +2993,14 @@ ZEND_METHOD(ReflectionUnionType, getTypes) append_type(return_value, *list_type); } ZEND_TYPE_LIST_FOREACH_END(); } else if (ZEND_TYPE_HAS_NAME(param->type)) { - if (ZEND_TYPE_HAS_CE_CACHE(param->type) - && ZEND_TYPE_CE_CACHE(param->type)) { - append_type(return_value, - (zend_type) ZEND_TYPE_INIT_CE(ZEND_TYPE_CE_CACHE(param->type), 0, 0)); - } else { - append_type(return_value, - (zend_type) ZEND_TYPE_INIT_CLASS(ZEND_TYPE_NAME(param->type), 0, 0)); + zend_string *name = ZEND_TYPE_NAME(param->type); + + if (ZSTR_HAS_CE_CACHE(name) && ZSTR_GET_CE_CACHE(name)) { + append_type(return_value, + (zend_type) ZEND_TYPE_INIT_CE(ZSTR_GET_CE_CACHE(name), 0, 0)); + } else { + append_type(return_value, + (zend_type) ZEND_TYPE_INIT_CLASS(name, 0, 0)); } } else if (ZEND_TYPE_HAS_CE(param->type)) { append_type(return_value,