[njs] Added DataView object.

Dmitry Volyntsev xeioex at nginx.com
Tue Sep 1 17:14:17 UTC 2020


details:   https://hg.nginx.org/njs/rev/d00a6ec5a39a
branches:  
changeset: 1513:d00a6ec5a39a
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue Sep 01 16:37:33 2020 +0000
description:
Added DataView object.

diffstat:

 src/njs_builtin.c        |   11 +
 src/njs_object_hash.h    |   12 +
 src/njs_typed_array.c    |  558 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/njs_typed_array.h    |    2 +
 src/njs_utils.h          |   32 ++
 src/njs_value.c          |    1 +
 src/njs_value.h          |   20 +
 src/njs_vm.h             |    3 +-
 src/test/njs_unit_test.c |   86 +++++++
 9 files changed, 721 insertions(+), 4 deletions(-)

diffs (894 lines):

diff -r d3e1f95c0c5c -r d00a6ec5a39a src/njs_builtin.c
--- a/src/njs_builtin.c	Fri Aug 28 11:51:35 2020 +0000
+++ b/src/njs_builtin.c	Tue Sep 01 16:37:33 2020 +0000
@@ -71,6 +71,7 @@ static const njs_object_type_init_t *con
     &njs_date_type_init,
     &njs_promise_type_init,
     &njs_array_buffer_type_init,
+    &njs_data_view_type_init,
     &njs_text_decoder_type_init,
     &njs_text_encoder_type_init,
 
@@ -1285,6 +1286,16 @@ static const njs_object_prop_t  njs_glob
 
     {
         .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("DataView"),
+        .value = njs_prop_handler2(njs_top_level_constructor,
+                                   NJS_OBJ_TYPE_DATA_VIEW,
+                                   NJS_DATA_VIEW_HASH),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
         .name = njs_string("TextDecoder"),
         .value = njs_prop_handler2(njs_top_level_constructor,
                                    NJS_OBJ_TYPE_TEXT_DECODER,
diff -r d3e1f95c0c5c -r d00a6ec5a39a src/njs_object_hash.h
--- a/src/njs_object_hash.h	Fri Aug 28 11:51:35 2020 +0000
+++ b/src/njs_object_hash.h	Tue Sep 01 16:37:33 2020 +0000
@@ -611,6 +611,18 @@
         'A'), 'r'), 'r'), 'a'), 'y'), 'B'), 'u'), 'f'), 'f'), 'e'), 'r')
 
 
+#define NJS_DATA_VIEW_HASH                                                    \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(NJS_DJB_HASH_INIT,                                       \
+        'D'), 'a'), 't'), 'a'), 'V'), 'i'), 'e'), 'w')
+
+
 #define NJS_UINT8ARRAY_HASH                                                   \
     njs_djb_hash_add(                                                         \
     njs_djb_hash_add(                                                         \
diff -r d3e1f95c0c5c -r d00a6ec5a39a src/njs_typed_array.c
--- a/src/njs_typed_array.c	Fri Aug 28 11:51:35 2020 +0000
+++ b/src/njs_typed_array.c	Tue Sep 01 16:37:33 2020 +0000
@@ -1,6 +1,7 @@
 
 /*
  * Copyright (C) Igor Sysoev
+ * Copyright (C) Dmitry Volyntsev
  * Copyright (C) NGINX, Inc.
  */
 
@@ -369,7 +370,7 @@ njs_typed_array_prototype_buffer(njs_vm_
     njs_typed_array_t  *array;
 
     this = njs_argument(args, 0);
-    if (!njs_is_typed_array(this)) {
+    if (!njs_is_typed_array(this) && !njs_is_data_view(this)) {
         njs_type_error(vm, "Method TypedArray.prototype.buffer called "
                        "on incompatible receiver");
         return NJS_ERROR;
@@ -391,7 +392,7 @@ njs_typed_array_prototype_byte_length(nj
     njs_typed_array_t  *array;
 
     this = njs_argument(args, 0);
-    if (!njs_is_typed_array(this)) {
+    if (!njs_is_typed_array(this) && !njs_is_data_view(this)) {
         njs_type_error(vm, "Method TypedArray.prototype.byteLength called "
                        "on incompatible receiver");
         return NJS_ERROR;
@@ -413,7 +414,7 @@ njs_typed_array_prototype_byte_offset(nj
     njs_typed_array_t  *array;
 
     this = njs_argument(args, 0);
-    if (!njs_is_typed_array(this)) {
+    if (!njs_is_typed_array(this) && !njs_is_data_view(this)) {
         njs_type_error(vm, "Method TypedArray.prototype.byteOffset called "
                        "on incompatible receiver");
         return NJS_ERROR;
@@ -2269,6 +2270,557 @@ const njs_object_type_init_t  njs_typed_
 };
 
 
+static njs_int_t
+njs_data_view_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    uint64_t            size, offset;
+    njs_int_t           ret;
+    njs_data_view_t     *view;
+    njs_array_buffer_t  *buffer;
+
+    if (!vm->top_frame->ctor) {
+        njs_type_error(vm, "Constructor of DataView requires 'new'");
+        return NJS_ERROR;
+    }
+
+    if (!njs_is_array_buffer(njs_arg(args, nargs, 1))) {
+        njs_type_error(vm, "buffer is not an ArrayBuffer");
+        return NJS_ERROR;
+    }
+
+    size = 0;
+    offset = 0;
+
+    buffer = njs_array_buffer(njs_argument(args, 1));
+
+    ret = njs_value_to_index(vm, njs_arg(args, nargs, 2), &offset);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    if (!njs_is_undefined(njs_arg(args, nargs, 3))) {
+        ret = njs_value_to_index(vm, njs_argument(args, 3), &size);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return NJS_ERROR;
+        }
+
+        if (njs_slow_path((offset + size) > buffer->size)) {
+            njs_range_error(vm, "Invalid DataView length: %uL", size);
+            return NJS_ERROR;
+        }
+
+    } else {
+        if (offset > buffer->size) {
+            njs_range_error(vm, "byteOffset %uL is outside the bound of "
+                            "the buffer", offset);
+            return NJS_ERROR;
+        }
+
+        size = buffer->size - offset;
+    }
+
+    view = njs_mp_zalloc(vm->mem_pool, sizeof(njs_data_view_t));
+    if (njs_slow_path(view == NULL)) {
+        goto memory_error;
+    }
+
+    view->buffer = buffer;
+    view->offset = offset;
+    view->byte_length = size;
+    view->type = NJS_OBJ_TYPE_DATA_VIEW;
+
+    njs_lvlhsh_init(&view->object.hash);
+    njs_lvlhsh_init(&view->object.shared_hash);
+    view->object.__proto__ = &vm->prototypes[view->type].object;
+    view->object.type = NJS_DATA_VIEW;
+    view->object.extensible = 1;
+
+    njs_set_data_view(&vm->retval, view);
+
+    return NJS_OK;
+
+memory_error:
+
+    njs_memory_error(vm);
+
+    return NJS_ERROR;
+}
+
+
+static const njs_object_prop_t  njs_data_view_constructor_props[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("DataView"),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 1.0),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("prototype"),
+        .value = njs_prop_handler(njs_object_prototype_create),
+    },
+};
+
+
+static const njs_object_init_t  njs_data_view_constructor_init = {
+    njs_data_view_constructor_props,
+    njs_nitems(njs_data_view_constructor_props),
+};
+
+
+typedef union {
+    float       f;
+    uint32_t    u;
+} njs_conv_f32_t;
+
+
+typedef union {
+    double      f;
+    uint64_t    u;
+} njs_conv_f64_t;
+
+
+static njs_int_t
+njs_data_view_prototype_get(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t type)
+{
+    double              v;
+    uint32_t            u32;
+    uint64_t            index;
+    njs_int_t           ret;
+    njs_bool_t          swap;
+    njs_value_t         *this;
+    const uint8_t       *u8;
+    njs_conv_f32_t      conv_f32;
+    njs_conv_f64_t      conv_f64;
+    njs_data_view_t     *view;
+    njs_array_buffer_t  *buffer;
+
+    this = njs_argument(args, 0);
+    if (njs_slow_path(!njs_is_data_view(this))) {
+        njs_type_error(vm, "this is not a DataView");
+        return NJS_ERROR;
+    }
+
+    ret = njs_value_to_index(vm, njs_arg(args, nargs, 1), &index);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    swap = njs_bool(njs_arg(args, nargs, 2));
+
+#if NJS_HAVE_LITTLE_ENDIAN
+    swap = !swap;
+#endif
+
+    view = njs_data_view(this);
+
+    if (njs_typed_array_element_size(type) + index > view->byte_length) {
+        njs_range_error(vm, "index %uL is outside the bound of the buffer",
+                        index);
+        return NJS_ERROR;
+    }
+
+    buffer = view->buffer;
+    u8 = &buffer->u.u8[index + view->offset];
+
+    switch (type) {
+    case NJS_OBJ_TYPE_UINT8_ARRAY:
+        v = *u8;
+        break;
+
+    case NJS_OBJ_TYPE_INT8_ARRAY:
+        v = (int8_t) *u8;
+        break;
+
+    case NJS_OBJ_TYPE_UINT16_ARRAY:
+        u32 = *((uint16_t *) u8);
+
+        if (swap) {
+            u32 = njs_bswap_u16(u32);
+        }
+
+        v = u32;
+        break;
+
+    case NJS_OBJ_TYPE_INT16_ARRAY:
+        u32 = *((uint16_t *) u8);
+
+        if (swap) {
+            u32 = njs_bswap_u16(u32);
+        }
+
+        v = (int16_t) u32;
+        break;
+
+    case NJS_OBJ_TYPE_UINT32_ARRAY:
+    case NJS_OBJ_TYPE_INT32_ARRAY:
+    case NJS_OBJ_TYPE_FLOAT32_ARRAY:
+        u32 = *((uint32_t *) u8);
+
+        if (swap) {
+            u32 = njs_bswap_u32(u32);
+        }
+
+        switch (type) {
+        case NJS_OBJ_TYPE_UINT32_ARRAY:
+            v = u32;
+            break;
+
+        case NJS_OBJ_TYPE_INT32_ARRAY:
+            v = (int32_t) u32;
+            break;
+
+        default:
+            conv_f32.u = u32;
+            v = conv_f32.f;
+        }
+
+        break;
+
+    default:
+        /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */
+
+        conv_f64.u = *((uint64_t *) u8);
+
+        if (swap) {
+            conv_f64.u = njs_bswap_u64(conv_f64.u);
+        }
+
+        v = conv_f64.f;
+    }
+
+    njs_set_number(&vm->retval, v);
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
+njs_data_view_prototype_set(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t type)
+{
+    double              v;
+    uint8_t             *u8;
+    uint32_t            u32;
+    uint64_t            index;
+    njs_int_t           ret;
+    njs_bool_t          swap;
+    njs_value_t         *this;
+    njs_conv_f32_t      conv_f32;
+    njs_conv_f64_t      conv_f64;
+    njs_data_view_t     *view;
+    njs_array_buffer_t  *buffer;
+
+    this = njs_argument(args, 0);
+    if (njs_slow_path(!njs_is_data_view(this))) {
+        njs_type_error(vm, "this is not a DataView");
+        return NJS_ERROR;
+    }
+
+    ret = njs_value_to_index(vm, njs_arg(args, nargs, 1), &index);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_value_to_number(vm, njs_arg(args, nargs, 2), &v);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    swap = njs_bool(njs_arg(args, nargs, 3));
+
+#if NJS_HAVE_LITTLE_ENDIAN
+    swap = !swap;
+#endif
+
+    view = njs_data_view(this);
+
+    if (njs_typed_array_element_size(type) + index > view->byte_length) {
+        njs_range_error(vm, "index %uL is outside the bound of the buffer",
+                        index);
+        return NJS_ERROR;
+    }
+
+    buffer = view->buffer;
+    u8 = &buffer->u.u8[index + view->offset];
+
+    switch (type) {
+    case NJS_OBJ_TYPE_UINT8_ARRAY:
+    case NJS_OBJ_TYPE_INT8_ARRAY:
+        *u8 = njs_number_to_int32(v);
+        break;
+
+    case NJS_OBJ_TYPE_UINT16_ARRAY:
+    case NJS_OBJ_TYPE_INT16_ARRAY:
+        u32 = (uint16_t) njs_number_to_int32(v);
+
+        if (swap) {
+            u32 = njs_bswap_u16(u32);
+        }
+
+        *((uint16_t *) u8) = u32;
+        break;
+
+    case NJS_OBJ_TYPE_UINT32_ARRAY:
+    case NJS_OBJ_TYPE_INT32_ARRAY:
+        u32 = njs_number_to_int32(v);
+
+        if (swap) {
+            u32 = njs_bswap_u32(u32);
+        }
+
+        *((uint32_t *) u8) = u32;
+        break;
+
+    case NJS_OBJ_TYPE_FLOAT32_ARRAY:
+        conv_f32.f = (float) v;
+
+        if (swap) {
+            conv_f32.u = njs_bswap_u32(conv_f32.u);
+        }
+
+        *((uint32_t *) u8) = conv_f32.u;
+        break;
+
+    default:
+        /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */
+
+        conv_f64.f = v;
+
+        if (swap) {
+            conv_f64.u = njs_bswap_u64(conv_f64.u);
+        }
+
+        *((uint64_t *) u8) = conv_f64.u;
+    }
+
+    njs_set_undefined(&vm->retval);
+
+    return NJS_OK;
+}
+
+
+static const njs_object_prop_t  njs_data_view_prototype_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG),
+        .value = njs_string("DataView"),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("constructor"),
+        .value = njs_prop_handler(njs_object_prototype_create_constructor),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("buffer"),
+        .value = njs_value(NJS_INVALID, 1, NAN),
+        .getter = njs_native_function(njs_typed_array_prototype_buffer, 0),
+        .setter = njs_value(NJS_UNDEFINED, 0, NAN),
+        .writable = NJS_ATTRIBUTE_UNSET,
+        .configurable = 1,
+        .enumerable = 0,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("byteLength"),
+        .value = njs_value(NJS_INVALID, 1, NAN),
+        .getter = njs_native_function(njs_typed_array_prototype_byte_length, 0),
+        .setter = njs_value(NJS_UNDEFINED, 0, NAN),
+        .writable = NJS_ATTRIBUTE_UNSET,
+        .configurable = 1,
+        .enumerable = 0,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("byteOffset"),
+        .value = njs_value(NJS_INVALID, 1, NAN),
+        .getter = njs_native_function(njs_typed_array_prototype_byte_offset, 0),
+        .setter = njs_value(NJS_UNDEFINED, 0, NAN),
+        .writable = NJS_ATTRIBUTE_UNSET,
+        .configurable = 1,
+        .enumerable = 0,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("getUint8"),
+        .value = njs_native_function2(njs_data_view_prototype_get, 1,
+                                      NJS_OBJ_TYPE_UINT8_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("getInt8"),
+        .value = njs_native_function2(njs_data_view_prototype_get, 1,
+                                      NJS_OBJ_TYPE_INT8_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("getUint16"),
+        .value = njs_native_function2(njs_data_view_prototype_get, 1,
+                                      NJS_OBJ_TYPE_UINT16_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("getInt16"),
+        .value = njs_native_function2(njs_data_view_prototype_get, 1,
+                                      NJS_OBJ_TYPE_INT16_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("getUint32"),
+        .value = njs_native_function2(njs_data_view_prototype_get, 1,
+                                      NJS_OBJ_TYPE_UINT32_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("getInt32"),
+        .value = njs_native_function2(njs_data_view_prototype_get, 1,
+                                      NJS_OBJ_TYPE_INT32_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("getFloat32"),
+        .value = njs_native_function2(njs_data_view_prototype_get, 1,
+                                      NJS_OBJ_TYPE_FLOAT32_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("getFloat64"),
+        .value = njs_native_function2(njs_data_view_prototype_get, 1,
+                                      NJS_OBJ_TYPE_FLOAT64_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("setUint8"),
+        .value = njs_native_function2(njs_data_view_prototype_set, 2,
+                                      NJS_OBJ_TYPE_UINT8_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("setInt8"),
+        .value = njs_native_function2(njs_data_view_prototype_set, 2,
+                                      NJS_OBJ_TYPE_INT8_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("setUint16"),
+        .value = njs_native_function2(njs_data_view_prototype_set, 2,
+                                      NJS_OBJ_TYPE_UINT16_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("setInt16"),
+        .value = njs_native_function2(njs_data_view_prototype_set, 2,
+                                      NJS_OBJ_TYPE_INT16_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("setUint32"),
+        .value = njs_native_function2(njs_data_view_prototype_set, 2,
+                                      NJS_OBJ_TYPE_UINT32_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("setInt32"),
+        .value = njs_native_function2(njs_data_view_prototype_set, 2,
+                                      NJS_OBJ_TYPE_INT32_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("setFloat32"),
+        .value = njs_native_function2(njs_data_view_prototype_set, 2,
+                                      NJS_OBJ_TYPE_FLOAT32_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("setFloat64"),
+        .value = njs_native_function2(njs_data_view_prototype_set, 2,
+                                      NJS_OBJ_TYPE_FLOAT64_ARRAY),
+        .writable = 1,
+        .configurable = 1,
+    },
+};
+
+
+static const njs_object_init_t  njs_data_view_prototype_init = {
+    njs_data_view_prototype_properties,
+    njs_nitems(njs_data_view_prototype_properties),
+};
+
+
+const njs_object_type_init_t  njs_data_view_type_init = {
+    .constructor = njs_native_ctor(njs_data_view_constructor, 1, 0),
+    .prototype_props = &njs_data_view_prototype_init,
+    .constructor_props = &njs_data_view_constructor_init,
+    .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
 static const njs_object_prop_t  njs_typed_array_u8_constructor_props[] =
 {
     {
diff -r d3e1f95c0c5c -r d00a6ec5a39a src/njs_typed_array.h
--- a/src/njs_typed_array.h	Fri Aug 28 11:51:35 2020 +0000
+++ b/src/njs_typed_array.h	Tue Sep 01 16:37:33 2020 +0000
@@ -24,6 +24,7 @@ njs_inline unsigned
 njs_typed_array_element_size(njs_object_type_t type)
 {
     switch (type) {
+    case NJS_OBJ_TYPE_DATA_VIEW:
     case NJS_OBJ_TYPE_UINT8_ARRAY:
     case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY:
     case NJS_OBJ_TYPE_INT8_ARRAY:
@@ -96,6 +97,7 @@ njs_typed_array_prop(const njs_typed_arr
 
 
 extern const njs_object_type_init_t  njs_typed_array_type_init;
+extern const njs_object_type_init_t  njs_data_view_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;
 extern const njs_object_type_init_t  njs_typed_array_i8_type_init;
diff -r d3e1f95c0c5c -r d00a6ec5a39a src/njs_utils.h
--- a/src/njs_utils.h	Fri Aug 28 11:51:35 2020 +0000
+++ b/src/njs_utils.h	Tue Sep 01 16:37:33 2020 +0000
@@ -72,4 +72,36 @@ njs_swap_u64(void *a, void *b, size_t si
 }
 
 
+njs_inline uint16_t
+njs_bswap_u16(uint16_t u16)
+{
+    return (u16 >> 8)
+           | (u16 << 8);
+}
+
+
+njs_inline uint32_t
+njs_bswap_u32(uint32_t u32)
+{
+    return ((u32 & 0xff000000) >> 24)
+           | ((u32 & 0x00ff0000) >> 8)
+           | ((u32 & 0x0000ff00) << 8)
+           | ((u32 & 0x000000ff) << 24);
+}
+
+
+njs_inline uint64_t
+njs_bswap_u64(uint64_t u64)
+{
+    return ((u64 & 0xff00000000000000ULL) >> 56)
+           | ((u64 & 0x00ff000000000000ULL) >> 40)
+           | ((u64 & 0x0000ff0000000000ULL) >> 24)
+           | ((u64 & 0x000000ff00000000ULL) >> 8)
+           | ((u64 & 0x00000000ff000000ULL) << 8)
+           | ((u64 & 0x0000000000ff0000ULL) << 24)
+           | ((u64 & 0x000000000000ff00ULL) << 40)
+           | ((u64 & 0x00000000000000ffULL) << 56);
+}
+
+
 #endif /* _NJS_UTILS_H_INCLUDED_ */
diff -r d3e1f95c0c5c -r d00a6ec5a39a src/njs_value.c
--- a/src/njs_value.c	Fri Aug 28 11:51:35 2020 +0000
+++ b/src/njs_value.c	Tue Sep 01 16:37:33 2020 +0000
@@ -524,6 +524,7 @@ njs_property_query(njs_vm_t *vm, njs_pro
     case NJS_OBJECT:
     case NJS_ARRAY:
     case NJS_ARRAY_BUFFER:
+    case NJS_DATA_VIEW:
     case NJS_TYPED_ARRAY:
     case NJS_OBJECT_BOOLEAN:
     case NJS_OBJECT_NUMBER:
diff -r d3e1f95c0c5c -r d00a6ec5a39a src/njs_value.h
--- a/src/njs_value.h	Fri Aug 28 11:51:35 2020 +0000
+++ b/src/njs_value.h	Tue Sep 01 16:37:33 2020 +0000
@@ -72,6 +72,7 @@ typedef enum {
     NJS_PROMISE,
     NJS_OBJECT_VALUE,
     NJS_ARRAY_BUFFER,
+    NJS_DATA_VIEW,
     NJS_VALUE_TYPE_MAX
 } njs_value_type_t;
 
@@ -95,6 +96,7 @@ typedef struct njs_regexp_pattern_s   nj
 typedef struct njs_array_s            njs_array_t;
 typedef struct njs_array_buffer_s     njs_array_buffer_t;
 typedef struct njs_typed_array_s      njs_typed_array_t;
+typedef struct njs_typed_array_s      njs_data_view_t;
 typedef struct njs_regexp_s           njs_regexp_t;
 typedef struct njs_date_s             njs_date_t;
 typedef struct njs_object_value_s     njs_promise_t;
@@ -141,6 +143,7 @@ union njs_value_s {
             njs_array_t               *array;
             njs_array_buffer_t        *array_buffer;
             njs_typed_array_t         *typed_array;
+            njs_data_view_t           *data_view;
             njs_object_value_t        *object_value;
             njs_function_t            *function;
             njs_function_lambda_t     *lambda;
@@ -656,6 +659,10 @@ typedef struct {
     ((value)->type == NJS_TYPED_ARRAY)
 
 
+#define njs_is_data_view(value)                                               \
+    ((value)->type == NJS_DATA_VIEW)
+
+
 #define njs_is_typed_array_uint8(value)                                       \
     (njs_is_typed_array(value)                                                \
      && njs_typed_array(value)->type == NJS_OBJ_TYPE_UINT8_ARRAY)
@@ -733,6 +740,10 @@ typedef struct {
     ((value)->data.u.array_buffer)
 
 
+#define njs_data_view(value)                                                  \
+    ((value)->data.u.data_view)
+
+
 #define njs_typed_array(value)                                                \
     ((value)->data.u.typed_array)
 
@@ -929,6 +940,15 @@ njs_set_typed_array(njs_value_t *value, 
 
 
 njs_inline void
+njs_set_data_view(njs_value_t *value, njs_data_view_t *array)
+{
+    value->data.u.data_view = array;
+    value->type = NJS_DATA_VIEW;
+    value->data.truth = 1;
+}
+
+
+njs_inline void
 njs_set_function(njs_value_t *value, njs_function_t *function)
 {
     value->data.u.function = function;
diff -r d3e1f95c0c5c -r d00a6ec5a39a src/njs_vm.h
--- a/src/njs_vm.h	Fri Aug 28 11:51:35 2020 +0000
+++ b/src/njs_vm.h	Tue Sep 01 16:37:33 2020 +0000
@@ -84,11 +84,12 @@ typedef enum {
     NJS_OBJ_TYPE_DATE,
     NJS_OBJ_TYPE_PROMISE,
     NJS_OBJ_TYPE_ARRAY_BUFFER,
+    NJS_OBJ_TYPE_DATA_VIEW,
     NJS_OBJ_TYPE_TEXT_DECODER,
     NJS_OBJ_TYPE_TEXT_ENCODER,
 
+#define NJS_OBJ_TYPE_HIDDEN_MIN    (NJS_OBJ_TYPE_FS_DIRENT)
     NJS_OBJ_TYPE_FS_DIRENT,
-#define NJS_OBJ_TYPE_HIDDEN_MIN    (NJS_OBJ_TYPE_FS_DIRENT)
     NJS_OBJ_TYPE_CRYPTO_HASH,
     NJS_OBJ_TYPE_CRYPTO_HMAC,
     NJS_OBJ_TYPE_TYPED_ARRAY,
diff -r d3e1f95c0c5c -r d00a6ec5a39a src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Fri Aug 28 11:51:35 2020 +0000
+++ b/src/test/njs_unit_test.c	Tue Sep 01 16:37:33 2020 +0000
@@ -6232,6 +6232,92 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("(new Float64Array([255,255,NaN,3,NaN,Infinity,3,-Infinity,0,-0,2,1,-5])).slice(2).sort()"),
       njs_str("-Infinity,-5,0,0,1,2,3,3,Infinity,NaN,NaN") },
 
+    { njs_str("(new DataView(new ArrayBuffer(3)))"),
+      njs_str("[object DataView]") },
+
+    { njs_str("(new DataView(new ArrayBuffer(3))).buffer"),
+      njs_str("[object ArrayBuffer]") },
+
+    { njs_str("(new DataView(new ArrayBuffer(3))).byteLength"),
+      njs_str("3") },
+
+    { njs_str("(new DataView(new ArrayBuffer(3), 1)).byteLength"),
+      njs_str("2") },
+
+    { njs_str("(new DataView(new ArrayBuffer(3), 3)).byteLength"),
+      njs_str("0") },
+
+    { njs_str("(new DataView(new ArrayBuffer(3), 1)).byteOffset"),
+      njs_str("1") },
+
+    { njs_str("(new DataView(new ArrayBuffer(3), 1, 1)).byteLength"),
+      njs_str("1") },
+
+    { njs_str("(new DataView(new ArrayBuffer(3), 4))"),
+      njs_str("RangeError: byteOffset 4 is outside the bound of the buffer") },
+
+    { njs_str("(new DataView(new ArrayBuffer(3), 1,3))"),
+      njs_str("RangeError: Invalid DataView length: 3") },
+
+    { njs_str("var u8 = new Uint8Array([255, 129, 130, 131, 4, 5, 6, 7, 8, 9, 255]); "
+              "var dv = new DataView(u8.buffer, 1); "
+              "['getUint8', 'getInt8',"
+              " 'getUint16', 'getInt16',"
+              " 'getUint32', 'getInt32',"
+              " 'getFloat32','getFloat64'"
+              "]"
+              ".map(fn => [dv[fn](0), dv[fn](0,1), dv[fn](1), dv[fn](1,1)])"),
+      njs_str("129,129,130,130,"
+              "-127,-127,-126,-126,"
+              "33154,33409,33411,33666,"
+              "-32382,-32127,-32125,-31870,"
+              "2172814084,75727489,2189624325,84181890,"
+              "-2122153212,75727489,-2105342971,84181890,"
+              "-4.794245620412925e-38,3.091780090135418e-36,-1.9251027092506622e-37,6.230764342760857e-36,"
+              "-2.159546358334202e-301,5.447603729090798e-270,-1.4538065947240604e-296,3.72581468952343e-265") },
+
+    { njs_str("var u8 = new Uint8Array(10);"
+              "var dv = new DataView(u8.buffer, 1);"
+              "var u8view = new Uint8Array(u8.buffer, 1);"
+              "function run(test) {"
+              "     var fn = test[0];"
+              "     var val = test[1];"
+              "     var size = parseInt(fn.match(/\\d+/)) / 8;"
+              "     "
+              "     return  [[0], [0,1],[1], [1,1]].map(args => {"
+              "           var offset = args[0];"
+              "           var le = args[1];"
+              "           u8.fill(0); "
+              "           dv[fn].apply(dv, [offset, val, le]);"
+              "           return `[${u8view.subarray(0, offset + size)}]`;"
+              "     })"
+              "};"
+              "["
+              " ['setUint8',    129],"
+              " ['setInt8',    -127],"
+              " ['setUint16', 33154],"
+              " ['setInt16', -32382],"
+              " ['setUint32', 2172814084],"
+              " ['setInt32', -2122153212],"
+              " ['setFloat32', -4.794245620412925e-38],"
+              " ['setFloat64', -2.159546358334202e-301],"
+              "]"
+              ".map(t => run(t))"),
+      njs_str("[129],[129],[0,129],[0,129],"
+              "[129],[129],[0,129],[0,129],"
+              "[129,130],[130,129],[0,129,130],[0,130,129],"
+              "[129,130],[130,129],[0,129,130],[0,130,129],"
+              "[129,130,131,4],[4,131,130,129],[0,129,130,131,4],[0,4,131,130,129],"
+              "[129,130,131,4],[4,131,130,129],[0,129,130,131,4],[0,4,131,130,129],"
+              "[129,130,131,4],[4,131,130,129],[0,129,130,131,4],[0,4,131,130,129],"
+              "[129,130,131,4,5,6,7,8],[8,7,6,5,4,131,130,129],[0,129,130,131,4,5,6,7,8],[0,8,7,6,5,4,131,130,129]"
+              ) },
+
+    { njs_str("var u8 = new Uint8Array([1,2,3]); "
+              "var dv = new DataView(u8.buffer); "
+              "dv.getUint16(2)"),
+      njs_str("RangeError: index 2 is outside the bound of the buffer") },
+
 #if NJS_HAVE_LARGE_STACK
     { njs_str("var o = Object({length: 3});"
                  "Object.defineProperty(o, '0', {set: function(v){this[0] = 2 * v}});"


More information about the nginx-devel mailing list