From: Fabrice Bellard Date: Mon, 12 Oct 2026 10:07:55 +0000 (+0200) Subject: disable Temporal and Intl on 32 bit hosts because int128 is not always supported... X-Git-Url: https://git.kaiwu.me/$%7BGITURL%7D$%7Bcid%7D?a=commitdiff_plain;h=bcb9ad17ea83f70a5fbbe042b9a5dca148b7e90b;p=quickjs.git disable Temporal and Intl on 32 bit hosts because int128 is not always supported in this case - avoid depending on float128 for duration division - simplified some int128 code --- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ee75ec..9264c47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,10 +79,6 @@ jobs: - name: Run built-in tests run: | make CONFIG_M32=y test - - name: Run test262 - run: | - make test2-bootstrap - make CONFIG_M32=y test2 linux-asan: runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index dec85a0..c3e34bf 100644 --- a/Makefile +++ b/Makefile @@ -41,8 +41,11 @@ endif #CONFIG_M32=y # cosmopolitan build (see https://github.com/jart/cosmopolitan) #CONFIG_COSMO=y -# experimental Temporal and Intl support +# experimental Temporal and Intl support (disable if your C compiler +# does not support 128 bit integers) +ifndef CONFIG_M32 CONFIG_TEMPORAL_INTL=y +endif # installation directory PREFIX?=/usr/local diff --git a/temporal/duration.c b/temporal/duration.c index 524e251..c3b5c5c 100644 --- a/temporal/duration.c +++ b/temporal/duration.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "../quickjs.h" #include "../cutils.h" @@ -106,11 +107,11 @@ static int to_integer_if_integral128(JSContext *ctx, JSValueConst val, js_int128 JS_ThrowRangeError(ctx, "value must be an integer"); return -1; } - *pres = (js_int128_t)d; - if (d != 0 && *pres == 0) { + if (d > 0x1p127 || d < -0x1p127) { JS_ThrowRangeError(ctx, "value out of range"); return -1; } + *pres = (js_int128_t)d; return 0; } @@ -1306,26 +1307,66 @@ static void duration_format_time_ns(js_int128_t total_ns, TIUnit largestUnit, JS } } -/* Divide total_ns by divisor as a correctly-rounded double. - |total_ns| < ~2^86 (from DURATION_MAX_SECONDS * 1e9 + subsecond parts). - divisor is a uint64_t unit in nanoseconds, always < 2^53. - The simplest correct method uses __float128 division. */ -static double duration_total_div(js_int128_t total_ns, uint64_t divisor) +static int clz128(js_uint128_t a) { - /* Fast path: both total_ns and divisor are exactly representable as doubles, - and IEEE 754 division is correctly rounded. */ - if (total_ns < (1LL << 53) && total_ns > -(1LL << 53)) { - return (double)total_ns / (double)divisor; - } -#ifdef __SIZEOF_FLOAT128__ - return (double)((__float128)total_ns / (__float128)divisor); -#else - { - js_int128_t q = total_ns / (js_int128_t)divisor; - js_int128_t r = total_ns % (js_int128_t)divisor; - return (double)q + (double)r / (double)divisor; + if ((a >> 64) != 0) + return clz64(a >> 64); + else + return clz64(a) + 64; +} + +static js_uint128_t shr_rnd128(js_uint128_t a, int n) +{ + js_uint128_t addend; + addend = ((js_uint128_t)1 << (n - 1)) - 1 + ((a >> n) & 1); + return (a + addend) >> n; +} + +/* Divide a by b as a correctly-rounded double. */ +static double duration_total_div(js_int128_t a, uint64_t b) +{ + int a_exp, b_exp, q_exp, r_exp, sgn, shift; + js_uint128_t a1, q, r; + uint64_t m, res; + + if (a > -((int64_t)1 << 53) && a < ((int64_t)1 << 53) && + b < ((uint64_t)1 << 53)) { + /* fast case */ + return (double)(int64_t)a / (double)(int64_t)b; } -#endif + + if (a == 0) + return 0; + + if (a < 0) { + sgn = 1; + a1 = -a; + } else { + sgn = 0; + a1 = a; + } + + a_exp = 127 - clz128(a1); /* 2^a_exp <= a < 2^(a_exp + 1) */ + b_exp = 63 - clz64(b); /* 2^b_exp <= b < 2^(b_exp + 1) */ + + /* Ensure that the quotient is >= 2^54: + 2^(a_exp - b_exp - 1) < a/b < 2^(a_exp - b_exp + 1) */ + shift = max_int(54 - (a_exp - b_exp - 1), 0); + a1 <<= shift; + r_exp = -shift; + + q = a1 / b; + r = a1 % b; + q |= (r != 0); + q_exp = 127 - clz128(q); + assert(q_exp >= 54); + r_exp += q_exp - 1; + shift = q_exp - 52; + m = shr_rnd128(q, shift); + if (m >= ((uint64_t)1 << 53)) + r_exp++; + res = ((uint64_t)sgn << 63) | ((uint64_t )(r_exp + 1024) << 52) | (m & (((uint64_t)1 << 52) - 1)); + return uint64_as_float64(res); } /* NudgeToCalendarUnit-style total for ZonedDateTime relativeTo. diff --git a/temporal/temporal.c b/temporal/temporal.c index ac84b9c..a7c9a28 100644 --- a/temporal/temporal.c +++ b/temporal/temporal.c @@ -3879,14 +3879,13 @@ int is_valid_epoch_timespec(const JSTimeSpec *ts) JSValue ti_timespec_to_bigint(JSContext *ctx, const JSTimeSpec *ts) { - js_int128_t total_ns = (js_int128_t)ts->secs * 1000000000LL + ts->nsecs; + js_int128_t total_ns = ti_timespec_to_ns(ts); return JS_NewBigInt128(ctx, (uint64_t)total_ns, (uint64_t)(total_ns >> 64)); } int ti_bigint_to_timespec(JSContext *ctx, JSValueConst val, JSTimeSpec *ts) { uint64_t low, high; - int32_t nsecs; int ret; js_int128_t total_ns; @@ -3903,12 +3902,6 @@ int ti_bigint_to_timespec(JSContext *ctx, JSValueConst val, JSTimeSpec *ts) JS_ThrowRangeError(ctx, "epochNanoseconds out of range"); return -1; } - ts->secs = (int64_t)(total_ns / 1000000000LL); - nsecs = (int32_t)(total_ns % 1000000000LL); - if (nsecs < 0) { - ts->secs -= 1; - nsecs += 1000000000; - } - ts->nsecs = (uint32_t)nsecs; + ti_ns_to_timespec(total_ns, ts); return 0; } diff --git a/temporal/temporal_private.h b/temporal/temporal_private.h index 0685777..c8ba297 100644 --- a/temporal/temporal_private.h +++ b/temporal/temporal_private.h @@ -11,8 +11,10 @@ /* 128-bit integer type: __int128 on 64-bit, _BitInt(128) on 32-bit */ #ifdef __SIZEOF_INT128__ typedef __int128 js_int128_t; +typedef unsigned __int128 js_uint128_t; #else typedef _BitInt(128) js_int128_t; +typedef unsigned _BitInt(128) js_uint128_t; #endif /* Temporal limits */ @@ -232,12 +234,14 @@ static inline js_int128_t ti_duration_time_fields_to_ns(const JSDurationData *d) static inline void ti_ns_to_timespec(js_int128_t ns, JSTimeSpec *ts) { + int32_t nsecs; ts->secs = (int64_t)(ns / 1000000000LL); - ts->nsecs = (uint32_t)(ns % 1000000000LL); - if (ts->nsecs != 0 && ns < 0) { - ts->nsecs += 1000000000; + nsecs = ns % 1000000000LL; + if (nsecs < 0) { + nsecs += 1000000000; ts->secs -= 1; } + ts->nsecs = nsecs; }