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