Skip to content

Commit 5209b2e

Browse files
committed
Optimize zend_compare
1 parent dda6b8f commit 5209b2e

File tree

1 file changed

+104
-99
lines changed

1 file changed

+104
-99
lines changed

Zend/zend_operators.c

Lines changed: 104 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static _locale_t current_locale = NULL;
5858
#define zend_tolower(c) tolower(c)
5959
#endif
6060

61-
#define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
61+
#define TYPE_PAIR(t1,t2) ((unsigned char) (((t1) << 4) | (t2)))
6262

6363
#ifdef ZEND_INTRIN_AVX2_NATIVE
6464
#define HAVE_BLOCKCONV
@@ -2235,127 +2235,133 @@ static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
22352235
}
22362236
/* }}} */
22372237

2238-
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
2238+
static int ZEND_FASTCALL zend_compare_fast(zval *op1, zval *op2, bool converted);
2239+
2240+
static int ZEND_FASTCALL zend_compare_slow(zval *op1, zval *op2, bool converted)
22392241
{
2240-
int converted = 0;
2241-
zval op1_copy, op2_copy;
2242+
if (Z_ISREF_P(op1) || Z_ISREF_P(op2)) {
2243+
ZVAL_DEREF(op1);
2244+
ZVAL_DEREF(op2);
2245+
return zend_compare_fast(op1, op2, converted);
2246+
}
22422247

2243-
while (1) {
2244-
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
2245-
case TYPE_PAIR(IS_LONG, IS_LONG):
2246-
return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
2248+
if (Z_TYPE_P(op1) == IS_OBJECT
2249+
&& Z_TYPE_P(op2) == IS_OBJECT
2250+
&& Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
2251+
return 0;
2252+
} else if (Z_TYPE_P(op1) == IS_OBJECT) {
2253+
return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
2254+
} else if (Z_TYPE_P(op2) == IS_OBJECT) {
2255+
return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
2256+
}
2257+
2258+
if (!converted) {
2259+
if (Z_TYPE_P(op1) < IS_TRUE) {
2260+
return zval_is_true(op2) ? -1 : 0;
2261+
} else if (Z_TYPE_P(op1) == IS_TRUE) {
2262+
return zval_is_true(op2) ? 0 : 1;
2263+
} else if (Z_TYPE_P(op2) < IS_TRUE) {
2264+
return zval_is_true(op1) ? 1 : 0;
2265+
} else if (Z_TYPE_P(op2) == IS_TRUE) {
2266+
return zval_is_true(op1) ? 0 : -1;
2267+
} else {
2268+
zval op1_copy, op2_copy;
2269+
op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy);
2270+
op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy);
2271+
if (EG(exception)) {
2272+
return 1; /* to stop comparison of arrays */
2273+
}
2274+
return zend_compare_fast(op1, op2, true);
2275+
}
2276+
} else if (Z_TYPE_P(op1)==IS_ARRAY) {
2277+
return 1;
2278+
} else if (Z_TYPE_P(op2)==IS_ARRAY) {
2279+
return -1;
2280+
} else {
2281+
ZEND_UNREACHABLE();
2282+
zend_throw_error(NULL, "Unsupported operand types");
2283+
return 1;
2284+
}
2285+
}
22472286

2248-
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2249-
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), (double)Z_LVAL_P(op2));
2287+
static inline int ZEND_FASTCALL zend_compare_fast(zval *op1, zval *op2, bool converted)
2288+
{
2289+
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
2290+
case TYPE_PAIR(IS_LONG, IS_LONG):
2291+
return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
22502292

2251-
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2252-
return ZEND_THREEWAY_COMPARE((double)Z_LVAL_P(op1), Z_DVAL_P(op2));
2293+
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2294+
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), (double)Z_LVAL_P(op2));
22532295

2254-
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2255-
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), Z_DVAL_P(op2));
2296+
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2297+
return ZEND_THREEWAY_COMPARE((double)Z_LVAL_P(op1), Z_DVAL_P(op2));
22562298

2257-
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2258-
return zend_compare_arrays(op1, op2);
2299+
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2300+
return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), Z_DVAL_P(op2));
22592301

2260-
case TYPE_PAIR(IS_NULL, IS_NULL):
2261-
case TYPE_PAIR(IS_NULL, IS_FALSE):
2262-
case TYPE_PAIR(IS_FALSE, IS_NULL):
2263-
case TYPE_PAIR(IS_FALSE, IS_FALSE):
2264-
case TYPE_PAIR(IS_TRUE, IS_TRUE):
2265-
return 0;
2302+
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2303+
return zend_compare_arrays(op1, op2);
22662304

2267-
case TYPE_PAIR(IS_NULL, IS_TRUE):
2268-
return -1;
2305+
case TYPE_PAIR(IS_NULL, IS_NULL):
2306+
case TYPE_PAIR(IS_NULL, IS_FALSE):
2307+
case TYPE_PAIR(IS_FALSE, IS_NULL):
2308+
case TYPE_PAIR(IS_FALSE, IS_FALSE):
2309+
case TYPE_PAIR(IS_TRUE, IS_TRUE):
2310+
return 0;
22692311

2270-
case TYPE_PAIR(IS_TRUE, IS_NULL):
2271-
return 1;
2312+
case TYPE_PAIR(IS_NULL, IS_TRUE):
2313+
return -1;
22722314

2273-
case TYPE_PAIR(IS_STRING, IS_STRING):
2274-
if (Z_STR_P(op1) == Z_STR_P(op2)) {
2275-
return 0;
2276-
}
2277-
return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
2315+
case TYPE_PAIR(IS_TRUE, IS_NULL):
2316+
return 1;
22782317

2279-
case TYPE_PAIR(IS_NULL, IS_STRING):
2280-
return Z_STRLEN_P(op2) == 0 ? 0 : -1;
2318+
case TYPE_PAIR(IS_STRING, IS_STRING):
2319+
if (Z_STR_P(op1) == Z_STR_P(op2)) {
2320+
return 0;
2321+
}
2322+
return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
22812323

2282-
case TYPE_PAIR(IS_STRING, IS_NULL):
2283-
return Z_STRLEN_P(op1) == 0 ? 0 : 1;
2324+
case TYPE_PAIR(IS_NULL, IS_STRING):
2325+
return Z_STRLEN_P(op2) == 0 ? 0 : -1;
22842326

2285-
case TYPE_PAIR(IS_LONG, IS_STRING):
2286-
return compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2));
2327+
case TYPE_PAIR(IS_STRING, IS_NULL):
2328+
return Z_STRLEN_P(op1) == 0 ? 0 : 1;
22872329

2288-
case TYPE_PAIR(IS_STRING, IS_LONG):
2289-
return -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1));
2330+
case TYPE_PAIR(IS_LONG, IS_STRING):
2331+
return compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2));
22902332

2291-
case TYPE_PAIR(IS_DOUBLE, IS_STRING):
2292-
if (zend_isnan(Z_DVAL_P(op1))) {
2293-
return 1;
2294-
}
2333+
case TYPE_PAIR(IS_STRING, IS_LONG):
2334+
return -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1));
22952335

2296-
return compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2));
2297-
2298-
case TYPE_PAIR(IS_STRING, IS_DOUBLE):
2299-
if (zend_isnan(Z_DVAL_P(op2))) {
2300-
return 1;
2301-
}
2336+
case TYPE_PAIR(IS_DOUBLE, IS_STRING):
2337+
if (zend_isnan(Z_DVAL_P(op1))) {
2338+
return 1;
2339+
}
23022340

2303-
return -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1));
2341+
return compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2));
23042342

2305-
case TYPE_PAIR(IS_OBJECT, IS_NULL):
2343+
case TYPE_PAIR(IS_STRING, IS_DOUBLE):
2344+
if (zend_isnan(Z_DVAL_P(op2))) {
23062345
return 1;
2346+
}
23072347

2308-
case TYPE_PAIR(IS_NULL, IS_OBJECT):
2309-
return -1;
2348+
return -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1));
23102349

2311-
default:
2312-
if (Z_ISREF_P(op1)) {
2313-
op1 = Z_REFVAL_P(op1);
2314-
continue;
2315-
} else if (Z_ISREF_P(op2)) {
2316-
op2 = Z_REFVAL_P(op2);
2317-
continue;
2318-
}
2350+
case TYPE_PAIR(IS_OBJECT, IS_NULL):
2351+
return 1;
23192352

2320-
if (Z_TYPE_P(op1) == IS_OBJECT
2321-
&& Z_TYPE_P(op2) == IS_OBJECT
2322-
&& Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
2323-
return 0;
2324-
} else if (Z_TYPE_P(op1) == IS_OBJECT) {
2325-
return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
2326-
} else if (Z_TYPE_P(op2) == IS_OBJECT) {
2327-
return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
2328-
}
2353+
case TYPE_PAIR(IS_NULL, IS_OBJECT):
2354+
return -1;
23292355

2330-
if (!converted) {
2331-
if (Z_TYPE_P(op1) < IS_TRUE) {
2332-
return zval_is_true(op2) ? -1 : 0;
2333-
} else if (Z_TYPE_P(op1) == IS_TRUE) {
2334-
return zval_is_true(op2) ? 0 : 1;
2335-
} else if (Z_TYPE_P(op2) < IS_TRUE) {
2336-
return zval_is_true(op1) ? 1 : 0;
2337-
} else if (Z_TYPE_P(op2) == IS_TRUE) {
2338-
return zval_is_true(op1) ? 0 : -1;
2339-
} else {
2340-
op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy);
2341-
op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy);
2342-
if (EG(exception)) {
2343-
return 1; /* to stop comparison of arrays */
2344-
}
2345-
converted = 1;
2346-
}
2347-
} else if (Z_TYPE_P(op1)==IS_ARRAY) {
2348-
return 1;
2349-
} else if (Z_TYPE_P(op2)==IS_ARRAY) {
2350-
return -1;
2351-
} else {
2352-
ZEND_UNREACHABLE();
2353-
zend_throw_error(NULL, "Unsupported operand types");
2354-
return 1;
2355-
}
2356-
}
2356+
default:
2357+
return zend_compare_slow(op1, op2, converted);
23572358
}
23582359
}
2360+
2361+
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
2362+
{
2363+
return zend_compare_fast(op1, op2, false);
2364+
}
23592365
/* }}} */
23602366

23612367
/* return int to be compatible with compare_func_t */
@@ -3353,8 +3359,7 @@ ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2)
33533359
* so a numeric comparison would be inaccurate */
33543360
goto string_cmp;
33553361
}
3356-
dval1 = dval1 - dval2;
3357-
return ZEND_NORMALIZE_BOOL(dval1);
3362+
return ZEND_THREEWAY_COMPARE(dval1, dval2);
33583363
} else { /* they both have to be long's */
33593364
return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
33603365
}

0 commit comments

Comments
 (0)