Skip to content

Commit a35fbeb

Browse files
committed
Optimize zend_compare
1 parent 7de83e2 commit a35fbeb

File tree

1 file changed

+106
-100
lines changed

1 file changed

+106
-100
lines changed

Zend/zend_operators.c

+106-100
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static _locale_t current_locale = NULL;
5555
#define zend_tolower(c) tolower(c)
5656
#endif
5757

58-
#define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
58+
#define TYPE_PAIR(t1,t2) ((unsigned char) (((t1) << 4) | (t2)))
5959

6060
#ifdef ZEND_INTRIN_AVX2_NATIVE
6161
#define HAVE_BLOCKCONV
@@ -2169,131 +2169,137 @@ static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
21692169
}
21702170
/* }}} */
21712171

2172-
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
2173-
{
2174-
int converted = 0;
2175-
zval op1_copy, op2_copy;
2172+
static int ZEND_FASTCALL zend_compare_fast(zval *op1, zval *op2, bool converted);
21762173

2177-
while (1) {
2178-
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
2179-
case TYPE_PAIR(IS_LONG, IS_LONG):
2180-
return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
2174+
static int ZEND_FASTCALL zend_compare_slow(zval *op1, zval *op2, bool converted)
2175+
{
2176+
if (Z_ISREF_P(op1) || Z_ISREF_P(op2)) {
2177+
ZVAL_DEREF(op1);
2178+
ZVAL_DEREF(op2);
2179+
return zend_compare_fast(op1, op2, converted);
2180+
}
21812181

2182-
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2183-
return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - (double)Z_LVAL_P(op2));
2182+
if (Z_TYPE_P(op1) == IS_OBJECT
2183+
&& Z_TYPE_P(op2) == IS_OBJECT
2184+
&& Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
2185+
return 0;
2186+
} else if (Z_TYPE_P(op1) == IS_OBJECT) {
2187+
return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
2188+
} else if (Z_TYPE_P(op2) == IS_OBJECT) {
2189+
return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
2190+
}
2191+
2192+
if (!converted) {
2193+
if (Z_TYPE_P(op1) < IS_TRUE) {
2194+
return zval_is_true(op2) ? -1 : 0;
2195+
} else if (Z_TYPE_P(op1) == IS_TRUE) {
2196+
return zval_is_true(op2) ? 0 : 1;
2197+
} else if (Z_TYPE_P(op2) < IS_TRUE) {
2198+
return zval_is_true(op1) ? 1 : 0;
2199+
} else if (Z_TYPE_P(op2) == IS_TRUE) {
2200+
return zval_is_true(op1) ? 0 : -1;
2201+
} else {
2202+
zval op1_copy, op2_copy;
2203+
op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy);
2204+
op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy);
2205+
if (EG(exception)) {
2206+
return 1; /* to stop comparison of arrays */
2207+
}
2208+
return zend_compare_fast(op1, op2, true);
2209+
}
2210+
} else if (Z_TYPE_P(op1)==IS_ARRAY) {
2211+
return 1;
2212+
} else if (Z_TYPE_P(op2)==IS_ARRAY) {
2213+
return -1;
2214+
} else {
2215+
ZEND_UNREACHABLE();
2216+
zend_throw_error(NULL, "Unsupported operand types");
2217+
return 1;
2218+
}
2219+
}
21842220

2185-
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2186-
return ZEND_NORMALIZE_BOOL((double)Z_LVAL_P(op1) - Z_DVAL_P(op2));
2221+
static inline int ZEND_FASTCALL zend_compare_fast(zval *op1, zval *op2, bool converted)
2222+
{
2223+
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
2224+
case TYPE_PAIR(IS_LONG, IS_LONG):
2225+
return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
21872226

2188-
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2189-
if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
2190-
return 0;
2191-
} else {
2192-
return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - Z_DVAL_P(op2));
2193-
}
2227+
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2228+
return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - (double)Z_LVAL_P(op2));
21942229

2195-
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2196-
return zend_compare_arrays(op1, op2);
2230+
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2231+
return ZEND_NORMALIZE_BOOL((double)Z_LVAL_P(op1) - Z_DVAL_P(op2));
21972232

2198-
case TYPE_PAIR(IS_NULL, IS_NULL):
2199-
case TYPE_PAIR(IS_NULL, IS_FALSE):
2200-
case TYPE_PAIR(IS_FALSE, IS_NULL):
2201-
case TYPE_PAIR(IS_FALSE, IS_FALSE):
2202-
case TYPE_PAIR(IS_TRUE, IS_TRUE):
2233+
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2234+
if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
22032235
return 0;
2236+
} else {
2237+
return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - Z_DVAL_P(op2));
2238+
}
22042239

2205-
case TYPE_PAIR(IS_NULL, IS_TRUE):
2206-
return -1;
2240+
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2241+
return zend_compare_arrays(op1, op2);
22072242

2208-
case TYPE_PAIR(IS_TRUE, IS_NULL):
2209-
return 1;
2243+
case TYPE_PAIR(IS_NULL, IS_NULL):
2244+
case TYPE_PAIR(IS_NULL, IS_FALSE):
2245+
case TYPE_PAIR(IS_FALSE, IS_NULL):
2246+
case TYPE_PAIR(IS_FALSE, IS_FALSE):
2247+
case TYPE_PAIR(IS_TRUE, IS_TRUE):
2248+
return 0;
22102249

2211-
case TYPE_PAIR(IS_STRING, IS_STRING):
2212-
if (Z_STR_P(op1) == Z_STR_P(op2)) {
2213-
return 0;
2214-
}
2215-
return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
2250+
case TYPE_PAIR(IS_NULL, IS_TRUE):
2251+
return -1;
22162252

2217-
case TYPE_PAIR(IS_NULL, IS_STRING):
2218-
return Z_STRLEN_P(op2) == 0 ? 0 : -1;
2253+
case TYPE_PAIR(IS_TRUE, IS_NULL):
2254+
return 1;
22192255

2220-
case TYPE_PAIR(IS_STRING, IS_NULL):
2221-
return Z_STRLEN_P(op1) == 0 ? 0 : 1;
2256+
case TYPE_PAIR(IS_STRING, IS_STRING):
2257+
if (Z_STR_P(op1) == Z_STR_P(op2)) {
2258+
return 0;
2259+
}
2260+
return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
22222261

2223-
case TYPE_PAIR(IS_LONG, IS_STRING):
2224-
return compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2));
2262+
case TYPE_PAIR(IS_NULL, IS_STRING):
2263+
return Z_STRLEN_P(op2) == 0 ? 0 : -1;
22252264

2226-
case TYPE_PAIR(IS_STRING, IS_LONG):
2227-
return -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1));
2265+
case TYPE_PAIR(IS_STRING, IS_NULL):
2266+
return Z_STRLEN_P(op1) == 0 ? 0 : 1;
22282267

2229-
case TYPE_PAIR(IS_DOUBLE, IS_STRING):
2230-
if (zend_isnan(Z_DVAL_P(op1))) {
2231-
return 1;
2232-
}
2268+
case TYPE_PAIR(IS_LONG, IS_STRING):
2269+
return compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2));
22332270

2234-
return compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2));
2271+
case TYPE_PAIR(IS_STRING, IS_LONG):
2272+
return -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1));
22352273

2236-
case TYPE_PAIR(IS_STRING, IS_DOUBLE):
2237-
if (zend_isnan(Z_DVAL_P(op2))) {
2238-
return 1;
2239-
}
2274+
case TYPE_PAIR(IS_DOUBLE, IS_STRING):
2275+
if (zend_isnan(Z_DVAL_P(op1))) {
2276+
return 1;
2277+
}
22402278

2241-
return -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1));
2279+
return compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2));
22422280

2243-
case TYPE_PAIR(IS_OBJECT, IS_NULL):
2281+
case TYPE_PAIR(IS_STRING, IS_DOUBLE):
2282+
if (zend_isnan(Z_DVAL_P(op2))) {
22442283
return 1;
2284+
}
22452285

2246-
case TYPE_PAIR(IS_NULL, IS_OBJECT):
2247-
return -1;
2286+
return -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1));
22482287

2249-
default:
2250-
if (Z_ISREF_P(op1)) {
2251-
op1 = Z_REFVAL_P(op1);
2252-
continue;
2253-
} else if (Z_ISREF_P(op2)) {
2254-
op2 = Z_REFVAL_P(op2);
2255-
continue;
2256-
}
2288+
case TYPE_PAIR(IS_OBJECT, IS_NULL):
2289+
return 1;
22572290

2258-
if (Z_TYPE_P(op1) == IS_OBJECT
2259-
&& Z_TYPE_P(op2) == IS_OBJECT
2260-
&& Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
2261-
return 0;
2262-
} else if (Z_TYPE_P(op1) == IS_OBJECT) {
2263-
return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
2264-
} else if (Z_TYPE_P(op2) == IS_OBJECT) {
2265-
return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
2266-
}
2291+
case TYPE_PAIR(IS_NULL, IS_OBJECT):
2292+
return -1;
22672293

2268-
if (!converted) {
2269-
if (Z_TYPE_P(op1) < IS_TRUE) {
2270-
return zval_is_true(op2) ? -1 : 0;
2271-
} else if (Z_TYPE_P(op1) == IS_TRUE) {
2272-
return zval_is_true(op2) ? 0 : 1;
2273-
} else if (Z_TYPE_P(op2) < IS_TRUE) {
2274-
return zval_is_true(op1) ? 1 : 0;
2275-
} else if (Z_TYPE_P(op2) == IS_TRUE) {
2276-
return zval_is_true(op1) ? 0 : -1;
2277-
} else {
2278-
op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy);
2279-
op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy);
2280-
if (EG(exception)) {
2281-
return 1; /* to stop comparison of arrays */
2282-
}
2283-
converted = 1;
2284-
}
2285-
} else if (Z_TYPE_P(op1)==IS_ARRAY) {
2286-
return 1;
2287-
} else if (Z_TYPE_P(op2)==IS_ARRAY) {
2288-
return -1;
2289-
} else {
2290-
ZEND_UNREACHABLE();
2291-
zend_throw_error(NULL, "Unsupported operand types");
2292-
return 1;
2293-
}
2294-
}
2294+
default:
2295+
return zend_compare_slow(op1, op2, converted);
22952296
}
22962297
}
2298+
2299+
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
2300+
{
2301+
return zend_compare_fast(op1, op2, false);
2302+
}
22972303
/* }}} */
22982304

22992305
/* return int to be compatible with compare_func_t */

0 commit comments

Comments
 (0)