Annotation of embedaddon/php/Zend/zend_operators.h, revision 1.1.1.4
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | Zend Engine |
4: +----------------------------------------------------------------------+
1.1.1.4 ! misho 5: | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
1.1 misho 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: {
1.1.1.3 misho 82: /* >= as (double)LONG_MAX is outside signed range */
83: if (d >= LONG_MAX) {
1.1 misho 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.
1.1.1.3 misho 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.
1.1 misho 108: */
1.1.1.3 misho 109: static inline zend_uchar is_numeric_string_ex(const char *str, int length, long *lval, double *dval, int allow_errors, int *oflow_info)
1.1 misho 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:
1.1.1.3 misho 120: if (oflow_info != NULL) {
121: *oflow_info = 0;
122: }
123:
1.1 misho 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) {
1.1.1.3 misho 176: if (oflow_info != NULL) {
177: *oflow_info = *str == '-' ? -1 : 1;
178: }
1.1 misho 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) {
1.1.1.2 misho 184: local_dval = zend_hex_strtod(str, &ptr);
1.1 misho 185: }
1.1.1.3 misho 186: if (oflow_info != NULL) {
187: *oflow_info = 1;
188: }
1.1 misho 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) {
1.1.1.2 misho 198: local_dval = zend_strtod(str, &ptr);
1.1 misho 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: }
1.1.1.3 misho 224: if (oflow_info != NULL) {
225: *oflow_info = *str == '-' ? -1 : 1;
226: }
1.1 misho 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:
1.1.1.3 misho 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:
1.1 misho 250: static inline char *
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:
1.1.1.2 misho 283: static inline const void *zend_memrchr(const void *s, int c, size_t n)
1.1 misho 284: {
1.1.1.2 misho 285: register const unsigned char *e;
1.1 misho 286:
287: if (n <= 0) {
288: return NULL;
289: }
290:
1.1.1.2 misho 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;
1.1 misho 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);
1.1.1.2 misho 325: ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC);
1.1 misho 326: ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
1.1.1.2 misho 327: ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
1.1 misho 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:
1.1.1.2 misho 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:
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:
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
1.1.1.4 ! misho 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: */
1.1.1.2 misho 601:
602: if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
1.1.1.4 ! misho 603: && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) {
1.1.1.2 misho 604: Z_DVAL_P(result) = (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2);
605: Z_TYPE_P(result) = IS_DOUBLE;
606: } else {
1.1.1.4 ! misho 607: Z_LVAL_P(result) = Z_LVAL_P(op1) + Z_LVAL_P(op2);
1.1.1.2 misho 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:
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:
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:
742: static zend_always_inline int fast_div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
743: {
1.1.1.4 ! misho 744: #if 0
1.1.1.2 misho 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: }
1.1.1.4 ! misho 799: #endif
1.1.1.2 misho 800: return div_function(result, op1, op2 TSRMLS_CC);
801: }
802:
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:
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:
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:
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:
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:
1.1 misho 902: #endif
903:
904: /*
905: * Local variables:
906: * tab-width: 4
907: * c-basic-offset: 4
908: * indent-tabs-mode: t
909: * End:
910: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>