Use special flag (HASH_FLAG_INITIALIZED) instead of (nTableMask == 0) to indicate...
authorDmitry Stogov <dmitry@zend.com>
Sat, 27 Dec 2014 08:07:12 +0000 (11:07 +0300)
committerDmitry Stogov <dmitry@zend.com>
Sat, 27 Dec 2014 08:07:12 +0000 (11:07 +0300)
Make nTableMask to be 0 for packed arrays.
Remove checks fo HASH_FLAG_PACKED in zend_hash_find/zend_hash_del and family (string keys are resolved through uninitialized_bucket).
Change HashTable layout for better locality.

Zend/zend_hash.c
Zend/zend_hash.h
Zend/zend_types.h
ext/opcache/zend_accelerator_util_funcs.c
ext/opcache/zend_persist.c
ext/opcache/zend_persist_calc.c

index ca2d7e69c7401db86b8ee881b4afa442c3bd0908..8e8edc956977bc0fdfe8adefeb572dd6ad8c110f 100644 (file)
@@ -82,18 +82,19 @@ static void _zend_is_inconsistent(const HashTable *ht, const char *file, int lin
 
 static void zend_hash_do_resize(HashTable *ht);
 
-#define CHECK_INIT(ht, packed) do {                                                                                            \
-       if (UNEXPECTED((ht)->nTableMask == 0)) {                                                        \
+#define CHECK_INIT(ht, packed) do { \
+       if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) { \
                if (packed) { \
-                       (ht)->arData = (Bucket *) safe_pemalloc((ht)->nTableSize, sizeof(Bucket), 0, (ht)->u.flags & HASH_FLAG_PERSISTENT);     \
-                       (ht)->u.flags |= HASH_FLAG_PACKED; \
+                       (ht)->u.flags |= HASH_FLAG_INITIALIZED | HASH_FLAG_PACKED; \
+                       (ht)->arData = (Bucket *) safe_pemalloc((ht)->nTableSize, sizeof(Bucket), 0, (ht)->u.flags & HASH_FLAG_PERSISTENT); \
                } else { \
-                       (ht)->arData = (Bucket *) safe_pemalloc((ht)->nTableSize, sizeof(Bucket) + sizeof(uint32_t), 0, (ht)->u.flags & HASH_FLAG_PERSISTENT);  \
-                       (ht)->arHash = (uint32_t*)((ht)->arData + (ht)->nTableSize);    \
-                       memset((ht)->arHash, INVALID_IDX, (ht)->nTableSize * sizeof(uint32_t)); \
+                       (ht)->u.flags |= HASH_FLAG_INITIALIZED; \
+                       (ht)->nTableMask = (ht)->nTableSize - 1; \
+                       (ht)->arData = (Bucket *) safe_pemalloc((ht)->nTableSize, sizeof(Bucket) + sizeof(uint32_t), 0, (ht)->u.flags & HASH_FLAG_PERSISTENT); \
+                       (ht)->arHash = (uint32_t*)((ht)->arData + (ht)->nTableSize); \
+                       memset((ht)->arHash, INVALID_IDX, (ht)->nTableSize * sizeof(uint32_t)); \
                } \
-               (ht)->nTableMask = (ht)->nTableSize - 1;                                                \
-       }                                                                                                                                       \
+       } \
 } while (0)
  
 static const uint32_t uninitialized_bucket = {INVALID_IDX};
@@ -129,7 +130,7 @@ ZEND_API void _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestru
 # endif
 #endif
 
-       ht->nTableMask = 0;     /* 0 means that ht->arBuckets is uninitialized */
+       ht->nTableMask = 0;
        ht->nNumUsed = 0;
        ht->nNumOfElements = 0;
        ht->nNextFreeElement = 0;
@@ -145,7 +146,6 @@ static void zend_hash_packed_grow(HashTable *ht)
        HANDLE_BLOCK_INTERRUPTIONS();
        ht->arData = (Bucket *) safe_perealloc(ht->arData, (ht->nTableSize << 1), sizeof(Bucket), 0, ht->u.flags & HASH_FLAG_PERSISTENT);
        ht->nTableSize = (ht->nTableSize << 1);
-       ht->nTableMask = ht->nTableSize - 1;
        HANDLE_UNBLOCK_INTERRUPTIONS();
 }
 
@@ -170,6 +170,7 @@ ZEND_API void zend_hash_to_packed(HashTable *ht)
 {
        HANDLE_BLOCK_INTERRUPTIONS();
        ht->u.flags |= HASH_FLAG_PACKED;
+       ht->nTableMask = 0;
        ht->arData = erealloc(ht->arData, ht->nTableSize * sizeof(Bucket));
        ht->arHash = (uint32_t*)&uninitialized_bucket;
        HANDLE_UNBLOCK_INTERRUPTIONS();
@@ -267,7 +268,7 @@ static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_s
 
        IS_CONSISTENT(ht);
 
-       if (UNEXPECTED(ht->nTableMask == 0)) {
+       if (UNEXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
                CHECK_INIT(ht, 0);
                goto add_to_hash; 
        } else if (ht->u.flags & HASH_FLAG_PACKED) {
@@ -418,7 +419,7 @@ static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht,
 
        IS_CONSISTENT(ht);
 
-       if (UNEXPECTED(ht->nTableMask == 0)) {
+       if (UNEXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
                CHECK_INIT(ht, h < ht->nTableSize);
                if (h < ht->nTableSize) {
                        p = ht->arData + h;
@@ -587,7 +588,7 @@ ZEND_API int zend_hash_rehash(HashTable *ht)
        IS_CONSISTENT(ht);
 
        if (UNEXPECTED(ht->nNumOfElements == 0)) {
-               if (ht->nTableMask) {
+               if (ht->u.flags & HASH_FLAG_INITIALIZED) {
                        memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));
                }
                return SUCCESS;
@@ -684,10 +685,6 @@ ZEND_API int zend_hash_del(HashTable *ht, zend_string *key)
 
        IS_CONSISTENT(ht);
 
-       if (ht->u.flags & HASH_FLAG_PACKED) {
-               return FAILURE;
-       }
-
        h = zend_string_hash_val(key);
        nIndex = h & ht->nTableMask;
 
@@ -718,10 +715,6 @@ ZEND_API int zend_hash_del_ind(HashTable *ht, zend_string *key)
 
        IS_CONSISTENT(ht);
 
-       if (ht->u.flags & HASH_FLAG_PACKED) {
-               return FAILURE;
-       }
-
        h = zend_string_hash_val(key);
        nIndex = h & ht->nTableMask;
 
@@ -765,10 +758,6 @@ ZEND_API int zend_hash_str_del(HashTable *ht, const char *str, size_t len)
 
        IS_CONSISTENT(ht);
 
-       if (ht->u.flags & HASH_FLAG_PACKED) {
-               return FAILURE;
-       }
-
        h = zend_inline_hash_func(str, len);
        nIndex = h & ht->nTableMask;
 
@@ -905,7 +894,7 @@ ZEND_API void zend_hash_destroy(HashTable *ht)
                                } while (++p != end);
                        }
                }
-       } else if (EXPECTED(!ht->nTableMask)) {
+       } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
                return;
        }
        pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
@@ -947,7 +936,7 @@ ZEND_API void zend_array_destroy(HashTable *ht)
                }
                
                SET_INCONSISTENT(HT_DESTROYED);
-       } else if (EXPECTED(!ht->nTableMask)) {
+       } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
                return;
        }
        pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
@@ -990,16 +979,14 @@ ZEND_API void zend_hash_clean(HashTable *ht)
                                } while (++p != end);
                        }
                }
+               if (!(ht->u.flags & HASH_FLAG_PACKED)) {
+                       memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));     
+               }
        }
        ht->nNumUsed = 0;
        ht->nNumOfElements = 0;
        ht->nNextFreeElement = 0;
        ht->nInternalPointer = INVALID_IDX;
-       if (ht->nTableMask) {
-               if (!(ht->u.flags & HASH_FLAG_PACKED)) {
-                       memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));     
-               }
-       }
 }
 
 ZEND_API void zend_symtable_clean(HashTable *ht)
@@ -1019,16 +1006,14 @@ ZEND_API void zend_symtable_clean(HashTable *ht)
                                }
                        }
                } while (++p != end);
+               if (!(ht->u.flags & HASH_FLAG_PACKED)) {
+                       memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));     
+               }
        }
        ht->nNumUsed = 0;
        ht->nNumOfElements = 0;
        ht->nNextFreeElement = 0;
        ht->nInternalPointer = INVALID_IDX;
-       if (ht->nTableMask) {
-               if (!(ht->u.flags & HASH_FLAG_PACKED)) {
-                       memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));     
-               }
-       }
 }
 
 ZEND_API void zend_hash_graceful_destroy(HashTable *ht)
@@ -1043,7 +1028,7 @@ ZEND_API void zend_hash_graceful_destroy(HashTable *ht)
                if (Z_TYPE(p->val) == IS_UNDEF) continue;
                _zend_hash_del_el(ht, idx, p);
        }
-       if (ht->nTableMask) {
+       if (ht->u.flags & HASH_FLAG_INITIALIZED) {
                pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
        }
 
@@ -1065,7 +1050,7 @@ ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht)
                _zend_hash_del_el(ht, idx, p);
        }
 
-       if (ht->nTableMask) {
+       if (ht->u.flags & HASH_FLAG_INITIALIZED) {
                pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
        }
 
@@ -1257,7 +1242,7 @@ ZEND_API void zend_array_dup(HashTable *target, HashTable *source)
        target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
 
        target_idx = 0;
-       if (target->nTableMask) {
+       if (target->u.flags & HASH_FLAG_INITIALIZED) {
                if (target->u.flags & HASH_FLAG_PACKED) {
                        target->nNumUsed = source->nNumUsed;
                        target->nNumOfElements = source->nNumOfElements;
@@ -1448,10 +1433,6 @@ ZEND_API zval *zend_hash_find(const HashTable *ht, zend_string *key)
 
        IS_CONSISTENT(ht);
 
-       if (ht->u.flags & HASH_FLAG_PACKED) {
-               return NULL;
-       }
-
        p = zend_hash_find_bucket(ht, key);
        return p ? &p->val : NULL;
 }
@@ -1463,10 +1444,6 @@ ZEND_API zval *zend_hash_str_find(const HashTable *ht, const char *str, size_t l
 
        IS_CONSISTENT(ht);
 
-       if (ht->u.flags & HASH_FLAG_PACKED) {
-               return NULL;
-       }
-
        h = zend_inline_hash_func(str, len);
        p = zend_hash_str_find_bucket(ht, str, len, h);
        return p ? &p->val : NULL;
@@ -1478,10 +1455,6 @@ ZEND_API zend_bool zend_hash_exists(const HashTable *ht, zend_string *key)
 
        IS_CONSISTENT(ht);
 
-       if (ht->u.flags & HASH_FLAG_PACKED) {
-               return 0;
-       }
-
        p = zend_hash_find_bucket(ht, key);
        return p ? 1 : 0;
 }
@@ -1493,10 +1466,6 @@ ZEND_API zend_bool zend_hash_str_exists(const HashTable *ht, const char *str, si
 
        IS_CONSISTENT(ht);
 
-       if (ht->u.flags & HASH_FLAG_PACKED) {
-               return 0;
-       }
-
        h = zend_inline_hash_func(str, len);
        p = zend_hash_str_find_bucket(ht, str, len, h);
        return p ? 1 : 0;
@@ -1744,6 +1713,7 @@ ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func,
        } else {
                if (renumber) {
                        ht->u.flags |= HASH_FLAG_PACKED;
+                       ht->nTableMask = 0;
                        ht->arData = erealloc(ht->arData, ht->nTableSize * sizeof(Bucket));
                        ht->arHash = (uint32_t*)&uninitialized_bucket;
                } else {
index fd03050947a42f85f8c60ac5737e1d60fa91750e..8f51b1e39f49fd0dcac80a77cf64146f6800cafa 100644 (file)
@@ -39,6 +39,7 @@
 #define HASH_FLAG_PERSISTENT       (1<<0)
 #define HASH_FLAG_APPLY_PROTECTION (1<<1)
 #define HASH_FLAG_PACKED           (1<<2)
+#define HASH_FLAG_INITIALIZED      (1<<3)
 
 #define HASH_MASK_CONSISTENCY      0x60
 
index 28885db75aeb1cae4288067baa85a2bee6437e84..faf54c556fb59fd18a92f201f6836fd22d8096e8 100644 (file)
@@ -157,15 +157,6 @@ typedef struct _Bucket {
 } Bucket;
 
 typedef struct _HashTable {    
-       uint32_t          nTableSize;
-       uint32_t          nTableMask;
-       uint32_t          nNumUsed;
-       uint32_t          nNumOfElements;
-       zend_long         nNextFreeElement;
-       Bucket           *arData;
-       uint32_t         *arHash;
-       dtor_func_t       pDestructor;
-       uint32_t          nInternalPointer; 
        union {
                struct {
                        ZEND_ENDIAN_LOHI_3(
@@ -175,6 +166,15 @@ typedef struct _HashTable {
                } v;
                uint32_t flags;
        } u;
+       uint32_t          nTableSize;
+       uint32_t          nTableMask;
+       uint32_t          nNumUsed;
+       uint32_t          nNumOfElements;
+       uint32_t          nInternalPointer; 
+       zend_long         nNextFreeElement;
+       Bucket           *arData;
+       uint32_t         *arHash;
+       dtor_func_t       pDestructor;
 } HashTable;
 
 struct _zend_array {
index 860e18a299f84b9923fe01e3ed49bf15a2288c06..41d6052b7f756b17d214bd00ed3c5266c31cb21e 100644 (file)
@@ -301,12 +301,12 @@ static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind)
        ht->nNumOfElements = source->nNumOfElements;
        ht->nNextFreeElement = source->nNextFreeElement;
        ht->pDestructor = ZVAL_PTR_DTOR;
-       ht->u.flags = HASH_FLAG_APPLY_PROTECTION;
+       ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED) | HASH_FLAG_APPLY_PROTECTION;
        ht->arData = NULL;
        ht->arHash = NULL;
        ht->nInternalPointer = source->nNumOfElements ? 0 : INVALID_IDX;
 
-       if (!ht->nTableMask) {
+       if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
                ht->arHash = (uint32_t*)&uninitialized_bucket;
                return;
        }
@@ -382,10 +382,10 @@ static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class
        ht->nNumOfElements = source->nNumOfElements;
        ht->nNextFreeElement = source->nNextFreeElement;
        ht->pDestructor = ZEND_FUNCTION_DTOR;
-       ht->u.flags = 0;
+       ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
        ht->nInternalPointer = source->nNumOfElements ? 0 : INVALID_IDX;
 
-       if (!ht->nTableMask) {
+       if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
                ht->arHash = (uint32_t*)&uninitialized_bucket;
                return;
        }
@@ -458,10 +458,10 @@ static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_cla
        ht->nNumOfElements = source->nNumOfElements;
        ht->nNextFreeElement = source->nNextFreeElement;
        ht->pDestructor = zend_destroy_property_info;
-       ht->u.flags = 0;
+       ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
        ht->nInternalPointer = source->nNumOfElements ? 0 : INVALID_IDX;
 
-       if (!ht->nTableMask) {
+       if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
                ht->arHash = (uint32_t*)&uninitialized_bucket;
                return;
        }
index 53811f626ef75b067853b34bf5083dd2b345bc37..d9e8765c34d07b941475cf0ed7cb9652bda980b7 100644 (file)
@@ -74,7 +74,7 @@ static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement
        uint idx;
        Bucket *p;
 
-       if (!ht->nTableMask) {
+       if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
                ht->arHash = (uint32_t*)&uninitialized_bucket;
                return;
        }
@@ -111,7 +111,7 @@ static void zend_hash_persist_immutable(HashTable *ht)
        uint idx;
        Bucket *p;
 
-       if (!ht->nTableMask) {
+       if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
                ht->arHash = (uint32_t*)&uninitialized_bucket;
                return;
        }
index f3fb7c081d65a04a1758bea99ff2bceebd711212..f06a871d084f537ecc24ee47c88747c772263abb 100644 (file)
@@ -54,7 +54,7 @@ static void zend_hash_persist_calc(HashTable *ht, void (*pPersistElement)(zval *
        uint idx;
        Bucket *p;
 
-       if (!ht->nTableMask) {
+       if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
                return;
        }
        if (ht->u.flags & HASH_FLAG_PACKED) {