Skip to content

Commit

Permalink
Use more compact representation for packed arrays.
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
dstogov committed Nov 3, 2021
1 parent 0eb603e commit 90b7bde
Show file tree
Hide file tree
Showing 89 changed files with 3,281 additions and 1,643 deletions.
2 changes: 1 addition & 1 deletion Zend/Optimizer/sccp.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ static inline zend_result ct_eval_in_array(zval *result, uint32_t extended_value
zval key_tmp;

res = 0;
ZEND_HASH_FOREACH_STR_KEY(ht, key) {
ZEND_HASH_MAP_FOREACH_STR_KEY(ht, key) {
ZVAL_STR(&key_tmp, key);
if (zend_compare(op1, &key_tmp) == 0) {
res = 1;
Expand Down
10 changes: 5 additions & 5 deletions Zend/Optimizer/zend_optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1360,15 +1360,15 @@ void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void

zend_foreach_op_array_helper(&script->main_op_array, func, context);

ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
ZEND_HASH_MAP_FOREACH_PTR(&script->function_table, op_array) {
zend_foreach_op_array_helper(op_array, func, context);
} ZEND_HASH_FOREACH_END();

ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
continue;
}
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
if (op_array->scope == ce
&& op_array->type == ZEND_USER_FUNCTION
&& !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
Expand Down Expand Up @@ -1516,11 +1516,11 @@ ZEND_API void zend_optimize_script(zend_script *script, zend_long optimization_l
}
}

ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
continue;
}
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
if (op_array->scope != ce && op_array->type == ZEND_USER_FUNCTION) {
zend_op_array *orig_op_array =
zend_hash_find_ptr(&op_array->scope->function_table, name);
Expand Down
33 changes: 18 additions & 15 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -1284,8 +1284,11 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */
zend_string *key;
zval *value;

if (HT_IS_PACKED(properties)) {
return;
}
EG(fake_scope) = Z_OBJCE_P(obj);
ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, value) {
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(properties, key, value) {
if (key) {
write_property(zobj, key, value, NULL);
}
Expand Down Expand Up @@ -1321,7 +1324,7 @@ ZEND_API HashTable *zend_separate_class_constants_table(zend_class_entry *class_
zend_hash_init(constants_table, zend_hash_num_elements(&class_type->constants_table), NULL, NULL, 0);
zend_hash_extend(constants_table, zend_hash_num_elements(&class_type->constants_table), 0);

ZEND_HASH_FOREACH_STR_KEY_PTR(&class_type->constants_table, key, c) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&class_type->constants_table, key, c) {
if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
memcpy(new_c, c, sizeof(zend_class_constant));
Expand Down Expand Up @@ -1409,7 +1412,7 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /
} else {
constants_table = &class_type->constants_table;
}
ZEND_HASH_FOREACH_PTR(constants_table, c) {
ZEND_HASH_MAP_FOREACH_PTR(constants_table, c) {
if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
val = &c->value;
if (UNEXPECTED(zval_update_constant_ex(val, c->ce) != SUCCESS)) {
Expand Down Expand Up @@ -1461,7 +1464,7 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /
}

if (class_type->default_static_members_count) {
ZEND_HASH_FOREACH_PTR(&class_type->properties_info, prop_info) {
ZEND_HASH_MAP_FOREACH_PTR(&class_type->properties_info, prop_info) {
if (prop_info->flags & ZEND_ACC_STATIC) {
val = static_members_table + prop_info->offset;
if (Z_TYPE_P(val) == IS_CONSTANT_AST
Expand Down Expand Up @@ -1526,7 +1529,7 @@ ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properti
zend_string *key;
zend_property_info *property_info;

ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, prop) {
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(properties, key, prop) {
property_info = zend_get_property_info(object->ce, key, 1);
if (property_info != ZEND_WRONG_PROPERTY_INFO &&
property_info &&
Expand Down Expand Up @@ -2243,7 +2246,7 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
int class_count = 0;

/* Collect extensions with request startup/shutdown handlers */
ZEND_HASH_FOREACH_PTR(&module_registry, module) {
ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
if (module->request_startup_func) {
startup_count++;
}
Expand All @@ -2266,7 +2269,7 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
module_post_deactivate_handlers[post_deactivate_count] = NULL;
startup_count = 0;

ZEND_HASH_FOREACH_PTR(&module_registry, module) {
ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
if (module->request_startup_func) {
module_request_startup_handlers[startup_count++] = module;
}
Expand All @@ -2279,7 +2282,7 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
} ZEND_HASH_FOREACH_END();

/* Collect internal classes with static members */
ZEND_HASH_FOREACH_PTR(CG(class_table), ce) {
ZEND_HASH_MAP_FOREACH_PTR(CG(class_table), ce) {
if (ce->type == ZEND_INTERNAL_CLASS &&
ce->default_static_members_count > 0) {
class_count++;
Expand All @@ -2292,7 +2295,7 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
class_cleanup_handlers[class_count] = NULL;

if (class_count) {
ZEND_HASH_FOREACH_PTR(CG(class_table), ce) {
ZEND_HASH_MAP_FOREACH_PTR(CG(class_table), ce) {
if (ce->type == ZEND_INTERNAL_CLASS &&
ce->default_static_members_count > 0) {
class_cleanup_handlers[--class_count] = ce;
Expand Down Expand Up @@ -2981,7 +2984,7 @@ ZEND_API void zend_deactivate_modules(void) /* {{{ */
if (EG(full_tables_cleanup)) {
zend_module_entry *module;

ZEND_HASH_REVERSE_FOREACH_PTR(&module_registry, module) {
ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&module_registry, module) {
if (module->request_shutdown_func) {
zend_try {
module->request_shutdown_func(module->type, module->module_number);
Expand Down Expand Up @@ -3009,20 +3012,20 @@ ZEND_API void zend_post_deactivate_modules(void) /* {{{ */
zval *zv;
zend_string *key;

ZEND_HASH_FOREACH_PTR(&module_registry, module) {
ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
if (module->post_deactivate_func) {
module->post_deactivate_func();
}
} ZEND_HASH_FOREACH_END();
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(&module_registry, key, zv) {
ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(&module_registry, key, zv) {
module = Z_PTR_P(zv);
if (module->type != MODULE_TEMPORARY) {
break;
}
module_destructor(module);
free(module);
zend_string_release_ex(key, 0);
} ZEND_HASH_FOREACH_END_DEL();
} ZEND_HASH_MAP_FOREACH_END_DEL();
} else {
zend_module_entry **p = module_post_deactivate_handlers;

Expand Down Expand Up @@ -3267,14 +3270,14 @@ ZEND_API zend_result zend_disable_class(const char *class_name, size_t class_nam
INIT_CLASS_ENTRY_INIT_METHODS((*disabled_class), disabled_class_new);
disabled_class->create_object = display_disabled_class;

ZEND_HASH_FOREACH_PTR(&disabled_class->function_table, fn) {
ZEND_HASH_MAP_FOREACH_PTR(&disabled_class->function_table, fn) {
if ((fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) &&
fn->common.scope == disabled_class) {
zend_free_internal_arg_info(&fn->internal_function);
}
} ZEND_HASH_FOREACH_END();
zend_hash_clean(&disabled_class->function_table);
ZEND_HASH_FOREACH_PTR(&disabled_class->properties_info, prop) {
ZEND_HASH_MAP_FOREACH_PTR(&disabled_class->properties_info, prop) {
if (prop->ce == disabled_class) {
zend_string_release(prop->name);
zend_type_release(prop->type, /* persistent */ 1);
Expand Down
6 changes: 3 additions & 3 deletions Zend/zend_attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname,
if (attributes) {
zend_attribute *attr;

ZEND_HASH_FOREACH_PTR(attributes, attr) {
ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) {
if (attr->offset == offset && zend_string_equals(attr->lcname, lcname)) {
return attr;
}
Expand All @@ -93,7 +93,7 @@ static zend_attribute *get_attribute_str(HashTable *attributes, const char *str,
if (attributes) {
zend_attribute *attr;

ZEND_HASH_FOREACH_PTR(attributes, attr) {
ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) {
if (attr->offset == offset && ZSTR_LEN(attr->lcname) == len) {
if (0 == memcmp(ZSTR_VAL(attr->lcname), str, len)) {
return attr;
Expand Down Expand Up @@ -173,7 +173,7 @@ ZEND_API bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *
{
zend_attribute *other;

ZEND_HASH_FOREACH_PTR(attributes, other) {
ZEND_HASH_PACKED_FOREACH_PTR(attributes, other) {
if (other != attr && other->offset == attr->offset) {
if (zend_string_equals(other->lcname, attr->lcname)) {
return 1;
Expand Down
24 changes: 12 additions & 12 deletions Zend/zend_builtin_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) &&
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) &&
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_closures.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ static HashTable *zend_closure_get_debug_info(zend_object *object, int *is_temp)

array_init(&val);

ZEND_HASH_FOREACH_STR_KEY_VAL(static_variables, key, var) {
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(static_variables, key, var) {
zval copy;

if (Z_TYPE_P(var) == IS_CONSTANT_AST) {
Expand Down
10 changes: 5 additions & 5 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1728,7 +1728,7 @@ ZEND_API void zend_activate_auto_globals(void) /* {{{ */
{
zend_auto_global *auto_global;

ZEND_HASH_FOREACH_PTR(CG(auto_globals), auto_global) {
ZEND_HASH_MAP_FOREACH_PTR(CG(auto_globals), auto_global) {
if (auto_global->jit) {
auto_global->armed = 1;
} else if (auto_global->auto_global_callback) {
Expand Down Expand Up @@ -5768,7 +5768,7 @@ static void zend_compile_try(zend_ast *ast) /* {{{ */
/* label: try { } must not be equal to try { label: } */
if (CG(context).labels) {
zend_label *label;
ZEND_HASH_REVERSE_FOREACH_PTR(CG(context).labels, label) {
ZEND_HASH_MAP_REVERSE_FOREACH_PTR(CG(context).labels, label) {
if (label->opline_num == get_next_op_number()) {
zend_emit_op(NULL, ZEND_NOP, NULL, NULL);
}
Expand Down Expand Up @@ -6440,7 +6440,7 @@ static void zend_compile_attributes(HashTable **attributes, zend_ast *ast, uint3
}

/* Validate attributes in a secondary loop (needed to detect repeated attributes). */
ZEND_HASH_FOREACH_PTR(*attributes, attr) {
ZEND_HASH_PACKED_FOREACH_PTR(*attributes, attr) {
if (attr->offset != offset || NULL == (config = zend_internal_attribute_get(attr->lcname))) {
continue;
}
Expand Down Expand Up @@ -6881,7 +6881,7 @@ static void compile_implicit_lexical_binds(
op_array->static_variables = zend_new_array(8);
}

ZEND_HASH_FOREACH_STR_KEY(&info->uses, var_name)
ZEND_HASH_MAP_FOREACH_STR_KEY(&info->uses, var_name)
zval *value = zend_hash_add(
op_array->static_variables, var_name, &EG(uninitialized_zval));
uint32_t offset = (uint32_t)((char*)value - (char*)op_array->static_variables->arData);
Expand Down Expand Up @@ -6930,7 +6930,7 @@ static void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
static void zend_compile_implicit_closure_uses(closure_info *info)
{
zend_string *var_name;
ZEND_HASH_FOREACH_STR_KEY(&info->uses, var_name)
ZEND_HASH_MAP_FOREACH_STR_KEY(&info->uses, var_name)
zval zv;
ZVAL_NULL(&zv);
zend_compile_static_var_common(var_name, &zv, ZEND_BIND_IMPLICIT);
Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_enum.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ static void zend_verify_enum_properties(zend_class_entry *ce)
{
zend_property_info *property_info;

ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
if (zend_string_equals_literal(property_info->name, "name")) {
continue;
}
Expand Down Expand Up @@ -192,7 +192,7 @@ static ZEND_NAMED_FUNCTION(zend_enum_cases_func)

array_init(return_value);

ZEND_HASH_FOREACH_PTR(CE_CONSTANTS_TABLE(ce), c) {
ZEND_HASH_MAP_FOREACH_PTR(CE_CONSTANTS_TABLE(ce), c) {
if (!(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE)) {
continue;
}
Expand Down
Loading

1 comment on commit 90b7bde

@dktapps
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to have been mentioned in UPGRADING.INTERNALS

Please sign in to comment.