Skip to content

add type hashing #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,9 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{
zend_hash_init(compiler_globals->class_table, 64, NULL, ZEND_CLASS_DTOR, 1);
zend_hash_copy(compiler_globals->class_table, global_class_table, zend_class_add_ref);

compiler_globals->constraint_cache = (HashTable *) malloc(sizeof(HashTable));
zend_hash_init(compiler_globals->constraint_cache, 64, NULL, NULL, 1);

zend_set_default_compile_time_values();

compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable));
Expand Down Expand Up @@ -794,6 +797,13 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{
pefree(compiler_globals->internal_run_time_cache, 1);
compiler_globals->internal_run_time_cache = NULL;
}
// HashTable *cache;
// ZEND_HASH_FOREACH_PTR(compiler_globals->constraint_cache, cache) {
// zend_hash_destroy(cache);
// free(cache);
// } ZEND_HASH_FOREACH_END();
// zend_hash_destroy(compiler_globals->constraint_cache);
// free(compiler_globals->constraint_cache);
}
/* }}} */

Expand Down Expand Up @@ -1029,6 +1039,7 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */
compiler_globals->in_compilation = 0;
compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable));
compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable));
compiler_globals->constraint_cache = (HashTable *) malloc(sizeof(HashTable));

*compiler_globals->function_table = *GLOBAL_FUNCTION_TABLE;
*compiler_globals->class_table = *GLOBAL_CLASS_TABLE;
Expand Down Expand Up @@ -1124,6 +1135,8 @@ zend_result zend_post_startup(void) /* {{{ */
compiler_globals->function_table = NULL;
free(compiler_globals->class_table);
compiler_globals->class_table = NULL;
free(compiler_globals->constraint_cache);
compiler_globals->constraint_cache = NULL;
if (compiler_globals->map_ptr_real_base) {
free(compiler_globals->map_ptr_real_base);
}
Expand Down
5 changes: 3 additions & 2 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -7359,6 +7359,7 @@ static zend_type zend_compile_typename_ex(
}

ast->attr = orig_ast_attr;

return type;
}
/* }}} */
Expand Down Expand Up @@ -8370,10 +8371,10 @@ static zend_op_array *zend_compile_func_decl_ex(
"nodiscard",
sizeof("nodiscard")-1
);

if (nodiscard_attribute) {
op_array->fn_flags |= ZEND_ACC_NODISCARD;
}
}
}

/* Do not leak the class scope into free standing functions, even if they are dynamically
Expand Down
16 changes: 12 additions & 4 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1140,7 +1140,7 @@ static zend_always_inline zend_class_entry *zend_fetch_ce_from_cache_slot(
return ce;
}

static bool zend_check_intersection_type_from_cache_slot(zend_type_list *intersection_type_list,
static bool zend_check_intersection_type_from_cache_slot(zend_type *original_type, zend_type_list *intersection_type_list,
zend_class_entry *arg_ce, void ***cache_slot_ptr)
{
void **cache_slot = *cache_slot_ptr;
Expand All @@ -1162,6 +1162,9 @@ static bool zend_check_intersection_type_from_cache_slot(zend_type_list *interse
if (HAVE_CACHE_SLOT) {
*cache_slot_ptr = cache_slot;
}
if (status) {
zend_type_satisfied_by_class(original_type, arg_ce);
}
return status;
}

Expand All @@ -1171,15 +1174,18 @@ static zend_always_inline bool zend_check_type_slow(
{
uint32_t type_mask;
if (ZEND_TYPE_IS_COMPLEX(*type) && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
zend_class_entry *ce;
zend_class_entry *ce = Z_OBJCE_P(arg);
if (EXPECTED(zend_type_is_satisfied_by_class(type, ce))) {
return 1;
}
if (UNEXPECTED(ZEND_TYPE_HAS_LIST(*type))) {
zend_type *list_type;
if (ZEND_TYPE_IS_INTERSECTION(*type)) {
return zend_check_intersection_type_from_cache_slot(ZEND_TYPE_LIST(*type), Z_OBJCE_P(arg), &cache_slot);
return zend_check_intersection_type_from_cache_slot(type, ZEND_TYPE_LIST(*type), Z_OBJCE_P(arg), &cache_slot);
} else {
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) {
if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
if (zend_check_intersection_type_from_cache_slot(ZEND_TYPE_LIST(*list_type), Z_OBJCE_P(arg), &cache_slot)) {
if (zend_check_intersection_type_from_cache_slot(type, ZEND_TYPE_LIST(*list_type), Z_OBJCE_P(arg), &cache_slot)) {
return true;
}
/* The cache_slot is progressed in zend_check_intersection_type_from_cache_slot() */
Expand All @@ -1188,6 +1194,7 @@ static zend_always_inline bool zend_check_type_slow(
ce = zend_fetch_ce_from_cache_slot(cache_slot, list_type);
/* Instance of a single type part of a union is sufficient to pass the type check */
if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) {
zend_type_satisfied_by_class(type, ce);
return true;
}
PROGRESS_CACHE_SLOT();
Expand All @@ -1199,6 +1206,7 @@ static zend_always_inline bool zend_check_type_slow(
/* If we have a CE we check if it satisfies the type constraint,
* otherwise it will check if a standard type satisfies it. */
if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) {
zend_type_satisfied_by_class(type, ce);
return true;
}
}
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ void init_executor(void) /* {{{ */

EG(function_table) = CG(function_table);
EG(class_table) = CG(class_table);
EG(constraint_cache) = CG(constraint_cache);

EG(in_autoload) = NULL;
EG(error_handling) = EH_NORMAL;
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ struct _zend_compiler_globals {

HashTable *function_table; /* function symbol table */
HashTable *class_table; /* class table */
HashTable *constraint_cache; /* constraint cache */

HashTable *auto_globals;

Expand Down Expand Up @@ -191,6 +192,7 @@ struct _zend_executor_globals {
HashTable *function_table; /* function symbol table */
HashTable *class_table; /* class table */
HashTable *zend_constants; /* constants table */
HashTable *constraint_cache; /* constraint cache */

zval *vm_stack_top;
zval *vm_stack_end;
Expand Down
25 changes: 25 additions & 0 deletions Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
Expand Up @@ -2194,6 +2194,31 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
}
/* }}} */

ZEND_API void zend_type_satisfied_by_class(const zend_type *type, const zend_class_entry *ce) {
const zend_ulong hash = zend_hash_type(type);
HashTable *constraint = zend_hash_index_find_ptr(EG(constraint_cache), hash);
if (UNEXPECTED(constraint == NULL)) {
constraint = malloc(sizeof(HashTable));
zend_hash_init(constraint, 8, NULL, NULL, 1);
zend_hash_index_add_new_ptr(EG(constraint_cache), hash, constraint);
}
zend_hash_add_empty_element(constraint, ce->name);
}

ZEND_API bool zend_type_is_satisfied_by_class(const zend_type *type, const zend_class_entry *ce) {
const zend_ulong hash = zend_hash_type(type);
const HashTable *constraint = zend_hash_index_find_ptr(EG(constraint_cache), hash);
if (UNEXPECTED(constraint == NULL)) {
return false;
}
return zend_hash_exists(constraint, ce->name);
}

ZEND_API ZEND_FASTCALL zend_ulong zend_hash_type(const zend_type *type) {
const uintptr_t hash = (uintptr_t)type;
return (zend_ulong)hash;
}

ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
{
uint32_t i, ignore = 0;
Expand Down
3 changes: 3 additions & 0 deletions Zend/zend_inheritance.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ BEGIN_EXTERN_C()

ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface);
ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *parent_ce, bool checked);
ZEND_API ZEND_FASTCALL zend_ulong zend_hash_type(const zend_type *type);
ZEND_API bool zend_type_is_satisfied_by_class(const zend_type *type, const zend_class_entry *ce);
ZEND_API void zend_type_satisfied_by_class(const zend_type *type, const zend_class_entry *ce);

static zend_always_inline void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce) {
zend_do_inheritance_ex(ce, parent_ce, 0);
Expand Down
Loading