]> granicus.if.org Git - php/commitdiff
Optimize Traversable unpacking in zend_vm_def.h
authorTyson Andre <tysonandre775@hotmail.com>
Sat, 13 Feb 2021 00:42:03 +0000 (19:42 -0500)
committerTyson Andre <tysonandre775@hotmail.com>
Sat, 13 Feb 2021 14:34:48 +0000 (09:34 -0500)
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();
```

Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 7d0b30ff2bdc257c76ab3a93e42ceb390126e88c..a0b222fa2bc67723216c5e56f8fb074273db7150 100644 (file)
@@ -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();
index 0fe4fb5bb5d0ca8cbdb5c469ef91314ed3e4f82a..b170b9ab475e4f529c0423d1ea97fef8771997ec 100644 (file)
@@ -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();