]> git.kaiwu.me - quickjs.git/commitdiff
disable Temporal and Intl on 32 bit hosts because int128 is not always supported...
authorFabrice Bellard <fabrice@bellard.org>
Mon, 12 Oct 2026 10:07:55 +0000 (12:07 +0200)
committerFabrice Bellard <fabrice@bellard.org>
Mon, 12 Oct 2026 10:07:55 +0000 (12:07 +0200)
.github/workflows/ci.yml
Makefile
temporal/duration.c
temporal/temporal.c
temporal/temporal_private.h

index 9ee75ec46b2be4799a898cecb312c4bc0d3e9514..9264c4798a5121df70a22002dfe8f7f6afadb8a6 100644 (file)
@@ -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
index dec85a0fb2f4170b254109158ea5323933e38ed2..c3e34bf6e5170fba7ec053517655df4aaebd0bde 100644 (file)
--- 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
index 524e251abd70d622d16988970c4c70f7c528a2e6..c3b5c5cc0c1d1a93874684fdf5c0b604c349d918 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <math.h>
+#include <assert.h>
 
 #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.
index ac84b9cb011a89daa148536c504197ae8ba6546c..a7c9a28ae3ccdb31fbc757e2341abccd53bb1c4e 100644 (file)
@@ -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;
 }
index 06857773686bf78f975a9f36941a1f0cacd09910..c8ba297b0fce1482e7a47bbe814d1734a6ff6d84 100644 (file)
 /* 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;
 }