Skip to content

Commit 41ecd7c

Browse files
ext/spl: Use fast ZPP in hot ArrayObject and ArrayIterator methods (#23946)
`return new \ArrayIterator($this->items);` is the usual getIterator() implementation of Twig nodes, Symfony bags or Doctrine collections, and profiling a foreach over such objects shows zend_parse_parameters() taking about 180 instructions per ArrayIterator::__construct() call. This switches both constructors and the ArrayAccess methods (offsetExists(), offsetGet(), offsetSet(), offsetUnset(), append()) to fast ZPP. Accepted types, error messages and deprecations don't change. Instructions per operation (callgrind, -O2 build, arrays of 0/5/100 elements): new ArrayIterator() -181, i.e. -16.5%/-13.8%/-6.6%, and -11.4%/-4.7%/-0.4% when followed by foreach. new ArrayObject() -199, i.e. -17.8%/-14.9%/-7.2%, and -8.7%/-4.2%/-0.4% with foreach. offsetGet() and friends called as methods, e.g. via parent::offsetSet() in subclasses, are 39% to 43% cheaper. Walking Twig's node trees with foreach (17.6k nodes): -4.2% per round. The binary grows by 472 bytes of text.
1 parent 62e2f86 commit 41ecd7c

1 file changed

Lines changed: 27 additions & 21 deletions

File tree

‎ext/spl/spl_array.c‎

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -643,19 +643,19 @@ static int spl_array_has_dimension(zend_object *object, zval *offset, int check_
643643
PHP_METHOD(ArrayObject, offsetExists)
644644
{
645645
zval *index;
646-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
647-
RETURN_THROWS();
648-
}
646+
ZEND_PARSE_PARAMETERS_START(1, 1)
647+
Z_PARAM_ZVAL(index)
648+
ZEND_PARSE_PARAMETERS_END();
649649
RETURN_BOOL(spl_array_has_dimension_ex(/* check_inherited */ false, Z_OBJ_P(ZEND_THIS), index, 2));
650650
} /* }}} */
651651

652652
/* {{{ Returns the value at the specified $index. */
653653
PHP_METHOD(ArrayObject, offsetGet)
654654
{
655655
zval *value, *index;
656-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
657-
RETURN_THROWS();
658-
}
656+
ZEND_PARSE_PARAMETERS_START(1, 1)
657+
Z_PARAM_ZVAL(index)
658+
ZEND_PARSE_PARAMETERS_END();
659659
value = spl_array_read_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index, BP_VAR_R, return_value);
660660
if (value != return_value) {
661661
RETURN_COPY_DEREF(value);
@@ -666,9 +666,10 @@ PHP_METHOD(ArrayObject, offsetGet)
666666
PHP_METHOD(ArrayObject, offsetSet)
667667
{
668668
zval *index, *value;
669-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &index, &value) == FAILURE) {
670-
RETURN_THROWS();
671-
}
669+
ZEND_PARSE_PARAMETERS_START(2, 2)
670+
Z_PARAM_ZVAL(index)
671+
Z_PARAM_ZVAL(value)
672+
ZEND_PARSE_PARAMETERS_END();
672673
spl_array_write_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index, value);
673674
} /* }}} */
674675

@@ -689,19 +690,19 @@ PHP_METHOD(ArrayObject, append)
689690
{
690691
zval *value;
691692

692-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
693-
RETURN_THROWS();
694-
}
693+
ZEND_PARSE_PARAMETERS_START(1, 1)
694+
Z_PARAM_ZVAL(value)
695+
ZEND_PARSE_PARAMETERS_END();
695696
spl_array_iterator_append(ZEND_THIS, value);
696697
} /* }}} */
697698

698699
/* {{{ Unsets the value at the specified $index. */
699700
PHP_METHOD(ArrayObject, offsetUnset)
700701
{
701702
zval *index;
702-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
703-
RETURN_THROWS();
704-
}
703+
ZEND_PARSE_PARAMETERS_START(1, 1)
704+
Z_PARAM_ZVAL(index)
705+
ZEND_PARSE_PARAMETERS_END();
705706
spl_array_unset_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index);
706707
} /* }}} */
707708

@@ -1000,9 +1001,12 @@ PHP_METHOD(ArrayObject, __construct)
10001001
return; /* nothing to do */
10011002
}
10021003

1003-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|AlC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
1004-
RETURN_THROWS();
1005-
}
1004+
ZEND_PARSE_PARAMETERS_START(0, 3)
1005+
Z_PARAM_OPTIONAL
1006+
Z_PARAM_ARRAY_OR_OBJECT(array)
1007+
Z_PARAM_LONG(ar_flags)
1008+
Z_PARAM_CLASS(ce_get_iterator)
1009+
ZEND_PARSE_PARAMETERS_END();
10061010

10071011
intern = Z_SPLARRAY_P(object);
10081012

@@ -1669,9 +1673,11 @@ PHP_METHOD(ArrayIterator, __construct)
16691673
return; /* nothing to do */
16701674
}
16711675

1672-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|Al", &array, &ar_flags) == FAILURE) {
1673-
RETURN_THROWS();
1674-
}
1676+
ZEND_PARSE_PARAMETERS_START(0, 2)
1677+
Z_PARAM_OPTIONAL
1678+
Z_PARAM_ARRAY_OR_OBJECT(array)
1679+
Z_PARAM_LONG(ar_flags)
1680+
ZEND_PARSE_PARAMETERS_END();
16751681

16761682
intern = Z_SPLARRAY_P(object);
16771683

0 commit comments

Comments
 (0)