Fast Class Cache

This is generalization of idea, that was previously usesd for caching
resolution of class_entries in zend_type. Now very similar mechanizm is
used for general zend_string into zend_class_entry resolution.

Interned zend_string with IS_STR_CLASS_NAME_MAP_PTR GC_FLAG uses its
refcount to adress corresponding zend_class_entry cache slot.
The refcount keeps an offset to this slot from CG(map_ptr_base).
Flag may be checked by ZSTR_HAS_CE_CACHE(str), cache slot may be read by
ZSTR_GET_CE_CACHE(str) and set by ZSTR_SET_CE_CACHE(str, ce).
This commit is contained in:
Dmitry Stogov 2021-04-08 23:37:40 +03:00
parent ad4b928750
commit d8e4fbae62
16 changed files with 216 additions and 135 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 "\" */

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
/* }}} */

View File

@ -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;

View File

@ -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 { \

View File

@ -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)

View File

@ -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);

View File

@ -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() \

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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,