From 9ded1b4edbb140520e060de597267b3cb439f4c4 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 19 Oct 2016 23:10:42 +0300 Subject: [PATCH] Introduced HT_IS_PACKED() and HT_IS_WITHOUT_HOLES() macros. (Benjamin Coutu) --- Zend/zend_hash.c | 48 ++++++++++++++++++++--------------------- Zend/zend_hash.h | 11 ++++++++-- Zend/zend_types.h | 2 +- ext/json/json_encoder.c | 4 ++++ ext/soap/php_encoding.c | 4 ++++ ext/standard/array.c | 4 +++- 6 files changed, 44 insertions(+), 29 deletions(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index ec9a5ba486..fdbdcac5a0 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -34,9 +34,7 @@ #define HT_POISONED_PTR ((HashTable *) (intptr_t) -1) #if ZEND_DEBUG -/* -#define HASH_MASK_CONSISTENCY 0xc0 -*/ + #define HT_OK 0x00 #define HT_IS_DESTROYING 0x40 #define HT_DESTROYED 0x80 @@ -44,10 +42,10 @@ static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line) { - if ((ht->u.flags & HASH_MASK_CONSISTENCY) == HT_OK) { + if (ht->u.v.consistency == HT_OK) { return; } - switch ((ht->u.flags & HASH_MASK_CONSISTENCY)) { + switch (ht->u.v.consistency) { case HT_IS_DESTROYING: zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht); break; @@ -65,7 +63,7 @@ static void _zend_is_inconsistent(const HashTable *ht, const char *file, int lin } #define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__); #define SET_INCONSISTENT(n) do { \ - (ht)->u.flags |= n; \ + (ht)->u.v.consistency = n; \ } while (0) #else #define IS_CONSISTENT(a) @@ -891,7 +889,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht) HT_HASH_RESET(ht); i = 0; p = ht->arData; - if (ht->nNumUsed == ht->nNumOfElements) { + if (HT_IS_WITHOUT_HOLES(ht)) { do { nIndex = p->h | ht->nTableMask; Z_NEXT(p->val) = HT_HASH(ht, nIndex); @@ -1232,8 +1230,8 @@ ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht) if (ht->pDestructor) { SET_INCONSISTENT(HT_IS_DESTROYING); - if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) { - if (ht->nNumUsed == ht->nNumOfElements) { + if (HT_HAS_STATIC_KEYS_ONLY(ht)) { + if (HT_IS_WITHOUT_HOLES(ht)) { do { ht->pDestructor(&p->val); } while (++p != end); @@ -1244,7 +1242,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht) } } while (++p != end); } - } else if (ht->nNumUsed == ht->nNumOfElements) { + } else if (HT_IS_WITHOUT_HOLES(ht)) { do { ht->pDestructor(&p->val); if (EXPECTED(p->key)) { @@ -1264,7 +1262,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht) SET_INCONSISTENT(HT_DESTROYED); } else { - if (!(ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS))) { + if (!HT_HAS_STATIC_KEYS_ONLY(ht)) { do { if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) { if (EXPECTED(p->key)) { @@ -1303,11 +1301,11 @@ ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht) end = p + ht->nNumUsed; SET_INCONSISTENT(HT_IS_DESTROYING); - if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) { + if (HT_HAS_STATIC_KEYS_ONLY(ht)) { do { i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC); } while (++p != end); - } else if (ht->nNumUsed == ht->nNumOfElements) { + } else if (HT_IS_WITHOUT_HOLES(ht)) { do { i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC); if (EXPECTED(p->key)) { @@ -1345,8 +1343,8 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht) p = ht->arData; end = p + ht->nNumUsed; if (ht->pDestructor) { - if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) { - if (ht->nNumUsed == ht->nNumOfElements) { + if (HT_HAS_STATIC_KEYS_ONLY(ht)) { + if (HT_IS_WITHOUT_HOLES(ht)) { do { ht->pDestructor(&p->val); } while (++p != end); @@ -1357,7 +1355,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht) } } while (++p != end); } - } else if (ht->nNumUsed == ht->nNumOfElements) { + } else if (HT_IS_WITHOUT_HOLES(ht)) { do { ht->pDestructor(&p->val); if (EXPECTED(p->key)) { @@ -1375,8 +1373,8 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht) } while (++p != end); } } else { - if (!(ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS))) { - if (ht->nNumUsed == ht->nNumOfElements) { + if (!HT_HAS_STATIC_KEYS_ONLY(ht)) { + if (HT_IS_WITHOUT_HOLES(ht)) { do { if (EXPECTED(p->key)) { zend_string_release(p->key); @@ -1413,11 +1411,11 @@ ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht) if (ht->nNumUsed) { p = ht->arData; end = p + ht->nNumUsed; - if (ht->u.flags & HASH_FLAG_STATIC_KEYS) { + if (HT_HAS_STATIC_KEYS_ONLY(ht)) { do { i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC); } while (++p != end); - } else if (ht->nNumUsed == ht->nNumOfElements) { + } else if (HT_IS_WITHOUT_HOLES(ht)) { do { i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC); if (EXPECTED(p->key)) { @@ -1805,7 +1803,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source) target->nInternalPointer = source->nInternalPointer; HT_HASH_RESET_PACKED(target); - if (target->nNumUsed == target->nNumOfElements) { + if (HT_IS_WITHOUT_HOLES(target)) { zend_array_dup_packed_elements(source, target, 0); } else { zend_array_dup_packed_elements(source, target, 1); @@ -1826,14 +1824,14 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source) HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target))); HT_HASH_RESET(target); - if (target->u.flags & HASH_FLAG_STATIC_KEYS) { - if (source->nNumUsed == source->nNumOfElements) { + if (HT_HAS_STATIC_KEYS_ONLY(target)) { + if (HT_IS_WITHOUT_HOLES(source)) { idx = zend_array_dup_elements(source, target, 1, 0); } else { idx = zend_array_dup_elements(source, target, 1, 1); } } else { - if (source->nNumUsed == source->nNumOfElements) { + if (HT_IS_WITHOUT_HOLES(source)) { idx = zend_array_dup_elements(source, target, 0, 0); } else { idx = zend_array_dup_elements(source, target, 0, 1); @@ -2256,7 +2254,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, co return SUCCESS; } - if (ht->nNumUsed == ht->nNumOfElements) { + if (HT_IS_WITHOUT_HOLES(ht)) { i = ht->nNumUsed; } else { for (j = 0, i = 0; j < ht->nNumUsed; j++) { diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index b7e6f37f71..190551d3f1 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -39,10 +39,17 @@ #define HASH_FLAG_APPLY_PROTECTION (1<<1) #define HASH_FLAG_PACKED (1<<2) #define HASH_FLAG_INITIALIZED (1<<3) -#define HASH_FLAG_STATIC_KEYS (1<<4) +#define HASH_FLAG_STATIC_KEYS (1<<4) /* long and interned strings */ #define HASH_FLAG_HAS_EMPTY_IND (1<<5) -#define HASH_MASK_CONSISTENCY 0xc0 +#define HT_IS_PACKED(ht) \ + (((ht)->u.flags & HASH_FLAG_PACKED) != 0) + +#define HT_IS_WITHOUT_HOLES(ht) \ + ((ht)->nNumUsed == (ht)->nNumOfElements) + +#define HT_HAS_STATIC_KEYS_ONLY(ht) \ + (((ht)->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) != 0) typedef struct _zend_hash_key { zend_ulong h; diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 29dec8e97f..2a108877bf 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -182,7 +182,7 @@ struct _zend_array { zend_uchar flags, zend_uchar nApplyCount, zend_uchar nIteratorsCount, - zend_uchar reserve) + zend_uchar consistency) } v; uint32_t flags; } u; diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index f94674831a..473726c569 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -45,6 +45,10 @@ static int php_json_determine_array_type(zval *val) /* {{{ */ zend_string *key; zend_ulong index, idx; + if (HT_IS_PACKED(myht) && HT_IS_WITHOUT_HOLES(myht)) { + return PHP_JSON_OUTPUT_ARRAY; + } + idx = 0; ZEND_HASH_FOREACH_KEY(myht, index, key) { if (key) { diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index c0e22d741b..c6a3f865cb 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -3483,6 +3483,10 @@ static int is_map(zval *array) zend_string *key; zend_ulong i = 0; + if (HT_IS_PACKED(Z_ARRVAL_P(array)) && HT_IS_WITHOUT_HOLES(Z_ARRVAL_P(array))) { + return FALSE; + } + ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(array), index, key) { if (key || index != i) { return TRUE; diff --git a/ext/standard/array.c b/ext/standard/array.c index 078b84ab8f..8cf417bcfa 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2909,7 +2909,9 @@ PHP_FUNCTION(array_slice) /* Start at the beginning and go until we hit offset */ pos = 0; - if ((Z_ARRVAL_P(input)->u.flags & HASH_FLAG_PACKED) && !preserve_keys) { + if (HT_IS_PACKED(Z_ARRVAL_P(input)) && + (!preserve_keys || + (offset == 0 && HT_IS_WITHOUT_HOLES(Z_ARRVAL_P(input))))) { zend_hash_real_init(Z_ARRVAL_P(return_value), 1); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) { -- 2.40.0