]> granicus.if.org Git - php/commitdiff
Optimize opcodes for fast path
authorDmitry Stogov <dmitry@zend.com>
Tue, 28 Apr 2015 20:57:21 +0000 (23:57 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 28 Apr 2015 20:57:21 +0000 (23:57 +0300)
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 7d2ab9619b72d23d475a3cdc492288a796b3be1b..20a35535ba60a2099e7ad12bde2d5f5c6853e91c 100644 (file)
@@ -527,16 +527,16 @@ static inline zval *_get_obj_zval_ptr_ptr(int op_type, znode_op node, zend_execu
 
 static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr)
 {
+       if (EXPECTED(!Z_ISREF_P(value_ptr))) {
+               ZVAL_NEW_REF(value_ptr, value_ptr);
+       }
        if (EXPECTED(variable_ptr != value_ptr)) {
                zend_reference *ref;
-               ZVAL_MAKE_REF(value_ptr);
-               Z_ADDREF_P(value_ptr);
-               ref = Z_REF_P(value_ptr);
 
+               ref = Z_REF_P(value_ptr);
+               GC_REFCOUNT(ref)++;
                zval_ptr_dtor(variable_ptr);
                ZVAL_REF(variable_ptr, ref);
-       } else {
-               ZVAL_MAKE_REF(variable_ptr);
        }
 }
 
@@ -743,7 +743,7 @@ static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, z
        }
 }
 
-static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value)
+static int zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value)
 {
        zend_arg_info *cur_arg_info;
        char *need_msg, *class_name;
@@ -754,7 +754,7 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg,
        } else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) {
                cur_arg_info = &zf->common.arg_info[zf->common.num_args];
        } else {
-               return;
+               return 1;
        }
 
        if (cur_arg_info->type_hint) {
@@ -764,24 +764,29 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg,
                                need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
                                if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) {
                                        zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
+                                       return 0;
                                }
                        }
                } else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value)))) {
                        if (cur_arg_info->class_name) {
                                need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
                                zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
+                               return 0;
                        } else if (cur_arg_info->type_hint == IS_CALLABLE) {
                                if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
                                        zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
+                                       return 0;
                                }
                        } else if (cur_arg_info->type_hint == _IS_BOOL &&
                                   EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
                                /* pass */
                        } else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_ARG_USES_STRICT_TYPES()))) {
                                zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
+                               return 0;
                        }
                }
        }
+       return 1;
 }
 
 static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num)
@@ -804,7 +809,6 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n
 
                        need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
                        zend_verify_arg_error(zf, arg_num, need_msg, class_name, "none", "", NULL);
-                       return 0;
                } else if (cur_arg_info->type_hint == IS_CALLABLE) {
                        zend_verify_arg_error(zf, arg_num, "be callable", "", "none", "", NULL);
                } else {
@@ -815,7 +819,7 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n
        return 1;
 }
 
-static void zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t arg_num)
+static int zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t arg_num)
 {
        if (EXPECTED(!(EX(func)->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) ||
            zend_verify_missing_arg_type(EX(func), arg_num)) {
@@ -829,7 +833,9 @@ static void zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t ar
                } else {
                        zend_error(E_WARNING, "Missing argument %u for %s%s%s()", arg_num, class_name, space, func_name);
                }
+               return 1;
        }
+       return 0;
 }
 
 ZEND_API void zend_verify_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
index 8d94a090553fb1ce655e7d5bd43833df0d23c0cd..a1bd6b860b0a11baa1a785e2545753ee4441169d 100644 (file)
@@ -4590,14 +4590,16 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY)
 
        if (UNEXPECTED(arg_num > EX_NUM_ARGS())) {
                SAVE_OPLINE();
-               zend_verify_missing_arg(execute_data, arg_num);
-               CHECK_EXCEPTION();
+               if (UNEXPECTED(!zend_verify_missing_arg(execute_data, arg_num))) {
+                       HANDLE_EXCEPTION();
+               }
        } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
                zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var);
 
                SAVE_OPLINE();
-               zend_verify_arg_type(EX(func), arg_num, param, NULL);
-               CHECK_EXCEPTION();
+               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL))) {
+                       HANDLE_EXCEPTION();
+               }
        }
 
        ZEND_VM_NEXT_OPCODE();
@@ -4609,11 +4611,11 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
        uint32_t arg_num = opline->op1.num;
        zval *param;
 
-       SAVE_OPLINE();
        param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var);
        if (arg_num > EX_NUM_ARGS()) {
                ZVAL_COPY_VALUE(param, EX_CONSTANT(opline->op2));
                if (Z_OPT_CONSTANT_P(param)) {
+                       SAVE_OPLINE();
                        if (UNEXPECTED(zval_update_constant_ex(param, 0, NULL) != SUCCESS)) {
                                ZVAL_UNDEF(param);
                                HANDLE_EXCEPTION();
@@ -4627,10 +4629,12 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
        }
 
        if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
-               zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2));
+               SAVE_OPLINE();
+               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2)))) {
+                       HANDLE_EXCEPTION();
+               }
        }
 
-       CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
 }
 
@@ -7609,7 +7613,6 @@ ZEND_VM_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST)
        zval *variable_ptr;
        uint32_t idx;
 
-       SAVE_OPLINE();
        varname = GET_OP2_ZVAL_PTR(BP_VAR_R);
 
        /* We store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
@@ -7650,9 +7653,30 @@ ZEND_VM_C_LABEL(check_indirect):
        }
 
        variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
-       zend_assign_to_variable_reference(variable_ptr, value);
 
-       CHECK_EXCEPTION();
+       if (UNEXPECTED(!Z_ISREF_P(value))) {
+               ZVAL_NEW_REF(value, value);
+       }
+       if (EXPECTED(variable_ptr != value)) {
+               zend_reference *ref;
+
+               ref = Z_REF_P(value);
+               GC_REFCOUNT(ref)++;
+               if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
+                       if (!Z_DELREF_P(variable_ptr)) {
+                               SAVE_OPLINE();
+                               zval_dtor_func_for_ptr(Z_COUNTED_P(variable_ptr));
+                               if (UNEXPECTED(EG(exception))) {
+                                       ZVAL_NULL(variable_ptr);
+                                       HANDLE_EXCEPTION();
+                               }
+                       } else {
+                               GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
+                       }
+               }
+               ZVAL_REF(variable_ptr, ref);
+       }
+
        ZEND_VM_NEXT_OPCODE();
 }
 
index 40cc771bda33dc8a58c0ff39f4323144d75db733..f8c528db54ad098e0bd10a6cf4351ac62deec1aa 100644 (file)
@@ -1182,14 +1182,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_
 
        if (UNEXPECTED(arg_num > EX_NUM_ARGS())) {
                SAVE_OPLINE();
-               zend_verify_missing_arg(execute_data, arg_num);
-               CHECK_EXCEPTION();
+               if (UNEXPECTED(!zend_verify_missing_arg(execute_data, arg_num))) {
+                       HANDLE_EXCEPTION();
+               }
        } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
                zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var);
 
                SAVE_OPLINE();
-               zend_verify_arg_type(EX(func), arg_num, param, NULL);
-               CHECK_EXCEPTION();
+               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL))) {
+                       HANDLE_EXCEPTION();
+               }
        }
 
        ZEND_VM_NEXT_OPCODE();
@@ -2225,11 +2227,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(Z
        uint32_t arg_num = opline->op1.num;
        zval *param;
 
-       SAVE_OPLINE();
        param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var);
        if (arg_num > EX_NUM_ARGS()) {
                ZVAL_COPY_VALUE(param, EX_CONSTANT(opline->op2));
                if (Z_OPT_CONSTANT_P(param)) {
+                       SAVE_OPLINE();
                        if (UNEXPECTED(zval_update_constant_ex(param, 0, NULL) != SUCCESS)) {
                                ZVAL_UNDEF(param);
                                HANDLE_EXCEPTION();
@@ -2243,10 +2245,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(Z
        }
 
        if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
-               zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2));
+               SAVE_OPLINE();
+               if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2)))) {
+                       HANDLE_EXCEPTION();
+               }
        }
 
-       CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
 }
 
@@ -32552,7 +32556,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_GLOBAL_SPEC_CV_CONST_HAND
        zval *variable_ptr;
        uint32_t idx;
 
-       SAVE_OPLINE();
        varname = EX_CONSTANT(opline->op2);
 
        /* We store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
@@ -32593,9 +32596,30 @@ check_indirect:
        }
 
        variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var);
-       zend_assign_to_variable_reference(variable_ptr, value);
 
-       CHECK_EXCEPTION();
+       if (UNEXPECTED(!Z_ISREF_P(value))) {
+               ZVAL_NEW_REF(value, value);
+       }
+       if (EXPECTED(variable_ptr != value)) {
+               zend_reference *ref;
+
+               ref = Z_REF_P(value);
+               GC_REFCOUNT(ref)++;
+               if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
+                       if (!Z_DELREF_P(variable_ptr)) {
+                               SAVE_OPLINE();
+                               zval_dtor_func_for_ptr(Z_COUNTED_P(variable_ptr));
+                               if (UNEXPECTED(EG(exception))) {
+                                       ZVAL_NULL(variable_ptr);
+                                       HANDLE_EXCEPTION();
+                               }
+                       } else {
+                               GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
+                       }
+               }
+               ZVAL_REF(variable_ptr, ref);
+       }
+
        ZEND_VM_NEXT_OPCODE();
 }