diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 65834adbafff..f9499c49d72b 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2937,7 +2937,6 @@ static void zend_convert_internal_arg_info_type(zend_type *type, bool persistent // temporary workaround, we support union types by splitting // the type name on `|` characters if necessary. const char *class_name = ZEND_TYPE_LITERAL_NAME(*type); - type->type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT; size_t num_types = 1; const char *p = class_name; @@ -2951,7 +2950,7 @@ static void zend_convert_internal_arg_info_type(zend_type *type, bool persistent zend_string *str = zend_string_init_interned(class_name, strlen(class_name), persistent); zend_alloc_ce_cache(str); ZEND_TYPE_SET_PTR(*type, str); - type->type_mask |= _ZEND_TYPE_NAME_BIT; + type->kind = ZEND_TYPE_KIND_NAME; } else { /* Union type */ zend_type_list *list = pemalloc(ZEND_TYPE_LIST_SIZE(num_types), persistent); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 105f99d24171..26cf551a5378 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7621,8 +7621,7 @@ static zend_type zend_compile_typename_ex( if (ZEND_TYPE_IS_COMPLEX(single_type)) { if (!ZEND_TYPE_IS_COMPLEX(type) && !is_composite) { /* The first class type can be stored directly as the type ptr payload. */ - ZEND_TYPE_SET_PTR(type, ZEND_TYPE_NAME(single_type)); - ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_NAME_BIT; + ZEND_TYPE_SET_PTR_AND_KIND(type, ZEND_TYPE_NAME(single_type), ZEND_TYPE_KIND_NAME); } else { if (type_list->num_types == 0) { /* Switch from single name to name list. */ diff --git a/Zend/zend_types.h b/Zend/zend_types.h index cfff3b942c4b..0258341e52da 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -113,13 +113,22 @@ typedef void (*copy_ctor_func_t)(zval *pElement); * ZEND_TYPE_INIT_*() should be used for construction. */ +/* zend_type.kind discriminates what type.ptr points at. Exactly one value + * applies at a time; it is a plain enum, not a bitmask like type_mask. */ +typedef enum zend_type_kind { + ZEND_TYPE_KIND_NONE, /* no payload; ptr is NULL */ + ZEND_TYPE_KIND_NAME, /* a `zend_string*` (class name) */ + ZEND_TYPE_KIND_LITERAL_NAME, /* a `const char*` (literal class name) */ + ZEND_TYPE_KIND_LIST, /* a `zend_type_list*` */ +} zend_type_kind; + typedef struct { /* Not using a union here, because there's no good way to initialize them * in a way that is supported in both C and C++ (designated initializers * are only supported since C++20). */ void *ptr; uint32_t type_mask; - /* TODO: We could use the extra 32-bit of padding on 64-bit systems. */ + zend_type_kind kind; } zend_type; typedef struct { @@ -129,12 +138,6 @@ typedef struct { #define _ZEND_TYPE_EXTRA_FLAGS_SHIFT 25 #define _ZEND_TYPE_MASK ((1u << 25) - 1) -/* Only one of these bits may be set. */ -#define _ZEND_TYPE_NAME_BIT (1u << 24) -// Used to signify that type.ptr is not a `zend_string*` but a `const char*`, -#define _ZEND_TYPE_LITERAL_NAME_BIT (1u << 23) -#define _ZEND_TYPE_LIST_BIT (1u << 22) -#define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_NAME_BIT|_ZEND_TYPE_LITERAL_NAME_BIT) /* For BC behaviour with iterable type */ #define _ZEND_TYPE_ITERABLE_BIT (1u << 21) /* Whether the type list is arena allocated */ @@ -149,21 +152,20 @@ typedef struct { #define _ZEND_TYPE_NULLABLE_BIT 0x2u #define ZEND_TYPE_IS_SET(t) \ - (((t).type_mask & _ZEND_TYPE_MASK) != 0) + (((t).type_mask & _ZEND_TYPE_MASK) != 0 || (t).kind != ZEND_TYPE_KIND_NONE) -/* If a type is complex it means it's either a list with a union or intersection, - * or the void pointer is a class name */ +/* A complex type carries a ptr payload: a class name or a type list. */ #define ZEND_TYPE_IS_COMPLEX(t) \ - ((((t).type_mask) & _ZEND_TYPE_KIND_MASK) != 0) + ((t).kind != ZEND_TYPE_KIND_NONE) #define ZEND_TYPE_HAS_NAME(t) \ - ((((t).type_mask) & _ZEND_TYPE_NAME_BIT) != 0) + ((t).kind == ZEND_TYPE_KIND_NAME) #define ZEND_TYPE_HAS_LITERAL_NAME(t) \ - ((((t).type_mask) & _ZEND_TYPE_LITERAL_NAME_BIT) != 0) + ((t).kind == ZEND_TYPE_KIND_LITERAL_NAME) #define ZEND_TYPE_HAS_LIST(t) \ - ((((t).type_mask) & _ZEND_TYPE_LIST_BIT) != 0) + ((t).kind == ZEND_TYPE_KIND_LIST) #define ZEND_TYPE_IS_ITERABLE_FALLBACK(t) \ ((((t).type_mask) & _ZEND_TYPE_ITERABLE_BIT) != 0) @@ -248,12 +250,11 @@ typedef struct { #define ZEND_TYPE_SET_PTR_AND_KIND(t, _ptr, kind_bit) do { \ (t).ptr = (_ptr); \ - (t).type_mask &= ~_ZEND_TYPE_KIND_MASK; \ - (t).type_mask |= (kind_bit); \ + (t).kind = (kind_bit); \ } while (0) #define ZEND_TYPE_SET_LIST(t, list) \ - ZEND_TYPE_SET_PTR_AND_KIND(t, list, _ZEND_TYPE_LIST_BIT) + ZEND_TYPE_SET_PTR_AND_KIND(t, list, ZEND_TYPE_KIND_LIST) /* FULL_MASK() includes the MAY_BE_* type mask, as well as additional metadata bits. * The PURE_MASK() only includes the MAY_BE_* type mask. */ @@ -284,10 +285,10 @@ typedef struct { #endif #define ZEND_TYPE_INIT_NONE(extra_flags) \ - _ZEND_TYPE_PREFIX { NULL, (extra_flags) } + _ZEND_TYPE_PREFIX { NULL, (extra_flags), ZEND_TYPE_KIND_NONE } #define ZEND_TYPE_INIT_MASK(_type_mask) \ - _ZEND_TYPE_PREFIX { NULL, (_type_mask) } + _ZEND_TYPE_PREFIX { NULL, (_type_mask), ZEND_TYPE_KIND_NONE } #define ZEND_TYPE_INIT_CODE(code, allow_null, extra_flags) \ ZEND_TYPE_INIT_MASK(((code) == _IS_BOOL ? MAY_BE_BOOL : ( (code) == IS_ITERABLE ? _ZEND_TYPE_ITERABLE_BIT : ((code) == IS_MIXED ? MAY_BE_ANY : (1 << (code))))) \ @@ -295,28 +296,28 @@ typedef struct { #define ZEND_TYPE_INIT_PTR(ptr, type_kind, allow_null, extra_flags) \ _ZEND_TYPE_PREFIX { (void *) (ptr), \ - (type_kind) | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags) } + (((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags)), (type_kind) } #define ZEND_TYPE_INIT_PTR_MASK(ptr, type_mask) \ - _ZEND_TYPE_PREFIX { (void *) (ptr), (type_mask) } + _ZEND_TYPE_PREFIX { (void *) (ptr), (type_mask), ZEND_TYPE_KIND_NONE } #define ZEND_TYPE_INIT_UNION(ptr, extra_flags) \ - _ZEND_TYPE_PREFIX { (void *) (ptr), (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_UNION_BIT) | (extra_flags) } + _ZEND_TYPE_PREFIX { (void *) (ptr), (_ZEND_TYPE_UNION_BIT) | (extra_flags), ZEND_TYPE_KIND_LIST } #define ZEND_TYPE_INIT_INTERSECTION(ptr, extra_flags) \ - _ZEND_TYPE_PREFIX { (void *) (ptr), (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_INTERSECTION_BIT) | (extra_flags) } + _ZEND_TYPE_PREFIX { (void *) (ptr), (_ZEND_TYPE_INTERSECTION_BIT) | (extra_flags), ZEND_TYPE_KIND_LIST } #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) + ZEND_TYPE_INIT_PTR(class_name, ZEND_TYPE_KIND_NAME, allow_null, extra_flags) #define ZEND_TYPE_INIT_CLASS_MASK(class_name, type_mask) \ - ZEND_TYPE_INIT_PTR_MASK(class_name, _ZEND_TYPE_NAME_BIT | (type_mask)) + _ZEND_TYPE_PREFIX { (void *) (class_name), (type_mask), ZEND_TYPE_KIND_NAME } #define ZEND_TYPE_INIT_CLASS_CONST(class_name, allow_null, extra_flags) \ - ZEND_TYPE_INIT_PTR(class_name, _ZEND_TYPE_LITERAL_NAME_BIT, allow_null, extra_flags) + ZEND_TYPE_INIT_PTR(class_name, ZEND_TYPE_KIND_LITERAL_NAME, allow_null, extra_flags) #define ZEND_TYPE_INIT_CLASS_CONST_MASK(class_name, type_mask) \ - ZEND_TYPE_INIT_PTR_MASK(class_name, (_ZEND_TYPE_LITERAL_NAME_BIT | (type_mask))) + _ZEND_TYPE_PREFIX { (void *) (class_name), (type_mask), ZEND_TYPE_KIND_LITERAL_NAME } typedef union _zend_value { zend_long lval; /* long value */ diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index cf43d3ad840f..6808e8225555 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -16115,9 +16115,11 @@ static int zend_jit_fetch_static_prop(zend_jit_ctx *jit, const zend_op *opline, // JIT: if (ZEND_TYPE_IS_SET(property_info->type)) prop_info_ref = ir_LOAD_L( ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2)); - if_typed = ir_IF(ir_AND_U32( - ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))), - ir_CONST_U32(_ZEND_TYPE_MASK))); + if_typed = ir_IF(ir_OR_U32( + ir_AND_U32( + ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))), + ir_CONST_U32(_ZEND_TYPE_MASK)), + ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.kind))))); ir_IF_FALSE(if_typed); ir_END_list(merge); ir_IF_TRUE(if_typed); @@ -16144,9 +16146,11 @@ static int zend_jit_fetch_static_prop(zend_jit_ctx *jit, const zend_op *opline, // JIT: if (ZEND_TYPE_IS_SET(property_info->type)) prop_info_ref = ir_LOAD_L( ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2)); - if_typed = ir_IF(ir_AND_U32( - ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))), - ir_CONST_U32(_ZEND_TYPE_MASK))); + if_typed = ir_IF(ir_OR_U32( + ir_AND_U32( + ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))), + ir_CONST_U32(_ZEND_TYPE_MASK)), + ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.kind))))); ir_IF_FALSE(if_typed); ir_END_list(merge); ir_IF_TRUE(if_typed);