From 9da66e6ad0f57d7ba71417731ec2586703f4d790 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 1 Mar 2021 22:37:37 +0300 Subject: [PATCH] Optimized object conversion to array without rebulding properties HashTable --- Zend/zend_object_handlers.c | 32 ++++++++++++++++++++++++++++++++ Zend/zend_object_handlers.h | 2 ++ Zend/zend_operators.c | 7 +++++++ Zend/zend_vm_def.h | 5 +++++ Zend/zend_vm_execute.h | 20 ++++++++++++++++++++ 5 files changed, 66 insertions(+) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 94d2ff8cf4..f10e2c58a6 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -87,6 +87,38 @@ ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */ } /* }}} */ +ZEND_API HashTable *zend_std_build_object_properties_array(zend_object *zobj) /* {{{ */ +{ + zend_property_info *prop_info; + zend_class_entry *ce = zobj->ce; + HashTable *ht; + zval* prop; + int i; + + ZEND_ASSERT(!zobj->properties); + ht = zend_new_array(ce->default_properties_count); + if (ce->default_properties_count) { + zend_hash_real_init_mixed(ht); + for (i = 0; i < ce->default_properties_count; i++) { + prop_info = ce->properties_info_table[i]; + + if (!prop_info) { + continue; + } + + prop = OBJ_PROP(zobj, prop_info->offset); + if (UNEXPECTED(Z_TYPE_P(prop) == IS_UNDEF)) { + continue; + } + + Z_TRY_ADDREF_P(prop); + _zend_hash_append(ht, prop_info->name, prop); + } + } + return ht; +} +/* }}} */ + ZEND_API HashTable *zend_std_get_properties(zend_object *zobj) /* {{{ */ { if (!zobj->properties) { diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 71c0168372..53eef82928 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -225,6 +225,8 @@ ZEND_API int zend_std_compare_objects(zval *o1, zval *o2); ZEND_API int zend_std_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only); ZEND_API void rebuild_object_properties(zend_object *zobj); +ZEND_API HashTable *zend_std_build_object_properties_array(zend_object *zobj); + /* Handler for objects that cannot be meaningfully compared. * Only objects with the same identity will be considered equal. */ ZEND_API int zend_objects_not_comparable(zval *o1, zval *o2); diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index a23dad9e1e..db53c71317 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -713,6 +713,13 @@ try_again: case IS_OBJECT: if (Z_OBJCE_P(op) == zend_ce_closure) { convert_scalar_to_array(op); + } else if (Z_OBJ_P(op)->properties == NULL + && Z_OBJ_HT_P(op)->get_properties_for == NULL + && Z_OBJ_HT_P(op)->get_properties == zend_std_get_properties) { + /* Optimized version without rebulding properties HashTable */ + HashTable *ht = zend_std_build_object_properties_array(Z_OBJ_P(op)); + OBJ_RELEASE(Z_OBJ_P(op)); + ZVAL_ARR(op, ht); } else { HashTable *obj_ht = zend_get_properties_for(op, ZEND_PROP_PURPOSE_ARRAY_CAST); if (obj_ht) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8b4a86b745..09dce52b68 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6139,6 +6139,11 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) } else { ZVAL_EMPTY_ARRAY(result); } + } else if (Z_OBJ_P(expr)->properties == NULL + && Z_OBJ_HT_P(expr)->get_properties_for == NULL + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + /* Optimized version without rebulding properties HashTable */ + ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); if (obj_ht) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 26903f9403..385941e595 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -4643,6 +4643,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H } else { ZVAL_EMPTY_ARRAY(result); } + } else if (Z_OBJ_P(expr)->properties == NULL + && Z_OBJ_HT_P(expr)->get_properties_for == NULL + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + /* Optimized version without rebulding properties HashTable */ + ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); if (obj_ht) { @@ -18859,6 +18864,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC } else { ZVAL_EMPTY_ARRAY(result); } + } else if (Z_OBJ_P(expr)->properties == NULL + && Z_OBJ_HT_P(expr)->get_properties_for == NULL + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + /* Optimized version without rebulding properties HashTable */ + ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); if (obj_ht) { @@ -21469,6 +21479,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC } else { ZVAL_EMPTY_ARRAY(result); } + } else if (Z_OBJ_P(expr)->properties == NULL + && Z_OBJ_HT_P(expr)->get_properties_for == NULL + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + /* Optimized version without rebulding properties HashTable */ + ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); if (obj_ht) { @@ -38144,6 +38159,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO } else { ZVAL_EMPTY_ARRAY(result); } + } else if (Z_OBJ_P(expr)->properties == NULL + && Z_OBJ_HT_P(expr)->get_properties_for == NULL + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + /* Optimized version without rebulding properties HashTable */ + ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); if (obj_ht) { -- 2.40.0