diff --git a/quickjs.c b/quickjs.c index dbb9c20..89a4dc5 100644 --- 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; } diff --git a/tests/test_bjson.js b/tests/test_bjson.js index c29ded4..12180d1 100644 --- a/tests/test_bjson.js +++ b/tests/test_bjson.js @@ -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"),