Skip to content

Commit 335c0b3

Browse files
authored
Optimize SplFixedArray dimension performance (#18184)
This patch optimizes reading and writing from SplFixedArray with the dimension operators. It accomplishes this due to the following optimizations: * Fast-path for long keys (inlined). * Optimization hints (UNEXPECTED + assertion) * Using an unsigned index so we can do a single length comparison For the following script: ```php $test = new SplFixedArray(4); for ($i = 0 ; $i< 5000000; $i++) $test[1] += $i; ``` On an i7-4790: ``` Benchmark 1: ./sapi/cli/php x.php Time (mean ± σ): 95.4 ms ± 1.6 ms [User: 91.5 ms, System: 3.2 ms] Range (min … max): 93.7 ms … 100.8 ms 31 runs Benchmark 2: ./sapi/cli/php_old x.php Time (mean ± σ): 119.1 ms ± 1.3 ms [User: 114.7 ms, System: 3.6 ms] Range (min … max): 117.6 ms … 123.1 ms 24 runs Summary ./sapi/cli/php x.php ran 1.25 ± 0.03 times faster than ./sapi/cli/php_old x.php ``` On an i7-1185G7: ``` Benchmark 1: ./sapi/cli/php x.php Time (mean ± σ): 67.9 ms ± 1.1 ms [User: 64.8 ms, System: 3.2 ms] Range (min … max): 66.6 ms … 72.8 ms 43 runs Benchmark 2: ./sapi/cli/php_old x.php Time (mean ± σ): 84.8 ms ± 1.1 ms [User: 81.0 ms, System: 3.9 ms] Range (min … max): 82.6 ms … 88.0 ms 34 runs Summary ./sapi/cli/php x.php ran 1.25 ± 0.03 times faster than ./sapi/cli/php_old x.php ```
1 parent 6e0b60c commit 335c0b3

File tree

1 file changed

+28
-24
lines changed

1 file changed

+28
-24
lines changed

ext/spl/spl_fixedarray.c

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -324,14 +324,14 @@ static zend_object *spl_fixedarray_object_clone(zend_object *old_object)
324324
return new_object;
325325
}
326326

327-
static zend_long spl_offset_convert_to_long(zval *offset) /* {{{ */
327+
static zend_never_inline zend_ulong spl_offset_convert_to_ulong_slow(const zval *offset) /* {{{ */
328328
{
329329
try_again:
330330
switch (Z_TYPE_P(offset)) {
331331
case IS_STRING: {
332332
zend_ulong index;
333333
if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), index)) {
334-
return (zend_long) index;
334+
return index;
335335
}
336336
break;
337337
}
@@ -356,23 +356,35 @@ static zend_long spl_offset_convert_to_long(zval *offset) /* {{{ */
356356
return 0;
357357
}
358358

359-
static zval *spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object *intern, zval *offset)
359+
/* Returned index is an unsigned number such that we don't have to do a negative check.
360+
* Negative numbers will be mapped at indices larger than ZEND_ULONG_MAX,
361+
* which is beyond the maximum length. */
362+
static zend_always_inline zend_ulong spl_offset_convert_to_ulong(const zval *offset)
360363
{
361-
zend_long index;
364+
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
365+
/* Allow skipping exception check at call-site. */
366+
ZEND_ASSERT(!EG(exception));
367+
return Z_LVAL_P(offset);
368+
} else {
369+
return spl_offset_convert_to_ulong_slow(offset);
370+
}
371+
}
362372

373+
static zval *spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object *intern, zval *offset)
374+
{
363375
/* we have to return NULL on error here to avoid memleak because of
364376
* ZE duplicating uninitialized_zval_ptr */
365377
if (!offset) {
366378
zend_throw_error(NULL, "[] operator not supported for SplFixedArray");
367379
return NULL;
368380
}
369381

370-
index = spl_offset_convert_to_long(offset);
371-
if (EG(exception)) {
382+
zend_ulong index = spl_offset_convert_to_ulong(offset);
383+
if (UNEXPECTED(EG(exception))) {
372384
return NULL;
373385
}
374386

375-
if (index < 0 || index >= intern->array.size) {
387+
if (UNEXPECTED(index >= intern->array.size)) {
376388
zend_throw_exception(spl_ce_OutOfBoundsException, "Index invalid or out of range", 0);
377389
return NULL;
378390
} else {
@@ -407,22 +419,19 @@ static zval *spl_fixedarray_object_read_dimension(zend_object *object, zval *off
407419

408420
static void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *intern, zval *offset, zval *value)
409421
{
410-
zend_long index;
411-
412422
if (!offset) {
413423
/* '$array[] = value' syntax is not supported */
414424
zend_throw_error(NULL, "[] operator not supported for SplFixedArray");
415425
return;
416426
}
417427

418-
index = spl_offset_convert_to_long(offset);
419-
if (EG(exception)) {
428+
zend_ulong index = spl_offset_convert_to_ulong(offset);
429+
if (UNEXPECTED(EG(exception))) {
420430
return;
421431
}
422432

423-
if (index < 0 || index >= intern->array.size) {
433+
if (UNEXPECTED(index >= intern->array.size)) {
424434
zend_throw_exception(spl_ce_OutOfBoundsException, "Index invalid or out of range", 0);
425-
return;
426435
} else {
427436
/* Fix #81429 */
428437
zval *ptr = &(intern->array.elements[index]);
@@ -452,16 +461,13 @@ static void spl_fixedarray_object_write_dimension(zend_object *object, zval *off
452461

453462
static void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *intern, zval *offset)
454463
{
455-
zend_long index;
456-
457-
index = spl_offset_convert_to_long(offset);
458-
if (EG(exception)) {
464+
zend_ulong index = spl_offset_convert_to_ulong(offset);
465+
if (UNEXPECTED(EG(exception))) {
459466
return;
460467
}
461468

462-
if (index < 0 || index >= intern->array.size) {
469+
if (UNEXPECTED(index >= intern->array.size)) {
463470
zend_throw_exception(spl_ce_OutOfBoundsException, "Index invalid or out of range", 0);
464-
return;
465471
} else {
466472
zval garbage;
467473
ZVAL_COPY_VALUE(&garbage, &intern->array.elements[index]);
@@ -483,14 +489,12 @@ static void spl_fixedarray_object_unset_dimension(zend_object *object, zval *off
483489

484490
static bool spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object *intern, zval *offset, bool check_empty)
485491
{
486-
zend_long index;
487-
488-
index = spl_offset_convert_to_long(offset);
489-
if (EG(exception)) {
492+
zend_ulong index = spl_offset_convert_to_ulong(offset);
493+
if (UNEXPECTED(EG(exception))) {
490494
return false;
491495
}
492496

493-
if (index < 0 || index >= intern->array.size) {
497+
if (index >= intern->array.size) {
494498
return false;
495499
}
496500

0 commit comments

Comments
 (0)