summaryrefslogtreecommitdiff
path: root/Zend/zend_types.h
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-09-25 13:21:13 +0200
committerNikita Popov <nikita.ppv@gmail.com>2019-11-08 15:15:48 +0100
commit999e32b65a8a4bb59e27e538fa68ffae4b99d863 (patch)
tree9b6c69d032b9b69fff2f3b71f95ad2566cdf4acb /Zend/zend_types.h
parentac4e0f0852ce780e143013ceff45067a172e8a83 (diff)
downloadphp-git-999e32b65a8a4bb59e27e538fa68ffae4b99d863.tar.gz
Implement union types
According to RFC: https://wiki.php.net/rfc/union_types_v2 The type representation now makes use of both the pointer payload and the type mask at the same time. Additionall, zend_type_list is introduced as a new kind of pointer payload, which is used to store multiple class types. Each of the class types is a tagged pointer, which may be either a class name or class entry. The latter is only used for typed properties, while arguments/returns will instead use cache slots. A type list can contain a mix of both names and CEs at the same time, as not all classes may be resolvable. One thing this is missing is support for union types in arginfo and stubs, which I want to handle separately. I've also dropped the special object code from the JIT implementation for now -- I plan to add this back in a different form at a later time. For now I did not want to include non-trivial JIT changes together with large functional changes. Another possible piece of follow-up work is to implement "iterable" as an internal alias for "array|Traversable". I believe this will eliminate quite a few special-cases that had to be implemented. Closes GH-4838.
Diffstat (limited to 'Zend/zend_types.h')
-rw-r--r--Zend/zend_types.h109
1 files changed, 90 insertions, 19 deletions
diff --git a/Zend/zend_types.h b/Zend/zend_types.h
index d77fbc68a3..4bfe335e0a 100644
--- a/Zend/zend_types.h
+++ b/Zend/zend_types.h
@@ -105,11 +105,11 @@ typedef void (*copy_ctor_func_t)(zval *pElement);
* zend_type - is an abstraction layer to represent information about type hint.
* It shouldn't be used directly. Only through ZEND_TYPE_* macros.
*
- * ZEND_TYPE_IS_SET() - checks if type-hint exists
- * ZEND_TYPE_IS_ONLY_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_IS_SET() - checks if there is a type-hint
+ * ZEND_TYPE_HAS_ONLY_MASK() - checks if type-hint refer to standard type only
+ * ZEND_TYPE_HAS_CLASS() - checks if type-hint contains some class
+ * ZEND_TYPE_HAS_CE() - checks if type-hint contains some class as zend_class_entry *
+ * ZEND_TYPE_HAS_NAME() - checks if type-hint contains some class as zend_string *
*
* ZEND_TYPE_NAME() - returns referenced class name
* ZEND_TYPE_CE() - returns referenced class entry
@@ -130,25 +130,41 @@ typedef struct {
/* TODO: We could use the extra 32-bit of padding on 64-bit systems. */
} zend_type;
+typedef struct {
+ size_t num_types;
+ void *types[1];
+} zend_type_list;
+
#define _ZEND_TYPE_EXTRA_FLAGS_SHIFT 24
#define _ZEND_TYPE_MASK ((1u << 24) - 1)
#define _ZEND_TYPE_MAY_BE_MASK ((1u << (IS_VOID+1)) - 1)
-#define _ZEND_TYPE_CE_BIT (1u << 22)
+/* Only one of these bits may be set. */
#define _ZEND_TYPE_NAME_BIT (1u << 23)
+#define _ZEND_TYPE_CE_BIT (1u << 22)
+#define _ZEND_TYPE_LIST_BIT (1u << 21)
+#define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_CE_BIT|_ZEND_TYPE_NAME_BIT)
+/* Whether the type list is arena allocated */
+#define _ZEND_TYPE_ARENA_BIT (1u << 20)
/* Must have same value as MAY_BE_NULL */
#define _ZEND_TYPE_NULLABLE_BIT 0x2
#define ZEND_TYPE_IS_SET(t) \
(((t).type_mask & _ZEND_TYPE_MASK) != 0)
-#define ZEND_TYPE_IS_CLASS(t) \
- (((t.type_mask) & (_ZEND_TYPE_NAME_BIT|_ZEND_TYPE_CE_BIT)) != 0)
+#define ZEND_TYPE_HAS_CLASS(t) \
+ ((((t).type_mask) & _ZEND_TYPE_KIND_MASK) != 0)
+
+#define ZEND_TYPE_HAS_CE(t) \
+ ((((t).type_mask) & _ZEND_TYPE_CE_BIT) != 0)
-#define ZEND_TYPE_IS_CE(t) \
- (((t.type_mask) & _ZEND_TYPE_CE_BIT) != 0)
+#define ZEND_TYPE_HAS_NAME(t) \
+ ((((t).type_mask) & _ZEND_TYPE_NAME_BIT) != 0)
-#define ZEND_TYPE_IS_NAME(t) \
- (((t.type_mask) & _ZEND_TYPE_NAME_BIT) != 0)
+#define ZEND_TYPE_HAS_LIST(t) \
+ ((((t).type_mask) & _ZEND_TYPE_LIST_BIT) != 0)
+
+#define ZEND_TYPE_USES_ARENA(t) \
+ ((((t).type_mask) & _ZEND_TYPE_ARENA_BIT) != 0)
#define ZEND_TYPE_IS_ONLY_MASK(t) \
(ZEND_TYPE_IS_SET(t) && (t).ptr == NULL)
@@ -162,9 +178,63 @@ typedef struct {
#define ZEND_TYPE_CE(t) \
((zend_class_entry *) (t).ptr)
+#define ZEND_TYPE_LIST(t) \
+ ((zend_type_list *) (t).ptr)
+
+/* Type lists use the low bit to distinguish NAME and CE entries,
+ * both of which may exist in the same list. */
+#define ZEND_TYPE_LIST_IS_CE(entry) \
+ (((uintptr_t) (entry)) & 1)
+
+#define ZEND_TYPE_LIST_IS_NAME(entry) \
+ !ZEND_TYPE_LIST_IS_CE(entry)
+
+#define ZEND_TYPE_LIST_GET_NAME(entry) \
+ ((zend_string *) (entry))
+
+#define ZEND_TYPE_LIST_GET_CE(entry) \
+ ((zend_class_entry *) ((uintptr_t) (entry) & ~1))
+
+#define ZEND_TYPE_LIST_ENCODE_NAME(name) \
+ ((void *) (name))
+
+#define ZEND_TYPE_LIST_ENCODE_CE(ce) \
+ ((void *) (((uintptr_t) ce) | 1))
+
+#define ZEND_TYPE_LIST_SIZE(num_types) \
+ (sizeof(zend_type_list) + ((num_types) - 1) * sizeof(void *))
+
+#define ZEND_TYPE_LIST_FOREACH_PTR(list, entry_ptr) do { \
+ void **_list = (list)->types; \
+ void **_end = _list + (list)->num_types; \
+ for (; _list < _end; _list++) { \
+ entry_ptr = _list;
+
+#define ZEND_TYPE_LIST_FOREACH(list, entry) do { \
+ void **_list = (list)->types; \
+ void **_end = _list + (list)->num_types; \
+ for (; _list < _end; _list++) { \
+ entry = *_list;
+
+#define ZEND_TYPE_LIST_FOREACH_END() \
+ } \
+} while (0)
+
#define ZEND_TYPE_SET_PTR(t, _ptr) \
((t).ptr = (_ptr))
+#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); \
+} while (0)
+
+#define ZEND_TYPE_SET_CE(t, ce) \
+ ZEND_TYPE_SET_PTR_AND_KIND(t, ce, _ZEND_TYPE_CE_BIT)
+
+#define ZEND_TYPE_SET_LIST(t, list) \
+ ZEND_TYPE_SET_PTR_AND_KIND(t, list, _ZEND_TYPE_LIST_BIT)
+
/* FULL_MASK() includes the MAY_BE_* type mask, the CE/NAME bits, as well as extra reserved bits.
* The PURE_MASK() only includes the MAY_BE_* type mask. */
#define ZEND_TYPE_FULL_MASK(t) \
@@ -192,20 +262,21 @@ typedef struct {
{ NULL, (_type_mask) }
#define ZEND_TYPE_INIT_CODE(code, allow_null, extra_flags) \
- ZEND_TYPE_INIT_MASK(((code) == _IS_BOOL ? (MAY_BE_FALSE|MAY_BE_TRUE) : (1 << (code))) \
+ ZEND_TYPE_INIT_MASK(((code) == _IS_BOOL ? MAY_BE_BOOL : (1 << (code))) \
| ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags))
+#define ZEND_TYPE_INIT_PTR(ptr, type_kind, allow_null, extra_flags) \
+ { (void *) (ptr), \
+ (type_kind) | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags) }
+
#define ZEND_TYPE_INIT_CE(_ce, allow_null, extra_flags) \
- { (void *) (_ce), \
- _ZEND_TYPE_CE_BIT | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags) }
+ ZEND_TYPE_INIT_PTR(_ce, _ZEND_TYPE_CE_BIT, allow_null, extra_flags)
#define ZEND_TYPE_INIT_CLASS(class_name, allow_null, extra_flags) \
- { (void *) (class_name), \
- _ZEND_TYPE_NAME_BIT | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags) }
+ ZEND_TYPE_INIT_PTR(class_name, _ZEND_TYPE_NAME_BIT, allow_null, extra_flags)
#define ZEND_TYPE_INIT_CLASS_CONST(class_name, allow_null, extra_flags) \
- { (void *) (class_name), \
- _ZEND_TYPE_NAME_BIT | ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags) }
+ ZEND_TYPE_INIT_PTR(class_name, _ZEND_TYPE_NAME_BIT, allow_null, extra_flags)
typedef union _zend_value {
zend_long lval; /* long value */