From: Dmitry Volyntsev Date: Mon, 17 Feb 2020 13:13:43 +0000 (+0300) Subject: Introduced ToLength() according to ES6. X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=27ecd4ede379024586b1d54e55d7317df48b0a7c;p=njs.git Introduced ToLength() according to ES6. Since ES6, according to the spec maximum length value is 2**53 - 1 not 2**32 - 1, so uint64_t data type is required. --- diff --git a/src/njs_array.c b/src/njs_array.c index fb5da0f8..59c3b7e4 100644 --- a/src/njs_array.c +++ b/src/njs_array.c @@ -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 = ∝ + } + + 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 = ∝ + } + + 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)) { diff --git a/src/njs_array.h b/src/njs_array.h index 663475d6..0dae0129 100644 --- a/src/njs_array.h +++ b/src/njs_array.h @@ -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) diff --git a/src/njs_chb.h b/src/njs_chb.h index 2cbf509d..caefda45 100644 --- a/src/njs_chb.h +++ b/src/njs_chb.h @@ -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; diff --git a/src/njs_function.c b/src/njs_function.c index beecd93c..ede96fe3 100644 --- a/src/njs_function.c +++ b/src/njs_function.c @@ -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; } diff --git a/src/njs_json.c b/src/njs_json.c index 46141b06..0a238767 100644 --- a/src/njs_json.c +++ b/src/njs_json.c @@ -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 { diff --git a/src/njs_number.c b/src/njs_number.c index 6d71baee..b8220f35 100644 --- a/src/njs_number.c +++ b/src/njs_number.c @@ -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) { diff --git a/src/njs_number.h b/src/njs_number.h index 5d5bec1f..886c7ea1 100644 --- a/src/njs_number.h +++ b/src/njs_number.h @@ -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) { diff --git a/src/njs_object.c b/src/njs_object.c index 99f87408..c9ea60c4 100644 --- a/src/njs_object.c +++ b/src/njs_object.c @@ -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; diff --git a/src/njs_object.h b/src/njs_object.h index 3f5cda99..c7f3d2f9 100644 --- a/src/njs_object.h +++ b/src/njs_object.h @@ -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; diff --git a/src/njs_regexp.c b/src/njs_regexp.c index e22c3e83..8947f78f 100644 --- a/src/njs_regexp.c +++ b/src/njs_regexp.c @@ -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; diff --git a/src/njs_string.c b/src/njs_string.c index a578dce1..d1da45c2 100644 --- a/src/njs_string.c +++ b/src/njs_string.c @@ -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)) { diff --git a/src/njs_typed_array.c b/src/njs_typed_array.c index 0cd89b35..c448f896 100644 --- a/src/njs_typed_array.c +++ b/src/njs_typed_array.c @@ -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; } diff --git a/src/njs_value.c b/src/njs_value.c index d6037082..493c5334 100644 --- a/src/njs_value.c +++ b/src/njs_value.c @@ -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) { diff --git a/src/njs_value.h b/src/njs_value.h index 2256f862..a38a18c1 100644 --- a/src/njs_value.h +++ b/src/njs_value.h @@ -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) { diff --git a/src/njs_value_conversion.h b/src/njs_value_conversion.h index d6845781..7bae4774 100644 --- a/src/njs_value_conversion.h +++ b/src/njs_value_conversion.h @@ -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; diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index e3ab57ff..4f9557a6 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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") },