Skip to content

Commit 4a761a5

Browse files
committed
Zend: store the zend_type kind discriminator in a dedicated field
zend_type packed the "what does ptr point at" discriminator (_ZEND_TYPE_NAME_BIT / _ZEND_TYPE_LITERAL_NAME_BIT / _ZEND_TYPE_LIST_BIT) into the high bits of type_mask, sharing the word with the MAY_BE_* mask and the arg-info extra flags. Only two bits were left free, which is not enough room for additional type kinds. Move the discriminator into a new `uint32_t kind` field. On 64-bit this occupies the existing 4 bytes of struct padding, so sizeof(zend_type) stays 16 (resolves the long-standing TODO); on 32-bit zend_type grows from 8 to 12 bytes. This frees type_mask bits 22-24 and gives the kind field room for future kinds. Pure refactor, no behaviour change. The bit constants keep their values and are simply read from / written to `kind` now. ZEND_TYPE_IS_SET() additionally checks `kind`, and the JIT's inlined typed-property IS_SET check ORs the kind field in. Signed-off-by: azjezz <azjezz@protonmail.com>
1 parent 8c63ec4 commit 4a761a5

4 files changed

Lines changed: 33 additions & 31 deletions

File tree

Zend/zend_API.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2937,7 +2937,7 @@ static void zend_convert_internal_arg_info_type(zend_type *type, bool persistent
29372937
// temporary workaround, we support union types by splitting
29382938
// the type name on `|` characters if necessary.
29392939
const char *class_name = ZEND_TYPE_LITERAL_NAME(*type);
2940-
type->type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT;
2940+
type->kind &= ~_ZEND_TYPE_LITERAL_NAME_BIT;
29412941

29422942
size_t num_types = 1;
29432943
const char *p = class_name;
@@ -2951,7 +2951,7 @@ static void zend_convert_internal_arg_info_type(zend_type *type, bool persistent
29512951
zend_string *str = zend_string_init_interned(class_name, strlen(class_name), persistent);
29522952
zend_alloc_ce_cache(str);
29532953
ZEND_TYPE_SET_PTR(*type, str);
2954-
type->type_mask |= _ZEND_TYPE_NAME_BIT;
2954+
type->kind |= _ZEND_TYPE_NAME_BIT;
29552955
} else {
29562956
/* Union type */
29572957
zend_type_list *list = pemalloc(ZEND_TYPE_LIST_SIZE(num_types), persistent);

Zend/zend_compile.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7621,8 +7621,7 @@ static zend_type zend_compile_typename_ex(
76217621
if (ZEND_TYPE_IS_COMPLEX(single_type)) {
76227622
if (!ZEND_TYPE_IS_COMPLEX(type) && !is_composite) {
76237623
/* The first class type can be stored directly as the type ptr payload. */
7624-
ZEND_TYPE_SET_PTR(type, ZEND_TYPE_NAME(single_type));
7625-
ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_NAME_BIT;
7624+
ZEND_TYPE_SET_PTR_AND_KIND(type, ZEND_TYPE_NAME(single_type), _ZEND_TYPE_NAME_BIT);
76267625
} else {
76277626
if (type_list->num_types == 0) {
76287627
/* Switch from single name to name list. */

Zend/zend_types.h

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ typedef struct {
119119
* are only supported since C++20). */
120120
void *ptr;
121121
uint32_t type_mask;
122-
/* TODO: We could use the extra 32-bit of padding on 64-bit systems. */
122+
uint32_t kind;
123123
} zend_type;
124124

125125
typedef struct {
@@ -129,11 +129,11 @@ typedef struct {
129129

130130
#define _ZEND_TYPE_EXTRA_FLAGS_SHIFT 25
131131
#define _ZEND_TYPE_MASK ((1u << 25) - 1)
132-
/* Only one of these bits may be set. */
133-
#define _ZEND_TYPE_NAME_BIT (1u << 24)
134-
// Used to signify that type.ptr is not a `zend_string*` but a `const char*`,
135-
#define _ZEND_TYPE_LITERAL_NAME_BIT (1u << 23)
136-
#define _ZEND_TYPE_LIST_BIT (1u << 22)
132+
/* These bits live in zend_type.kind (not type_mask). Only one may be set.
133+
* Signifies what type.ptr points at: */
134+
#define _ZEND_TYPE_NAME_BIT (1u << 24) /* a `zend_string*` (class name) */
135+
#define _ZEND_TYPE_LITERAL_NAME_BIT (1u << 23) /* a `const char*` (literal class name) */
136+
#define _ZEND_TYPE_LIST_BIT (1u << 22) /* a `zend_type_list*` */
137137
#define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_NAME_BIT|_ZEND_TYPE_LITERAL_NAME_BIT)
138138
/* For BC behaviour with iterable type */
139139
#define _ZEND_TYPE_ITERABLE_BIT (1u << 21)
@@ -149,21 +149,21 @@ typedef struct {
149149
#define _ZEND_TYPE_NULLABLE_BIT 0x2u
150150

151151
#define ZEND_TYPE_IS_SET(t) \
152-
(((t).type_mask & _ZEND_TYPE_MASK) != 0)
152+
(((t).type_mask & _ZEND_TYPE_MASK) != 0 || (t).kind != 0)
153153

154154
/* If a type is complex it means it's either a list with a union or intersection,
155155
* or the void pointer is a class name */
156156
#define ZEND_TYPE_IS_COMPLEX(t) \
157-
((((t).type_mask) & _ZEND_TYPE_KIND_MASK) != 0)
157+
((((t).kind) & _ZEND_TYPE_KIND_MASK) != 0)
158158

159159
#define ZEND_TYPE_HAS_NAME(t) \
160-
((((t).type_mask) & _ZEND_TYPE_NAME_BIT) != 0)
160+
((((t).kind) & _ZEND_TYPE_NAME_BIT) != 0)
161161

162162
#define ZEND_TYPE_HAS_LITERAL_NAME(t) \
163-
((((t).type_mask) & _ZEND_TYPE_LITERAL_NAME_BIT) != 0)
163+
((((t).kind) & _ZEND_TYPE_LITERAL_NAME_BIT) != 0)
164164

165165
#define ZEND_TYPE_HAS_LIST(t) \
166-
((((t).type_mask) & _ZEND_TYPE_LIST_BIT) != 0)
166+
((((t).kind) & _ZEND_TYPE_LIST_BIT) != 0)
167167

168168
#define ZEND_TYPE_IS_ITERABLE_FALLBACK(t) \
169169
((((t).type_mask) & _ZEND_TYPE_ITERABLE_BIT) != 0)
@@ -248,8 +248,7 @@ typedef struct {
248248

249249
#define ZEND_TYPE_SET_PTR_AND_KIND(t, _ptr, kind_bit) do { \
250250
(t).ptr = (_ptr); \
251-
(t).type_mask &= ~_ZEND_TYPE_KIND_MASK; \
252-
(t).type_mask |= (kind_bit); \
251+
(t).kind = (kind_bit); \
253252
} while (0)
254253

255254
#define ZEND_TYPE_SET_LIST(t, list) \
@@ -284,39 +283,39 @@ typedef struct {
284283
#endif
285284

286285
#define ZEND_TYPE_INIT_NONE(extra_flags) \
287-
_ZEND_TYPE_PREFIX { NULL, (extra_flags) }
286+
_ZEND_TYPE_PREFIX { NULL, (extra_flags), 0 }
288287

289288
#define ZEND_TYPE_INIT_MASK(_type_mask) \
290-
_ZEND_TYPE_PREFIX { NULL, (_type_mask) }
289+
_ZEND_TYPE_PREFIX { NULL, (_type_mask), 0 }
291290

292291
#define ZEND_TYPE_INIT_CODE(code, allow_null, extra_flags) \
293292
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))))) \
294293
| ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags))
295294

296295
#define ZEND_TYPE_INIT_PTR(ptr, type_kind, allow_null, extra_flags) \
297296
_ZEND_TYPE_PREFIX { (void *) (ptr), \
298-
(type_kind) | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags) }
297+
(((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags)), (type_kind) }
299298

300299
#define ZEND_TYPE_INIT_PTR_MASK(ptr, type_mask) \
301-
_ZEND_TYPE_PREFIX { (void *) (ptr), (type_mask) }
300+
_ZEND_TYPE_PREFIX { (void *) (ptr), (type_mask), 0 }
302301

303302
#define ZEND_TYPE_INIT_UNION(ptr, extra_flags) \
304-
_ZEND_TYPE_PREFIX { (void *) (ptr), (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_UNION_BIT) | (extra_flags) }
303+
_ZEND_TYPE_PREFIX { (void *) (ptr), (_ZEND_TYPE_UNION_BIT) | (extra_flags), _ZEND_TYPE_LIST_BIT }
305304

306305
#define ZEND_TYPE_INIT_INTERSECTION(ptr, extra_flags) \
307-
_ZEND_TYPE_PREFIX { (void *) (ptr), (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_INTERSECTION_BIT) | (extra_flags) }
306+
_ZEND_TYPE_PREFIX { (void *) (ptr), (_ZEND_TYPE_INTERSECTION_BIT) | (extra_flags), _ZEND_TYPE_LIST_BIT }
308307

309308
#define ZEND_TYPE_INIT_CLASS(class_name, allow_null, extra_flags) \
310309
ZEND_TYPE_INIT_PTR(class_name, _ZEND_TYPE_NAME_BIT, allow_null, extra_flags)
311310

312311
#define ZEND_TYPE_INIT_CLASS_MASK(class_name, type_mask) \
313-
ZEND_TYPE_INIT_PTR_MASK(class_name, _ZEND_TYPE_NAME_BIT | (type_mask))
312+
_ZEND_TYPE_PREFIX { (void *) (class_name), (type_mask), _ZEND_TYPE_NAME_BIT }
314313

315314
#define ZEND_TYPE_INIT_CLASS_CONST(class_name, allow_null, extra_flags) \
316315
ZEND_TYPE_INIT_PTR(class_name, _ZEND_TYPE_LITERAL_NAME_BIT, allow_null, extra_flags)
317316

318317
#define ZEND_TYPE_INIT_CLASS_CONST_MASK(class_name, type_mask) \
319-
ZEND_TYPE_INIT_PTR_MASK(class_name, (_ZEND_TYPE_LITERAL_NAME_BIT | (type_mask)))
318+
_ZEND_TYPE_PREFIX { (void *) (class_name), (type_mask), _ZEND_TYPE_LITERAL_NAME_BIT }
320319

321320
typedef union _zend_value {
322321
zend_long lval; /* long value */

ext/opcache/jit/zend_jit_ir.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16115,9 +16115,11 @@ static int zend_jit_fetch_static_prop(zend_jit_ctx *jit, const zend_op *opline,
1611516115
// JIT: if (ZEND_TYPE_IS_SET(property_info->type))
1611616116
prop_info_ref = ir_LOAD_L(
1611716117
ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
16118-
if_typed = ir_IF(ir_AND_U32(
16119-
ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
16120-
ir_CONST_U32(_ZEND_TYPE_MASK)));
16118+
if_typed = ir_IF(ir_OR_U32(
16119+
ir_AND_U32(
16120+
ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
16121+
ir_CONST_U32(_ZEND_TYPE_MASK)),
16122+
ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.kind)))));
1612116123
ir_IF_FALSE(if_typed);
1612216124
ir_END_list(merge);
1612316125
ir_IF_TRUE(if_typed);
@@ -16144,9 +16146,11 @@ static int zend_jit_fetch_static_prop(zend_jit_ctx *jit, const zend_op *opline,
1614416146
// JIT: if (ZEND_TYPE_IS_SET(property_info->type))
1614516147
prop_info_ref = ir_LOAD_L(
1614616148
ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
16147-
if_typed = ir_IF(ir_AND_U32(
16148-
ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
16149-
ir_CONST_U32(_ZEND_TYPE_MASK)));
16149+
if_typed = ir_IF(ir_OR_U32(
16150+
ir_AND_U32(
16151+
ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
16152+
ir_CONST_U32(_ZEND_TYPE_MASK)),
16153+
ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.kind)))));
1615016154
ir_IF_FALSE(if_typed);
1615116155
ir_END_list(merge);
1615216156
ir_IF_TRUE(if_typed);

0 commit comments

Comments
 (0)