@@ -44,8 +44,6 @@ typedef struct _spl_array_object {
4444 uint32_t ht_iter ;
4545 int ar_flags ;
4646 unsigned char nApplyCount ;
47- bool is_child ;
48- Bucket * bucket ;
4947 zend_function * fptr_offset_get ;
5048 zend_function * fptr_offset_set ;
5149 zend_function * fptr_offset_has ;
@@ -166,8 +164,6 @@ static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zend_o
166164 object_properties_init (& intern -> std , class_type );
167165
168166 intern -> ar_flags = 0 ;
169- intern -> is_child = false;
170- intern -> bucket = NULL ;
171167 intern -> ce_get_iterator = spl_ce_ArrayIterator ;
172168 if (orig ) {
173169 spl_array_object * other = spl_array_from_obj (orig );
@@ -466,21 +462,12 @@ static zval *spl_array_read_dimension(zend_object *object, zval *offset, int typ
466462} /* }}} */
467463
468464/*
469- * The assertion(HT_ASSERT_RC1(ht)) failed because the refcount was increased manually when intern->is_child is true.
470- * We have to set the refcount to 1 to make assertion success and restore the refcount to the original value after
471- * modifying the array when intern->is_child is true.
465+ * Before modifying the internal array, we must ensure exclusive ownership
466+ * to satisfy HT_ASSERT_RC1 in Zend hash operations.
467+ *
468+ * SEPARATE_ARRAY implements CoW: if the array is shared (RC > 1),
469+ * it creates a duplicate via zend_array_dup() and updates intern->array.
472470 */
473- static uint32_t spl_array_set_refcount (bool is_child , HashTable * ht , uint32_t refcount ) /* {{{ */
474- {
475- uint32_t old_refcount = 0 ;
476- if (is_child ) {
477- old_refcount = GC_REFCOUNT (ht );
478- GC_SET_REFCOUNT (ht , refcount );
479- }
480-
481- return old_refcount ;
482- } /* }}} */
483-
484471static void spl_array_write_dimension_ex (int check_inherited , zend_object * object , zval * offset , zval * value ) /* {{{ */
485472{
486473 spl_array_object * intern = spl_array_from_obj (object );
@@ -505,18 +492,15 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
505492
506493 Z_TRY_ADDREF_P (value );
507494
508- uint32_t refcount = 0 ;
509495 if (!offset || Z_TYPE_P (offset ) == IS_NULL ) {
496+ if (Z_TYPE (intern -> array ) == IS_ARRAY ) {
497+ SEPARATE_ARRAY (& intern -> array );
498+ }
510499 ht = spl_array_get_hash_table (intern );
511500 if (UNEXPECTED (ht == intern -> sentinel_array )) {
512501 return ;
513502 }
514- refcount = spl_array_set_refcount (intern -> is_child , ht , 1 );
515503 zend_hash_next_index_insert (ht , value );
516-
517- if (refcount ) {
518- spl_array_set_refcount (intern -> is_child , ht , refcount );
519- }
520504 return ;
521505 }
522506
@@ -526,22 +510,20 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
526510 return ;
527511 }
528512
513+ if (Z_TYPE (intern -> array ) == IS_ARRAY ) {
514+ SEPARATE_ARRAY (& intern -> array );
515+ }
529516 ht = spl_array_get_hash_table (intern );
530517 if (UNEXPECTED (ht == intern -> sentinel_array )) {
531518 spl_hash_key_release (& key );
532519 return ;
533520 }
534- refcount = spl_array_set_refcount (intern -> is_child , ht , 1 );
535521 if (key .key ) {
536522 zend_hash_update_ind (ht , key .key , value );
537523 spl_hash_key_release (& key );
538524 } else {
539525 zend_hash_index_update (ht , key .h , value );
540526 }
541-
542- if (refcount ) {
543- spl_array_set_refcount (intern -> is_child , ht , refcount );
544- }
545527} /* }}} */
546528
547529static void spl_array_write_dimension (zend_object * object , zval * offset , zval * value ) /* {{{ */
@@ -570,8 +552,10 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec
570552 return ;
571553 }
572554
555+ if (Z_TYPE (intern -> array ) == IS_ARRAY ) {
556+ SEPARATE_ARRAY (& intern -> array );
557+ }
573558 ht = spl_array_get_hash_table (intern );
574- uint32_t refcount = spl_array_set_refcount (intern -> is_child , ht , 1 );
575559
576560 if (key .key ) {
577561 zval * data = zend_hash_find (ht , key .key );
@@ -597,10 +581,6 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec
597581 } else {
598582 zend_hash_index_del (ht , key .h );
599583 }
600-
601- if (refcount ) {
602- spl_array_set_refcount (intern -> is_child , ht , refcount );
603- }
604584} /* }}} */
605585
606586static void spl_array_unset_dimension (zend_object * object , zval * offset ) /* {{{ */
@@ -970,17 +950,7 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar
970950 if (Z_REFCOUNT_P (array ) == 1 ) {
971951 ZVAL_COPY (& intern -> array , array );
972952 } else {
973- //??? TODO: try to avoid array duplication
974953 ZVAL_ARR (& intern -> array , zend_array_dup (Z_ARR_P (array )));
975-
976- if (intern -> is_child ) {
977- Z_TRY_DELREF (intern -> bucket -> val );
978- /*
979- * replace bucket->val with copied array, so the changes between
980- * parent and child object can affect each other.
981- */
982- ZVAL_COPY (& intern -> bucket -> val , & intern -> array );
983- }
984954 }
985955 } else {
986956 php_error_docref (NULL , E_DEPRECATED ,
@@ -1850,15 +1820,6 @@ PHP_METHOD(RecursiveArrayIterator, hasChildren)
18501820static void spl_instantiate_child_arg (zend_class_entry * pce , zval * retval , zval * arg1 , zval * arg2 ) /* {{{ */
18511821{
18521822 object_init_ex (retval , pce );
1853- spl_array_object * new_intern = Z_SPLARRAY_P (retval );
1854- /*
1855- * set new_intern->is_child is true to indicate that the object was created by
1856- * RecursiveArrayIterator::getChildren() method.
1857- */
1858- new_intern -> is_child = true;
1859-
1860- /* find the bucket of parent object. */
1861- new_intern -> bucket = (Bucket * )((char * )(arg1 ) - XtOffsetOf (Bucket , val ));;
18621823 zend_call_known_instance_method_with_2_params (pce -> constructor , Z_OBJ_P (retval ), NULL , arg1 , arg2 );
18631824}
18641825/* }}} */
0 commit comments