From: Dmitry Stogov Date: Tue, 28 Apr 2015 20:57:21 +0000 (+0300) Subject: Optimize opcodes for fast path X-Git-Tag: PRE_PHP7_NSAPI_REMOVAL~124 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3057034608a1b8c91ef3ae64d5e32d59cfe82197;p=php Optimize opcodes for fast path --- diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 7d2ab9619b..20a35535ba 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -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) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8d94a09055..a1bd6b860b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 40cc771bda..f8c528db54 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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(); }