]> git.kaiwu.me - quickjs.git/commitdiff
fixed BigInt.AsUintN() and added corresponding regression tests from quickjs-ng
authorFabrice Bellard <fabrice@bellard.org>
Sat, 26 Sep 2026 12:39:43 +0000 (14:39 +0200)
committerFabrice Bellard <fabrice@bellard.org>
Sat, 26 Sep 2026 12:39:43 +0000 (14:39 +0200)
quickjs.c
tests/test_bigint.js

index 4ca6831bd461c7cd5754f567054b855a7235154a..eb93ac5cc3406f6fc89fae3016707fdcd7c168f9 100644 (file)
--- a/quickjs.c
+++ b/quickjs.c
@@ -56312,6 +56312,8 @@ static JSValue js_bigint_asUintN(JSContext *ctx,
 {
     uint64_t bits;
     JSValue res, a;
+    JSBigInt *p;
+    JSBigIntBuf buf;
     
     if (JS_ToIndex(ctx, &bits, argv[0]))
         return JS_EXCEPTION;
@@ -56323,13 +56325,18 @@ static JSValue js_bigint_asUintN(JSContext *ctx,
         res = __JS_NewShortBigInt(ctx, 0);
     } else if (JS_VALUE_GET_TAG(a) == JS_TAG_SHORT_BIG_INT) {
         /* fast case */
+        js_slimb_t sv = JS_VALUE_GET_SHORT_BIG_INT(a);
         if (bits >= JS_SHORT_BIG_INT_BITS) {
-            res = a;
+            if (!asIntN && sv < 0) {
+                p = js_bigint_set_short(&buf, a);
+                goto slow_case;
+            } else {
+                res = a;
+            }
         } else {
-            uint64_t v;
+            uint64_t v = sv;
             int shift;
             shift = 64 - bits;
-            v = JS_VALUE_GET_SHORT_BIG_INT(a);
             v = v << shift;
             if (asIntN)
                 v = (int64_t)v >> shift;
@@ -56338,30 +56345,49 @@ static JSValue js_bigint_asUintN(JSContext *ctx,
             res = __JS_NewShortBigInt(ctx, v);
         }
     } else {
-        JSBigInt *r, *p = JS_VALUE_GET_PTR(a);
-        if (bits >= p->len * JS_LIMB_BITS) {
+        JSBigInt *r;
+        p = JS_VALUE_GET_PTR(a);
+        if (bits >= p->len * JS_LIMB_BITS && (asIntN || !js_bigint_sign(p))) {
             res = a;
         } else {
-            int len, shift, i;
+            uint64_t len64;
+            int len, shift, i, l, is_neg;
             js_limb_t v;
-            len = (bits + JS_LIMB_BITS - 1) / JS_LIMB_BITS;
+        slow_case:
+            is_neg = js_bigint_sign(p);
+            len64 = (bits + JS_LIMB_BITS - 1) / JS_LIMB_BITS;
+            len = min_int64(len64, INT32_MAX);
             r = js_bigint_new(ctx, len);
             if (!r) {
                 JS_FreeValue(ctx, a);
                 return JS_EXCEPTION;
             }
+            /* sign extend */
             r->len = len;
-            for(i = 0; i < len - 1; i++)
+            l = min_int(len, p->len);
+            for(i = 0; i < l; i++)
                 r->tab[i] = p->tab[i];
+            for(i = l; i < len; i++)
+                r->tab[i] = -is_neg;
+
             shift = (-bits) & (JS_LIMB_BITS - 1);
             /* 0 <= shift <= JS_LIMB_BITS - 1 */
-            v = p->tab[len - 1] << shift;
+            v = r->tab[len - 1] << shift;
             if (asIntN)
                 v = (js_slimb_t)v >> shift;
             else
                 v = v >> shift;
             r->tab[len - 1] = v;
-            r = js_bigint_normalize(ctx, r);
+            
+            if (!asIntN) {
+                r = js_bigint_extend(ctx, r, 0);
+                if (!r) {
+                    JS_FreeValue(ctx, a);
+                    return JS_EXCEPTION;
+                }
+            } else {
+                r = js_bigint_normalize(ctx, r);
+            }
             JS_FreeValue(ctx, a);
             res = JS_CompactBigInt(ctx, r);
         }
index a0d028c91f099807e3f4218967c091c9b871e9c0..c734678392cf9cb9bf4eb3c73491d7a7fd0fcbd5 100644 (file)
@@ -243,7 +243,37 @@ function test_pi()
     assert(compute_pi(2000), "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151557485724245415069595082953311686172785588907509838175463746493931925506040092770167113900984882401285836160356370766010471018194295559619894676783744944825537977472684710404753464620804668425906949129331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992458631503028618297455570674983850549458858692699569092721079750930295532116534498720275596023648066549911988183479775356636980742654252786255181841757467289097777279380008164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179049460165346680498862723279178608578438382796797668145410095388378636095068006422512520511739298489608412848862694560424196528502221066118630674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009");
 }
 
+function test_bigint_asintn()
+{
+    /* BigInt.asIntN */
+    assert(BigInt.asIntN(0, -1n), 0n);
+    assert(BigInt.asIntN(1, -1n), -1n);
+    assert(BigInt.asIntN(8, 128n), -128n);
+    assert(BigInt.asIntN(8, 127n), 127n);
+    assert(BigInt.asIntN(64, -1n), -1n);
+    assert(BigInt.asIntN(64, 0x8000000000000000n), -0x8000000000000000n);
+    assert(BigInt.asIntN(128, -1n), -1n);
+
+    /* BigInt.asUintN: wrapping a negative value when the requested width is a
+       multiple of the internal limb size used to return the value unchanged. */
+    assert(BigInt.asUintN(0, -1n), 0n);
+    assert(BigInt.asUintN(1, -1n), 1n);
+    assert(BigInt.asUintN(8, -1n), 0xffn);
+    assert(BigInt.asUintN(64, -1n), 0xffffffffffffffffn);
+    assert(BigInt.asUintN(64, -2n), 0xfffffffffffffffen);
+    assert(BigInt.asUintN(64, 0x8000000000000000n), 0x8000000000000000n);
+    assert(BigInt.asUintN(128, -1n), (1n << 128n) - 1n);
+    assert(BigInt.asUintN(192, -1n), (1n << 192n) - 1n);
+    assert(BigInt.asUintN(64, -(1n << 64n)), 0n);
+    assert(BigInt.asUintN(64, 1n << 64n), 0n);
+
+    /* non-negative values are returned unchanged */
+    assert(BigInt.asUintN(64, 123n), 123n);
+    assert(BigInt.asIntN(64, 123n), 123n);
+}
+
 test_bigint1();
 test_bigint2();
 test_bigint3();
 test_pi();
+test_bigint_asintn();