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