From 340013ad01aa6bda92c6c71080f315fc63c9841c Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 19 Mar 2021 22:36:24 +0300 Subject: Add zend_hash_lookup() and zend_hash_index_lookup() functions. Thet search for an element with given key/index and add an empty one (NULL), if no found. --- Zend/zend_execute.c | 81 +++++++++++++++++++++++++++-------------------------- Zend/zend_hash.c | 42 +++++++++++++++++++++++---- Zend/zend_hash.h | 17 +++++++++++ 3 files changed, 96 insertions(+), 44 deletions(-) (limited to 'Zend') diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 39862a2425..f34e1930e2 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2121,59 +2121,62 @@ try_again: if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) { hval = Z_LVAL_P(dim); num_index: - ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef); - return retval; + if (type != BP_VAR_W) { + ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef); + return retval; num_undef: - switch (type) { - case BP_VAR_R: - zend_undefined_offset(hval); - /* break missing intentionally */ - case BP_VAR_UNSET: - case BP_VAR_IS: - retval = &EG(uninitialized_zval); - break; - case BP_VAR_RW: - if (UNEXPECTED(zend_undefined_offset_write(ht, hval) == FAILURE)) { - return NULL; - } - /* break missing intentionally */ - case BP_VAR_W: - retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval)); - break; - } - } else if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) { - offset_key = Z_STR_P(dim); - if (ZEND_CONST_COND(dim_type != IS_CONST, 1)) { - if (ZEND_HANDLE_NUMERIC(offset_key, hval)) { - goto num_index; - } - } -str_index: - retval = zend_hash_find_ex(ht, offset_key, ZEND_CONST_COND(dim_type == IS_CONST, 0)); - if (!retval) { switch (type) { case BP_VAR_R: - zend_undefined_index(offset_key); + zend_undefined_offset(hval); /* break missing intentionally */ case BP_VAR_UNSET: case BP_VAR_IS: retval = &EG(uninitialized_zval); break; case BP_VAR_RW: - /* Key may be released while throwing the undefined index warning. */ - zend_string_addref(offset_key); - if (UNEXPECTED(zend_undefined_index_write(ht, offset_key) == FAILURE)) { - zend_string_release(offset_key); + if (UNEXPECTED(zend_undefined_offset_write(ht, hval) == FAILURE)) { return NULL; } - retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval)); - zend_string_release(offset_key); - break; - case BP_VAR_W: - retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval)); + retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval)); break; + } + } else { + ZEND_HASH_INDEX_LOOKUP(ht, hval, retval); + } + } else if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) { + offset_key = Z_STR_P(dim); + if (ZEND_CONST_COND(dim_type != IS_CONST, 1)) { + if (ZEND_HANDLE_NUMERIC(offset_key, hval)) { + goto num_index; } } +str_index: + if (type != BP_VAR_W) { + retval = zend_hash_find_ex(ht, offset_key, ZEND_CONST_COND(dim_type == IS_CONST, 0)); + if (!retval) { + switch (type) { + case BP_VAR_R: + zend_undefined_index(offset_key); + /* break missing intentionally */ + case BP_VAR_UNSET: + case BP_VAR_IS: + retval = &EG(uninitialized_zval); + break; + case BP_VAR_RW: + /* Key may be released while throwing the undefined index warning. */ + zend_string_addref(offset_key); + if (UNEXPECTED(zend_undefined_index_write(ht, offset_key) == FAILURE)) { + zend_string_release(offset_key); + return NULL; + } + retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval)); + zend_string_release(offset_key); + break; + } + } + } else { + retval = zend_hash_lookup(ht, offset_key); + } } else if (EXPECTED(Z_TYPE_P(dim) == IS_REFERENCE)) { dim = Z_REFVAL_P(dim); goto try_again; diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 8d3c7640bf..e52939b1eb 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -748,7 +748,9 @@ static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_s zval *data; ZEND_ASSERT((flag & HASH_ADD_NEW) == 0); - if (flag & HASH_ADD) { + if (flag & HASH_LOOKUP) { + return &p->val; + } else if (flag & HASH_ADD) { if (!(flag & HASH_UPDATE_INDIRECT)) { return NULL; } @@ -793,7 +795,11 @@ add_to_hash: nIndex = h | ht->nTableMask; Z_NEXT(p->val) = HT_HASH_EX(arData, nIndex); HT_HASH_EX(arData, nIndex) = HT_IDX_TO_HASH(idx); - ZVAL_COPY_VALUE(&p->val, pData); + if (flag & HASH_LOOKUP) { + ZVAL_NULL(&p->val); + } else { + ZVAL_COPY_VALUE(&p->val, pData); + } return &p->val; } @@ -821,7 +827,9 @@ static zend_always_inline zval *_zend_hash_str_add_or_update_i(HashTable *ht, co if (p) { zval *data; - if (flag & HASH_ADD) { + if (flag & HASH_LOOKUP) { + return &p->val; + } else if (flag & HASH_ADD) { if (!(flag & HASH_UPDATE_INDIRECT)) { return NULL; } @@ -859,7 +867,11 @@ add_to_hash: p->key = key = zend_string_init(str, len, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); p->h = ZSTR_H(key) = h; HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS; - ZVAL_COPY_VALUE(&p->val, pData); + if (flag & HASH_LOOKUP) { + ZVAL_NULL(&p->val); + } else { + ZVAL_COPY_VALUE(&p->val, pData); + } nIndex = h | ht->nTableMask; Z_NEXT(p->val) = HT_HASH(ht, nIndex); HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx); @@ -901,6 +913,11 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key, return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW); } +ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key) +{ + return _zend_hash_add_or_update_i(ht, key, NULL, HASH_LOOKUP); +} + ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_or_update(HashTable *ht, const char *str, size_t len, zval *pData, uint32_t flag) { if (flag == HASH_ADD) { @@ -984,6 +1001,9 @@ static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, if (h < ht->nNumUsed) { p = ht->arData + h; if (Z_TYPE(p->val) != IS_UNDEF) { + if (flag & HASH_LOOKUP) { + return &p->val; + } replace: if (flag & HASH_ADD) { return NULL; @@ -1032,6 +1052,9 @@ convert_to_hash: if ((flag & HASH_ADD_NEW) == 0 || ZEND_DEBUG) { p = zend_hash_index_find_bucket(ht, h); if (p) { + if (flag & HASH_LOOKUP) { + return &p->val; + } ZEND_ASSERT((flag & HASH_ADD_NEW) == 0); goto replace; } @@ -1051,7 +1074,11 @@ add: ht->nNumOfElements++; p->h = h; p->key = NULL; - ZVAL_COPY_VALUE(&p->val, pData); + if (flag & HASH_LOOKUP) { + ZVAL_NULL(&p->val); + } else { + ZVAL_COPY_VALUE(&p->val, pData); + } return &p->val; } @@ -1099,6 +1126,11 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEW | HASH_ADD_NEXT); } +ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h) +{ + return _zend_hash_index_add_or_update_i(ht, h, NULL, HASH_LOOKUP); +} + ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *b, zend_string *key) { uint32_t nIndex; diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 64a9220573..25d48f6237 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -32,6 +32,7 @@ #define HASH_UPDATE_INDIRECT (1<<2) #define HASH_ADD_NEW (1<<3) #define HASH_ADD_NEXT (1<<4) +#define HASH_LOOKUP (1<<5) #define HASH_FLAG_CONSISTENCY ((1<<0) | (1<<1)) #define HASH_FLAG_PACKED (1<<2) @@ -206,6 +207,22 @@ static zend_always_inline zval *zend_hash_find_ex(const HashTable *ht, zend_stri } while (0) +/* Find or add NULL, if doesn't exist */ +ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key); +ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h); + +#define ZEND_HASH_INDEX_LOOKUP(_ht, _h, _ret) do { \ + if (EXPECTED(HT_FLAGS(_ht) & HASH_FLAG_PACKED)) { \ + if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) { \ + _ret = &_ht->arData[_h].val; \ + if (EXPECTED(Z_TYPE_P(_ret) != IS_UNDEF)) { \ + break; \ + } \ + } \ + } \ + _ret = zend_hash_index_lookup(_ht, _h); \ + } while (0) + /* Misc */ static zend_always_inline bool zend_hash_exists(const HashTable *ht, zend_string *key) { -- cgit v1.2.1