comparing anything but two numbers or two strings is an error

This commit is contained in:
2025-06-16 18:45:57 -05:00
parent a88cee7fae
commit 43b55b29f3

View File

@@ -13452,131 +13452,59 @@ static int js_compare_bigint(JSContext *ctx, OPCodeEnum op,
static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
OPCodeEnum op)
{
JSValue op1, op2;
JSValue op1 = sp[-2], op2 = sp[-1];
uint32_t tag1 = JS_VALUE_GET_NORM_TAG(op1);
uint32_t tag2 = JS_VALUE_GET_NORM_TAG(op2);
int res;
uint32_t tag1, tag2;
op1 = sp[-2];
op2 = sp[-1];
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
goto exception;
}
op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
if (JS_IsException(op2)) {
JS_FreeValue(ctx, op1);
goto exception;
}
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
/* string <=> string */
if (tag_is_string(tag1) && tag_is_string(tag2)) {
if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
res = js_string_compare(ctx, JS_VALUE_GET_STRING(op1),
if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING)
res = js_string_compare(ctx,
JS_VALUE_GET_STRING(op1),
JS_VALUE_GET_STRING(op2));
} else {
else
res = js_string_rope_compare(ctx, op1, op2, FALSE);
}
switch(op) {
case OP_lt:
res = (res < 0);
break;
case OP_lte:
res = (res <= 0);
break;
case OP_gt:
res = (res > 0);
break;
default:
case OP_gte:
res = (res >= 0);
break;
case OP_lt: res = (res < 0); break;
case OP_lte: res = (res <= 0); break;
case OP_gt: res = (res > 0); break;
default: res = (res >= 0); break;
}
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
} else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&
(tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {
/* fast path for float64/int */
goto float64_compare;
/* number <=> number */
} else if ((tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64) &&
(tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) {
double d1 = (tag1 == JS_TAG_FLOAT64
? JS_VALUE_GET_FLOAT64(op1)
: (double)JS_VALUE_GET_INT(op1));
double d2 = (tag2 == JS_TAG_FLOAT64
? JS_VALUE_GET_FLOAT64(op2)
: (double)JS_VALUE_GET_INT(op2));
switch(op) {
case OP_lt: res = (d1 < d2); break;
case OP_lte: res = (d1 <= d2); break;
case OP_gt: res = (d1 > d2); break;
default: res = (d1 >= d2); break;
}
/* anything else → TypeError */
} else {
if ((((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
tag_is_string(tag2)) ||
((tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) &&
tag_is_string(tag1)))) {
if (tag_is_string(tag1)) {
op1 = JS_StringToBigInt(ctx, op1);
if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&
JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)
goto invalid_bigint_string;
}
if (tag_is_string(tag2)) {
op2 = JS_StringToBigInt(ctx, op2);
if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&
JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT) {
invalid_bigint_string:
JS_ThrowTypeError(ctx,
"Relational operators only supported on two strings or two numbers");
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
res = FALSE;
goto done;
}
}
} else {
op1 = JS_ToNumericFree(ctx, op1);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
goto exception;
}
op2 = JS_ToNumericFree(ctx, op2);
if (JS_IsException(op2)) {
/* free the two input values and push the result */
JS_FreeValue(ctx, op1);
goto exception;
}
}
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||
tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {
res = js_compare_bigint(ctx, op, op1, op2);
} else {
double d1, d2;
float64_compare:
/* can use floating point comparison */
if (tag1 == JS_TAG_FLOAT64) {
d1 = JS_VALUE_GET_FLOAT64(op1);
} else {
d1 = JS_VALUE_GET_INT(op1);
}
if (tag2 == JS_TAG_FLOAT64) {
d2 = JS_VALUE_GET_FLOAT64(op2);
} else {
d2 = JS_VALUE_GET_INT(op2);
}
switch(op) {
case OP_lt:
res = (d1 < d2); /* if NaN return false */
break;
case OP_lte:
res = (d1 <= d2); /* if NaN return false */
break;
case OP_gt:
res = (d1 > d2); /* if NaN return false */
break;
default:
case OP_gte:
res = (d1 >= d2); /* if NaN return false */
break;
}
}
}
done:
JS_FreeValue(ctx, op2);
sp[-2] = JS_NewBool(ctx, res);
return 0;
exception:
sp[-2] = JS_UNDEFINED;
sp[-1] = JS_UNDEFINED;