From 3b907e75436637cb925ed1de32014b58f3a0be14 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Tue, 1 Sep 2020 16:37:33 +0000 Subject: [PATCH] Added DataView object. --- 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(-) diff --git a/src/njs_builtin.c b/src/njs_builtin.c index 636d97fb..352d67a6 100644 --- a/src/njs_builtin.c +++ b/src/njs_builtin.c @@ -71,6 +71,7 @@ static const njs_object_type_init_t *const &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, @@ -1283,6 +1284,16 @@ static const njs_object_prop_t njs_global_this_object_properties[] = .configurable = 1, }, + { + .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"), diff --git a/src/njs_object_hash.h b/src/njs_object_hash.h index aaf25596..0cd25bcf 100644 --- a/src/njs_object_hash.h +++ b/src/njs_object_hash.h @@ -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 --git a/src/njs_typed_array.c b/src/njs_typed_array.c index 980de7c6..0cd5f11b 100644 --- a/src/njs_typed_array.c +++ b/src/njs_typed_array.c @@ -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_t *vm, njs_value_t *args, 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(njs_vm_t *vm, njs_value_t *args, 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(njs_vm_t *vm, njs_value_t *args, 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_array_type_init = { }; +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 --git a/src/njs_typed_array.h b/src/njs_typed_array.h index a96446bf..7e31a7db 100644 --- a/src/njs_typed_array.h +++ b/src/njs_typed_array.h @@ -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_array_t *array, uint32_t index) 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 --git a/src/njs_utils.h b/src/njs_utils.h index 1ba7462a..960954a7 100644 --- a/src/njs_utils.h +++ b/src/njs_utils.h @@ -72,4 +72,36 @@ njs_swap_u64(void *a, void *b, size_t size) } +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 --git a/src/njs_value.c b/src/njs_value.c index 82e9c523..c733aace 100644 --- a/src/njs_value.c +++ b/src/njs_value.c @@ -524,6 +524,7 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *value, 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 --git a/src/njs_value.h b/src/njs_value.h index 1e984568..4a8da81b 100644 --- a/src/njs_value.h +++ b/src/njs_value.h @@ -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 njs_regexp_pattern_t; 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) @@ -928,6 +939,15 @@ njs_set_typed_array(njs_value_t *value, njs_typed_array_t *array) } +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) { diff --git a/src/njs_vm.h b/src/njs_vm.h index 7d12b716..cec67fe6 100644 --- a/src/njs_vm.h +++ b/src/njs_vm.h @@ -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, - NJS_OBJ_TYPE_FS_DIRENT, #define NJS_OBJ_TYPE_HIDDEN_MIN (NJS_OBJ_TYPE_FS_DIRENT) + NJS_OBJ_TYPE_FS_DIRENT, NJS_OBJ_TYPE_CRYPTO_HASH, NJS_OBJ_TYPE_CRYPTO_HMAC, NJS_OBJ_TYPE_TYPED_ARRAY, diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index ed8da999..b6efe042 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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}});" -- 2.47.3