Skip to content

Commit 4239f98

Browse files
committed
More RC1 optimisations
1 parent 99d99d5 commit 4239f98

File tree

1 file changed

+52
-9
lines changed

1 file changed

+52
-9
lines changed

ext/standard/array.c

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
9191
}
9292
/* }}} */
9393

94+
static zend_always_inline bool zend_may_modify_array_in_place(const zval *arg)
95+
{
96+
return !(GC_FLAGS(Z_ARRVAL_P(arg)) & (IS_ARRAY_IMMUTABLE | IS_ARRAY_PERSISTENT)) && Z_REFCOUNT_P(arg) == 1;
97+
}
98+
9499
static zend_never_inline ZEND_COLD int stable_sort_fallback(Bucket *a, Bucket *b) {
95100
if (Z_EXTRA(a->val) > Z_EXTRA(b->val)) {
96101
return 1;
@@ -901,8 +906,12 @@ static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compar
901906
RETURN_TRUE;
902907
}
903908

904-
/* Copy array, so the in-place modifications will not be visible to the callback function */
905-
arr = zend_array_dup(arr);
909+
/* Copy array, so the in-place modifications will not be visible to the callback function.
910+
* Unless there are no other references since we know for sure it won't be visible. */
911+
bool in_place = zend_may_modify_array_in_place(array);
912+
if (!in_place) {
913+
arr = zend_array_dup(arr);
914+
}
906915

907916
zend_hash_sort(arr, compare_func, renumber);
908917

@@ -911,6 +920,10 @@ static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compar
911920
ZVAL_ARR(array, arr);
912921
zval_ptr_dtor(&garbage);
913922

923+
if (in_place) {
924+
GC_ADDREF(arr);
925+
}
926+
914927
PHP_ARRAY_CMP_FUNC_RESTORE();
915928
RETURN_TRUE;
916929
}
@@ -3866,10 +3879,17 @@ static zend_always_inline void php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM
38663879
}
38673880
}
38683881

3869-
/* copy first array */
3882+
/* copy first array if necessary */
38703883
arg = args;
3871-
dest = zend_array_dup(Z_ARRVAL_P(arg));
3884+
bool in_place = zend_may_modify_array_in_place(arg);
3885+
if (in_place) {
3886+
dest = Z_ARRVAL_P(arg);
3887+
} else {
3888+
dest = zend_array_dup(Z_ARRVAL_P(arg));
3889+
}
3890+
38723891
ZVAL_ARR(return_value, dest);
3892+
38733893
if (recursive) {
38743894
for (i = 1; i < argc; i++) {
38753895
arg = args + i;
@@ -3881,6 +3901,10 @@ static zend_always_inline void php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM
38813901
zend_hash_merge(dest, Z_ARRVAL_P(arg), zval_add_ref, 1);
38823902
}
38833903
}
3904+
3905+
if (in_place) {
3906+
GC_ADDREF(dest);
3907+
}
38843908
}
38853909
/* }}} */
38863910

@@ -3949,7 +3973,7 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET
39493973
/* copy first array if necessary */
39503974
if (HT_IS_PACKED(src)) {
39513975
/* Note: If it has holes, it might get sequentialized */
3952-
if (HT_IS_WITHOUT_HOLES(src) && !(GC_FLAGS(Z_ARRVAL_P(arg)) & (IS_ARRAY_IMMUTABLE | IS_ARRAY_PERSISTENT)) && Z_REFCOUNT_P(arg) == 1) {
3976+
if (HT_IS_WITHOUT_HOLES(src) && zend_may_modify_array_in_place(arg)) {
39533977
dest = src;
39543978
in_place = true;
39553979
ZVAL_ARR(return_value, dest);
@@ -4001,7 +4025,7 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET
40014025
}
40024026

40034027
if (in_place) {
4004-
GC_ADDREF(Z_ARRVAL_P(return_value));
4028+
GC_ADDREF(dest);
40054029
}
40064030
//fprintf(stderr, "after, in-place %d %d\n", in_place, GC_REFCOUNT(Z_ARRVAL_P(return_value)));
40074031
}
@@ -4611,7 +4635,12 @@ PHP_FUNCTION(array_unique)
46114635

46124636
cmp = php_get_data_compare_func_unstable(sort_type, 0);
46134637

4614-
RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array)));
4638+
bool in_place = zend_may_modify_array_in_place(array);
4639+
if (in_place) {
4640+
RETVAL_ARR(Z_ARRVAL_P(array));
4641+
} else {
4642+
RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array)));
4643+
}
46154644

46164645
/* create and sort array with pointers to the target_hash buckets */
46174646
arTmp = pemalloc((Z_ARRVAL_P(array)->nNumOfElements + 1) * sizeof(struct bucketindex), GC_FLAGS(Z_ARRVAL_P(array)) & IS_ARRAY_PERSISTENT);
@@ -4657,6 +4686,10 @@ PHP_FUNCTION(array_unique)
46574686
}
46584687
}
46594688
pefree(arTmp, GC_FLAGS(Z_ARRVAL_P(array)) & IS_ARRAY_PERSISTENT);
4689+
4690+
if (in_place) {
4691+
Z_ADDREF_P(return_value);
4692+
}
46604693
}
46614694
/* }}} */
46624695

@@ -4781,6 +4814,7 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
47814814
zend_fcall_info *fci_key = NULL, *fci_data;
47824815
zend_fcall_info_cache *fci_key_cache = NULL, *fci_data_cache;
47834816
PHP_ARRAY_CMP_FUNC_VARS;
4817+
bool in_place = false;
47844818

47854819
bucket_compare_func_t intersect_key_compare_func;
47864820
bucket_compare_func_t intersect_data_compare_func;
@@ -4907,8 +4941,13 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
49074941
}
49084942
}
49094943

4910-
/* copy the argument array */
4911-
RETVAL_ARR(zend_array_dup(Z_ARRVAL(args[0])));
4944+
/* copy the argument array if necessary */
4945+
in_place = zend_may_modify_array_in_place(&args[0]);
4946+
if (in_place) {
4947+
RETVAL_ARR(Z_ARRVAL_P(&args[0]));
4948+
} else {
4949+
RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(&args[0])));
4950+
}
49124951

49134952
/* go through the lists and look for common values */
49144953
while (Z_TYPE(ptrs[0]->val) != IS_UNDEF) {
@@ -5019,6 +5058,10 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
50195058

50205059
efree(ptrs);
50215060
efree(lists);
5061+
5062+
if (in_place) {
5063+
Z_ADDREF_P(return_value);
5064+
}
50225065
}
50235066
/* }}} */
50245067

0 commit comments

Comments
 (0)