1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2014 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
42 BEGIN_EXTERN_C()
43 ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
44 ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
45 ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
46 ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
47 ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
48 ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
49 ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC);
50 ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC);
51 ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
52 ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
53 ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
54 ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
55 ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
56 ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
57
58 ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
59 ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
60 ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
61 ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
62 ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
63 ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
64
65 ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC);
66 ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC);
END_EXTERN_C()67 END_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)
72 static 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
80 static 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 */
109 static 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++) {
153 check_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])) {
192 process_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
is_numeric_string(const char * str,int length,long * lval,double * dval,int allow_errors)246 static 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
250 static inline char *
zend_memnstr(char * haystack,char * needle,int needle_len,char * end)251 zend_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
zend_memrchr(const void * s,int c,size_t n)283 static 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
300 BEGIN_EXTERN_C()
301 ZEND_API int increment_function(zval *op1);
302 ZEND_API int decrement_function(zval *op2);
303
304 ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC);
305 ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC);
306 ZEND_API void convert_to_long(zval *op);
307 ZEND_API void convert_to_double(zval *op);
308 ZEND_API void convert_to_long_base(zval *op, int base);
309 ZEND_API void convert_to_null(zval *op);
310 ZEND_API void convert_to_boolean(zval *op);
311 ZEND_API void convert_to_array(zval *op);
312 ZEND_API void convert_to_object(zval *op);
313 ZEND_API void multi_convert_to_long_ex(int argc, ...);
314 ZEND_API void multi_convert_to_double_ex(int argc, ...);
315 ZEND_API void multi_convert_to_string_ex(int argc, ...);
316 ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2);
317 ZEND_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
320 ZEND_API double zend_string_to_double(const char *number, zend_uint length);
321
322 ZEND_API int zval_is_true(zval *op);
323 ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
324 ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
325 ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC);
326 ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
327 ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
328 #if HAVE_STRCOLL
329 ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
330 #endif
331
332 ZEND_API void zend_str_tolower(char *str, unsigned int length);
333 ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length);
334 ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length);
335
336 ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2);
337 ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3);
338 ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2);
339 ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3);
340 ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint len2);
341 ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint len2, uint length);
342 ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, uint len2);
343 ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, uint len2, uint length);
344
345 ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2);
346 ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC);
347 ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC);
348 ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC);
349
350 ZEND_API int zend_atoi(const char *str, int str_len);
351 ZEND_API long zend_atol(const char *str, int str_len);
352
353 ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC);
354 END_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
472 ZEND_API void zend_update_current_locale(void);
473 #else
474 #define zend_update_current_locale()
475 #endif
476
fast_increment_function(zval * op1)477 static 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
fast_decrement_function(zval * op1)514 static 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
fast_add_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)551 static 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 /*
597 * 'result' may alias with op1 or op2, so we need to
598 * ensure that 'result' is not updated until after we
599 * have read the values of op1 and op2.
600 */
601
602 if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
603 && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) {
604 Z_DVAL_P(result) = (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2);
605 Z_TYPE_P(result) = IS_DOUBLE;
606 } else {
607 Z_LVAL_P(result) = Z_LVAL_P(op1) + Z_LVAL_P(op2);
608 Z_TYPE_P(result) = IS_LONG;
609 }
610 #endif
611 return SUCCESS;
612 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
613 Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2);
614 Z_TYPE_P(result) = IS_DOUBLE;
615 return SUCCESS;
616 }
617 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
618 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
619 Z_DVAL_P(result) = Z_DVAL_P(op1) + Z_DVAL_P(op2);
620 Z_TYPE_P(result) = IS_DOUBLE;
621 return SUCCESS;
622 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
623 Z_DVAL_P(result) = Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2));
624 Z_TYPE_P(result) = IS_DOUBLE;
625 return SUCCESS;
626 }
627 }
628 return add_function(result, op1, op2 TSRMLS_CC);
629 }
630
fast_sub_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)631 static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
632 {
633 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
634 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
635 #if defined(__GNUC__) && defined(__i386__)
636 __asm__(
637 "movl (%1), %%eax\n\t"
638 "subl (%2), %%eax\n\t"
639 "jo 0f\n\t"
640 "movl %%eax, (%0)\n\t"
641 "movb $0x1,0xc(%0)\n\t"
642 "jmp 1f\n"
643 "0:\n\t"
644 "fildl (%2)\n\t"
645 "fildl (%1)\n\t"
646 #if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10))
647 "fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */
648 #else
649 "fsubp %%st, %%st(1)\n\t"
650 #endif
651 "movb $0x2,0xc(%0)\n\t"
652 "fstpl (%0)\n"
653 "1:"
654 :
655 : "r"(result),
656 "r"(op1),
657 "r"(op2)
658 : "eax");
659 #elif defined(__GNUC__) && defined(__x86_64__)
660 __asm__(
661 "movq (%1), %%rax\n\t"
662 "subq (%2), %%rax\n\t"
663 "jo 0f\n\t"
664 "movq %%rax, (%0)\n\t"
665 "movb $0x1,0x14(%0)\n\t"
666 "jmp 1f\n"
667 "0:\n\t"
668 "fildq (%2)\n\t"
669 "fildq (%1)\n\t"
670 #if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10))
671 "fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */
672 #else
673 "fsubp %%st, %%st(1)\n\t"
674 #endif
675 "movb $0x2,0x14(%0)\n\t"
676 "fstpl (%0)\n"
677 "1:"
678 :
679 : "r"(result),
680 "r"(op1),
681 "r"(op2)
682 : "rax");
683 #else
684 Z_LVAL_P(result) = Z_LVAL_P(op1) - Z_LVAL_P(op2);
685
686 if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK)
687 && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) {
688 Z_DVAL_P(result) = (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2);
689 Z_TYPE_P(result) = IS_DOUBLE;
690 } else {
691 Z_TYPE_P(result) = IS_LONG;
692 }
693 #endif
694 return SUCCESS;
695 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
696 Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2);
697 Z_TYPE_P(result) = IS_DOUBLE;
698 return SUCCESS;
699 }
700 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
701 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
702 Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
703 Z_TYPE_P(result) = IS_DOUBLE;
704 return SUCCESS;
705 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
706 Z_DVAL_P(result) = Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2));
707 Z_TYPE_P(result) = IS_DOUBLE;
708 return SUCCESS;
709 }
710 }
711 return sub_function(result, op1, op2 TSRMLS_CC);
712 }
713
fast_mul_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)714 static zend_always_inline int fast_mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
715 {
716 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
717 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
718 long overflow;
719
720 ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow);
721 Z_TYPE_P(result) = overflow ? IS_DOUBLE : IS_LONG;
722 return SUCCESS;
723 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
724 Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2);
725 Z_TYPE_P(result) = IS_DOUBLE;
726 return SUCCESS;
727 }
728 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
729 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
730 Z_DVAL_P(result) = Z_DVAL_P(op1) * Z_DVAL_P(op2);
731 Z_TYPE_P(result) = IS_DOUBLE;
732 return SUCCESS;
733 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
734 Z_DVAL_P(result) = Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2));
735 Z_TYPE_P(result) = IS_DOUBLE;
736 return SUCCESS;
737 }
738 }
739 return mul_function(result, op1, op2 TSRMLS_CC);
740 }
741
fast_div_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)742 static zend_always_inline int fast_div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
743 {
744 #if 0
745 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && 0) {
746 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
747 if (UNEXPECTED(Z_LVAL_P(op2) == 0)) {
748 zend_error(E_WARNING, "Division by zero");
749 Z_LVAL_P(result) = 0;
750 Z_TYPE_P(result) = IS_BOOL;
751 return FAILURE;
752 } else if (UNEXPECTED(Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == LONG_MIN)) {
753 /* Prevent overflow error/crash */
754 Z_DVAL_P(result) = (double) LONG_MIN / -1;
755 Z_TYPE_P(result) = IS_DOUBLE;
756 } else if (EXPECTED(Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0)) {
757 /* integer */
758 Z_LVAL_P(result) = Z_LVAL_P(op1) / Z_LVAL_P(op2);
759 Z_TYPE_P(result) = IS_LONG;
760 } else {
761 Z_DVAL_P(result) = ((double) Z_LVAL_P(op1)) / ((double)Z_LVAL_P(op2));
762 Z_TYPE_P(result) = IS_DOUBLE;
763 }
764 return SUCCESS;
765 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
766 if (UNEXPECTED(Z_DVAL_P(op2) == 0)) {
767 zend_error(E_WARNING, "Division by zero");
768 Z_LVAL_P(result) = 0;
769 Z_TYPE_P(result) = IS_BOOL;
770 return FAILURE;
771 }
772 Z_DVAL_P(result) = ((double)Z_LVAL_P(op1)) / Z_DVAL_P(op2);
773 Z_TYPE_P(result) = IS_DOUBLE;
774 return SUCCESS;
775 }
776 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE) && 0) {
777 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
778 if (UNEXPECTED(Z_DVAL_P(op2) == 0)) {
779 zend_error(E_WARNING, "Division by zero");
780 Z_LVAL_P(result) = 0;
781 Z_TYPE_P(result) = IS_BOOL;
782 return FAILURE;
783 }
784 Z_DVAL_P(result) = Z_DVAL_P(op1) / Z_DVAL_P(op2);
785 Z_TYPE_P(result) = IS_DOUBLE;
786 return SUCCESS;
787 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
788 if (UNEXPECTED(Z_LVAL_P(op2) == 0)) {
789 zend_error(E_WARNING, "Division by zero");
790 Z_LVAL_P(result) = 0;
791 Z_TYPE_P(result) = IS_BOOL;
792 return FAILURE;
793 }
794 Z_DVAL_P(result) = Z_DVAL_P(op1) / ((double)Z_LVAL_P(op2));
795 Z_TYPE_P(result) = IS_DOUBLE;
796 return SUCCESS;
797 }
798 }
799 #endif
800 return div_function(result, op1, op2 TSRMLS_CC);
801 }
802
fast_mod_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)803 static zend_always_inline int fast_mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
804 {
805 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
806 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
807 if (UNEXPECTED(Z_LVAL_P(op2) == 0)) {
808 zend_error(E_WARNING, "Division by zero");
809 Z_LVAL_P(result) = 0;
810 Z_TYPE_P(result) = IS_BOOL;
811 return FAILURE;
812 } else if (UNEXPECTED(Z_LVAL_P(op2) == -1)) {
813 /* Prevent overflow error/crash if op1==LONG_MIN */
814 Z_LVAL_P(result) = 0;
815 Z_TYPE_P(result) = IS_LONG;
816 return SUCCESS;
817 }
818 Z_LVAL_P(result) = Z_LVAL_P(op1) % Z_LVAL_P(op2);
819 Z_TYPE_P(result) = IS_LONG;
820 return SUCCESS;
821 }
822 }
823 return mod_function(result, op1, op2 TSRMLS_CC);
824 }
825
fast_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)826 static zend_always_inline int fast_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
827 {
828 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
829 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
830 return Z_LVAL_P(op1) == Z_LVAL_P(op2);
831 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
832 return ((double)Z_LVAL_P(op1)) == Z_DVAL_P(op2);
833 }
834 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
835 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
836 return Z_DVAL_P(op1) == Z_DVAL_P(op2);
837 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
838 return Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2));
839 }
840 }
841 compare_function(result, op1, op2 TSRMLS_CC);
842 return Z_LVAL_P(result) == 0;
843 }
844
fast_not_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)845 static zend_always_inline int fast_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
846 {
847 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
848 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
849 return Z_LVAL_P(op1) != Z_LVAL_P(op2);
850 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
851 return ((double)Z_LVAL_P(op1)) != Z_DVAL_P(op2);
852 }
853 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
854 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
855 return Z_DVAL_P(op1) != Z_DVAL_P(op2);
856 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
857 return Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2));
858 }
859 }
860 compare_function(result, op1, op2 TSRMLS_CC);
861 return Z_LVAL_P(result) != 0;
862 }
863
fast_is_smaller_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)864 static zend_always_inline int fast_is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
865 {
866 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
867 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
868 return Z_LVAL_P(op1) < Z_LVAL_P(op2);
869 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
870 return ((double)Z_LVAL_P(op1)) < Z_DVAL_P(op2);
871 }
872 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
873 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
874 return Z_DVAL_P(op1) < Z_DVAL_P(op2);
875 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
876 return Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2));
877 }
878 }
879 compare_function(result, op1, op2 TSRMLS_CC);
880 return Z_LVAL_P(result) < 0;
881 }
882
fast_is_smaller_or_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)883 static zend_always_inline int fast_is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
884 {
885 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
886 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
887 return Z_LVAL_P(op1) <= Z_LVAL_P(op2);
888 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
889 return ((double)Z_LVAL_P(op1)) <= Z_DVAL_P(op2);
890 }
891 } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
892 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
893 return Z_DVAL_P(op1) <= Z_DVAL_P(op2);
894 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
895 return Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2));
896 }
897 }
898 compare_function(result, op1, op2 TSRMLS_CC);
899 return Z_LVAL_P(result) <= 0;
900 }
901
902 #endif
903
904 /*
905 * Local variables:
906 * tab-width: 4
907 * c-basic-offset: 4
908 * indent-tabs-mode: t
909 * End:
910 */
911