simpler addition rule

This commit is contained in:
2025-06-16 20:40:41 -05:00
parent 43b55b29f3
commit 9ecdaae7a7

View File

@@ -16942,82 +16942,105 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_add):
{
JSValue op1, op2;
op1 = sp[-2];
op2 = sp[-1];
JSValue op1 = sp[-2], op2 = sp[-1], res;
int tag1 = JS_VALUE_GET_NORM_TAG(op1);
int tag2 = JS_VALUE_GET_NORM_TAG(op2);
/* 1) both ints? keep fast int path with overflow check */
if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
int64_t r;
r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2);
if (unlikely((int)r != r))
goto add_slow;
sp[-2] = JS_NewInt32(ctx, r);
sp--;
} else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) +
JS_VALUE_GET_FLOAT64(op2));
sp--;
} else if (JS_IsString(op1) && JS_IsString(op2)) {
sp[-2] = JS_ConcatString(ctx, op1, op2);
sp--;
if (JS_IsException(sp[-1]))
goto exception;
} else {
add_slow:
sf->cur_pc = pc;
if (js_add_slow(ctx, sp))
goto exception;
sp--;
int64_t tmp = (int64_t)JS_VALUE_GET_INT(op1)
+ JS_VALUE_GET_INT(op2);
if (likely((int)tmp == tmp)) {
res = JS_NewInt32(ctx, (int)tmp);
} else {
res = __JS_NewFloat64(ctx, (double)JS_VALUE_GET_INT(op1) + (double)JS_VALUE_GET_INT(op2));
}
}
/* 2) both floats? */
else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
res = __JS_NewFloat64(ctx,
JS_VALUE_GET_FLOAT64(op1)
+ JS_VALUE_GET_FLOAT64(op2));
}
/* 3) both strings? */
else if (JS_IsString(op1) && JS_IsString(op2)) {
res = JS_ConcatString(ctx, op1, op2);
if (JS_IsException(res))
goto exception;
}
/* 4) mixed int/float? promote to float */
// TODO: Seems slow
else if ((tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) ||
(tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_INT)) {
double a, b;
if(tag1 == JS_TAG_INT)
a = (double)JS_VALUE_GET_INT(op1);
else
a = JS_VALUE_GET_FLOAT64(op1);
if(tag2 == JS_TAG_INT)
b = (double)JS_VALUE_GET_INT(op2);
else
b = JS_VALUE_GET_FLOAT64(op2);
res = __JS_NewFloat64(ctx, a + b);
}
/* 5) anything else → null */
else {
res = JS_NULL;
}
sp[-2] = res;
sp--;
}
BREAK;
CASE(OP_add_loc):
{
JSValue op2;
JSValue *pv;
int idx;
idx = *pc;
pc += 1;
op2 = sp[-1];
pv = &var_buf[idx];
if (likely(JS_VALUE_IS_BOTH_INT(*pv, op2))) {
int64_t r;
r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(op2);
if (unlikely((int)r != r))
goto add_loc_slow;
*pv = JS_NewInt32(ctx, r);
sp--;
} else if (JS_VALUE_IS_BOTH_FLOAT(*pv, op2)) {
*pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) +
JS_VALUE_GET_FLOAT64(op2));
sp--;
} else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
sp--;
sf->cur_pc = pc;
op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
if (JS_IsException(op2))
goto exception;
if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) {
JS_FreeValue(ctx, op2);
} else {
op2 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op2);
if (JS_IsException(op2))
goto exception;
set_value(ctx, pv, op2);
}
} else {
JSValue ops[2];
add_loc_slow:
/* In case of exception, js_add_slow frees ops[0]
and ops[1], so we must duplicate *pv */
sf->cur_pc = pc;
ops[0] = JS_DupValue(ctx, *pv);
ops[1] = op2;
sp--;
if (js_add_slow(ctx, ops + 2))
goto exception;
set_value(ctx, pv, ops[0]);
}
int idx = *pc++;
JSValue rhs = sp[-1];
JSValue lhs = var_buf[idx];
JSValue res;
int tag1 = JS_VALUE_GET_NORM_TAG(lhs);
int tag2 = JS_VALUE_GET_NORM_TAG(rhs);
/* 1) both ints? fast path, overflow → float64 */
if (likely(JS_VALUE_IS_BOTH_INT(lhs, rhs))) {
int a_i = JS_VALUE_GET_INT(lhs);
int b_i = JS_VALUE_GET_INT(rhs);
int64_t tmp = (int64_t)a_i + b_i;
if ((int)tmp == tmp)
res = JS_NewInt32(ctx, (int)tmp);
else
res = __JS_NewFloat64(ctx, (double)a_i + (double)b_i);
}
/* 2) both floats? */
else if (JS_VALUE_IS_BOTH_FLOAT(lhs, rhs)) {
res = __JS_NewFloat64(ctx,
JS_VALUE_GET_FLOAT64(lhs)
+ JS_VALUE_GET_FLOAT64(rhs));
}
/* 3) both strings? */
else if (JS_IsString(lhs) && JS_IsString(rhs)) {
res = JS_ConcatString(ctx, lhs, rhs);
if (JS_IsException(res))
goto exception;
}
/* 4) mixed int/float? promote to float64 */
else if ((tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) ||
(tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_INT)) {
double a = tag1 == JS_TAG_INT
? (double)JS_VALUE_GET_INT(lhs)
: JS_VALUE_GET_FLOAT64(lhs);
double b = tag2 == JS_TAG_INT
? (double)JS_VALUE_GET_INT(rhs)
: JS_VALUE_GET_FLOAT64(rhs);
res = __JS_NewFloat64(ctx, a + b);
}
/* 5) anything else → null */
else {
res = JS_NULL;
}
var_buf[idx] = res;
sp--;
}
BREAK;
CASE(OP_sub):