@@ -901,11 +901,19 @@ static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compar
901
901
RETURN_TRUE ;
902
902
}
903
903
904
- /* Copy array, so the in-place modifications will not be visible to the callback function */
905
- arr = zend_array_dup (arr );
904
+ /* Copy array, so the in-place modifications will not be visible to the callback function.
905
+ * Unless there are no other references since we know for sure it won't be visible. */
906
+ bool in_place = zend_may_modify_arg_in_place (array );
907
+ if (!in_place ) {
908
+ arr = zend_array_dup (arr );
909
+ }
906
910
907
911
zend_hash_sort (arr , compare_func , renumber );
908
912
913
+ if (in_place ) {
914
+ GC_ADDREF (arr );
915
+ }
916
+
909
917
zval garbage ;
910
918
ZVAL_COPY_VALUE (& garbage , array );
911
919
ZVAL_ARR (array , arr );
@@ -3866,10 +3874,17 @@ static zend_always_inline void php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM
3866
3874
}
3867
3875
}
3868
3876
3869
- /* copy first array */
3877
+ /* copy first array if necessary */
3870
3878
arg = args ;
3871
- dest = zend_array_dup (Z_ARRVAL_P (arg ));
3879
+ bool in_place = zend_may_modify_arg_in_place (arg );
3880
+ if (in_place ) {
3881
+ dest = Z_ARRVAL_P (arg );
3882
+ } else {
3883
+ dest = zend_array_dup (Z_ARRVAL_P (arg ));
3884
+ }
3885
+
3872
3886
ZVAL_ARR (return_value , dest );
3887
+
3873
3888
if (recursive ) {
3874
3889
for (i = 1 ; i < argc ; i ++ ) {
3875
3890
arg = args + i ;
@@ -3881,6 +3896,10 @@ static zend_always_inline void php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM
3881
3896
zend_hash_merge (dest , Z_ARRVAL_P (arg ), zval_add_ref , 1 );
3882
3897
}
3883
3898
}
3899
+
3900
+ if (in_place ) {
3901
+ GC_ADDREF (dest );
3902
+ }
3884
3903
}
3885
3904
/* }}} */
3886
3905
@@ -3945,22 +3964,34 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET
3945
3964
3946
3965
arg = args ;
3947
3966
src = Z_ARRVAL_P (arg );
3948
- /* copy first array */
3949
- array_init_size (return_value , count );
3950
- dest = Z_ARRVAL_P (return_value );
3967
+ /* copy first array if necessary */
3968
+ bool in_place = false;
3951
3969
if (HT_IS_PACKED (src )) {
3952
- zend_hash_real_init_packed (dest );
3953
- ZEND_HASH_FILL_PACKED (dest ) {
3954
- ZEND_HASH_PACKED_FOREACH_VAL (src , src_entry ) {
3955
- if (UNEXPECTED (Z_ISREF_P (src_entry ) &&
3956
- Z_REFCOUNT_P (src_entry ) == 1 )) {
3957
- src_entry = Z_REFVAL_P (src_entry );
3958
- }
3959
- Z_TRY_ADDREF_P (src_entry );
3960
- ZEND_HASH_FILL_ADD (src_entry );
3961
- } ZEND_HASH_FOREACH_END ();
3962
- } ZEND_HASH_FILL_END ();
3970
+ /* Note: If it has holes, it might get sequentialized */
3971
+ if (HT_IS_WITHOUT_HOLES (src ) && zend_may_modify_arg_in_place (arg )) {
3972
+ dest = src ;
3973
+ in_place = true;
3974
+ ZVAL_ARR (return_value , dest );
3975
+ } else {
3976
+ array_init_size (return_value , count );
3977
+ dest = Z_ARRVAL_P (return_value );
3978
+
3979
+ zend_hash_real_init_packed (dest );
3980
+ ZEND_HASH_FILL_PACKED (dest ) {
3981
+ ZEND_HASH_PACKED_FOREACH_VAL (src , src_entry ) {
3982
+ if (UNEXPECTED (Z_ISREF_P (src_entry ) &&
3983
+ Z_REFCOUNT_P (src_entry ) == 1 )) {
3984
+ src_entry = Z_REFVAL_P (src_entry );
3985
+ }
3986
+ Z_TRY_ADDREF_P (src_entry );
3987
+ ZEND_HASH_FILL_ADD (src_entry );
3988
+ } ZEND_HASH_FOREACH_END ();
3989
+ } ZEND_HASH_FILL_END ();
3990
+ }
3963
3991
} else {
3992
+ array_init_size (return_value , count );
3993
+ dest = Z_ARRVAL_P (return_value );
3994
+
3964
3995
zend_string * string_key ;
3965
3996
zend_hash_real_init_mixed (dest );
3966
3997
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL (src , string_key , src_entry ) {
@@ -3987,6 +4018,10 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET
3987
4018
php_array_merge (dest , Z_ARRVAL_P (arg ));
3988
4019
}
3989
4020
}
4021
+
4022
+ if (in_place ) {
4023
+ GC_ADDREF (dest );
4024
+ }
3990
4025
}
3991
4026
/* }}} */
3992
4027
@@ -4594,7 +4629,12 @@ PHP_FUNCTION(array_unique)
4594
4629
4595
4630
cmp = php_get_data_compare_func_unstable (sort_type , 0 );
4596
4631
4597
- RETVAL_ARR (zend_array_dup (Z_ARRVAL_P (array )));
4632
+ bool in_place = zend_may_modify_arg_in_place (array );
4633
+ if (in_place ) {
4634
+ RETVAL_ARR (Z_ARRVAL_P (array ));
4635
+ } else {
4636
+ RETVAL_ARR (zend_array_dup (Z_ARRVAL_P (array )));
4637
+ }
4598
4638
4599
4639
/* create and sort array with pointers to the target_hash buckets */
4600
4640
arTmp = pemalloc ((Z_ARRVAL_P (array )-> nNumOfElements + 1 ) * sizeof (struct bucketindex ), GC_FLAGS (Z_ARRVAL_P (array )) & IS_ARRAY_PERSISTENT );
@@ -4640,6 +4680,10 @@ PHP_FUNCTION(array_unique)
4640
4680
}
4641
4681
}
4642
4682
pefree (arTmp , GC_FLAGS (Z_ARRVAL_P (array )) & IS_ARRAY_PERSISTENT );
4683
+
4684
+ if (in_place ) {
4685
+ Z_ADDREF_P (return_value );
4686
+ }
4643
4687
}
4644
4688
/* }}} */
4645
4689
@@ -4764,6 +4808,7 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
4764
4808
zend_fcall_info * fci_key = NULL , * fci_data ;
4765
4809
zend_fcall_info_cache * fci_key_cache = NULL , * fci_data_cache ;
4766
4810
PHP_ARRAY_CMP_FUNC_VARS ;
4811
+ bool in_place = false;
4767
4812
4768
4813
bucket_compare_func_t intersect_key_compare_func ;
4769
4814
bucket_compare_func_t intersect_data_compare_func ;
@@ -4890,8 +4935,13 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
4890
4935
}
4891
4936
}
4892
4937
4893
- /* copy the argument array */
4894
- RETVAL_ARR (zend_array_dup (Z_ARRVAL (args [0 ])));
4938
+ /* copy the argument array if necessary */
4939
+ in_place = zend_may_modify_arg_in_place (& args [0 ]);
4940
+ if (in_place ) {
4941
+ RETVAL_ARR (Z_ARRVAL_P (& args [0 ]));
4942
+ } else {
4943
+ RETVAL_ARR (zend_array_dup (Z_ARRVAL_P (& args [0 ])));
4944
+ }
4895
4945
4896
4946
/* go through the lists and look for common values */
4897
4947
while (Z_TYPE (ptrs [0 ]-> val ) != IS_UNDEF ) {
@@ -5002,6 +5052,10 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
5002
5052
5003
5053
efree (ptrs );
5004
5054
efree (lists );
5055
+
5056
+ if (in_place ) {
5057
+ Z_ADDREF_P (return_value );
5058
+ }
5005
5059
}
5006
5060
/* }}} */
5007
5061
0 commit comments