Skip to content

Commit b9f5880

Browse files
committed
fixed invalid Array.prototype.push/unshift optimization
1 parent b5e6289 commit b9f5880

File tree

1 file changed

+64
-66
lines changed

1 file changed

+64
-66
lines changed

quickjs.c

Lines changed: 64 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -37973,29 +37973,64 @@ static int JS_CopySubArray(JSContext *ctx,
3797337973
JSValueConst obj, int64_t to_pos,
3797437974
int64_t from_pos, int64_t count, int dir)
3797537975
{
37976-
int64_t i, from, to;
37976+
JSObject *p;
37977+
int64_t i, from, to, len;
3797737978
JSValue val;
3797837979
int fromPresent;
3797937980

37980-
/* XXX: should special case fast arrays */
37981-
for (i = 0; i < count; i++) {
37981+
p = NULL;
37982+
if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
37983+
p = JS_VALUE_GET_OBJ(obj);
37984+
if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) {
37985+
p = NULL;
37986+
}
37987+
}
37988+
37989+
for (i = 0; i < count; ) {
3798237990
if (dir < 0) {
3798337991
from = from_pos + count - i - 1;
3798437992
to = to_pos + count - i - 1;
3798537993
} else {
3798637994
from = from_pos + i;
3798737995
to = to_pos + i;
3798837996
}
37989-
fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
37990-
if (fromPresent < 0)
37991-
goto exception;
37992-
37993-
if (fromPresent) {
37994-
if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
37995-
goto exception;
37997+
if (p && p->fast_array &&
37998+
from >= 0 && from < (len = p->u.array.count) &&
37999+
to >= 0 && to < len) {
38000+
int64_t l, j;
38001+
/* Fast path for fast arrays. Since we don't look at the
38002+
prototype chain, we can optimize only the cases where
38003+
all the elements are present in the array. */
38004+
l = count - i;
38005+
if (dir < 0) {
38006+
l = min_int64(l, from + 1);
38007+
l = min_int64(l, to + 1);
38008+
for(j = 0; j < l; j++) {
38009+
set_value(ctx, &p->u.array.u.values[to - j],
38010+
JS_DupValue(ctx, p->u.array.u.values[from - j]));
38011+
}
38012+
} else {
38013+
l = min_int64(l, len - from);
38014+
l = min_int64(l, len - to);
38015+
for(j = 0; j < l; j++) {
38016+
set_value(ctx, &p->u.array.u.values[to + j],
38017+
JS_DupValue(ctx, p->u.array.u.values[from + j]));
38018+
}
38019+
}
38020+
i += l;
3799638021
} else {
37997-
if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
38022+
fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
38023+
if (fromPresent < 0)
3799838024
goto exception;
38025+
38026+
if (fromPresent) {
38027+
if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
38028+
goto exception;
38029+
} else {
38030+
if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
38031+
goto exception;
38032+
}
38033+
i++;
3799938034
}
3800038035
}
3800138036
return 0;
@@ -38957,64 +38992,27 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
3895738992
int64_t len, from, newLen;
3895838993

3895938994
obj = JS_ToObject(ctx, this_val);
38960-
38961-
if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
38962-
JSObject *p = JS_VALUE_GET_OBJ(obj);
38963-
if (p->class_id != JS_CLASS_ARRAY ||
38964-
!p->fast_array || !p->extensible)
38965-
goto generic_case;
38966-
/* length must be writable */
38967-
if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE)))
38968-
goto generic_case;
38969-
/* check the length */
38970-
if (unlikely(JS_VALUE_GET_TAG(p->prop[0].u.value) != JS_TAG_INT))
38971-
goto generic_case;
38972-
len = JS_VALUE_GET_INT(p->prop[0].u.value);
38973-
/* we don't support holes */
38974-
if (unlikely(len != p->u.array.count))
38975-
goto generic_case;
38976-
newLen = len + argc;
38977-
if (unlikely(newLen > INT32_MAX))
38978-
goto generic_case;
38979-
if (newLen > p->u.array.u1.size) {
38980-
if (expand_fast_array(ctx, p, newLen))
38981-
goto exception;
38982-
}
38983-
if (unshift && argc > 0) {
38984-
memmove(p->u.array.u.values + argc, p->u.array.u.values,
38985-
len * sizeof(p->u.array.u.values[0]));
38986-
from = 0;
38987-
} else {
38988-
from = len;
38989-
}
38990-
for(i = 0; i < argc; i++) {
38991-
p->u.array.u.values[from + i] = JS_DupValue(ctx, argv[i]);
38992-
}
38993-
p->u.array.count = newLen;
38994-
p->prop[0].u.value = JS_NewInt32(ctx, newLen);
38995-
} else {
38996-
generic_case:
38997-
if (js_get_length64(ctx, &len, obj))
38998-
goto exception;
38999-
newLen = len + argc;
39000-
if (newLen > MAX_SAFE_INTEGER) {
39001-
JS_ThrowTypeError(ctx, "Array loo long");
38995+
if (js_get_length64(ctx, &len, obj))
38996+
goto exception;
38997+
newLen = len + argc;
38998+
if (newLen > MAX_SAFE_INTEGER) {
38999+
JS_ThrowTypeError(ctx, "Array loo long");
39000+
goto exception;
39001+
}
39002+
from = len;
39003+
if (unshift && argc > 0) {
39004+
if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
3900239005
goto exception;
39003-
}
39004-
from = len;
39005-
if (unshift && argc > 0) {
39006-
if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
39007-
goto exception;
39008-
from = 0;
39009-
}
39010-
for(i = 0; i < argc; i++) {
39011-
if (JS_SetPropertyInt64(ctx, obj, from + i,
39012-
JS_DupValue(ctx, argv[i])) < 0)
39013-
goto exception;
39014-
}
39015-
if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
39006+
from = 0;
39007+
}
39008+
for(i = 0; i < argc; i++) {
39009+
if (JS_SetPropertyInt64(ctx, obj, from + i,
39010+
JS_DupValue(ctx, argv[i])) < 0)
3901639011
goto exception;
3901739012
}
39013+
if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
39014+
goto exception;
39015+
3901839016
JS_FreeValue(ctx, obj);
3901939017
return JS_NewInt64(ctx, newLen);
3902039018

0 commit comments

Comments
 (0)