[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