mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Always use CE_CACHE, remove TYPE_HAS_CE (#7336)
Currently, CE_CACHE on strings is only used with opcache interned strings. This patch extends usage to non-opcache interned strings as well. This means that most type strings can now make use of CE_CACHE even if opcache is not loaded, which allows us to remove TYPE_HAS_CE kind, and fix some discrepancies depending on whether a type stores a resolved or non-resolved name. There are two cases where CE_CACHE will not be used: * When opcache is not used and a permanent interned string (that is not an internal class name) is used as a type name during the request. In this case we can't allocate a map_ptr index for the permanent string, as it would be not be in the permanent map_ptr index space. * When opcache is used but the script is not cached (e.g. eval'd code or opcache full). If opcache is used, we can't allocate additional map_ptr indexes at runtime, because they may conflict with indexes allocated by opcache. In these two cases we would end up not using CE caching for property types (argument/return types still have the separate cache slot).
This commit is contained in:
parent
7d2a2c7dc0
commit
315f40942b
15 changed files with 123 additions and 276 deletions
|
@ -2269,9 +2269,7 @@ static uint32_t zend_convert_type(const zend_script *script, zend_type type, zen
|
|||
if (pce) {
|
||||
/* As we only have space to store one CE,
|
||||
* we use a plain object type for class unions. */
|
||||
if (ZEND_TYPE_HAS_CE(type)) {
|
||||
*pce = ZEND_TYPE_CE(type);
|
||||
} else if (ZEND_TYPE_HAS_NAME(type)) {
|
||||
if (ZEND_TYPE_HAS_NAME(type)) {
|
||||
zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(type));
|
||||
*pce = zend_optimizer_get_class_entry(script, lcname);
|
||||
zend_string_release_ex(lcname, 0);
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
--TEST--
|
||||
method overloading with different method signature
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (getenv('SKIP_PRELOAD')) die('xfail Difference in class name casing');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
|
64
Zend/zend.c
64
Zend/zend.c
|
@ -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")) {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
}
|
||||
|
||||
zend_hash_update_ptr(&ce->properties_info, name, property_info);
|
||||
|
||||
return property_info;
|
||||
|
|
|
@ -1202,43 +1202,13 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
|
|||
zend_type *list_type;
|
||||
bool is_intersection = ZEND_TYPE_IS_INTERSECTION(type);
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
|
||||
if (ZEND_TYPE_HAS_CE(*list_type)) {
|
||||
str = add_type_string(str, ZEND_TYPE_CE(*list_type)->name, is_intersection);
|
||||
} else {
|
||||
zend_string *name = ZEND_TYPE_NAME(*list_type);
|
||||
|
||||
if (ZSTR_HAS_CE_CACHE(name)
|
||||
&& ZSTR_GET_CE_CACHE(name)) {
|
||||
zend_class_entry *ce = ZSTR_GET_CE_CACHE(name);
|
||||
if (ce->ce_flags & ZEND_ACC_ANON_CLASS) {
|
||||
zend_string *tmp = zend_string_init(ZSTR_VAL(ce->name), strlen(ZSTR_VAL(ce->name)), 0);
|
||||
str = add_type_string(str, tmp, is_intersection);
|
||||
} else {
|
||||
str = add_type_string(str, ce->name, is_intersection);
|
||||
}
|
||||
} else {
|
||||
zend_string *resolved = resolve_class_name(name, scope);
|
||||
str = add_type_string(str, resolved, is_intersection);
|
||||
zend_string_release(resolved);
|
||||
}
|
||||
}
|
||||
zend_string *name = ZEND_TYPE_NAME(*list_type);
|
||||
zend_string *resolved = resolve_class_name(name, scope);
|
||||
str = add_type_string(str, resolved, is_intersection);
|
||||
zend_string_release(resolved);
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(type)) {
|
||||
zend_string *name = ZEND_TYPE_NAME(type);
|
||||
|
||||
if (ZSTR_HAS_CE_CACHE(name)
|
||||
&& ZSTR_GET_CE_CACHE(name)) {
|
||||
zend_class_entry *ce = ZSTR_GET_CE_CACHE(name);
|
||||
if (ce->ce_flags & ZEND_ACC_ANON_CLASS) {
|
||||
str = zend_string_init(ZSTR_VAL(ce->name), strlen(ZSTR_VAL(ce->name)), 0);
|
||||
} else {
|
||||
str = zend_string_copy(ce->name);
|
||||
}
|
||||
} else {
|
||||
str = resolve_class_name(name, scope);
|
||||
}
|
||||
} else if (ZEND_TYPE_HAS_CE(type)) {
|
||||
str = zend_string_copy(ZEND_TYPE_CE(type)->name);
|
||||
str = resolve_class_name(ZEND_TYPE_NAME(type), scope);
|
||||
}
|
||||
|
||||
uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
|
||||
|
@ -6232,6 +6202,8 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
|
|||
}
|
||||
}
|
||||
|
||||
class_name = zend_new_interned_string(class_name);
|
||||
zend_alloc_ce_cache(class_name);
|
||||
return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, 0, 0);
|
||||
}
|
||||
}
|
||||
|
@ -7687,6 +7659,9 @@ void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel) /* {{{
|
|||
ce->type = ZEND_USER_CLASS;
|
||||
ce->name = name;
|
||||
zend_initialize_class_data(ce, 1);
|
||||
if (!(decl->flags & ZEND_ACC_ANON_CLASS)) {
|
||||
zend_alloc_ce_cache(ce->name);
|
||||
}
|
||||
|
||||
if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
|
||||
ce->ce_flags |= ZEND_ACC_PRELOADED;
|
||||
|
|
|
@ -851,11 +851,6 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(
|
|||
|
||||
static zend_class_entry *resolve_single_class_type(zend_string *name, zend_class_entry *self_ce) {
|
||||
if (zend_string_equals_literal_ci(name, "self")) {
|
||||
/* We need to explicitly check for this here, to avoid updating the type in the trait and
|
||||
* later using the wrong "self" when the trait is used in a class. */
|
||||
if (UNEXPECTED((self_ce->ce_flags & ZEND_ACC_TRAIT) != 0)) {
|
||||
return NULL;
|
||||
}
|
||||
return self_ce;
|
||||
} else if (zend_string_equals_literal_ci(name, "parent")) {
|
||||
return self_ce->parent;
|
||||
|
@ -866,26 +861,16 @@ static zend_class_entry *resolve_single_class_type(zend_string *name, zend_class
|
|||
|
||||
static zend_always_inline zend_class_entry *zend_ce_from_type(
|
||||
zend_property_info *info, zend_type *type) {
|
||||
if (UNEXPECTED(!ZEND_TYPE_HAS_NAME(*type))) {
|
||||
ZEND_ASSERT(ZEND_TYPE_HAS_CE(*type));
|
||||
return ZEND_TYPE_CE(*type);
|
||||
}
|
||||
|
||||
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*type));
|
||||
zend_string *name = ZEND_TYPE_NAME(*type);
|
||||
zend_class_entry *ce;
|
||||
if (ZSTR_HAS_CE_CACHE(name)) {
|
||||
ce = ZSTR_GET_CE_CACHE(name);
|
||||
zend_class_entry *ce = ZSTR_GET_CE_CACHE(name);
|
||||
if (!ce) {
|
||||
ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
|
||||
}
|
||||
} else {
|
||||
ce = resolve_single_class_type(name, info->ce);
|
||||
if (ce && !(info->ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
|
||||
zend_string_release(name);
|
||||
ZEND_TYPE_SET_CE(*type, ce);
|
||||
}
|
||||
return ce;
|
||||
}
|
||||
return ce;
|
||||
return resolve_single_class_type(name, info->ce);
|
||||
}
|
||||
|
||||
static bool zend_check_and_resolve_property_class_type(
|
||||
|
|
|
@ -430,9 +430,6 @@ static inheritance_status zend_is_intersection_subtype_of_class(
|
|||
|
||||
if (!proto_ce) proto_ce = lookup_class(proto_scope, proto_class_name);
|
||||
fe_ce = lookup_class(fe_scope, fe_class_name);
|
||||
} else if (ZEND_TYPE_HAS_CE(*single_type)) {
|
||||
if (!proto_ce) proto_ce = lookup_class(proto_scope, proto_class_name);
|
||||
fe_ce = ZEND_TYPE_CE(*single_type);
|
||||
} else {
|
||||
/* standard type in an intersection type is impossible,
|
||||
* because it would be a fatal compile error */
|
||||
|
@ -456,8 +453,9 @@ static inheritance_status zend_is_intersection_subtype_of_class(
|
|||
|
||||
/* Check whether a single class proto type is a subtype of a potentially complex fe_type. */
|
||||
static inheritance_status zend_is_class_subtype_of_type(
|
||||
zend_class_entry *fe_scope, zend_string *fe_class_name, zend_class_entry *fe_ce,
|
||||
zend_class_entry *fe_scope, zend_string *fe_class_name,
|
||||
zend_class_entry *proto_scope, zend_type proto_type) {
|
||||
zend_class_entry *fe_ce = NULL;
|
||||
bool have_unresolved = 0;
|
||||
|
||||
/* If the parent has 'object' as a return type, any class satisfies the co-variant check */
|
||||
|
@ -503,9 +501,6 @@ static inheritance_status zend_is_class_subtype_of_type(
|
|||
|
||||
if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
|
||||
proto_ce = lookup_class(proto_scope, proto_class_name);
|
||||
} else if (ZEND_TYPE_HAS_CE(*single_type)) {
|
||||
if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
|
||||
proto_ce = ZEND_TYPE_CE(*single_type);
|
||||
} else {
|
||||
/* standard type */
|
||||
ZEND_ASSERT(!is_intersection);
|
||||
|
@ -535,16 +530,10 @@ static inheritance_status zend_is_class_subtype_of_type(
|
|||
return is_intersection ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
|
||||
}
|
||||
|
||||
static zend_string *get_class_from_type(
|
||||
zend_class_entry **ce, zend_class_entry *scope, zend_type single_type) {
|
||||
static zend_string *get_class_from_type(zend_class_entry *scope, zend_type single_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(single_type)) {
|
||||
*ce = NULL;
|
||||
return resolve_class_name(scope, ZEND_TYPE_NAME(single_type));
|
||||
}
|
||||
if (ZEND_TYPE_HAS_CE(single_type)) {
|
||||
*ce = ZEND_TYPE_CE(single_type);
|
||||
return (*ce)->name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -617,14 +606,11 @@ static inheritance_status zend_perform_covariant_type_check(
|
|||
if (proto_type_mask & (MAY_BE_OBJECT|MAY_BE_ITERABLE)) {
|
||||
bool any_class = (proto_type_mask & MAY_BE_OBJECT) != 0;
|
||||
ZEND_TYPE_FOREACH(fe_type, single_type) {
|
||||
zend_class_entry *fe_ce;
|
||||
zend_string *fe_class_name = get_class_from_type(&fe_ce, fe_scope, *single_type);
|
||||
zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
|
||||
if (!fe_class_name) {
|
||||
continue;
|
||||
}
|
||||
if (!fe_ce) {
|
||||
fe_ce = lookup_class(fe_scope, fe_class_name);
|
||||
}
|
||||
zend_class_entry *fe_ce = lookup_class(fe_scope, fe_class_name);
|
||||
if (fe_ce) {
|
||||
if (any_class || unlinked_instanceof(fe_ce, zend_ce_traversable)) {
|
||||
track_class_dependency(fe_ce, fe_class_name);
|
||||
|
@ -643,13 +629,12 @@ static inheritance_status zend_perform_covariant_type_check(
|
|||
early_exit_status =
|
||||
ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
|
||||
ZEND_TYPE_FOREACH(proto_type, single_type) {
|
||||
zend_class_entry *proto_ce;
|
||||
zend_string *proto_class_name =
|
||||
get_class_from_type(&proto_ce, proto_scope, *single_type);
|
||||
zend_string *proto_class_name = get_class_from_type(proto_scope, *single_type);
|
||||
if (!proto_class_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
zend_class_entry *proto_ce = NULL;
|
||||
inheritance_status status = zend_is_intersection_subtype_of_class(
|
||||
fe_scope, fe_type, proto_scope, proto_class_name, proto_ce);
|
||||
if (status == early_exit_status) {
|
||||
|
@ -666,14 +651,13 @@ static inheritance_status zend_perform_covariant_type_check(
|
|||
* whether proto_type is a union or intersection (only the inner check differs). */
|
||||
early_exit_status = INHERITANCE_ERROR;
|
||||
ZEND_TYPE_FOREACH(fe_type, single_type) {
|
||||
zend_class_entry *fe_ce;
|
||||
zend_string *fe_class_name = get_class_from_type(&fe_ce, fe_scope, *single_type);
|
||||
zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
|
||||
if (!fe_class_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inheritance_status status = zend_is_class_subtype_of_type(
|
||||
fe_scope, fe_class_name, fe_ce, proto_scope, proto_type);
|
||||
fe_scope, fe_class_name, proto_scope, proto_type);
|
||||
if (status == early_exit_status) {
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -103,5 +103,6 @@
|
|||
ZEND_API void zend_map_ptr_reset(void);
|
||||
ZEND_API void *zend_map_ptr_new(void);
|
||||
ZEND_API void zend_map_ptr_extend(size_t last);
|
||||
ZEND_API void zend_alloc_ce_cache(zend_string *type_name);
|
||||
|
||||
#endif /* ZEND_MAP_PTR_H */
|
||||
|
|
|
@ -111,13 +111,11 @@ typedef void (*copy_ctor_func_t)(zval *pElement);
|
|||
* ZEND_TYPE_IS_SET() - checks if there is a type-hint
|
||||
* ZEND_TYPE_IS_ONLY_MASK() - checks if type-hint refer to standard type only
|
||||
* ZEND_TYPE_IS_COMPLEX() - checks if type is a type_list, or contains a class either as a CE or as a name
|
||||
* ZEND_TYPE_HAS_CE() - checks if type-hint contains some class as zend_class_entry *
|
||||
* ZEND_TYPE_HAS_NAME() - checks if type-hint contains some class as zend_string *
|
||||
* ZEND_TYPE_IS_INTERSECTION() - checks if the type_list represents an intersection type list
|
||||
* ZEND_TYPE_IS_UNION() - checks if the type_list represents a union type list
|
||||
*
|
||||
* ZEND_TYPE_NAME() - returns referenced class name
|
||||
* ZEND_TYPE_CE() - returns referenced class entry
|
||||
* ZEND_TYPE_PURE_MASK() - returns MAY_BE_* type mask
|
||||
* ZEND_TYPE_FULL_MASK() - returns MAY_BE_* type mask together with other flags
|
||||
*
|
||||
|
@ -144,9 +142,8 @@ typedef struct {
|
|||
#define _ZEND_TYPE_MASK ((1u << 25) - 1)
|
||||
/* Only one of these bits may be set. */
|
||||
#define _ZEND_TYPE_NAME_BIT (1u << 24)
|
||||
#define _ZEND_TYPE_CE_BIT (1u << 23)
|
||||
#define _ZEND_TYPE_LIST_BIT (1u << 22)
|
||||
#define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_CE_BIT|_ZEND_TYPE_NAME_BIT)
|
||||
#define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_NAME_BIT)
|
||||
/* TODO: bit 21 is not used */
|
||||
/* Whether the type list is arena allocated */
|
||||
#define _ZEND_TYPE_ARENA_BIT (1u << 20)
|
||||
|
@ -163,13 +160,10 @@ typedef struct {
|
|||
(((t).type_mask & _ZEND_TYPE_MASK) != 0)
|
||||
|
||||
/* If a type is complex it means it's either a list with a union or intersection,
|
||||
* or the void pointer is a CE/Name */
|
||||
* or the void pointer is a class name */
|
||||
#define ZEND_TYPE_IS_COMPLEX(t) \
|
||||
((((t).type_mask) & _ZEND_TYPE_KIND_MASK) != 0)
|
||||
|
||||
#define ZEND_TYPE_HAS_CE(t) \
|
||||
((((t).type_mask) & _ZEND_TYPE_CE_BIT) != 0)
|
||||
|
||||
#define ZEND_TYPE_HAS_NAME(t) \
|
||||
((((t).type_mask) & _ZEND_TYPE_NAME_BIT) != 0)
|
||||
|
||||
|
@ -194,9 +188,6 @@ typedef struct {
|
|||
#define ZEND_TYPE_LITERAL_NAME(t) \
|
||||
((const char *) (t).ptr)
|
||||
|
||||
#define ZEND_TYPE_CE(t) \
|
||||
((zend_class_entry *) (t).ptr)
|
||||
|
||||
#define ZEND_TYPE_LIST(t) \
|
||||
((zend_type_list *) (t).ptr)
|
||||
|
||||
|
@ -242,13 +233,10 @@ typedef struct {
|
|||
(t).type_mask |= (kind_bit); \
|
||||
} while (0)
|
||||
|
||||
#define ZEND_TYPE_SET_CE(t, ce) \
|
||||
ZEND_TYPE_SET_PTR_AND_KIND(t, ce, _ZEND_TYPE_CE_BIT)
|
||||
|
||||
#define ZEND_TYPE_SET_LIST(t, list) \
|
||||
ZEND_TYPE_SET_PTR_AND_KIND(t, list, _ZEND_TYPE_LIST_BIT)
|
||||
|
||||
/* FULL_MASK() includes the MAY_BE_* type mask, the CE/NAME bits, as well as extra reserved bits.
|
||||
/* FULL_MASK() includes the MAY_BE_* type mask, as well as additional metadata bits.
|
||||
* The PURE_MASK() only includes the MAY_BE_* type mask. */
|
||||
#define ZEND_TYPE_FULL_MASK(t) \
|
||||
((t).type_mask)
|
||||
|
@ -285,9 +273,6 @@ typedef struct {
|
|||
#define ZEND_TYPE_INIT_PTR_MASK(ptr, type_mask) \
|
||||
{ (void *) (ptr), (type_mask) }
|
||||
|
||||
#define ZEND_TYPE_INIT_CE(_ce, allow_null, extra_flags) \
|
||||
ZEND_TYPE_INIT_PTR(_ce, _ZEND_TYPE_CE_BIT, allow_null, extra_flags)
|
||||
|
||||
#define ZEND_TYPE_INIT_CLASS(class_name, allow_null, extra_flags) \
|
||||
ZEND_TYPE_INIT_PTR(class_name, _ZEND_TYPE_NAME_BIT, allow_null, extra_flags)
|
||||
|
||||
|
|
|
@ -485,8 +485,7 @@ zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str)
|
|||
do {
|
||||
s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
|
||||
if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
|
||||
zend_string_release(str);
|
||||
return s;
|
||||
goto finish;
|
||||
}
|
||||
pos = STRTAB_COLLISION(s);
|
||||
} while (pos != STRTAB_INVALID_POS);
|
||||
|
@ -511,6 +510,15 @@ zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str)
|
|||
memcpy(ZSTR_VAL(s), ZSTR_VAL(str), ZSTR_LEN(s) + 1);
|
||||
ZCSG(interned_strings).top = STRTAB_NEXT(s);
|
||||
|
||||
finish:
|
||||
/* Transfer CE_CACHE map ptr slot to new interned string.
|
||||
* Should only happen for permanent interned strings with permanent map_ptr slot. */
|
||||
if (ZSTR_HAS_CE_CACHE(str) && !ZSTR_HAS_CE_CACHE(s)) {
|
||||
ZEND_ASSERT(GC_FLAGS(str) & IS_STR_PERMANENT);
|
||||
GC_SET_REFCOUNT(s, GC_REFCOUNT(str));
|
||||
GC_ADD_FLAGS(s, IS_STR_CLASS_NAME_MAP_PTR);
|
||||
}
|
||||
|
||||
zend_string_release(str);
|
||||
return s;
|
||||
}
|
||||
|
@ -624,6 +632,7 @@ static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_int
|
|||
|
||||
if (ce->name) {
|
||||
ce->name = new_interned_string(ce->name);
|
||||
ZEND_ASSERT(ZSTR_HAS_CE_CACHE(ce->name));
|
||||
}
|
||||
|
||||
ZEND_HASH_FOREACH_BUCKET(&ce->properties_info, q) {
|
||||
|
@ -741,20 +750,6 @@ static zend_string* ZEND_FASTCALL accel_replace_string_by_shm_permanent(zend_str
|
|||
return str;
|
||||
}
|
||||
|
||||
static void accel_allocate_ce_cache_slots(void)
|
||||
{
|
||||
Bucket *p;
|
||||
|
||||
ZEND_HASH_FOREACH_BUCKET(CG(class_table), p) {
|
||||
zend_class_entry *ce;
|
||||
|
||||
ce = (zend_class_entry*)Z_PTR(p->val);
|
||||
if (ce->name) {
|
||||
zend_accel_get_class_name_map_ptr(ce->name);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
static void accel_use_shm_interned_strings(void)
|
||||
{
|
||||
HANDLE_BLOCK_INTERRUPTIONS();
|
||||
|
@ -763,7 +758,6 @@ static void accel_use_shm_interned_strings(void)
|
|||
|
||||
if (ZCSG(interned_strings).saved_top == NULL) {
|
||||
accel_copy_permanent_strings(accel_new_interned_string);
|
||||
accel_allocate_ce_cache_slots();
|
||||
} else {
|
||||
ZCG(counted) = 1;
|
||||
accel_copy_permanent_strings(accel_replace_string_by_shm_permanent);
|
||||
|
@ -3789,32 +3783,6 @@ static bool preload_try_resolve_constants(zend_class_entry *ce)
|
|||
return ok || was_changed;
|
||||
}
|
||||
|
||||
static zend_class_entry *preload_fetch_resolved_ce(zend_string *name) {
|
||||
zend_string *lcname = zend_string_tolower(name);
|
||||
zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lcname);
|
||||
zend_string_release(lcname);
|
||||
return ce;
|
||||
}
|
||||
|
||||
static void preload_try_resolve_property_types(zend_class_entry *ce)
|
||||
{
|
||||
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
|
||||
zend_property_info *prop;
|
||||
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(prop->type, single_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*single_type)) {
|
||||
zend_class_entry *p =
|
||||
preload_fetch_resolved_ce(ZEND_TYPE_NAME(*single_type));
|
||||
if (p) {
|
||||
ZEND_TYPE_SET_CE(*single_type, p);
|
||||
}
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
|
||||
static void (*orig_error_cb)(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message);
|
||||
|
||||
static void preload_error_cb(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message)
|
||||
|
@ -3986,18 +3954,6 @@ static void preload_link(void)
|
|||
} ZEND_HASH_FOREACH_END();
|
||||
} while (changed);
|
||||
|
||||
/* Resolve property types */
|
||||
ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
|
||||
ce = Z_PTR_P(zv);
|
||||
if (ce->type == ZEND_INTERNAL_CLASS) {
|
||||
break;
|
||||
}
|
||||
if (!(ce->ce_flags & ZEND_ACC_TRAIT)) {
|
||||
preload_try_resolve_property_types(ce);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
|
||||
do {
|
||||
changed = 0;
|
||||
|
||||
|
|
|
@ -260,35 +260,35 @@ static void *zend_file_cache_serialize_interned(zend_string *str,
|
|||
((_ZSTR_HEADER_SIZE + 1 + new_len + 4095) & ~0xfff) - (_ZSTR_HEADER_SIZE + 1),
|
||||
0);
|
||||
}
|
||||
memcpy(ZSTR_VAL((zend_string*)ZCG(mem)) + info->str_size, str, len);
|
||||
|
||||
zend_string *new_str = (zend_string *) (ZSTR_VAL((zend_string*)ZCG(mem)) + info->str_size);
|
||||
memcpy(new_str, str, len);
|
||||
GC_ADD_FLAGS(new_str, IS_STR_INTERNED);
|
||||
GC_DEL_FLAGS(new_str, IS_STR_PERMANENT|IS_STR_CLASS_NAME_MAP_PTR);
|
||||
info->str_size += len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *zend_file_cache_unserialize_interned(zend_string *str, int in_shm)
|
||||
{
|
||||
zend_string *ret;
|
||||
|
||||
str = (zend_string*)((char*)ZCG(mem) + ((size_t)(str) & ~Z_UL(1)));
|
||||
if (in_shm) {
|
||||
ret = accel_new_interned_string(str);
|
||||
if (ret == str) {
|
||||
/* We have to create new SHM allocated string */
|
||||
size_t size = _ZSTR_STRUCT_SIZE(ZSTR_LEN(str));
|
||||
ret = zend_shared_alloc(size);
|
||||
if (!ret) {
|
||||
zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
|
||||
LONGJMP(*EG(bailout), FAILURE);
|
||||
}
|
||||
memcpy(ret, str, size);
|
||||
/* String wasn't interned but we will use it as interned anyway */
|
||||
GC_SET_REFCOUNT(ret, 1);
|
||||
GC_TYPE_INFO(ret) = GC_STRING | ((IS_STR_INTERNED | IS_STR_PERSISTENT | IS_STR_PERMANENT) << GC_FLAGS_SHIFT);
|
||||
if (!in_shm) {
|
||||
return str;
|
||||
}
|
||||
|
||||
zend_string *ret = accel_new_interned_string(str);
|
||||
if (ret == str) {
|
||||
/* We have to create new SHM allocated string */
|
||||
size_t size = _ZSTR_STRUCT_SIZE(ZSTR_LEN(str));
|
||||
ret = zend_shared_alloc(size);
|
||||
if (!ret) {
|
||||
zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
|
||||
LONGJMP(*EG(bailout), FAILURE);
|
||||
}
|
||||
} else {
|
||||
ret = str;
|
||||
GC_ADD_FLAGS(ret, IS_STR_INTERNED);
|
||||
GC_DEL_FLAGS(ret, IS_STR_PERMANENT);
|
||||
memcpy(ret, str, size);
|
||||
/* String wasn't interned but we will use it as interned anyway */
|
||||
GC_SET_REFCOUNT(ret, 1);
|
||||
GC_TYPE_INFO(ret) = GC_STRING | ((IS_STR_INTERNED | IS_STR_PERSISTENT | IS_STR_PERMANENT) << GC_FLAGS_SHIFT);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -440,10 +440,6 @@ static void zend_file_cache_serialize_type(
|
|||
zend_string *type_name = ZEND_TYPE_NAME(*type);
|
||||
SERIALIZE_STR(type_name);
|
||||
ZEND_TYPE_SET_PTR(*type, type_name);
|
||||
} else if (ZEND_TYPE_HAS_CE(*type)) {
|
||||
zend_class_entry *ce = ZEND_TYPE_CE(*type);
|
||||
SERIALIZE_PTR(ce);
|
||||
ZEND_TYPE_SET_PTR(*type, ce);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1232,11 +1228,9 @@ static void zend_file_cache_unserialize_type(
|
|||
ZEND_TYPE_SET_PTR(*type, type_name);
|
||||
if (!script->corrupted) {
|
||||
zend_accel_get_class_name_map_ptr(type_name);
|
||||
} else {
|
||||
zend_alloc_ce_cache(type_name);
|
||||
}
|
||||
} else if (ZEND_TYPE_HAS_CE(*type)) {
|
||||
zend_class_entry *ce = ZEND_TYPE_CE(*type);
|
||||
UNSERIALIZE_PTR(ce);
|
||||
ZEND_TYPE_SET_PTR(*type, ce);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1497,9 +1491,12 @@ static void zend_file_cache_unserialize_class(zval *zv,
|
|||
ce = Z_PTR_P(zv);
|
||||
|
||||
UNSERIALIZE_STR(ce->name);
|
||||
if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS)
|
||||
&& !script->corrupted) {
|
||||
zend_accel_get_class_name_map_ptr(ce->name);
|
||||
if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS)) {
|
||||
if (!script->corrupted) {
|
||||
zend_accel_get_class_name_map_ptr(ce->name);
|
||||
} else {
|
||||
zend_alloc_ce_cache(ce->name);
|
||||
}
|
||||
}
|
||||
if (ce->parent) {
|
||||
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
|
||||
|
|
|
@ -1118,24 +1118,6 @@ void zend_update_parent_ce(zend_class_entry *ce)
|
|||
}
|
||||
}
|
||||
|
||||
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
|
||||
zend_property_info *prop;
|
||||
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(prop->type, single_type) {
|
||||
if (ZEND_TYPE_HAS_CE(*single_type)) {
|
||||
zend_class_entry *ce = ZEND_TYPE_CE(*single_type);
|
||||
if (ce->type == ZEND_USER_CLASS) {
|
||||
ce = zend_shared_alloc_get_xlat_entry(ce);
|
||||
if (ce) {
|
||||
ZEND_TYPE_SET_PTR(*single_type, ce);
|
||||
}
|
||||
}
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
/* update methods */
|
||||
if (ce->constructor) {
|
||||
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->constructor);
|
||||
|
|
|
@ -3061,17 +3061,7 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
|
|||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(param->type)) {
|
||||
zend_string *name = ZEND_TYPE_NAME(param->type);
|
||||
|
||||
if (ZSTR_HAS_CE_CACHE(name) && ZSTR_GET_CE_CACHE(name)) {
|
||||
append_type(return_value,
|
||||
(zend_type) ZEND_TYPE_INIT_CE(ZSTR_GET_CE_CACHE(name), 0, 0));
|
||||
} else {
|
||||
append_type(return_value,
|
||||
(zend_type) ZEND_TYPE_INIT_CLASS(name, 0, 0));
|
||||
}
|
||||
} else if (ZEND_TYPE_HAS_CE(param->type)) {
|
||||
append_type(return_value,
|
||||
(zend_type) ZEND_TYPE_INIT_CE(ZEND_TYPE_CE(param->type), 0, 0));
|
||||
append_type(return_value, (zend_type) ZEND_TYPE_INIT_CLASS(name, 0, 0));
|
||||
}
|
||||
|
||||
type_mask = ZEND_TYPE_PURE_MASK(param->type);
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
--TEST--
|
||||
Intersection types in reflection
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (getenv('SKIP_PRELOAD')) die('xfail Difference in class name casing');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
@ -71,13 +67,13 @@ Allows null: false
|
|||
Name: Countable
|
||||
String: Countable
|
||||
Allows Null: false
|
||||
Type x&y&Countable:
|
||||
Type X&Y&Countable:
|
||||
Allows null: false
|
||||
Name: x
|
||||
String: x
|
||||
Name: X
|
||||
String: X
|
||||
Allows Null: false
|
||||
Name: y
|
||||
String: y
|
||||
Name: Y
|
||||
String: Y
|
||||
Allows Null: false
|
||||
Name: Countable
|
||||
String: Countable
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
--TEST--
|
||||
Union types in reflection
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (getenv('SKIP_PRELOAD')) die('xfail Difference in class name casing');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
@ -90,10 +86,10 @@ Allows null: false
|
|||
Name: int
|
||||
String: int
|
||||
Allows Null: false
|
||||
Type x|Y|int:
|
||||
Type X|Y|int:
|
||||
Allows null: false
|
||||
Name: x
|
||||
String: x
|
||||
Name: X
|
||||
String: X
|
||||
Allows Null: false
|
||||
Name: Y
|
||||
String: Y
|
||||
|
@ -101,13 +97,13 @@ Allows null: false
|
|||
Name: int
|
||||
String: int
|
||||
Allows Null: false
|
||||
Type x|y|int:
|
||||
Type X|Y|int:
|
||||
Allows null: false
|
||||
Name: x
|
||||
String: x
|
||||
Name: X
|
||||
String: X
|
||||
Allows Null: false
|
||||
Name: y
|
||||
String: y
|
||||
Name: Y
|
||||
String: Y
|
||||
Allows Null: false
|
||||
Name: int
|
||||
String: int
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue