Skip to content

Commit b275f58

Browse files
committed
add type hashing
1 parent d80682e commit b275f58

File tree

7 files changed

+60
-7
lines changed

7 files changed

+60
-7
lines changed

Zend/zend.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,9 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{
724724
zend_hash_init(compiler_globals->class_table, 64, NULL, ZEND_CLASS_DTOR, 1);
725725
zend_hash_copy(compiler_globals->class_table, global_class_table, zend_class_add_ref);
726726

727+
compiler_globals->constraint_cache = (HashTable *) malloc(sizeof(HashTable));
728+
zend_hash_init(compiler_globals->constraint_cache, 64, NULL, NULL, 1);
729+
727730
zend_set_default_compile_time_values();
728731

729732
compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable));
@@ -794,6 +797,13 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{
794797
pefree(compiler_globals->internal_run_time_cache, 1);
795798
compiler_globals->internal_run_time_cache = NULL;
796799
}
800+
HashTable *cache;
801+
ZEND_HASH_FOREACH_PTR(compiler_globals->constraint_cache, cache) {
802+
zend_hash_destroy(cache);
803+
free(cache);
804+
} ZEND_HASH_FOREACH_END();
805+
zend_hash_destroy(compiler_globals->constraint_cache);
806+
free(compiler_globals->constraint_cache);
797807
}
798808
/* }}} */
799809

@@ -1029,6 +1039,7 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */
10291039
compiler_globals->in_compilation = 0;
10301040
compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable));
10311041
compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable));
1042+
compiler_globals->constraint_cache = (HashTable *) malloc(sizeof(HashTable));
10321043

10331044
*compiler_globals->function_table = *GLOBAL_FUNCTION_TABLE;
10341045
*compiler_globals->class_table = *GLOBAL_CLASS_TABLE;
@@ -1124,6 +1135,8 @@ zend_result zend_post_startup(void) /* {{{ */
11241135
compiler_globals->function_table = NULL;
11251136
free(compiler_globals->class_table);
11261137
compiler_globals->class_table = NULL;
1138+
free(compiler_globals->constraint_cache);
1139+
compiler_globals->constraint_cache = NULL;
11271140
if (compiler_globals->map_ptr_real_base) {
11281141
free(compiler_globals->map_ptr_real_base);
11291142
}

Zend/zend_compile.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7359,6 +7359,7 @@ static zend_type zend_compile_typename_ex(
73597359
}
73607360

73617361
ast->attr = orig_ast_attr;
7362+
73627363
return type;
73637364
}
73647365
/* }}} */
@@ -8370,10 +8371,10 @@ static zend_op_array *zend_compile_func_decl_ex(
83708371
"nodiscard",
83718372
sizeof("nodiscard")-1
83728373
);
8373-
8374+
83748375
if (nodiscard_attribute) {
83758376
op_array->fn_flags |= ZEND_ACC_NODISCARD;
8376-
}
8377+
}
83778378
}
83788379

83798380
/* Do not leak the class scope into free standing functions, even if they are dynamically

Zend/zend_execute.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,11 +1140,11 @@ static zend_always_inline zend_class_entry *zend_fetch_ce_from_cache_slot(
11401140
return ce;
11411141
}
11421142

1143-
static bool zend_check_intersection_type_from_cache_slot(zend_type_list *intersection_type_list,
1143+
static bool zend_check_intersection_type_from_cache_slot(zend_type *original_type, zend_type_list *intersection_type_list,
11441144
zend_class_entry *arg_ce, void ***cache_slot_ptr)
11451145
{
11461146
void **cache_slot = *cache_slot_ptr;
1147-
zend_class_entry *ce;
1147+
zend_class_entry *ce = NULL;
11481148
zend_type *list_type;
11491149
bool status = true;
11501150
ZEND_TYPE_LIST_FOREACH(intersection_type_list, list_type) {
@@ -1162,6 +1162,9 @@ static bool zend_check_intersection_type_from_cache_slot(zend_type_list *interse
11621162
if (HAVE_CACHE_SLOT) {
11631163
*cache_slot_ptr = cache_slot;
11641164
}
1165+
if (status && ce) {
1166+
zend_type_satisfied_by_class(original_type, ce);
1167+
}
11651168
return status;
11661169
}
11671170

@@ -1171,15 +1174,18 @@ static zend_always_inline bool zend_check_type_slow(
11711174
{
11721175
uint32_t type_mask;
11731176
if (ZEND_TYPE_IS_COMPLEX(*type) && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
1174-
zend_class_entry *ce;
1177+
zend_class_entry *ce = Z_OBJCE_P(arg);
1178+
if (EXPECTED(zend_type_is_satisfied_by_class(type, ce))) {
1179+
return 1;
1180+
}
11751181
if (UNEXPECTED(ZEND_TYPE_HAS_LIST(*type))) {
11761182
zend_type *list_type;
11771183
if (ZEND_TYPE_IS_INTERSECTION(*type)) {
1178-
return zend_check_intersection_type_from_cache_slot(ZEND_TYPE_LIST(*type), Z_OBJCE_P(arg), &cache_slot);
1184+
return zend_check_intersection_type_from_cache_slot(type, ZEND_TYPE_LIST(*type), Z_OBJCE_P(arg), &cache_slot);
11791185
} else {
11801186
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) {
11811187
if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
1182-
if (zend_check_intersection_type_from_cache_slot(ZEND_TYPE_LIST(*list_type), Z_OBJCE_P(arg), &cache_slot)) {
1188+
if (zend_check_intersection_type_from_cache_slot(type, ZEND_TYPE_LIST(*list_type), Z_OBJCE_P(arg), &cache_slot)) {
11831189
return true;
11841190
}
11851191
/* The cache_slot is progressed in zend_check_intersection_type_from_cache_slot() */
@@ -1188,6 +1194,7 @@ static zend_always_inline bool zend_check_type_slow(
11881194
ce = zend_fetch_ce_from_cache_slot(cache_slot, list_type);
11891195
/* Instance of a single type part of a union is sufficient to pass the type check */
11901196
if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) {
1197+
zend_type_satisfied_by_class(type, ce);
11911198
return true;
11921199
}
11931200
PROGRESS_CACHE_SLOT();
@@ -1199,6 +1206,7 @@ static zend_always_inline bool zend_check_type_slow(
11991206
/* If we have a CE we check if it satisfies the type constraint,
12001207
* otherwise it will check if a standard type satisfies it. */
12011208
if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) {
1209+
zend_type_satisfied_by_class(type, ce);
12021210
return true;
12031211
}
12041212
}

Zend/zend_execute_API.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ void init_executor(void) /* {{{ */
148148

149149
EG(function_table) = CG(function_table);
150150
EG(class_table) = CG(class_table);
151+
EG(constraint_cache) = CG(constraint_cache);
151152

152153
EG(in_autoload) = NULL;
153154
EG(error_handling) = EH_NORMAL;

Zend/zend_globals.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct _zend_compiler_globals {
9494

9595
HashTable *function_table; /* function symbol table */
9696
HashTable *class_table; /* class table */
97+
HashTable *constraint_cache; /* constraint cache */
9798

9899
HashTable *auto_globals;
99100

@@ -191,6 +192,7 @@ struct _zend_executor_globals {
191192
HashTable *function_table; /* function symbol table */
192193
HashTable *class_table; /* class table */
193194
HashTable *zend_constants; /* constants table */
195+
HashTable *constraint_cache; /* constraint cache */
194196

195197
zval *vm_stack_top;
196198
zval *vm_stack_end;

Zend/zend_inheritance.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,6 +2194,31 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
21942194
}
21952195
/* }}} */
21962196

2197+
ZEND_API void zend_type_satisfied_by_class(const zend_type *type, const zend_class_entry *ce) {
2198+
const zend_ulong hash = zend_hash_type(type);
2199+
HashTable *constraint = zend_hash_index_find_ptr(EG(constraint_cache), hash);
2200+
if (UNEXPECTED(constraint == NULL)) {
2201+
constraint = malloc(sizeof(HashTable));
2202+
zend_hash_init(constraint, 8, NULL, NULL, 1);
2203+
zend_hash_index_add_new_ptr(EG(constraint_cache), hash, constraint);
2204+
}
2205+
zend_hash_add_empty_element(constraint, ce->name);
2206+
}
2207+
2208+
ZEND_API bool zend_type_is_satisfied_by_class(const zend_type *type, const zend_class_entry *ce) {
2209+
const zend_ulong hash = zend_hash_type(type);
2210+
const HashTable *constraint = zend_hash_index_find_ptr(EG(constraint_cache), hash);
2211+
if (UNEXPECTED(constraint == NULL)) {
2212+
return false;
2213+
}
2214+
return zend_hash_exists(constraint, ce->name);
2215+
}
2216+
2217+
ZEND_API ZEND_FASTCALL zend_ulong zend_hash_type(const zend_type *type) {
2218+
const uintptr_t hash = (uintptr_t)type;
2219+
return (zend_ulong)hash;
2220+
}
2221+
21972222
ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
21982223
{
21992224
uint32_t i, ignore = 0;

Zend/zend_inheritance.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ BEGIN_EXTERN_C()
2727

2828
ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface);
2929
ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *parent_ce, bool checked);
30+
ZEND_API ZEND_FASTCALL zend_ulong zend_hash_type(const zend_type *type);
31+
ZEND_API bool zend_type_is_satisfied_by_class(const zend_type *type, const zend_class_entry *ce);
32+
ZEND_API void zend_type_satisfied_by_class(const zend_type *type, const zend_class_entry *ce);
3033

3134
static zend_always_inline void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce) {
3235
zend_do_inheritance_ex(ce, parent_ce, 0);

0 commit comments

Comments
 (0)