[njs] Introduced memory-efficient arrays.
Dmitry Volyntsev
xeioex at nginx.com
Tue Feb 4 17:35:28 UTC 2020
details: https://hg.nginx.org/njs/rev/ccfa84cea2b3
branches:
changeset: 1316:ccfa84cea2b3
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Tue Feb 04 20:35:02 2020 +0300
description:
Introduced memory-efficient arrays.
1) If "length" of ordinary array exceeds 32768 it is converted to
to array-like object.
2) Array.prototype.concat() is rewritten according to the spec.
3) Array.prototype.slice() is rewritten according to the spec.
diffstat:
src/njs_array.c | 997 +++++++++++++++++++++++++++++++++-------------
src/njs_array.h | 20 +-
src/njs_array_buffer.c | 2 +
src/njs_chb.h | 2 +-
src/njs_clang.h | 3 +
src/njs_crypto.c | 2 +
src/njs_date.c | 2 +
src/njs_error.c | 2 +
src/njs_json.c | 362 ++++++++++------
src/njs_module.c | 2 +
src/njs_object.c | 23 +-
src/njs_object.h | 2 +
src/njs_object_prop.c | 87 +++-
src/njs_promise.c | 3 +-
src/njs_regexp.c | 2 +
src/njs_typed_array.c | 1 -
src/njs_value.c | 125 ++++-
src/njs_value.h | 8 +
src/test/njs_benchmark.c | 6 +-
src/test/njs_unit_test.c | 280 ++++++++++++-
20 files changed, 1415 insertions(+), 516 deletions(-)
diffs (truncated from 3354 to 1000 lines):
diff -r f5afb325896f -r ccfa84cea2b3 src/njs_array.c
--- a/src/njs_array.c Tue Feb 04 20:35:00 2020 +0300
+++ b/src/njs_array.c Tue Feb 04 20:35:02 2020 +0300
@@ -8,7 +8,7 @@
#include <njs_main.h>
-#define NJS_ARRAY_LARGE_OBJECT_LENGTH 4096
+#define njs_fast_object(_sz) ((_sz) <= NJS_ARRAY_FAST_OBJECT_LENGTH)
typedef struct {
@@ -29,35 +29,36 @@ typedef njs_int_t (*njs_array_iterator_h
static njs_int_t njs_array_prototype_slice_copy(njs_vm_t *vm,
njs_value_t *this, int64_t start, int64_t length);
-static njs_value_t *njs_array_copy(njs_value_t *dst, njs_value_t *src);
-static njs_array_t *njs_object_indexes(njs_vm_t *vm, njs_value_t *object);
njs_array_t *
njs_array_alloc(njs_vm_t *vm, uint64_t length, uint32_t spare)
{
uint64_t size;
+ njs_int_t ret;
njs_array_t *array;
+ njs_value_t value;
if (njs_slow_path(length > UINT32_MAX)) {
goto overflow;
}
- size = length + spare;
-
- if (njs_slow_path(size > NJS_ARRAY_MAX_LENGTH)) {
- goto memory_error;
- }
-
array = njs_mp_alloc(vm->mem_pool, sizeof(njs_array_t));
if (njs_slow_path(array == NULL)) {
goto memory_error;
}
- array->data = njs_mp_align(vm->mem_pool, sizeof(njs_value_t),
- size * sizeof(njs_value_t));
- if (njs_slow_path(array->data == NULL)) {
- goto memory_error;
+ size = length + spare;
+
+ if (size <= NJS_ARRAY_LARGE_OBJECT_LENGTH) {
+ array->data = njs_mp_align(vm->mem_pool, sizeof(njs_value_t),
+ size * sizeof(njs_value_t));
+ if (njs_slow_path(array->data == NULL)) {
+ goto memory_error;
+ }
+
+ } else {
+ array->data = NULL;
}
array->start = array->data;
@@ -67,9 +68,23 @@ njs_array_alloc(njs_vm_t *vm, uint64_t l
array->object.type = NJS_ARRAY;
array->object.shared = 0;
array->object.extensible = 1;
- array->object.fast_array = 1;
- array->size = size;
- array->length = length;
+ array->object.error_data = 0;
+ array->object.fast_array = (array->data != NULL);
+
+ if (njs_fast_path(array->object.fast_array)) {
+ array->size = size;
+ array->length = length;
+
+ } else {
+ array->size = 0;
+ array->length = 0;
+
+ njs_set_array(&value, array);
+ ret = njs_array_length_redefine(vm, &value, length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NULL;
+ }
+ }
return array;
@@ -88,6 +103,130 @@ overflow:
njs_int_t
+njs_array_convert_to_slow_array(njs_vm_t *vm, njs_array_t *array)
+{
+ uint32_t i, length;
+ njs_value_t index, value;
+ njs_object_prop_t *prop;
+
+ njs_set_array(&value, array);
+ array->object.fast_array = 0;
+
+ length = array->length;
+
+ for (i = 0; i < length; i++) {
+ njs_uint32_to_string(&index, i);
+
+ if (njs_is_valid(&array->start[i])) {
+ prop = njs_object_property_add(vm, &value, &index, 0);
+ if (njs_slow_path(prop == NULL)) {
+ return NJS_ERROR;
+ }
+
+ prop->value = array->start[i];
+ }
+ }
+
+ /* GC: release value. */
+
+ njs_mp_free(vm->mem_pool, array->start);
+ array->start = NULL;
+
+ return NJS_OK;
+}
+
+
+njs_int_t
+njs_array_length_redefine(njs_vm_t *vm, njs_value_t *value, uint32_t length)
+{
+ njs_object_prop_t *prop;
+
+ static const njs_value_t string_length = njs_string("length");
+
+ if (njs_slow_path(!njs_is_array(value))) {
+ njs_internal_error(vm, "njs_array_length_redefine() "
+ "applied to non-array");
+ return NJS_ERROR;
+ }
+
+ prop = njs_object_property_add(vm, value, njs_value_arg(&string_length), 1);
+ if (njs_slow_path(prop == NULL)) {
+ njs_internal_error(vm, "njs_array_length_redefine() "
+ "cannot redefine \"length\"");
+ return NJS_ERROR;
+ }
+
+ prop->enumerable = 0;
+ prop->configurable = 0;
+
+ njs_value_number_set(&prop->value, length);
+
+ return NJS_OK;
+}
+
+
+njs_int_t
+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;
+ njs_int_t ret;
+ njs_array_t *array, *keys;
+
+ array = njs_object_proto_lookup(njs_object(value), NJS_ARRAY, njs_array_t);
+ if (njs_slow_path(array == NULL)) {
+ return NJS_DECLINED;
+ }
+
+ ret = njs_value_to_number(vm, setval, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ length = njs_number_to_length(num);
+ if ((double) length != num) {
+ njs_range_error(vm, "Invalid array length");
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_to_length(vm, &prev->value, &prev_length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (length < prev_length) {
+ keys = njs_array_indices(vm, value);
+ if (njs_slow_path(keys == NULL)) {
+ return NJS_ERROR;
+ }
+
+ if (keys->length != 0) {
+ i = keys->length - 1;
+
+ do {
+ idx = njs_string_to_index(&keys->start[i]);
+ if (idx >= length) {
+ ret = njs_value_property_delete(vm, value, &keys->start[i],
+ NULL);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+ }
+ } while (i-- != 0);
+ }
+ }
+
+ ret = njs_array_length_redefine(vm, value, length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ return NJS_OK;
+}
+
+
+njs_int_t
njs_array_add(njs_vm_t *vm, njs_array_t *array, njs_value_t *value)
{
njs_int_t ret;
@@ -206,24 +345,25 @@ njs_array_constructor(njs_vm_t *vm, njs_
if (njs_fast_path(array != NULL)) {
- value = array->start;
-
- if (args == NULL) {
- while (size != 0) {
- njs_set_invalid(value);
- value++;
- size--;
- }
-
- } else {
- while (size != 0) {
- njs_retain(args);
- *value++ = *args++;
- size--;
+ if (array->object.fast_array) {
+ value = array->start;
+
+ if (args == NULL) {
+ while (size != 0) {
+ njs_set_invalid(value);
+ value++;
+ size--;
+ }
+
+ } else {
+ while (size != 0) {
+ njs_retain(args);
+ *value++ = *args++;
+ size--;
+ }
}
}
-
njs_set_array(&vm->retval, array);
return NJS_OK;
@@ -253,26 +393,28 @@ njs_array_is_array(njs_vm_t *vm, njs_val
static njs_int_t
-njs_array_of(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
+njs_array_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
{
- uint32_t length, i;
- njs_array_t *array;
-
- length = nargs > 1 ? nargs - 1 : 0;
-
- array = njs_array_alloc(vm, length, NJS_ARRAY_SPARE);
- if (njs_slow_path(array == NULL)) {
- return NJS_ERROR;
- }
-
- njs_set_array(&vm->retval, array);
-
+ uint32_t length, i;
+ njs_array_t *array;
+
+ length = nargs > 1 ? nargs - 1 : 0;
+
+ array = njs_array_alloc(vm, length, NJS_ARRAY_SPARE);
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ njs_set_array(&vm->retval, array);
+
+ if (array->object.fast_array) {
for (i = 0; i < length; i++) {
array->start[i] = args[i + 1];
}
-
- return NJS_OK;
+ }
+
+ return NJS_OK;
}
@@ -358,18 +500,12 @@ njs_array_length(njs_vm_t *vm,njs_object
return NJS_DECLINED;
}
- if (njs_slow_path(!njs_is_number(setval))) {
- ret = njs_value_to_number(vm, setval, &num);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- } else {
- num = njs_number(setval);
+ ret = njs_value_to_number(vm, setval, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
}
length = njs_number_to_length(num);
-
if ((double) length != num) {
njs_range_error(vm, "Invalid array length");
return NJS_ERROR;
@@ -377,35 +513,46 @@ njs_array_length(njs_vm_t *vm,njs_object
array = (njs_array_t *) proto;
- size = (int64_t) length - array->length;
-
- if (size > 0) {
- ret = njs_array_expand(vm, array, 0, size);
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
+ if (njs_fast_path(array->object.fast_array)) {
+ if (njs_fast_path(length <= NJS_ARRAY_LARGE_OBJECT_LENGTH)) {
+ size = (int64_t) length - array->length;
+
+ if (size > 0) {
+ ret = njs_array_expand(vm, array, 0, size);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ val = &array->start[array->length];
+
+ do {
+ njs_set_invalid(val);
+ val++;
+ size--;
+ } while (size != 0);
+ }
+
+ array->length = length;
+
+ *retval = *setval;
+ return NJS_OK;
}
- val = &array->start[array->length];
-
- do {
- njs_set_invalid(val);
- val++;
- size--;
- } while (size != 0);
+ ret = njs_array_convert_to_slow_array(vm, array);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
}
- array->length = length;
+ prop->type = NJS_PROPERTY;
+ njs_set_number(&prop->value, length);
*retval = *setval;
+
return NJS_OK;
}
-/*
- * Array.slice(start[, end]).
- * JavaScript 1.2, ECMAScript 3.
- */
-
static njs_int_t
njs_array_prototype_slice(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
@@ -413,16 +560,16 @@ njs_array_prototype_slice(njs_vm_t *vm,
int64_t start, end, length;
uint32_t object_length;
njs_int_t ret;
- njs_value_t *value;
-
- value = njs_arg(args, nargs, 0);
-
- ret = njs_value_to_object(vm, value);
+ njs_value_t *this;
+
+ this = njs_argument(args, 0);
+
+ ret = njs_value_to_object(vm, this);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
- ret = njs_object_length(vm, value, &object_length);
+ ret = njs_object_length(vm, this, &object_length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -474,7 +621,7 @@ njs_array_prototype_slice(njs_vm_t *vm,
}
}
- return njs_array_prototype_slice_copy(vm, value, start, length);
+ return njs_array_prototype_slice_copy(vm, this, start, length);
}
@@ -486,8 +633,8 @@ njs_array_prototype_slice_copy(njs_vm_t
u_char *dst;
uint32_t n;
njs_int_t ret;
- njs_array_t *array;
- njs_value_t *value, name;
+ njs_array_t *array, *keys;
+ njs_value_t *value, index, retval, array_value;
const u_char *src, *end;
njs_slice_prop_t string_slice;
njs_string_prop_t string;
@@ -497,17 +644,37 @@ njs_array_prototype_slice_copy(njs_vm_t
return NJS_ERROR;
}
- njs_set_array(&vm->retval, array);
-
- if (length != 0) {
- n = 0;
-
- if (njs_fast_path(njs_is_array(this))) {
+ if (njs_slow_path(length == 0)) {
+ goto done;
+ }
+
+ n = 0;
+
+ if (njs_fast_path(array->object.fast_array)) {
+ if (njs_fast_path(njs_is_fast_array(this))) {
value = njs_array_start(this);
do {
- /* GC: retain long string and object in values[start]. */
- array->start[n++] = value[start++];
+ if (njs_fast_path(njs_is_valid(&value[start]))) {
+ array->start[n++] = value[start++];
+
+ } else {
+
+ /* 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);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return NJS_ERROR;
+ }
+
+ if (ret != NJS_OK) {
+ njs_set_invalid(value);
+ }
+ }
+
length--;
} while (length != 0);
@@ -553,10 +720,10 @@ njs_array_prototype_slice_copy(njs_vm_t
} else if (njs_is_object(this)) {
do {
- njs_uint32_to_string(&name, start++);
+ njs_uint32_to_string(&index, start++);
value = &array->start[n++];
- ret = njs_value_property(vm, this, &name, value);
+ ret = njs_value_property(vm, this, &index, value);
if (ret != NJS_OK) {
njs_set_invalid(value);
@@ -576,8 +743,56 @@ njs_array_prototype_slice_copy(njs_vm_t
length--;
} while (length != 0);
}
+
+ goto done;
}
+ njs_set_array(&array_value, array);
+
+ if (njs_fast_object(length)) {
+ do {
+ njs_uint32_to_string(&index, start++);
+
+ ret = njs_value_property(vm, this, &index, &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);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+ }
+
+ length--;
+ } while (length != 0);
+
+ goto done;
+ }
+
+ keys = njs_array_indices(vm, this);
+ if (njs_slow_path(keys == NULL)) {
+ return NJS_ERROR;
+ }
+
+ for (n = 0; n < keys->length; n++) {
+ ret = njs_value_property(vm, this, &keys->start[n], &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ ret = njs_value_property_set(vm, &array_value, &keys->start[n],
+ &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+ }
+
+done:
+
+ njs_set_array(&vm->retval, array);
+
return NJS_OK;
}
@@ -590,18 +805,18 @@ njs_array_prototype_push(njs_vm_t *vm, n
njs_int_t ret;
njs_uint_t i;
njs_array_t *array;
- njs_value_t *value, index;
-
- value = njs_arg(args, nargs, 0);
+ njs_value_t *this, index;
+
length = 0;
-
- ret = njs_value_to_object(vm, value);
+ this = njs_argument(args, 0);
+
+ ret = njs_value_to_object(vm, this);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
- if (njs_is_array(&args[0])) {
- array = njs_array(&args[0]);
+ if (njs_is_fast_array(this)) {
+ array = njs_array(this);
if (nargs != 0) {
ret = njs_array_expand(vm, array, 0, nargs);
@@ -620,7 +835,7 @@ njs_array_prototype_push(njs_vm_t *vm, n
return NJS_OK;
}
- ret = njs_object_length(vm, value, &length);
+ ret = njs_object_length(vm, this, &length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -628,13 +843,13 @@ njs_array_prototype_push(njs_vm_t *vm, n
for (i = 1; i < nargs; i++) {
njs_uint32_to_string(&index, length++);
- ret = njs_value_property_set(vm, value, &index, &args[i]);
+ ret = njs_value_property_set(vm, this, &index, &args[i]);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
}
- ret = njs_object_length_set(vm, value, length);
+ ret = njs_object_length_set(vm, this, length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -652,19 +867,19 @@ njs_array_prototype_pop(njs_vm_t *vm, nj
uint32_t length;
njs_int_t ret;
njs_array_t *array;
- njs_value_t *value, *entry, index;
-
- value = njs_arg(args, nargs, 0);
-
- ret = njs_value_to_object(vm, value);
+ njs_value_t *this, *entry, index;
+
+ this = njs_argument(args, 0);
+
+ ret = njs_value_to_object(vm, this);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
njs_set_undefined(&vm->retval);
- if (njs_is_array(&args[0])) {
- array = njs_array(&args[0]);
+ if (njs_is_fast_array(this)) {
+ array = njs_array(this);
if (array->length != 0) {
array->length--;
@@ -678,7 +893,7 @@ njs_array_prototype_pop(njs_vm_t *vm, nj
return NJS_OK;
}
- ret = njs_object_length(vm, value, &length);
+ ret = njs_object_length(vm, this, &length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -686,13 +901,13 @@ njs_array_prototype_pop(njs_vm_t *vm, nj
if (length != 0) {
njs_uint32_to_string(&index, --length);
- ret = njs_value_property_delete(vm, value, &index, &vm->retval);
+ ret = njs_value_property_delete(vm, this, &index, &vm->retval);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
}
- ret = njs_object_length_set(vm, value, length);
+ ret = njs_object_length_set(vm, this, length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -710,19 +925,19 @@ njs_array_prototype_unshift(njs_vm_t *vm
njs_int_t ret;
njs_uint_t n;
njs_array_t *array, *keys;
- njs_value_t *value, entry, index;
-
- value = njs_arg(args, nargs, 0);
+ njs_value_t *this, entry, index;
+
+ this = njs_argument(args, 0);
length = 0;
n = nargs - 1;
- ret = njs_value_to_object(vm, value);
+ ret = njs_value_to_object(vm, this);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
- if (njs_is_array(value)) {
- array = njs_array(value);
+ if (njs_is_fast_array(this)) {
+ array = njs_array(this);
if (array->length > (UINT32_MAX - n)) {
njs_type_error(vm, "Invalid length");
@@ -751,7 +966,7 @@ njs_array_prototype_unshift(njs_vm_t *vm
return NJS_OK;
}
- ret = njs_object_length(vm, value, &length);
+ ret = njs_object_length(vm, this, &length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -765,8 +980,8 @@ njs_array_prototype_unshift(njs_vm_t *vm
return NJS_ERROR;
}
- if (length > NJS_ARRAY_LARGE_OBJECT_LENGTH) {
- keys = njs_object_indexes(vm, value);
+ if (!njs_fast_object(length)) {
+ keys = njs_array_indices(vm, this);
if (njs_slow_path(keys == NULL)) {
return NJS_ERROR;
}
@@ -774,7 +989,7 @@ njs_array_prototype_unshift(njs_vm_t *vm
from = keys->length;
while (from > 0) {
- ret = njs_value_property_delete(vm, value, &keys->start[--from],
+ ret = njs_value_property_delete(vm, this, &keys->start[--from],
&entry);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
@@ -785,7 +1000,7 @@ njs_array_prototype_unshift(njs_vm_t *vm
njs_uint32_to_string(&index, (uint32_t) idx + nargs - 1);
- ret = njs_value_property_set(vm, value, &index, &entry);
+ ret = njs_value_property_set(vm, this, &index, &entry);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -804,7 +1019,7 @@ njs_array_prototype_unshift(njs_vm_t *vm
while (from > 0) {
njs_uint32_to_string(&index, --from);
- ret = njs_value_property_delete(vm, value, &index, &entry);
+ ret = njs_value_property_delete(vm, this, &index, &entry);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -814,7 +1029,7 @@ njs_array_prototype_unshift(njs_vm_t *vm
if (ret == NJS_OK) {
njs_uint32_to_string(&index, to);
- ret = njs_value_property_set(vm, value, &index, &entry);
+ ret = njs_value_property_set(vm, this, &index, &entry);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -826,7 +1041,7 @@ copy:
for (n = 1; n < nargs; n++) {
njs_uint32_to_string(&index, n - 1);
- ret = njs_value_property_set(vm, value, &index, &args[n]);
+ ret = njs_value_property_set(vm, this, &index, &args[n]);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -834,7 +1049,7 @@ copy:
done:
- ret = njs_object_length_set(vm, value, length);
+ ret = njs_object_length_set(vm, this, length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -852,20 +1067,20 @@ njs_array_prototype_shift(njs_vm_t *vm,
uint32_t i, length;
njs_int_t ret;
njs_array_t *array;
- njs_value_t *value, *item, entry, index;
-
- value = njs_arg(args, nargs, 0);
+ njs_value_t *this, *item, entry, index;
+
+ this = njs_argument(args, 0);
length = 0;
- ret = njs_value_to_object(vm, value);
+ ret = njs_value_to_object(vm, this);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
njs_set_undefined(&vm->retval);
- if (njs_is_array(&args[0])) {
- array = njs_array(&args[0]);
+ if (njs_is_fast_array(this)) {
+ array = njs_array(this);
if (array->length != 0) {
array->length--;
@@ -881,7 +1096,7 @@ njs_array_prototype_shift(njs_vm_t *vm,
return NJS_OK;
}
- ret = njs_object_length(vm, value, &length);
+ ret = njs_object_length(vm, this, &length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -892,7 +1107,7 @@ njs_array_prototype_shift(njs_vm_t *vm,
njs_uint32_to_string(&index, 0);
- ret = njs_value_property_delete(vm, value, &index, &vm->retval);
+ ret = njs_value_property_delete(vm, this, &index, &vm->retval);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -900,7 +1115,7 @@ njs_array_prototype_shift(njs_vm_t *vm,
for (i = 1; i < length; i++) {
njs_uint32_to_string(&index, i);
- ret = njs_value_property_delete(vm, value, &index, &entry);
+ ret = njs_value_property_delete(vm, this, &index, &entry);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -908,7 +1123,7 @@ njs_array_prototype_shift(njs_vm_t *vm,
if (ret == NJS_OK) {
njs_uint32_to_string(&index, i - 1);
- ret = njs_value_property_set(vm, value, &index, &entry);
+ ret = njs_value_property_set(vm, this, &index, &entry);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -919,7 +1134,7 @@ njs_array_prototype_shift(njs_vm_t *vm,
done:
- ret = njs_object_length_set(vm, value, length);
+ ret = njs_object_length_set(vm, this, length);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
@@ -935,35 +1150,33 @@ njs_array_prototype_splice(njs_vm_t *vm,
int64_t n, start, length, items, delta, delete;
njs_int_t ret;
njs_uint_t i;
- njs_value_t *value;
+ njs_value_t *this;
njs_array_t *array, *deleted;
- value = njs_arg(args, nargs, 0);
-
- ret = njs_value_to_object(vm, value);
+ this = njs_argument(args, 0);
+
+ ret = njs_value_to_object(vm, this);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
+ if (njs_slow_path(!njs_is_fast_array(this))) {
+ njs_internal_error(vm, "splice() is not implemented yet for objects");
+ return NJS_ERROR;
+ }
+
array = NULL;
start = 0;
delete = 0;
- if (njs_is_array(value)) {
- array = njs_array(value);
+ if (njs_is_fast_array(this)) {
+ array = njs_array(this);
length = array->length;
if (nargs > 1) {
- value = njs_argument(args, 1);
-
- if (njs_slow_path(!njs_is_number(value))) {
- ret = njs_value_to_integer(vm, value, &start);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- } else {
- start = njs_number_to_integer(njs_number(value));
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &start);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
}
if (start < 0) {
@@ -980,16 +1193,9 @@ njs_array_prototype_splice(njs_vm_t *vm,
delete = length - start;
if (nargs > 2) {
- value = njs_argument(args, 2);
-
- if (njs_slow_path(!njs_is_number(value))) {
- ret = njs_value_to_integer(vm, value, &n);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- } else {
- n = njs_number_to_integer(njs_number(value));
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &n);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
}
if (n < 0) {
@@ -1007,6 +1213,11 @@ njs_array_prototype_splice(njs_vm_t *vm,
return NJS_ERROR;
}
+ if (njs_slow_path(!deleted->object.fast_array)) {
+ njs_internal_error(vm, "deleted is not a fast_array");
+ return NJS_ERROR;
+ }
+
if (array != NULL && (delete >= 0 || nargs > 3)) {
/* Move deleted items to a new array to return. */
@@ -1055,19 +1266,35 @@ 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;
njs_int_t ret;
- njs_uint_t i, n, length;
+ njs_uint_t i, n;
njs_value_t value, *this;
njs_array_t *array;
- this = njs_arg(args, nargs, 0);
+ this = njs_argument(args, 0);
ret = njs_value_to_object(vm, this);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
- if (njs_is_array(this)) {
+ ret = njs_object_length(vm, this, &length);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (njs_slow_path(length == 0)) {
+ vm->retval = *this;
+ return NJS_OK;
+ }
+
+ if (njs_slow_path(!njs_is_fast_array(this))) {
+ njs_internal_error(vm, "reverse() is not implemented yet for objects");
+ return NJS_ERROR;
+ }
+
+ if (njs_is_fast_array(this)) {
array = njs_array(this);
length = array->length;
@@ -1080,10 +1307,6 @@ njs_array_prototype_reverse(njs_vm_t *vm
}
njs_set_array(&vm->retval, array);
-
- } else {
- /* STUB */
- vm->retval = *this;
}
return NJS_OK;
@@ -1126,15 +1349,18 @@ njs_array_prototype_join(njs_vm_t *vm, n
u_char *p, *last;
size_t size;
ssize_t length;
+ uint32_t len;
njs_int_t ret;
njs_chb_t chain;
njs_utf8_t utf8;
njs_uint_t i;
njs_array_t *array;
- njs_value_t *value;
+ njs_value_t *value, *this, index, entry;
njs_string_prop_t separator, string;
- ret = njs_value_to_object(vm, &args[0]);
+ this = njs_argument(args, 0);
+
+ ret = njs_value_to_object(vm, this);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
@@ -1155,20 +1381,47 @@ njs_array_prototype_join(njs_vm_t *vm, n
(void) njs_string_prop(&separator, value);
- if (!njs_is_array(&args[0]) || njs_array_len(&args[0]) == 0) {
+ if (njs_slow_path(!njs_is_object(this))) {
vm->retval = njs_string_empty;
return NJS_OK;
}
- array = njs_array(&args[0]);
+ length = 0;
+ array = NULL;
+ utf8 = njs_is_byte_string(&separator) ? NJS_STRING_BYTE : NJS_STRING_UTF8;
+
+ if (njs_is_fast_array(this)) {
+ array = njs_array(this);
+ len = array->length;
+
+ } else {
More information about the nginx-devel
mailing list