mirror of
https://github.com/php/php-src.git
synced 2024-11-24 02:15:04 +08:00
Use zend_type inside type lists
Instead of having a completely independent encoding for type list entries. This is going to use more memory, but I'm not particularly concerned about that, as type unions that contain multiple classes should be uncommon. On the other hand, this allows us to treat top-level types and types inside lists mostly the same. A new ZEND_TYPE_FOREACH macros allows to transparently treat list and non-list types the same way. I'm not using it everywhere it could be used for now, just the places that seemed most obvious. Of course, this will make any future type system changes much simpler, as it will not be necessary to duplicate all logic two times.
This commit is contained in:
parent
afdaa91170
commit
bd1977282c
30
Zend/zend.c
30
Zend/zend.c
@ -600,10 +600,10 @@ static void function_copy_ctor(zval *zv) /* {{{ */
|
||||
memcpy(new_list, old_list, ZEND_TYPE_LIST_SIZE(old_list->num_types));
|
||||
ZEND_TYPE_SET_PTR(new_arg_info[i].type, new_list);
|
||||
|
||||
void **entry;
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(new_list, entry) {
|
||||
zend_string *name = zend_string_dup(ZEND_TYPE_LIST_GET_NAME(*entry), 1);
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_NAME(name);
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(new_list, list_type) {
|
||||
zend_string *name = zend_string_dup(ZEND_TYPE_NAME(*list_type), 1);
|
||||
ZEND_TYPE_SET_PTR(*list_type, name);
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(arg_info[i].type)) {
|
||||
zend_string *name = zend_string_dup(ZEND_TYPE_NAME(arg_info[i].type), 1);
|
||||
@ -983,20 +983,14 @@ static void zend_resolve_property_types(void) /* {{{ */
|
||||
|
||||
if (UNEXPECTED(ZEND_CLASS_HAS_TYPE_HINTS(ce))) {
|
||||
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
|
||||
if (ZEND_TYPE_HAS_LIST(prop_info->type)) {
|
||||
void **entry;
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(ZEND_TYPE_LIST(prop_info->type), entry) {
|
||||
if (ZEND_TYPE_LIST_IS_NAME(*entry)) {
|
||||
zend_string *type_name = ZEND_TYPE_LIST_GET_NAME(*entry);
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_CE(resolve_type_name(type_name));
|
||||
zend_string_release(type_name);
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(prop_info->type)) {
|
||||
zend_string *type_name = ZEND_TYPE_NAME(prop_info->type);
|
||||
ZEND_TYPE_SET_CE(prop_info->type, resolve_type_name(type_name));
|
||||
zend_string_release(type_name);
|
||||
}
|
||||
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();
|
||||
}
|
||||
ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
|
||||
|
@ -1164,13 +1164,12 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop
|
||||
zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope) {
|
||||
zend_string *str = NULL;
|
||||
if (ZEND_TYPE_HAS_LIST(type)) {
|
||||
void *elem;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), elem) {
|
||||
if (ZEND_TYPE_LIST_IS_CE(elem)) {
|
||||
str = add_type_string(str, ZEND_TYPE_LIST_GET_CE(elem)->name);
|
||||
zend_type *list_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);
|
||||
} else {
|
||||
str = add_type_string(str,
|
||||
resolve_class_name(ZEND_TYPE_LIST_GET_NAME(elem), scope));
|
||||
str = add_type_string(str, resolve_class_name(ZEND_TYPE_NAME(*list_type), scope));
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(type)) {
|
||||
@ -1245,23 +1244,16 @@ static void zend_mark_function_as_generator() /* {{{ */
|
||||
|
||||
if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
|
||||
zend_type return_type = CG(active_op_array)->arg_info[-1].type;
|
||||
zend_bool valid_type = 0;
|
||||
if (ZEND_TYPE_HAS_CLASS(return_type)) {
|
||||
if (ZEND_TYPE_HAS_LIST(return_type)) {
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(return_type), entry) {
|
||||
ZEND_ASSERT(ZEND_TYPE_LIST_IS_NAME(entry));
|
||||
if (is_generator_compatible_class_type(ZEND_TYPE_LIST_GET_NAME(entry))) {
|
||||
valid_type = 1;
|
||||
break;
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else {
|
||||
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(return_type));
|
||||
valid_type = is_generator_compatible_class_type(ZEND_TYPE_NAME(return_type));
|
||||
}
|
||||
} else {
|
||||
valid_type = (ZEND_TYPE_FULL_MASK(return_type) & MAY_BE_ITERABLE) != 0;
|
||||
zend_bool valid_type = (ZEND_TYPE_FULL_MASK(return_type) & MAY_BE_ITERABLE) != 0;
|
||||
if (!valid_type) {
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(return_type, single_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*single_type)
|
||||
&& is_generator_compatible_class_type(ZEND_TYPE_NAME(*single_type))) {
|
||||
valid_type = 1;
|
||||
break;
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
}
|
||||
|
||||
if (!valid_type) {
|
||||
@ -5521,17 +5513,13 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
|
||||
}
|
||||
|
||||
static zend_bool zend_type_contains_traversable(zend_type type) {
|
||||
if (ZEND_TYPE_HAS_LIST(type)) {
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), entry) {
|
||||
ZEND_ASSERT(ZEND_TYPE_LIST_IS_NAME(entry));
|
||||
if (zend_string_equals_literal_ci(ZEND_TYPE_LIST_GET_NAME(entry), "Traversable")) {
|
||||
return 1;
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(type)) {
|
||||
return zend_string_equals_literal_ci(ZEND_TYPE_NAME(type), "Traversable");
|
||||
}
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(type, single_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*single_type)
|
||||
&& zend_string_equals_literal_ci(ZEND_TYPE_NAME(*single_type), "Traversable")) {
|
||||
return 1;
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5561,6 +5549,7 @@ static zend_type zend_compile_typename(
|
||||
"Duplicate type %s is redundant", ZSTR_VAL(overlap_type_str));
|
||||
}
|
||||
ZEND_TYPE_FULL_MASK(type) |= ZEND_TYPE_PURE_MASK(single_type);
|
||||
ZEND_TYPE_FULL_MASK(single_type) &= ~_ZEND_TYPE_MAY_BE_MASK;
|
||||
|
||||
if (ZEND_TYPE_HAS_CLASS(single_type)) {
|
||||
if (!ZEND_TYPE_HAS_CLASS(type)) {
|
||||
@ -5580,15 +5569,16 @@ static zend_type zend_compile_typename(
|
||||
} else {
|
||||
list = erealloc(old_list, ZEND_TYPE_LIST_SIZE(old_list->num_types + 1));
|
||||
}
|
||||
list->types[list->num_types++] = ZEND_TYPE_NAME(single_type);
|
||||
} else {
|
||||
/* Switch from single name to name list. */
|
||||
size_t size = ZEND_TYPE_LIST_SIZE(2);
|
||||
list = use_arena ? zend_arena_alloc(&CG(arena), size) : emalloc(size);
|
||||
list->num_types = 2;
|
||||
list->types[0] = ZEND_TYPE_NAME(type);
|
||||
list->types[1] = ZEND_TYPE_NAME(single_type);
|
||||
list->num_types = 1;
|
||||
list->types[0] = type;
|
||||
ZEND_TYPE_FULL_MASK(list->types[0]) &= ~_ZEND_TYPE_MAY_BE_MASK;
|
||||
}
|
||||
|
||||
list->types[list->num_types++] = single_type;
|
||||
ZEND_TYPE_SET_LIST(type, list);
|
||||
if (use_arena) {
|
||||
ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_ARENA_BIT;
|
||||
@ -5597,8 +5587,7 @@ static zend_type zend_compile_typename(
|
||||
/* Check for trivially redundant class types */
|
||||
for (size_t i = 0; i < list->num_types - 1; i++) {
|
||||
if (zend_string_equals_ci(
|
||||
ZEND_TYPE_LIST_GET_NAME(list->types[i]),
|
||||
ZEND_TYPE_NAME(single_type))) {
|
||||
ZEND_TYPE_NAME(list->types[i]), ZEND_TYPE_NAME(single_type))) {
|
||||
zend_string *single_type_str = zend_type_to_string(single_type);
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"Duplicate type %s is redundant", ZSTR_VAL(single_type_str));
|
||||
|
@ -941,18 +941,18 @@ static zend_bool zend_check_and_resolve_property_class_type(
|
||||
zend_property_info *info, zend_class_entry *object_ce) {
|
||||
zend_class_entry *ce;
|
||||
if (ZEND_TYPE_HAS_LIST(info->type)) {
|
||||
void **entry;
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(ZEND_TYPE_LIST(info->type), entry) {
|
||||
if (ZEND_TYPE_LIST_IS_NAME(*entry)) {
|
||||
zend_string *name = ZEND_TYPE_LIST_GET_NAME(*entry);
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(info->type), list_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*list_type)) {
|
||||
zend_string *name = ZEND_TYPE_NAME(*list_type);
|
||||
ce = resolve_single_class_type(name, info->ce);
|
||||
if (!ce) {
|
||||
continue;
|
||||
}
|
||||
zend_string_release(name);
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_CE(ce);
|
||||
ZEND_TYPE_SET_CE(*list_type, ce);
|
||||
} else {
|
||||
ce = ZEND_TYPE_LIST_GET_CE(*entry);
|
||||
ce = ZEND_TYPE_CE(*list_type);
|
||||
}
|
||||
if (instanceof_function(object_ce, ce)) {
|
||||
return 1;
|
||||
@ -1032,12 +1032,12 @@ static zend_always_inline zend_bool zend_check_type_slow(
|
||||
if (ZEND_TYPE_HAS_CLASS(type) && Z_TYPE_P(arg) == IS_OBJECT) {
|
||||
zend_class_entry *ce;
|
||||
if (ZEND_TYPE_HAS_LIST(type)) {
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), entry) {
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
|
||||
if (*cache_slot) {
|
||||
ce = *cache_slot;
|
||||
} else {
|
||||
ce = zend_fetch_class(ZEND_TYPE_LIST_GET_NAME(entry),
|
||||
ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type),
|
||||
(ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
|
||||
if (!ce) {
|
||||
cache_slot++;
|
||||
|
@ -49,10 +49,10 @@ static void zend_type_copy_ctor(zend_type *type, zend_bool persistent) {
|
||||
memcpy(new_list, old_list, ZEND_TYPE_LIST_SIZE(old_list->num_types));
|
||||
ZEND_TYPE_SET_PTR(*type, new_list);
|
||||
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(new_list, entry) {
|
||||
ZEND_ASSERT(ZEND_TYPE_LIST_IS_NAME(entry));
|
||||
zend_string_addref(ZEND_TYPE_LIST_GET_NAME(entry));
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(new_list, list_type) {
|
||||
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type));
|
||||
zend_string_addref(ZEND_TYPE_NAME(*list_type));
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(*type)) {
|
||||
zend_string_addref(ZEND_TYPE_NAME(*type));
|
||||
@ -323,19 +323,13 @@ static zend_bool unlinked_instanceof(zend_class_entry *ce1, zend_class_entry *ce
|
||||
}
|
||||
|
||||
static zend_bool zend_type_contains_traversable(zend_type type) {
|
||||
if (ZEND_TYPE_HAS_LIST(type)) {
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), entry) {
|
||||
ZEND_ASSERT(ZEND_TYPE_LIST_IS_NAME(entry));
|
||||
if (zend_string_equals_literal_ci(ZEND_TYPE_LIST_GET_NAME(entry), "Traversable")) {
|
||||
return 1;
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
return 0;
|
||||
}
|
||||
if (ZEND_TYPE_HAS_NAME(type)) {
|
||||
return zend_string_equals_literal_ci(ZEND_TYPE_NAME(type), "Traversable");
|
||||
}
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(type, single_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*single_type)
|
||||
&& zend_string_equals_literal_ci(ZEND_TYPE_NAME(*single_type), "Traversable")) {
|
||||
return 1;
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -373,33 +367,18 @@ static inheritance_status zend_perform_covariant_class_type_check(
|
||||
return INHERITANCE_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (ZEND_TYPE_HAS_NAME(proto_type)) {
|
||||
zend_string *proto_class_name = resolve_class_name(proto_scope, ZEND_TYPE_NAME(proto_type));
|
||||
if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
|
||||
return INHERITANCE_SUCCESS;
|
||||
}
|
||||
|
||||
/* Make sure to always load both classes, to avoid only registering one of them as
|
||||
* a delayed autoload. */
|
||||
if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name, register_unresolved);
|
||||
zend_class_entry *proto_ce =
|
||||
lookup_class(proto_scope, proto_class_name, register_unresolved);
|
||||
if (!fe_ce || !proto_ce) {
|
||||
have_unresolved = 1;
|
||||
} else if (unlinked_instanceof(fe_ce, proto_ce)) {
|
||||
return INHERITANCE_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (ZEND_TYPE_HAS_LIST(proto_type)) {
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(proto_type), entry) {
|
||||
ZEND_ASSERT(ZEND_TYPE_LIST_IS_NAME(entry));
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(proto_type, single_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*single_type)) {
|
||||
zend_string *proto_class_name =
|
||||
resolve_class_name(proto_scope, ZEND_TYPE_LIST_GET_NAME(entry));
|
||||
resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
|
||||
if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
|
||||
return INHERITANCE_SUCCESS;
|
||||
}
|
||||
|
||||
/* Make sure to always load both classes, to avoid only registering one of them as
|
||||
* a delayed autoload. */
|
||||
if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name, register_unresolved);
|
||||
zend_class_entry *proto_ce =
|
||||
lookup_class(proto_scope, proto_class_name, register_unresolved);
|
||||
@ -408,8 +387,9 @@ static inheritance_status zend_perform_covariant_class_type_check(
|
||||
} else if (unlinked_instanceof(fe_ce, proto_ce)) {
|
||||
return INHERITANCE_SUCCESS;
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
}
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
|
||||
return have_unresolved ? INHERITANCE_UNRESOLVED : INHERITANCE_ERROR;
|
||||
}
|
||||
|
||||
@ -452,14 +432,14 @@ static inheritance_status zend_perform_covariant_type_check(
|
||||
}
|
||||
|
||||
if (ZEND_TYPE_HAS_LIST(fe_type)) {
|
||||
void *entry;
|
||||
zend_type *list_type;
|
||||
zend_bool all_success = 1;
|
||||
|
||||
/* First try to check whether we can succeed without resolving anything */
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(fe_type), entry) {
|
||||
ZEND_ASSERT(ZEND_TYPE_LIST_IS_NAME(entry));
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(fe_type), list_type) {
|
||||
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type));
|
||||
zend_string *fe_class_name =
|
||||
resolve_class_name(fe_scope, ZEND_TYPE_LIST_GET_NAME(entry));
|
||||
resolve_class_name(fe_scope, ZEND_TYPE_NAME(*list_type));
|
||||
inheritance_status status = zend_perform_covariant_class_type_check(
|
||||
fe_scope, fe_class_name, proto_scope, proto_type, /* register_unresolved */ 0);
|
||||
if (status == INHERITANCE_ERROR) {
|
||||
@ -477,10 +457,10 @@ static inheritance_status zend_perform_covariant_type_check(
|
||||
}
|
||||
|
||||
/* Register all classes that may have to be resolved */
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(fe_type), entry) {
|
||||
ZEND_ASSERT(ZEND_TYPE_LIST_IS_NAME(entry));
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(fe_type), list_type) {
|
||||
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type));
|
||||
zend_string *fe_class_name =
|
||||
resolve_class_name(fe_scope, ZEND_TYPE_LIST_GET_NAME(entry));
|
||||
resolve_class_name(fe_scope, ZEND_TYPE_NAME(*list_type));
|
||||
zend_perform_covariant_class_type_check(
|
||||
fe_scope, fe_class_name, proto_scope, proto_type, /* register_unresolved */ 1);
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
|
@ -104,10 +104,10 @@ ZEND_API void destroy_zend_function(zend_function *function)
|
||||
|
||||
ZEND_API void zend_type_release(zend_type type, zend_bool persistent) {
|
||||
if (ZEND_TYPE_HAS_LIST(type)) {
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), entry) {
|
||||
if (ZEND_TYPE_LIST_IS_NAME(entry)) {
|
||||
zend_string_release(ZEND_TYPE_LIST_GET_NAME(entry));
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*list_type)) {
|
||||
zend_string_release(ZEND_TYPE_NAME(*list_type));
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
if (!ZEND_TYPE_USES_ARENA(type)) {
|
||||
|
@ -131,8 +131,8 @@ typedef struct {
|
||||
} zend_type;
|
||||
|
||||
typedef struct {
|
||||
size_t num_types;
|
||||
void *types[1];
|
||||
uint32_t num_types;
|
||||
zend_type types[1];
|
||||
} zend_type_list;
|
||||
|
||||
#define _ZEND_TYPE_EXTRA_FLAGS_SHIFT 24
|
||||
@ -182,45 +182,39 @@ typedef struct {
|
||||
#define ZEND_TYPE_LIST(t) \
|
||||
((zend_type_list *) (t).ptr)
|
||||
|
||||
/* Type lists use the low bit to distinguish NAME and CE entries,
|
||||
* both of which may exist in the same list. */
|
||||
#define ZEND_TYPE_LIST_IS_CE(entry) \
|
||||
(((uintptr_t) (entry)) & 1)
|
||||
|
||||
#define ZEND_TYPE_LIST_IS_NAME(entry) \
|
||||
!ZEND_TYPE_LIST_IS_CE(entry)
|
||||
|
||||
#define ZEND_TYPE_LIST_GET_NAME(entry) \
|
||||
((zend_string *) (entry))
|
||||
|
||||
#define ZEND_TYPE_LIST_GET_CE(entry) \
|
||||
((zend_class_entry *) ((uintptr_t) (entry) & ~1))
|
||||
|
||||
#define ZEND_TYPE_LIST_ENCODE_NAME(name) \
|
||||
((void *) (name))
|
||||
|
||||
#define ZEND_TYPE_LIST_ENCODE_CE(ce) \
|
||||
((void *) (((uintptr_t) ce) | 1))
|
||||
|
||||
#define ZEND_TYPE_LIST_SIZE(num_types) \
|
||||
(sizeof(zend_type_list) + ((num_types) - 1) * sizeof(void *))
|
||||
(sizeof(zend_type_list) + ((num_types) - 1) * sizeof(zend_type))
|
||||
|
||||
#define ZEND_TYPE_LIST_FOREACH_PTR(list, entry_ptr) do { \
|
||||
void **_list = (list)->types; \
|
||||
void **_end = _list + (list)->num_types; \
|
||||
/* This iterates over a zend_type_list. */
|
||||
#define ZEND_TYPE_LIST_FOREACH(list, type_ptr) do { \
|
||||
zend_type *_list = (list)->types; \
|
||||
zend_type *_end = _list + (list)->num_types; \
|
||||
for (; _list < _end; _list++) { \
|
||||
entry_ptr = _list;
|
||||
|
||||
#define ZEND_TYPE_LIST_FOREACH(list, entry) do { \
|
||||
void **_list = (list)->types; \
|
||||
void **_end = _list + (list)->num_types; \
|
||||
for (; _list < _end; _list++) { \
|
||||
entry = *_list;
|
||||
type_ptr = _list;
|
||||
|
||||
#define ZEND_TYPE_LIST_FOREACH_END() \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* This iterates over any zend_type. If it's a type list, all list elements will
|
||||
* be visited. If it's a single type, only the single type is visited. */
|
||||
#define ZEND_TYPE_FOREACH(type, type_ptr) do { \
|
||||
zend_type *_cur, *_end; \
|
||||
if (ZEND_TYPE_HAS_LIST(type)) { \
|
||||
zend_type_list *_list = ZEND_TYPE_LIST(type); \
|
||||
_cur = _list->types; \
|
||||
_end = _cur + _list->num_types; \
|
||||
} else { \
|
||||
_cur = &(type); \
|
||||
_end = _cur + 1; \
|
||||
} \
|
||||
do { \
|
||||
type_ptr = _cur;
|
||||
|
||||
#define ZEND_TYPE_FOREACH_END() \
|
||||
} while (++_cur < _end); \
|
||||
} while (0)
|
||||
|
||||
#define ZEND_TYPE_SET_PTR(t, _ptr) \
|
||||
((t).ptr = (_ptr))
|
||||
|
||||
|
@ -602,16 +602,13 @@ static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_int
|
||||
num_args++;
|
||||
}
|
||||
for (i = 0 ; i < num_args; i++) {
|
||||
if (ZEND_TYPE_HAS_LIST(arg_info[i].type)) {
|
||||
void **entry;
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(ZEND_TYPE_LIST(arg_info[i].type), entry) {
|
||||
ZEND_ASSERT(ZEND_TYPE_LIST_IS_NAME(*entry));
|
||||
*entry = zend_new_interned_string(ZEND_TYPE_LIST_GET_NAME(*entry));
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(arg_info[i].type)) {
|
||||
ZEND_TYPE_SET_PTR(arg_info[i].type,
|
||||
new_interned_string(ZEND_TYPE_NAME(arg_info[i].type)));
|
||||
}
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(arg_info[i].type, single_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*single_type)) {
|
||||
ZEND_TYPE_SET_PTR(*single_type,
|
||||
new_interned_string(ZEND_TYPE_NAME(*single_type)));
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
@ -3581,31 +3578,18 @@ static zend_class_entry *preload_fetch_resolved_ce(zend_string *name, zend_class
|
||||
static zend_bool preload_try_resolve_property_types(zend_class_entry *ce)
|
||||
{
|
||||
zend_bool ok = 1;
|
||||
zend_property_info *prop;
|
||||
zend_class_entry *p;
|
||||
|
||||
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
|
||||
zend_property_info *prop;
|
||||
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
|
||||
if (ZEND_TYPE_HAS_LIST(prop->type)) {
|
||||
void **entry;
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(ZEND_TYPE_LIST(prop->type), entry) {
|
||||
if (ZEND_TYPE_LIST_IS_NAME(*entry)) {
|
||||
p = preload_fetch_resolved_ce(ZEND_TYPE_LIST_GET_NAME(*entry), ce);
|
||||
if (!p) {
|
||||
ok = 0;
|
||||
continue;
|
||||
}
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_CE(p);
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(prop->type)) {
|
||||
p = preload_fetch_resolved_ce(ZEND_TYPE_NAME(prop->type), ce);
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(prop->type, single_type) {
|
||||
zend_class_entry *p = preload_fetch_resolved_ce(ZEND_TYPE_NAME(*single_type), ce);
|
||||
if (!p) {
|
||||
ok = 0;
|
||||
continue;
|
||||
}
|
||||
ZEND_TYPE_SET_CE(prop->type, p);
|
||||
}
|
||||
ZEND_TYPE_SET_CE(*single_type, p);
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
@ -3625,19 +3609,15 @@ static zend_bool preload_is_class_type_known(zend_class_entry *ce, zend_string *
|
||||
return known;
|
||||
}
|
||||
|
||||
static zend_bool preload_is_type_known(zend_class_entry *ce, zend_type type) {
|
||||
if (ZEND_TYPE_HAS_LIST(type)) {
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), entry) {
|
||||
if (ZEND_TYPE_LIST_IS_NAME(entry)
|
||||
&& !preload_is_class_type_known(ce, ZEND_TYPE_LIST_GET_NAME(entry))) {
|
||||
static zend_bool preload_is_type_known(zend_class_entry *ce, zend_type *type) {
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(*type, single_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*single_type)) {
|
||||
if (!preload_is_class_type_known(ce, ZEND_TYPE_NAME(*single_type))) {
|
||||
return 0;
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
}
|
||||
if (ZEND_TYPE_HAS_NAME(type)) {
|
||||
return preload_is_class_type_known(ce, ZEND_TYPE_NAME(type));
|
||||
}
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3685,13 +3665,13 @@ static zend_bool preload_needed_types_known(zend_class_entry *ce) {
|
||||
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, lcname, fptr) {
|
||||
uint32_t i;
|
||||
if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
|
||||
if (!preload_is_type_known(ce, fptr->common.arg_info[-1].type) &&
|
||||
if (!preload_is_type_known(ce, &fptr->common.arg_info[-1].type) &&
|
||||
preload_is_method_maybe_override(ce, lcname)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < fptr->common.num_args; i++) {
|
||||
if (!preload_is_type_known(ce, fptr->common.arg_info[i].type) &&
|
||||
if (!preload_is_type_known(ce, &fptr->common.arg_info[i].type) &&
|
||||
preload_is_method_maybe_override(ce, lcname)) {
|
||||
return 0;
|
||||
}
|
||||
@ -3979,20 +3959,14 @@ static void preload_ensure_classes_loadable() {
|
||||
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
|
||||
zend_property_info *prop;
|
||||
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
|
||||
if (ZEND_TYPE_HAS_LIST(prop->type)) {
|
||||
void **entry;
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(ZEND_TYPE_LIST(prop->type), entry) {
|
||||
if (ZEND_TYPE_LIST_IS_NAME(*entry)) {
|
||||
zend_class_entry *ce = preload_load_prop_type(
|
||||
prop, ZEND_TYPE_LIST_GET_NAME(*entry));
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_CE(ce);
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(prop->type)) {
|
||||
zend_class_entry *ce =
|
||||
preload_load_prop_type(prop, ZEND_TYPE_NAME(prop->type));
|
||||
ZEND_TYPE_SET_CE(prop->type, ce);
|
||||
}
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(prop->type, single_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*single_type)) {
|
||||
zend_class_entry *ce = preload_load_prop_type(
|
||||
prop, ZEND_TYPE_NAME(*single_type));
|
||||
ZEND_TYPE_SET_CE(*single_type, ce);
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
|
||||
|
@ -1148,12 +1148,12 @@ static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, const zend_op_arra
|
||||
if (ZEND_TYPE_HAS_CLASS(arg_info->type) && Z_TYPE_P(arg) == IS_OBJECT) {
|
||||
zend_class_entry *ce;
|
||||
if (ZEND_TYPE_HAS_LIST(arg_info->type)) {
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(arg_info->type), entry) {
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(arg_info->type), list_type) {
|
||||
if (*cache_slot) {
|
||||
ce = *cache_slot;
|
||||
} else {
|
||||
ce = zend_fetch_class(ZEND_TYPE_LIST_GET_NAME(entry),
|
||||
ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type),
|
||||
(ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
|
||||
if (!ce) {
|
||||
cache_slot++;
|
||||
|
@ -239,13 +239,13 @@ static void zend_hash_clone_prop_info(HashTable *ht)
|
||||
list = ARENA_REALLOC(list);
|
||||
ZEND_TYPE_SET_PTR(prop_info->type, list);
|
||||
|
||||
void **entry;
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(ZEND_TYPE_LIST(prop_info->type), entry) {
|
||||
if (ZEND_TYPE_LIST_IS_CE(*entry)) {
|
||||
zend_class_entry *ce = ZEND_TYPE_LIST_GET_CE(*entry);
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(prop_info->type), list_type) {
|
||||
if (ZEND_TYPE_HAS_CE(*list_type)) {
|
||||
zend_class_entry *ce = ZEND_TYPE_CE(*list_type);
|
||||
if (IN_ARENA(ce)) {
|
||||
ce = ARENA_REALLOC(ce);
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_CE(ce);
|
||||
ZEND_TYPE_SET_PTR(*list_type, ce);
|
||||
}
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
|
@ -380,17 +380,9 @@ static void zend_file_cache_serialize_type(
|
||||
ZEND_TYPE_SET_PTR(*type, list);
|
||||
UNSERIALIZE_PTR(list);
|
||||
|
||||
void **entry;
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(list, entry) {
|
||||
if (ZEND_TYPE_LIST_IS_NAME(*entry)) {
|
||||
zend_string *name = ZEND_TYPE_LIST_GET_NAME(*entry);
|
||||
SERIALIZE_STR(name);
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_NAME(name);
|
||||
} else {
|
||||
zend_class_entry *ce = ZEND_TYPE_LIST_GET_CE(*entry);
|
||||
SERIALIZE_PTR(ce);
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_CE(ce);
|
||||
}
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(list, list_type) {
|
||||
zend_file_cache_serialize_type(list_type, script, info, buf);
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(*type)) {
|
||||
zend_string *type_name = ZEND_TYPE_NAME(*type);
|
||||
@ -1108,17 +1100,9 @@ static void zend_file_cache_unserialize_type(
|
||||
UNSERIALIZE_PTR(list);
|
||||
ZEND_TYPE_SET_PTR(*type, list);
|
||||
|
||||
void **entry;
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(list, entry) {
|
||||
if (ZEND_TYPE_LIST_IS_NAME(*entry)) {
|
||||
zend_string *name = ZEND_TYPE_LIST_GET_NAME(*entry);
|
||||
UNSERIALIZE_STR(name);
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_NAME(name);
|
||||
} else {
|
||||
zend_class_entry *ce = ZEND_TYPE_LIST_GET_CE(*entry);
|
||||
UNSERIALIZE_PTR(ce);
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_CE(ce);
|
||||
}
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(list, list_type) {
|
||||
zend_file_cache_unserialize_type(list_type, script, buf);
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(*type)) {
|
||||
zend_string *type_name = ZEND_TYPE_NAME(*type);
|
||||
|
@ -260,7 +260,7 @@ static void zend_persist_zval(zval *z)
|
||||
|
||||
static void zend_persist_type(zend_type *type) {
|
||||
if (ZEND_TYPE_HAS_LIST(*type)) {
|
||||
void **entry;
|
||||
zend_type *list_type;
|
||||
zend_type_list *list = ZEND_TYPE_LIST(*type);
|
||||
if (ZEND_TYPE_USES_ARENA(*type)) {
|
||||
if (!ZCG(is_immutable_class)) {
|
||||
@ -275,10 +275,10 @@ static void zend_persist_type(zend_type *type) {
|
||||
}
|
||||
ZEND_TYPE_SET_PTR(*type, list);
|
||||
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(list, entry) {
|
||||
zend_string *type_name = ZEND_TYPE_LIST_GET_NAME(*entry);
|
||||
ZEND_TYPE_LIST_FOREACH(list, list_type) {
|
||||
zend_string *type_name = ZEND_TYPE_NAME(*list_type);
|
||||
zend_accel_store_interned_string(type_name);
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_NAME(type_name);
|
||||
ZEND_TYPE_SET_PTR(*list_type, type_name);
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(*type)) {
|
||||
zend_string *type_name = ZEND_TYPE_NAME(*type);
|
||||
@ -963,28 +963,18 @@ static 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) {
|
||||
if (ZEND_TYPE_HAS_LIST(prop->type)) {
|
||||
void **entry;
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(ZEND_TYPE_LIST(prop->type), entry) {
|
||||
if (ZEND_TYPE_LIST_IS_CE(*entry)) {
|
||||
zend_class_entry *ce = ZEND_TYPE_LIST_GET_CE(*entry);
|
||||
if (ce->type == ZEND_USER_CLASS) {
|
||||
ce = zend_shared_alloc_get_xlat_entry(ce);
|
||||
if (ce) {
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_CE(ce);
|
||||
}
|
||||
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_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_CE(prop->type)) {
|
||||
zend_class_entry *ce = ZEND_TYPE_CE(prop->type);
|
||||
if (ce->type == ZEND_USER_CLASS) {
|
||||
ce = zend_shared_alloc_get_xlat_entry(ce);
|
||||
if (ce) {
|
||||
ZEND_TYPE_SET_PTR(prop->type, ce);
|
||||
}
|
||||
}
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
|
@ -151,16 +151,16 @@ static void zend_persist_zval_calc(zval *z)
|
||||
static void zend_persist_type_calc(zend_type *type)
|
||||
{
|
||||
if (ZEND_TYPE_HAS_LIST(*type)) {
|
||||
void **entry;
|
||||
zend_type *list_type;
|
||||
if (ZEND_TYPE_USES_ARENA(*type) && !ZCG(is_immutable_class)) {
|
||||
ADD_ARENA_SIZE(ZEND_TYPE_LIST_SIZE(ZEND_TYPE_LIST(*type)->num_types));
|
||||
} else {
|
||||
ADD_SIZE(ZEND_TYPE_LIST_SIZE(ZEND_TYPE_LIST(*type)->num_types));
|
||||
}
|
||||
ZEND_TYPE_LIST_FOREACH_PTR(ZEND_TYPE_LIST(*type), entry) {
|
||||
zend_string *type_name = ZEND_TYPE_LIST_GET_NAME(*entry);
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) {
|
||||
zend_string *type_name = ZEND_TYPE_NAME(*list_type);
|
||||
ADD_INTERNED_STRING(type_name);
|
||||
*entry = ZEND_TYPE_LIST_ENCODE_NAME(type_name);
|
||||
ZEND_TYPE_SET_PTR(*list_type, type_name);
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(*type)) {
|
||||
zend_string *type_name = ZEND_TYPE_NAME(*type);
|
||||
@ -349,16 +349,12 @@ static void check_property_type_resolution(zend_class_entry *ce) {
|
||||
|
||||
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
|
||||
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
|
||||
if (ZEND_TYPE_HAS_LIST(prop->type)) {
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(prop->type), entry) {
|
||||
if (ZEND_TYPE_LIST_IS_NAME(entry)) {
|
||||
return;
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(prop->type)) {
|
||||
return;
|
||||
}
|
||||
zend_type *single_type;
|
||||
ZEND_TYPE_FOREACH(prop->type, single_type) {
|
||||
if (ZEND_TYPE_HAS_NAME(*single_type)) {
|
||||
return;
|
||||
}
|
||||
} ZEND_TYPE_FOREACH_END();
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
|
||||
|
@ -2938,15 +2938,9 @@ ZEND_METHOD(reflection_union_type, getTypes)
|
||||
|
||||
array_init(return_value);
|
||||
if (ZEND_TYPE_HAS_LIST(param->type)) {
|
||||
void *entry;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(param->type), entry) {
|
||||
if (ZEND_TYPE_LIST_IS_NAME(entry)) {
|
||||
append_type(return_value,
|
||||
(zend_type) ZEND_TYPE_INIT_CLASS(ZEND_TYPE_LIST_GET_NAME(entry), 0, 0));
|
||||
} else {
|
||||
append_type(return_value,
|
||||
(zend_type) ZEND_TYPE_INIT_CE(ZEND_TYPE_LIST_GET_CE(entry), 0, 0));
|
||||
}
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(param->type), list_type) {
|
||||
append_type(return_value, *list_type);
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(param->type)) {
|
||||
append_type(return_value,
|
||||
|
@ -270,8 +270,8 @@ PHP_MINIT_FUNCTION(zend_test)
|
||||
zend_string *class_name2 = zend_string_init("Iterator", sizeof("Iterator") - 1, 1);
|
||||
zend_type_list *type_list = malloc(ZEND_TYPE_LIST_SIZE(2));
|
||||
type_list->num_types = 2;
|
||||
type_list->types[0] = ZEND_TYPE_LIST_ENCODE_NAME(class_name1);
|
||||
type_list->types[1] = ZEND_TYPE_LIST_ENCODE_NAME(class_name2);
|
||||
type_list->types[0] = (zend_type) ZEND_TYPE_INIT_CLASS(class_name1, 0, 0);
|
||||
type_list->types[1] = (zend_type) ZEND_TYPE_INIT_CLASS(class_name2, 0, 0);
|
||||
zend_type type = ZEND_TYPE_INIT_PTR(type_list, _ZEND_TYPE_LIST_BIT, 1, 0);
|
||||
zval val;
|
||||
ZVAL_NULL(&val);
|
||||
|
Loading…
Reference in New Issue
Block a user