From f5cc5f6ada58ab64c90af2449a2be64b1f52d1fd Mon Sep 17 00:00:00 2001 From: jhdxr Date: Fri, 21 Oct 2022 17:31:59 +0800 Subject: [PATCH 1/2] optimize spread operator for packed arrays --- Zend/zend_vm_def.h | 52 ++++++++++++++++++++++++++++++------------ Zend/zend_vm_execute.h | 50 ++++++++++++++++++++++++++++------------ 2 files changed, 73 insertions(+), 29 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index cebf44282909d..6e5e6606234c9 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6047,23 +6047,45 @@ ZEND_VM_C_LABEL(add_unpack_again): if (EXPECTED(Z_TYPE_P(op1) == IS_ARRAY)) { HashTable *ht = Z_ARRVAL_P(op1); zval *val; - zend_string *key; - - ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { - if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) { - val = Z_REFVAL_P(val); - } - Z_TRY_ADDREF_P(val); - if (key) { - zend_hash_update(result_ht, key, val); + + if (HT_IS_PACKED(ht) && + (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) { + if (zend_hash_num_elements(result_ht) == 0) { + result_ht->nTableSize = zend_hash_num_elements(ht);; + zend_hash_real_init_packed(result_ht); } else { - if (!zend_hash_next_index_insert(result_ht, val)) { - zend_cannot_add_element(); - zval_ptr_dtor_nogc(val); - break; - } + zend_hash_extend(result_ht, zend_hash_num_elements(result_ht) + zend_hash_num_elements(ht), 1); } - } ZEND_HASH_FOREACH_END(); + ZEND_HASH_FILL_PACKED(result_ht) { + ZEND_HASH_PACKED_FOREACH_VAL(ht, val) { + if (UNEXPECTED(Z_ISREF_P(val)) && + UNEXPECTED(Z_REFCOUNT_P(val) == 1)) { + val = Z_REFVAL_P(val); + } + Z_TRY_ADDREF_P(val); + ZEND_HASH_FILL_ADD(val); + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FILL_END(); + } else { + zend_string *key; + + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { + if (UNEXPECTED(Z_ISREF_P(val)) && + UNEXPECTED(Z_REFCOUNT_P(val) == 1)) { + val = Z_REFVAL_P(val); + } + Z_TRY_ADDREF_P(val); + if (key) { + zend_hash_update(result_ht, key, val); + } else { + if (!zend_hash_next_index_insert(result_ht, val)) { + zend_cannot_add_element(); + zval_ptr_dtor_nogc(val); + break; + } + } + } ZEND_HASH_FOREACH_END(); + } } else if (EXPECTED(Z_TYPE_P(op1) == IS_OBJECT)) { zend_class_entry *ce = Z_OBJCE_P(op1); zend_object_iterator *iter; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f51e628d27361..cb83c7cb8e2df 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2624,23 +2624,45 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_UNPACK_SPEC_HANDLER( if (EXPECTED(Z_TYPE_P(op1) == IS_ARRAY)) { HashTable *ht = Z_ARRVAL_P(op1); zval *val; - zend_string *key; - ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { - if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) { - val = Z_REFVAL_P(val); - } - Z_TRY_ADDREF_P(val); - if (key) { - zend_hash_update(result_ht, key, val); + if (HT_IS_PACKED(ht) && + (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) { + if (zend_hash_num_elements(result_ht) == 0) { + result_ht->nTableSize = zend_hash_num_elements(ht);; + zend_hash_real_init_packed(result_ht); } else { - if (!zend_hash_next_index_insert(result_ht, val)) { - zend_cannot_add_element(); - zval_ptr_dtor_nogc(val); - break; - } + zend_hash_extend(result_ht, zend_hash_num_elements(result_ht) + zend_hash_num_elements(ht), 1); } - } ZEND_HASH_FOREACH_END(); + ZEND_HASH_FILL_PACKED(result_ht) { + ZEND_HASH_PACKED_FOREACH_VAL(ht, val) { + if (UNEXPECTED(Z_ISREF_P(val)) && + UNEXPECTED(Z_REFCOUNT_P(val) == 1)) { + val = Z_REFVAL_P(val); + } + Z_TRY_ADDREF_P(val); + ZEND_HASH_FILL_ADD(val); + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FILL_END(); + } else { + zend_string *key; + + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { + if (UNEXPECTED(Z_ISREF_P(val)) && + UNEXPECTED(Z_REFCOUNT_P(val) == 1)) { + val = Z_REFVAL_P(val); + } + Z_TRY_ADDREF_P(val); + if (key) { + zend_hash_update(result_ht, key, val); + } else { + if (!zend_hash_next_index_insert(result_ht, val)) { + zend_cannot_add_element(); + zval_ptr_dtor_nogc(val); + break; + } + } + } ZEND_HASH_FOREACH_END(); + } } else if (EXPECTED(Z_TYPE_P(op1) == IS_OBJECT)) { zend_class_entry *ce = Z_OBJCE_P(op1); zend_object_iterator *iter; From 106207d32313a6c8d0aa5b61654d662e6999c144 Mon Sep 17 00:00:00 2001 From: jhdxr Date: Fri, 21 Oct 2022 19:20:36 +0800 Subject: [PATCH 2/2] ci fix --- Zend/zend_vm_def.h | 10 ++-------- Zend/zend_vm_execute.h | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 6e5e6606234c9..650a8839b1a7b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6048,14 +6048,8 @@ ZEND_VM_C_LABEL(add_unpack_again): HashTable *ht = Z_ARRVAL_P(op1); zval *val; - if (HT_IS_PACKED(ht) && - (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) { - if (zend_hash_num_elements(result_ht) == 0) { - result_ht->nTableSize = zend_hash_num_elements(ht);; - zend_hash_real_init_packed(result_ht); - } else { - zend_hash_extend(result_ht, zend_hash_num_elements(result_ht) + zend_hash_num_elements(ht), 1); - } + if (HT_IS_PACKED(ht) && (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) { + zend_hash_extend(result_ht, zend_hash_num_elements(result_ht) + zend_hash_num_elements(ht), 1); ZEND_HASH_FILL_PACKED(result_ht) { ZEND_HASH_PACKED_FOREACH_VAL(ht, val) { if (UNEXPECTED(Z_ISREF_P(val)) && diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index cb83c7cb8e2df..598646eb42d66 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2625,14 +2625,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_UNPACK_SPEC_HANDLER( HashTable *ht = Z_ARRVAL_P(op1); zval *val; - if (HT_IS_PACKED(ht) && - (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) { - if (zend_hash_num_elements(result_ht) == 0) { - result_ht->nTableSize = zend_hash_num_elements(ht);; - zend_hash_real_init_packed(result_ht); - } else { - zend_hash_extend(result_ht, zend_hash_num_elements(result_ht) + zend_hash_num_elements(ht), 1); - } + if (HT_IS_PACKED(ht) && (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) { + zend_hash_extend(result_ht, zend_hash_num_elements(result_ht) + zend_hash_num_elements(ht), 1); ZEND_HASH_FILL_PACKED(result_ht) { ZEND_HASH_PACKED_FOREACH_VAL(ht, val) { if (UNEXPECTED(Z_ISREF_P(val)) &&