[njs] Fixed Array.prototype.map() for a object with nonexistent values.
Alexander Borisov
alexander.borisov at nginx.com
Tue Oct 8 05:16:53 UTC 2019
details: https://hg.nginx.org/njs/rev/b63351157159
branches:
changeset: 1175:b63351157159
user: Alexander Borisov <alexander.borisov at nginx.com>
date: Mon Sep 30 11:41:00 2019 +0300
description:
Fixed Array.prototype.map() for a object with nonexistent values.
Previously nonexistent values in the object were skipped and not added
to the result.
diffstat:
src/njs_array.c | 104 +++++++++++++++++++++-------------------------
src/test/njs_unit_test.c | 10 ++++
2 files changed, 57 insertions(+), 57 deletions(-)
diffs (198 lines):
diff -r c9061ff75070 -r b63351157159 src/njs_array.c
--- a/src/njs_array.c Mon Oct 07 18:16:47 2019 +0300
+++ b/src/njs_array.c Mon Sep 30 11:41:00 2019 +0300
@@ -1300,6 +1300,34 @@ njs_object_indexes(njs_vm_t *vm, njs_val
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_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;
+ }
+
+ entry = (ret == NJS_OK) ? &prop : njs_value_arg(&njs_value_invalid);
+
+ ret = handler(vm, args, entry, i);
+
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret > 0) {
+ return NJS_DECLINED;
+ }
+
+ return NJS_ERROR;
+ }
+
+ return ret;
+}
+
+
+njs_inline njs_int_t
njs_array_iterator(njs_vm_t *vm, njs_array_iterator_args_t *args,
njs_array_iterator_handler_t handler)
{
@@ -1307,7 +1335,7 @@ njs_array_iterator(njs_vm_t *vm, njs_arr
uint32_t length, i, from, to;
njs_int_t ret;
njs_array_t *keys;
- njs_value_t *entry, *value, character, index, string_obj, prop;
+ njs_value_t *entry, *value, character, index, string_obj;
njs_object_t *object;
const u_char *p, *end, *pos;
njs_string_prop_t string_prop;
@@ -1421,21 +1449,11 @@ process_object:
continue;
}
- ret = njs_value_property(vm, value, &keys->start[i], &prop);
- if (njs_slow_path(ret == NJS_ERROR)) {
+ ret = njs_array_object_handler(vm, handler, args, &keys->start[i],
+ i);
+ if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
-
- if (ret != NJS_DECLINED) {
- ret = handler(vm, args, &prop, i);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
- }
-
- return NJS_ERROR;
- }
- }
}
return NJS_OK;
@@ -1444,21 +1462,10 @@ process_object:
for (i = from; i < to; i++) {
njs_uint32_to_string(&index, i);
- ret = njs_value_property(vm, value, &index, &prop);
- if (njs_slow_path(ret == NJS_ERROR)) {
+ ret = njs_array_object_handler(vm, handler, args, &index, i);
+ if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
-
- if (ret != NJS_DECLINED) {
- ret = handler(vm, args, &prop, i);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
- }
-
- return NJS_ERROR;
- }
- }
}
return NJS_OK;
@@ -1473,7 +1480,7 @@ njs_array_reverse_iterator(njs_vm_t *vm,
uint32_t i, from, to, length;
njs_int_t ret;
njs_array_t *keys;
- njs_value_t *entry, *value, character, index, string_obj, prop;
+ njs_value_t *entry, *value, character, index, string_obj;
njs_object_t *object;
const u_char *p, *end, *pos;
njs_string_prop_t string_prop;
@@ -1597,21 +1604,11 @@ process_object:
continue;
}
- ret = njs_value_property(vm, value, &keys->start[i], &prop);
- if (njs_slow_path(ret == NJS_ERROR)) {
+ ret = njs_array_object_handler(vm, handler, args, &keys->start[i],
+ idx);
+ if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
-
- if (ret != NJS_DECLINED) {
- ret = handler(vm, args, &prop, idx);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
- }
-
- return NJS_ERROR;
- }
- }
}
return NJS_OK;
@@ -1622,21 +1619,10 @@ process_object:
while (i-- > to) {
njs_uint32_to_string(&index, i);
- ret = njs_value_property(vm, value, &index, &prop);
- if (njs_slow_path(ret == NJS_ERROR)) {
+ ret = njs_array_object_handler(vm, handler, args, &index, i);
+ if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
-
- if (ret != NJS_DECLINED) {
- ret = handler(vm, args, &prop, i);
- if (njs_slow_path(ret != NJS_OK)) {
- if (ret > 0) {
- return NJS_DECLINED;
- }
-
- return NJS_ERROR;
- }
- }
}
return NJS_OK;
@@ -2457,6 +2443,12 @@ njs_array_prototype_map(njs_vm_t *vm, nj
return NJS_ERROR;
}
+ if (length > NJS_ARRAY_LARGE_OBJECT_LENGTH) {
+ for (i = 0; i < length; i++) {
+ njs_set_invalid(&iargs.array->start[i]);
+ }
+ }
+
if (length > 0) {
iargs.from = 0;
iargs.to = length;
@@ -2466,9 +2458,7 @@ njs_array_prototype_map(njs_vm_t *vm, nj
return ret;
}
- if (njs_is_array(&args[0])
- && njs_object_hash_is_empty(&args[0]))
- {
+ if (njs_is_array(&args[0]) && njs_object_hash_is_empty(&args[0])) {
array = iargs.array;
for (i = njs_array_len(&args[0]); i < length; i++) {
diff -r c9061ff75070 -r b63351157159 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Mon Oct 07 18:16:47 2019 +0300
+++ b/src/test/njs_unit_test.c Mon Sep 30 11:41:00 2019 +0300
@@ -4799,6 +4799,16 @@ static njs_unit_test_t njs_test[] =
{ njs_str("Array.prototype.map.call('abcdef', (val, idx, obj) => {return val === 100})"),
njs_str("false,false,false,false,false,false") },
+ { njs_str("function callbackfn(val, idx, obj) {return idx === 1 && typeof val === 'undefined';}"
+ "var obj = {2: 2, length: 10};"
+ "var res = Array.prototype.map.call(obj, callbackfn); typeof res[7]"),
+ njs_str("undefined") },
+
+ { njs_str("function callbackfn(val, idx, obj) {return idx === 1 && typeof val === 'undefined';}"
+ "var obj = {2: 2, length: 9000};"
+ "var res = Array.prototype.map.call(obj, callbackfn); typeof res[8000]"),
+ njs_str("undefined") },
+
{ njs_str("var a = [];"
"a.reduce(function(p, v, i, a) { return p + v })"),
njs_str("TypeError: Reduce of empty object with no initial value") },
More information about the nginx-devel
mailing list