simpler addition rule
This commit is contained in:
163
source/quickjs.c
163
source/quickjs.c
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user