diff options
author | Tyson Andre <tysonandre775@hotmail.com> | 2021-02-12 19:42:03 -0500 |
---|---|---|
committer | Tyson Andre <tysonandre775@hotmail.com> | 2021-02-13 09:34:48 -0500 |
commit | 8ffc20ace6c8a59b30aea53e2100aa26e4f1f3ee (patch) | |
tree | 2d1a5e510b68167be1ab86dd2ea48ad2bc59ac92 | |
parent | f74a02d263aa332d995f78bd71878012952623b1 (diff) | |
download | php-git-8ffc20ace6c8a59b30aea53e2100aa26e4f1f3ee.tar.gz |
Optimize Traversable unpacking in zend_vm_def.h
The C compiler sees that a dynamic function is being called, so it cannot infer
that iter->funcs has not changed.
This results in more assembly instructions and slightly more time to execute that code
path.
Unpacking traversables to arrays(`ZEND_ADD_ARRAY_UNPACK`),
starting foreach loops (`ZEND_FE_FETCH*`), etc. are affected.
```
<?php
/*
* Before: 1.576 seconds
* After: 1.474 seconds
*/
function example() {
$start = hrtime(true);
$it = new SplFixedArray(1000);
$total = 0;
for ($i = 0; $i < 100000; $i++) {
$total += count([...$it]);
}
$end = hrtime(true);
printf("Elapsed: %.6f\n", ($end - $start) / 1_000_000_000);
}
example();
```
-rw-r--r-- | Zend/zend_vm_def.h | 52 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 52 |
2 files changed, 56 insertions, 48 deletions
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 7d0b30ff2b..a0b222fa2b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5092,26 +5092,27 @@ ZEND_VM_C_LABEL(send_again): HANDLE_EXCEPTION(); } - if (iter->funcs->rewind) { - iter->funcs->rewind(iter); + const zend_object_iterator_funcs *funcs = iter->funcs; + if (funcs->rewind) { + funcs->rewind(iter); } - for (; iter->funcs->valid(iter) == SUCCESS; ++arg_num) { + for (; funcs->valid(iter) == SUCCESS; ++arg_num) { zval *arg, *top; if (UNEXPECTED(EG(exception) != NULL)) { break; } - arg = iter->funcs->get_current_data(iter); + arg = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { break; } zend_string *name = NULL; - if (iter->funcs->get_current_key) { + if (funcs->get_current_key) { zval key; - iter->funcs->get_current_key(iter, &key); + funcs->get_current_key(iter, &key); if (UNEXPECTED(EG(exception) != NULL)) { break; } @@ -5173,7 +5174,7 @@ ZEND_VM_C_LABEL(send_again): ZEND_CALL_NUM_ARGS(EX(call))++; } - iter->funcs->move_forward(iter); + funcs->move_forward(iter); } zend_iterator_dtor(iter); @@ -5997,25 +5998,26 @@ ZEND_VM_C_LABEL(add_unpack_again): HANDLE_EXCEPTION(); } - if (iter->funcs->rewind) { - iter->funcs->rewind(iter); + const zend_object_iterator_funcs *funcs = iter->funcs; + if (funcs->rewind) { + funcs->rewind(iter); } - for (; iter->funcs->valid(iter) == SUCCESS; ) { + for (; funcs->valid(iter) == SUCCESS; ) { zval *val; if (UNEXPECTED(EG(exception) != NULL)) { break; } - val = iter->funcs->get_current_data(iter); + val = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { break; } zval key; - if (iter->funcs->get_current_key) { - iter->funcs->get_current_key(iter, &key); + if (funcs->get_current_key) { + funcs->get_current_key(iter, &key); if (UNEXPECTED(EG(exception) != NULL)) { break; } @@ -6045,7 +6047,7 @@ ZEND_VM_C_LABEL(add_unpack_again): } } - iter->funcs->move_forward(iter); + funcs->move_forward(iter); if (UNEXPECTED(EG(exception))) { break; } @@ -6748,15 +6750,16 @@ ZEND_VM_C_LABEL(fe_fetch_r_exit): } } } else { + const zend_object_iterator_funcs *funcs = iter->funcs; if (EXPECTED(++iter->index > 0)) { /* This could cause an endless loop if index becomes zero again. * In case that ever happens we need an additional flag. */ - iter->funcs->move_forward(iter); + funcs->move_forward(iter); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); } - if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) { + if (UNEXPECTED(funcs->valid(iter) == FAILURE)) { /* reached end of iteration */ if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); @@ -6765,7 +6768,7 @@ ZEND_VM_C_LABEL(fe_fetch_r_exit): ZEND_VM_C_GOTO(fe_fetch_r_exit); } } - value = iter->funcs->get_current_data(iter); + value = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); @@ -6775,8 +6778,8 @@ ZEND_VM_C_LABEL(fe_fetch_r_exit): ZEND_VM_C_GOTO(fe_fetch_r_exit); } if (RETURN_VALUE_USED(opline)) { - if (iter->funcs->get_current_key) { - iter->funcs->get_current_key(iter, EX_VAR(opline->result.var)); + if (funcs->get_current_key) { + funcs->get_current_key(iter, EX_VAR(opline->result.var)); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); @@ -6901,15 +6904,16 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR) } } } else { + const zend_object_iterator_funcs *funcs = iter->funcs; if (++iter->index > 0) { /* This could cause an endless loop if index becomes zero again. * In case that ever happens we need an additional flag. */ - iter->funcs->move_forward(iter); + funcs->move_forward(iter); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); } - if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) { + if (UNEXPECTED(funcs->valid(iter) == FAILURE)) { /* reached end of iteration */ if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); @@ -6918,7 +6922,7 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR) ZEND_VM_C_GOTO(fe_fetch_w_exit); } } - value = iter->funcs->get_current_data(iter); + value = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); @@ -6928,8 +6932,8 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR) ZEND_VM_C_GOTO(fe_fetch_w_exit); } if (RETURN_VALUE_USED(opline)) { - if (iter->funcs->get_current_key) { - iter->funcs->get_current_key(iter, EX_VAR(opline->result.var)); + if (funcs->get_current_key) { + funcs->get_current_key(iter, EX_VAR(opline->result.var)); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 0fe4fb5bb5..b170b9ab47 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2203,26 +2203,27 @@ send_again: HANDLE_EXCEPTION(); } - if (iter->funcs->rewind) { - iter->funcs->rewind(iter); + const zend_object_iterator_funcs *funcs = iter->funcs; + if (funcs->rewind) { + funcs->rewind(iter); } - for (; iter->funcs->valid(iter) == SUCCESS; ++arg_num) { + for (; funcs->valid(iter) == SUCCESS; ++arg_num) { zval *arg, *top; if (UNEXPECTED(EG(exception) != NULL)) { break; } - arg = iter->funcs->get_current_data(iter); + arg = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { break; } zend_string *name = NULL; - if (iter->funcs->get_current_key) { + if (funcs->get_current_key) { zval key; - iter->funcs->get_current_key(iter, &key); + funcs->get_current_key(iter, &key); if (UNEXPECTED(EG(exception) != NULL)) { break; } @@ -2284,7 +2285,7 @@ send_again: ZEND_CALL_NUM_ARGS(EX(call))++; } - iter->funcs->move_forward(iter); + funcs->move_forward(iter); } zend_iterator_dtor(iter); @@ -2544,25 +2545,26 @@ add_unpack_again: HANDLE_EXCEPTION(); } - if (iter->funcs->rewind) { - iter->funcs->rewind(iter); + const zend_object_iterator_funcs *funcs = iter->funcs; + if (funcs->rewind) { + funcs->rewind(iter); } - for (; iter->funcs->valid(iter) == SUCCESS; ) { + for (; funcs->valid(iter) == SUCCESS; ) { zval *val; if (UNEXPECTED(EG(exception) != NULL)) { break; } - val = iter->funcs->get_current_data(iter); + val = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { break; } zval key; - if (iter->funcs->get_current_key) { - iter->funcs->get_current_key(iter, &key); + if (funcs->get_current_key) { + funcs->get_current_key(iter, &key); if (UNEXPECTED(EG(exception) != NULL)) { break; } @@ -2592,7 +2594,7 @@ add_unpack_again: } } - iter->funcs->move_forward(iter); + funcs->move_forward(iter); if (UNEXPECTED(EG(exception))) { break; } @@ -21692,15 +21694,16 @@ fe_fetch_r_exit: } } } else { + const zend_object_iterator_funcs *funcs = iter->funcs; if (EXPECTED(++iter->index > 0)) { /* This could cause an endless loop if index becomes zero again. * In case that ever happens we need an additional flag. */ - iter->funcs->move_forward(iter); + funcs->move_forward(iter); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); } - if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) { + if (UNEXPECTED(funcs->valid(iter) == FAILURE)) { /* reached end of iteration */ if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); @@ -21709,7 +21712,7 @@ fe_fetch_r_exit: goto fe_fetch_r_exit; } } - value = iter->funcs->get_current_data(iter); + value = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); @@ -21719,8 +21722,8 @@ fe_fetch_r_exit: goto fe_fetch_r_exit; } if (RETURN_VALUE_USED(opline)) { - if (iter->funcs->get_current_key) { - iter->funcs->get_current_key(iter, EX_VAR(opline->result.var)); + if (funcs->get_current_key) { + funcs->get_current_key(iter, EX_VAR(opline->result.var)); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); @@ -21845,15 +21848,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z } } } else { + const zend_object_iterator_funcs *funcs = iter->funcs; if (++iter->index > 0) { /* This could cause an endless loop if index becomes zero again. * In case that ever happens we need an additional flag. */ - iter->funcs->move_forward(iter); + funcs->move_forward(iter); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); } - if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) { + if (UNEXPECTED(funcs->valid(iter) == FAILURE)) { /* reached end of iteration */ if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); @@ -21862,7 +21866,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z goto fe_fetch_w_exit; } } - value = iter->funcs->get_current_data(iter); + value = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); @@ -21872,8 +21876,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z goto fe_fetch_w_exit; } if (RETURN_VALUE_USED(opline)) { - if (iter->funcs->get_current_key) { - iter->funcs->get_current_key(iter, EX_VAR(opline->result.var)); + if (funcs->get_current_key) { + funcs->get_current_key(iter, EX_VAR(opline->result.var)); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); |