Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
3 changes: 1 addition & 2 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
55 changes: 28 additions & 27 deletions Zend/zend_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 */
Expand All @@ -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)
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -284,39 +285,39 @@ 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))))) \
| ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags))

#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 */
Expand Down
16 changes: 10 additions & 6 deletions ext/opcache/jit/zend_jit_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
Loading