mirror of
https://github.com/php/php-src.git
synced 2026-04-09 17:13:31 +02:00
Speed up foreach/FE_FREE (optimize for arrays without gc)
In the case where there are still references to an array being iterated
over when the iterator is freed (or the array is not reference counted):
- There's need to save the opline.
- There's no need to check for exceptions.
```
// Before: 0.404 seconds
// After: 0.362 seconds
// loop_iter_empty(1000, 5000);
function loop_iter_empty(int $a, int $b) {
$values = array_fill(0, $b, []);
$total = 0;
for ($i = 0; $i < $b; $i++) {
foreach ($values as $v) {
foreach ($v as $x) {
$total += $x;
}
}
}
return $total;
}
```
This commit is contained in:
committed by
Dmitry Stogov
parent
8bf663d3b2
commit
7901913b83
@@ -3044,13 +3044,24 @@ ZEND_VM_HOT_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
|
||||
zval *var;
|
||||
USE_OPLINE
|
||||
|
||||
SAVE_OPLINE();
|
||||
var = EX_VAR(opline->op1.var);
|
||||
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
if (Z_TYPE_P(var) != IS_ARRAY) {
|
||||
SAVE_OPLINE();
|
||||
if (Z_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
|
||||
/* This is freeing an array. Use an inlined version of zval_ptr_dtor_nogc. */
|
||||
/* PHP only needs to save the opline and check for an exception if the last reference to the array was garbage collected (destructors of elements in the array could throw an exception) */
|
||||
if (Z_REFCOUNTED_P(var) && !Z_DELREF_P(var)) {
|
||||
SAVE_OPLINE();
|
||||
rc_dtor_func(Z_COUNTED_P(var));
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
|
||||
|
||||
@@ -12882,13 +12882,24 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FREE_SPEC_TMPVA
|
||||
zval *var;
|
||||
USE_OPLINE
|
||||
|
||||
SAVE_OPLINE();
|
||||
var = EX_VAR(opline->op1.var);
|
||||
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
if (Z_TYPE_P(var) != IS_ARRAY) {
|
||||
SAVE_OPLINE();
|
||||
if (Z_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
|
||||
/* This is freeing an array. Use an inlined version of zval_ptr_dtor_nogc. */
|
||||
/* PHP only needs to save the opline and check for an exception if the last reference to the array was garbage collected (destructors of elements in the array could throw an exception) */
|
||||
if (Z_REFCOUNTED_P(var) && !Z_DELREF_P(var)) {
|
||||
SAVE_OPLINE();
|
||||
rc_dtor_func(Z_COUNTED_P(var));
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_THROW_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
|
||||
Reference in New Issue
Block a user