mirror of
https://github.com/php/php-src.git
synced 2024-11-23 09:54:15 +08:00
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:
parent
ad4b928750
commit
d8e4fbae62
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 "\" */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -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;
|
||||
|
@ -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 { \
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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() \
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user