]> git.kaiwu.me - quickjs.git/commitdiff
fixed BJSON array serialization (#457)
authorFabrice Bellard <fabrice@bellard.org>
Sat, 15 Nov 2025 13:52:50 +0000 (14:52 +0100)
committerFabrice Bellard <fabrice@bellard.org>
Sat, 15 Nov 2025 13:52:50 +0000 (14:52 +0100)
quickjs.c
tests/test_bjson.js

index dbb9c20bc92c478afb2f0bd5f841558c2cc26b3c..89a4dc51623c8e7e2765697166eedf7585391096 100644 (file)
--- a/quickjs.c
+++ b/quickjs.c
@@ -37258,14 +37258,17 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
     return -1;
 }
 
+/* XXX: be compatible with the structured clone algorithm */
 static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
 {
+    JSContext *ctx = s->ctx;
     JSObject *p = JS_VALUE_GET_OBJ(obj);
     uint32_t i, len;
-    JSValue val;
     int ret;
     BOOL is_template;
-
+    JSShapeProperty *prs;
+    JSProperty *pr;
+    
     if (s->allow_bytecode && !p->extensible) {
         /* not extensible array: we consider it is a
            template when we are saving bytecode */
@@ -37275,29 +37278,62 @@ static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
         bc_put_u8(s, BC_TAG_ARRAY);
         is_template = FALSE;
     }
-    if (js_get_length32(s->ctx, &len, obj))
-        goto fail1;
+    if (js_get_length32(ctx, &len, obj)) /* no side effect */
+        goto fail;
     bc_put_leb128(s, len);
-    for(i = 0; i < len; i++) {
-        val = JS_GetPropertyUint32(s->ctx, obj, i);
-        if (JS_IsException(val))
-            goto fail1;
-        ret = JS_WriteObjectRec(s, val);
-        JS_FreeValue(s->ctx, val);
-        if (ret)
-            goto fail1;
+    if (p->fast_array) {
+        for(i = 0; i < p->u.array.count; i++) {
+            ret = JS_WriteObjectRec(s, p->u.array.u.values[i]);
+            if (ret)
+                goto fail;
+        }
+        for(i = p->u.array.count; i < len; i++) {
+            ret = JS_WriteObjectRec(s, JS_UNDEFINED);
+            if (ret)
+                goto fail;
+        }
+    } else {
+        for(i = 0; i < len; i++) {
+            JSAtom atom;
+            atom = JS_NewAtomUInt32(ctx, i);
+            if (atom == JS_ATOM_NULL)
+                goto fail;
+            prs = find_own_property(&pr, p, atom);
+            JS_FreeAtom(ctx, atom);
+            if (prs && (prs->flags & JS_PROP_ENUMERABLE)) {
+                if (prs->flags & JS_PROP_TMASK) {
+                    JS_ThrowTypeError(ctx, "only value properties are supported");
+                    goto fail;
+                }
+                ret = JS_WriteObjectRec(s, pr->u.value);
+                if (ret)
+                    goto fail;
+            } else {
+                ret = JS_WriteObjectRec(s, JS_UNDEFINED);
+                if (ret)
+                    goto fail;
+            }
+        }
     }
     if (is_template) {
-        val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw);
-        if (JS_IsException(val))
-            goto fail1;
-        ret = JS_WriteObjectRec(s, val);
-        JS_FreeValue(s->ctx, val);
-        if (ret)
-            goto fail1;
+        /* the 'raw' property is not enumerable */
+        prs = find_own_property(&pr, p, JS_ATOM_raw);
+        if (prs) {
+            if (prs->flags & JS_PROP_TMASK) {
+                JS_ThrowTypeError(ctx, "only value properties are supported");
+                goto fail;
+            }
+            ret = JS_WriteObjectRec(s, pr->u.value);
+            if (ret)
+                goto fail;
+        } else {
+            ret = JS_WriteObjectRec(s, JS_UNDEFINED);
+            if (ret)
+                goto fail;
+        }
     }
     return 0;
- fail1:
+ fail:
     return -1;
 }
 
index c29ded4d84e73b958fb1c21ba6c0509deb41b20c..12180d163975c4c67455f2fc0f1094e33aa00c27 100644 (file)
@@ -184,7 +184,18 @@ function bjson_test_all()
     var obj;
 
     bjson_test({x:1, y:2, if:3});
+
     bjson_test([1, 2, 3]);
+
+    /* array with holes */
+    bjson_test([1, , 2, , 3]); 
+
+    /* fast array with hole */
+    obj = new Array(5);
+    obj[0] = 1;
+    obj[1] = 2;
+    bjson_test(obj);
+
     bjson_test([1.0, "aa", true, false, undefined, null, NaN, -Infinity, -0.0]);
     if (typeof BigInt !== "undefined") {
         bjson_test([BigInt("1"), -BigInt("0x123456789"),