summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2014-07-11 16:32:20 +0400
committerDmitry Stogov <dmitry@zend.com>2014-07-11 16:32:20 +0400
commit27f38798a1963de1c60aae4ef8a3675138255574 (patch)
tree479abed5848c1b7c9eacec88c85d98c80acf07e7 /Zend
parent8f229b285527a403d46be047546384032a0f6bb3 (diff)
downloadphp-git-27f38798a1963de1c60aae4ef8a3675138255574.tar.gz
Fast parameter parsing API
This API is experemental. It may be changed or removed. It should be used only for really often used functions. (Keep the original parsing code and wrap usage with #ifndef FAST_ZPP)
Diffstat (limited to 'Zend')
-rw-r--r--Zend/zend.h8
-rw-r--r--Zend/zend_API.c90
-rw-r--r--Zend/zend_API.h604
-rw-r--r--Zend/zend_builtin_functions.c73
-rw-r--r--Zend/zend_operators.c4
-rw-r--r--Zend/zend_operators.h2
6 files changed, 780 insertions, 1 deletions
diff --git a/Zend/zend.h b/Zend/zend.h
index 2f1f239732..1021829c3b 100644
--- a/Zend/zend.h
+++ b/Zend/zend.h
@@ -179,6 +179,14 @@ char *alloca ();
# define ZEND_ATTRIBUTE_DEPRECATED
#endif
+#if defined(__GNUC__) && ZEND_GCC_VERSION >= 4003
+# define ZEND_ATTRIBUTE_UNUSED __attribute__((unused))
+# define ZEND_ATTRIBUTE_UNUSED_LABEL __attribute__((cold, unused));
+#else
+# define ZEND_ATTRIBUTE_UNUSED
+# define ZEND_ATTRIBUTE_UNUSED_LABEL
+#endif
+
#if defined(__GNUC__) && ZEND_GCC_VERSION >= 3004 && defined(__i386__)
# define ZEND_FASTCALL __attribute__((fastcall))
#elif defined(_MSC_VER) && defined(_M_IX86)
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 0edff3e1a7..5770b9b030 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -262,7 +262,7 @@ static int parse_arg_object_to_string(zval *arg, char **p, int *pl, int type TSR
}
/* }}} */
-static int parse_arg_object_to_str(zval *arg, zend_string **str, int type TSRMLS_DC) /* {{{ */
+ZEND_API int parse_arg_object_to_str(zval *arg, zend_string **str, int type TSRMLS_DC) /* {{{ */
{
if (Z_OBJ_HANDLER_P(arg, cast_object)) {
zval obj;
@@ -300,6 +300,94 @@ static int parse_arg_object_to_str(zval *arg, zend_string **str, int type TSRMLS
}
/* }}} */
+#ifdef FAST_ZPP
+ZEND_API void zend_wrong_paramers_count_error(int num_args, int min_num_args, int max_num_args TSRMLS_DC) /* {{{ */
+{
+ zend_function *active_function = EG(current_execute_data)->func;
+ const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
+
+ zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given",
+ class_name, \
+ class_name[0] ? "::" : "", \
+ active_function->common.function_name->val,
+ min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most",
+ num_args < min_num_args ? min_num_args : max_num_args,
+ (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s",
+ num_args);
+}
+/* }}} */
+
+ZEND_API void zend_wrong_paramer_type_error(int num, zend_expected_type expected_type, zval *arg TSRMLS_DC) /* {{{ */
+{
+ const char *space;
+ const char *class_name = get_active_class_name(&space TSRMLS_CC);
+ static const char * const expected_error[] = {
+ Z_EXPECTED_TYPES(Z_EXPECTED_TYPE_STR)
+ NULL
+ };
+
+ zend_error(E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given",
+ class_name, space, get_active_function_name(TSRMLS_C), num, expected_error[expected_type], zend_zval_type_name(arg));
+}
+/* }}} */
+
+ZEND_API void zend_wrong_paramer_class_error(int num, char *name, zval *arg TSRMLS_DC) /* {{{ */
+{
+ const char *space;
+ const char *class_name = get_active_class_name(&space TSRMLS_CC);
+
+ zend_error(E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given",
+ class_name, space, get_active_function_name(TSRMLS_C), num, name, zend_zval_type_name(arg));
+}
+/* }}} */
+
+ZEND_API void zend_wrong_callback_error(int severity, int num, char *error TSRMLS_DC) /* {{{ */
+{
+ const char *space;
+ const char *class_name = get_active_class_name(&space TSRMLS_CC);
+
+ zend_error(severity, "%s%s%s() expects parameter %d to be a valid callback, %s",
+ class_name, space, get_active_function_name(TSRMLS_C), num, error);
+ efree(error);
+}
+/* }}} */
+
+ZEND_API int _z_param_class(zval *arg, zend_class_entry **pce, int num, int check_null TSRMLS_CC) /* {{{ */
+{
+ zend_class_entry *ce_base = *pce;
+
+ if (check_null && Z_TYPE_P(arg) == IS_NULL) {
+ *pce = NULL;
+ return 1;
+ }
+ convert_to_string_ex(arg);
+ *pce = zend_lookup_class(Z_STR_P(arg) TSRMLS_CC);
+ if (ce_base) {
+ if ((!*pce || !instanceof_function(*pce, ce_base TSRMLS_CC))) {
+ const char *space;
+ const char *class_name = get_active_class_name(&space TSRMLS_CC);
+
+ zend_error(E_WARNING, "%s%s%s() expects parameter %d to be a class name derived from %s, '%s' given",
+ class_name, space, get_active_function_name(TSRMLS_C), num,
+ ce_base->name->val, Z_STRVAL_P(arg));
+ *pce = NULL;
+ return 0;
+ }
+ }
+ if (!*pce) {
+ const char *space;
+ const char *class_name = get_active_class_name(&space TSRMLS_CC);
+
+ zend_error(E_WARNING, "%s%s%s() expects parameter %d to be a valid class name, '%s' given",
+ class_name, space, get_active_function_name(TSRMLS_C), num,
+ Z_STRVAL_P(arg));
+ return 0;
+ }
+ return 1;
+}
+/* }}} */
+#endif
+
static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, const char **spec, char **error, int *severity TSRMLS_DC) /* {{{ */
{
const char *spec_walk = *spec;
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
index beca63c50b..9278224c72 100644
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@ -680,6 +680,610 @@ END_EXTERN_C()
#define ZEND_GINIT_FUNCTION ZEND_MODULE_GLOBALS_CTOR_D
#define ZEND_GSHUTDOWN_FUNCTION ZEND_MODULE_GLOBALS_DTOR_D
+/* Fast parameter parsing API */
+
+/* TODO: This API is experemental. It may be changed or removed ???
+ * It should be used only for really often used functions.
+ * (Keep the original parsing code and wrap usage with #ifndef FAST_ZPP)
+ */
+#define FAST_ZPP 1
+
+#ifdef FAST_ZPP
+
+#define Z_EXPECTED_TYPES(_) \
+ _(Z_EXPECTED_LONG, "long") \
+ _(Z_EXPECTED_BOOL, "boolean") \
+ _(Z_EXPECTED_STRING, "string") \
+ _(Z_EXPECTED_ARRAY, "array") \
+ _(Z_EXPECTED_FUNC, "valid callback") \
+ _(Z_EXPECTED_RESOURCE, "resource") \
+ _(Z_EXPECTED_PATH, "a valid path") \
+ _(Z_EXPECTED_OBJECT, "object") \
+ _(Z_EXPECTED_DOUBLE, "double")
+
+#define Z_EXPECTED_TYPE_ENUM(id, str) id,
+#define Z_EXPECTED_TYPE_STR(id, str) str,
+
+typedef enum _zend_expected_type {
+ Z_EXPECTED_TYPES(Z_EXPECTED_TYPE_ENUM)
+ Z_EXPECTED_LAST
+} zend_expected_type;
+
+ZEND_API int parse_arg_object_to_str(zval *arg, zend_string **str, int type TSRMLS_DC);
+ZEND_API void zend_wrong_paramers_count_error(int num_args, int min_num_args, int max_num_args TSRMLS_DC);
+ZEND_API void zend_wrong_paramer_type_error(int num, zend_expected_type expected_type, zval *arg TSRMLS_DC);
+ZEND_API void zend_wrong_paramer_class_error(int num, char *name, zval *arg TSRMLS_DC);
+ZEND_API void zend_wrong_callback_error(int severity, int num, char *error TSRMLS_DC);
+ZEND_API int _z_param_class(zval *arg, zend_class_entry **pce, int num, int check_null TSRMLS_CC);
+
+#define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \
+ const int _flags = (flags); \
+ int _min_num_args = (min_num_args); \
+ int _max_num_args = (max_num_args); \
+ int _num_args = EG(current_execute_data)->num_args; \
+ int _i; \
+ zval *_real_arg, *_arg; \
+ zend_expected_type _expected_type; \
+ char *_error; \
+ zend_bool _dummy; \
+ ((void)_i); \
+ ((void)_real_arg); \
+ ((void)_arg); \
+ ((void)_expected_type); \
+ ((void)_error); \
+ ((void)_dummy); \
+ if (UNEXPECTED(_num_args < _min_num_args) || \
+ (UNEXPECTED(_num_args > _max_num_args) && \
+ EXPECTED(_max_num_args >= 0))) { \
+ if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
+ zend_wrong_paramers_count_error(_num_args, _min_num_args, _max_num_args); \
+ } \
+ goto zend_parse_params_failure; \
+ } \
+ _i = 0; \
+ _real_arg = ZEND_CALL_ARG(EG(current_execute_data), 0);
+
+#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args) \
+ ZEND_PARSE_PARAMETERS_START_EX(0, min_num_args, max_num_args)
+
+#define ZEND_PARSE_PARAMETERS_END_EX(failure) \
+ if (0) { \
+zend_parse_params_wrong_callback: ZEND_ATTRIBUTE_UNUSED_LABEL \
+ if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
+ zend_wrong_callback_error(E_WARNING, _i, _error TSRMLS_DC); \
+ } \
+ goto zend_parse_params_failure; \
+zend_parse_params_wrong_class: ZEND_ATTRIBUTE_UNUSED_LABEL \
+ if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
+ zend_wrong_paramer_class_error(_i, _error, _arg TSRMLS_DC); \
+ } \
+ goto zend_parse_params_failure; \
+zend_parse_params_wrong_arg: ZEND_ATTRIBUTE_UNUSED_LABEL \
+ if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
+ zend_wrong_paramer_type_error(_i, _expected_type, _arg TSRMLS_DC); \
+ } \
+zend_parse_params_failure: ZEND_ATTRIBUTE_UNUSED_LABEL \
+ failure; \
+ } \
+ } while (0)
+
+#define ZEND_PARSE_PARAMETERS_END() \
+ ZEND_PARSE_PARAMETERS_END_EX(return)
+
+#define Z_PARAM_PROLOGUE(separate) \
+ if (UNEXPECTED(++_i >_num_args)) break; \
+ _real_arg++; \
+ _arg = _real_arg; \
+ ZVAL_DEREF(_arg); \
+ if (separate) { \
+ SEPARATE_ZVAL_NOREF(_arg); \
+ }
+
+/* old "|" */
+#define Z_PARAM_OPTIONAL
+
+/* old "a" */
+#define Z_PARAM_ARRAY_EX(dest, check_null, separate) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_array(_arg, &dest, check_null, 0)) { \
+ _expected_type = Z_EXPECTED_ARRAY; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_array(_arg, &dest, check_null, 1)) { \
+ _expected_type = Z_EXPECTED_ARRAY; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_bool(_arg, &dest, &is_null, check_null)) { \
+ _expected_type = Z_EXPECTED_BOOL; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#define Z_PARAM_BOOL(dest) \
+ Z_PARAM_BOOL_EX(dest, _dummy, 0, 0)
+
+/* old "C" */
+#define Z_PARAM_CLASS_EX(dest, check_null, separate) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_class(_arg, &dest, _i, check_null TSRMLS_CC)) { \
+ goto zend_parse_params_failure; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_double(_arg, &dest, &is_null, check_null)) { \
+ _expected_type = Z_EXPECTED_DOUBLE; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_func(_arg, &dest_fci, &dest_fcc, check_null, &_error)) { \
+ if (!_error) { \
+ _expected_type = Z_EXPECTED_FUNC; \
+ goto zend_parse_params_wrong_arg; \
+ } else { \
+ goto zend_parse_params_wrong_callback; \
+ } \
+ } else if (_error) { \
+ zend_wrong_callback_error(E_STRICT, _i, _error TSRMLS_DC); \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_array_ht(_arg, &dest, check_null, 0)) { \
+ _expected_type = Z_EXPECTED_ARRAY; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_array_ht(_arg, &dest, check_null, 1)) { \
+ _expected_type = Z_EXPECTED_ARRAY; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_long(_arg, &dest, &is_null, check_null, 0)) { \
+ _expected_type = Z_EXPECTED_LONG; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_long(_arg, &dest, &is_null, check_null, 1)) { \
+ _expected_type = Z_EXPECTED_LONG; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_object(_arg, &dest, NULL, check_null)) { \
+ _expected_type = Z_EXPECTED_OBJECT; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_object(_arg, &dest, _ce, check_null)) { \
+ if (_ce) { \
+ _error = (_ce)->name->val; \
+ goto zend_parse_params_wrong_class; \
+ } else { \
+ _expected_type = Z_EXPECTED_OBJECT; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_path(_arg, &dest, &dest_len, check_null)) { \
+ _expected_type = Z_EXPECTED_PATH; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_path_str(_arg, &dest, check_null)) { \
+ _expected_type = Z_EXPECTED_PATH; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_resource(_arg, &dest, check_null)) { \
+ _expected_type = Z_EXPECTED_RESOURCE; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_string(_arg, &dest, &dest_len, check_null)) { \
+ _expected_type = Z_EXPECTED_STRING; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ if (!_z_param_str(_arg, &dest, check_null)) { \
+ _expected_type = Z_EXPECTED_STRING; \
+ goto zend_parse_params_wrong_arg; \
+ } \
+ } while (0);
+
+#define Z_PARAM_STR(dest) \
+ Z_PARAM_STR_EX(dest, 0, 0)
+
+/* old "z" */
+#define Z_PARAM_ZVAL_EX(dest, check_null, separate) do { \
+ if (separate) { \
+ Z_PARAM_PROLOGUE(separate); \
+ _z_param_zval_deref(_arg, &dest, check_null); \
+ } else { \
+ if (UNEXPECTED(++_i >_num_args)) break; \
+ _real_arg++; \
+ _z_param_zval(_real_arg, &dest, check_null); \
+ } \
+ } while (0);
+
+#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) do { \
+ Z_PARAM_PROLOGUE(separate); \
+ _z_param_zval_deref(_arg, &dest, check_null); \
+ } while (0);
+
+#define Z_PARAM_ZVAL_DEREF(dest) \
+ Z_PARAM_ZVAL_DEREF_EX(dest, 0, 0)
+
+/* old "+" and "*" */
+#define Z_PARAM_VARIADIC_EX(spec, dest, dest_num, post_varargs) do { \
+ int _num_varargs = _num_args - _i - (post_varargs); \
+ if (_num_varargs > 0) { \
+ dest = _real_arg + 1; \
+ dest_num = _num_varargs; \
+ _i += _num_varargs; \
+ _real_arg += _num_varargs; \
+ } else { \
+ dest = NULL; \
+ dest_num = 0; \
+ } \
+ } while (0);
+
+#define Z_PARAM_VARIADIC(spec, dest, dest_num) \
+ Z_PARAM_VARIADIC_EX(spec, dest, dest_num, 0)
+
+/* Private part of new parameter parsing API */
+
+static zend_always_inline int _z_param_bool(zval *arg, zend_bool *dest, zend_bool *is_null, int check_null)
+{
+ if (check_null) {
+ *is_null = 0;
+ }
+ if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
+ *dest = 1;
+ } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
+ if (check_null) {
+ *is_null = (Z_TYPE_P(arg) == IS_NULL);
+ }
+ *dest = 0;
+ } else if (EXPECTED(Z_TYPE_P(arg) <= IS_STRING)) {
+ *dest = zend_is_true(arg);
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_long(zval *arg, long *dest, zend_bool *is_null, int check_null, int strict)
+{
+ if (check_null) {
+ *is_null = 0;
+ }
+ if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
+ if (strict && UNEXPECTED(Z_DVAL_P(arg) > LONG_MAX)) {
+ *dest = LONG_MAX;
+ } else if (strict && UNEXPECTED(Z_DVAL_P(arg) < LONG_MIN)) {
+ *dest = LONG_MIN;
+ } else {
+ *dest = Z_LVAL_P(arg);
+ }
+ } else if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) {
+ *dest = zend_dval_to_lval(Z_DVAL_P(arg));
+ } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {
+ double d;
+ int type;
+
+ if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), dest, &d)) != IS_LONG)) {
+ if (EXPECTED(type != 0)) {
+ if (strict && UNEXPECTED(d > LONG_MAX)) {
+ *dest = LONG_MAX;
+ } else if (strict && UNEXPECTED(d < LONG_MIN)) {
+ *dest = LONG_MIN;
+ } else {
+ *dest = zend_dval_to_lval(d);
+ }
+ } else {
+ return 0;
+ }
+ }
+ } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
+ if (check_null) {
+ *is_null = (Z_TYPE_P(arg) == IS_NULL);
+ }
+ *dest = 0;
+ } else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
+ *dest = 1;
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_double(zval *arg, double *dest, zend_bool *is_null, int check_null)
+{
+ if (check_null) {
+ *is_null = 0;
+ }
+ if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) {
+ *dest = Z_DVAL_P(arg);
+ } else if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
+ *dest = (double)Z_LVAL_P(arg);
+ } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {
+ long l;
+ int type;
+
+ if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), &l, dest)) != IS_DOUBLE)) {
+ if (EXPECTED(type != 0)) {
+ *dest = (double)(l);
+ } else {
+ return 0;
+ }
+ }
+ } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
+ if (check_null) {
+ *is_null = (Z_TYPE_P(arg) == IS_NULL);
+ }
+ *dest = 0.0;
+ } else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
+ *dest = 1.0;
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_str(zval *arg, zend_string **dest, int check_null)
+{
+ if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {
+ *dest = Z_STR_P(arg);
+ } else if (EXPECTED(Z_TYPE_P(arg) < IS_STRING)) {
+ if (check_null && UNEXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
+ *dest = NULL;
+ } else {
+ if (Z_COPYABLE_P(arg) && Z_REFCOUNT_P(arg) > 1) {
+ Z_DELREF_P(arg);
+ zval_copy_ctor_func(arg);
+ }
+ convert_to_string(arg);
+ *dest = Z_STR_P(arg);
+ }
+ } else if (UNEXPECTED(Z_TYPE_P(arg) != IS_OBJECT) ||
+ UNEXPECTED(parse_arg_object_to_str(arg, dest, IS_STRING TSRMLS_CC) != SUCCESS)) {
+ return 0;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_string(zval *arg, char **dest, int *dest_len, int check_null)
+{
+ zend_string *str;
+
+ if (!_z_param_str(arg, &str, check_null)) {
+ return 0;
+ }
+ if (check_null && UNEXPECTED(!str)) {
+ *dest = NULL;
+ *dest_len = 0;
+ } else {
+ *dest = str->val;
+ *dest_len = str->len;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_path_str(zval *arg, zend_string **dest, int check_null)
+{
+ if (!_z_param_str(arg, dest, check_null) ||
+ (check_null && UNEXPECTED(!(*dest)->val)) ||
+ UNEXPECTED(CHECK_NULL_PATH((*dest)->val, (*dest)->len))) {
+ return 0;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_path(zval *arg, char **dest, int *dest_len, int check_null)
+{
+ zend_string *str;
+
+ if (!_z_param_path_str(arg, &str, check_null)) {
+ return 0;
+ }
+ if (check_null && UNEXPECTED(!str)) {
+ *dest = NULL;
+ *dest_len = 0;
+ } else {
+ *dest = str->val;
+ *dest_len = str->len;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_array(zval *arg, zval **dest, int check_null, int or_object)
+{
+ if (EXPECTED(Z_TYPE_P(arg) == IS_ARRAY) ||
+ (or_object && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT))) {
+ *dest = arg;
+ } else if (check_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
+ *dest = NULL;
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_array_ht(zval *arg, HashTable **dest, int check_null, int or_object)
+{
+ if (EXPECTED(Z_TYPE_P(arg) == IS_ARRAY)) {
+ *dest = Z_ARRVAL_P(arg);
+ } else if (or_object && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
+ *dest = Z_OBJ_HT_P(arg)->get_properties(arg TSRMLS_CC);
+ } else if (check_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
+ *dest = NULL;
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_object(zval *arg, zval **dest, zend_class_entry *ce, int check_null)
+{
+ if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT) &&
+ (!ce || EXPECTED(instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC) != 0))) {
+ *dest = arg;
+ } else if (check_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
+ *dest = NULL;
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_resource(zval *arg, zval **dest, int check_null)
+{
+ if (EXPECTED(Z_TYPE_P(arg) == IS_RESOURCE)) {
+ *dest = arg;
+ } else if (check_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
+ *dest = NULL;
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+static zend_always_inline int _z_param_func(zval *arg, zend_fcall_info *dest_fci, zend_fcall_info_cache *dest_fcc, int check_null, char **error)
+{
+ if (check_null && UNEXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
+ dest_fci->size = 0;
+ dest_fcc->initialized = 0;
+ *error = NULL;
+ } else if (UNEXPECTED(zend_fcall_info_init(arg, 0, dest_fci, dest_fcc, NULL, error TSRMLS_CC) != SUCCESS)) {
+ return 0;
+ }
+ return 1;
+}
+
+static zend_always_inline void _z_param_zval(zval *arg, zval **dest, int check_null)
+{
+ *dest = (check_null &&
+ (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) ||
+ (UNEXPECTED(Z_ISREF_P(arg)) &&
+ UNEXPECTED(Z_TYPE_P(Z_REFVAL_P(arg)) == IS_NULL)))) ? NULL : arg;
+}
+
+static zend_always_inline void _z_param_zval_deref(zval *arg, zval **dest, int check_null)
+{
+ *dest = (check_null && UNEXPECTED(Z_TYPE_P(arg) == IS_NULL)) ? NULL : arg;
+}
+
+#endif /* FAST_ZPP */
+
+/* End of new parameter parsing API */
+
END_EXTERN_C()
#endif /* ZEND_API_H */
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 51265ecb40..1e29ea4db1 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -518,9 +518,15 @@ ZEND_FUNCTION(strlen)
{
zend_string *s;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S", &s) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_STR(s)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
RETVAL_LONG(s->len);
}
@@ -697,9 +703,18 @@ ZEND_FUNCTION(define)
int case_sensitive = CONST_CS;
zend_constant c;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Sz|b", &name, &val, &non_cs) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(2, 3)
+ Z_PARAM_STR(name)
+ Z_PARAM_ZVAL(val)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_BOOL(non_cs)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
if(non_cs) {
case_sensitive = 0;
@@ -764,9 +779,15 @@ ZEND_FUNCTION(defined)
{
zend_string *name;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S", &name) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_STR(name)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
if (zend_get_constant_ex(name, NULL, ZEND_FETCH_CLASS_SILENT TSRMLS_CC)) {
RETURN_TRUE;
@@ -869,9 +890,18 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass)
zend_bool allow_string = only_subclass;
zend_bool retval;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zS|b", &obj, &class_name, &allow_string) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(2, 3)
+ Z_PARAM_ZVAL(obj)
+ Z_PARAM_STR(class_name)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_BOOL(allow_string)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
/*
* allow_string - is_a default is no, is_subclass_of is yes.
* if it's allowed, then the autoloader will be called if the class does not exist.
@@ -1007,9 +1037,15 @@ ZEND_FUNCTION(get_object_vars)
uint prop_len;
zend_object *zobj;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_OBJECT(obj)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
if (Z_OBJ_HT_P(obj)->get_properties == NULL) {
RETURN_FALSE;
@@ -1124,9 +1160,16 @@ ZEND_FUNCTION(method_exists)
zend_string *lcname;
zend_class_entry * ce;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zS", &klass, &method_name) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(2, 2)
+ Z_PARAM_ZVAL(klass)
+ Z_PARAM_STR(method_name)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
if (Z_TYPE_P(klass) == IS_OBJECT) {
ce = Z_OBJCE_P(klass);
} else if (Z_TYPE_P(klass) == IS_STRING) {
@@ -1227,9 +1270,17 @@ ZEND_FUNCTION(class_exists)
zend_class_entry *ce;
zend_bool autoload = 1;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S|b", &class_name, &autoload) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(1, 2)
+ Z_PARAM_STR(class_name)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_BOOL(autoload)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
if (!autoload) {
if (class_name->val[0] == '\\') {
@@ -1262,9 +1313,17 @@ ZEND_FUNCTION(interface_exists)
zend_class_entry *ce;
zend_bool autoload = 1;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S|b", &iface_name, &autoload) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(1, 2)
+ Z_PARAM_STR(iface_name)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_BOOL(autoload)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
if (!autoload) {
if (iface_name->val[0] == '\\') {
@@ -1297,9 +1356,17 @@ ZEND_FUNCTION(trait_exists)
zend_class_entry *ce;
zend_bool autoload = 1;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S|b", &trait_name, &autoload) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(1, 2)
+ Z_PARAM_STR(trait_name)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_BOOL(autoload)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
if (!autoload) {
if (trait_name->val[0] == '\\') {
@@ -1334,9 +1401,15 @@ ZEND_FUNCTION(function_exists)
zend_function *func;
zend_string *lcname;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_STRING(name, name_len)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
if (name[0] == '\\') {
/* Ignore leading "\" */
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
index 76c732732e..dc2756fe09 100644
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -2561,6 +2561,10 @@ ZEND_API zend_string *zend_long_to_str(long num) /* {{{ */
}
/* }}} */
+ZEND_API zend_uchar is_numeric_str_function(const zend_string *str, long *lval, double *dval) {
+ return is_numeric_string_ex(str->val, str->len, lval, dval, -1, NULL);
+}
+
/*
* Local variables:
* tab-width: 4
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index b952b9889e..1ab9518b9a 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -270,6 +270,8 @@ static inline zend_uchar is_numeric_string(const char *str, int length, long *lv
return is_numeric_string_ex(str, length, lval, dval, allow_errors, NULL);
}
+ZEND_API zend_uchar is_numeric_str_function(const zend_string *str, long *lval, double *dval);
+
static inline const char *
zend_memnstr(const char *haystack, const char *needle, int needle_len, char *end)
{