Improved new Zend Parameter Parsing API to avoid useless dereferences.

This derefernce made sense only for explicit paramter passing by reference, but this feature was removed in PHP-7.
The improvement is 100% backward compatible, only few "tricky" functions may be affected (e.g. extract and usort).
This commit is contained in:
Dmitry Stogov 2017-06-08 13:03:24 +03:00
parent bdc37442bf
commit ace9fe5317
2 changed files with 97 additions and 50 deletions

View file

@ -779,7 +779,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(zend_bool throw_
#define ZEND_PARSE_PARAMETERS_END() \
ZEND_PARSE_PARAMETERS_END_EX(return)
#define Z_PARAM_PROLOGUE(separate) \
#define Z_PARAM_PROLOGUE(deref, separate) \
++_i; \
ZEND_ASSERT(_i <= _min_num_args || _optional==1); \
ZEND_ASSERT(_i > _min_num_args || _optional==0); \
@ -788,7 +788,9 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(zend_bool throw_
} \
_real_arg++; \
_arg = _real_arg; \
ZVAL_DEREF(_arg); \
if (deref) { \
ZVAL_DEREF(_arg); \
} \
if (separate) { \
SEPARATE_ZVAL_NOREF(_arg); \
}
@ -798,67 +800,82 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(zend_bool throw_
_optional = 1;
/* old "a" */
#define Z_PARAM_ARRAY_EX(dest, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_ARRAY_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_array(_arg, &dest, check_null, 0))) { \
_expected_type = Z_EXPECTED_ARRAY; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_ARRAY_EX(dest, check_null, separate) \
Z_PARAM_ARRAY_EX2(dest, check_null, separate, separate)
#define Z_PARAM_ARRAY(dest) \
Z_PARAM_ARRAY_EX(dest, 0, 0)
/* old "A" */
#define Z_PARAM_ARRAY_OR_OBJECT_EX(dest, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_ARRAY_OR_OBJECT_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_array(_arg, &dest, check_null, 1))) { \
_expected_type = Z_EXPECTED_ARRAY; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_ARRAY_OR_OBJECT_EX(dest, check_null, separate) \
Z_PARAM_ARRAY_OR_OBJECT_EX2(dest, check_null, separate, separate)
#define Z_PARAM_ARRAY_OR_OBJECT(dest, check_null, separate) \
Z_PARAM_ARRAY_OR_OBJECT_EX(dest, 0, 0)
/* old "b" */
#define Z_PARAM_BOOL_EX(dest, is_null, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_BOOL_EX2(dest, is_null, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_bool(_arg, &dest, &is_null, check_null))) { \
_expected_type = Z_EXPECTED_BOOL; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_BOOL_EX(dest, is_null, check_null, separate) \
Z_PARAM_BOOL_EX2(dest, is_null, check_null, separate, separate)
#define Z_PARAM_BOOL(dest) \
Z_PARAM_BOOL_EX(dest, _dummy, 0, 0)
/* old "C" */
#define Z_PARAM_CLASS_EX(dest, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_CLASS_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_class(_arg, &dest, _i, check_null))) { \
error_code = ZPP_ERROR_FAILURE; \
break; \
}
#define Z_PARAM_CLASS_EX(dest, check_null, separate) \
Z_PARAM_CLASS_EX2(dest, check_null, separate, separate)
#define Z_PARAM_CLASS(dest) \
Z_PARAM_CLASS_EX(dest, 0, 0)
/* old "d" */
#define Z_PARAM_DOUBLE_EX(dest, is_null, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_DOUBLE_EX2(dest, is_null, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_double(_arg, &dest, &is_null, check_null))) { \
_expected_type = Z_EXPECTED_DOUBLE; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_DOUBLE_EX(dest, is_null, check_null, separate) \
Z_PARAM_DOUBLE_EX2(dest, is_null, check_null, separate, separate)
#define Z_PARAM_DOUBLE(dest) \
Z_PARAM_DOUBLE_EX(dest, _dummy, 0, 0)
/* old "f" */
#define Z_PARAM_FUNC_EX(dest_fci, dest_fcc, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_FUNC_EX2(dest_fci, dest_fcc, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_func(_arg, &dest_fci, &dest_fcc, check_null, &_error))) { \
if (!_error) { \
_expected_type = Z_EXPECTED_FUNC; \
@ -872,72 +889,90 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(zend_bool throw_
zend_wrong_callback_error(_flags & ZEND_PARSE_PARAMS_THROW, E_DEPRECATED, _i, _error); \
}
#define Z_PARAM_FUNC_EX(dest_fci, dest_fcc, check_null, separate) \
Z_PARAM_FUNC_EX2(dest_fci, dest_fcc, check_null, separate, separate)
#define Z_PARAM_FUNC(dest_fci, dest_fcc) \
Z_PARAM_FUNC_EX(dest_fci, dest_fcc, 0, 0)
/* old "h" */
#define Z_PARAM_ARRAY_HT_EX(dest, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_ARRAY_HT_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_array_ht(_arg, &dest, check_null, 0, separate))) { \
_expected_type = Z_EXPECTED_ARRAY; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_ARRAY_HT_EX(dest, check_null, separate) \
Z_PARAM_ARRAY_HT_EX2(dest, check_null, separate, separate)
#define Z_PARAM_ARRAY_HT(dest) \
Z_PARAM_ARRAY_HT_EX(dest, 0, 0)
/* old "H" */
#define Z_PARAM_ARRAY_OR_OBJECT_HT_EX(dest, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_ARRAY_OR_OBJECT_HT_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_array_ht(_arg, &dest, check_null, 1, separate))) { \
_expected_type = Z_EXPECTED_ARRAY; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_ARRAY_OR_OBJECT_HT_EX(dest, check_null, separate) \
Z_PARAM_ARRAY_OR_OBJECT_HT_EX2(dest, check_null, separate, separate)
#define Z_PARAM_ARRAY_OR_OBJECT_HT(dest) \
Z_PARAM_ARRAY_OR_OBJECT_HT_EX(dest, 0, 0)
/* old "l" */
#define Z_PARAM_LONG_EX(dest, is_null, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_LONG_EX2(dest, is_null, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_long(_arg, &dest, &is_null, check_null, 0))) { \
_expected_type = Z_EXPECTED_LONG; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_LONG_EX(dest, is_null, check_null, separate) \
Z_PARAM_LONG_EX2(dest, is_null, check_null, separate, separate)
#define Z_PARAM_LONG(dest) \
Z_PARAM_LONG_EX(dest, _dummy, 0, 0)
/* old "L" */
#define Z_PARAM_STRICT_LONG_EX(dest, is_null, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_STRICT_LONG_EX2(dest, is_null, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_long(_arg, &dest, &is_null, check_null, 1))) { \
_expected_type = Z_EXPECTED_LONG; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_STRICT_LONG_EX(dest, is_null, check_null, separate) \
Z_PARAM_STRICT_LONG_EX2(dest, is_null, check_null, separate, separate)
#define Z_PARAM_STRICT_LONG(dest) \
Z_PARAM_STRICT_LONG_EX(dest, _dummy, 0, 0)
/* old "o" */
#define Z_PARAM_OBJECT_EX(dest, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_OBJECT_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_object(_arg, &dest, NULL, check_null))) { \
_expected_type = Z_EXPECTED_OBJECT; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_OBJECT_EX(dest, check_null, separate) \
Z_PARAM_OBJECT_EX2(dest, check_null, separate, separate)
#define Z_PARAM_OBJECT(dest) \
Z_PARAM_OBJECT_EX(dest, 0, 0)
/* old "O" */
#define Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_OBJECT_OF_CLASS_EX2(dest, _ce, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_object(_arg, &dest, _ce, check_null))) { \
if (_ce) { \
_error = ZSTR_VAL((_ce)->name); \
@ -950,89 +985,101 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(zend_bool throw_
} \
}
#define Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, check_null, separate) \
Z_PARAM_OBJECT_OF_CLASS_EX2(dest, _ce, check_null, separate, separate)
#define Z_PARAM_OBJECT_OF_CLASS(dest, _ce) \
Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, 0, 0)
/* old "p" */
#define Z_PARAM_PATH_EX(dest, dest_len, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_PATH_EX2(dest, dest_len, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_path(_arg, &dest, &dest_len, check_null))) { \
_expected_type = Z_EXPECTED_PATH; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_PATH_EX(dest, dest_len, check_null, separate) \
Z_PARAM_PATH_EX2(dest, dest_len, check_null, separate, separate)
#define Z_PARAM_PATH(dest, dest_len) \
Z_PARAM_PATH_EX(dest, dest_len, 0, 0)
/* old "P" */
#define Z_PARAM_PATH_STR_EX(dest, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_PATH_STR_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_path_str(_arg, &dest, check_null))) { \
_expected_type = Z_EXPECTED_PATH; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_PATH_STR_EX(dest, check_null, separate) \
Z_PARAM_PATH_STR_EX2(dest, check_null, separate, separate)
#define Z_PARAM_PATH_STR(dest) \
Z_PARAM_PATH_STR_EX(dest, 0, 0)
/* old "r" */
#define Z_PARAM_RESOURCE_EX(dest, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_RESOURCE_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_resource(_arg, &dest, check_null))) { \
_expected_type = Z_EXPECTED_RESOURCE; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_RESOURCE_EX(dest, check_null, separate) \
Z_PARAM_RESOURCE_EX2(dest, check_null, separate, separate)
#define Z_PARAM_RESOURCE(dest) \
Z_PARAM_RESOURCE_EX(dest, 0, 0)
/* old "s" */
#define Z_PARAM_STRING_EX(dest, dest_len, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_STRING_EX2(dest, dest_len, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_string(_arg, &dest, &dest_len, check_null))) { \
_expected_type = Z_EXPECTED_STRING; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_STRING_EX(dest, dest_len, check_null, separate) \
Z_PARAM_STRING_EX2(dest, dest_len, check_null, separate, separate)
#define Z_PARAM_STRING(dest, dest_len) \
Z_PARAM_STRING_EX(dest, dest_len, 0, 0)
/* old "S" */
#define Z_PARAM_STR_EX(dest, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
#define Z_PARAM_STR_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_str(_arg, &dest, check_null))) { \
_expected_type = Z_EXPECTED_STRING; \
error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}
#define Z_PARAM_STR_EX(dest, check_null, separate) \
Z_PARAM_STR_EX2(dest, check_null, separate, separate)
#define Z_PARAM_STR(dest) \
Z_PARAM_STR_EX(dest, 0, 0)
/* old "z" */
#define Z_PARAM_ZVAL_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
zend_parse_arg_zval_deref(_arg, &dest, check_null);
#define Z_PARAM_ZVAL_EX(dest, check_null, separate) \
if (separate) { \
Z_PARAM_PROLOGUE(separate); \
zend_parse_arg_zval_deref(_arg, &dest, check_null); \
} else { \
++_i; \
ZEND_ASSERT(_i <= _min_num_args || _optional==1); \
ZEND_ASSERT(_i > _min_num_args || _optional==0); \
if (_optional && UNEXPECTED(_i >_num_args)) break; \
_real_arg++; \
zend_parse_arg_zval(_real_arg, &dest, check_null); \
}
Z_PARAM_ZVAL_EX2(dest, check_null, separate, separate)
#define Z_PARAM_ZVAL(dest) \
Z_PARAM_ZVAL_EX(dest, 0, 0)
/* old "z" (with dereference) */
#define Z_PARAM_ZVAL_DEREF_EX(dest, check_null, separate) \
Z_PARAM_PROLOGUE(separate); \
Z_PARAM_PROLOGUE(1, separate); \
zend_parse_arg_zval_deref(_arg, &dest, check_null);
#define Z_PARAM_ZVAL_DEREF(dest) \

View file

@ -1035,7 +1035,7 @@ static void php_usort(INTERNAL_FUNCTION_PARAMETERS, compare_func_t compare_func,
PHP_ARRAY_CMP_FUNC_BACKUP();
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_ARRAY(array)
Z_PARAM_ARRAY_EX2(array, 0, 1, 0)
Z_PARAM_FUNC(BG(user_compare_fci), BG(user_compare_fci_cache))
ZEND_PARSE_PARAMETERS_END_EX( PHP_ARRAY_CMP_FUNC_RESTORE(); return );
@ -2467,7 +2467,7 @@ PHP_FUNCTION(extract)
zend_array *symbol_table;
ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_ARRAY(var_array_param)
Z_PARAM_ARRAY_EX2(var_array_param, 0, 1, 0)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(extract_type)
Z_PARAM_ZVAL_EX(prefix, 0, 1)