fix number rep

This commit is contained in:
2026-02-02 07:56:53 -06:00
parent 2d834c37b3
commit f2a76cbb55
5 changed files with 53 additions and 55 deletions

View File

@@ -166,7 +166,7 @@ static void nota_encode_value(NotaEncodeContext *enc, JSValueConst val, JSValueC
case JS_TAG_NULL:
nota_write_sym(&enc->nb, NOTA_NULL);
break;
case JS_TAG_OBJECT: {
case JS_TAG_PTR: {
if (js_is_blob(ctx, replaced)) {
size_t buf_len;
void *buf_data = js_get_blob_data(ctx, &buf_len, replaced);

View File

@@ -156,7 +156,7 @@ static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueC
case JS_TAG_NULL:
wota_write_sym(&enc->wb, WOTA_NULL);
break;
case JS_TAG_OBJECT: {
case JS_TAG_PTR: {
if (js_is_blob(ctx, replaced)) {
size_t buf_len;
void *buf_data = js_get_blob_data(ctx, &buf_len, replaced);

View File

@@ -5205,7 +5205,7 @@ static int JS_ToBoolFree (JSContext *ctx, JSValue val) {
default:
if (JS_TAG_IS_FLOAT64 (tag)) {
double d = JS_VALUE_GET_FLOAT64 (val);
return !isnan (d) && d != 0;
return d != 0; /* NaN impossible in short floats */
} else {
return TRUE;
}
@@ -5521,16 +5521,13 @@ redo:
return -1;
case JS_TAG_FLOAT64: {
double d = JS_VALUE_GET_FLOAT64 (val);
if (isnan (d)) {
ret = 0;
} else {
if (d < INT32_MIN)
ret = INT32_MIN;
else if (d > INT32_MAX)
ret = INT32_MAX;
else
ret = (int)d;
}
/* NaN impossible in short floats */
if (d < INT32_MIN)
ret = INT32_MIN;
else if (d > INT32_MAX)
ret = INT32_MAX;
else
ret = (int)d;
} break;
default:
val = JS_ToNumberFree (ctx, val);
@@ -5577,17 +5574,14 @@ redo:
return -1;
case JS_TAG_FLOAT64: {
double d = JS_VALUE_GET_FLOAT64 (val);
if (isnan (d)) {
*pres = 0;
} else {
if (d < INT64_MIN)
*pres = INT64_MIN;
else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot
be exactly represented as a double */
*pres = INT64_MAX;
else
*pres = (int64_t)d;
}
/* NaN impossible in short floats */
if (d < INT64_MIN)
*pres = INT64_MIN;
else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot
be exactly represented as a double */
*pres = INT64_MAX;
else
*pres = (int64_t)d;
}
return 0;
default:
@@ -6409,12 +6403,7 @@ js_unary_arith_slow (JSContext *ctx, JSValue *sp, OPCodeEnum op) {
case OP_plus:
break;
case OP_neg:
if (v64 == 0) {
sp[-1] = __JS_NewFloat64 (ctx, -0.0);
return 0;
} else {
v64 = -v64;
}
v64 = -v64; /* -0 normalized to 0 by __JS_NewFloat64 */
break;
default:
abort ();
@@ -6518,10 +6507,7 @@ js_binary_arith_slow (JSContext *ctx, JSValue *sp, OPCodeEnum op) {
break;
case OP_mul:
v = (int64_t)v1 * (int64_t)v2;
if (v == 0 && (v1 | v2) < 0) {
sp[-2] = __JS_NewFloat64 (ctx, -0.0);
return 0;
}
/* -0 normalized to 0, no special case needed */
break;
case OP_div:
sp[-2] = JS_NewFloat64 (ctx, (double)v1 / (double)v2);
@@ -8548,11 +8534,7 @@ restart:
d = (double)r;
goto mul_fp_res;
}
/* need to test zero case for -0 result */
if (unlikely (r == 0 && (v1 | v2) < 0)) {
d = -0.0;
goto mul_fp_res;
}
/* -0 normalized to 0, no special case needed */
sp[-2] = JS_NewInt32 (ctx, r);
sp--;
} else if (JS_VALUE_IS_BOTH_FLOAT (op1, op2)) {
@@ -8625,11 +8607,7 @@ restart:
tag = JS_VALUE_GET_TAG (op1);
if (tag == JS_TAG_INT) {
val = JS_VALUE_GET_INT (op1);
/* Note: -0 cannot be expressed as integer */
if (unlikely (val == 0)) {
d = -0.0;
goto neg_fp_res;
}
/* -0 normalized to 0, val==0 just stays 0 */
if (unlikely (val == INT32_MIN)) {
d = -(double)val;
goto neg_fp_res;

View File

@@ -240,8 +240,8 @@ __JS_NewFloat64 (JSContext *ctx, double d) {
int exp = (u.u >> 52) & 0x7FF;
uint64_t mantissa = u.u & ((1ULL << 52) - 1);
/* Zero → short float zero */
if (exp == 0 && mantissa == 0) { return (sign << 63) | JS_TAG_SHORT_FLOAT; }
/* Zero → short float zero (always +0, no -0) */
if (exp == 0 && mantissa == 0) { return JS_TAG_SHORT_FLOAT; }
/* NaN/Inf → NULL */
if (exp == 0x7FF) { return JS_MKVAL (JS_TAG_NULL, 0); }
@@ -273,7 +273,7 @@ static inline double JS_VALUE_GET_FLOAT64 (JSValue v) {
uint64_t short_exp = (v >> 55) & 0xFF;
uint64_t mantissa = (v >> 3) & ((1ULL << 52) - 1);
if (short_exp == 0) return sign ? -0.0 : 0.0;
if (short_exp == 0) return 0.0; /* Always +0, no -0 */
uint64_t exp = short_exp - 127 + 1023;
union {

View File

@@ -1244,15 +1244,16 @@ return {
// EDGE CASES AND SPECIAL VALUES
// ============================================================================
test_infinity: function() {
test_division_by_zero_is_null: function() {
var inf = 1 / 0
if (!(inf > 1000000)) throw "infinity failed"
if (!(-inf < -1000000)) throw "negative infinity failed"
if (inf != null) throw "division by zero should be null"
var ninf = -1 / 0
if (ninf != null) throw "negative division by zero should be null"
},
test_nan: function() {
test_zero_div_zero_is_null: function() {
var nan = 0 / 0
if (nan == nan) throw "NaN should not equal itself"
if (nan != null) throw "0/0 should be null"
},
test_max_safe_integer: function() {
@@ -1403,17 +1404,36 @@ return {
test_number_division_by_zero: function() {
var result = 1 / 0
if (!(result > 1000000)) throw "division by zero should give infinity"
if (result != null) throw "division by zero should give null"
},
test_number_negative_division_by_zero: function() {
var result = -1 / 0
if (!(result < -1000000)) throw "negative division by zero should give -infinity"
if (result != null) throw "negative division by zero should give null"
},
test_zero_division_by_zero: function() {
var result = 0 / 0
if (result == result) throw "0/0 should give NaN"
if (result != null) throw "0/0 should give null"
},
test_negative_zero_normalized: function() {
var nz = -0
if (nz != 0) throw "-0 should equal 0"
var mul_nz = 0 * -1
if (mul_nz != 0) throw "0 * -1 should be 0"
var neg_zero = -(0)
if (neg_zero != 0) throw "-(0) should be 0"
},
test_overflow_is_null: function() {
var result = 1e38 * 1e38
if (result != null) throw "overflow should give null"
},
test_modulo_by_zero_is_null: function() {
var result = 5 % 0
if (result != null) throw "modulo by zero should give null"
},
// ============================================================================