Skip to content
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

add type hashing #8

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
@@ -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));
@@ -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);
}
/* }}} */

@@ -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;
@@ -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);
}
5 changes: 3 additions & 2 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
@@ -7359,6 +7359,7 @@ static zend_type zend_compile_typename_ex(
}

ast->attr = orig_ast_attr;

return type;
}
/* }}} */
@@ -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
16 changes: 12 additions & 4 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
@@ -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;
@@ -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;
}

@@ -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() */
@@ -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();
@@ -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;
}
}
1 change: 1 addition & 0 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
@@ -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;
2 changes: 2 additions & 0 deletions Zend/zend_globals.h
Original file line number Diff line number Diff line change
@@ -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;

@@ -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;
25 changes: 25 additions & 0 deletions Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
@@ -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;
3 changes: 3 additions & 0 deletions Zend/zend_inheritance.h
Original file line number Diff line number Diff line change
@@ -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);