static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic);
-static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj)
-{
- /* Try and handle fast arrays explicitly */
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
- return TRUE;
- }
- }
- return FALSE;
-}
-
/* Access an Array's internal JSValue array if available */
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
JSValue **arrpp, uint32_t *countp)
return JS_DupValue(ctx, this_val);
}
-static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,
- JSValueConst len_val)
+/* XXX: optimize */
+static JSValue JS_ArraySpeciesGetCtor(JSContext *ctx, JSValueConst obj)
{
- JSValue ctor, ret, species;
+ JSValue ctor, species;
int res;
JSContext *realm;
if (res < 0)
return JS_EXCEPTION;
if (!res)
- return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
+ return JS_UNDEFINED;
ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
if (JS_IsException(ctor))
return ctor;
if (JS_IsNull(ctor))
ctor = JS_UNDEFINED;
}
+ if (!JS_IsUndefined(ctor) &&
+ js_same_value(ctx, ctor, ctx->array_ctor)) {
+ JS_FreeValue(ctx, ctor);
+ ctor = JS_UNDEFINED;
+ }
+ return ctor;
+}
+
+static JSValue JS_ArrayCreateFromCtor(JSContext *ctx, JSValueConst ctor, int64_t len)
+{
+ JSValue len_val, ret;
+
+ len_val = JS_NewInt64(ctx, len);
if (JS_IsUndefined(ctor)) {
- return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
+ ret = js_array_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&len_val);
} else {
- ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
- JS_FreeValue(ctx, ctor);
- return ret;
+ ret = JS_CallConstructor(ctx, ctor, 1, (JSValueConst *)&len_val);
}
+ JS_FreeValue(ctx, len_val);
+ return ret;
+}
+
+/* len must be >= 0 */
+static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj, int64_t len)
+{
+ JSValue ctor, ret;
+
+ ctor = JS_ArraySpeciesGetCtor(ctx, obj);
+ if (JS_IsException(ctor))
+ return ctor;
+ ret = JS_ArrayCreateFromCtor(ctx, ctor, len);
+ JS_FreeValue(ctx, ctor);
+ return ret;
}
static const JSCFunctionListEntry js_array_funcs[] = {
if (JS_IsException(obj))
goto exception;
- arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
+ arr = JS_ArraySpeciesCreate(ctx, obj, 0);
if (JS_IsException(arr))
goto exception;
n = 0;
ret = JS_FALSE;
break;
case special_map:
- /* XXX: JS_ArraySpeciesCreate should take int64_t */
- ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len));
+ ret = JS_ArraySpeciesCreate(ctx, obj, len);
if (JS_IsException(ret))
goto exception;
break;
case special_filter:
- ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
+ ret = JS_ArraySpeciesCreate(ctx, obj, 0);
if (JS_IsException(ret))
goto exception;
break;
}
static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int splice)
+ int argc, JSValueConst *argv)
{
- JSValue obj, arr, val, len_val;
- int64_t len, start, k, final, n, count, del_count, new_len;
+ JSValue obj, arr, val, ctor;
+ int64_t len, start, k, final, n, count;
int kPresent;
JSValue *arrp;
- uint32_t count32, i, item_count;
+ uint32_t count32;
arr = JS_UNDEFINED;
obj = JS_ToObject(ctx, this_val);
if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
goto exception;
- if (splice) {
- if (argc == 0) {
- item_count = 0;
- del_count = 0;
- } else
- if (argc == 1) {
- item_count = 0;
- del_count = len - start;
- } else {
- item_count = argc - 2;
- if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))
- goto exception;
- }
- if (len + item_count - del_count > MAX_SAFE_INTEGER) {
- JS_ThrowTypeError(ctx, "Array loo long");
+ final = len;
+ if (!JS_IsUndefined(argv[1])) {
+ if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))
goto exception;
- }
- count = del_count;
- } else {
- item_count = 0; /* avoid warning */
- final = len;
- if (!JS_IsUndefined(argv[1])) {
- if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))
- goto exception;
- }
- count = max_int64(final - start, 0);
}
- len_val = JS_NewInt64(ctx, count);
- arr = JS_ArraySpeciesCreate(ctx, obj, len_val);
- JS_FreeValue(ctx, len_val);
- if (JS_IsException(arr))
+ count = max_int64(final - start, 0);
+
+ ctor = JS_ArraySpeciesGetCtor(ctx, obj);
+ if (JS_IsException(ctor))
goto exception;
- k = start;
final = start + count;
- n = 0;
- /* The fast array test on arr ensures that
- JS_CreateDataPropertyUint32() won't modify obj in case arr is
- an exotic object */
- /* Special case fast arrays */
- if (js_get_fast_array(ctx, obj, &arrp, &count32) &&
- js_is_fast_array(ctx, arr)) {
- /* XXX: should share code with fast array constructor */
- for (; k < final && k < count32; k++, n++) {
- if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0)
+ if (JS_IsUndefined(ctor) &&
+ js_get_fast_array(ctx, obj, &arrp, &count32) &&
+ final <= count32) {
+ /* fast case */
+ arr = js_create_array(ctx, count, (JSValueConst *)arrp + start);
+ } else {
+ arr = JS_ArrayCreateFromCtor(ctx, ctor, count);
+ JS_FreeValue(ctx, ctor);
+ if (JS_IsException(arr))
+ goto exception;
+
+ n = 0;
+ for (k = start; k < final; k++, n++) {
+ kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
+ if (kPresent < 0)
goto exception;
+ if (kPresent) {
+ if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
+ goto exception;
+ }
}
+ if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
+ goto exception;
}
- /* Copy the remaining elements if any (handle case of inherited properties) */
- for (; k < final; k++, n++) {
- kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
- if (kPresent < 0)
+ JS_FreeValue(ctx, obj);
+ return arr;
+
+ exception:
+ JS_FreeValue(ctx, obj);
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_array_splice(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj, arr, val, ctor;
+ int64_t len, start, k, final, n, del_count, new_len;
+ int kPresent;
+ uint32_t i, item_count;
+ JSObject *p;
+
+ arr = JS_UNDEFINED;
+ obj = JS_ToObject(ctx, this_val);
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+
+ if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
+ goto exception;
+
+ if (argc == 0) {
+ item_count = 0;
+ del_count = 0;
+ } else if (argc == 1) {
+ item_count = 0;
+ del_count = len - start;
+ } else {
+ item_count = argc - 2;
+ if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))
goto exception;
- if (kPresent) {
- if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
- goto exception;
- }
}
- if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
+ if (len + item_count - del_count > MAX_SAFE_INTEGER) {
+ JS_ThrowTypeError(ctx, "Array loo long");
+ goto exception;
+ }
+ final = start + del_count;
+ /* warning: 'len' may be different from the actual array length
+ because it may have been modified */
+ new_len = len + item_count - del_count;
+
+ ctor = JS_ArraySpeciesGetCtor(ctx, obj);
+ if (JS_IsException(ctor))
goto exception;
- if (splice) {
- new_len = len + item_count - del_count;
+ p = JS_VALUE_GET_PTR(obj);
+ if (JS_IsUndefined(ctor) &&
+ p->class_id == JS_CLASS_ARRAY &&
+ p->fast_array &&
+ final <= p->u.array.count &&
+ (get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE) && /* writable array length */
+ can_extend_fast_array(p)) {
+ uint32_t count32 = p->u.array.count;
+ JSValue *arrp = p->u.array.u.values;
+
+ /* fast case */
+ arr = js_create_array(ctx, del_count, (JSValueConst *)arrp + start);
+ if (JS_IsException(arr))
+ goto exception;
+
+ if (item_count != del_count) {
+ /* resize */
+ uint32_t new_count32;
+ new_count32 = count32 + item_count - del_count;
+ if (del_count > item_count) {
+ for(i = 0; i < del_count - item_count; i++)
+ JS_FreeValue(ctx, arrp[start + item_count + i]);
+ memmove(arrp + start + item_count, arrp + final,
+ (count32 - final) * sizeof(arrp[0]));
+ } else {
+ if (unlikely(new_count32 > p->u.array.u1.size)) {
+ if (expand_fast_array(ctx, p, new_count32))
+ goto exception;
+ arrp = p->u.array.u.values;
+ }
+ memmove(arrp + start + item_count, arrp + final,
+ (count32 - final) * sizeof(arrp[0]));
+ for(i = 0; i < item_count - del_count; i++)
+ arrp[start + del_count + i] = JS_UNDEFINED;
+ }
+ p->u.array.count = new_count32;
+ }
+ for(i = 0; i < item_count; i++)
+ set_value(ctx, &arrp[start + i], JS_DupValue(ctx, argv[i + 2]));
+ } else {
+ arr = JS_ArrayCreateFromCtor(ctx, ctor, del_count);
+ JS_FreeValue(ctx, ctor);
+ if (JS_IsException(arr))
+ goto exception;
+
+ n = 0;
+ for (k = start; k < final; k++, n++) {
+ kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
+ if (kPresent < 0)
+ goto exception;
+ if (kPresent) {
+ if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
+ goto exception;
+ }
+ }
+ if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
+ goto exception;
+
if (item_count != del_count) {
if (JS_CopySubArray(ctx, obj, start + item_count,
start + del_count, len - (start + del_count),
if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0)
goto exception;
}
- if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0)
- goto exception;
}
+ if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0)
+ goto exception;
JS_FreeValue(ctx, obj);
return arr;
goto exception;
}
}
- arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
+ arr = JS_ArraySpeciesCreate(ctx, obj, 0);
if (JS_IsException(arr))
goto exception;
if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum,
JS_CFUNC_DEF("toReversed", 0, js_array_toReversed ),
JS_CFUNC_DEF("sort", 1, js_array_sort ),
JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ),
- JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ),
- JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ),
+ JS_CFUNC_DEF("slice", 2, js_array_slice ),
+ JS_CFUNC_DEF("splice", 2, js_array_splice ),
JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ),
JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),