Skip to content

Commit d8e4fba

Browse files
committed
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).
1 parent ad4b928 commit d8e4fba

16 files changed

+216
-135
lines changed

Zend/tests/return_types/inheritance001.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ class A {
88
}
99

1010
class B extends A {
11-
function foo(): StdClass {}
11+
function foo(): stdClass {}
1212
}
1313
?>
1414
--EXPECTF--
15-
Fatal error: Declaration of B::foo(): StdClass must be compatible with A::foo(): A in %s on line %d
15+
Fatal error: Declaration of B::foo(): stdClass must be compatible with A::foo(): A in %s on line %d

Zend/tests/return_types/inheritance002.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ abstract class A {
88
}
99

1010
class B extends A {
11-
function foo(): StdClass {}
11+
function foo(): stdClass {}
1212
}
1313
?>
1414
--EXPECTF--
15-
Fatal error: Declaration of B::foo(): StdClass must be compatible with A::foo(): A in %s on line %d
15+
Fatal error: Declaration of B::foo(): stdClass must be compatible with A::foo(): A in %s on line %d

Zend/tests/return_types/inheritance003.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ interface A {
88
}
99

1010
class B implements A {
11-
function foo(): StdClass {}
11+
function foo(): stdClass {}
1212
}
1313
?>
1414
--EXPECTF--
15-
Fatal error: Declaration of B::foo(): StdClass must be compatible with A::foo(): A in %s on line %d
15+
Fatal error: Declaration of B::foo(): stdClass must be compatible with A::foo(): A in %s on line %d

Zend/zend_builtin_functions.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,13 @@ static inline void class_exists_impl(INTERNAL_FUNCTION_PARAMETERS, int flags, in
995995
Z_PARAM_BOOL(autoload)
996996
ZEND_PARSE_PARAMETERS_END();
997997

998+
if (ZSTR_HAS_CE_CACHE(name)) {
999+
ce = ZSTR_GET_CE_CACHE(name);
1000+
if (ce) {
1001+
RETURN_BOOL(((ce->ce_flags & flags) == flags) && !(ce->ce_flags & skip_flags));
1002+
}
1003+
}
1004+
9981005
if (!autoload) {
9991006
if (ZSTR_VAL(name)[0] == '\\') {
10001007
/* Ignore leading "\" */

Zend/zend_compile.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,33 +1197,37 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
11971197
if (ZEND_TYPE_HAS_CE(*list_type)) {
11981198
str = add_type_string(str, ZEND_TYPE_CE(*list_type)->name);
11991199
} else {
1200-
if (ZEND_TYPE_HAS_CE_CACHE(*list_type)
1201-
&& ZEND_TYPE_CE_CACHE(*list_type)) {
1202-
zend_class_entry *ce = ZEND_TYPE_CE_CACHE(*list_type);
1200+
zend_string *name = ZEND_TYPE_NAME(*list_type);
1201+
1202+
if (ZSTR_HAS_CE_CACHE(name)
1203+
&& ZSTR_GET_CE_CACHE(name)) {
1204+
zend_class_entry *ce = ZSTR_GET_CE_CACHE(name);
12031205
if (ce->ce_flags & ZEND_ACC_ANON_CLASS) {
12041206
zend_string *tmp = zend_string_init(ZSTR_VAL(ce->name), strlen(ZSTR_VAL(ce->name)), 0);
12051207
str = add_type_string(str, tmp);
12061208
} else {
12071209
str = add_type_string(str, ce->name);
12081210
}
12091211
} else {
1210-
zend_string *resolved = resolve_class_name(ZEND_TYPE_NAME(*list_type), scope);
1212+
zend_string *resolved = resolve_class_name(name, scope);
12111213
str = add_type_string(str, resolved);
12121214
zend_string_release(resolved);
12131215
}
12141216
}
12151217
} ZEND_TYPE_LIST_FOREACH_END();
12161218
} else if (ZEND_TYPE_HAS_NAME(type)) {
1217-
if (ZEND_TYPE_HAS_CE_CACHE(type)
1218-
&& ZEND_TYPE_CE_CACHE(type)) {
1219-
zend_class_entry *ce = ZEND_TYPE_CE_CACHE(type);
1219+
zend_string *name = ZEND_TYPE_NAME(type);
1220+
1221+
if (ZSTR_HAS_CE_CACHE(name)
1222+
&& ZSTR_GET_CE_CACHE(name)) {
1223+
zend_class_entry *ce = ZSTR_GET_CE_CACHE(name);
12201224
if (ce->ce_flags & ZEND_ACC_ANON_CLASS) {
12211225
str = zend_string_init(ZSTR_VAL(ce->name), strlen(ZSTR_VAL(ce->name)), 0);
12221226
} else {
12231227
str = zend_string_copy(ce->name);
12241228
}
12251229
} else {
1226-
str = resolve_class_name(ZEND_TYPE_NAME(type), scope);
1230+
str = resolve_class_name(name, scope);
12271231
}
12281232
} else if (ZEND_TYPE_HAS_CE(type)) {
12291233
str = zend_string_copy(ZEND_TYPE_CE(type)->name);

Zend/zend_execute.c

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -852,24 +852,25 @@ static bool zend_check_and_resolve_property_class_type(
852852
zend_type *list_type;
853853
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(info->type), list_type) {
854854
if (ZEND_TYPE_HAS_NAME(*list_type)) {
855-
if (ZEND_TYPE_HAS_CE_CACHE(*list_type)) {
856-
ce = ZEND_TYPE_CE_CACHE(*list_type);
855+
zend_string *name = ZEND_TYPE_NAME(*list_type);
856+
857+
if (ZSTR_HAS_CE_CACHE(name)) {
858+
ce = ZSTR_GET_CE_CACHE(name);
857859
if (!ce) {
858-
zend_string *name = ZEND_TYPE_NAME(*list_type);
859-
ce = resolve_single_class_type(name, info->ce);
860+
ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
860861
if (UNEXPECTED(!ce)) {
861862
continue;
862863
}
863-
ZEND_TYPE_SET_CE_CACHE(*list_type, ce);
864864
}
865865
} else {
866-
zend_string *name = ZEND_TYPE_NAME(*list_type);
867866
ce = resolve_single_class_type(name, info->ce);
868867
if (!ce) {
869868
continue;
870869
}
871-
zend_string_release(name);
872-
ZEND_TYPE_SET_CE(*list_type, ce);
870+
if (!(info->ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
871+
zend_string_release(name);
872+
ZEND_TYPE_SET_CE(*list_type, ce);
873+
}
873874
}
874875
} else {
875876
ce = ZEND_TYPE_CE(*list_type);
@@ -881,25 +882,25 @@ static bool zend_check_and_resolve_property_class_type(
881882
return 0;
882883
} else {
883884
if (UNEXPECTED(ZEND_TYPE_HAS_NAME(info->type))) {
884-
if (ZEND_TYPE_HAS_CE_CACHE(info->type)) {
885-
ce = ZEND_TYPE_CE_CACHE(info->type);
885+
zend_string *name = ZEND_TYPE_NAME(info->type);
886+
887+
if (ZSTR_HAS_CE_CACHE(name)) {
888+
ce = ZSTR_GET_CE_CACHE(name);
886889
if (!ce) {
887-
zend_string *name = ZEND_TYPE_NAME(info->type);
888-
ce = resolve_single_class_type(name, info->ce);
890+
ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
889891
if (UNEXPECTED(!ce)) {
890892
return 0;
891893
}
892-
ZEND_TYPE_SET_CE_CACHE(info->type, ce);
893894
}
894895
} else {
895-
zend_string *name = ZEND_TYPE_NAME(info->type);
896896
ce = resolve_single_class_type(name, info->ce);
897897
if (UNEXPECTED(!ce)) {
898898
return 0;
899899
}
900-
901-
zend_string_release(name);
902-
ZEND_TYPE_SET_CE(info->type, ce);
900+
if (!(info->ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
901+
zend_string_release(name);
902+
ZEND_TYPE_SET_CE(info->type, ce);
903+
}
903904
}
904905
} else {
905906
ce = ZEND_TYPE_CE(info->type);
@@ -989,26 +990,33 @@ static zend_always_inline bool zend_check_type_slow(
989990
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) {
990991
if (HAVE_CACHE_SLOT && *cache_slot) {
991992
ce = *cache_slot;
992-
} else if (ZEND_TYPE_HAS_CE_CACHE(*list_type) && ZEND_TYPE_CE_CACHE(*list_type)) {
993-
ce = ZEND_TYPE_CE_CACHE(*list_type);
994-
if (HAVE_CACHE_SLOT) {
995-
*cache_slot = ce;
996-
}
997993
} else {
998-
ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type),
999-
ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT);
1000-
if (!ce) {
1001-
if (HAVE_CACHE_SLOT) {
1002-
cache_slot++;
994+
zend_string *name = ZEND_TYPE_NAME(*list_type);
995+
996+
if (ZSTR_HAS_CE_CACHE(name)) {
997+
ce = ZSTR_GET_CE_CACHE(name);
998+
if (!ce) {
999+
ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
1000+
if (!ce) {
1001+
if (HAVE_CACHE_SLOT) {
1002+
cache_slot++;
1003+
}
1004+
continue;
1005+
}
1006+
}
1007+
} else {
1008+
ce = zend_fetch_class(name,
1009+
ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT);
1010+
if (!ce) {
1011+
if (HAVE_CACHE_SLOT) {
1012+
cache_slot++;
1013+
}
1014+
continue;
10031015
}
1004-
continue;
10051016
}
10061017
if (HAVE_CACHE_SLOT) {
10071018
*cache_slot = ce;
10081019
}
1009-
if (ZEND_TYPE_HAS_CE_CACHE(*list_type)) {
1010-
ZEND_TYPE_SET_CE_CACHE(*list_type, ce);
1011-
}
10121020
}
10131021
if (instanceof_function(Z_OBJCE_P(arg), ce)) {
10141022
return 1;
@@ -1020,23 +1028,27 @@ static zend_always_inline bool zend_check_type_slow(
10201028
} else {
10211029
if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) {
10221030
ce = (zend_class_entry *) *cache_slot;
1023-
} else if (ZEND_TYPE_HAS_CE_CACHE(*type) && ZEND_TYPE_CE_CACHE(*type)) {
1024-
ce = ZEND_TYPE_CE_CACHE(*type);
1025-
if (HAVE_CACHE_SLOT) {
1026-
*cache_slot = ce;
1027-
}
10281031
} else {
1029-
ce = zend_fetch_class(ZEND_TYPE_NAME(*type),
1030-
ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT);
1031-
if (UNEXPECTED(!ce)) {
1032-
goto builtin_types;
1032+
zend_string *name = ZEND_TYPE_NAME(*type);
1033+
1034+
if (ZSTR_HAS_CE_CACHE(name)) {
1035+
ce = ZSTR_GET_CE_CACHE(name);
1036+
if (!ce) {
1037+
ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
1038+
if (UNEXPECTED(!ce)) {
1039+
goto builtin_types;
1040+
}
1041+
}
1042+
} else {
1043+
ce = zend_fetch_class(name,
1044+
ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT);
1045+
if (UNEXPECTED(!ce)) {
1046+
goto builtin_types;
1047+
}
10331048
}
10341049
if (HAVE_CACHE_SLOT) {
10351050
*cache_slot = (void *) ce;
10361051
}
1037-
if (ZEND_TYPE_HAS_CE_CACHE(*type)) {
1038-
ZEND_TYPE_SET_CE_CACHE(*type, ce);
1039-
}
10401052
}
10411053
if (instanceof_function(Z_OBJCE_P(arg), ce)) {
10421054
return 1;

Zend/zend_execute_API.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,13 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
10541054
zend_string *lc_name;
10551055
zend_string *autoload_name;
10561056

1057+
if (ZSTR_HAS_CE_CACHE(name)) {
1058+
ce = ZSTR_GET_CE_CACHE(name);
1059+
if (ce) {
1060+
return ce;
1061+
}
1062+
}
1063+
10571064
if (key) {
10581065
lc_name = key;
10591066
} else {
@@ -1092,6 +1099,9 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
10921099
}
10931100
return NULL;
10941101
}
1102+
if (ZSTR_HAS_CE_CACHE(name)) {
1103+
ZSTR_SET_CE_CACHE(name, ce);
1104+
}
10951105
return ce;
10961106
}
10971107

@@ -1144,6 +1154,11 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
11441154
if (!key) {
11451155
zend_string_release_ex(lc_name, 0);
11461156
}
1157+
if (ce) {
1158+
if (ZSTR_HAS_CE_CACHE(name)) {
1159+
ZSTR_SET_CE_CACHE(name, ce);
1160+
}
1161+
}
11471162
return ce;
11481163
}
11491164
/* }}} */

Zend/zend_inheritance.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2682,6 +2682,9 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
26822682
}
26832683
zv = zend_hash_find_ex(CG(class_table), key, 1);
26842684
Z_CE_P(zv) = ret;
2685+
if (ZSTR_HAS_CE_CACHE(ret->name)) {
2686+
ZSTR_SET_CE_CACHE(ret->name, ret);
2687+
}
26852688
return ret;
26862689
}
26872690
} else {
@@ -2803,6 +2806,10 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
28032806
free_alloca(traits_and_interfaces, use_heap);
28042807
}
28052808

2809+
if (ZSTR_HAS_CE_CACHE(ce->name)) {
2810+
ZSTR_SET_CE_CACHE(ce->name, ce);
2811+
}
2812+
28062813
return ce;
28072814
}
28082815
/* }}} */
@@ -2875,6 +2882,9 @@ zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *pa
28752882
return NULL;
28762883
}
28772884
}
2885+
if (ZSTR_HAS_CE_CACHE(ret->name)) {
2886+
ZSTR_SET_CE_CACHE(ret->name, ret);
2887+
}
28782888
return ret;
28792889
}
28802890
} else {
@@ -2942,6 +2952,10 @@ zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *pa
29422952
}
29432953
}
29442954

2955+
if (ZSTR_HAS_CE_CACHE(ce->name)) {
2956+
ZSTR_SET_CE_CACHE(ce->name, ce);
2957+
}
2958+
29452959
return ce;
29462960
}
29472961
return NULL;

Zend/zend_map_ptr.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,34 +55,34 @@
5555
# define ZEND_MAP_PTR_SET_REAL_BASE(base, ptr) do { \
5656
base = (ptr); \
5757
} while (0)
58-
# define ZEND_MAP_PTR_OFFSET2PTR(ptr) \
59-
((void**)((char*)CG(map_ptr_base) + (uintptr_t)ZEND_MAP_PTR(ptr)))
58+
# define ZEND_MAP_PTR_OFFSET2PTR(offset) \
59+
((void**)((char*)CG(map_ptr_base) + offset))
6060
#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
6161
# define ZEND_MAP_PTR(ptr) \
6262
ptr ## __ptr
6363
# define ZEND_MAP_PTR_DEF(type, name) \
6464
type * ZEND_MAP_PTR(name)
6565
# define ZEND_MAP_PTR_IS_OFFSET(ptr) \
6666
(((uintptr_t)ZEND_MAP_PTR(ptr)) & 1L)
67-
# define ZEND_MAP_PTR_OFFSET2PTR(ptr) \
68-
((void**)((char*)CG(map_ptr_base) + (uintptr_t)ZEND_MAP_PTR(ptr)))
67+
# define ZEND_MAP_PTR_OFFSET2PTR(offset) \
68+
((void**)((char*)CG(map_ptr_base) + offset))
6969
# define ZEND_MAP_PTR_PTR2OFFSET(ptr) \
7070
((void*)(((char*)(ptr)) - ((char*)CG(map_ptr_base))))
7171
# define ZEND_MAP_PTR_GET(ptr) \
7272
(*(ZEND_MAP_PTR_IS_OFFSET(ptr) ? \
73-
ZEND_MAP_PTR_OFFSET2PTR(ptr) : \
73+
ZEND_MAP_PTR_OFFSET2PTR((uintptr_t)ZEND_MAP_PTR(ptr)) : \
7474
((void**)(ZEND_MAP_PTR(ptr)))))
7575
# define ZEND_MAP_PTR_GET_IMM(ptr) \
76-
(*ZEND_MAP_PTR_OFFSET2PTR(ptr))
76+
(*ZEND_MAP_PTR_OFFSET2PTR((uintptr_t)ZEND_MAP_PTR(ptr)))
7777
# define ZEND_MAP_PTR_SET(ptr, val) do { \
7878
void **__p = (void**)(ZEND_MAP_PTR(ptr)); \
7979
if (ZEND_MAP_PTR_IS_OFFSET(ptr)) { \
80-
__p = ZEND_MAP_PTR_OFFSET2PTR(ptr); \
80+
__p = ZEND_MAP_PTR_OFFSET2PTR((uintptr_t)ZEND_MAP_PTR(ptr)); \
8181
} \
8282
*__p = (val); \
8383
} while (0)
8484
# define ZEND_MAP_PTR_SET_IMM(ptr, val) do { \
85-
void **__p = ZEND_MAP_PTR_OFFSET2PTR(ptr); \
85+
void **__p = ZEND_MAP_PTR_OFFSET2PTR((uintptr_t)ZEND_MAP_PTR(ptr)); \
8686
*__p = (val); \
8787
} while (0)
8888
# define ZEND_MAP_PTR_INIT(ptr, val) do { \

0 commit comments

Comments
 (0)