fixed invalid Array.prototype.push/unshift optimization

This commit is contained in:
bellard 2022-03-06 18:53:03 +01:00
parent b5e62895c6
commit b9f58802dc

130
quickjs.c
View file

@ -37973,12 +37973,20 @@ static int JS_CopySubArray(JSContext *ctx,
JSValueConst obj, int64_t to_pos, JSValueConst obj, int64_t to_pos,
int64_t from_pos, int64_t count, int dir) int64_t from_pos, int64_t count, int dir)
{ {
int64_t i, from, to; JSObject *p;
int64_t i, from, to, len;
JSValue val; JSValue val;
int fromPresent; int fromPresent;
/* XXX: should special case fast arrays */ p = NULL;
for (i = 0; i < count; i++) { if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
p = JS_VALUE_GET_OBJ(obj);
if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) {
p = NULL;
}
}
for (i = 0; i < count; ) {
if (dir < 0) { if (dir < 0) {
from = from_pos + count - i - 1; from = from_pos + count - i - 1;
to = to_pos + count - i - 1; to = to_pos + count - i - 1;
@ -37986,16 +37994,43 @@ static int JS_CopySubArray(JSContext *ctx,
from = from_pos + i; from = from_pos + i;
to = to_pos + i; to = to_pos + i;
} }
fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val); if (p && p->fast_array &&
if (fromPresent < 0) from >= 0 && from < (len = p->u.array.count) &&
goto exception; to >= 0 && to < len) {
int64_t l, j;
if (fromPresent) { /* Fast path for fast arrays. Since we don't look at the
if (JS_SetPropertyInt64(ctx, obj, to, val) < 0) prototype chain, we can optimize only the cases where
goto exception; all the elements are present in the array. */
l = count - i;
if (dir < 0) {
l = min_int64(l, from + 1);
l = min_int64(l, to + 1);
for(j = 0; j < l; j++) {
set_value(ctx, &p->u.array.u.values[to - j],
JS_DupValue(ctx, p->u.array.u.values[from - j]));
}
} else {
l = min_int64(l, len - from);
l = min_int64(l, len - to);
for(j = 0; j < l; j++) {
set_value(ctx, &p->u.array.u.values[to + j],
JS_DupValue(ctx, p->u.array.u.values[from + j]));
}
}
i += l;
} else { } else {
if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0) fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
if (fromPresent < 0)
goto exception; goto exception;
if (fromPresent) {
if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
goto exception;
} else {
if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
goto exception;
}
i++;
} }
} }
return 0; return 0;
@ -38957,64 +38992,27 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
int64_t len, from, newLen; int64_t len, from, newLen;
obj = JS_ToObject(ctx, this_val); obj = JS_ToObject(ctx, this_val);
if (js_get_length64(ctx, &len, obj))
if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { goto exception;
JSObject *p = JS_VALUE_GET_OBJ(obj); newLen = len + argc;
if (p->class_id != JS_CLASS_ARRAY || if (newLen > MAX_SAFE_INTEGER) {
!p->fast_array || !p->extensible) JS_ThrowTypeError(ctx, "Array loo long");
goto generic_case; goto exception;
/* length must be writable */ }
if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) from = len;
goto generic_case; if (unshift && argc > 0) {
/* check the length */ if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
if (unlikely(JS_VALUE_GET_TAG(p->prop[0].u.value) != JS_TAG_INT))
goto generic_case;
len = JS_VALUE_GET_INT(p->prop[0].u.value);
/* we don't support holes */
if (unlikely(len != p->u.array.count))
goto generic_case;
newLen = len + argc;
if (unlikely(newLen > INT32_MAX))
goto generic_case;
if (newLen > p->u.array.u1.size) {
if (expand_fast_array(ctx, p, newLen))
goto exception;
}
if (unshift && argc > 0) {
memmove(p->u.array.u.values + argc, p->u.array.u.values,
len * sizeof(p->u.array.u.values[0]));
from = 0;
} else {
from = len;
}
for(i = 0; i < argc; i++) {
p->u.array.u.values[from + i] = JS_DupValue(ctx, argv[i]);
}
p->u.array.count = newLen;
p->prop[0].u.value = JS_NewInt32(ctx, newLen);
} else {
generic_case:
if (js_get_length64(ctx, &len, obj))
goto exception; goto exception;
newLen = len + argc; from = 0;
if (newLen > MAX_SAFE_INTEGER) { }
JS_ThrowTypeError(ctx, "Array loo long"); for(i = 0; i < argc; i++) {
goto exception; if (JS_SetPropertyInt64(ctx, obj, from + i,
} JS_DupValue(ctx, argv[i])) < 0)
from = len;
if (unshift && argc > 0) {
if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
goto exception;
from = 0;
}
for(i = 0; i < argc; i++) {
if (JS_SetPropertyInt64(ctx, obj, from + i,
JS_DupValue(ctx, argv[i])) < 0)
goto exception;
}
if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
goto exception; goto exception;
} }
if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
goto exception;
JS_FreeValue(ctx, obj); JS_FreeValue(ctx, obj);
return JS_NewInt64(ctx, newLen); return JS_NewInt64(ctx, newLen);