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