]> git.kaiwu.me - njs.git/commitdiff
Introduced ToLength() according to ES6.
authorDmitry Volyntsev <xeioex@nginx.com>
Mon, 17 Feb 2020 13:13:43 +0000 (16:13 +0300)
committerDmitry Volyntsev <xeioex@nginx.com>
Mon, 17 Feb 2020 13:13:43 +0000 (16:13 +0300)
Since ES6, according to the spec maximum length value is 2**53 - 1 not
2**32 - 1, so uint64_t data type is required.

16 files changed:
src/njs_array.c
src/njs_array.h
src/njs_chb.h
src/njs_function.c
src/njs_json.c
src/njs_number.c
src/njs_number.h
src/njs_object.c
src/njs_object.h
src/njs_regexp.c
src/njs_string.c
src/njs_typed_array.c
src/njs_value.c
src/njs_value.h
src/njs_value_conversion.h
src/test/njs_unit_test.c

index fb5da0f80ba641553de4a58740e1bb4c73aaf2fc..59c3b7e471fe8573f3b0ff5885324730ec8cbbce 100644 (file)
@@ -18,13 +18,13 @@ typedef struct {
 
     njs_array_t     *array;
 
-    uint32_t        from;
-    uint32_t        to;
+    int64_t        from;
+    int64_t        to;
 } njs_array_iterator_args_t;
 
 
 typedef njs_int_t (*njs_array_iterator_handler_t)(njs_vm_t *vm,
-    njs_array_iterator_args_t *args, njs_value_t *entry, uint32_t n);
+    njs_array_iterator_args_t *args, njs_value_t *entry, uint64_t n);
 
 
 static njs_int_t njs_array_prototype_slice_copy(njs_vm_t *vm,
@@ -128,9 +128,8 @@ njs_array_convert_to_slow_array(njs_vm_t *vm, njs_array_t *array)
     length = array->length;
 
     for (i = 0; i < length; i++) {
-        njs_uint32_to_string(&index, i);
-
         if (njs_is_valid(&array->start[i])) {
+            njs_uint32_to_string(&index, i);
             prop = njs_object_property_add(vm, &value, &index, 0);
             if (njs_slow_path(prop == NULL)) {
                 return NJS_ERROR;
@@ -183,7 +182,8 @@ njs_array_length_set(njs_vm_t *vm, njs_value_t *value,
     njs_object_prop_t *prev, njs_value_t *setval)
 {
     double        num, idx;
-    uint32_t      i, length, prev_length;
+    uint32_t      i, length;
+    uint64_t      prev_length;
     njs_int_t     ret;
     njs_array_t   *array, *keys;
 
@@ -197,7 +197,7 @@ njs_array_length_set(njs_vm_t *vm, njs_value_t *value,
         return ret;
     }
 
-    length = njs_number_to_length(num);
+    length = (uint32_t) njs_number_to_length(num);
     if ((double) length != num) {
         njs_range_error(vm, "Invalid array length");
         return NJS_ERROR;
@@ -306,7 +306,7 @@ njs_array_expand(njs_vm_t *vm, njs_array_t *array, uint32_t prepend,
         size += size / 2;
     }
 
-    if (njs_slow_path(size > NJS_ARRAY_MAX_LENGTH)) {
+    if (njs_slow_path(size > (UINT32_MAX / sizeof(njs_value_t)))) {
         goto memory_error;
     }
 
@@ -354,7 +354,7 @@ njs_array_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     if (size == 1 && njs_is_number(&args[0])) {
         num = njs_number(&args[0]);
-        size = (uint32_t) num;
+        size = (uint32_t) njs_number_to_length(num);
 
         if ((double) size != num) {
             njs_range_error(vm, "Invalid array length");
@@ -529,7 +529,7 @@ njs_array_length(njs_vm_t *vm,njs_object_prop_t *prop, njs_value_t *value,
         return ret;
     }
 
-    length = njs_number_to_length(num);
+    length = (uint32_t) njs_number_to_length(num);
     if ((double) length != num) {
         njs_range_error(vm, "Invalid array length");
         return NJS_ERROR;
@@ -582,7 +582,7 @@ njs_array_prototype_slice(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
     int64_t      start, end, length;
-    uint32_t     object_length;
+    uint64_t     object_length;
     njs_int_t    ret;
     njs_value_t  *this;
 
@@ -658,7 +658,7 @@ njs_array_prototype_slice_copy(njs_vm_t *vm, njs_value_t *this,
     uint32_t           n;
     njs_int_t          ret;
     njs_array_t        *array, *keys;
-    njs_value_t        *value, index, retval, array_value;
+    njs_value_t        *value, retval, self;
     const u_char       *src, *end;
     njs_slice_prop_t   string_slice;
     njs_string_prop_t  string;
@@ -688,10 +688,8 @@ njs_array_prototype_slice_copy(njs_vm_t *vm, njs_value_t *this,
 
                     /* src value may be in Array.prototype object. */
 
-                    njs_uint32_to_string(&index, start++);
-
                     value = &array->start[n++];
-                    ret = njs_value_property(vm, this, &index, value);
+                    ret = njs_value_property_i64(vm, this, start++, value);
                     if (njs_slow_path(ret == NJS_ERROR)) {
                         return NJS_ERROR;
                     }
@@ -746,10 +744,8 @@ njs_array_prototype_slice_copy(njs_vm_t *vm, njs_value_t *this,
         } else if (njs_is_object(this)) {
 
             do {
-                njs_uint32_to_string(&index, start++);
-
                 value = &array->start[n++];
-                ret = njs_value_property(vm, this, &index, value);
+                ret = njs_value_property_i64(vm, this, start++, value);
 
                 if (ret != NJS_OK) {
                     njs_set_invalid(value);
@@ -774,19 +770,17 @@ njs_array_prototype_slice_copy(njs_vm_t *vm, njs_value_t *this,
         goto done;
     }
 
-    njs_set_array(&array_value, array);
+    njs_set_array(&self, array);
 
     if (njs_fast_object(length)) {
         do {
-            njs_uint32_to_string(&index, start++);
-
-            ret = njs_value_property(vm, this, &index, &retval);
+            ret = njs_value_property_i64(vm, this, start++, &retval);
             if (njs_slow_path(ret == NJS_ERROR)) {
                 return NJS_ERROR;
             }
 
             if (ret == NJS_OK) {
-                ret = njs_value_property_set(vm, &array_value, &index, &retval);
+                ret = njs_value_property_i64_set(vm, &self, start, &retval);
                 if (njs_slow_path(ret == NJS_ERROR)) {
                     return ret;
                 }
@@ -810,8 +804,7 @@ njs_array_prototype_slice_copy(njs_vm_t *vm, njs_value_t *this,
             goto done;
         }
 
-        ret = njs_value_property_set(vm, &array_value, &keys->start[n],
-                                     &retval);
+        ret = njs_value_property_set(vm, &self, &keys->start[n], &retval);
         if (njs_slow_path(ret == NJS_ERROR)) {
             goto done;
         }
@@ -835,11 +828,11 @@ static njs_int_t
 njs_array_prototype_push(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    uint32_t     length;
+    uint64_t     length;
     njs_int_t    ret;
     njs_uint_t   i;
     njs_array_t  *array;
-    njs_value_t  *this, index;
+    njs_value_t  *this;
 
     length = 0;
     this = njs_argument(args, 0);
@@ -874,10 +867,13 @@ njs_array_prototype_push(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         return ret;
     }
 
-    for (i = 1; i < nargs; i++) {
-        njs_uint32_to_string(&index, length++);
+    if (njs_slow_path((length + nargs - 1) > NJS_MAX_LENGTH)) {
+        njs_type_error(vm, "Invalid length");
+        return NJS_ERROR;
+    }
 
-        ret = njs_value_property_set(vm, this, &index, &args[i]);
+    for (i = 1; i < nargs; i++) {
+        ret = njs_value_property_i64_set(vm, this, length++, &args[i]);
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
         }
@@ -898,10 +894,10 @@ static njs_int_t
 njs_array_prototype_pop(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    uint32_t     length;
+    uint64_t     length;
     njs_int_t    ret;
     njs_array_t  *array;
-    njs_value_t  *this, *entry, index;
+    njs_value_t  *this, *entry;
 
     this = njs_argument(args, 0);
 
@@ -921,6 +917,15 @@ njs_array_prototype_pop(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
             if (njs_is_valid(entry)) {
                 vm->retval = *entry;
+
+            } else {
+                /* src value may be in Array.prototype object. */
+
+                ret = njs_value_property_i64(vm, this, array->length,
+                                             &vm->retval);
+                if (njs_slow_path(ret == NJS_ERROR)) {
+                    return NJS_ERROR;
+                }
             }
         }
 
@@ -932,15 +937,23 @@ njs_array_prototype_pop(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         return ret;
     }
 
-    if (length != 0) {
-        njs_uint32_to_string(&index, --length);
+    if (length == 0) {
+        njs_set_undefined(&vm->retval);
+        goto done;
+    }
 
-        ret = njs_value_property_delete(vm, this, &index, &vm->retval);
-        if (njs_slow_path(ret == NJS_ERROR)) {
-            return ret;
-        }
+    ret = njs_value_property_i64(vm, this, --length, &vm->retval);
+    if (njs_slow_path(ret == NJS_ERROR)) {
+        return ret;
+    }
+
+    ret = njs_value_property_i64_delete(vm, this, length, NULL);
+    if (njs_slow_path(ret == NJS_ERROR)) {
+        return ret;
     }
 
+done:
+
     ret = njs_object_length_set(vm, this, length);
     if (njs_slow_path(ret == NJS_ERROR)) {
         return ret;
@@ -955,11 +968,11 @@ njs_array_prototype_unshift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
     double       idx;
-    uint32_t     from, to, length;
+    uint64_t     from, to, length;
     njs_int_t    ret;
     njs_uint_t   n;
     njs_array_t  *array, *keys;
-    njs_value_t  *this, entry, index;
+    njs_value_t  *this, entry;
 
     this = njs_argument(args, 0);
     length = 0;
@@ -970,14 +983,9 @@ njs_array_prototype_unshift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         return ret;
     }
 
-    if (njs_is_fast_array(this)) {
+    if (njs_fast_path(njs_is_fast_array(this))) {
         array = njs_array(this);
 
-        if (array->length > (UINT32_MAX - n)) {
-            njs_type_error(vm, "Invalid length");
-            return NJS_ERROR;
-        }
-
         if (n != 0) {
             ret = njs_array_expand(vm, array, n, 0);
             if (njs_slow_path(ret != NJS_OK)) {
@@ -1009,7 +1017,7 @@ njs_array_prototype_unshift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         goto done;
     }
 
-    if (length > (UINT32_MAX - n)) {
+    if (njs_slow_path((length + n) > NJS_MAX_LENGTH)) {
         njs_type_error(vm, "Invalid length");
         return NJS_ERROR;
     }
@@ -1031,11 +1039,9 @@ njs_array_prototype_unshift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             }
 
             if (ret == NJS_OK) {
-                idx = njs_string_to_index(&keys->start[from]);
-
-                njs_uint32_to_string(&index, (uint32_t) idx + nargs - 1);
+                idx = njs_string_to_index(&keys->start[from]) + n;
 
-                ret = njs_value_property_set(vm, this, &index, &entry);
+                ret = njs_value_property_i64_set(vm, this, idx, &entry);
                 if (njs_slow_path(ret == NJS_ERROR)) {
                     njs_array_destroy(vm, keys);
                     return ret;
@@ -1045,7 +1051,7 @@ njs_array_prototype_unshift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
         njs_array_destroy(vm, keys);
 
-        length += nargs - 1;
+        length += n;
 
         goto copy;
     }
@@ -1055,9 +1061,7 @@ njs_array_prototype_unshift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     to = length;
 
     while (from > 0) {
-        njs_uint32_to_string(&index, --from);
-
-        ret = njs_value_property_delete(vm, this, &index, &entry);
+        ret = njs_value_property_i64_delete(vm, this, --from, &entry);
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
         }
@@ -1065,9 +1069,7 @@ njs_array_prototype_unshift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         to--;
 
         if (ret == NJS_OK) {
-            njs_uint32_to_string(&index, to);
-
-            ret = njs_value_property_set(vm, this, &index, &entry);
+            ret = njs_value_property_i64_set(vm, this, to, &entry);
             if (njs_slow_path(ret == NJS_ERROR)) {
                 return ret;
             }
@@ -1077,9 +1079,7 @@ njs_array_prototype_unshift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 copy:
 
     for (n = 1; n < nargs; n++) {
-        njs_uint32_to_string(&index, n - 1);
-
-        ret = njs_value_property_set(vm, this, &index, &args[n]);
+        ret = njs_value_property_i64_set(vm, this, n - 1, &args[n]);
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
         }
@@ -1102,10 +1102,10 @@ static njs_int_t
 njs_array_prototype_shift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    uint32_t     i, length;
+    uint64_t     i, length;
     njs_int_t    ret;
     njs_array_t  *array;
-    njs_value_t  *this, *item, entry, index;
+    njs_value_t  *this, *item, entry;
 
     this = njs_argument(args, 0);
     length = 0;
@@ -1122,13 +1122,21 @@ njs_array_prototype_shift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
         if (array->length != 0) {
             array->length--;
-
             item = &array->start[0];
-            array->start++;
 
             if (njs_is_valid(item)) {
                 vm->retval = *item;
+
+            } else {
+                /* src value may be in Array.prototype object. */
+
+                ret = njs_value_property_i64(vm, this, 0, &vm->retval);
+                if (njs_slow_path(ret == NJS_ERROR)) {
+                    return NJS_ERROR;
+                }
             }
+
+            array->start++;
         }
 
         return NJS_OK;
@@ -1143,25 +1151,19 @@ njs_array_prototype_shift(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         goto done;
     }
 
-    njs_uint32_to_string(&index, 0);
-
-    ret = njs_value_property_delete(vm, this, &index, &vm->retval);
+    ret = njs_value_property_i64_delete(vm, this, 0, &vm->retval);
     if (njs_slow_path(ret == NJS_ERROR)) {
         return ret;
     }
 
     for (i = 1; i < length; i++) {
-        njs_uint32_to_string(&index, i);
-
-        ret = njs_value_property_delete(vm, this, &index, &entry);
+        ret = njs_value_property_i64_delete(vm, this, i, &entry);
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
         }
 
         if (ret == NJS_OK) {
-            njs_uint32_to_string(&index, i - 1);
-
-            ret = njs_value_property_set(vm, this, &index, &entry);
+            ret = njs_value_property_i64_set(vm, this, i - 1, &entry);
             if (njs_slow_path(ret == NJS_ERROR)) {
                 return ret;
             }
@@ -1304,7 +1306,7 @@ static njs_int_t
 njs_array_prototype_reverse(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    uint32_t     length;
+    uint64_t     length;
     njs_int_t    ret;
     njs_uint_t   i, n;
     njs_value_t  value, *this;
@@ -1385,15 +1387,13 @@ njs_array_prototype_join(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
     u_char             *p, *last;
-    size_t             size;
-    ssize_t            length;
-    uint32_t           len;
+    int64_t            length;
+    uint64_t           i, len, size;
     njs_int_t          ret;
     njs_chb_t          chain;
     njs_utf8_t         utf8;
-    njs_uint_t         i;
     njs_array_t        *array;
-    njs_value_t        *value, *this, index, entry;
+    njs_value_t        *value, *this, entry;
     njs_string_prop_t  separator, string;
 
     this = njs_argument(args, 0);
@@ -1447,13 +1447,13 @@ njs_array_prototype_join(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_chb_init(&chain, vm->mem_pool);
 
     for (i = 0; i < len; i++) {
-        if (njs_fast_path(array != NULL)) {
+        if (njs_fast_path(njs_object(this)->fast_array
+                          && njs_is_valid(&array->start[i])))
+        {
             value = &array->start[i];
 
         } else {
-            njs_uint32_to_string(&index, i);
-
-            ret = njs_value_property(vm, this, &index, &entry);
+            ret = njs_value_property_i64(vm, this, i, &entry);
             if (njs_slow_path(ret == NJS_ERROR)) {
                 return ret;
             }
@@ -1493,6 +1493,11 @@ njs_array_prototype_join(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
         length += separator.length;
         njs_chb_append(&chain, separator.start, separator.size);
+
+        if (njs_slow_path(length > NJS_STRING_MAX_LENGTH)) {
+            njs_range_error(vm, "invalid string length");
+            return NJS_ERROR;
+        }
     }
 
     njs_chb_drop(&chain, separator.size);
@@ -1597,14 +1602,22 @@ njs_array_indices(njs_vm_t *vm, const njs_value_t *object)
 
 njs_inline njs_int_t
 njs_array_object_handler(njs_vm_t *vm, njs_array_iterator_handler_t handler,
-    njs_array_iterator_args_t *args, njs_value_t *key, uint32_t i)
+    njs_array_iterator_args_t *args, njs_value_t *key, uint64_t i)
 {
     njs_int_t    ret;
     njs_value_t  prop, *entry;
 
-    ret = njs_value_property(vm, args->value, key, &prop);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return ret;
+    if (key != NULL) {
+        ret = njs_value_property(vm, args->value, key, &prop);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return ret;
+        }
+
+    } else {
+        ret = njs_value_property_i64(vm, args->value, i, &prop);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return ret;
+        }
     }
 
     entry = (ret == NJS_OK) ? &prop : njs_value_arg(&njs_value_invalid);
@@ -1627,10 +1640,10 @@ njs_array_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
     njs_array_iterator_handler_t handler)
 {
     double             idx;
-    uint32_t           length, i, from, to;
+    uint64_t           length, i, from, to;
     njs_int_t          ret;
-    njs_array_t        *keys;
-    njs_value_t        *value, character, index, string_obj;
+    njs_array_t        *array, *keys;
+    njs_value_t        *value, *entry, prop, character, string_obj;
     njs_object_t       *object;
     const u_char       *p, *end, *pos;
     njs_string_prop_t  string_prop;
@@ -1640,16 +1653,30 @@ njs_array_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
     to = args->to;
 
     if (njs_is_array(value)) {
-        if (njs_slow_path(!njs_is_fast_array(value))) {
-            goto process_object;
-        }
+        array = njs_array(value);
 
-        for (i = from; i < to; i++) {
-            if (i < njs_array_len(value)) {
-                ret = handler(vm, args, &njs_array_start(value)[i], i);
+        for (; from < to; from++) {
+            if (njs_slow_path(!array->object.fast_array)) {
+                goto process_object;
+            }
+
+            if (njs_fast_path(from < array->length
+                              && njs_is_valid(&array->start[from])))
+            {
+                ret = handler(vm, args, &array->start[from], from);
 
             } else {
-                ret = handler(vm, args, njs_value_arg(&njs_value_invalid), i);
+                entry = njs_value_arg(&njs_value_invalid);
+                ret = njs_value_property_i64(vm, value, from, &prop);
+                if (njs_slow_path(ret != NJS_DECLINED)) {
+                    if (ret == NJS_ERROR) {
+                        return NJS_ERROR;
+                    }
+
+                    entry = &prop;
+                }
+
+                ret = handler(vm, args, entry, from);
             }
 
             if (njs_slow_path(ret != NJS_OK)) {
@@ -1680,7 +1707,7 @@ njs_array_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
             value = njs_object_value(value);
         }
 
-        length = (uint32_t) njs_string_prop(&string_prop, value);
+        length = njs_string_prop(&string_prop, value);
 
         p = string_prop.start;
         end = p + string_prop.size;
@@ -1760,9 +1787,7 @@ process_object:
     }
 
     for (i = from; i < to; i++) {
-        njs_uint32_to_string(&index, i);
-
-        ret = njs_array_object_handler(vm, handler, args, &index, i);
+        ret = njs_array_object_handler(vm, handler, args, NULL, i);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
@@ -1777,10 +1802,10 @@ njs_array_reverse_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
     njs_array_iterator_handler_t handler)
 {
     double             idx;
-    uint32_t           i, from, to, length;
+    uint64_t           i, from, to, length;
     njs_int_t          ret;
-    njs_array_t        *keys;
-    njs_value_t        *entry, *value, character, index, string_obj;
+    njs_array_t        *array, *keys;
+    njs_value_t        *entry, *value, prop, character, string_obj;
     njs_object_t       *object;
     const u_char       *p, *end, *pos;
     njs_string_prop_t  string_prop;
@@ -1790,16 +1815,34 @@ njs_array_reverse_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
     to = args->to;
 
     if (njs_is_array(value)) {
-        if (njs_slow_path(!njs_is_fast_array(value))) {
-            goto process_object;
-        }
+        array = njs_array(value);
 
-        i = from + 1;
+        from += 1;
 
-        while (i-- > to) {
-            entry = &njs_array_start(value)[i];
+        while (from-- > to) {
+            if (njs_slow_path(!array->object.fast_array)) {
+                goto process_object;
+            }
+
+            if (njs_fast_path(from < array->length
+                              && njs_is_valid(&array->start[from])))
+            {
+                ret = handler(vm, args, &array->start[from], from);
+
+            } else {
+                entry = njs_value_arg(&njs_value_invalid);
+                ret = njs_value_property_i64(vm, value, from, &prop);
+                if (njs_slow_path(ret != NJS_DECLINED)) {
+                    if (ret == NJS_ERROR) {
+                        return NJS_ERROR;
+                    }
+
+                    entry = &prop;
+                }
+
+                ret = handler(vm, args, entry, from);
+            }
 
-            ret = handler(vm, args, entry, i);
             if (njs_slow_path(ret != NJS_OK)) {
                 if (ret > 0) {
                     return NJS_DECLINED;
@@ -1828,7 +1871,7 @@ njs_array_reverse_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
             value = njs_object_value(value);
         }
 
-        length = (uint32_t) njs_string_prop(&string_prop, value);
+        length = njs_string_prop(&string_prop, value);
         end = string_prop.start + string_prop.size;
 
         if (length == string_prop.size) {
@@ -1921,9 +1964,7 @@ process_object:
     i = from + 1;
 
     while (i-- > to) {
-        njs_uint32_to_string(&index, i);
-
-        ret = njs_array_object_handler(vm, handler, args, &index, i);
+        ret = njs_array_object_handler(vm, handler, args, NULL, i);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
@@ -1964,11 +2005,9 @@ njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
     double       idx;
-    uint32_t     len;
-    uint64_t     length;
+    uint64_t     i, k, len, length;
     njs_int_t    ret;
-    njs_uint_t   i, k;
-    njs_value_t  this, index, retval, *value, *e;
+    njs_value_t  this, retval, *value, *e;
     njs_array_t  *array, *keys;
 
     ret = njs_value_to_object(vm, &args[0]);
@@ -2002,7 +2041,7 @@ njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
                 return ret;
             }
 
-            if (njs_slow_path((length + len) >= NJS_ARRAY_MAX_LENGTH53)) {
+            if (njs_slow_path((length + len) > NJS_MAX_LENGTH)) {
                 njs_type_error(vm, "Invalid length");
                 return NJS_ERROR;
             }
@@ -2014,9 +2053,7 @@ njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
                     value = &njs_array_start(e)[k];
 
                     if (njs_slow_path(!njs_is_valid(value))) {
-                        njs_uint32_to_string(&index, k);
-                        ret = njs_value_property(vm, e, &index,
-                                                 &retval);
+                        ret = njs_value_property_i64(vm, e, k, &retval);
                         if (njs_slow_path(ret == NJS_ERROR)) {
                             return ret;
                         }
@@ -2039,9 +2076,7 @@ njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
             if (njs_fast_object(len)) {
                 for (k = 0; k < len; k++, length++) {
-                    njs_uint32_to_string(&index, k);
-
-                    ret = njs_value_property(vm, e, &index, &retval);
+                    ret = njs_value_property_i64(vm, e, k, &retval);
                     if (njs_slow_path(ret == NJS_ERROR)) {
                         return ret;
                     }
@@ -2050,9 +2085,8 @@ njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
                         continue;
                     }
 
-                    njs_uint32_to_string(&index, length);
-
-                    ret = njs_value_property_set(vm, &this, &index, &retval);
+                    ret = njs_value_property_i64_set(vm, &this, length,
+                                                     &retval);
                     if (njs_slow_path(ret == NJS_ERROR)) {
                         return ret;
                     }
@@ -2072,12 +2106,10 @@ njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
                     return ret;
                 }
 
-                idx = njs_string_to_index(&keys->start[k]);
+                idx = njs_string_to_index(&keys->start[k]) + length;
 
                 if (ret == NJS_OK) {
-                    njs_uint32_to_string(&index, length + idx);
-
-                    ret = njs_value_property_set(vm, &this, &index, &retval);
+                    ret = njs_value_property_i64_set(vm, &this, idx, &retval);
                     if (njs_slow_path(ret == NJS_ERROR)) {
                         njs_array_destroy(vm, keys);
                         return ret;
@@ -2092,7 +2124,7 @@ njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             continue;
         }
 
-        if (njs_slow_path((length + len) >= NJS_ARRAY_MAX_LENGTH53)) {
+        if (njs_slow_path((length + len) >= NJS_MAX_LENGTH)) {
             njs_type_error(vm, "Invalid length");
             return NJS_ERROR;
         }
@@ -2104,9 +2136,7 @@ njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             }
 
         } else {
-            njs_uint32_to_string(&index, length);
-
-            ret = njs_value_property_set(vm, &this, &index, e);
+            ret = njs_value_property_i64_set(vm, &this, length, e);
             if (njs_slow_path(ret == NJS_ERROR)) {
                 return ret;
             }
@@ -2128,7 +2158,7 @@ njs_array_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
 static njs_int_t
 njs_array_handler_index_of(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     if (njs_values_strict_equal(args->argument, entry)) {
         njs_set_number(&vm->retval, n);
@@ -2145,7 +2175,7 @@ njs_array_prototype_index_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
     int64_t                    from;
-    uint32_t                   length;
+    uint64_t                   length;
     njs_int_t                  ret;
     njs_array_iterator_args_t  iargs;
 
@@ -2180,12 +2210,12 @@ njs_array_prototype_index_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         }
     }
 
-    iargs.from = (uint32_t) from;
+    iargs.from = from;
     iargs.to = length;
 
     ret = njs_array_iterator(vm, &iargs, njs_array_handler_index_of);
-    if (njs_fast_path(ret == NJS_DECLINED)) {
-        return NJS_OK;
+    if (njs_fast_path(ret != NJS_OK)) {
+        return (ret == NJS_DECLINED) ? NJS_OK : NJS_ERROR;
     }
 
 not_found:
@@ -2201,7 +2231,7 @@ njs_array_prototype_last_index_of(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused)
 {
     int64_t                    from;
-    uint32_t                   length;
+    uint64_t                   length;
     njs_int_t                  ret;
     njs_array_iterator_args_t  iargs;
 
@@ -2234,7 +2264,7 @@ njs_array_prototype_last_index_of(njs_vm_t *vm, njs_value_t *args,
     }
 
     if (from >= 0) {
-        from = njs_min(from, length - 1);
+        from = njs_min((uint64_t) from, length - 1);
 
     } else if (from < 0) {
         from += length;
@@ -2248,8 +2278,8 @@ njs_array_prototype_last_index_of(njs_vm_t *vm, njs_value_t *args,
     iargs.to = 0;
 
     ret = njs_array_reverse_iterator(vm, &iargs, njs_array_handler_index_of);
-    if (njs_fast_path(ret == NJS_DECLINED)) {
-        return NJS_OK;
+    if (njs_fast_path(ret != NJS_OK)) {
+        return (ret == NJS_DECLINED) ? NJS_OK : NJS_ERROR;
     }
 
 not_found:
@@ -2262,7 +2292,7 @@ not_found:
 
 static njs_int_t
 njs_array_handler_includes(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     if (!njs_is_valid(entry)) {
         entry = njs_value_arg(&njs_value_undefined);
@@ -2283,7 +2313,7 @@ njs_array_prototype_includes(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
     int64_t                    from;
-    uint32_t                   length;
+    uint64_t                   length;
     njs_int_t                  ret;
     njs_array_iterator_args_t  iargs;
 
@@ -2318,12 +2348,12 @@ njs_array_prototype_includes(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         }
     }
 
-    iargs.from = (uint32_t) from;
+    iargs.from = from;
     iargs.to = length;
 
     ret = njs_array_iterator(vm, &iargs, njs_array_handler_includes);
-    if (njs_fast_path(ret == NJS_DECLINED)) {
-        return NJS_OK;
+    if (njs_fast_path(ret != NJS_OK)) {
+        return (ret == NJS_DECLINED) ? NJS_OK : NJS_ERROR;
     }
 
 not_found:
@@ -2338,11 +2368,10 @@ static njs_int_t
 njs_array_prototype_fill(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    int64_t       start, end;
-    uint32_t      length;
-    njs_int_t     i, ret;
+    int64_t       i, length, start, end;
+    njs_int_t     ret;
     njs_array_t   *array;
-    njs_value_t   name, *this, *value;
+    njs_value_t   *this, *value;
 
     this = njs_argument(args, 0);
 
@@ -2358,7 +2387,7 @@ njs_array_prototype_fill(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         length = array->length;
 
     } else {
-        ret = njs_object_length(vm, this, &length);
+        ret = njs_object_length(vm, this, (uint64_t *) &length);
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
         }
@@ -2398,9 +2427,7 @@ njs_array_prototype_fill(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     value = njs_arg(args, nargs, 1);
 
     while (start < end) {
-        njs_uint32_to_string(&name, start++);
-
-        ret = njs_value_property_set(vm, this, &name, value);
+        ret = njs_value_property_i64_set(vm, this, start++, value);
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
         }
@@ -2442,7 +2469,7 @@ njs_array_validate_args(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         return ret;
     }
 
-    ret = njs_value_length(vm, iargs->value, &iargs->to);
+    ret = njs_value_length(vm, iargs->value, (uint64_t *) &iargs->to);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -2467,7 +2494,7 @@ failed:
 
 static njs_int_t
 njs_array_handler_for_each(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     if (njs_is_valid(entry)) {
         return njs_array_iterator_call(vm, args, entry, n);
@@ -2502,7 +2529,7 @@ njs_array_prototype_for_each(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
 static njs_int_t
 njs_array_handler_some(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     njs_int_t  ret;
 
@@ -2550,7 +2577,7 @@ njs_array_prototype_some(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
 static njs_int_t
 njs_array_handler_every(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     njs_int_t  ret;
 
@@ -2598,7 +2625,7 @@ njs_array_prototype_every(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
 static njs_int_t
 njs_array_handler_filter(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     njs_int_t    ret;
     njs_value_t  copy;
@@ -2654,7 +2681,7 @@ njs_array_prototype_filter(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
 static njs_int_t
 njs_array_handler_find(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     njs_int_t    ret;
     njs_value_t  copy;
@@ -2708,7 +2735,7 @@ njs_array_prototype_find(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
 static njs_int_t
 njs_array_handler_find_index(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     njs_int_t    ret;
     njs_value_t  copy;
@@ -2762,11 +2789,11 @@ njs_array_prototype_find_index(njs_vm_t *vm, njs_value_t *args,
 
 static njs_int_t
 njs_array_handler_map(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     njs_int_t    ret;
     njs_array_t  *retval;
-    njs_value_t  this, key;
+    njs_value_t  this;
 
     retval = args->array;
 
@@ -2786,9 +2813,8 @@ njs_array_handler_map(njs_vm_t *vm, njs_array_iterator_args_t *args,
 
             } else {
                 njs_set_array(&this, retval);
-                njs_uint32_to_string(&key, n);
 
-                ret = njs_value_property_set(vm, &this, &key, &vm->retval);
+                ret = njs_value_property_i64_set(vm, &this, n, &vm->retval);
                 if (njs_slow_path(ret != NJS_OK)) {
                     return ret;
                 }
@@ -2804,7 +2830,7 @@ static njs_int_t
 njs_array_prototype_map(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    uint32_t                   length, i;
+    uint64_t                   length, i;
     njs_int_t                  ret;
     njs_array_t                *array;
     njs_value_t                *this;
@@ -2870,7 +2896,7 @@ unexpected_args:
 
 njs_inline njs_int_t
 njs_array_iterator_reduce(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     njs_value_t  arguments[5];
 
@@ -2888,7 +2914,7 @@ njs_array_iterator_reduce(njs_vm_t *vm, njs_array_iterator_args_t *args,
 
 static njs_int_t
 njs_array_handler_reduce(njs_vm_t *vm, njs_array_iterator_args_t *args,
-    njs_value_t *entry, uint32_t n)
+    njs_value_t *entry, uint64_t n)
 {
     njs_int_t  ret;
 
@@ -2960,7 +2986,7 @@ njs_array_prototype_reduce_right(njs_vm_t *vm, njs_value_t *args,
         return ret;
     }
 
-    ret = njs_value_length(vm, iargs.value, &iargs.from);
+    ret = njs_value_length(vm, iargs.value, (uint64_t *) &iargs.from);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -3019,8 +3045,8 @@ unexpected_args:
 
 
 static njs_int_t
-njs_array_string_sort(njs_vm_t *vm, njs_value_t *args,
-    njs_uint_t nargs, njs_index_t unused)
+njs_array_string_sort(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
 {
     njs_int_t   ret;
     njs_uint_t  i;
@@ -3051,10 +3077,10 @@ static const njs_function_t  njs_array_string_sort_function = {
 
 
 static njs_int_t
-njs_array_prototype_sort(njs_vm_t *vm, njs_value_t *args,
-    njs_uint_t nargs, njs_index_t unused)
+njs_array_prototype_sort(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
 {
-    uint32_t        n, index, length, current;
+    uint64_t        n, index, length, current;
     njs_int_t       ret;
     njs_array_t     *array;
     njs_value_t     retval, value, *this, *start, arguments[3];
@@ -3167,11 +3193,10 @@ njs_array_prototype_copy_within(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused)
 {
     int8_t       direction;
-    int64_t      count, to, from, end;
-    uint32_t     length;
+    int64_t      length, count, to, from, end;
     njs_int_t    ret;
     njs_array_t  *array;
-    njs_value_t  *this, *value, from_key, to_key, prop;
+    njs_value_t  *this, *value, prop;
 
     this = njs_argument(args, 0);
 
@@ -3180,7 +3205,7 @@ njs_array_prototype_copy_within(njs_vm_t *vm, njs_value_t *args,
         return ret;
     }
 
-    ret = njs_value_length(vm, this, &length);
+    ret = njs_value_length(vm, this, (uint64_t *) &length);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -3240,22 +3265,17 @@ njs_array_prototype_copy_within(njs_vm_t *vm, njs_value_t *args,
     }
 
     while (count-- > 0) {
-        /* FIXME: largest index is 2**53-1. */
-
-        njs_uint32_to_string(&from_key, (uint32_t) from);
-        njs_uint32_to_string(&to_key, (uint32_t) to);
-
-        ret = njs_value_property(vm, this, &from_key, &prop);
+        ret = njs_value_property_i64(vm, this, from, &prop);
 
         if (ret == NJS_OK) {
-            ret = njs_value_property_set(vm, this, &to_key, &prop);
+            ret = njs_value_property_i64_set(vm, this, to, &prop);
 
         } else {
             if (njs_slow_path(ret == NJS_ERROR)) {
                 return ret;
             }
 
-            ret = njs_value_property_delete(vm, this, &to_key, NULL);
+            ret = njs_value_property_i64_delete(vm, this, to, NULL);
         }
 
         if (njs_slow_path(ret == NJS_ERROR)) {
index 663475d6d2b16a9c403a84e0f8bd92cc2aa7503e..0dae0129ebdffbeae03f075b3aa0c83f7eba063b 100644 (file)
@@ -12,9 +12,7 @@
 #define NJS_ARRAY_INVALID_INDEX        NJS_ARRAY_MAX_INDEX
 
 #define NJS_ARRAY_SPARE                8
-#define NJS_ARRAY_MAX_LENGTH           (UINT32_MAX/ sizeof(njs_value_t))
-#define NJS_ARRAY_MAX_LENGTH53         (0x1fffffffffffff)
-#define NJS_ARRAY_FAST_OBJECT_LENGTH   (128)
+#define NJS_ARRAY_FAST_OBJECT_LENGTH   (1024)
 #define NJS_ARRAY_LARGE_OBJECT_LENGTH  (32768)
 #define NJS_ARRAY_FLAT_MAX_LENGTH      (1048576)
 
index 2cbf509dfe1fe8a235e2cf68d691a406507d2e85..caefda454faf0176354ff01daf139e3de3d22116 100644 (file)
@@ -61,10 +61,10 @@ njs_chb_init(njs_chb_t *chain, njs_mp_t *pool)
 }
 
 
-njs_inline size_t
+njs_inline uint64_t
 njs_chb_size(njs_chb_t *chain)
 {
-    size_t          size;
+    uint64_t        size;
     njs_chb_node_t  *n;
 
     n = chain->nodes;
@@ -80,10 +80,10 @@ njs_chb_size(njs_chb_t *chain)
 }
 
 
-njs_inline ssize_t
+njs_inline int64_t
 njs_chb_utf8_length(njs_chb_t *chain)
 {
-    ssize_t         len, length;
+    int64_t         len, length;
     njs_chb_node_t  *n;
 
     n = chain->nodes;
index beecd93ceae4fa7beee930cf4f5f8d98483ecc28..ede96fe30a6736c74c4e4f13e63092847e67f1d2 100644 (file)
@@ -1086,10 +1086,10 @@ static njs_int_t
 njs_function_prototype_apply(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    uint32_t        i, length;
+    uint64_t        i, length;
     njs_int_t       ret;
     njs_frame_t     *frame;
-    njs_value_t     name, *this, *arr_like;
+    njs_value_t     *this, *arr_like;
     njs_array_t     *arr;
     njs_function_t  *func;
 
@@ -1133,9 +1133,7 @@ njs_function_prototype_apply(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     args = arr->start;
 
     for (i = 0; i < length; i++) {
-        njs_uint32_to_string(&name, i);
-
-        ret = njs_value_property(vm, arr_like, &name, &args[i]);
+        ret = njs_value_property_i64(vm, arr_like, i, &args[i]);
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
         }
index 46141b061c3beda35171a0ab06c80e4bf57fe2af..0a238767d5a629c7c3d61ca629fdd06fc343be89 100644 (file)
@@ -28,8 +28,8 @@ typedef struct {
        NJS_JSON_ARRAY,
     }                          type:8;
 
-    uint32_t                   index;
-    uint32_t                   length;
+    uint64_t                   index;
+    uint64_t                   length;
     njs_array_t                *keys;
     njs_value_t                *key;
     njs_object_prop_t          *prop;
@@ -1120,8 +1120,8 @@ njs_json_stringify_iterator(njs_vm_t *vm, njs_json_stringify_t *stringify,
     njs_value_t *object)
 {
     u_char            *p;
-    size_t            size;
-    ssize_t           length;
+    int64_t           length;
+    uint64_t          size;
     njs_int_t         ret;
     njs_chb_t         chain;
     njs_value_t       *key, *value, index, wrapper;
@@ -1165,7 +1165,7 @@ njs_json_stringify_iterator(njs_vm_t *vm, njs_json_stringify_t *stringify,
             value = &stringify->retval;
 
             if (state->array) {
-                njs_uint32_to_string(&index, state->index++);
+                njs_set_number(&index, state->index++);
                 key = &index;
 
             } else {
index 6d71baeed98e51c63c54b73329ab838f0bfbef88..b8220f352ed614b28e47b3ca57c901e25753a706 100644 (file)
@@ -229,6 +229,30 @@ njs_number_to_string(njs_vm_t *vm, njs_value_t *string,
 }
 
 
+njs_int_t
+njs_uint64_to_string(njs_vm_t *vm, njs_value_t *value, uint64_t u64)
+{
+    size_t  size;
+    u_char  *dst, *p;
+    u_char  buf[128];
+
+    if (njs_fast_path(u64 < 0x3fffffffffff)) {
+        /* Fits to short_string. */
+        dst = njs_string_short_start(value);
+
+        p = njs_sprintf(dst, dst + NJS_STRING_SHORT, "%uL", u64);
+
+        njs_string_short_set(value, p - dst, p - dst);
+
+        return NJS_OK;
+    }
+
+    size = njs_dtoa(u64, (char *) buf);
+
+    return njs_string_new(vm, value, buf, size, size);
+}
+
+
 njs_int_t
 njs_number_to_chain(njs_vm_t *vm, njs_chb_t *chain, double num)
 {
index 5d5bec1fc5083d4b37fdc02ca5e33ac6b7157533..886c7ea1c1eac761d97636868d10532891fabf6a 100644 (file)
@@ -8,6 +8,9 @@
 #define _NJS_NUMBER_H_INCLUDED_
 
 
+#define NJS_MAX_LENGTH           (0x1fffffffffffff)
+
+
 double njs_key_to_index(const njs_value_t *value);
 double njs_number_dec_parse(const u_char **start, const u_char *end);
 uint64_t njs_number_oct_parse(const u_char **start, const u_char *end);
@@ -119,23 +122,21 @@ njs_number_to_uint16(double num)
 }
 
 
-njs_inline uint32_t
+njs_inline uint64_t
 njs_number_to_length(double num)
 {
-#if (NJS_NAN_TO_UINT_CONVERSION != 0)
     if (isnan(num)) {
         return 0;
     }
-#endif
 
-    if (num > UINT32_MAX) {
-        return UINT32_MAX;
+    if (num > NJS_MAX_LENGTH) {
+        return NJS_MAX_LENGTH;
 
     } else if (num < 0.0) {
         return 0;
     }
 
-    return (uint32_t) (int64_t) num;
+    return (uint64_t) num;
 }
 
 
@@ -161,6 +162,7 @@ njs_char_to_hex(u_char c)
     return c;
 }
 
+
 njs_inline void
 njs_uint32_to_string(njs_value_t *value, uint32_t u32)
 {
index 99f8740828fda86779baca3f85109cd70301f7aa..c9ea60c4f69a3da01a8474aff7ac0a913e11279f 100644 (file)
@@ -2805,7 +2805,7 @@ const njs_object_init_t  njs_object_prototype_init = {
 
 
 njs_int_t
-njs_object_length(njs_vm_t *vm, njs_value_t *value, uint32_t *length)
+njs_object_length(njs_vm_t *vm, njs_value_t *value, uint64_t *length)
 {
     njs_int_t    ret;
     njs_value_t  value_length;
index 3f5cda99f4258256034f11c5f2e5c65c1afc9357..c7f3d2f9409b80381efd1f0cc19220d2b05a1b13 100644 (file)
@@ -67,7 +67,7 @@ njs_value_t *njs_property_constructor_create(njs_vm_t *vm, njs_lvlhsh_t *hash,
     njs_value_t *constructor);
 njs_int_t njs_object_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused);
-njs_int_t njs_object_length(njs_vm_t *vm, njs_value_t *value, uint32_t *dest);
+njs_int_t njs_object_length(njs_vm_t *vm, njs_value_t *value, uint64_t *dst);
 
 njs_int_t njs_prop_private_copy(njs_vm_t *vm, njs_property_query_t *pq);
 njs_object_prop_t *njs_object_prop_alloc(njs_vm_t *vm, const njs_value_t *name,
@@ -226,7 +226,7 @@ njs_key_string_get(njs_vm_t *vm, njs_value_t *key, njs_str_t *str)
 
 
 njs_inline njs_int_t
-njs_object_length_set(njs_vm_t *vm, njs_value_t *value, uint32_t length)
+njs_object_length_set(njs_vm_t *vm, njs_value_t *value, uint64_t length)
 {
     njs_value_t  index;
 
index e22c3e832f87da5d97dc64a5882240ece6f03c27..8947f78f2b3dab9d70763203bcdf29ab6050f441 100644 (file)
@@ -870,7 +870,7 @@ njs_regexp_prototype_test(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
     int                     *captures;
-    uint32_t                last_index;
+    uint64_t                last_index;
     njs_int_t               ret, match;
     njs_uint_t              n;
     njs_regex_t             *regex;
@@ -962,7 +962,7 @@ njs_int_t
 njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    uint32_t                last_index;
+    uint64_t                last_index;
     njs_int_t               ret;
     njs_utf8_t              utf8;
     njs_value_t             *value, lvalue;
index a578dce10eb58f223cedddfe1d3f69842ef94d19..d1da45c2bfcd6c0a180727378d9e7d3ab34b1475 100644 (file)
@@ -1644,7 +1644,8 @@ static njs_int_t
 njs_string_bytes_from_array_like(njs_vm_t *vm, njs_value_t *value)
 {
     u_char              *p;
-    uint32_t            u32, length;
+    uint32_t            u32;
+    uint64_t            length;
     njs_int_t           ret;
     njs_array_t         *array;
     njs_value_t         *octet, index, prop;
@@ -1705,7 +1706,7 @@ njs_string_bytes_from_array_like(njs_vm_t *vm, njs_value_t *value)
         p += length - 1;
 
         while (length != 0) {
-            njs_uint32_to_string(&index, length - 1);
+            njs_set_number(&index, length - 1);
 
             ret = njs_value_property(vm, value, &index, &prop);
             if (njs_slow_path(ret == NJS_ERROR)) {
index 0cd89b35f69c2887717302f2cd6eb4a4dd2e7222..c448f896d71b8f66d81828f38baf001459038993 100644 (file)
@@ -13,10 +13,10 @@ njs_typed_array_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t magic)
 {
     double              num;
-    uint32_t            i, length, element_size;
-    uint64_t            size, offset;
+    uint32_t            element_size;
+    uint64_t            i, length, size, offset;
     njs_int_t           ret;
-    njs_value_t         *value, index, prop;
+    njs_value_t         *value, prop;
     njs_array_t         *src_array;
     njs_object_type_t   type;
     njs_typed_array_t   *array, *src_tarray;
@@ -99,7 +99,7 @@ njs_typed_array_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             }
         }
 
-        size = (uint64_t) length * element_size;
+        size = length * element_size;
 
     } else {
         ret = njs_value_to_index(vm, value, &size);
@@ -153,9 +153,7 @@ njs_typed_array_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     } else if (!njs_is_array_buffer(value) && njs_is_object(value)) {
         for (i = 0; i < length; i++) {
-            njs_uint32_to_string(&index, i);
-
-            ret = njs_value_property(vm, value, &index, &prop);
+            ret = njs_value_property_i64(vm, value, i, &prop);
             if (njs_slow_path(ret == NJS_ERROR)) {
                 return NJS_ERROR;
             }
@@ -362,10 +360,10 @@ njs_typed_array_prototype_set(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused)
 {
     double             num;
-    uint32_t           i, length, src_length;
-    int64_t            offset;
+    uint32_t           i;
+    int64_t            length, src_length, offset;
     njs_int_t          ret;
-    njs_value_t        *this, *src, *value, index, prop;
+    njs_value_t        *this, *src, *value, prop;
     njs_array_t        *array;
     njs_typed_array_t  *self, *src_tarray;
 
@@ -438,7 +436,7 @@ njs_typed_array_prototype_set(njs_vm_t *vm, njs_value_t *args,
             return ret;
         }
 
-        ret = njs_object_length(vm, src, &src_length);
+        ret = njs_object_length(vm, src, (uint64_t *) &src_length);
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
         }
@@ -453,9 +451,7 @@ njs_typed_array_prototype_set(njs_vm_t *vm, njs_value_t *args,
         length = njs_min(src_length, length - offset);
 
         for (i = 0; i < length; i++) {
-            njs_uint32_to_string(&index, i);
-
-            ret = njs_value_property(vm, src, &index, &prop);
+            ret = njs_value_property_i64(vm, src, i, &prop);
             if (njs_slow_path(ret == NJS_ERROR)) {
                 return NJS_ERROR;
             }
index d6037082ccc86c0cdbaedc32ddc3df0df8f65e30..493c5334cd89d8c2c1b879f8672d1918eeac8015 100644 (file)
@@ -285,12 +285,12 @@ njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value,
 
 
 njs_int_t
-njs_value_length(njs_vm_t *vm, njs_value_t *value, uint32_t *length)
+njs_value_length(njs_vm_t *vm, njs_value_t *value, uint64_t *length)
 {
     njs_string_prop_t  string_prop;
 
     if (njs_is_string(value)) {
-        *length = (uint32_t) njs_string_prop(&string_prop, value);
+        *length = njs_string_prop(&string_prop, value);
 
     } else if (njs_is_primitive(value)) {
         *length = 0;
@@ -731,7 +731,7 @@ static njs_int_t
 njs_array_property_query(njs_vm_t *vm, njs_property_query_t *pq,
     njs_array_t *array, uint32_t index)
 {
-    uint32_t           size, length;
+    uint64_t           size, length;
     njs_int_t          ret;
     njs_value_t        *setval, value;
     njs_object_prop_t  *prop;
@@ -1419,7 +1419,17 @@ njs_value_property_delete(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
         /* Fall through. */
 
     case NJS_PROPERTY:
-        break;
+        if (njs_is_data_descriptor(prop) || removed == NULL) {
+            break;
+        }
+
+        if (njs_is_undefined(&prop->getter)) {
+            njs_set_undefined(removed);
+            break;
+        }
+
+        return njs_function_apply(vm, njs_function(&prop->getter), value,
+                                  1, removed);
 
     case NJS_PROPERTY_REF:
         if (removed != NULL) {
index 2256f8620110c7e70902753c5d3ed4b320412f3d..a38a18c1ada51e03102f61fd448e36ca833a7088 100644 (file)
@@ -995,6 +995,8 @@ njs_set_object_value(njs_value_t *value, njs_object_value_t *object_value)
         (pq)->lhq.key.length = 0;                                             \
         (pq)->lhq.key.start = NULL;                                           \
         (pq)->lhq.value = NULL;                                               \
+        /* FIXME: False-positive in MSAN?. */                                 \
+        njs_msan_unpoison(&(pq)->key, sizeof(njs_value_t));                   \
         (pq)->own_whiteout = NULL;                                            \
         (pq)->query = _query;                                                 \
         (pq)->shared = 0;                                                     \
@@ -1010,7 +1012,7 @@ njs_array_t *njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value,
     njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
 njs_array_t *njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value,
     njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
-njs_int_t njs_value_length(njs_vm_t *vm, njs_value_t *value, uint32_t *dest);
+njs_int_t njs_value_length(njs_vm_t *vm, njs_value_t *value, uint64_t *dst);
 const char *njs_type_string(njs_value_type_t type);
 
 njs_int_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst,
@@ -1018,11 +1020,13 @@ njs_int_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst,
 njs_int_t njs_primitive_value_to_chain(njs_vm_t *vm, njs_chb_t *chain,
     const njs_value_t *src);
 double njs_string_to_number(const njs_value_t *value, njs_bool_t parse_float);
+njs_int_t njs_uint64_to_string(njs_vm_t *vm, njs_value_t *value, uint64_t u64);
 
 njs_bool_t njs_string_eq(const njs_value_t *v1, const njs_value_t *v2);
 
 njs_int_t njs_property_query(njs_vm_t *vm, njs_property_query_t *pq,
     njs_value_t *value, njs_value_t *key);
+
 njs_int_t njs_value_property(njs_vm_t *vm, njs_value_t *value,
     njs_value_t *key, njs_value_t *retval);
 njs_int_t njs_value_property_set(njs_vm_t *vm, njs_value_t *value,
@@ -1037,6 +1041,63 @@ njs_int_t njs_value_species_constructor(njs_vm_t *vm, njs_value_t *object,
     njs_value_t *default_constructor, njs_value_t *dst);
 
 
+njs_inline njs_int_t
+njs_value_property_i64(njs_vm_t *vm, njs_value_t *value, int64_t index,
+    njs_value_t *retval)
+{
+    njs_int_t    ret;
+    njs_value_t  key;
+
+    /* FIXME: False-positive in MSAN?. */
+    njs_msan_unpoison(&key, sizeof(njs_value_t));
+
+    ret = njs_uint64_to_string(vm, &key, index);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_value_property(vm, value, &key, retval);
+}
+
+
+njs_inline njs_int_t
+njs_value_property_i64_set(njs_vm_t *vm, njs_value_t *value, int64_t index,
+    njs_value_t *setval)
+{
+    njs_int_t    ret;
+    njs_value_t  key;
+
+    /* FIXME: False-positive in MSAN?. */
+    njs_msan_unpoison(&key, sizeof(njs_value_t));
+
+    ret = njs_uint64_to_string(vm, &key, index);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_value_property_set(vm, value, &key, setval);
+}
+
+
+njs_inline njs_int_t
+njs_value_property_i64_delete(njs_vm_t *vm, njs_value_t *value, int64_t index,
+    njs_value_t *removed)
+{
+    njs_int_t    ret;
+    njs_value_t  key;
+
+    /* FIXME: False-positive in MSAN?. */
+    njs_msan_unpoison(&key, sizeof(njs_value_t));
+
+    ret = njs_uint64_to_string(vm, &key, index);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_value_property_delete(vm, value, &key, removed);
+}
+
+
 njs_inline njs_bool_t
 njs_values_same_non_numeric(const njs_value_t *val1, const njs_value_t *val2)
 {
index d684578119d859fa434ddeb94a4b9d192ca85892..7bae4774fe15622e2997c2813d3e6b28c94361d0 100644 (file)
@@ -80,7 +80,7 @@ njs_value_to_integer(njs_vm_t *vm, njs_value_t *value, int64_t *dst)
 
 
 njs_inline njs_int_t
-njs_value_to_length(njs_vm_t *vm, njs_value_t *value, uint32_t *dst)
+njs_value_to_length(njs_vm_t *vm, njs_value_t *value, uint64_t *dst)
 {
     double     num;
     njs_int_t  ret;
index e3ab57ff0bf800eb0b686f3a86f3d106d112c03a..4f9557a60f256a7b52c8c046bc7c9c4682db3239 100644 (file)
@@ -4269,6 +4269,15 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("var obj = {}; obj.pop = Array.prototype.pop; obj.pop(); obj.length === 0"),
       njs_str("true") },
 
+    { njs_str("Array.prototype[1] = 1; [0,,].pop()"),
+      njs_str("1") },
+
+    { njs_str("Array.prototype[1] = 1; var a = [0,,]; a.pop(); a.length"),
+      njs_str("1") },
+
+    { njs_str("Object.prototype[1] = 1; Object.prototype.length = 2; Array.prototype.pop.call({0:0})"),
+      njs_str("1") },
+
     { njs_str("var o = Object.freeze({0: 0, 1: 1, length: 2}); Array.prototype.pop.call(o)"),
       njs_str("TypeError: Cannot delete property \"1\" of object") },
 
@@ -4287,9 +4296,6 @@ static njs_unit_test_t  njs_test[] =
               "Array.prototype.pop.call(a); [a.length, a[a.length - 1]]"),
       njs_str("32768,y") },
 
-    { njs_str("Array.prototype.shift()"),
-      njs_str("undefined") },
-
     { njs_str("[0,1].slice()"),
       njs_str("0,1") },
 
@@ -4333,9 +4339,40 @@ static njs_unit_test_t  njs_test[] =
               "catch (e) {i += '; ' + e} i"),
       njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") },
 
+    { njs_str("var x = []; x.length = 4294967295; var push = x.push(); push === 4294967295"),
+      njs_str("true") },
+
+    { njs_str("var x = []; x.length = 4294967295; x.push(); x.push(1)"),
+      njs_str("RangeError: Invalid array length") },
+
+    { njs_str("var x = []; x.length = 4294967295; x.push(); "
+              "try {x.push('x')} catch (e) {}; x[4294967295]"),
+      njs_str("x") },
+
+    { njs_str("var x = []; x.length = 4294967295; x.push(); "
+              "try {x.push('x')} catch (e) {}; x.length"),
+      njs_str("4294967295") },
+
+    { njs_str("["
+              " [2**53-2, [1]],"
+              " [2**53-2, [1,2]],"
+              " [2**53-1, [1]],"
+              " [2**53, []],"
+              " [Number.POSITIVE_INFINITY, []],"
+              "]"
+              ".map(args=>{ try {return Array.prototype.push.apply({length:args[0]}, args[1])}"
+              "             catch (e) {return e.name} })"),
+      njs_str("9007199254740991,TypeError,TypeError,9007199254740991,9007199254740991") },
+
+    { njs_str("Array.prototype.shift()"),
+      njs_str("undefined") },
+
     { njs_str("var a = [1,2,3]; a.shift() +' '+ a[0] +' '+ a.length"),
       njs_str("1 2 2") },
 
+    { njs_str("Array.prototype[0] = 1; var x = [,2]; x.length = 2; x.shift()"),
+      njs_str("1") },
+
     { njs_str("var x = {'0': 'x', '1': 'y', '2': 'z', 'length': 3};"
               "Array.prototype.shift.call(x) +' '+ x[0] +' '+ x.length"),
       njs_str("x y 2") },
@@ -4373,9 +4410,13 @@ static njs_unit_test_t  njs_test[] =
               "Array.prototype.forEach.call(x, (v, k) => a.push(k + ':' + v)); a + ', ' + x.length"),
       njs_str("0:0,1:1,7:2,12:3,13:4,14:5,22:6, 23") },
 
-    { njs_str("var x = {0: 0, length: 4294967294};"
-              "Array.prototype.unshift.call(x, '0', '1');"),
-      njs_str("TypeError: Invalid length") },
+    { njs_str("var x = {0: 0, length: 2**32-2};"
+              "Array.prototype.unshift.call(x, '0', '1'); Object.keys(x).sort()"),
+      njs_str("0,1,2,length") },
+
+    { njs_str("var x = {0: 0, length: 2**53-3};"
+              "Array.prototype.unshift.call(x, '0', '1'); x.length"),
+      njs_str("9007199254740991") },
 
     { njs_str("var x = {0: 0}; Array.prototype.unshift.call(x); x.length"),
       njs_str("0") },
@@ -4489,12 +4530,10 @@ static njs_unit_test_t  njs_test[] =
               "Array.prototype.indexOf.call(o); i"),
       njs_str("1") },
 
-#if (!NJS_HAVE_MEMORY_SANITIZER) /* False-positive in MSAN? */
     { njs_str("var a = new Array(); a[100] =1; a[99999] = ''; a[10] = new Object(); "
               "a[5555] = 5.5; a[123456] = 'str'; a[5] = 1E+309; "
               "[1, '', 'str', 1E+309, 5.5, true, 5, 'str1', null, new Object()].map(v=>a.indexOf(v))"),
       njs_str("100,99999,123456,5,5555,-1,-1,-1,-1,-1") },
-#endif
 
     { njs_str("Array.prototype.indexOf.call({199:true, 200:'200.59', length:200}, '200.59')"),
       njs_str("-1") },
@@ -4508,6 +4547,14 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("Array.prototype.indexOf.call({1:true, 2:'200.59', length:3}, '200.59')"),
       njs_str("2") },
 
+    { njs_str("var stopped = 0;"
+              "var o = {length:3}; "
+              "Object.defineProperty(o, '1',{get:()=>{throw 'Oops'}});"
+              "Object.defineProperty(o, '2', {get:()=>stopped++});"
+              "try { Array.prototype.indexOf.call(o, 7)} catch (e) {};"
+              "stopped"),
+      njs_str("0") },
+
     { njs_str("[].lastIndexOf(1, -1)"),
       njs_str("-1") },
 
@@ -4553,6 +4600,14 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("[1,2,1].lastIndexOf(1)"),
       njs_str("2") },
 
+    { njs_str("var stopped = 0;"
+              "var o = {length:3}; "
+              "Object.defineProperty(o, '1', {get:()=>stopped++});"
+              "Object.defineProperty(o, '2',{get:()=>{throw 'Oops'}});"
+              "try { Array.prototype.lastIndexOf.call(o)} catch (e) {};"
+              "stopped"),
+      njs_str("0") },
+
     { njs_str("var o = 'addc';"
               "Array.prototype.lastIndexOf.call(o, 'd')"),
       njs_str("2") },
@@ -4583,12 +4638,10 @@ static njs_unit_test_t  njs_test[] =
               "Array.prototype.lastIndexOf.call(o, 'd')"),
       njs_str("3") },
 
-#if (!NJS_HAVE_MEMORY_SANITIZER) /* False-positive in MSAN? */
     { njs_str("var a = new Array(); a[100] =1; a[99999] = ''; a[10] = new Object(); "
               "a[5555] = 5.5; a[123456] = 'str'; a[5] = 1E+309; "
               "[1,'', 'str', 1E+309, 5.5, true, 5, 'str1', null, new Object()].map(v=>a.lastIndexOf(v))"),
       njs_str("100,99999,123456,5,5555,-1,-1,-1,-1,-1") },
-#endif
 
     { njs_str("var obj = {'10000000': 'x', '10000001': 'y', '10000002': 'z'}; var a = [];"
               "obj.length = 90000000;"
@@ -4661,6 +4714,14 @@ static njs_unit_test_t  njs_test[] =
               "Array.prototype.includes.call(obj, 'a', fromIndex);"),
       njs_str("false") },
 
+    { njs_str("var stopped = 0;"
+              "var o = {length:3}; "
+              "Object.defineProperty(o, '1',{get:()=>{throw 'Oops'}});"
+              "Object.defineProperty(o, '2', {get:()=>stopped++});"
+              "try { Array.prototype.includes.call(o, 7)} catch (e) {};"
+              "stopped"),
+      njs_str("0") },
+
     { njs_str("var a = []; var s = { sum: 0 };"
                  "a.forEach(function(v, i, a) { this.sum += v }, s); s.sum"),
       njs_str("0") },
@@ -4786,6 +4847,9 @@ static njs_unit_test_t  njs_test[] =
               "Array.prototype.every.call(obj, (val,idx,obj)=>!(obj instanceof Date))"),
       njs_str("false") },
 
+    { njs_str("Array.prototype.every.call({0:11,1:9,length:2**32+1}, val=>val>10)"),
+      njs_str("false") },
+
     { njs_str("var vis = false; var a = []; "
               "Object.defineProperty(a, '0', {get:()=>{vis = true; return 11;}, configurable:true});"
               "Object.defineProperty(a, '1', {get:()=>{if (vis) {return 9;} else {return 11}}, configurable:true});"
@@ -4884,6 +4948,18 @@ static njs_unit_test_t  njs_test[] =
                  "Array.prototype.slice.call(Array.prototype.fill.call(o, 1))"),
       njs_str("1,1") },
 
+    { njs_str("Array.prototype.slice.call({length:2**32})"),
+      njs_str("RangeError: Invalid array length") },
+
+    { njs_str("Array.prototype.slice.call({0:'x', [2**32-1]:'y',length:2**32}, 0, 2**32)"),
+      njs_str("RangeError: Invalid array length") },
+
+    { njs_str("Array.prototype.slice.call({length:2**32+2, [2**32]:'x', [2**32+1]:'y'}, 2**32)"),
+      njs_str("x,y") },
+
+    { njs_str("Array.prototype.slice.call({length:2**53+2, [2**53-3]:'x', [2**53-2]:'y', [2**53-1]:'z'}, 2**53-3)"),
+      njs_str("x,y") },
+
     { njs_str("var o = {}; Object.defineProperty(o, 'length', {get:()=> {throw TypeError('Boom')}}); "
                  "Array.prototype.fill.call(o, 1)"),
       njs_str("TypeError: Boom") },
@@ -5790,6 +5866,13 @@ static njs_unit_test_t  njs_test[] =
                  "var a = Array.prototype.reduce.call(o, reducer); a"),
       njs_str("abc") },
 
+    { njs_str("function reducer(a, b, i, arr) {"
+              "   if (i == 2) Object.defineProperty(arr, i, {enumerable:false}); "
+              "   return a + b;"
+              "};"
+              "Array.prototype.reduce.call([1,2,3,4], reducer)"),
+      njs_str("10") },
+
     { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
               "Object.defineProperty(o, 'length', {get: () => 4});"
               "Object.defineProperty(o, '3', {get: () => 'd'});"
@@ -5865,6 +5948,17 @@ static njs_unit_test_t  njs_test[] =
               "m.join('')"),
       njs_str("0а00000000000000000000000000000") },
 
+    { njs_str("function reducer(a, b, i, arr) {"
+              "   if (i == 2) Object.defineProperty(arr, i, {enumerable:false}); "
+              "   return a + b;"
+              "};"
+              "Array.prototype.reduceRight.call([1,2,3,4], reducer)"),
+      njs_str("10") },
+
+    { njs_str("Array.prototype[0] = 1; Array.prototype[1] = 2; Array.prototype[2] = 3;"
+              "[,,].reduceRight((a,b)=>a+b)"),
+      njs_str("3") },
+
     { njs_str("var a = ['1','2','3','4','5','6']; a.sort()"),
       njs_str("1,2,3,4,5,6") },
 
@@ -8656,6 +8750,18 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("[1,2,3].join(undefined)"),
       njs_str("1,2,3") },
 
+    { njs_str("Array.prototype[1] = 1; var x = [0]; x.length = 2; x.join()"),
+      njs_str("0,1") },
+
+    { njs_str("Object.prototype[1] = 1; Object.prototype.length = 2; Array.prototype.join.call({0:0})"),
+      njs_str("0,1") },
+
+    { njs_str("var x = [0,,4]; x.length = 3; "
+              "Object.defineProperty(Array.prototype, 1, "
+                "{get:()=>{Object.defineProperty(x, 2, {value:'x', enumerable:false}); return 1}});"
+              "x.join()"),
+      njs_str("0,1,x") },
+
     { njs_str("[].slice.call()"),
       njs_str("TypeError: cannot convert null or undefined to object") },