]> granicus.if.org Git - php/commitdiff
Improve zend_leave_helper() by checking all rare conditions at once.
authorDmitry Stogov <dmitry@zend.com>
Mon, 11 Apr 2016 10:17:24 +0000 (13:17 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 11 Apr 2016 10:17:24 +0000 (13:17 +0300)
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 7a6974de09b8e0b36bf65d0b1e9e855a47b79c53..7f2dd632b97e1f05e0c6f905f88931e76171e3c4 100644 (file)
@@ -2514,34 +2514,56 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
        uint32_t call_info = EX_CALL_INFO();
 
        if (EXPECTED(ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_FUNCTION)) {
-               zend_object *object;
-
                i_free_compiled_variables(execute_data);
-               if (UNEXPECTED(call_info & ZEND_CALL_FREE_SYMBOL_TABLE)) {
-                       zend_clean_and_cache_symbol_table(EX(symbol_table));
-               }
-               zend_vm_stack_free_extra_args_ex(call_info, execute_data);
-               old_execute_data = execute_data;
-               execute_data = EG(current_execute_data) = EX(prev_execute_data);
-               if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
-                       object = Z_OBJ(old_execute_data->This);
+               if (UNEXPECTED(call_info & (ZEND_CALL_FREE_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED))) {
+                       if (UNEXPECTED(call_info & ZEND_CALL_FREE_SYMBOL_TABLE)) {
+                               zend_clean_and_cache_symbol_table(EX(symbol_table));
+                       }
+                       EG(current_execute_data) = EX(prev_execute_data);
+                       if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
+                               zend_object *object = Z_OBJ(execute_data->This);
 #if 0
-                       if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
+                               if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
 #else
-                       if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
+                               if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
 #endif
-                               GC_REFCOUNT(object)--;
-                               if (GC_REFCOUNT(object) == 1) {
-                                       zend_object_store_ctor_failed(object);
+                                       GC_REFCOUNT(object)--;
+                                       if (GC_REFCOUNT(object) == 1) {
+                                               zend_object_store_ctor_failed(object);
+                                       }
                                }
+                               OBJ_RELEASE(object);
+                       } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+                               OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
                        }
-                       OBJ_RELEASE(object);
-               } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
-                       OBJ_RELEASE((zend_object*)old_execute_data->func->op_array.prototype);
+
+                       zend_vm_stack_free_extra_args_ex(call_info, execute_data);
+                       old_execute_data = execute_data;
+                       execute_data = EX(prev_execute_data);
+                       zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
+               } else {
+                       EG(current_execute_data) = EX(prev_execute_data);
+                       if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
+                               zend_object *object = Z_OBJ(execute_data->This);
+#if 0
+                               if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
+#else
+                               if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
+#endif
+                                       GC_REFCOUNT(object)--;
+                                       if (GC_REFCOUNT(object) == 1) {
+                                               zend_object_store_ctor_failed(object);
+                                       }
+                               }
+                               OBJ_RELEASE(object);
+                       } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+                               OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
+                       }
+                       EG(vm_stack_top) = (zval*)execute_data;
+                       execute_data = EX(prev_execute_data);
                }
-               EG(scope) = EX(func)->op_array.scope;
 
-               zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
+               EG(scope) = EX(func)->op_array.scope;
 
                if (UNEXPECTED(EG(exception) != NULL)) {
                        const zend_op *old_opline = EX(opline);
@@ -2554,8 +2576,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
 
                LOAD_NEXT_OPLINE();
                ZEND_VM_LEAVE();
-       }
-       if (EXPECTED((ZEND_CALL_KIND_EX(call_info) & ZEND_CALL_TOP) == 0)) {
+       } else if (EXPECTED((ZEND_CALL_KIND_EX(call_info) & ZEND_CALL_TOP) == 0)) {
                zend_detach_symbol_table(execute_data);
                destroy_op_array(&EX(func)->op_array);
                efree_size(EX(func), sizeof(zend_op_array));
@@ -2574,14 +2595,17 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
        } else {
                if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_TOP_FUNCTION) {
                        i_free_compiled_variables(execute_data);
-                       if (UNEXPECTED(call_info & ZEND_CALL_FREE_SYMBOL_TABLE)) {
-                               zend_clean_and_cache_symbol_table(EX(symbol_table));
+                       if (UNEXPECTED(call_info & (ZEND_CALL_FREE_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS))) {
+                               if (UNEXPECTED(call_info & ZEND_CALL_FREE_SYMBOL_TABLE)) {
+                                       zend_clean_and_cache_symbol_table(EX(symbol_table));
+                               }
+                               zend_vm_stack_free_extra_args_ex(call_info, execute_data);
                        }
-                       zend_vm_stack_free_extra_args_ex(call_info, execute_data);
                        EG(current_execute_data) = EX(prev_execute_data);
                        if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
                                OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
                        }
+                       ZEND_VM_RETURN();
                } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ {
                        zend_array *symbol_table = EX(symbol_table);
 
@@ -2597,9 +2621,8 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
                                old_execute_data = old_execute_data->prev_execute_data;
                        }
                        EG(current_execute_data) = EX(prev_execute_data);
+                       ZEND_VM_RETURN();
                }
-
-               ZEND_VM_RETURN();
        }
 }
 
index 0b3bafecf00bb80780936229c1e6fc21c9b800d8..8e2541f78c35a3a56df2cf9f1e96892d09f6e95a 100644 (file)
@@ -475,34 +475,56 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
        uint32_t call_info = EX_CALL_INFO();
 
        if (EXPECTED(ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_FUNCTION)) {
-               zend_object *object;
-
                i_free_compiled_variables(execute_data);
-               if (UNEXPECTED(call_info & ZEND_CALL_FREE_SYMBOL_TABLE)) {
-                       zend_clean_and_cache_symbol_table(EX(symbol_table));
-               }
-               zend_vm_stack_free_extra_args_ex(call_info, execute_data);
-               old_execute_data = execute_data;
-               execute_data = EG(current_execute_data) = EX(prev_execute_data);
-               if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
-                       object = Z_OBJ(old_execute_data->This);
+               if (UNEXPECTED(call_info & (ZEND_CALL_FREE_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED))) {
+                       if (UNEXPECTED(call_info & ZEND_CALL_FREE_SYMBOL_TABLE)) {
+                               zend_clean_and_cache_symbol_table(EX(symbol_table));
+                       }
+                       EG(current_execute_data) = EX(prev_execute_data);
+                       if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
+                               zend_object *object = Z_OBJ(execute_data->This);
 #if 0
-                       if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
+                               if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
 #else
-                       if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
+                               if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
 #endif
-                               GC_REFCOUNT(object)--;
-                               if (GC_REFCOUNT(object) == 1) {
-                                       zend_object_store_ctor_failed(object);
+                                       GC_REFCOUNT(object)--;
+                                       if (GC_REFCOUNT(object) == 1) {
+                                               zend_object_store_ctor_failed(object);
+                                       }
                                }
+                               OBJ_RELEASE(object);
+                       } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+                               OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
                        }
-                       OBJ_RELEASE(object);
-               } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
-                       OBJ_RELEASE((zend_object*)old_execute_data->func->op_array.prototype);
+
+                       zend_vm_stack_free_extra_args_ex(call_info, execute_data);
+                       old_execute_data = execute_data;
+                       execute_data = EX(prev_execute_data);
+                       zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
+               } else {
+                       EG(current_execute_data) = EX(prev_execute_data);
+                       if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
+                               zend_object *object = Z_OBJ(execute_data->This);
+#if 0
+                               if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
+#else
+                               if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
+#endif
+                                       GC_REFCOUNT(object)--;
+                                       if (GC_REFCOUNT(object) == 1) {
+                                               zend_object_store_ctor_failed(object);
+                                       }
+                               }
+                               OBJ_RELEASE(object);
+                       } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+                               OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
+                       }
+                       EG(vm_stack_top) = (zval*)execute_data;
+                       execute_data = EX(prev_execute_data);
                }
-               EG(scope) = EX(func)->op_array.scope;
 
-               zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
+               EG(scope) = EX(func)->op_array.scope;
 
                if (UNEXPECTED(EG(exception) != NULL)) {
                        const zend_op *old_opline = EX(opline);
@@ -515,8 +537,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
 
                LOAD_NEXT_OPLINE();
                ZEND_VM_LEAVE();
-       }
-       if (EXPECTED((ZEND_CALL_KIND_EX(call_info) & ZEND_CALL_TOP) == 0)) {
+       } else if (EXPECTED((ZEND_CALL_KIND_EX(call_info) & ZEND_CALL_TOP) == 0)) {
                zend_detach_symbol_table(execute_data);
                destroy_op_array(&EX(func)->op_array);
                efree_size(EX(func), sizeof(zend_op_array));
@@ -535,14 +556,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
        } else {
                if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_TOP_FUNCTION) {
                        i_free_compiled_variables(execute_data);
-                       if (UNEXPECTED(call_info & ZEND_CALL_FREE_SYMBOL_TABLE)) {
-                               zend_clean_and_cache_symbol_table(EX(symbol_table));
+                       if (UNEXPECTED(call_info & (ZEND_CALL_FREE_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS))) {
+                               if (UNEXPECTED(call_info & ZEND_CALL_FREE_SYMBOL_TABLE)) {
+                                       zend_clean_and_cache_symbol_table(EX(symbol_table));
+                               }
+                               zend_vm_stack_free_extra_args_ex(call_info, execute_data);
                        }
-                       zend_vm_stack_free_extra_args_ex(call_info, execute_data);
                        EG(current_execute_data) = EX(prev_execute_data);
                        if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
                                OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
                        }
+                       ZEND_VM_RETURN();
                } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ {
                        zend_array *symbol_table = EX(symbol_table);
 
@@ -558,9 +582,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
                                old_execute_data = old_execute_data->prev_execute_data;
                        }
                        EG(current_execute_data) = EX(prev_execute_data);
+                       ZEND_VM_RETURN();
                }
-
-               ZEND_VM_RETURN();
        }
 }