Extend ZEND_HASH_FILL_* API with ZEND_HASH_FILL_GROW and use it to optimize get_declared_classes()

This commit is contained in:
Dmitry Stogov 2021-04-06 16:18:47 +03:00
parent e10a7107a5
commit e86bea8d45
3 changed files with 34 additions and 20 deletions

View file

@ -1257,51 +1257,54 @@ ZEND_FUNCTION(restore_exception_handler)
}
/* }}} */
static inline void get_declared_class_impl(INTERNAL_FUNCTION_PARAMETERS, int flags, int skip_flags) /* {{{ */
static inline void get_declared_class_impl(INTERNAL_FUNCTION_PARAMETERS, int flags) /* {{{ */
{
zend_string *key;
zval *zv, tmp;
zval *zv;
zend_class_entry *ce;
ZEND_PARSE_PARAMETERS_NONE();
array_init(return_value);
ZEND_HASH_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
ce = Z_PTR_P(zv);
if (key
&& ZSTR_VAL(key)[0] != 0
&& (ce->ce_flags & flags)
&& !(ce->ce_flags & skip_flags)) {
if (EXPECTED(Z_TYPE_P(zv) == IS_PTR)) {
ZVAL_STR_COPY(&tmp, ce->name);
} else {
ZEND_ASSERT(Z_TYPE_P(zv) == IS_ALIAS_PTR);
ZVAL_STR_COPY(&tmp, key);
zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
ZEND_HASH_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
ce = Z_PTR_P(zv);
if ((ce->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT)) == flags
&& key
&& ZSTR_VAL(key)[0] != 0) {
ZEND_HASH_FILL_GROW();
if (EXPECTED(Z_TYPE_P(zv) == IS_PTR)) {
ZEND_HASH_FILL_SET_STR_COPY(ce->name);
} else {
ZEND_ASSERT(Z_TYPE_P(zv) == IS_ALIAS_PTR);
ZEND_HASH_FILL_SET_STR_COPY(key);
}
ZEND_HASH_FILL_NEXT();
}
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FILL_END();
}
/* {{{ */
/* {{{ Returns an array of all declared traits. */
ZEND_FUNCTION(get_declared_traits)
{
get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_TRAIT, 0);
get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED | ZEND_ACC_TRAIT);
}
/* }}} */
/* {{{ Returns an array of all declared classes. */
ZEND_FUNCTION(get_declared_classes)
{
get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED, ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT);
get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED);
}
/* }}} */
/* {{{ Returns an array of all declared interfaces. */
ZEND_FUNCTION(get_declared_interfaces)
{
get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_INTERFACE, 0);
get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED | ZEND_ACC_INTERFACE);
}
/* }}} */

View file

@ -300,7 +300,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2)
return ht;
}
static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht)
ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht)
{
HT_ASSERT_RC1(ht);
if (ht->nTableSize >= HT_MAX_SIZE) {

View file

@ -112,6 +112,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht);
ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht);
ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool packed);
ZEND_API void ZEND_FASTCALL zend_hash_discard(HashTable *ht, uint32_t nNumUsed);
ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht);
/* additions/updates/changes */
ZEND_API zval* ZEND_FASTCALL zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag);
@ -1161,6 +1162,16 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
uint32_t __fill_idx = __fill_ht->nNumUsed; \
ZEND_ASSERT(HT_FLAGS(__fill_ht) & HASH_FLAG_PACKED);
#define ZEND_HASH_FILL_GROW() do { \
if (UNEXPECTED(__fill_idx >= __fill_ht->nTableSize)) { \
__fill_ht->nNumUsed = __fill_idx; \
__fill_ht->nNumOfElements = __fill_idx; \
__fill_ht->nNextFreeElement = __fill_idx; \
zend_hash_packed_grow(__fill_ht); \
__fill_bkt = __fill_ht->arData + __fill_idx; \
} \
} while (0);
#define ZEND_HASH_FILL_SET(_val) \
ZVAL_COPY_VALUE(&__fill_bkt->val, _val)