1/* 2 +----------------------------------------------------------------------+ 3 | Zend Engine | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1998-2013 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 +----------------------------------------------------------------------+ 18*/ 19 20/* $Id$ */ 21 22#ifndef ZEND_OPERATORS_H 23#define ZEND_OPERATORS_H 24 25#include <errno.h> 26#include <math.h> 27#include <assert.h> 28 29#ifdef HAVE_IEEEFP_H 30#include <ieeefp.h> 31#endif 32 33#include "zend_strtod.h" 34#include "zend_multiply.h" 35 36#if 0&&HAVE_BCMATH 37#include "ext/bcmath/libbcmath/src/bcmath.h" 38#endif 39 40#define LONG_SIGN_MASK (1L << (8*sizeof(long)-1)) 41 42BEGIN_EXTERN_C() 43ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 44ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 45ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 46ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 47ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 48ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 49ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC); 50ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC); 51ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 52ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 53ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 54ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 55ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 56ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 57 58ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 59ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 60ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 61ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 62ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 63ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 64 65ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC); 66ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC); 67END_EXTERN_C() 68 69#if ZEND_DVAL_TO_LVAL_CAST_OK 70# define zend_dval_to_lval(d) ((long) (d)) 71#elif SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) 72static zend_always_inline long zend_dval_to_lval(double d) 73{ 74 if (d > LONG_MAX || d < LONG_MIN) { 75 return (long)(unsigned long)(zend_long64) d; 76 } 77 return (long) d; 78} 79#else 80static zend_always_inline long zend_dval_to_lval(double d) 81{ 82 /* >= as (double)LONG_MAX is outside signed range */ 83 if (d >= LONG_MAX) { 84 return (long)(unsigned long) d; 85 } 86 return (long) d; 87} 88#endif 89/* }}} */ 90 91#define ZEND_IS_DIGIT(c) ((c) >= '0' && (c) <= '9') 92#define ZEND_IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) 93 94/** 95 * Checks whether the string "str" with length "length" is numeric. The value 96 * of allow_errors determines whether it's required to be entirely numeric, or 97 * just its prefix. Leading whitespace is allowed. 98 * 99 * The function returns 0 if the string did not contain a valid number; IS_LONG 100 * if it contained a number that fits within the range of a long; or IS_DOUBLE 101 * if the number was out of long range or contained a decimal point/exponent. 102 * The number's value is returned into the respective pointer, *lval or *dval, 103 * if that pointer is not NULL. 104 * 105 * This variant also gives information if a string that represents an integer 106 * could not be represented as such due to overflow. It writes 1 to oflow_info 107 * if the integer is larger than LONG_MAX and -1 if it's smaller than LONG_MIN. 108 */ 109static inline zend_uchar is_numeric_string_ex(const char *str, int length, long *lval, double *dval, int allow_errors, int *oflow_info) 110{ 111 const char *ptr; 112 int base = 10, digits = 0, dp_or_e = 0; 113 double local_dval; 114 zend_uchar type; 115 116 if (!length) { 117 return 0; 118 } 119 120 if (oflow_info != NULL) { 121 *oflow_info = 0; 122 } 123 124 /* Skip any whitespace 125 * This is much faster than the isspace() function */ 126 while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') { 127 str++; 128 length--; 129 } 130 ptr = str; 131 132 if (*ptr == '-' || *ptr == '+') { 133 ptr++; 134 } 135 136 if (ZEND_IS_DIGIT(*ptr)) { 137 /* Handle hex numbers 138 * str is used instead of ptr to disallow signs and keep old behavior */ 139 if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) { 140 base = 16; 141 ptr += 2; 142 } 143 144 /* Skip any leading 0s */ 145 while (*ptr == '0') { 146 ptr++; 147 } 148 149 /* Count the number of digits. If a decimal point/exponent is found, 150 * it's a double. Otherwise, if there's a dval or no need to check for 151 * a full match, stop when there are too many digits for a long */ 152 for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) { 153check_digits: 154 if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) { 155 continue; 156 } else if (base == 10) { 157 if (*ptr == '.' && dp_or_e < 1) { 158 goto process_double; 159 } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) { 160 const char *e = ptr + 1; 161 162 if (*e == '-' || *e == '+') { 163 ptr = e++; 164 } 165 if (ZEND_IS_DIGIT(*e)) { 166 goto process_double; 167 } 168 } 169 } 170 171 break; 172 } 173 174 if (base == 10) { 175 if (digits >= MAX_LENGTH_OF_LONG) { 176 if (oflow_info != NULL) { 177 *oflow_info = *str == '-' ? -1 : 1; 178 } 179 dp_or_e = -1; 180 goto process_double; 181 } 182 } else if (!(digits < SIZEOF_LONG * 2 || (digits == SIZEOF_LONG * 2 && ptr[-digits] <= '7'))) { 183 if (dval) { 184 local_dval = zend_hex_strtod(str, &ptr); 185 } 186 if (oflow_info != NULL) { 187 *oflow_info = 1; 188 } 189 type = IS_DOUBLE; 190 } 191 } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) { 192process_double: 193 type = IS_DOUBLE; 194 195 /* If there's a dval, do the conversion; else continue checking 196 * the digits if we need to check for a full match */ 197 if (dval) { 198 local_dval = zend_strtod(str, &ptr); 199 } else if (allow_errors != 1 && dp_or_e != -1) { 200 dp_or_e = (*ptr++ == '.') ? 1 : 2; 201 goto check_digits; 202 } 203 } else { 204 return 0; 205 } 206 207 if (ptr != str + length) { 208 if (!allow_errors) { 209 return 0; 210 } 211 if (allow_errors == -1) { 212 zend_error(E_NOTICE, "A non well formed numeric value encountered"); 213 } 214 } 215 216 if (type == IS_LONG) { 217 if (digits == MAX_LENGTH_OF_LONG - 1) { 218 int cmp = strcmp(&ptr[-digits], long_min_digits); 219 220 if (!(cmp < 0 || (cmp == 0 && *str == '-'))) { 221 if (dval) { 222 *dval = zend_strtod(str, NULL); 223 } 224 if (oflow_info != NULL) { 225 *oflow_info = *str == '-' ? -1 : 1; 226 } 227 228 return IS_DOUBLE; 229 } 230 } 231 232 if (lval) { 233 *lval = strtol(str, NULL, base); 234 } 235 236 return IS_LONG; 237 } else { 238 if (dval) { 239 *dval = local_dval; 240 } 241 242 return IS_DOUBLE; 243 } 244} 245 246static inline zend_uchar is_numeric_string(const char *str, int length, long *lval, double *dval, int allow_errors) { 247 return is_numeric_string_ex(str, length, lval, dval, allow_errors, NULL); 248} 249 250static inline char * 251zend_memnstr(char *haystack, char *needle, int needle_len, char *end) 252{ 253 char *p = haystack; 254 char ne = needle[needle_len-1]; 255 256 if (needle_len == 1) { 257 return (char *)memchr(p, *needle, (end-p)); 258 } 259 260 if (needle_len > end-haystack) { 261 return NULL; 262 } 263 264 end -= needle_len; 265 266 while (p <= end) { 267 if ((p = (char *)memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) { 268 if (!memcmp(needle, p, needle_len-1)) { 269 return p; 270 } 271 } 272 273 if (p == NULL) { 274 return NULL; 275 } 276 277 p++; 278 } 279 280 return NULL; 281} 282 283static inline const void *zend_memrchr(const void *s, int c, size_t n) 284{ 285 register const unsigned char *e; 286 287 if (n <= 0) { 288 return NULL; 289 } 290 291 for (e = (const unsigned char *)s + n - 1; e >= (const unsigned char *)s; e--) { 292 if (*e == (const unsigned char)c) { 293 return (const void *)e; 294 } 295 } 296 297 return NULL; 298} 299 300BEGIN_EXTERN_C() 301ZEND_API int increment_function(zval *op1); 302ZEND_API int decrement_function(zval *op2); 303 304ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC); 305ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC); 306ZEND_API void convert_to_long(zval *op); 307ZEND_API void convert_to_double(zval *op); 308ZEND_API void convert_to_long_base(zval *op, int base); 309ZEND_API void convert_to_null(zval *op); 310ZEND_API void convert_to_boolean(zval *op); 311ZEND_API void convert_to_array(zval *op); 312ZEND_API void convert_to_object(zval *op); 313ZEND_API void multi_convert_to_long_ex(int argc, ...); 314ZEND_API void multi_convert_to_double_ex(int argc, ...); 315ZEND_API void multi_convert_to_string_ex(int argc, ...); 316ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2); 317ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2); 318#define convert_to_string(op) if ((op)->type != IS_STRING) { _convert_to_string((op) ZEND_FILE_LINE_CC); } 319 320ZEND_API double zend_string_to_double(const char *number, zend_uint length); 321 322ZEND_API int zval_is_true(zval *op); 323ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 324ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 325ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC); 326ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 327ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 328#if HAVE_STRCOLL 329ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); 330#endif 331 332ZEND_API void zend_str_tolower(char *str, unsigned int length); 333ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length); 334ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length); 335 336ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2); 337ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3); 338ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2); 339ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3); 340ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint len2); 341ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint len2, uint length); 342ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, uint len2); 343ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, uint len2, uint length); 344 345ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2); 346ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC); 347ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC); 348ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC); 349 350ZEND_API int zend_atoi(const char *str, int str_len); 351ZEND_API long zend_atol(const char *str, int str_len); 352 353ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC); 354END_EXTERN_C() 355 356#define convert_to_ex_master(ppzv, lower_type, upper_type) \ 357 if (Z_TYPE_PP(ppzv)!=IS_##upper_type) { \ 358 SEPARATE_ZVAL_IF_NOT_REF(ppzv); \ 359 convert_to_##lower_type(*ppzv); \ 360 } 361 362#define convert_to_explicit_type(pzv, type) \ 363 do { \ 364 switch (type) { \ 365 case IS_NULL: \ 366 convert_to_null(pzv); \ 367 break; \ 368 case IS_LONG: \ 369 convert_to_long(pzv); \ 370 break; \ 371 case IS_DOUBLE: \ 372 convert_to_double(pzv); \ 373 break; \ 374 case IS_BOOL: \ 375 convert_to_boolean(pzv); \ 376 break; \ 377 case IS_ARRAY: \ 378 convert_to_array(pzv); \ 379 break; \ 380 case IS_OBJECT: \ 381 convert_to_object(pzv); \ 382 break; \ 383 case IS_STRING: \ 384 convert_to_string(pzv); \ 385 break; \ 386 default: \ 387 assert(0); \ 388 break; \ 389 } \ 390 } while (0); 391 392#define convert_to_explicit_type_ex(ppzv, str_type) \ 393 if (Z_TYPE_PP(ppzv) != str_type) { \ 394 SEPARATE_ZVAL_IF_NOT_REF(ppzv); \ 395 convert_to_explicit_type(*ppzv, str_type); \ 396 } 397 398#define convert_to_boolean_ex(ppzv) convert_to_ex_master(ppzv, boolean, BOOL) 399#define convert_to_long_ex(ppzv) convert_to_ex_master(ppzv, long, LONG) 400#define convert_to_double_ex(ppzv) convert_to_ex_master(ppzv, double, DOUBLE) 401#define convert_to_string_ex(ppzv) convert_to_ex_master(ppzv, string, STRING) 402#define convert_to_array_ex(ppzv) convert_to_ex_master(ppzv, array, ARRAY) 403#define convert_to_object_ex(ppzv) convert_to_ex_master(ppzv, object, OBJECT) 404#define convert_to_null_ex(ppzv) convert_to_ex_master(ppzv, null, NULL) 405 406#define convert_scalar_to_number_ex(ppzv) \ 407 if (Z_TYPE_PP(ppzv)!=IS_LONG && Z_TYPE_PP(ppzv)!=IS_DOUBLE) { \ 408 if (!Z_ISREF_PP(ppzv)) { \ 409 SEPARATE_ZVAL(ppzv); \ 410 } \ 411 convert_scalar_to_number(*ppzv TSRMLS_CC); \ 412 } 413 414 415#define Z_LVAL(zval) (zval).value.lval 416#define Z_BVAL(zval) ((zend_bool)(zval).value.lval) 417#define Z_DVAL(zval) (zval).value.dval 418#define Z_STRVAL(zval) (zval).value.str.val 419#define Z_STRLEN(zval) (zval).value.str.len 420#define Z_ARRVAL(zval) (zval).value.ht 421#define Z_OBJVAL(zval) (zval).value.obj 422#define Z_OBJ_HANDLE(zval) Z_OBJVAL(zval).handle 423#define Z_OBJ_HT(zval) Z_OBJVAL(zval).handlers 424#define Z_OBJCE(zval) zend_get_class_entry(&(zval) TSRMLS_CC) 425#define Z_OBJPROP(zval) Z_OBJ_HT((zval))->get_properties(&(zval) TSRMLS_CC) 426#define Z_OBJ_HANDLER(zval, hf) Z_OBJ_HT((zval))->hf 427#define Z_RESVAL(zval) (zval).value.lval 428#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)) 429 430#define Z_LVAL_P(zval_p) Z_LVAL(*zval_p) 431#define Z_BVAL_P(zval_p) Z_BVAL(*zval_p) 432#define Z_DVAL_P(zval_p) Z_DVAL(*zval_p) 433#define Z_STRVAL_P(zval_p) Z_STRVAL(*zval_p) 434#define Z_STRLEN_P(zval_p) Z_STRLEN(*zval_p) 435#define Z_ARRVAL_P(zval_p) Z_ARRVAL(*zval_p) 436#define Z_OBJPROP_P(zval_p) Z_OBJPROP(*zval_p) 437#define Z_OBJCE_P(zval_p) Z_OBJCE(*zval_p) 438#define Z_RESVAL_P(zval_p) Z_RESVAL(*zval_p) 439#define Z_OBJVAL_P(zval_p) Z_OBJVAL(*zval_p) 440#define Z_OBJ_HANDLE_P(zval_p) Z_OBJ_HANDLE(*zval_p) 441#define Z_OBJ_HT_P(zval_p) Z_OBJ_HT(*zval_p) 442#define Z_OBJ_HANDLER_P(zval_p, h) Z_OBJ_HANDLER(*zval_p, h) 443#define Z_OBJDEBUG_P(zval_p,is_tmp) Z_OBJDEBUG(*zval_p,is_tmp) 444 445#define Z_LVAL_PP(zval_pp) Z_LVAL(**zval_pp) 446#define Z_BVAL_PP(zval_pp) Z_BVAL(**zval_pp) 447#define Z_DVAL_PP(zval_pp) Z_DVAL(**zval_pp) 448#define Z_STRVAL_PP(zval_pp) Z_STRVAL(**zval_pp) 449#define Z_STRLEN_PP(zval_pp) Z_STRLEN(**zval_pp) 450#define Z_ARRVAL_PP(zval_pp) Z_ARRVAL(**zval_pp) 451#define Z_OBJPROP_PP(zval_pp) Z_OBJPROP(**zval_pp) 452#define Z_OBJCE_PP(zval_pp) Z_OBJCE(**zval_pp) 453#define Z_RESVAL_PP(zval_pp) Z_RESVAL(**zval_pp) 454#define Z_OBJVAL_PP(zval_pp) Z_OBJVAL(**zval_pp) 455#define Z_OBJ_HANDLE_PP(zval_p) Z_OBJ_HANDLE(**zval_p) 456#define Z_OBJ_HT_PP(zval_p) Z_OBJ_HT(**zval_p) 457#define Z_OBJ_HANDLER_PP(zval_p, h) Z_OBJ_HANDLER(**zval_p, h) 458#define Z_OBJDEBUG_PP(zval_pp,is_tmp) Z_OBJDEBUG(**zval_pp,is_tmp) 459 460#define Z_TYPE(zval) (zval).type 461#define Z_TYPE_P(zval_p) Z_TYPE(*zval_p) 462#define Z_TYPE_PP(zval_pp) Z_TYPE(**zval_pp) 463 464#if HAVE_SETLOCALE && defined(ZEND_WIN32) && !defined(ZTS) && defined(_MSC_VER) && (_MSC_VER >= 1400) 465/* This is performance improvement of tolower() on Windows and VC2005 466 * Gives 10-18% on bench.php 467 */ 468#define ZEND_USE_TOLOWER_L 1 469#endif 470 471#ifdef ZEND_USE_TOLOWER_L 472ZEND_API void zend_update_current_locale(void); 473#else 474#define zend_update_current_locale() 475#endif 476 477static zend_always_inline int fast_increment_function(zval *op1) 478{ 479 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { 480#if defined(__GNUC__) && defined(__i386__) 481 __asm__( 482 "incl (%0)\n\t" 483 "jno 0f\n\t" 484 "movl $0x0, (%0)\n\t" 485 "movl $0x41e00000, 0x4(%0)\n\t" 486 "movb $0x2,0xc(%0)\n" 487 "0:" 488 : 489 : "r"(op1)); 490#elif defined(__GNUC__) && defined(__x86_64__) 491 __asm__( 492 "incq (%0)\n\t" 493 "jno 0f\n\t" 494 "movl $0x0, (%0)\n\t" 495 "movl $0x43e00000, 0x4(%0)\n\t" 496 "movb $0x2,0x14(%0)\n" 497 "0:" 498 : 499 : "r"(op1)); 500#else 501 if (UNEXPECTED(Z_LVAL_P(op1) == LONG_MAX)) { 502 /* switch to double */ 503 Z_DVAL_P(op1) = (double)LONG_MAX + 1.0; 504 Z_TYPE_P(op1) = IS_DOUBLE; 505 } else { 506 Z_LVAL_P(op1)++; 507 } 508#endif 509 return SUCCESS; 510 } 511 return increment_function(op1); 512} 513 514static zend_always_inline int fast_decrement_function(zval *op1) 515{ 516 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { 517#if defined(__GNUC__) && defined(__i386__) 518 __asm__( 519 "decl (%0)\n\t" 520 "jno 0f\n\t" 521 "movl $0x00200000, (%0)\n\t" 522 "movl $0xc1e00000, 0x4(%0)\n\t" 523 "movb $0x2,0xc(%0)\n" 524 "0:" 525 : 526 : "r"(op1)); 527#elif defined(__GNUC__) && defined(__x86_64__) 528 __asm__( 529 "decq (%0)\n\t" 530 "jno 0f\n\t" 531 "movl $0x00000000, (%0)\n\t" 532 "movl $0xc3e00000, 0x4(%0)\n\t" 533 "movb $0x2,0x14(%0)\n" 534 "0:" 535 : 536 : "r"(op1)); 537#else 538 if (UNEXPECTED(Z_LVAL_P(op1) == LONG_MIN)) { 539 /* switch to double */ 540 Z_DVAL_P(op1) = (double)LONG_MIN - 1.0; 541 Z_TYPE_P(op1) = IS_DOUBLE; 542 } else { 543 Z_LVAL_P(op1)--; 544 } 545#endif 546 return SUCCESS; 547 } 548 return decrement_function(op1); 549} 550 551static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) 552{ 553 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { 554 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 555#if defined(__GNUC__) && defined(__i386__) 556 __asm__( 557 "movl (%1), %%eax\n\t" 558 "addl (%2), %%eax\n\t" 559 "jo 0f\n\t" 560 "movl %%eax, (%0)\n\t" 561 "movb $0x1,0xc(%0)\n\t" 562 "jmp 1f\n" 563 "0:\n\t" 564 "fildl (%1)\n\t" 565 "fildl (%2)\n\t" 566 "faddp %%st, %%st(1)\n\t" 567 "movb $0x2,0xc(%0)\n\t" 568 "fstpl (%0)\n" 569 "1:" 570 : 571 : "r"(result), 572 "r"(op1), 573 "r"(op2) 574 : "eax"); 575#elif defined(__GNUC__) && defined(__x86_64__) 576 __asm__( 577 "movq (%1), %%rax\n\t" 578 "addq (%2), %%rax\n\t" 579 "jo 0f\n\t" 580 "movq %%rax, (%0)\n\t" 581 "movb $0x1,0x14(%0)\n\t" 582 "jmp 1f\n" 583 "0:\n\t" 584 "fildq (%1)\n\t" 585 "fildq (%2)\n\t" 586 "faddp %%st, %%st(1)\n\t" 587 "movb $0x2,0x14(%0)\n\t" 588 "fstpl (%0)\n" 589 "1:" 590 : 591 : "r"(result), 592 "r"(op1), 593 "r"(op2) 594 : "rax"); 595#else 596 Z_LVAL_P(result) = Z_LVAL_P(op1) + Z_LVAL_P(op2); 597 598 if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK) 599 && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) { 600 Z_DVAL_P(result) = (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2); 601 Z_TYPE_P(result) = IS_DOUBLE; 602 } else { 603 Z_TYPE_P(result) = IS_LONG; 604 } 605#endif 606 return SUCCESS; 607 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 608 Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2); 609 Z_TYPE_P(result) = IS_DOUBLE; 610 return SUCCESS; 611 } 612 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { 613 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 614 Z_DVAL_P(result) = Z_DVAL_P(op1) + Z_DVAL_P(op2); 615 Z_TYPE_P(result) = IS_DOUBLE; 616 return SUCCESS; 617 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 618 Z_DVAL_P(result) = Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)); 619 Z_TYPE_P(result) = IS_DOUBLE; 620 return SUCCESS; 621 } 622 } 623 return add_function(result, op1, op2 TSRMLS_CC); 624} 625 626static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) 627{ 628 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { 629 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 630#if defined(__GNUC__) && defined(__i386__) 631 __asm__( 632 "movl (%1), %%eax\n\t" 633 "subl (%2), %%eax\n\t" 634 "jo 0f\n\t" 635 "movl %%eax, (%0)\n\t" 636 "movb $0x1,0xc(%0)\n\t" 637 "jmp 1f\n" 638 "0:\n\t" 639 "fildl (%2)\n\t" 640 "fildl (%1)\n\t" 641#if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10)) 642 "fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */ 643#else 644 "fsubp %%st, %%st(1)\n\t" 645#endif 646 "movb $0x2,0xc(%0)\n\t" 647 "fstpl (%0)\n" 648 "1:" 649 : 650 : "r"(result), 651 "r"(op1), 652 "r"(op2) 653 : "eax"); 654#elif defined(__GNUC__) && defined(__x86_64__) 655 __asm__( 656 "movq (%1), %%rax\n\t" 657 "subq (%2), %%rax\n\t" 658 "jo 0f\n\t" 659 "movq %%rax, (%0)\n\t" 660 "movb $0x1,0x14(%0)\n\t" 661 "jmp 1f\n" 662 "0:\n\t" 663 "fildq (%2)\n\t" 664 "fildq (%1)\n\t" 665#if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10)) 666 "fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */ 667#else 668 "fsubp %%st, %%st(1)\n\t" 669#endif 670 "movb $0x2,0x14(%0)\n\t" 671 "fstpl (%0)\n" 672 "1:" 673 : 674 : "r"(result), 675 "r"(op1), 676 "r"(op2) 677 : "rax"); 678#else 679 Z_LVAL_P(result) = Z_LVAL_P(op1) - Z_LVAL_P(op2); 680 681 if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK) 682 && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) { 683 Z_DVAL_P(result) = (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2); 684 Z_TYPE_P(result) = IS_DOUBLE; 685 } else { 686 Z_TYPE_P(result) = IS_LONG; 687 } 688#endif 689 return SUCCESS; 690 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 691 Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2); 692 Z_TYPE_P(result) = IS_DOUBLE; 693 return SUCCESS; 694 } 695 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { 696 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 697 Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2); 698 Z_TYPE_P(result) = IS_DOUBLE; 699 return SUCCESS; 700 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 701 Z_DVAL_P(result) = Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)); 702 Z_TYPE_P(result) = IS_DOUBLE; 703 return SUCCESS; 704 } 705 } 706 return sub_function(result, op1, op2 TSRMLS_CC); 707} 708 709static zend_always_inline int fast_mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) 710{ 711 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { 712 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 713 long overflow; 714 715 ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); 716 Z_TYPE_P(result) = overflow ? IS_DOUBLE : IS_LONG; 717 return SUCCESS; 718 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 719 Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2); 720 Z_TYPE_P(result) = IS_DOUBLE; 721 return SUCCESS; 722 } 723 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { 724 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 725 Z_DVAL_P(result) = Z_DVAL_P(op1) * Z_DVAL_P(op2); 726 Z_TYPE_P(result) = IS_DOUBLE; 727 return SUCCESS; 728 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 729 Z_DVAL_P(result) = Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)); 730 Z_TYPE_P(result) = IS_DOUBLE; 731 return SUCCESS; 732 } 733 } 734 return mul_function(result, op1, op2 TSRMLS_CC); 735} 736 737static zend_always_inline int fast_div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) 738{ 739 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && 0) { 740 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 741 if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { 742 zend_error(E_WARNING, "Division by zero"); 743 Z_LVAL_P(result) = 0; 744 Z_TYPE_P(result) = IS_BOOL; 745 return FAILURE; 746 } else if (UNEXPECTED(Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == LONG_MIN)) { 747 /* Prevent overflow error/crash */ 748 Z_DVAL_P(result) = (double) LONG_MIN / -1; 749 Z_TYPE_P(result) = IS_DOUBLE; 750 } else if (EXPECTED(Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0)) { 751 /* integer */ 752 Z_LVAL_P(result) = Z_LVAL_P(op1) / Z_LVAL_P(op2); 753 Z_TYPE_P(result) = IS_LONG; 754 } else { 755 Z_DVAL_P(result) = ((double) Z_LVAL_P(op1)) / ((double)Z_LVAL_P(op2)); 756 Z_TYPE_P(result) = IS_DOUBLE; 757 } 758 return SUCCESS; 759 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 760 if (UNEXPECTED(Z_DVAL_P(op2) == 0)) { 761 zend_error(E_WARNING, "Division by zero"); 762 Z_LVAL_P(result) = 0; 763 Z_TYPE_P(result) = IS_BOOL; 764 return FAILURE; 765 } 766 Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) / Z_DVAL_P(op2); 767 Z_TYPE_P(result) = IS_DOUBLE; 768 return SUCCESS; 769 } 770 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE) && 0) { 771 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 772 if (UNEXPECTED(Z_DVAL_P(op2) == 0)) { 773 zend_error(E_WARNING, "Division by zero"); 774 Z_LVAL_P(result) = 0; 775 Z_TYPE_P(result) = IS_BOOL; 776 return FAILURE; 777 } 778 Z_DVAL_P(result) = Z_DVAL_P(op1) / Z_DVAL_P(op2); 779 Z_TYPE_P(result) = IS_DOUBLE; 780 return SUCCESS; 781 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 782 if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { 783 zend_error(E_WARNING, "Division by zero"); 784 Z_LVAL_P(result) = 0; 785 Z_TYPE_P(result) = IS_BOOL; 786 return FAILURE; 787 } 788 Z_DVAL_P(result) = Z_DVAL_P(op1) / ((double)Z_LVAL_P(op2)); 789 Z_TYPE_P(result) = IS_DOUBLE; 790 return SUCCESS; 791 } 792 } 793 return div_function(result, op1, op2 TSRMLS_CC); 794} 795 796static zend_always_inline int fast_mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) 797{ 798 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { 799 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 800 if (UNEXPECTED(Z_LVAL_P(op2) == 0)) { 801 zend_error(E_WARNING, "Division by zero"); 802 Z_LVAL_P(result) = 0; 803 Z_TYPE_P(result) = IS_BOOL; 804 return FAILURE; 805 } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) { 806 /* Prevent overflow error/crash if op1==LONG_MIN */ 807 Z_LVAL_P(result) = 0; 808 Z_TYPE_P(result) = IS_LONG; 809 return SUCCESS; 810 } 811 Z_LVAL_P(result) = Z_LVAL_P(op1) % Z_LVAL_P(op2); 812 Z_TYPE_P(result) = IS_LONG; 813 return SUCCESS; 814 } 815 } 816 return mod_function(result, op1, op2 TSRMLS_CC); 817} 818 819static zend_always_inline int fast_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) 820{ 821 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { 822 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 823 return Z_LVAL_P(op1) == Z_LVAL_P(op2); 824 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 825 return ((double)Z_LVAL_P(op1)) == Z_DVAL_P(op2); 826 } 827 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { 828 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 829 return Z_DVAL_P(op1) == Z_DVAL_P(op2); 830 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 831 return Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2)); 832 } 833 } 834 compare_function(result, op1, op2 TSRMLS_CC); 835 return Z_LVAL_P(result) == 0; 836} 837 838static zend_always_inline int fast_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) 839{ 840 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { 841 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 842 return Z_LVAL_P(op1) != Z_LVAL_P(op2); 843 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 844 return ((double)Z_LVAL_P(op1)) != Z_DVAL_P(op2); 845 } 846 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { 847 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 848 return Z_DVAL_P(op1) != Z_DVAL_P(op2); 849 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 850 return Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2)); 851 } 852 } 853 compare_function(result, op1, op2 TSRMLS_CC); 854 return Z_LVAL_P(result) != 0; 855} 856 857static zend_always_inline int fast_is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) 858{ 859 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { 860 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 861 return Z_LVAL_P(op1) < Z_LVAL_P(op2); 862 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 863 return ((double)Z_LVAL_P(op1)) < Z_DVAL_P(op2); 864 } 865 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { 866 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 867 return Z_DVAL_P(op1) < Z_DVAL_P(op2); 868 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 869 return Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2)); 870 } 871 } 872 compare_function(result, op1, op2 TSRMLS_CC); 873 return Z_LVAL_P(result) < 0; 874} 875 876static zend_always_inline int fast_is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) 877{ 878 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { 879 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 880 return Z_LVAL_P(op1) <= Z_LVAL_P(op2); 881 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 882 return ((double)Z_LVAL_P(op1)) <= Z_DVAL_P(op2); 883 } 884 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { 885 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { 886 return Z_DVAL_P(op1) <= Z_DVAL_P(op2); 887 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { 888 return Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2)); 889 } 890 } 891 compare_function(result, op1, op2 TSRMLS_CC); 892 return Z_LVAL_P(result) <= 0; 893} 894 895#endif 896 897/* 898 * Local variables: 899 * tab-width: 4 900 * c-basic-offset: 4 901 * indent-tabs-mode: t 902 * End: 903 */ 904