Use more compact representation for packed arrays.

- for packed arrays we store just an array of zvals without keys.
- the elements of packed array are accessible throuf as ht->arPacked[i]
  instead of ht->arData[i]
- in addition to general ZEND_HASH_FOREACH_* macros, we introduced similar
  familied for packed (ZEND_HASH_PACKED_FORECH_*) and real hashes
  (ZEND_HASH_MAP_FOREACH_*)
- introduced an additional family of macros to access elements of array
  (packed or real hashes) ZEND_ARRAY_ELEMET_SIZE, ZEND_ARRAY_ELEMET_EX,
  ZEND_ARRAY_ELEMET, ZEND_ARRAY_NEXT_ELEMENT, ZEND_ARRAY_PREV_ELEMENT
- zend_hash_minmax() prototype was changed to compare only values

Because of smaller data set, this patch may show performance improvement
on some apps and benchmarks that use packed arrays. (~1% on PHP-Parser)

TODO:
    - sapi/phpdbg needs special support for packed arrays (WATCH_ON_BUCKET).
    - zend_hash_sort_ex() may require converting packed arrays to hash.
This commit is contained in:
Dmitry Stogov 2021-11-03 15:18:26 +03:00
parent 0eb603e3bb
commit 90b7bde615
89 changed files with 3302 additions and 1664 deletions

View file

@ -669,7 +669,7 @@ static void add_class_vars(zend_class_entry *scope, zend_class_entry *ce, bool s
zend_string *key;
zval *default_properties_table = CE_DEFAULT_PROPERTIES_TABLE(ce);
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
if (((prop_info->flags & ZEND_ACC_PROTECTED) &&
!zend_check_protected(prop_info->ce, scope)) ||
((prop_info->flags & ZEND_ACC_PRIVATE) &&
@ -758,7 +758,7 @@ ZEND_FUNCTION(get_object_vars)
} else {
array_init_size(return_value, zend_hash_num_elements(properties));
ZEND_HASH_FOREACH_KEY_VAL(properties, num_key, key, value) {
ZEND_HASH_MAP_FOREACH_KEY_VAL(properties, num_key, key, value) {
bool is_dynamic = 1;
if (Z_TYPE_P(value) == IS_INDIRECT) {
value = Z_INDIRECT_P(value);
@ -838,7 +838,7 @@ ZEND_FUNCTION(get_class_methods)
array_init(return_value);
scope = zend_get_executed_scope();
ZEND_HASH_FOREACH_PTR(&ce->function_table, mptr) {
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, mptr) {
if ((mptr->common.fn_flags & ZEND_ACC_PUBLIC)
|| (scope &&
(((mptr->common.fn_flags & ZEND_ACC_PROTECTED) &&
@ -1094,7 +1094,7 @@ ZEND_FUNCTION(get_included_files)
ZEND_PARSE_PARAMETERS_NONE();
array_init(return_value);
ZEND_HASH_FOREACH_STR_KEY(&EG(included_files), entry) {
ZEND_HASH_MAP_FOREACH_STR_KEY(&EG(included_files), entry) {
if (entry) {
add_next_index_str(return_value, zend_string_copy(entry));
}
@ -1248,7 +1248,7 @@ static inline void get_declared_class_impl(INTERNAL_FUNCTION_PARAMETERS, int fla
array_init(return_value);
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) {
ZEND_HASH_MAP_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
@ -1309,7 +1309,7 @@ ZEND_FUNCTION(get_defined_functions)
array_init(&user);
array_init(return_value);
ZEND_HASH_FOREACH_STR_KEY_PTR(EG(function_table), key, func) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(function_table), key, func) {
if (key && ZSTR_VAL(key)[0] != 0) {
if (func->type == ZEND_INTERNAL_FUNCTION) {
add_next_index_str(&internal, zend_string_copy(key));
@ -1455,7 +1455,7 @@ ZEND_FUNCTION(get_loaded_extensions)
} else {
zend_module_entry *module;
ZEND_HASH_FOREACH_PTR(&module_registry, module) {
ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
add_next_index_string(return_value, module->name);
} ZEND_HASH_FOREACH_END();
}
@ -1485,13 +1485,13 @@ ZEND_FUNCTION(get_defined_constants)
module_names = emalloc((zend_hash_num_elements(&module_registry) + 2) * sizeof(char *));
module_names[0] = "internal";
ZEND_HASH_FOREACH_PTR(&module_registry, module) {
ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
module_names[module->module_number] = (char *)module->name;
i++;
} ZEND_HASH_FOREACH_END();
module_names[i] = "user";
ZEND_HASH_FOREACH_PTR(EG(zend_constants), val) {
ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), val) {
if (!val->name) {
/* skip special constants */
continue;
@ -1521,7 +1521,7 @@ ZEND_FUNCTION(get_defined_constants)
zend_constant *constant;
zval const_val;
ZEND_HASH_FOREACH_PTR(EG(zend_constants), constant) {
ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) {
if (!constant->name) {
/* skip special constants */
continue;
@ -1606,7 +1606,7 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /
zend_string *name;
zval *arg;
SEPARATE_ARRAY(arg_array);
ZEND_HASH_FOREACH_STR_KEY_VAL(call->extra_named_params, name, arg) {
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(call->extra_named_params, name, arg) {
ZVAL_DEREF(arg);
Z_TRY_ADDREF_P(arg);
zend_hash_add_new(Z_ARRVAL_P(arg_array), name, arg);
@ -1902,7 +1902,7 @@ ZEND_FUNCTION(get_extension_funcs)
array = 0;
}
ZEND_HASH_FOREACH_PTR(CG(function_table), zif) {
ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), zif) {
if (zif->common.type == ZEND_INTERNAL_FUNCTION
&& zif->internal_function.module == module) {
if (!array) {