[njs] Introduced copy-on-write for ArrayBuffer.
Dmitry Volyntsev
xeioex at nginx.com
Fri Aug 28 11:52:54 UTC 2020
details: https://hg.nginx.org/njs/rev/d3e1f95c0c5c
branches:
changeset: 1512:d3e1f95c0c5c
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Fri Aug 28 11:51:35 2020 +0000
description:
Introduced copy-on-write for ArrayBuffer.
diffstat:
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(-)
diffs (720 lines):
diff -r b0092a58d4fa -r d3e1f95c0c5c src/njs.h
--- a/src/njs.h Fri Aug 28 11:48:22 2020 +0000
+++ b/src/njs.h Fri Aug 28 11:51:35 2020 +0000
@@ -317,6 +317,13 @@ NJS_EXPORT njs_int_t njs_vm_value_string
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.
*/
NJS_EXPORT njs_int_t njs_vm_value_to_string(njs_vm_t *vm, njs_str_t *dst,
diff -r b0092a58d4fa -r d3e1f95c0c5c src/njs_array_buffer.c
--- a/src/njs_array_buffer.c Fri Aug 28 11:48:22 2020 +0000
+++ b/src/njs_array_buffer.c Fri Aug 28 11:51:35 2020 +0000
@@ -111,6 +111,30 @@ njs_array_buffer_is_view(njs_vm_t *vm, n
}
+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 -r b0092a58d4fa -r d3e1f95c0c5c src/njs_array_buffer.h
--- a/src/njs_array_buffer.h Fri Aug 28 11:48:22 2020 +0000
+++ b/src/njs_array_buffer.h Fri Aug 28 11:51:35 2020 +0000
@@ -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 -r b0092a58d4fa -r d3e1f95c0c5c src/njs_object.c
--- a/src/njs_object.c Fri Aug 28 11:48:22 2020 +0000
+++ b/src/njs_object.c Fri Aug 28 11:51:35 2020 +0000
@@ -668,7 +668,7 @@ njs_object_enumerate_typed_array(njs_vm_
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_
}
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 -r b0092a58d4fa -r d3e1f95c0c5c src/njs_typed_array.c
--- a/src/njs_typed_array.c Fri Aug 28 11:48:22 2020 +0000
+++ b/src/njs_typed_array.c Fri Aug 28 11:51:35 2020 +0000
@@ -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_
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_
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_
}
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_
}
}
- 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, n
}
+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(nj
}
+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 *
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 *
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 *
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 *
}
}
- 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
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
} 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(nj
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_v
}
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_
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
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
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, n
}
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 -r b0092a58d4fa -r d3e1f95c0c5c src/njs_typed_array.h
--- a/src/njs_typed_array.h Fri Aug 28 11:48:22 2020 +0000
+++ b/src/njs_typed_array.h Fri Aug 28 11:51:35 2020 +0000
@@ -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_a
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_arra
}
-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 -r b0092a58d4fa -r d3e1f95c0c5c src/njs_value.c
--- a/src/njs_value.c Fri Aug 28 11:48:22 2020 +0000
+++ b/src/njs_value.c Fri Aug 28 11:51:35 2020 +0000
@@ -812,7 +812,7 @@ njs_typed_array_property_query(njs_vm_t
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_val
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
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 -r b0092a58d4fa -r d3e1f95c0c5c src/njs_value.h
--- a/src/njs_value.h Fri Aug 28 11:48:22 2020 +0000
+++ b/src/njs_value.h Fri Aug 28 11:51:35 2020 +0000
@@ -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 -r b0092a58d4fa -r d3e1f95c0c5c src/njs_vm.c
--- a/src/njs_vm.c Fri Aug 28 11:48:22 2020 +0000
+++ b/src/njs_vm.c Fri Aug 28 11:51:35 2020 +0000
@@ -696,6 +696,14 @@ njs_vm_value_string_set(njs_vm_t *vm, nj
}
+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 -r b0092a58d4fa -r d3e1f95c0c5c src/test/njs_benchmark.c
--- a/src/test/njs_benchmark.c Fri Aug 28 11:48:22 2020 +0000
+++ b/src/test/njs_benchmark.c Fri Aug 28 11:51:35 2020 +0000
@@ -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 -r b0092a58d4fa -r d3e1f95c0c5c src/test/njs_externals_test.c
--- a/src/test/njs_externals_test.c Fri Aug 28 11:48:22 2020 +0000
+++ b/src/test/njs_externals_test.c Fri Aug 28 11:51:35 2020 +0000
@@ -194,6 +194,15 @@ njs_unit_test_r_host(njs_vm_t *vm, njs_o
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)
{
@@ -554,6 +563,15 @@ static njs_external_t njs_unit_test_r_e
},
{
+ .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"),
.writable = 1,
diff -r b0092a58d4fa -r d3e1f95c0c5c src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Fri Aug 28 11:48:22 2020 +0000
+++ b/src/test/njs_unit_test.c Fri Aug 28 11:51:35 2020 +0000
@@ -18502,6 +18502,37 @@ static njs_unit_test_t njs_externals_te
{ 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[] =
More information about the nginx-devel
mailing list