summaryrefslogtreecommitdiff
path: root/quickjs.c
diff options
context:
space:
mode:
authorbellard <6490144+bellard@users.noreply.github.com>2022-03-06 18:53:03 +0100
committerbellard <6490144+bellard@users.noreply.github.com>2022-03-06 18:53:03 +0100
commitb9f58802dc8d3e6d8dfb65434dee63c7611c05e8 (patch)
tree52076e15675623622295fab027f4cafd1e2b837d /quickjs.c
parentb5e62895c619d4ffc75c9d822c8d85f1ece77e5b (diff)
downloadquickjs-b9f58802dc8d3e6d8dfb65434dee63c7611c05e8.tar.gz
quickjs-b9f58802dc8d3e6d8dfb65434dee63c7611c05e8.zip
fixed invalid Array.prototype.push/unshift optimization
Diffstat (limited to 'quickjs.c')
-rw-r--r--quickjs.c130
1 files changed, 64 insertions, 66 deletions
diff --git a/quickjs.c b/quickjs.c
index 48aeffc..bcf9cbc 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -37973,12 +37973,20 @@ static int JS_CopySubArray(JSContext *ctx,
JSValueConst obj, int64_t to_pos,
int64_t from_pos, int64_t count, int dir)
{
- int64_t i, from, to;
+ JSObject *p;
+ int64_t i, from, to, len;
JSValue val;
int fromPresent;
- /* XXX: should special case fast arrays */
- for (i = 0; i < count; i++) {
+ p = NULL;
+ 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) {
from = from_pos + count - i - 1;
to = to_pos + count - i - 1;
@@ -37986,16 +37994,43 @@ static int JS_CopySubArray(JSContext *ctx,
from = from_pos + i;
to = to_pos + i;
}
- fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
- if (fromPresent < 0)
- goto exception;
-
- if (fromPresent) {
- if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
- goto exception;
+ if (p && p->fast_array &&
+ from >= 0 && from < (len = p->u.array.count) &&
+ to >= 0 && to < len) {
+ int64_t l, j;
+ /* Fast path for fast arrays. Since we don't look at the
+ prototype chain, we can optimize only the cases where
+ 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 {
- if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
+ fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
+ if (fromPresent < 0)
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;
@@ -38957,64 +38992,27 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
int64_t len, from, newLen;
obj = JS_ToObject(ctx, this_val);
-
- 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 || !p->extensible)
- goto generic_case;
- /* length must be writable */
- if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE)))
- goto generic_case;
- /* check the length */
- 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;
- newLen = len + argc;
- if (newLen > MAX_SAFE_INTEGER) {
- JS_ThrowTypeError(ctx, "Array loo long");
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+ newLen = len + argc;
+ if (newLen > MAX_SAFE_INTEGER) {
+ JS_ThrowTypeError(ctx, "Array loo long");
+ goto exception;
+ }
+ from = len;
+ if (unshift && argc > 0) {
+ if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
goto exception;
- }
- 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)
+ 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;
+
JS_FreeValue(ctx, obj);
return JS_NewInt64(ctx, newLen);