]> granicus.if.org Git - php/commitdiff
Use zend_type inside type lists
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 16 Jan 2020 16:04:11 +0000 (17:04 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 17 Jan 2020 08:37:54 +0000 (09:37 +0100)
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.

14 files changed:
Zend/zend.c
Zend/zend_compile.c
Zend/zend_execute.c
Zend/zend_inheritance.c
Zend/zend_opcode.c
Zend/zend_types.h
ext/opcache/ZendAccelerator.c
ext/opcache/jit/zend_jit_helpers.c
ext/opcache/zend_accelerator_util_funcs.c
ext/opcache/zend_file_cache.c
ext/opcache/zend_persist.c
ext/opcache/zend_persist_calc.c
ext/reflection/php_reflection.c
ext/zend_test/test.c

index 427db2a86151aa45e4ce28a63c1b93af0e6c60ee..20e7e85acc94cfa46a56e19b37b564f057928fb7 100644 (file)
@@ -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;
index 1e092222c585230dc83d5907bc0456b247988cbb..0f01d1a4e5e4f569174b98f82d5c7948696d088f 100644 (file)
@@ -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));
index 17de515410b1d32e999a427d4e125831a3c72567..cbd3a06fad1dbc7de0cd8e1cabaf9e49b9405ea0 100644 (file)
@@ -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++;
index 53494515b6f1598a8ebf3dd13e0387f649500f58..9a9199a1988da725fc12e7bcec8624748358f8eb 100644 (file)
@@ -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();
index e197e9bf16ab5b8a277d4d2b62da05131a59c0f3..b7423de45b00a50725a7614f996e181d23097ac3 100644 (file)
@@ -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)) {
index 2df97fcd3fdfcc8401333b33a0d818507a5b7ffe..b9f09ffede9c744f7c9918b642fc7b99ce0ef3f2 100644 (file)
@@ -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))
 
index 0e62f3765964905bb076522cb4fa4c1916c69339..c2c81ba8a6bd08e880207b2744a9592377a75d71 100644 (file)
@@ -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;
index c04985110c5fda5ebc36d02c15c7e90e19dd8bce..38294d5c27d1d24375c6d7ea7b4b36e3ffad698c 100644 (file)
@@ -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++;
index 6c54d4231cd41ce7e8147166c973a08cb6d5753f..131fc8495b910dceddcf79929afb3398ddad686e 100644 (file)
@@ -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();
index d5d0cb4466a83079b77ead52db3f751754e52491..eb74187e5d419dace139b147baf3531eeba27d5b 100644 (file)
@@ -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);
index cbf91144f3b219c146e181c06acf580b3e088cd3..1bcec7caf09deab1ef4e336bac8ba33d6d5b359c 100644 (file)
@@ -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();
        }
 
index 830a5dd8b0a9acbbb3b8361b51ff089246717845..293af3b3e63f15f772d8fd46f2c598729f619b31 100644 (file)
@@ -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;
index 73ab2b89694241ef8f1c5e28e0ad9d684480ead6..b240d233f754f08180d5d83e2e265fa11b6d9730 100644 (file)
@@ -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,
index 48b8ffe564cd9a8786bf1ca60fcd1c86132fd9f3..dc8a44cd95690cd47783c08b3ad4a1a5fa5cb0a0 100644 (file)
@@ -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);