diff options
Diffstat (limited to 'Zend/zend_operators.h')
-rw-r--r-- | Zend/zend_operators.h | 712 |
1 files changed, 350 insertions, 362 deletions
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 15ad79e4db..f95e856e68 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ - | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) | + | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | | that is bundled with this package in the file LICENSE, and is | @@ -41,12 +41,13 @@ #include "ext/bcmath/libbcmath/src/bcmath.h" #endif -#define LONG_SIGN_MASK (1L << (8*sizeof(long)-1)) +#define LONG_SIGN_MASK (((zend_long)1) << (8*sizeof(zend_long)-1)) BEGIN_EXTERN_C() ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); +ZEND_API int pow_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); @@ -68,14 +69,41 @@ ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSR ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC); ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC); + +/** + * Checks whether the string "str" with length "length" is numeric. The value + * of allow_errors determines whether it's required to be entirely numeric, or + * just its prefix. Leading whitespace is allowed. + * + * The function returns 0 if the string did not contain a valid number; IS_LONG + * if it contained a number that fits within the range of a long; or IS_DOUBLE + * if the number was out of long range or contained a decimal point/exponent. + * The number's value is returned into the respective pointer, *lval or *dval, + * if that pointer is not NULL. + * + * This variant also gives information if a string that represents an integer + * could not be represented as such due to overflow. It writes 1 to oflow_info + * if the integer is larger than ZEND_LONG_MAX and -1 if it's smaller than ZEND_LONG_MIN. + */ +ZEND_API zend_uchar _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info); + END_EXTERN_C() #if ZEND_DVAL_TO_LVAL_CAST_OK -# define zend_dval_to_lval(d) ((long) (d)) -#elif SIZEOF_LONG == 4 -static zend_always_inline long zend_dval_to_lval(double d) +static zend_always_inline zend_long zend_dval_to_lval(double d) +{ + if (EXPECTED(zend_finite(d)) && EXPECTED(!zend_isnan(d))) { + return (zend_long)d; + } else { + return 0; + } +} +#elif SIZEOF_ZEND_LONG == 4 +static zend_always_inline zend_long zend_dval_to_lval(double d) { - if (d > LONG_MAX || d < LONG_MIN) { + if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) { + return 0; + } else if (d > ZEND_LONG_MAX || d < ZEND_LONG_MIN) { double two_pow_32 = pow(2., 32.), dmod; @@ -85,15 +113,17 @@ static zend_always_inline long zend_dval_to_lval(double d) * to simulate rounding towards 0 of the negative number */ dmod = ceil(dmod) + two_pow_32; } - return (long)(unsigned long)dmod; + return (zend_long)(zend_ulong)dmod; } - return (long)d; + return (zend_long)d; } #else -static zend_always_inline long zend_dval_to_lval(double d) +static zend_always_inline zend_long zend_dval_to_lval(double d) { - /* >= as (double)LONG_MAX is outside signed range */ - if (d >= LONG_MAX || d < LONG_MIN) { + if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) { + return 0; + /* >= as (double)ZEND_LONG_MAX is outside signed range */ + } else if (d >= ZEND_LONG_MAX || d < ZEND_LONG_MIN) { double two_pow_64 = pow(2., 64.), dmod; @@ -103,9 +133,9 @@ static zend_always_inline long zend_dval_to_lval(double d) * fractional part, hence dmod does not have one either */ dmod += two_pow_64; } - return (long)(unsigned long)dmod; + return (zend_long)(zend_ulong)dmod; } - return (long)d; + return (zend_long)d; } #endif /* }}} */ @@ -113,173 +143,35 @@ static zend_always_inline long zend_dval_to_lval(double d) #define ZEND_IS_DIGIT(c) ((c) >= '0' && (c) <= '9') #define ZEND_IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) -/** - * Checks whether the string "str" with length "length" is numeric. The value - * of allow_errors determines whether it's required to be entirely numeric, or - * just its prefix. Leading whitespace is allowed. - * - * The function returns 0 if the string did not contain a valid number; IS_LONG - * if it contained a number that fits within the range of a long; or IS_DOUBLE - * if the number was out of long range or contained a decimal point/exponent. - * The number's value is returned into the respective pointer, *lval or *dval, - * if that pointer is not NULL. - * - * This variant also gives information if a string that represents an integer - * could not be represented as such due to overflow. It writes 1 to oflow_info - * if the integer is larger than LONG_MAX and -1 if it's smaller than LONG_MIN. - */ -static inline zend_uchar is_numeric_string_ex(const char *str, int length, long *lval, double *dval, int allow_errors, int *oflow_info) +static zend_always_inline zend_uchar is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info) { - const char *ptr; - int base = 10, digits = 0, dp_or_e = 0; - double local_dval = 0.0; - zend_uchar type; - - if (!length) { - return 0; - } - - if (oflow_info != NULL) { - *oflow_info = 0; - } - - /* Skip any whitespace - * This is much faster than the isspace() function */ - while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') { - str++; - length--; - } - ptr = str; - - if (*ptr == '-' || *ptr == '+') { - ptr++; - } - - if (ZEND_IS_DIGIT(*ptr)) { - /* Handle hex numbers - * str is used instead of ptr to disallow signs and keep old behavior */ - if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) { - base = 16; - ptr += 2; - } - - /* Skip any leading 0s */ - while (*ptr == '0') { - ptr++; - } - - /* Count the number of digits. If a decimal point/exponent is found, - * it's a double. Otherwise, if there's a dval or no need to check for - * a full match, stop when there are too many digits for a long */ - for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) { -check_digits: - if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) { - continue; - } else if (base == 10) { - if (*ptr == '.' && dp_or_e < 1) { - goto process_double; - } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) { - const char *e = ptr + 1; - - if (*e == '-' || *e == '+') { - ptr = e++; - } - if (ZEND_IS_DIGIT(*e)) { - goto process_double; - } - } - } - - break; - } - - if (base == 10) { - if (digits >= MAX_LENGTH_OF_LONG) { - if (oflow_info != NULL) { - *oflow_info = *str == '-' ? -1 : 1; - } - dp_or_e = -1; - goto process_double; - } - } else if (!(digits < SIZEOF_LONG * 2 || (digits == SIZEOF_LONG * 2 && ptr[-digits] <= '7'))) { - if (dval) { - local_dval = zend_hex_strtod(str, &ptr); - } - if (oflow_info != NULL) { - *oflow_info = 1; - } - type = IS_DOUBLE; - } - } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) { -process_double: - type = IS_DOUBLE; - - /* If there's a dval, do the conversion; else continue checking - * the digits if we need to check for a full match */ - if (dval) { - local_dval = zend_strtod(str, &ptr); - } else if (allow_errors != 1 && dp_or_e != -1) { - dp_or_e = (*ptr++ == '.') ? 1 : 2; - goto check_digits; - } - } else { + if (*str > '9') { return 0; } - - if (ptr != str + length) { - if (!allow_errors) { - return 0; - } - if (allow_errors == -1) { - zend_error(E_NOTICE, "A non well formed numeric value encountered"); - } - } - - if (type == IS_LONG) { - if (digits == MAX_LENGTH_OF_LONG - 1) { - int cmp = strcmp(&ptr[-digits], long_min_digits); - - if (!(cmp < 0 || (cmp == 0 && *str == '-'))) { - if (dval) { - *dval = zend_strtod(str, NULL); - } - if (oflow_info != NULL) { - *oflow_info = *str == '-' ? -1 : 1; - } - - return IS_DOUBLE; - } - } - - if (lval) { - *lval = strtol(str, NULL, base); - } - - return IS_LONG; - } else { - if (dval) { - *dval = local_dval; - } - - return IS_DOUBLE; - } + return _is_numeric_string_ex(str, length, lval, dval, allow_errors, oflow_info); } -static inline zend_uchar is_numeric_string(const char *str, int length, long *lval, double *dval, int allow_errors) { +static zend_always_inline zend_uchar is_numeric_string(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors) { return is_numeric_string_ex(str, length, lval, dval, allow_errors, NULL); } -static inline const char * -zend_memnstr(const char *haystack, const char *needle, int needle_len, char *end) +ZEND_API zend_uchar is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval); + +static zend_always_inline const char * +zend_memnstr(const char *haystack, const char *needle, size_t needle_len, char *end) { const char *p = haystack; const char ne = needle[needle_len-1]; + ptrdiff_t off_p; + size_t off_s; if (needle_len == 1) { return (char *)memchr(p, *needle, (end-p)); } - if (needle_len > end-haystack) { + off_p = end - haystack; + off_s = (off_p > 0) ? (size_t)off_p : 0; + if (needle_len > off_s) { return NULL; } @@ -302,7 +194,7 @@ zend_memnstr(const char *haystack, const char *needle, int needle_len, char *end return NULL; } -static inline const void *zend_memrchr(const void *s, int c, size_t n) +static zend_always_inline const void *zend_memrchr(const void *s, int c, size_t n) { register const unsigned char *e; @@ -336,12 +228,29 @@ ZEND_API void convert_to_object(zval *op); ZEND_API void multi_convert_to_long_ex(int argc, ...); ZEND_API void multi_convert_to_double_ex(int argc, ...); ZEND_API void multi_convert_to_string_ex(int argc, ...); + +ZEND_API zend_long _zval_get_long_func(zval *op TSRMLS_DC); +ZEND_API double _zval_get_double_func(zval *op TSRMLS_DC); +ZEND_API zend_string *_zval_get_string_func(zval *op TSRMLS_DC); + +static zend_always_inline zend_long _zval_get_long(zval *op TSRMLS_DC) { + return Z_TYPE_P(op) == IS_LONG ? Z_LVAL_P(op) : _zval_get_long_func(op TSRMLS_CC); +} +static zend_always_inline double _zval_get_double(zval *op TSRMLS_DC) { + return Z_TYPE_P(op) == IS_DOUBLE ? Z_DVAL_P(op) : _zval_get_double_func(op TSRMLS_CC); +} +static zend_always_inline zend_string *_zval_get_string(zval *op TSRMLS_DC) { + return Z_TYPE_P(op) == IS_STRING ? zend_string_copy(Z_STR_P(op)) : _zval_get_string_func(op TSRMLS_CC); +} + +#define zval_get_long(op) _zval_get_long((op) TSRMLS_CC) +#define zval_get_double(op) _zval_get_double((op) TSRMLS_CC) +#define zval_get_string(op) _zval_get_string((op) TSRMLS_CC) + ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2); ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2); -#define convert_to_cstring(op) if ((op)->type != IS_STRING) { _convert_to_cstring((op) ZEND_FILE_LINE_CC); } -#define convert_to_string(op) if ((op)->type != IS_STRING) { _convert_to_string((op) ZEND_FILE_LINE_CC); } - -ZEND_API double zend_string_to_double(const char *number, zend_uint length); +#define convert_to_cstring(op) if (Z_TYPE_P(op) != IS_STRING) { _convert_to_cstring((op) ZEND_FILE_LINE_CC); } +#define convert_to_string(op) if (Z_TYPE_P(op) != IS_STRING) { _convert_to_string((op) ZEND_FILE_LINE_CC); } ZEND_API int zval_is_true(zval *op); ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); @@ -353,19 +262,20 @@ ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSR ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); #endif -ZEND_API void zend_str_tolower(char *str, unsigned int length); -ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length); -ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length); +ZEND_API void zend_str_tolower(char *str, size_t length); +ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, size_t length); +ZEND_API char *zend_str_tolower_dup(const char *source, size_t length); ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2); ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3); ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2); ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3); -ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint len2); -ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint len2, uint length); -ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, uint len2); -ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, uint len2, uint length); -ZEND_API int zend_binary_strncasecmp_l(const char *s1, uint len1, const char *s2, uint len2, uint length); +ZEND_API int zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2); +ZEND_API int zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length); +ZEND_API int zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2); +ZEND_API int zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length); +ZEND_API int zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2); +ZEND_API int zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length); ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2); ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC); @@ -373,15 +283,14 @@ ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC); ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC); ZEND_API int zend_atoi(const char *str, int str_len); -ZEND_API long zend_atol(const char *str, int str_len); +ZEND_API zend_long zend_atol(const char *str, int str_len); ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC); -END_EXTERN_C() -#define convert_to_ex_master(ppzv, lower_type, upper_type) \ - if (Z_TYPE_PP(ppzv)!=IS_##upper_type) { \ - SEPARATE_ZVAL_IF_NOT_REF(ppzv); \ - convert_to_##lower_type(*ppzv); \ +#define convert_to_ex_master(pzv, lower_type, upper_type) \ + if (Z_TYPE_P(pzv)!=upper_type) { \ + SEPARATE_ZVAL_IF_NOT_REF(pzv); \ + convert_to_##lower_type(pzv); \ } #define convert_to_explicit_type(pzv, type) \ @@ -396,7 +305,7 @@ END_EXTERN_C() case IS_DOUBLE: \ convert_to_double(pzv); \ break; \ - case IS_BOOL: \ + case _IS_BOOL: \ convert_to_boolean(pzv); \ break; \ case IS_ARRAY: \ @@ -414,78 +323,26 @@ END_EXTERN_C() } \ } while (0); -#define convert_to_explicit_type_ex(ppzv, str_type) \ - if (Z_TYPE_PP(ppzv) != str_type) { \ - SEPARATE_ZVAL_IF_NOT_REF(ppzv); \ - convert_to_explicit_type(*ppzv, str_type); \ +#define convert_to_explicit_type_ex(pzv, str_type) \ + if (Z_TYPE_P(pzv) != str_type) { \ + SEPARATE_ZVAL_IF_NOT_REF(pzv); \ + convert_to_explicit_type(pzv, str_type); \ } -#define convert_to_boolean_ex(ppzv) convert_to_ex_master(ppzv, boolean, BOOL) -#define convert_to_long_ex(ppzv) convert_to_ex_master(ppzv, long, LONG) -#define convert_to_double_ex(ppzv) convert_to_ex_master(ppzv, double, DOUBLE) -#define convert_to_string_ex(ppzv) convert_to_ex_master(ppzv, string, STRING) -#define convert_to_array_ex(ppzv) convert_to_ex_master(ppzv, array, ARRAY) -#define convert_to_object_ex(ppzv) convert_to_ex_master(ppzv, object, OBJECT) -#define convert_to_null_ex(ppzv) convert_to_ex_master(ppzv, null, NULL) - -#define convert_scalar_to_number_ex(ppzv) \ - if (Z_TYPE_PP(ppzv)!=IS_LONG && Z_TYPE_PP(ppzv)!=IS_DOUBLE) { \ - if (!Z_ISREF_PP(ppzv)) { \ - SEPARATE_ZVAL(ppzv); \ - } \ - convert_scalar_to_number(*ppzv TSRMLS_CC); \ +#define convert_to_boolean_ex(pzv) convert_to_ex_master(pzv, boolean, _IS_BOOL) +#define convert_to_long_ex(pzv) convert_to_ex_master(pzv, long, IS_LONG) +#define convert_to_double_ex(pzv) convert_to_ex_master(pzv, double, IS_DOUBLE) +#define convert_to_string_ex(pzv) convert_to_ex_master(pzv, string, IS_STRING) +#define convert_to_array_ex(pzv) convert_to_ex_master(pzv, array, IS_ARRAY) +#define convert_to_object_ex(pzv) convert_to_ex_master(pzv, object, IS_OBJECT) +#define convert_to_null_ex(pzv) convert_to_ex_master(pzv, null, IS_NULL) + +#define convert_scalar_to_number_ex(pzv) \ + if (Z_TYPE_P(pzv)!=IS_LONG && Z_TYPE_P(pzv)!=IS_DOUBLE) { \ + SEPARATE_ZVAL_IF_NOT_REF(pzv); \ + convert_scalar_to_number(pzv TSRMLS_CC); \ } - -#define Z_LVAL(zval) (zval).value.lval -#define Z_BVAL(zval) ((zend_bool)(zval).value.lval) -#define Z_DVAL(zval) (zval).value.dval -#define Z_STRVAL(zval) (zval).value.str.val -#define Z_STRLEN(zval) (zval).value.str.len -#define Z_ARRVAL(zval) (zval).value.ht -#define Z_OBJVAL(zval) (zval).value.obj -#define Z_OBJ_HANDLE(zval) Z_OBJVAL(zval).handle -#define Z_OBJ_HT(zval) Z_OBJVAL(zval).handlers -#define Z_OBJCE(zval) zend_get_class_entry(&(zval) TSRMLS_CC) -#define Z_OBJPROP(zval) Z_OBJ_HT((zval))->get_properties(&(zval) TSRMLS_CC) -#define Z_OBJ_HANDLER(zval, hf) Z_OBJ_HT((zval))->hf -#define Z_RESVAL(zval) (zval).value.lval -#define Z_OBJDEBUG(zval,is_tmp) (Z_OBJ_HANDLER((zval),get_debug_info)?Z_OBJ_HANDLER((zval),get_debug_info)(&(zval),&is_tmp TSRMLS_CC):(is_tmp=0,Z_OBJ_HANDLER((zval),get_properties)?Z_OBJPROP(zval):NULL)) - -#define Z_LVAL_P(zval_p) Z_LVAL(*zval_p) -#define Z_BVAL_P(zval_p) Z_BVAL(*zval_p) -#define Z_DVAL_P(zval_p) Z_DVAL(*zval_p) -#define Z_STRVAL_P(zval_p) Z_STRVAL(*zval_p) -#define Z_STRLEN_P(zval_p) Z_STRLEN(*zval_p) -#define Z_ARRVAL_P(zval_p) Z_ARRVAL(*zval_p) -#define Z_OBJPROP_P(zval_p) Z_OBJPROP(*zval_p) -#define Z_OBJCE_P(zval_p) Z_OBJCE(*zval_p) -#define Z_RESVAL_P(zval_p) Z_RESVAL(*zval_p) -#define Z_OBJVAL_P(zval_p) Z_OBJVAL(*zval_p) -#define Z_OBJ_HANDLE_P(zval_p) Z_OBJ_HANDLE(*zval_p) -#define Z_OBJ_HT_P(zval_p) Z_OBJ_HT(*zval_p) -#define Z_OBJ_HANDLER_P(zval_p, h) Z_OBJ_HANDLER(*zval_p, h) -#define Z_OBJDEBUG_P(zval_p,is_tmp) Z_OBJDEBUG(*zval_p,is_tmp) - -#define Z_LVAL_PP(zval_pp) Z_LVAL(**zval_pp) -#define Z_BVAL_PP(zval_pp) Z_BVAL(**zval_pp) -#define Z_DVAL_PP(zval_pp) Z_DVAL(**zval_pp) -#define Z_STRVAL_PP(zval_pp) Z_STRVAL(**zval_pp) -#define Z_STRLEN_PP(zval_pp) Z_STRLEN(**zval_pp) -#define Z_ARRVAL_PP(zval_pp) Z_ARRVAL(**zval_pp) -#define Z_OBJPROP_PP(zval_pp) Z_OBJPROP(**zval_pp) -#define Z_OBJCE_PP(zval_pp) Z_OBJCE(**zval_pp) -#define Z_RESVAL_PP(zval_pp) Z_RESVAL(**zval_pp) -#define Z_OBJVAL_PP(zval_pp) Z_OBJVAL(**zval_pp) -#define Z_OBJ_HANDLE_PP(zval_p) Z_OBJ_HANDLE(**zval_p) -#define Z_OBJ_HT_PP(zval_p) Z_OBJ_HT(**zval_p) -#define Z_OBJ_HANDLER_PP(zval_p, h) Z_OBJ_HANDLER(**zval_p, h) -#define Z_OBJDEBUG_PP(zval_pp,is_tmp) Z_OBJDEBUG(**zval_pp,is_tmp) - -#define Z_TYPE(zval) (zval).type -#define Z_TYPE_P(zval_p) Z_TYPE(*zval_p) -#define Z_TYPE_PP(zval_pp) Z_TYPE(**zval_pp) - #if HAVE_SETLOCALE && defined(ZEND_WIN32) && !defined(ZTS) && defined(_MSC_VER) && (_MSC_VER >= 1400) /* This is performance improvement of tolower() on Windows and VC2005 * Gives 10-18% on bench.php @@ -501,7 +358,7 @@ ZEND_API void zend_update_current_locale(void); /* The offset in bytes between the value and type fields of a zval */ #define ZVAL_OFFSETOF_TYPE \ - (offsetof(zval,type) - offsetof(zval,value)) + (offsetof(zval, u1.type_info) - offsetof(zval, value)) static zend_always_inline int fast_increment_function(zval *op1) { @@ -512,7 +369,7 @@ static zend_always_inline int fast_increment_function(zval *op1) "jno 0f\n\t" "movl $0x0, (%0)\n\t" "movl $0x41e00000, 0x4(%0)\n\t" - "movb %1, %c2(%0)\n" + "movl %1, %c2(%0)\n" "0:" : : "r"(&op1->value), @@ -525,7 +382,7 @@ static zend_always_inline int fast_increment_function(zval *op1) "jno 0f\n\t" "movl $0x0, (%0)\n\t" "movl $0x43e00000, 0x4(%0)\n\t" - "movb %1, %c2(%0)\n" + "movl %1, %c2(%0)\n" "0:" : : "r"(&op1->value), @@ -533,10 +390,9 @@ static zend_always_inline int fast_increment_function(zval *op1) "n"(ZVAL_OFFSETOF_TYPE) : "cc"); #else - if (UNEXPECTED(Z_LVAL_P(op1) == LONG_MAX)) { + if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MAX)) { /* switch to double */ - Z_DVAL_P(op1) = (double)LONG_MAX + 1.0; - Z_TYPE_P(op1) = IS_DOUBLE; + ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0); } else { Z_LVAL_P(op1)++; } @@ -555,7 +411,7 @@ static zend_always_inline int fast_decrement_function(zval *op1) "jno 0f\n\t" "movl $0x00200000, (%0)\n\t" "movl $0xc1e00000, 0x4(%0)\n\t" - "movb %1,%c2(%0)\n" + "movl %1,%c2(%0)\n" "0:" : : "r"(&op1->value), @@ -568,7 +424,7 @@ static zend_always_inline int fast_decrement_function(zval *op1) "jno 0f\n\t" "movl $0x00000000, (%0)\n\t" "movl $0xc3e00000, 0x4(%0)\n\t" - "movb %1,%c2(%0)\n" + "movl %1,%c2(%0)\n" "0:" : : "r"(&op1->value), @@ -576,10 +432,9 @@ static zend_always_inline int fast_decrement_function(zval *op1) "n"(ZVAL_OFFSETOF_TYPE) : "cc"); #else - if (UNEXPECTED(Z_LVAL_P(op1) == LONG_MIN)) { + if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MIN)) { /* switch to double */ - Z_DVAL_P(op1) = (double)LONG_MIN - 1.0; - Z_TYPE_P(op1) = IS_DOUBLE; + ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0); } else { Z_LVAL_P(op1)--; } @@ -599,13 +454,13 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o "addl (%2), %%eax\n\t" "jo 0f\n\t" "movl %%eax, (%0)\n\t" - "movb %3, %c5(%0)\n\t" + "movl %3, %c5(%0)\n\t" "jmp 1f\n" "0:\n\t" "fildl (%1)\n\t" "fildl (%2)\n\t" "faddp %%st, %%st(1)\n\t" - "movb %4, %c5(%0)\n\t" + "movl %4, %c5(%0)\n\t" "fstpl (%0)\n" "1:" : @@ -622,13 +477,13 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o "addq (%2), %%rax\n\t" "jo 0f\n\t" "movq %%rax, (%0)\n\t" - "movb %3, %c5(%0)\n\t" + "movl %3, %c5(%0)\n\t" "jmp 1f\n" "0:\n\t" "fildq (%1)\n\t" "fildq (%2)\n\t" "faddp %%st, %%st(1)\n\t" - "movb %4, %c5(%0)\n\t" + "movl %4, %c5(%0)\n\t" "fstpl (%0)\n" "1:" : @@ -640,30 +495,30 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o "n"(ZVAL_OFFSETOF_TYPE) : "rax","cc"); #else - Z_LVAL_P(result) = Z_LVAL_P(op1) + Z_LVAL_P(op2); + /* + * 'result' may alias with op1 or op2, so we need to + * ensure that 'result' is not updated until after we + * have read the values of op1 and op2. + */ if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK) - && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) { - Z_DVAL_P(result) = (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2); - Z_TYPE_P(result) = IS_DOUBLE; + && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) { + ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2)); } else { - Z_TYPE_P(result) = IS_LONG; + ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2)); } #endif return SUCCESS; } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); return SUCCESS; } } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - Z_DVAL_P(result) = Z_DVAL_P(op1) + Z_DVAL_P(op2); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); return SUCCESS; } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - Z_DVAL_P(result) = Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); return SUCCESS; } } @@ -680,7 +535,7 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o "subl (%2), %%eax\n\t" "jo 0f\n\t" "movl %%eax, (%0)\n\t" - "movb %3, %c5(%0)\n\t" + "movl %3, %c5(%0)\n\t" "jmp 1f\n" "0:\n\t" "fildl (%2)\n\t" @@ -690,7 +545,7 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o #else "fsubp %%st, %%st(1)\n\t" #endif - "movb %4, %c5(%0)\n\t" + "movl %4, %c5(%0)\n\t" "fstpl (%0)\n" "1:" : @@ -707,7 +562,7 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o "subq (%2), %%rax\n\t" "jo 0f\n\t" "movq %%rax, (%0)\n\t" - "movb %3, %c5(%0)\n\t" + "movl %3, %c5(%0)\n\t" "jmp 1f\n" "0:\n\t" "fildq (%2)\n\t" @@ -717,7 +572,7 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o #else "fsubp %%st, %%st(1)\n\t" #endif - "movb %4, %c5(%0)\n\t" + "movl %4, %c5(%0)\n\t" "fstpl (%0)\n" "1:" : @@ -729,30 +584,24 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o "n"(ZVAL_OFFSETOF_TYPE) : "rax","cc"); #else - Z_LVAL_P(result) = Z_LVAL_P(op1) - Z_LVAL_P(op2); + ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2)); if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK) && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) { - Z_DVAL_P(result) = (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2); - Z_TYPE_P(result) = IS_DOUBLE; - } else { - Z_TYPE_P(result) = IS_LONG; + ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2)); } #endif return SUCCESS; } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2)); return SUCCESS; } } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2)); return SUCCESS; } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - Z_DVAL_P(result) = Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2))); return SUCCESS; } } @@ -763,24 +612,21 @@ static zend_always_inline int fast_mul_function(zval *result, zval *op1, zval *o { if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - long overflow; + zend_long overflow; ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); - Z_TYPE_P(result) = overflow ? IS_DOUBLE : IS_LONG; + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; return SUCCESS; } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2)); return SUCCESS; } } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - Z_DVAL_P(result) = Z_DVAL_P(op1) * Z_DVAL_P(op2); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2)); return SUCCESS; } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - Z_DVAL_P(result) = Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2))); return SUCCESS; } } @@ -789,60 +635,52 @@ static zend_always_inline int fast_mul_function(zval *result, zval *op1, zval *o static zend_always_inline int fast_div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { +#if 0 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && 0) { if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { zend_error(E_WARNING, "Division by zero"); - Z_LVAL_P(result) = 0; - Z_TYPE_P(result) = IS_BOOL; + ZVAL_BOOL(result, 0); return FAILURE; - } else if (UNEXPECTED(Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == LONG_MIN)) { + } else if (UNEXPECTED(Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN)) { /* Prevent overflow error/crash */ - Z_DVAL_P(result) = (double) LONG_MIN / -1; - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1); } else if (EXPECTED(Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0)) { /* integer */ - Z_LVAL_P(result) = Z_LVAL_P(op1) / Z_LVAL_P(op2); - Z_TYPE_P(result) = IS_LONG; + ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2)); } else { - Z_DVAL_P(result) = ((double) Z_LVAL_P(op1)) / ((double)Z_LVAL_P(op2)); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / ((double)Z_LVAL_P(op2))); } return SUCCESS; } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { if (UNEXPECTED(Z_DVAL_P(op2) == 0)) { zend_error(E_WARNING, "Division by zero"); - Z_LVAL_P(result) = 0; - Z_TYPE_P(result) = IS_BOOL; + ZVAL_BOOL(result, 0); return FAILURE; } - Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) / Z_DVAL_P(op2); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) / Z_DVAL_P(op2)); return SUCCESS; } } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE) && 0) { if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { if (UNEXPECTED(Z_DVAL_P(op2) == 0)) { zend_error(E_WARNING, "Division by zero"); - Z_LVAL_P(result) = 0; - Z_TYPE_P(result) = IS_BOOL; + ZVAL_BOOL(result, 0); return FAILURE; } - Z_DVAL_P(result) = Z_DVAL_P(op1) / Z_DVAL_P(op2); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2)); return SUCCESS; } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { zend_error(E_WARNING, "Division by zero"); - Z_LVAL_P(result) = 0; - Z_TYPE_P(result) = IS_BOOL; + ZVAL_BOOL(result, 0); return FAILURE; } - Z_DVAL_P(result) = Z_DVAL_P(op1) / ((double)Z_LVAL_P(op2)); - Z_TYPE_P(result) = IS_DOUBLE; + ZVAL_DOUBLE(result, Z_DVAL_P(op1) / ((double)Z_LVAL_P(op2))); return SUCCESS; } } +#endif return div_function(result, op1, op2 TSRMLS_CC); } @@ -852,24 +690,21 @@ static zend_always_inline int fast_mod_function(zval *result, zval *op1, zval *o if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { zend_error(E_WARNING, "Division by zero"); - Z_LVAL_P(result) = 0; - Z_TYPE_P(result) = IS_BOOL; + ZVAL_BOOL(result, 0); return FAILURE; } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { - /* Prevent overflow error/crash if op1==LONG_MIN */ - Z_LVAL_P(result) = 0; - Z_TYPE_P(result) = IS_LONG; + /* Prevent overflow error/crash if op1==ZEND_LONG_MIN */ + ZVAL_LONG(result, 0); return SUCCESS; } - Z_LVAL_P(result) = Z_LVAL_P(op1) % Z_LVAL_P(op2); - Z_TYPE_P(result) = IS_LONG; + ZVAL_LONG(result, Z_LVAL_P(op1) % Z_LVAL_P(op2)); return SUCCESS; } } return mod_function(result, op1, op2 TSRMLS_CC); } -static zend_always_inline int fast_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) +static zend_always_inline int fast_equal_check_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { @@ -883,86 +718,239 @@ static zend_always_inline int fast_equal_function(zval *result, zval *op1, zval } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { return Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2)); } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + return 1; + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + return 0; + } else { + return memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0; + } + } else { + zendi_smart_strcmp(result, op1, op2); + return Z_LVAL_P(result) == 0; + } + } } compare_function(result, op1, op2 TSRMLS_CC); return Z_LVAL_P(result) == 0; } -static zend_always_inline int fast_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) +static zend_always_inline void fast_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) +{ + if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(result, Z_LVAL_P(op1) == Z_LVAL_P(op2)); + return; + } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(result, (double)Z_LVAL_P(op1) == Z_DVAL_P(op2)); + return; + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { + ZVAL_BOOL(result, Z_DVAL_P(op1) == Z_DVAL_P(op2)); + return; + } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + ZVAL_BOOL(result, Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2))); + return; + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_TRUE(result); + return; + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_FALSE(result); + return; + } else { + ZVAL_BOOL(result, memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0); + return; + } + } else { + zendi_smart_strcmp(result, op1, op2); + ZVAL_BOOL(result, Z_LVAL_P(result) == 0); + return; + } + } + } + compare_function(result, op1, op2 TSRMLS_CC); + ZVAL_BOOL(result, Z_LVAL_P(result) == 0); +} + +static zend_always_inline void fast_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - return Z_LVAL_P(op1) != Z_LVAL_P(op2); + ZVAL_BOOL(result, Z_LVAL_P(op1) != Z_LVAL_P(op2)); + return; } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - return ((double)Z_LVAL_P(op1)) != Z_DVAL_P(op2); + ZVAL_BOOL(result, (double)Z_LVAL_P(op1) != Z_DVAL_P(op2)); + return; } } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - return Z_DVAL_P(op1) != Z_DVAL_P(op2); + ZVAL_BOOL(result, Z_DVAL_P(op1) != Z_DVAL_P(op2)); + return; } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - return Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2)); + ZVAL_BOOL(result, Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2))); + return; + } + } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + if (Z_STR_P(op1) == Z_STR_P(op2)) { + ZVAL_FALSE(result); + return; + } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') { + if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) { + ZVAL_TRUE(result); + return; + } else { + ZVAL_BOOL(result, memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) != 0); + return; + } + } else { + zendi_smart_strcmp(result, op1, op2); + ZVAL_BOOL(result, Z_LVAL_P(result) != 0); + return; + } } } compare_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result) != 0; + ZVAL_BOOL(result, Z_LVAL_P(result) != 0); } -static zend_always_inline int fast_is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) +static zend_always_inline void fast_is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - return Z_LVAL_P(op1) < Z_LVAL_P(op2); + ZVAL_BOOL(result, Z_LVAL_P(op1) < Z_LVAL_P(op2)); + return; } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - return ((double)Z_LVAL_P(op1)) < Z_DVAL_P(op2); + ZVAL_BOOL(result, (double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); + return; } } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - return Z_DVAL_P(op1) < Z_DVAL_P(op2); + ZVAL_BOOL(result, Z_DVAL_P(op1) < Z_DVAL_P(op2)); + return; } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - return Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2)); + ZVAL_BOOL(result, Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2))); + return; } } compare_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result) < 0; + ZVAL_BOOL(result, Z_LVAL_P(result) < 0); } -static zend_always_inline int fast_is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) +static zend_always_inline void fast_is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) { if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - return Z_LVAL_P(op1) <= Z_LVAL_P(op2); + ZVAL_BOOL(result, Z_LVAL_P(op1) <= Z_LVAL_P(op2)); + return; } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - return ((double)Z_LVAL_P(op1)) <= Z_DVAL_P(op2); + ZVAL_BOOL(result, (double)Z_LVAL_P(op1) <= Z_DVAL_P(op2)); + return; } } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - return Z_DVAL_P(op1) <= Z_DVAL_P(op2); + ZVAL_BOOL(result, Z_DVAL_P(op1) <= Z_DVAL_P(op2)); + return; } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - return Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2)); + ZVAL_BOOL(result, Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2))); + return; } } compare_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result) <= 0; + ZVAL_BOOL(result, Z_LVAL_P(result) <= 0); +} + +static zend_always_inline void fast_is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) +{ + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + ZVAL_BOOL(result, 0); + return; + } + is_identical_function(result, op1, op2 TSRMLS_CC); +} + +static zend_always_inline void fast_is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) +{ + if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) { + ZVAL_BOOL(result, 1); + return; + } + is_identical_function(result, op1, op2 TSRMLS_CC); + ZVAL_BOOL(result, Z_TYPE_P(result) != IS_TRUE); } -#define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode) \ - if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation)) { \ - if (SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) { \ - return SUCCESS; \ - } \ - } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, do_operation)) { \ - if (SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) { \ - return SUCCESS; \ - } \ +#define ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode, binary_op) \ + if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT) \ + && op1 == result \ + && UNEXPECTED(Z_OBJ_HANDLER_P(op1, get)) \ + && EXPECTED(Z_OBJ_HANDLER_P(op1, set))) { \ + int ret; \ + zval rv; \ + zval *objval = Z_OBJ_HANDLER_P(op1, get)(op1, &rv TSRMLS_CC); \ + Z_ADDREF_P(objval); \ + ret = binary_op(objval, objval, op2 TSRMLS_CC); \ + Z_OBJ_HANDLER_P(op1, set)(op1, objval TSRMLS_CC); \ + zval_ptr_dtor(objval); \ + return ret; \ + } else if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT) \ + && UNEXPECTED(Z_OBJ_HANDLER_P(op1, do_operation))) { \ + if (EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2 TSRMLS_CC))) { \ + return SUCCESS; \ + } \ } -#define ZEND_TRY_UNARY_OBJECT_OPERATION(opcode) \ - if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation) \ - && SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, NULL TSRMLS_CC) \ - ) { \ - return SUCCESS; \ +#define ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode) \ + if (UNEXPECTED(Z_TYPE_P(op2) == IS_OBJECT) \ + && UNEXPECTED(Z_OBJ_HANDLER_P(op2, do_operation)) \ + && EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2 TSRMLS_CC))) { \ + return SUCCESS; \ } +#define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode, binary_op) \ + ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode, binary_op) \ + else \ + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode) + +#define ZEND_TRY_UNARY_OBJECT_OPERATION(opcode) \ + if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT) \ + && UNEXPECTED(Z_OBJ_HANDLER_P(op1, do_operation)) \ + && EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, NULL TSRMLS_CC))) { \ + return SUCCESS; \ + } + +/* buf points to the END of the buffer */ +static zend_always_inline char *zend_print_ulong_to_buf(char *buf, zend_ulong num) { + *buf = '\0'; + do { + *--buf = (char) (num % 10) + '0'; + num /= 10; + } while (num > 0); + return buf; +} + +/* buf points to the END of the buffer */ +static zend_always_inline char *zend_print_long_to_buf(char *buf, zend_long num) { + if (num < 0) { + char *result = zend_print_ulong_to_buf(buf, ~((zend_ulong) num) + 1); + *--result = '-'; + return result; + } else { + return zend_print_ulong_to_buf(buf, num); + } +} + +ZEND_API zend_string *zend_long_to_str(zend_long num); + +END_EXTERN_C() + #endif /* |