Skip to content

Commit

Permalink
Improved new Zend Parameter Parsing API to avoid useless dereferences.
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
dstogov committed Jun 8, 2017
1 parent bdc3744 commit ace9fe5
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 50 deletions.
143 changes: 95 additions & 48 deletions Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); \
Expand All @@ -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); \
}
Expand All @@ -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; \
Expand All @@ -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); \
Expand All @@ -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) \
Expand Down
4 changes: 2 additions & 2 deletions ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit ace9fe5

Please sign in to comment.