From 9e8ba7891e74a80265e09ff5b810ec947680c1ce Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 19 Sep 2019 12:11:29 +0200 Subject: Change representation of zend_type from type code to MAY_BE_* mask This switches zend_type from storing a single IS_* type code to storing a MAY_BE_* type mask. Right now most code still assumes that there is only a single type in the mask (or two together with MAY_BE_NULL). But this will make it a lot simpler to introduce union types. An additional advantage (and why I'm doing this separately), is that a number of special cases no longer need to be handled separately: We can do a single mask & (1 << type) check to handle all simple types, booleans (true|false) and null. --- Zend/zend_types.h | 76 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 32 deletions(-) (limited to 'Zend/zend_types.h') diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 653a07b6b2..be6c52b8ca 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -106,61 +106,73 @@ typedef void (*copy_ctor_func_t)(zval *pElement); * It shouldn't be used directly. Only through ZEND_TYPE_* macros. * * ZEND_TYPE_IS_SET() - checks if type-hint exists - * ZEND_TYPE_IS_CODE() - checks if type-hint refer to standard type + * ZEND_TYPE_IS_MASK() - checks if type-hint refer to standard type * ZEND_TYPE_IS_CLASS() - checks if type-hint refer to some class * ZEND_TYPE_IS_CE() - checks if type-hint refer to some class by zend_class_entry * * ZEND_TYPE_IS_NAME() - checks if type-hint refer to some class by zend_string * * * ZEND_TYPE_NAME() - returns referenced class name * ZEND_TYPE_CE() - returns referenced class entry - * ZEND_TYPE_CODE() - returns standard type code (e.g. IS_LONG, _IS_BOOL) + * ZEND_TYPE_MASK() - returns MAY_BE_* type mask * * ZEND_TYPE_ALLOW_NULL() - checks if NULL is allowed * - * ZEND_TYPE_ENCODE() and ZEND_TYPE_ENCODE_CLASS() should be used for - * construction. + * ZEND_TYPE_ENCODE_*() should be used for construction. */ typedef uintptr_t zend_type; +#define _ZEND_TYPE_CODE_MAX ((Z_L(1)<<(IS_VOID+1))-1) +#define _ZEND_TYPE_FLAG_MASK Z_L(0x3) +#define _ZEND_TYPE_CE_BIT Z_L(0x1) +/* Must have same value as MAY_BE_NULL */ +#define _ZEND_TYPE_NULLABLE_BIT Z_L(0x2) + #define ZEND_TYPE_IS_SET(t) \ - ((t) > Z_L(0x3)) + ((t) > _ZEND_TYPE_FLAG_MASK) -#define ZEND_TYPE_IS_CODE(t) \ - (((t) > Z_L(0x3)) && ((t) <= Z_L(0x3ff))) +#define ZEND_TYPE_IS_MASK(t) \ + (((t) > _ZEND_TYPE_FLAG_MASK) && ((t) <= _ZEND_TYPE_CODE_MAX)) #define ZEND_TYPE_IS_CLASS(t) \ - ((t) > Z_L(0x3ff)) + ((t) > _ZEND_TYPE_CODE_MAX) #define ZEND_TYPE_IS_CE(t) \ - (((t) & Z_L(0x2)) != 0) + (((t) & _ZEND_TYPE_CE_BIT) != 0) #define ZEND_TYPE_IS_NAME(t) \ (ZEND_TYPE_IS_CLASS(t) && !ZEND_TYPE_IS_CE(t)) #define ZEND_TYPE_NAME(t) \ - ((zend_string*)((t) & ~Z_L(0x3))) + ((zend_string*)((t) & ~_ZEND_TYPE_FLAG_MASK)) #define ZEND_TYPE_CE(t) \ - ((zend_class_entry*)((t) & ~Z_L(0x3))) + ((zend_class_entry*)((t) & ~_ZEND_TYPE_FLAG_MASK)) + +#define ZEND_TYPE_MASK(t) \ + (t) -#define ZEND_TYPE_CODE(t) \ - ((t) >> Z_L(2)) +#define ZEND_TYPE_CONTAINS_CODE(t, code) \ + (((t) & (1 << (code))) != 0) #define ZEND_TYPE_ALLOW_NULL(t) \ - (((t) & Z_L(0x1)) != 0) + (((t) & _ZEND_TYPE_NULLABLE_BIT) != 0) #define ZEND_TYPE_WITHOUT_NULL(t) \ - ((t) & ~Z_L(0x1)) + ((t) & ~_ZEND_TYPE_NULLABLE_BIT) -#define ZEND_TYPE_ENCODE(code, allow_null) \ - (((code) << Z_L(2)) | ((allow_null) ? Z_L(0x1) : Z_L(0x0))) +#define ZEND_TYPE_ENCODE_MASK(maybe_code) \ + (maybe_code) + +#define ZEND_TYPE_ENCODE_CODE(code, allow_null) \ + (((code) == _IS_BOOL ? (MAY_BE_FALSE|MAY_BE_TRUE) : (1 << (code))) \ + | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : Z_L(0x0))) #define ZEND_TYPE_ENCODE_CE(ce, allow_null) \ - (((uintptr_t)(ce)) | ((allow_null) ? Z_L(0x3) : Z_L(0x2))) + (((uintptr_t)(ce)) | _ZEND_TYPE_CE_BIT | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : Z_L(0x0))) #define ZEND_TYPE_ENCODE_CLASS(class_name, allow_null) \ - (((uintptr_t)(class_name)) | ((allow_null) ? Z_L(0x1) : Z_L(0x0))) + (((uintptr_t)(class_name)) | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : Z_L(0x0))) #define ZEND_TYPE_ENCODE_CLASS_CONST_0(class_name) \ ((zend_type) class_name) @@ -410,7 +422,7 @@ struct _zend_ast_ref { /*zend_ast ast; zend_ast follows the zend_ast_ref structure */ }; -/* regular data types */ +/* Regular data types: Must be in sync with zend_variables.c. */ #define IS_UNDEF 0 #define IS_NULL 1 #define IS_FALSE 2 @@ -422,21 +434,21 @@ struct _zend_ast_ref { #define IS_OBJECT 8 #define IS_RESOURCE 9 #define IS_REFERENCE 10 +#define IS_CONSTANT_AST 11 /* Constant expressions */ -/* constant expressions */ -#define IS_CONSTANT_AST 11 +/* Fake types used only for type hinting. IS_VOID should be the last. */ +#define IS_CALLABLE 12 +#define IS_ITERABLE 13 +#define IS_VOID 14 /* internal types */ -#define IS_INDIRECT 13 -#define IS_PTR 14 -#define _IS_ERROR 15 - -/* fake types used only for type hinting (Z_TYPE(zv) can not use them) */ -#define _IS_BOOL 16 -#define IS_CALLABLE 17 -#define IS_ITERABLE 18 -#define IS_VOID 19 -#define _IS_NUMBER 20 +#define IS_INDIRECT 15 +#define IS_PTR 16 +#define _IS_ERROR 17 + +/* used for casts */ +#define _IS_BOOL 18 +#define _IS_NUMBER 19 static zend_always_inline zend_uchar zval_get_type(const zval* pz) { return pz->u1.v.type; -- cgit v1.2.1