From 409004cb00999f0f6088907a4e5e2ea8a9e5237e Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Fri, 28 Aug 2020 11:51:35 +0000 Subject: [PATCH] Introduced copy-on-write for ArrayBuffer. --- src/njs.h | 7 ++ src/njs_array_buffer.c | 24 ++++ src/njs_array_buffer.h | 2 +- src/njs_object.c | 4 +- src/njs_typed_array.c | 210 +++++++++++++++++++++++++++++----- src/njs_typed_array.h | 61 +--------- src/njs_value.c | 11 +- src/njs_value.h | 4 - src/njs_vm.c | 8 ++ src/test/njs_benchmark.c | 9 +- src/test/njs_externals_test.c | 18 +++ src/test/njs_unit_test.c | 31 +++++ 12 files changed, 288 insertions(+), 101 deletions(-) diff --git a/src/njs.h b/src/njs.h index 31cbf787..f486511e 100644 --- a/src/njs.h +++ b/src/njs.h @@ -316,6 +316,13 @@ NJS_EXPORT u_char *njs_vm_value_string_alloc(njs_vm_t *vm, njs_value_t *value, NJS_EXPORT njs_int_t njs_vm_value_string_copy(njs_vm_t *vm, njs_str_t *retval, njs_value_t *value, uintptr_t *next); +/* + * Sets a Uint8Array value. + * start data is not copied and should not be freed. + */ +NJS_EXPORT njs_int_t njs_vm_value_typed_array_uint8_set(njs_vm_t *vm, + njs_value_t *value, const u_char *start, uint32_t size); + /* * Converts a value to string. */ diff --git a/src/njs_array_buffer.c b/src/njs_array_buffer.c index bc1051e6..ab104c78 100644 --- a/src/njs_array_buffer.c +++ b/src/njs_array_buffer.c @@ -111,6 +111,30 @@ njs_array_buffer_is_view(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } +njs_int_t +njs_array_buffer_writable(njs_vm_t *vm, njs_array_buffer_t *buffer) +{ + void *dst; + + if (!buffer->object.shared) { + return NJS_OK; + } + + dst = njs_mp_alloc(vm->mem_pool, buffer->size); + if (njs_slow_path(dst == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } + + memcpy(dst, buffer->u.data, buffer->size); + + buffer->object.shared = 0; + buffer->u.data = dst; + + return NJS_OK; +} + + static const njs_object_prop_t njs_array_buffer_constructor_properties[] = { { diff --git a/src/njs_array_buffer.h b/src/njs_array_buffer.h index 7616c305..6db271b5 100644 --- a/src/njs_array_buffer.h +++ b/src/njs_array_buffer.h @@ -13,7 +13,7 @@ njs_array_buffer_t *njs_array_buffer_alloc(njs_vm_t *vm, uint64_t size); - +njs_int_t njs_array_buffer_writable(njs_vm_t *vm, njs_array_buffer_t *buffer); njs_inline njs_array_buffer_t * njs_array_buffer_slice(njs_vm_t *vm, njs_array_buffer_t *this, int64_t start, diff --git a/src/njs_object.c b/src/njs_object.c index e77e3737..e1a02665 100644 --- a/src/njs_object.c +++ b/src/njs_object.c @@ -668,7 +668,7 @@ njs_object_enumerate_typed_array(njs_vm_t *vm, const njs_typed_array_t *array, case NJS_ENUM_VALUES: for (i = 0; i < length; i++) { - njs_set_number(item++, njs_typed_array_get(array, i)); + njs_set_number(item++, njs_typed_array_prop(array, i)); } break; @@ -681,7 +681,7 @@ njs_object_enumerate_typed_array(njs_vm_t *vm, const njs_typed_array_t *array, } njs_uint32_to_string(&entry->start[0], i); - njs_set_number(&entry->start[1], njs_typed_array_get(array, i)); + njs_set_number(&entry->start[1], njs_typed_array_prop(array, i)); njs_set_array(item++, entry); } diff --git a/src/njs_typed_array.c b/src/njs_typed_array.c index 9418c027..980de7c6 100644 --- a/src/njs_typed_array.c +++ b/src/njs_typed_array.c @@ -19,6 +19,10 @@ typedef enum { } njs_array_iterator_fun_t; +static void njs_typed_array_prop_set(njs_vm_t *vm, njs_typed_array_t *array, + uint32_t index, double v); + + njs_typed_array_t * njs_typed_array_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_object_type_t type) @@ -93,7 +97,7 @@ njs_typed_array_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, size = (uint64_t) njs_typed_array_length(src_tarray) * element_size; } else if (njs_is_object(value)) { - if (njs_is_array(value) && njs_object_hash_is_empty(value)) { + if (njs_is_fast_array(value)) { src_array = njs_array(value); length = src_array->length; @@ -136,8 +140,8 @@ njs_typed_array_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, if (type != src_tarray->type) { length = njs_typed_array_length(src_tarray); for (i = 0; i < length; i++) { - njs_typed_array_set(array, i, - njs_typed_array_get(src_tarray, i)); + njs_typed_array_prop_set(vm, array, i, + njs_typed_array_prop(src_tarray, i)); } } else { @@ -152,7 +156,7 @@ njs_typed_array_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } if (ret == NJS_OK) { - njs_typed_array_set(array, i, num); + njs_typed_array_prop_set(vm, array, i, num); } } @@ -172,7 +176,7 @@ njs_typed_array_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } } - njs_typed_array_set(array, i, num); + njs_typed_array_prop_set(vm, array, i, num); } } @@ -193,6 +197,53 @@ memory_error: } +njs_int_t +njs_typed_array_uint8_set(njs_vm_t *vm, njs_value_t *value, const u_char *start, + uint32_t size) +{ + njs_object_t *proto; + njs_typed_array_t *array; + njs_array_buffer_t *buffer; + + array = njs_mp_zalloc(vm->mem_pool, sizeof(njs_typed_array_t) + + sizeof(njs_array_buffer_t)); + if (njs_slow_path(array == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } + + buffer = (njs_array_buffer_t *) &array[1]; + + proto = &vm->prototypes[NJS_OBJ_TYPE_ARRAY_BUFFER].object; + + njs_lvlhsh_init(&buffer->object.hash); + njs_lvlhsh_init(&buffer->object.shared_hash); + buffer->object.__proto__ = proto; + buffer->object.slots = NULL; + buffer->object.type = NJS_ARRAY_BUFFER; + buffer->object.shared = 1; + buffer->object.extensible = 1; + buffer->object.error_data = 0; + buffer->object.fast_array = 0; + buffer->u.data = (void *) start; + buffer->size = size; + + array->buffer = buffer; + array->byte_length = size; + array->type = NJS_OBJ_TYPE_UINT8_ARRAY; + njs_lvlhsh_init(&array->object.hash); + njs_lvlhsh_init(&array->object.shared_hash); + array->object.__proto__ = &vm->prototypes[array->type].object; + array->object.type = NJS_TYPED_ARRAY; + array->object.extensible = 1; + array->object.fast_array = 1; + + njs_set_typed_array(value, array); + + return NJS_OK; +} + + static njs_int_t njs_typed_array_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t magic) @@ -225,6 +276,23 @@ njs_typed_array_get_this(njs_vm_t *vm, njs_value_t *args, } +njs_array_buffer_t * +njs_typed_array_writable(njs_vm_t *vm, njs_typed_array_t *array) +{ + njs_int_t ret; + njs_array_buffer_t *buffer; + + buffer = array->buffer; + + ret = njs_array_buffer_writable(vm, buffer); + if (njs_slow_path(ret != NJS_OK)) { + return NULL; + } + + return buffer; +} + + static const njs_value_t njs_typed_array_uint8_tag = njs_string("Uint8Array"); static const njs_value_t njs_typed_array_uint8_clamped_tag = njs_long_string("Uint8ClampedArray"); @@ -360,19 +428,82 @@ njs_typed_array_prototype_byte_offset(njs_vm_t *vm, njs_value_t *args, } +static void +njs_typed_array_prop_set(njs_vm_t *vm, njs_typed_array_t *array, uint32_t index, + double v) +{ + int8_t i8; + int16_t i16; + int32_t i32; + njs_array_buffer_t *buffer; + + buffer = array->buffer; + index += array->offset; + + njs_assert(!buffer->object.shared); + + switch (array->type) { + case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY: + if (isnan(v) || v < 0) { + v = 0; + } else if (v > 255) { + v = 255; + } + + buffer->u.u8[index] = lrint(v); + + break; + + case NJS_OBJ_TYPE_UINT8_ARRAY: + case NJS_OBJ_TYPE_INT8_ARRAY: + i8 = njs_number_to_int32(v); + buffer->u.u8[index] = i8; + break; + + case NJS_OBJ_TYPE_UINT16_ARRAY: + case NJS_OBJ_TYPE_INT16_ARRAY: + i16 = njs_number_to_int32(v); + buffer->u.u16[index] = i16; + break; + + case NJS_OBJ_TYPE_UINT32_ARRAY: + case NJS_OBJ_TYPE_INT32_ARRAY: + i32 = njs_number_to_int32(v); + buffer->u.u32[index] = i32; + break; + + case NJS_OBJ_TYPE_FLOAT32_ARRAY: + buffer->u.f32[index] = v; + break; + + default: + + /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */ + + buffer->u.f64[index] = v; + } +} + + njs_int_t njs_typed_array_set_value(njs_vm_t *vm, njs_typed_array_t *array, uint32_t index, njs_value_t *setval) { - double num; - njs_int_t ret; + double num; + njs_int_t ret; + njs_array_buffer_t *buffer; ret = njs_value_to_number(vm, setval, &num); if (njs_slow_path(ret != NJS_OK)) { return ret; } - njs_typed_array_set(array, index, num); + buffer = njs_typed_array_writable(vm, array); + if (njs_slow_path(buffer == NULL)) { + return NJS_ERROR; + } + + njs_typed_array_prop_set(vm, array, index, num); njs_set_number(setval, num); @@ -384,12 +515,13 @@ static njs_int_t njs_typed_array_prototype_set(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { - double num; - int64_t i, length, src_length, offset; - njs_int_t ret; - njs_value_t *this, *src, *value, prop; - njs_array_t *array; - njs_typed_array_t *self, *src_tarray; + double num; + int64_t i, length, src_length, offset; + njs_int_t ret; + njs_value_t *this, *src, *value, prop; + njs_array_t *array; + njs_typed_array_t *self, *src_tarray; + njs_array_buffer_t *buffer; this = njs_argument(args, 0); if (njs_slow_path(!njs_is_typed_array(this))) { @@ -411,6 +543,11 @@ njs_typed_array_prototype_set(njs_vm_t *vm, njs_value_t *args, return NJS_ERROR; } + buffer = njs_typed_array_writable(vm, self); + if (njs_slow_path(buffer == NULL)) { + return NJS_ERROR; + } + length = njs_typed_array_length(self); if (njs_is_typed_array(src)) { @@ -427,12 +564,12 @@ njs_typed_array_prototype_set(njs_vm_t *vm, njs_value_t *args, length = njs_min(njs_typed_array_length(src_tarray), length - offset); for (i = 0; i < length; i++) { - njs_typed_array_set(self, offset + i, - njs_typed_array_get(src_tarray, i)); + njs_typed_array_prop_set(vm, self, offset + i, + njs_typed_array_prop(src_tarray, i)); } } else { - if (njs_is_array(src) && njs_object_hash_is_empty(src)) { + if (njs_is_fast_array(src)) { array = njs_array(src); src_length = array->length; @@ -448,7 +585,7 @@ njs_typed_array_prototype_set(njs_vm_t *vm, njs_value_t *args, for (i = 0; i < length; i++) { ret = njs_value_to_number(vm, &array->start[i], &num); if (ret == NJS_OK) { - njs_typed_array_set(self, offset + i, num); + njs_typed_array_prop_set(vm, self, offset + i, num); } } @@ -489,7 +626,7 @@ njs_typed_array_prototype_set(njs_vm_t *vm, njs_value_t *args, } } - njs_typed_array_set(self, offset + i, num); + njs_typed_array_prop_set(vm, self, offset + i, num); } } @@ -552,9 +689,13 @@ njs_typed_array_prototype_fill(njs_vm_t *vm, njs_value_t *args, end = (end < 0) ? njs_max(length + end, 0) : njs_min(end, length); + buffer = njs_typed_array_writable(vm, array); + if (njs_slow_path(buffer == NULL)) { + return NJS_ERROR; + } + njs_set_typed_array(&vm->retval, array); - buffer = array->buffer; offset = array->offset; switch (array->type) { @@ -744,8 +885,8 @@ njs_typed_array_prototype_slice(njs_vm_t *vm, njs_value_t *args, } else { for (i = 0; i < count; i++) { - njs_typed_array_set(new_array, i, - njs_typed_array_get(array, i + start)); + njs_typed_array_prop_set(vm, new_array, i, + njs_typed_array_prop(array, i + start)); } } @@ -824,7 +965,11 @@ njs_typed_array_prototype_copy_within(njs_vm_t *vm, njs_value_t *args, return NJS_OK; } - buffer = njs_typed_array_buffer(array); + buffer = njs_typed_array_writable(vm, array); + if (njs_slow_path(buffer == NULL)) { + return NJS_ERROR; + } + element_size = njs_typed_array_element_size(array->type); to = (to + array->offset) * element_size; @@ -892,7 +1037,7 @@ njs_typed_array_prototype_iterator(njs_vm_t *vm, njs_value_t *args, } for (i = 0; i < length; i++) { - val = njs_typed_array_get(array, i); + val = njs_typed_array_prop(array, i); arguments[0] = *this_arg; njs_set_number(&arguments[1], val); @@ -1290,14 +1435,14 @@ njs_typed_array_prototype_reduce(njs_vm_t *vm, njs_value_t *args, accumulator = *njs_argument(args, 2); } else { - njs_set_number(&accumulator, njs_typed_array_get(array, from)); + njs_set_number(&accumulator, njs_typed_array_prop(array, from)); from += increment; } for (i = from; i != to; i += increment) { njs_set_undefined(&arguments[0]); arguments[1] = accumulator; - njs_set_number(&arguments[2], njs_typed_array_get(array, i)); + njs_set_number(&arguments[2], njs_typed_array_prop(array, i)); njs_set_number(&arguments[3], i); njs_set_typed_array(&arguments[4], array); @@ -1335,7 +1480,10 @@ njs_typed_array_prototype_reverse(njs_vm_t *vm, njs_value_t *args, array = njs_typed_array(this); length = njs_typed_array_length(array); - buffer = array->buffer; + buffer = njs_typed_array_writable(vm, array); + if (njs_slow_path(buffer == NULL)) { + return NJS_ERROR; + } switch (array->type) { case NJS_OBJ_TYPE_UINT8_ARRAY: @@ -1676,8 +1824,12 @@ njs_typed_array_prototype_sort(njs_vm_t *vm, njs_value_t *args, break; } + buffer = njs_typed_array_writable(vm, array); + if (njs_slow_path(buffer == NULL)) { + return NJS_ERROR; + } + length = njs_typed_array_length(array); - buffer = njs_typed_array_buffer(array); element_size = njs_typed_array_element_size(array->type); base = &buffer->u.u8[array->offset * element_size]; orig = base; @@ -1734,7 +1886,7 @@ njs_typed_array_to_chain(njs_vm_t *vm, njs_chb_t *chain, } for (i = 0; i < arr_length; i++) { - njs_number_to_chain(vm, chain, njs_typed_array_get(array, i)); + njs_number_to_chain(vm, chain, njs_typed_array_prop(array, i)); njs_chb_append(chain, separator.start, separator.size); } diff --git a/src/njs_typed_array.h b/src/njs_typed_array.h index 5548097e..a96446bf 100644 --- a/src/njs_typed_array.h +++ b/src/njs_typed_array.h @@ -10,6 +10,10 @@ njs_typed_array_t *njs_typed_array_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_object_type_t type); +njs_int_t njs_typed_array_uint8_set(njs_vm_t *vm, njs_value_t *value, + const u_char *start, uint32_t size); +njs_array_buffer_t *njs_typed_array_writable(njs_vm_t *vm, + njs_typed_array_t *array); njs_int_t njs_typed_array_set_value(njs_vm_t *vm, njs_typed_array_t *array, uint32_t index, njs_value_t *setval); njs_int_t njs_typed_array_to_chain(njs_vm_t *vm, njs_chb_t *chain, @@ -51,7 +55,7 @@ njs_typed_array_length(const njs_typed_array_t *array) njs_inline double -njs_typed_array_get(const njs_typed_array_t *array, uint32_t index) +njs_typed_array_prop(const njs_typed_array_t *array, uint32_t index) { njs_array_buffer_t *buffer; @@ -91,61 +95,6 @@ njs_typed_array_get(const njs_typed_array_t *array, uint32_t index) } -njs_inline void -njs_typed_array_set(njs_typed_array_t *array, uint32_t index, double v) -{ - int8_t i8; - int16_t i16; - int32_t i32; - njs_array_buffer_t *buffer; - - index += array->offset; - - buffer = array->buffer; - - switch (array->type) { - case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY: - if (isnan(v) || v < 0) { - v = 0; - } else if (v > 255) { - v = 255; - } - - buffer->u.u8[index] = lrint(v); - - break; - - case NJS_OBJ_TYPE_UINT8_ARRAY: - case NJS_OBJ_TYPE_INT8_ARRAY: - i8 = njs_number_to_int32(v); - buffer->u.u8[index] = i8; - break; - - case NJS_OBJ_TYPE_UINT16_ARRAY: - case NJS_OBJ_TYPE_INT16_ARRAY: - i16 = njs_number_to_int32(v); - buffer->u.u16[index] = i16; - break; - - case NJS_OBJ_TYPE_UINT32_ARRAY: - case NJS_OBJ_TYPE_INT32_ARRAY: - i32 = njs_number_to_int32(v); - buffer->u.u32[index] = i32; - break; - - case NJS_OBJ_TYPE_FLOAT32_ARRAY: - buffer->u.f32[index] = v; - break; - - default: - - /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */ - - buffer->u.f64[index] = v; - } -} - - extern const njs_object_type_init_t njs_typed_array_type_init; extern const njs_object_type_init_t njs_typed_array_u8_type_init; extern const njs_object_type_init_t njs_typed_array_u8clamped_type_init; diff --git a/src/njs_value.c b/src/njs_value.c index 4a1756fa..82e9c523 100644 --- a/src/njs_value.c +++ b/src/njs_value.c @@ -812,7 +812,7 @@ njs_typed_array_property_query(njs_vm_t *vm, njs_property_query_t *pq, prop = &pq->scratch; if (pq->query == NJS_PROPERTY_QUERY_GET) { - njs_set_number(&prop->value, njs_typed_array_get(array, index)); + njs_set_number(&prop->value, njs_typed_array_prop(array, index)); prop->type = NJS_PROPERTY; } else { @@ -961,7 +961,7 @@ njs_value_property(njs_vm_t *vm, njs_value_t *value, njs_value_t *key, goto slow_path; } - njs_set_number(retval, njs_typed_array_get(tarray, index)); + njs_set_number(retval, njs_typed_array_prop(tarray, index)); return NJS_OK; } @@ -1084,12 +1084,7 @@ njs_value_property_set(njs_vm_t *vm, njs_value_t *value, njs_value_t *key, tarray = njs_typed_array(value); if (njs_fast_path(index < njs_typed_array_length(tarray))) { - ret = njs_value_to_number(vm, setval, &num); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - - njs_typed_array_set(tarray, index, num); + return njs_typed_array_set_value(vm, tarray, index, setval); } return NJS_OK; diff --git a/src/njs_value.h b/src/njs_value.h index 158a749d..1e984568 100644 --- a/src/njs_value.h +++ b/src/njs_value.h @@ -721,10 +721,6 @@ typedef struct { ((value)->data.u.object->slots) -#define njs_object_hash_is_empty(value) \ - (njs_lvlhsh_is_empty(njs_object_hash(value))) - - #define njs_array(value) \ ((value)->data.u.array) diff --git a/src/njs_vm.c b/src/njs_vm.c index 3a03ce18..a8daf2a0 100644 --- a/src/njs_vm.c +++ b/src/njs_vm.c @@ -696,6 +696,14 @@ njs_vm_value_string_set(njs_vm_t *vm, njs_value_t *value, const u_char *start, } +njs_int_t +njs_vm_value_typed_array_uint8_set(njs_vm_t *vm, njs_value_t *value, + const u_char *start, uint32_t size) +{ + return njs_typed_array_uint8_set(vm, value, start, size); +} + + u_char * njs_vm_value_string_alloc(njs_vm_t *vm, njs_value_t *value, uint32_t size) { diff --git a/src/test/njs_benchmark.c b/src/test/njs_benchmark.c index 7eeb0e35..0025f355 100644 --- a/src/test/njs_benchmark.c +++ b/src/test/njs_benchmark.c @@ -253,7 +253,7 @@ static njs_benchmark_test_t njs_test[] = 1 }, { "typed array 10M", - njs_str("var arr = new Uint8Array(10000000);" + njs_str("var arr = new Uint8Array(10**7);" "var count = 0, length = arr.length;" "arr.fill(2);" "for (var i = 0; i < length; i++) { count += arr[i]; }" @@ -261,6 +261,13 @@ static njs_benchmark_test_t njs_test[] = njs_str("20000000"), 1 }, + { "typed array 10M set", + njs_str("var arr = new Uint32Array(10**7);" + "var length = arr.length;" + "for (var i = 0; i < length; i++) { arr[i] = i; }"), + njs_str("undefined"), + 1 }, + { "external property ($shared.uri)", njs_str("$shared.uri"), njs_str("shared"), diff --git a/src/test/njs_externals_test.c b/src/test/njs_externals_test.c index 85d8144e..67f4cc64 100644 --- a/src/test/njs_externals_test.c +++ b/src/test/njs_externals_test.c @@ -193,6 +193,15 @@ njs_unit_test_r_host(njs_vm_t *vm, njs_object_prop_t *prop, } +static njs_int_t +njs_unit_test_r_u8buffer(njs_vm_t *vm, njs_object_prop_t *prop, + njs_value_t *value, njs_value_t *setval, njs_value_t *retval) +{ + return njs_vm_value_typed_array_uint8_set(vm, retval, + (u_char *) "АБВГДЕЁЖЗИЙ", 22); +} + + static njs_int_t njs_unit_test_r_vars(njs_vm_t *vm, njs_object_prop_t *self, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) @@ -553,6 +562,15 @@ static njs_external_t njs_unit_test_r_external[] = { } }, + { + .flags = NJS_EXTERN_PROPERTY, + .name.string = njs_str("u8buffer"), + .enumerable = 1, + .u.property = { + .handler = njs_unit_test_r_u8buffer, + } + }, + { .flags = NJS_EXTERN_METHOD, .name.string = njs_str("method"), diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index f55c899b..ed8da999 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -18502,6 +18502,37 @@ static njs_unit_test_t njs_externals_test[] = { njs_str("var r = JSON.parse(JSON.stringify($r));" "[r.uri, r.host, r.props.a, njs.dump(r.vars), njs.dump(r.consts), r.header['02']]"), njs_str("АБВ,АБВГДЕЁЖЗИЙ,1,{},{},02|АБВ") }, + + { njs_str("var s = (new TextDecoder()).decode($r.u8buffer); [s, s.length]"), + njs_str("АБВГДЕЁЖЗИЙ,11") }, + + { njs_str("var b = $r.u8buffer; " + "b[4] = '@'.codePointAt(0); b[5] = '#'.codePointAt(0);" + "var s = (new TextDecoder()).decode(b); [s, s.length]"), + njs_str("АБ@#ГДЕЁЖЗИЙ,12") }, + + { njs_str("var b = $r.u8buffer; " + "b.copyWithin(16,0,6);" + "var s = (new TextDecoder()).decode(b); [s, s.length]"), + njs_str("АБВГДЕЁЖАБВ,11") }, + + { njs_str("var b = $r.u8buffer; " + "b.fill('#'.codePointAt(0));" + "var s = (new TextDecoder()).decode(b); [s, s.length]"), + njs_str("######################,22") }, + + { njs_str("var b = $r.u8buffer; " + "b.set(['@'.codePointAt(0), '#'.codePointAt(0)], 4);" + "var s = (new TextDecoder()).decode(b); [s, s.length]"), + njs_str("АБ@#ГДЕЁЖЗИЙ,12") }, + + { njs_str("var b = $r.u8buffer; " + "var u16 = new Uint16Array(b.buffer); u16.reverse();" + "var s = (new TextDecoder()).decode(u16); [s, s.length]"), + njs_str("ЙИЗЖЁЕДГВБА,11") }, + + { njs_str("$r.u8buffer.sort().slice(0,3)"), + njs_str("129,144,145") }, }; static njs_unit_test_t njs_shared_test[] = -- 2.47.3