summaryrefslogtreecommitdiff
path: root/Zend/zend_types.h
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-09-19 12:11:29 +0200
committerNikita Popov <nikita.ppv@gmail.com>2019-09-23 15:31:35 +0200
commit9e8ba7891e74a80265e09ff5b810ec947680c1ce (patch)
tree6550898580da2445d9d54370d2adef6e68a881b3 /Zend/zend_types.h
parent9ec2480bd6d8cadd8ca2ecac07f00fd3d411bc7a (diff)
downloadphp-git-9e8ba7891e74a80265e09ff5b810ec947680c1ce.tar.gz
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.
Diffstat (limited to 'Zend/zend_types.h')
-rw-r--r--Zend/zend_types.h76
1 files changed, 44 insertions, 32 deletions
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;