[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