From: Alexander Borisov Date: Mon, 30 Sep 2019 08:41:00 +0000 (+0300) Subject: Fixed Array.prototype.map() for a object with nonexistent values. X-Git-Url: http://git.kaiwu.me/postgresql/log/contrib/postgres_fdw/static/gitweb.js?a=commitdiff_plain;h=135c69517737b46d9af5e538a2e70a5ed256d36c;p=njs.git Fixed Array.prototype.map() for a object with nonexistent values. Previously nonexistent values in the object were skipped and not added to the result. --- diff --git a/src/njs_array.c b/src/njs_array.c index c1d21a78..adab009d 100644 --- a/src/njs_array.c +++ b/src/njs_array.c @@ -1299,6 +1299,34 @@ njs_object_indexes(njs_vm_t *vm, 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_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_array_iterator_args_t *args, 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, njs_array_iterator_args_t *args, 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, njs_value_t *args, njs_uint_t nargs, 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, njs_value_t *args, njs_uint_t nargs, 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 --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index bfed0e36..644d106e 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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") },