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