root/Zend/zend_operators.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. zend_dval_to_lval
  2. zend_dval_to_lval
  3. is_numeric_string_ex
  4. is_numeric_string
  5. zend_memnstr
  6. zend_memrchr
  7. zend_memnrstr
  8. _zval_get_long
  9. _zval_get_double
  10. _zval_get_string
  11. i_zend_is_true
  12. fast_long_increment_function
  13. fast_long_decrement_function
  14. fast_long_add_function
  15. fast_add_function
  16. fast_long_sub_function
  17. fast_div_function
  18. fast_equal_check_function
  19. fast_equal_check_long
  20. fast_equal_check_string
  21. fast_is_identical_function
  22. fast_is_not_identical_function
  23. zend_print_ulong_to_buf
  24. zend_print_long_to_buf

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend Engine                                                          |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 2.00 of the Zend license,     |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.zend.com/license/2_00.txt.                                |
  11    | If you did not receive a copy of the Zend license and are unable to  |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@zend.com so we can mail you a copy immediately.              |
  14    +----------------------------------------------------------------------+
  15    | Authors: Andi Gutmans <andi@zend.com>                                |
  16    |          Zeev Suraski <zeev@zend.com>                                |
  17    |          Dmitry Stogov <dmitry@zend.com>                             |
  18    +----------------------------------------------------------------------+
  19 */
  20 
  21 /* $Id$ */
  22 
  23 #ifndef ZEND_OPERATORS_H
  24 #define ZEND_OPERATORS_H
  25 
  26 #include <errno.h>
  27 #include <math.h>
  28 #include <assert.h>
  29 
  30 #ifdef __GNUC__
  31 #include <stddef.h>
  32 #endif
  33 
  34 #ifdef HAVE_IEEEFP_H
  35 #include <ieeefp.h>
  36 #endif
  37 
  38 #include "zend_strtod.h"
  39 #include "zend_multiply.h"
  40 
  41 #if 0&&HAVE_BCMATH
  42 #include "ext/bcmath/libbcmath/src/bcmath.h"
  43 #endif
  44 
  45 #define LONG_SIGN_MASK (((zend_long)1) << (8*sizeof(zend_long)-1))
  46 
  47 BEGIN_EXTERN_C()
  48 ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2);
  49 ZEND_API int ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2);
  50 ZEND_API int ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2);
  51 ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2);
  52 ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2);
  53 ZEND_API int ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2);
  54 ZEND_API int ZEND_FASTCALL boolean_xor_function(zval *result, zval *op1, zval *op2);
  55 ZEND_API int ZEND_FASTCALL boolean_not_function(zval *result, zval *op1);
  56 ZEND_API int ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1);
  57 ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op2);
  58 ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *op2);
  59 ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *op2);
  60 ZEND_API int ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op2);
  61 ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2);
  62 ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2);
  63 
  64 ZEND_API int ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2);
  65 
  66 ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2);
  67 ZEND_API int ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2);
  68 ZEND_API int ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zval *op2);
  69 ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2);
  70 ZEND_API int ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2);
  71 ZEND_API int ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1, zval *op2);
  72 
  73 ZEND_API zend_bool ZEND_FASTCALL instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only);
  74 ZEND_API zend_bool ZEND_FASTCALL instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce);
  75 
  76 /**
  77  * Checks whether the string "str" with length "length" is numeric. The value
  78  * of allow_errors determines whether it's required to be entirely numeric, or
  79  * just its prefix. Leading whitespace is allowed.
  80  *
  81  * The function returns 0 if the string did not contain a valid number; IS_LONG
  82  * if it contained a number that fits within the range of a long; or IS_DOUBLE
  83  * if the number was out of long range or contained a decimal point/exponent.
  84  * The number's value is returned into the respective pointer, *lval or *dval,
  85  * if that pointer is not NULL.
  86  *
  87  * This variant also gives information if a string that represents an integer
  88  * could not be represented as such due to overflow. It writes 1 to oflow_info
  89  * if the integer is larger than ZEND_LONG_MAX and -1 if it's smaller than ZEND_LONG_MIN.
  90  */
  91 ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info);
  92 
  93 ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end);
  94 ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end);
  95 
  96 #if SIZEOF_ZEND_LONG == 4
  97 #       define ZEND_DOUBLE_FITS_LONG(d) (!((d) > ZEND_LONG_MAX || (d) < ZEND_LONG_MIN))
  98 #else
  99         /* >= as (double)ZEND_LONG_MAX is outside signed range */
 100 #       define ZEND_DOUBLE_FITS_LONG(d) (!((d) >= ZEND_LONG_MAX || (d) < ZEND_LONG_MIN))
 101 #endif
 102 
 103 #if ZEND_DVAL_TO_LVAL_CAST_OK
 104 static zend_always_inline zend_long zend_dval_to_lval(double d)
 105 {
 106     if (EXPECTED(zend_finite(d)) && EXPECTED(!zend_isnan(d))) {
 107         return (zend_long)d;
 108     } else {
 109         return 0;
 110     }
 111 }
 112 #else
 113 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d);
 114 
 115 static zend_always_inline zend_long zend_dval_to_lval(double d)
 116 {
 117         if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) {
 118                 return 0;
 119         } else if (!ZEND_DOUBLE_FITS_LONG(d)) {
 120                 return zend_dval_to_lval_slow(d);
 121         }
 122         return (zend_long)d;
 123 }
 124 #endif
 125 /* }}} */
 126 
 127 #define ZEND_IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
 128 #define ZEND_IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))
 129 
 130 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)
 131 {
 132         if (*str > '9') {
 133                 return 0;
 134         }
 135         return _is_numeric_string_ex(str, length, lval, dval, allow_errors, oflow_info);
 136 }
 137 
 138 static zend_always_inline zend_uchar is_numeric_string(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors) {
 139     return is_numeric_string_ex(str, length, lval, dval, allow_errors, NULL);
 140 }
 141 
 142 ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval);
 143 
 144 static zend_always_inline const char *
 145 zend_memnstr(const char *haystack, const char *needle, size_t needle_len, const char *end)
 146 {
 147         const char *p = haystack;
 148         const char ne = needle[needle_len-1];
 149         ptrdiff_t off_p;
 150         size_t off_s;
 151 
 152         if (needle_len == 1) {
 153                 return (const char *)memchr(p, *needle, (end-p));
 154         }
 155 
 156         off_p = end - haystack;
 157         off_s = (off_p > 0) ? (size_t)off_p : 0;
 158 
 159         if (needle_len > off_s) {
 160                 return NULL;
 161         }
 162 
 163         if (EXPECTED(off_s < 1024 || needle_len < 3)) {
 164                 end -= needle_len;
 165 
 166                 while (p <= end) {
 167                         if ((p = (const char *)memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) {
 168                                 if (!memcmp(needle, p, needle_len-1)) {
 169                                         return p;
 170                                 }
 171                         }
 172 
 173                         if (p == NULL) {
 174                                 return NULL;
 175                         }
 176 
 177                         p++;
 178                 }
 179 
 180                 return NULL;
 181         } else {
 182                 return zend_memnstr_ex(haystack, needle, needle_len, end);
 183         }
 184 }
 185 
 186 static zend_always_inline const void *zend_memrchr(const void *s, int c, size_t n)
 187 {
 188         register const unsigned char *e;
 189         if (n <= 0) {
 190                 return NULL;
 191         }
 192 
 193         for (e = (const unsigned char *)s + n - 1; e >= (const unsigned char *)s; e--) {
 194                 if (*e == (const unsigned char)c) {
 195                         return (const void *)e;
 196                 }
 197         }
 198         return NULL;
 199 }
 200 
 201 
 202 static zend_always_inline const char *
 203 zend_memnrstr(const char *haystack, const char *needle, size_t needle_len, char *end)
 204 {
 205     const char *p = end;
 206     const char ne = needle[needle_len-1];
 207     ptrdiff_t off_p;
 208     size_t off_s;
 209 
 210     if (needle_len == 1) {
 211         return (const char *)zend_memrchr(haystack, *needle, (p - haystack));
 212     }
 213 
 214     off_p = end - haystack;
 215     off_s = (off_p > 0) ? (size_t)off_p : 0;
 216 
 217     if (needle_len > off_s) {
 218         return NULL;
 219     }
 220 
 221         if (EXPECTED(off_s < 1024 || needle_len < 3)) {
 222                 p -= needle_len;
 223 
 224                 do {
 225                         if ((p = (const char *)zend_memrchr(haystack, *needle, (p - haystack) + 1)) && ne == p[needle_len-1]) {
 226                                 if (!memcmp(needle, p, needle_len - 1)) {
 227                                         return p;
 228                                 }
 229                         }
 230                 } while (p-- >= haystack);
 231 
 232                 return NULL;
 233         } else {
 234                 return zend_memnrstr_ex(haystack, needle, needle_len, end);
 235         }
 236 }
 237 
 238 ZEND_API int ZEND_FASTCALL increment_function(zval *op1);
 239 ZEND_API int ZEND_FASTCALL decrement_function(zval *op2);
 240 
 241 ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op);
 242 ZEND_API void ZEND_FASTCALL _convert_to_cstring(zval *op ZEND_FILE_LINE_DC);
 243 ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op ZEND_FILE_LINE_DC);
 244 ZEND_API void ZEND_FASTCALL convert_to_long(zval *op);
 245 ZEND_API void ZEND_FASTCALL convert_to_double(zval *op);
 246 ZEND_API void ZEND_FASTCALL convert_to_long_base(zval *op, int base);
 247 ZEND_API void ZEND_FASTCALL convert_to_null(zval *op);
 248 ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op);
 249 ZEND_API void ZEND_FASTCALL convert_to_array(zval *op);
 250 ZEND_API void ZEND_FASTCALL convert_to_object(zval *op);
 251 ZEND_API void multi_convert_to_long_ex(int argc, ...);
 252 ZEND_API void multi_convert_to_double_ex(int argc, ...);
 253 ZEND_API void multi_convert_to_string_ex(int argc, ...);
 254 
 255 ZEND_API zend_long    ZEND_FASTCALL _zval_get_long_func(zval *op);
 256 ZEND_API double       ZEND_FASTCALL _zval_get_double_func(zval *op);
 257 ZEND_API zend_string* ZEND_FASTCALL _zval_get_string_func(zval *op);
 258 
 259 static zend_always_inline zend_long _zval_get_long(zval *op) {
 260         return Z_TYPE_P(op) == IS_LONG ? Z_LVAL_P(op) : _zval_get_long_func(op);
 261 }
 262 static zend_always_inline double _zval_get_double(zval *op) {
 263         return Z_TYPE_P(op) == IS_DOUBLE ? Z_DVAL_P(op) : _zval_get_double_func(op);
 264 }
 265 static zend_always_inline zend_string *_zval_get_string(zval *op) {
 266         return Z_TYPE_P(op) == IS_STRING ? zend_string_copy(Z_STR_P(op)) : _zval_get_string_func(op);
 267 }
 268 
 269 #define zval_get_long(op) _zval_get_long((op))
 270 #define zval_get_double(op) _zval_get_double((op))
 271 #define zval_get_string(op) _zval_get_string((op))
 272 
 273 #define convert_to_cstring(op) if (Z_TYPE_P(op) != IS_STRING) { _convert_to_cstring((op) ZEND_FILE_LINE_CC); }
 274 #define convert_to_string(op) if (Z_TYPE_P(op) != IS_STRING) { _convert_to_string((op) ZEND_FILE_LINE_CC); }
 275 
 276 
 277 ZEND_API int ZEND_FASTCALL zend_is_true(zval *op);
 278 ZEND_API int ZEND_FASTCALL zend_object_is_true(zval *op);
 279 
 280 #define zval_is_true(op) \
 281         zend_is_true(op)
 282 
 283 static zend_always_inline int i_zend_is_true(zval *op)
 284 {
 285         int result = 0;
 286 
 287 again:
 288         switch (Z_TYPE_P(op)) {
 289                 case IS_TRUE:
 290                         result = 1;
 291                         break;
 292                 case IS_LONG:
 293                         if (Z_LVAL_P(op)) {
 294                                 result = 1;
 295                         }
 296                         break;
 297                 case IS_DOUBLE:
 298                         if (Z_DVAL_P(op)) {
 299                                 result = 1;
 300                         }
 301                         break;
 302                 case IS_STRING:
 303                         if (Z_STRLEN_P(op) > 1 || (Z_STRLEN_P(op) && Z_STRVAL_P(op)[0] != '0')) {
 304                                 result = 1;
 305                         }
 306                         break;
 307                 case IS_ARRAY:
 308                         if (zend_hash_num_elements(Z_ARRVAL_P(op))) {
 309                                 result = 1;
 310                         }
 311                         break;
 312                 case IS_OBJECT:
 313                         result = zend_object_is_true(op);
 314                         break;
 315                 case IS_RESOURCE:
 316                         if (EXPECTED(Z_RES_HANDLE_P(op))) {
 317                                 result = 1;
 318                         }
 319                         break;
 320                 case IS_REFERENCE:
 321                         op = Z_REFVAL_P(op);
 322                         goto again;
 323                         break;
 324                 default:
 325                         break;
 326         }
 327         return result;
 328 }
 329 
 330 ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2);
 331 
 332 ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2);
 333 ZEND_API int ZEND_FASTCALL string_compare_function_ex(zval *op1, zval *op2, zend_bool case_insensitive);
 334 ZEND_API int ZEND_FASTCALL string_compare_function(zval *op1, zval *op2);
 335 ZEND_API int ZEND_FASTCALL string_case_compare_function(zval *op1, zval *op2);
 336 #if HAVE_STRCOLL
 337 ZEND_API int ZEND_FASTCALL string_locale_compare_function(zval *op1, zval *op2);
 338 #endif
 339 
 340 ZEND_API void         ZEND_FASTCALL zend_str_tolower(char *str, size_t length);
 341 ZEND_API char*        ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length);
 342 ZEND_API char*        ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length);
 343 ZEND_API char*        ZEND_FASTCALL zend_str_tolower_dup_ex(const char *source, size_t length);
 344 ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower(zend_string *str);
 345 
 346 ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2);
 347 ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3);
 348 ZEND_API int ZEND_FASTCALL zend_binary_zval_strcasecmp(zval *s1, zval *s2);
 349 ZEND_API int ZEND_FASTCALL zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3);
 350 ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2);
 351 ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length);
 352 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2);
 353 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length);
 354 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2);
 355 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length);
 356 
 357 ZEND_API zend_long ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2);
 358 ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2);
 359 ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2);
 360 ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2);
 361 
 362 ZEND_API int ZEND_FASTCALL zend_atoi(const char *str, int str_len);
 363 ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, int str_len);
 364 
 365 ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC);
 366 
 367 #define convert_to_ex_master(pzv, lower_type, upper_type)       \
 368         if (Z_TYPE_P(pzv)!=upper_type) {                                        \
 369                 convert_to_##lower_type(pzv);                                           \
 370         }
 371 
 372 #define convert_to_explicit_type(pzv, type)             \
 373         do {                                                                            \
 374                 switch (type) {                                                 \
 375                         case IS_NULL:                                           \
 376                                 convert_to_null(pzv);                   \
 377                                 break;                                                  \
 378                         case IS_LONG:                                           \
 379                                 convert_to_long(pzv);                   \
 380                                 break;                                                  \
 381                         case IS_DOUBLE:                                         \
 382                                 convert_to_double(pzv);                 \
 383                                 break;                                                  \
 384                         case _IS_BOOL:                                          \
 385                                 convert_to_boolean(pzv);                \
 386                                 break;                                                  \
 387                         case IS_ARRAY:                                          \
 388                                 convert_to_array(pzv);                  \
 389                                 break;                                                  \
 390                         case IS_OBJECT:                                         \
 391                                 convert_to_object(pzv);                 \
 392                                 break;                                                  \
 393                         case IS_STRING:                                         \
 394                                 convert_to_string(pzv);                 \
 395                                 break;                                                  \
 396                         default:                                                        \
 397                                 assert(0);                                              \
 398                                 break;                                                  \
 399                 }                                                                               \
 400         } while (0);
 401 
 402 #define convert_to_explicit_type_ex(pzv, str_type)      \
 403         if (Z_TYPE_P(pzv) != str_type) {                                \
 404                 convert_to_explicit_type(pzv, str_type);        \
 405         }
 406 
 407 #define convert_to_boolean_ex(pzv)      convert_to_ex_master(pzv, boolean, _IS_BOOL)
 408 #define convert_to_long_ex(pzv)         convert_to_ex_master(pzv, long, IS_LONG)
 409 #define convert_to_double_ex(pzv)       convert_to_ex_master(pzv, double, IS_DOUBLE)
 410 #define convert_to_string_ex(pzv)       convert_to_ex_master(pzv, string, IS_STRING)
 411 #define convert_to_array_ex(pzv)        convert_to_ex_master(pzv, array, IS_ARRAY)
 412 #define convert_to_object_ex(pzv)       convert_to_ex_master(pzv, object, IS_OBJECT)
 413 #define convert_to_null_ex(pzv)         convert_to_ex_master(pzv, null, IS_NULL)
 414 
 415 #define convert_scalar_to_number_ex(pzv)                                                        \
 416         if (Z_TYPE_P(pzv)!=IS_LONG && Z_TYPE_P(pzv)!=IS_DOUBLE) {               \
 417                 convert_scalar_to_number(pzv);                                  \
 418         }
 419 
 420 #if HAVE_SETLOCALE && defined(ZEND_WIN32) && !defined(ZTS) && defined(_MSC_VER)
 421 /* This performance improvement of tolower() on Windows gives 10-18% on bench.php */
 422 #define ZEND_USE_TOLOWER_L 1
 423 #endif
 424 
 425 #ifdef ZEND_USE_TOLOWER_L
 426 ZEND_API void zend_update_current_locale(void);
 427 #else
 428 #define zend_update_current_locale()
 429 #endif
 430 
 431 /* The offset in bytes between the value and type fields of a zval */
 432 #define ZVAL_OFFSETOF_TYPE      \
 433         (offsetof(zval, u1.type_info) - offsetof(zval, value))
 434 
 435 static zend_always_inline void fast_long_increment_function(zval *op1)
 436 {
 437 #if defined(__GNUC__) && defined(__i386__)
 438         __asm__(
 439                 "incl (%0)\n\t"
 440                 "jno  0f\n\t"
 441                 "movl $0x0, (%0)\n\t"
 442                 "movl $0x41e00000, 0x4(%0)\n\t"
 443                 "movl %1, %c2(%0)\n"
 444                 "0:"
 445                 :
 446                 : "r"(&op1->value),
 447                   "n"(IS_DOUBLE),
 448                   "n"(ZVAL_OFFSETOF_TYPE)
 449                 : "cc");
 450 #elif defined(__GNUC__) && defined(__x86_64__)
 451         __asm__(
 452                 "incq (%0)\n\t"
 453                 "jno  0f\n\t"
 454                 "movl $0x0, (%0)\n\t"
 455                 "movl $0x43e00000, 0x4(%0)\n\t"
 456                 "movl %1, %c2(%0)\n"
 457                 "0:"
 458                 :
 459                 : "r"(&op1->value),
 460                   "n"(IS_DOUBLE),
 461                   "n"(ZVAL_OFFSETOF_TYPE)
 462                 : "cc");
 463 #else
 464         if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MAX)) {
 465                 /* switch to double */
 466                 ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0);
 467         } else {
 468                 Z_LVAL_P(op1)++;
 469         }
 470 #endif
 471 }
 472 
 473 static zend_always_inline void fast_long_decrement_function(zval *op1)
 474 {
 475 #if defined(__GNUC__) && defined(__i386__)
 476         __asm__(
 477                 "decl (%0)\n\t"
 478                 "jno  0f\n\t"
 479                 "movl $0x00200000, (%0)\n\t"
 480                 "movl $0xc1e00000, 0x4(%0)\n\t"
 481                 "movl %1,%c2(%0)\n"
 482                 "0:"
 483                 :
 484                 : "r"(&op1->value),
 485                   "n"(IS_DOUBLE),
 486                   "n"(ZVAL_OFFSETOF_TYPE)
 487                 : "cc");
 488 #elif defined(__GNUC__) && defined(__x86_64__)
 489         __asm__(
 490                 "decq (%0)\n\t"
 491                 "jno  0f\n\t"
 492                 "movl $0x00000000, (%0)\n\t"
 493                 "movl $0xc3e00000, 0x4(%0)\n\t"
 494                 "movl %1,%c2(%0)\n"
 495                 "0:"
 496                 :
 497                 : "r"(&op1->value),
 498                   "n"(IS_DOUBLE),
 499                   "n"(ZVAL_OFFSETOF_TYPE)
 500                 : "cc");
 501 #else
 502         if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MIN)) {
 503                 /* switch to double */
 504                 ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0);
 505         } else {
 506                 Z_LVAL_P(op1)--;
 507         }
 508 #endif
 509 }
 510 
 511 static zend_always_inline void fast_long_add_function(zval *result, zval *op1, zval *op2)
 512 {
 513 #if defined(__GNUC__) && defined(__i386__) && !(4 == __GNUC__ && 8 == __GNUC_MINOR__)
 514         __asm__(
 515                 "movl   (%1), %%eax\n\t"
 516                 "addl   (%2), %%eax\n\t"
 517                 "jo     0f\n\t"
 518                 "movl   %%eax, (%0)\n\t"
 519                 "movl   %3, %c5(%0)\n\t"
 520                 "jmp    1f\n"
 521                 "0:\n\t"
 522                 "fildl  (%1)\n\t"
 523                 "fildl  (%2)\n\t"
 524                 "faddp  %%st, %%st(1)\n\t"
 525                 "movl   %4, %c5(%0)\n\t"
 526                 "fstpl  (%0)\n"
 527                 "1:"
 528                 :
 529                 : "r"(&result->value),
 530                   "r"(&op1->value),
 531                   "r"(&op2->value),
 532                   "n"(IS_LONG),
 533                   "n"(IS_DOUBLE),
 534                   "n"(ZVAL_OFFSETOF_TYPE)
 535                 : "eax","cc");
 536 #elif defined(__GNUC__) && defined(__x86_64__)
 537         __asm__(
 538                 "movq   (%1), %%rax\n\t"
 539                 "addq   (%2), %%rax\n\t"
 540                 "jo     0f\n\t"
 541                 "movq   %%rax, (%0)\n\t"
 542                 "movl   %3, %c5(%0)\n\t"
 543                 "jmp    1f\n"
 544                 "0:\n\t"
 545                 "fildq  (%1)\n\t"
 546                 "fildq  (%2)\n\t"
 547                 "faddp  %%st, %%st(1)\n\t"
 548                 "movl   %4, %c5(%0)\n\t"
 549                 "fstpl  (%0)\n"
 550                 "1:"
 551                 :
 552                 : "r"(&result->value),
 553                   "r"(&op1->value),
 554                   "r"(&op2->value),
 555                   "n"(IS_LONG),
 556                   "n"(IS_DOUBLE),
 557                   "n"(ZVAL_OFFSETOF_TYPE)
 558                 : "rax","cc");
 559 #else
 560         /*
 561          * 'result' may alias with op1 or op2, so we need to
 562          * ensure that 'result' is not updated until after we
 563          * have read the values of op1 and op2.
 564          */
 565 
 566         if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
 567                 && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) {
 568                 ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
 569         } else {
 570                 ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2));
 571         }
 572 #endif
 573 }
 574 
 575 static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *op2)
 576 {
 577         if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
 578                 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
 579                         fast_long_add_function(result, op1, op2);
 580                         return SUCCESS;
 581                 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
 582                         ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
 583                         return SUCCESS;
 584                 }
 585         } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
 586                 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
 587                         ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
 588                         return SUCCESS;
 589                 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
 590                         ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
 591                         return SUCCESS;
 592                 }
 593         }
 594         return add_function(result, op1, op2);
 595 }
 596 
 597 static zend_always_inline void fast_long_sub_function(zval *result, zval *op1, zval *op2)
 598 {
 599 #if defined(__GNUC__) && defined(__i386__) && !(4 == __GNUC__ && 8 == __GNUC_MINOR__)
 600         __asm__(
 601                 "movl   (%1), %%eax\n\t"
 602                 "subl   (%2), %%eax\n\t"
 603                 "jo     0f\n\t"
 604                 "movl   %%eax, (%0)\n\t"
 605                 "movl   %3, %c5(%0)\n\t"
 606                 "jmp    1f\n"
 607                 "0:\n\t"
 608                 "fildl  (%2)\n\t"
 609                 "fildl  (%1)\n\t"
 610 #if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10))
 611                 "fsubp  %%st(1), %%st\n\t"  /* LLVM bug #9164 */
 612 #else
 613                 "fsubp  %%st, %%st(1)\n\t"
 614 #endif
 615                 "movl   %4, %c5(%0)\n\t"
 616                 "fstpl  (%0)\n"
 617                 "1:"
 618                 :
 619                 : "r"(&result->value),
 620                   "r"(&op1->value),
 621                   "r"(&op2->value),
 622                   "n"(IS_LONG),
 623                   "n"(IS_DOUBLE),
 624                   "n"(ZVAL_OFFSETOF_TYPE)
 625                 : "eax","cc");
 626 #elif defined(__GNUC__) && defined(__x86_64__)
 627         __asm__(
 628                 "movq   (%1), %%rax\n\t"
 629                 "subq   (%2), %%rax\n\t"
 630                 "jo     0f\n\t"
 631                 "movq   %%rax, (%0)\n\t"
 632                 "movl   %3, %c5(%0)\n\t"
 633                 "jmp    1f\n"
 634                 "0:\n\t"
 635                 "fildq  (%2)\n\t"
 636                 "fildq  (%1)\n\t"
 637 #if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10))
 638                 "fsubp  %%st(1), %%st\n\t"  /* LLVM bug #9164 */
 639 #else
 640                 "fsubp  %%st, %%st(1)\n\t"
 641 #endif
 642                 "movl   %4, %c5(%0)\n\t"
 643                 "fstpl  (%0)\n"
 644                 "1:"
 645                 :
 646                 : "r"(&result->value),
 647                   "r"(&op1->value),
 648                   "r"(&op2->value),
 649                   "n"(IS_LONG),
 650                   "n"(IS_DOUBLE),
 651                   "n"(ZVAL_OFFSETOF_TYPE)
 652                 : "rax","cc");
 653 #else
 654         ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2));
 655 
 656         if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK)
 657                 && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) {
 658                 ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
 659         }
 660 #endif
 661 }
 662 
 663 static zend_always_inline int fast_div_function(zval *result, zval *op1, zval *op2)
 664 {
 665         return div_function(result, op1, op2);
 666 }
 667 
 668 static zend_always_inline int fast_equal_check_function(zval *op1, zval *op2)
 669 {
 670         zval result;
 671         if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
 672                 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
 673                         return Z_LVAL_P(op1) == Z_LVAL_P(op2);
 674                 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
 675                         return ((double)Z_LVAL_P(op1)) == Z_DVAL_P(op2);
 676                 }
 677         } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
 678                 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
 679                         return Z_DVAL_P(op1) == Z_DVAL_P(op2);
 680                 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
 681                         return Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2));
 682                 }
 683         } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
 684                 if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
 685                         if (Z_STR_P(op1) == Z_STR_P(op2)) {
 686                                 return 1;
 687                         } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') {
 688                                 if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) {
 689                                         return 0;
 690                                 } else {
 691                                         return memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0;
 692                                 }
 693                         } else {
 694                                 return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2)) == 0;
 695                         }
 696                 }
 697         }
 698         compare_function(&result, op1, op2);
 699         return Z_LVAL(result) == 0;
 700 }
 701 
 702 static zend_always_inline int fast_equal_check_long(zval *op1, zval *op2)
 703 {
 704         zval result;
 705         if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
 706                 return Z_LVAL_P(op1) == Z_LVAL_P(op2);
 707         }
 708         compare_function(&result, op1, op2);
 709         return Z_LVAL(result) == 0;
 710 }
 711 
 712 static zend_always_inline int fast_equal_check_string(zval *op1, zval *op2)
 713 {
 714         zval result;
 715         if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
 716                 if (Z_STR_P(op1) == Z_STR_P(op2)) {
 717                         return 1;
 718                 } else if (Z_STRVAL_P(op1)[0] > '9' || Z_STRVAL_P(op2)[0] > '9') {
 719                         if (Z_STRLEN_P(op1) != Z_STRLEN_P(op2)) {
 720                                 return 0;
 721                         } else {
 722                                 return memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0;
 723                         }
 724                 } else {
 725                         return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2)) == 0;
 726                 }
 727         }
 728         compare_function(&result, op1, op2);
 729         return Z_LVAL(result) == 0;
 730 }
 731 
 732 static zend_always_inline int fast_is_identical_function(zval *op1, zval *op2)
 733 {
 734         if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
 735                 return 0;
 736         } else if (Z_TYPE_P(op1) <= IS_TRUE) {
 737                 return 1;
 738         }
 739         return zend_is_identical(op1, op2);
 740 }
 741 
 742 static zend_always_inline int fast_is_not_identical_function(zval *op1, zval *op2)
 743 {
 744         if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
 745                 return 1;
 746         } else if (Z_TYPE_P(op1) <= IS_TRUE) {
 747                 return 0;
 748         }
 749         return !zend_is_identical(op1, op2);
 750 }
 751 
 752 #define ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode, binary_op)                                            \
 753         if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT)                                                             \
 754                 && op1 == result                                                                                   \
 755                 && UNEXPECTED(Z_OBJ_HANDLER_P(op1, get))                                                           \
 756                 && EXPECTED(Z_OBJ_HANDLER_P(op1, set))) {                                                          \
 757                 int ret;                                                                                           \
 758                 zval rv;                                                                                           \
 759                 zval *objval = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);                                      \
 760                 Z_TRY_ADDREF_P(objval);                                                                                \
 761                 ret = binary_op(objval, objval, op2);                                                    \
 762                 Z_OBJ_HANDLER_P(op1, set)(op1, objval);                                                  \
 763                 zval_ptr_dtor(objval);                                                                             \
 764                 return ret;                                                                                        \
 765         } else if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT)                                                      \
 766                 && UNEXPECTED(Z_OBJ_HANDLER_P(op1, do_operation))) {                                               \
 767                 if (EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2))) { \
 768                         return SUCCESS;                                                                                \
 769                 }                                                                                                  \
 770         }
 771 
 772 #define ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode)                                                       \
 773         if (UNEXPECTED(Z_TYPE_P(op2) == IS_OBJECT)                                                             \
 774                 && UNEXPECTED(Z_OBJ_HANDLER_P(op2, do_operation))                                                  \
 775                 && EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2))) {  \
 776                 return SUCCESS;                                                                                    \
 777         }
 778 
 779 #define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode, binary_op)                                                \
 780         ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode, binary_op)                                                \
 781         else                                                                                                   \
 782         ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode)
 783 
 784 #define ZEND_TRY_UNARY_OBJECT_OPERATION(opcode)                                                            \
 785         if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT)                                                             \
 786                 && UNEXPECTED(Z_OBJ_HANDLER_P(op1, do_operation))                                                  \
 787                 && EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, NULL))) { \
 788                 return SUCCESS;                                                                                    \
 789         }
 790 
 791 /* buf points to the END of the buffer */
 792 static zend_always_inline char *zend_print_ulong_to_buf(char *buf, zend_ulong num) {
 793         *buf = '\0';
 794         do {
 795                 *--buf = (char) (num % 10) + '0';
 796                 num /= 10;
 797         } while (num > 0);
 798         return buf;
 799 }
 800 
 801 /* buf points to the END of the buffer */
 802 static zend_always_inline char *zend_print_long_to_buf(char *buf, zend_long num) {
 803         if (num < 0) {
 804             char *result = zend_print_ulong_to_buf(buf, ~((zend_ulong) num) + 1);
 805             *--result = '-';
 806                 return result;
 807         } else {
 808             return zend_print_ulong_to_buf(buf, num);
 809         }
 810 }
 811 
 812 ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num);
 813 
 814 END_EXTERN_C()
 815 
 816 #endif
 817 
 818 /*
 819  * Local variables:
 820  * tab-width: 4
 821  * c-basic-offset: 4
 822  * indent-tabs-mode: t
 823  * End:
 824  */

/* [<][>][^][v][top][bottom][index][help] */