-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Always use CE_CACHE, remove TYPE_HAS_CE #7336
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,7 @@ | |
#include "Optimizer/zend_optimizer.h" | ||
|
||
static size_t global_map_ptr_last = 0; | ||
static bool startup_done = false; | ||
|
||
#ifdef ZTS | ||
ZEND_API int compiler_globals_id; | ||
|
@@ -1018,40 +1019,6 @@ void zend_register_standard_ini_entries(void) /* {{{ */ | |
} | ||
/* }}} */ | ||
|
||
static zend_class_entry *resolve_type_name(zend_string *type_name) { | ||
zend_string *lc_type_name = zend_string_tolower(type_name); | ||
zend_class_entry *ce = zend_hash_find_ptr(CG(class_table), lc_type_name); | ||
|
||
ZEND_ASSERT(ce && ce->type == ZEND_INTERNAL_CLASS); | ||
zend_string_release(lc_type_name); | ||
return ce; | ||
} | ||
|
||
static void zend_resolve_property_types(void) /* {{{ */ | ||
{ | ||
zend_class_entry *ce; | ||
zend_property_info *prop_info; | ||
|
||
ZEND_HASH_FOREACH_PTR(CG(class_table), ce) { | ||
if (ce->type != ZEND_INTERNAL_CLASS) { | ||
continue; | ||
} | ||
|
||
if (UNEXPECTED(ZEND_CLASS_HAS_TYPE_HINTS(ce))) { | ||
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) { | ||
zend_type *single_type; | ||
ZEND_TYPE_FOREACH(prop_info->type, single_type) { | ||
if (ZEND_TYPE_HAS_NAME(*single_type)) { | ||
zend_string *type_name = ZEND_TYPE_NAME(*single_type); | ||
ZEND_TYPE_SET_CE(*single_type, resolve_type_name(type_name)); | ||
zend_string_release(type_name); | ||
} | ||
} ZEND_TYPE_FOREACH_END(); | ||
} ZEND_HASH_FOREACH_END(); | ||
} | ||
} ZEND_HASH_FOREACH_END(); | ||
} | ||
/* }}} */ | ||
|
||
/* Unlink the global (r/o) copies of the class, function and constant tables, | ||
* and use a fresh r/w copy for the startup thread | ||
|
@@ -1065,7 +1032,7 @@ zend_result zend_post_startup(void) /* {{{ */ | |
zend_executor_globals *executor_globals = ts_resource(executor_globals_id); | ||
#endif | ||
|
||
zend_resolve_property_types(); | ||
startup_done = true; | ||
|
||
if (zend_post_startup_cb) { | ||
zend_result (*cb)(void) = zend_post_startup_cb; | ||
|
@@ -1164,6 +1131,7 @@ void zend_shutdown(void) /* {{{ */ | |
zend_destroy_rsrc_list_dtors(); | ||
|
||
zend_optimizer_shutdown(); | ||
startup_done = false; | ||
} | ||
/* }}} */ | ||
|
||
|
@@ -1892,3 +1860,29 @@ ZEND_API void zend_map_ptr_extend(size_t last) | |
CG(map_ptr_last) = last; | ||
} | ||
} | ||
|
||
ZEND_API void zend_alloc_ce_cache(zend_string *type_name) | ||
{ | ||
if (ZSTR_HAS_CE_CACHE(type_name) || !ZSTR_IS_INTERNED(type_name)) { | ||
return; | ||
} | ||
|
||
if ((GC_FLAGS(type_name) & IS_STR_PERMANENT) && startup_done) { | ||
/* Don't allocate slot on permanent interned string outside module startup. | ||
* The cache slot would no longer be valid on the next request. */ | ||
return; | ||
} | ||
|
||
if (zend_string_equals_literal_ci(type_name, "self") | ||
|| zend_string_equals_literal_ci(type_name, "parent")) { | ||
Comment on lines
+1876
to
+1877
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may make sense to add |
||
return; | ||
} | ||
|
||
/* We use the refcount to keep map_ptr of corresponding type */ | ||
uint32_t ret; | ||
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); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3053,6 +3053,7 @@ static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class | |
|
||
class_entry->type = ZEND_INTERNAL_CLASS; | ||
zend_initialize_class_data(class_entry, 0); | ||
zend_alloc_ce_cache(class_entry->name); | ||
class_entry->ce_flags = orig_class_entry->ce_flags | ce_flags | ZEND_ACC_CONSTANTS_UPDATED | ZEND_ACC_LINKED | ZEND_ACC_RESOLVED_PARENT | ZEND_ACC_RESOLVED_INTERFACES; | ||
class_entry->info.internal.module = EG(current_module); | ||
|
||
|
@@ -4126,6 +4127,17 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z | |
property_info->ce = ce; | ||
property_info->type = type; | ||
|
||
if (is_persistent_class(ce)) { | ||
zend_type *single_type; | ||
ZEND_TYPE_FOREACH(property_info->type, single_type) { | ||
if (ZEND_TYPE_HAS_NAME(*single_type)) { | ||
zend_string *name = zend_new_interned_string(ZEND_TYPE_NAME(*single_type)); | ||
ZEND_TYPE_SET_PTR(*single_type, name); | ||
zend_alloc_ce_cache(name); | ||
Comment on lines
+4134
to
+4136
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This won't allocate new cache slot for eval()'ed code when opcache active (or when opcache is full). |
||
} | ||
} ZEND_TYPE_FOREACH_END(); | ||
} | ||
|
||
zend_hash_update_ptr(&ce->properties_info, name, property_info); | ||
|
||
return property_info; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means, that we won't allocate CE cache slots during requests if opcache active. Right?
This will affect eval()'ed code, opcache.blacklisted files and situation when opcache is full.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is the key tradeoff with this patch. There are cases where we can't allocate CE_CACHE (eval with opcache, permanent strings during request without opcache), so property types will be uncached (arg types still have separate cache slot).
I didn't have any simple ideas on how to address this. One thought I had is that we could change the map_ptr mechanism to not work using "ptr or offset", but to have two different map_ptr_base for permanent and per-request and always use offset. That is
*(map_ptr_base[ptr & 1] + ptr)
as the access method. Per-request slots would then be allocated in the map_ptr area rather than on CG arena.This would allow allocating new per-request slots without clashing with new permanent slots allocated by opcache. However, just that isn't enough as well, as with opcache there are no per-request interned strings at all, and we can't use the refcount as storage for non-interned strings.
Do you have any ideas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible to grow map_ptr vector in both directions having the single biased base. e.g. positive offsets for permanent slots and negative for per-request slots. anyway, this is not for 8.1