src/njs_generator.c \
src/njs_disassembler.c \
src/njs_array_buffer.c \
+ src/njs_typed_array.c \
src/njs_promise.c \
"
NJS_EXPORT njs_int_t njs_vm_retval_string(njs_vm_t *vm, njs_str_t *dst);
NJS_EXPORT njs_int_t njs_vm_value_dump(njs_vm_t *vm, njs_str_t *dst,
- const njs_value_t *value, njs_uint_t console, njs_uint_t indent);
+ njs_value_t *value, njs_uint_t console, njs_uint_t indent);
NJS_EXPORT njs_int_t njs_vm_retval_dump(njs_vm_t *vm, njs_str_t *dst,
njs_uint_t indent);
}
-static njs_int_t
+njs_int_t
njs_array_prototype_to_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
const u_char *start, size_t size, size_t length);
njs_int_t njs_array_expand(njs_vm_t *vm, njs_array_t *array, uint32_t prepend,
uint32_t append);
+njs_int_t njs_array_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused);
extern const njs_object_init_t njs_array_instance_init;
njs_array_buffer_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- uint32_t size;
+ uint64_t size;
njs_int_t ret;
njs_value_t *value;
njs_array_buffer_t *array;
}
+static njs_int_t
+njs_array_buffer_is_view(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ njs_set_boolean(&vm->retval, njs_is_typed_array(njs_arg(args, nargs, 1)));
+
+ return NJS_OK;
+}
+
+
static const njs_object_prop_t njs_array_buffer_constructor_properties[] =
{
/* ArrayBuffer.name == "ArrayBuffer". */
.configurable = 1,
.enumerable = 0,
},
+
+ /* ArrayBuffer.isView(new Uint8Array()) === true */
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("isView"),
+ .value = njs_native_function(njs_array_buffer_is_view, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
};
&njs_obj_type_init,
&njs_array_type_init,
- &njs_array_buffer_type_init,
&njs_boolean_type_init,
&njs_number_type_init,
&njs_symbol_type_init,
&njs_regexp_type_init,
&njs_date_type_init,
&njs_promise_type_init,
+ &njs_array_buffer_type_init,
/* Hidden types. */
&njs_hash_type_init,
&njs_hmac_type_init,
+ &njs_typed_array_type_init,
- /* Error types. */
+ /* TypedArray types. */
+ &njs_typed_array_u8_type_init,
+ &njs_typed_array_u8clamped_type_init,
+ &njs_typed_array_i8_type_init,
+ &njs_typed_array_u16_type_init,
+ &njs_typed_array_i16_type_init,
+ &njs_typed_array_u32_type_init,
+ &njs_typed_array_i32_type_init,
+ &njs_typed_array_f32_type_init,
+ &njs_typed_array_f64_type_init,
+
+ /* Error types. */
&njs_error_type_init,
&njs_eval_error_type_init,
&njs_internal_error_type_init,
{
size_t size;
njs_uint_t i;
- njs_object_t *object_prototype, *function_prototype, *error_prototype,
- *error_constructor;
+ njs_object_t *object_prototype, *function_prototype,
+ *typed_array_prototype, *error_prototype,
+ *typed_array_ctor, *error_ctor;
/*
* Copy both prototypes and constructors arrays by one memcpy()
object_prototype = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
- for (i = NJS_OBJ_TYPE_ARRAY; i < NJS_OBJ_TYPE_EVAL_ERROR; i++) {
+ for (i = NJS_OBJ_TYPE_ARRAY; i < NJS_OBJ_TYPE_NORMAL_MAX; i++) {
vm->prototypes[i].object.__proto__ = object_prototype;
}
+ typed_array_prototype = &vm->prototypes[NJS_OBJ_TYPE_TYPED_ARRAY].object;
+
+ for (i = NJS_OBJ_TYPE_TYPED_ARRAY_MIN;
+ i < NJS_OBJ_TYPE_TYPED_ARRAY_MAX;
+ i++)
+ {
+ vm->prototypes[i].object.__proto__ = typed_array_prototype;
+ }
+
error_prototype = &vm->prototypes[NJS_OBJ_TYPE_ERROR].object;
+ error_prototype->__proto__ = object_prototype;
for (i = NJS_OBJ_TYPE_EVAL_ERROR; i < NJS_OBJ_TYPE_MAX; i++) {
vm->prototypes[i].object.__proto__ = error_prototype;
function_prototype = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object;
- for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_EVAL_ERROR; i++) {
+ for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_NORMAL_MAX; i++) {
vm->constructors[i].object.__proto__ = function_prototype;
}
- error_constructor = &vm->constructors[NJS_OBJ_TYPE_ERROR].object;
+ typed_array_ctor = &vm->constructors[NJS_OBJ_TYPE_TYPED_ARRAY].object;
+
+ for (i = NJS_OBJ_TYPE_TYPED_ARRAY_MIN;
+ i < NJS_OBJ_TYPE_TYPED_ARRAY_MAX;
+ i++)
+ {
+ vm->constructors[i].object.__proto__ = typed_array_ctor;
+ }
+
+ error_ctor = &vm->constructors[NJS_OBJ_TYPE_ERROR].object;
+ error_ctor->__proto__ = function_prototype;
for (i = NJS_OBJ_TYPE_EVAL_ERROR; i < NJS_OBJ_TYPE_MAX; i++) {
- vm->constructors[i].object.__proto__ = error_constructor;
+ vm->constructors[i].object.__proto__ = error_ctor;
}
vm->global_object.__proto__ = object_prototype;
.configurable = 1,
},
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("Uint8Array"),
+ .value = njs_prop_handler2(njs_top_level_constructor,
+ NJS_OBJ_TYPE_UINT8_ARRAY,
+ NJS_UINT8ARRAY_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("Uint16Array"),
+ .value = njs_prop_handler2(njs_top_level_constructor,
+ NJS_OBJ_TYPE_UINT16_ARRAY,
+ NJS_UINT16ARRAY_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("Uint32Array"),
+ .value = njs_prop_handler2(njs_top_level_constructor,
+ NJS_OBJ_TYPE_UINT32_ARRAY,
+ NJS_UINT32ARRAY_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("Int8Array"),
+ .value = njs_prop_handler2(njs_top_level_constructor,
+ NJS_OBJ_TYPE_INT8_ARRAY,
+ NJS_INT8ARRAY_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("Int16Array"),
+ .value = njs_prop_handler2(njs_top_level_constructor,
+ NJS_OBJ_TYPE_INT16_ARRAY,
+ NJS_INT16ARRAY_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("Int32Array"),
+ .value = njs_prop_handler2(njs_top_level_constructor,
+ NJS_OBJ_TYPE_INT32_ARRAY,
+ NJS_INT32ARRAY_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("Float32Array"),
+ .value = njs_prop_handler2(njs_top_level_constructor,
+ NJS_OBJ_TYPE_FLOAT32_ARRAY,
+ NJS_FLOAT32ARRAY_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("Float64Array"),
+ .value = njs_prop_handler2(njs_top_level_constructor,
+ NJS_OBJ_TYPE_FLOAT64_ARRAY,
+ NJS_FLOAT64ARRAY_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_long_string("Uint8ClampedArray"),
+ .value = njs_prop_handler2(njs_top_level_constructor,
+ NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY,
+ NJS_UINT8CLAMPEDARRAY_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("Boolean"),
}
-#define njs_json_is_object(value) \
- (((value)->type == NJS_OBJECT) \
- || ((value)->type == NJS_OBJECT_SYMBOL) \
- || ((value)->type == NJS_EXTERNAL) \
- || ((value)->type == NJS_ARRAY) \
- || ((value)->type >= NJS_REGEXP))
+njs_inline njs_bool_t
+njs_json_is_object(const njs_value_t *value)
+{
+ return (((value)->type == NJS_OBJECT)
+ || ((value)->type == NJS_ARRAY)
+ || ((value)->type == NJS_OBJECT_SYMBOL)
+ || ((value)->type == NJS_EXTERNAL)
+ || ((value)->type >= NJS_REGEXP));
+}
#define njs_json_stringify_indent(times) \
static njs_int_t
-njs_dump_value(njs_json_stringify_t *stringify, njs_chb_t *chain,
- const njs_value_t *value, njs_uint_t console)
+njs_dump_terminal(njs_json_stringify_t *stringify, njs_chb_t *chain,
+ njs_value_t *value, njs_uint_t console)
{
- njs_str_t str;
- njs_int_t ret;
- njs_value_t str_val;
+ njs_str_t str;
+ njs_int_t ret;
+ njs_value_t str_val, tag;
+ njs_typed_array_t *array;
+ njs_string_prop_t string;
njs_int_t (*to_string)(njs_vm_t *, njs_value_t *, const njs_value_t *);
break;
+ case NJS_TYPED_ARRAY:
+ array = njs_typed_array(value);
+ ret = njs_object_string_tag(stringify->vm, value, &tag);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (ret == NJS_OK) {
+ (void) njs_string_prop(&string, &tag);
+ njs_chb_append(chain, string.start, string.size);
+ njs_chb_append_literal(chain, " ");
+ }
+
+ njs_chb_append_literal(chain, "[");
+
+ (void) njs_typed_array_to_chain(stringify->vm, chain, array, NULL);
+
+ njs_chb_append_literal(chain, "]");
+
+ break;
+
case NJS_NUMBER:
if (njs_slow_path(njs_number(value) == 0.0
&& signbit(njs_number(value))))
njs_inline njs_bool_t
-njs_dump_is_object(const njs_value_t *value)
+njs_dump_is_recursive(const njs_value_t *value)
{
return (value->type == NJS_OBJECT && !njs_object(value)->error_data)
|| (value->type == NJS_ARRAY)
- || (value->type == NJS_ARRAY_BUFFER)
- || (value->type == NJS_PROMISE)
- || (value->type == NJS_OBJECT_VALUE)
+ || (value->type >= NJS_OBJECT_SPECIAL_MAX)
|| njs_dump_is_external_object(value);
}
njs_int_t
-njs_vm_value_dump(njs_vm_t *vm, njs_str_t *retval, const njs_value_t *value,
+njs_vm_value_dump(njs_vm_t *vm, njs_str_t *retval, njs_value_t *value,
njs_uint_t console, njs_uint_t indent)
{
njs_int_t i;
stringify->vm = vm;
stringify->depth = 0;
- njs_set_undefined(&stringify->replacer);
- stringify->keys_type = NJS_ENUM_STRING | NJS_ENUM_SYMBOL;
njs_chb_init(&chain, vm->mem_pool);
- if (!njs_dump_is_object(value)) {
- ret = njs_dump_value(stringify, &chain, value, console);
+ if (!njs_dump_is_recursive(value)) {
+ ret = njs_dump_terminal(stringify, &chain, value, console);
if (njs_slow_path(ret != NJS_OK)) {
goto memory_error;
}
goto done;
}
+ njs_set_undefined(&stringify->replacer);
+ stringify->keys_type = NJS_ENUM_STRING | NJS_ENUM_SYMBOL;
indent = njs_min(indent, 10);
stringify->space.length = indent;
stringify->space.start = stringify->space_buf;
if (njs_is_defined(&prop->getter)) {
if (njs_is_defined(&prop->setter)) {
val = njs_value_arg(&string_get_set);
+
} else {
val = njs_value_arg(&string_get);
}
njs_chb_append_literal(&chain, " ");
}
- if (njs_dump_is_object(val)) {
+ if (njs_dump_is_recursive(val)) {
state = njs_json_push_stringify_state(vm, stringify, val);
if (njs_slow_path(state == NULL)) {
goto exception;
break;
}
- ret = njs_dump_value(stringify, &chain, val, console);
+ ret = njs_dump_terminal(stringify, &chain, val, console);
if (njs_slow_path(ret != NJS_OK)) {
if (ret == NJS_DECLINED) {
goto exception;
case NJS_JSON_ARRAY:
if (state->index == 0) {
+ ret = njs_object_string_tag(vm, &state->value, &tag);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (ret == NJS_OK) {
+ (void) njs_string_prop(&string, &tag);
+ njs_chb_append(&chain, string.start, string.size);
+ njs_chb_append_literal(&chain, " ");
+ }
+
njs_chb_append_literal(&chain, "[");
njs_json_stringify_indent(stringify->depth + 1);
}
val = &njs_array_start(&state->value)[state->index++];
- if (njs_dump_is_object(val)) {
+ if (njs_dump_is_recursive(val)) {
state = njs_json_push_stringify_state(vm, stringify, val);
if (njs_slow_path(state == NULL)) {
goto exception;
state->written = 1;
- ret = njs_dump_value(stringify, &chain, val, console);
+ ret = njs_dump_terminal(stringify, &chain, val, console);
if (njs_slow_path(ret != NJS_OK)) {
if (ret == NJS_DECLINED) {
goto exception;
#include <njs_object_hash.h>
#include <njs_array.h>
#include <njs_array_buffer.h>
+#include <njs_typed_array.h>
#include <njs_function.h>
#include <njs_regexp.h>
#include <njs_regexp_pattern.h>
double number, uint32_t radix);
-uint32_t
+double
njs_key_to_index(const njs_value_t *value)
{
- double num;
njs_array_t *array;
- num = NAN;
-
if (njs_fast_path(njs_is_numeric(value))) {
- num = njs_number(value);
+ return njs_number(value);
} else if (njs_is_string(value)) {
- num = njs_string_to_index(value);
+ return njs_string_to_index(value);
} else if (njs_is_array(value)) {
}
}
- if ((uint32_t) num == num) {
- return (uint32_t) num;
- }
-
- return NJS_ARRAY_INVALID_INDEX;
+ return NAN;
}
#define _NJS_NUMBER_H_INCLUDED_
-uint32_t njs_key_to_index(const njs_value_t *value);
+double njs_key_to_index(const njs_value_t *value);
double njs_number_dec_parse(const u_char **start, const u_char *end);
uint64_t njs_number_oct_parse(const u_char **start, const u_char *end);
uint64_t njs_number_bin_parse(const u_char **start, const u_char *end);
njs_uint_t nargs, njs_index_t unused);
+njs_inline njs_bool_t
+njs_number_is_integer_index(double num, const njs_value_t *value)
+{
+ uint32_t u32;
+
+ u32 = num;
+
+ return (u32 == num && u32 != 0xffffffff)
+ && !(njs_is_string(value) && num == 0 && signbit(num));
+}
+
njs_inline int64_t
njs_number_to_int64(double num)
{
njs_object_enum_type_t type, njs_bool_t all);
static njs_int_t njs_object_enumerate_array(njs_vm_t *vm,
const njs_array_t *array, njs_array_t *items, njs_object_enum_t kind);
+static njs_int_t njs_object_enumerate_typed_array(njs_vm_t *vm,
+ const njs_typed_array_t *array, njs_array_t *items, njs_object_enum_t kind);
static njs_int_t njs_object_enumerate_string(njs_vm_t *vm,
const njs_value_t *value, njs_array_t *items, njs_object_enum_t kind);
static njs_int_t njs_object_enumerate_object(njs_vm_t *vm,
length += njs_object_enumerate_array_length(object);
break;
+ case NJS_TYPED_ARRAY:
+ length += njs_typed_array_length((njs_typed_array_t *) object);
+ break;
+
case NJS_OBJECT_STRING:
length += njs_object_enumerate_string_length(object);
break;
kind);
break;
+ case NJS_TYPED_ARRAY:
+ ret = njs_object_enumerate_typed_array(vm,
+ (njs_typed_array_t *) object,
+ items, kind);
+ break;
+
case NJS_OBJECT_STRING:
obj_val = (njs_object_value_t *) object;
}
+static njs_int_t
+njs_object_enumerate_typed_array(njs_vm_t *vm, const njs_typed_array_t *array,
+ njs_array_t *items, njs_object_enum_t kind)
+{
+ uint32_t i, length;
+ njs_value_t *item;
+ njs_array_t *entry;
+
+ item = items->start;
+ length = njs_typed_array_length(array);
+
+ switch (kind) {
+ case NJS_ENUM_KEYS:
+ for (i = 0; i < length; i++) {
+ njs_uint32_to_string(item++, i);
+ }
+
+ break;
+
+ case NJS_ENUM_VALUES:
+ for (i = 0; i < length; i++) {
+ njs_set_number(item++, njs_typed_array_get(array, i));
+ }
+
+ break;
+
+ case NJS_ENUM_BOTH:
+ for (i = 0; i < length; i++) {
+ entry = njs_array_alloc(vm, 2, 0);
+ if (njs_slow_path(entry == NULL)) {
+ return NJS_ERROR;
+ }
+
+ njs_uint32_to_string(&entry->start[0], i);
+ njs_set_number(&entry->start[1], njs_typed_array_get(array, i));
+
+ njs_set_array(item++, entry);
+ }
+
+ break;
+ }
+
+ items->start = item;
+
+ return NJS_OK;
+}
+
+
static njs_int_t
njs_object_enumerate_string(njs_vm_t *vm, const njs_value_t *value,
njs_array_t *items, njs_object_enum_t kind)
njs_long_string("[object Object]");
static const njs_value_t njs_object_array_string =
njs_string("[object Array]");
-static const njs_value_t njs_object_array_buffer_string =
- njs_long_string("[object ArrayBuffer]");
static const njs_value_t njs_object_function_string =
njs_long_string("[object Function]");
static const njs_value_t njs_object_regexp_string =
&njs_object_date_string,
&njs_object_object_string,
&njs_object_object_string,
- &njs_object_array_buffer_string,
+ &njs_object_object_string,
+ &njs_object_object_string,
};
value = njs_argument(args, 0);
'A'), 'r'), 'r'), 'a'), 'y'), 'B'), 'u'), 'f'), 'f'), 'e'), 'r')
+#define NJS_UINT8ARRAY_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_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'U'), 'i'), 'n'), 't'), '8'), 'A'), 'r'), 'r'), 'a'), 'y')
+
+
+#define NJS_UINT16ARRAY_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_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'U'), 'i'), 'n'), 't'), '1'), '6'), 'A'), 'r'), 'r'), 'a'), 'y')
+
+
+#define NJS_UINT32ARRAY_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_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'U'), 'i'), 'n'), 't'), '3'), '2'), 'A'), 'r'), 'r'), 'a'), 'y')
+
+
+#define NJS_INT8ARRAY_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_add(NJS_DJB_HASH_INIT, \
+ 'I'), 'n'), 't'), '8'), 'A'), 'r'), 'r'), 'a'), 'y')
+
+
+#define NJS_INT16ARRAY_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_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'I'), 'n'), 't'), '1'), '6'), 'A'), 'r'), 'r'), 'a'), 'y')
+
+
+#define NJS_INT32ARRAY_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_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'I'), 'n'), 't'), '3'), '2'), 'A'), 'r'), 'r'), 'a'), 'y')
+
+
+#define NJS_FLOAT32ARRAY_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_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'F'), 'l'), 'o'), 'a'), 't'), '3'), '2'), 'A'), 'r'), 'r'), 'a'), 'y')
+
+
+#define NJS_FLOAT64ARRAY_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_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'F'), 'l'), 'o'), 'a'), 't'), '6'), '4'), 'A'), 'r'), 'r'), 'a'), 'y')
+
+
+#define NJS_UINT8CLAMPEDARRAY_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_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_add(NJS_DJB_HASH_INIT, \
+ 'U'), 'i'), 'n'), 't'), '8'), 'C'), 'l'), 'a'), 'm'), 'p'), 'e'), \
+ 'd'), 'A'), 'r'), 'r'), 'a'), 'y')
+
+
#endif /* _NJS_OBJECT_HASH_H_INCLUDED_ */
return NJS_ERROR;
}
+ if (njs_slow_path(njs_is_typed_array(object)
+ && njs_is_string(name)))
+ {
+ /* Integer-Indexed Exotic Objects [[DefineOwnProperty]]. */
+ if (!isnan(njs_string_to_index(name))) {
+ njs_type_error(vm, "Invalid typed array index");
+ return NJS_ERROR;
+ }
+ }
+
/* 6.2.5.6 CompletePropertyDescriptor */
if (njs_is_accessor_descriptor(prop)) {
return NJS_OK;
+ case NJS_PROPERTY_TYPED_ARRAY_REF:
+ if (njs_is_accessor_descriptor(prop)) {
+ goto exception;
+ }
+
+ if (prop->configurable == NJS_ATTRIBUTE_TRUE ||
+ prop->enumerable == NJS_ATTRIBUTE_FALSE ||
+ prop->writable == NJS_ATTRIBUTE_FALSE)
+ {
+ goto exception;
+ }
+
+ if (njs_is_valid(&prop->value)) {
+ return njs_typed_array_set_value(vm, njs_typed_array(&prev->value),
+ prev->value.data.magic32,
+ &prop->value);
+ }
+
+ return NJS_OK;
+
default:
njs_internal_error(vm, "unexpected property type \"%s\" "
"while defining property",
double
njs_string_to_index(const njs_value_t *value)
{
+ size_t size, len;
double num;
- size_t size;
- const u_char *p, *end;
+ njs_bool_t minus;
+ const u_char *p, *start, *end;
+ u_char buf[128];
size = value->short_string.size;
if (size != NJS_STRING_LONG) {
- p = value->short_string.start;
+ start = value->short_string.start;
} else {
size = value->long_string.size;
- p = value->long_string.data->start;
+ start = value->long_string.data->start;
}
- if (size == 0) {
- return NAN;
+ p = start;
+ end = p + size;
+ minus = 0;
+
+ if (size > 1) {
+ switch (p[0]) {
+ case '0':
+ if (size != 1) {
+ return NAN;
+ }
+
+ /* Fall through. */
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+
+ case '-':
+ if (size == 2 && p[1] == '0') {
+ return -0.0;
+ }
+
+ if (size == njs_length("-Infinity")
+ && memcmp(&p[1], "Infinity", njs_length("Infinity")) == 0)
+ {
+ return -INFINITY;
+ }
+
+ p++;
+ minus = 1;
+
+ break;
+
+ case 'I':
+ if (size == njs_length("Infinity")
+ && memcmp(p, "Infinity", njs_length("Infinity")) == 0)
+ {
+ return INFINITY;
+ }
+
+ /* Fall through. */
+
+ default:
+ return NAN;
+ }
}
- if (*p == '0' && size > 1) {
+ num = njs_strtod(&p, end);
+ if (p != end) {
return NAN;
}
- end = p + size;
- num = njs_number_dec_parse(&p, end);
+ num = minus ? -num : num;
- if (p != end) {
+ len = njs_dtoa(num, (char *) buf);
+ if (size != len || memcmp(start, buf, size) != 0) {
return NAN;
}
--- /dev/null
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+
+#include <njs_main.h>
+
+
+static njs_int_t
+njs_typed_array_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t magic)
+{
+ double num;
+ uint32_t i, length, element_size;
+ uint64_t size, offset;
+ njs_int_t ret;
+ njs_value_t *value, index, prop;
+ njs_array_t *src_array;
+ njs_object_type_t type;
+ njs_typed_array_t *array, *src_tarray;
+ njs_array_buffer_t *buffer;
+
+ size = 0;
+ offset = 0;
+
+ buffer = NULL;
+ src_array = NULL;
+ src_tarray = NULL;
+
+ type = magic;
+ element_size = njs_typed_array_element_size(type);
+
+ if (!vm->top_frame->ctor) {
+ njs_type_error(vm, "Constructor of TypedArray requires 'new'");
+ return NJS_ERROR;
+ }
+
+ value = njs_arg(args, nargs, 1);
+
+ if (njs_is_array_buffer(value)) {
+ buffer = njs_array_buffer(value);
+
+ ret = njs_value_to_index(vm, njs_arg(args, nargs, 2), &offset);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ if (njs_slow_path((offset % element_size) != 0)) {
+ njs_range_error(vm, "start offset must be multiple of %uD",
+ element_size);
+ 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;
+ }
+
+ size *= element_size;
+
+ if (njs_slow_path((offset + size) > buffer->size)) {
+ njs_range_error(vm, "Invalid typed array length: %uD", size);
+ return NJS_ERROR;
+ }
+
+ } else {
+ if (njs_slow_path((buffer->size % element_size) != 0)) {
+ njs_range_error(vm, "byteLength of buffer must be "
+ "multiple of %uD", element_size);
+ return NJS_ERROR;
+ }
+
+ 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;
+ }
+
+ } else if (njs_is_typed_array(value)) {
+ src_tarray = njs_typed_array(value);
+ size = 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)) {
+ src_array = njs_array(value);
+ length = src_array->length;
+
+ } else {
+ ret = njs_object_length(vm, value, &length);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+ }
+
+ size = (uint64_t) length * element_size;
+
+ } else {
+ ret = njs_value_to_index(vm, value, &size);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ size *= element_size;
+ }
+
+ if (buffer == NULL) {
+ buffer = njs_array_buffer_alloc(vm, size);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ array = njs_mp_zalloc(vm->mem_pool, sizeof(njs_typed_array_t));
+ if (njs_slow_path(array == NULL)) {
+ goto memory_error;
+ }
+
+ array->buffer = buffer;
+ array->offset = offset / element_size;
+ array->byte_length = size;
+ array->type = type;
+
+ if (src_tarray != NULL) {
+ 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));
+ }
+
+ } else {
+ memcpy(&buffer->u.u8[0], &src_tarray->buffer->u.u8[0], size);
+ }
+
+ } else if (src_array != NULL) {
+ for (i = 0; i < length; i++) {
+ ret = njs_value_to_number(vm, &src_array->start[i], &num);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return NJS_ERROR;
+ }
+
+ if (ret == NJS_OK) {
+ njs_typed_array_set(array, i, num);
+ }
+ }
+
+ } else if (!njs_is_array_buffer(value) && njs_is_object(value)) {
+ for (i = 0; i < length; i++) {
+ njs_uint32_to_string(&index, i);
+
+ ret = njs_value_property(vm, value, &index, &prop);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return NJS_ERROR;
+ }
+
+ num = NAN;
+
+ if (ret == NJS_OK) {
+ ret = njs_value_to_number(vm, &prop, &num);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return NJS_ERROR;
+ }
+ }
+
+ njs_typed_array_set(array, i, num);
+ }
+ }
+
+ njs_lvlhsh_init(&array->object.hash);
+ njs_lvlhsh_init(&array->object.shared_hash);
+ array->object.__proto__ = &vm->prototypes[type].object;
+ array->object.type = NJS_TYPED_ARRAY;
+ array->object.shared = 0;
+ array->object.extensible = 1;
+
+ njs_set_typed_array(&vm->retval, array);
+
+ return NJS_OK;
+
+memory_error:
+
+ njs_memory_error(vm);
+
+ return NJS_ERROR;
+}
+
+
+static njs_int_t
+njs_typed_array_get_this(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ vm->retval = args[0];
+
+ return NJS_OK;
+}
+
+
+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");
+static const njs_value_t njs_typed_array_int8_tag = njs_string("Int8Array");
+static const njs_value_t njs_typed_array_uint16_tag =
+ njs_string("Uint16Array");
+static const njs_value_t njs_typed_array_int16_tag = njs_string("Int16Array");
+static const njs_value_t njs_typed_array_uint32_tag =
+ njs_string("Uint32Array");
+static const njs_value_t njs_typed_array_int32_tag = njs_string("Int32Array");
+static const njs_value_t njs_typed_array_float32_tag =
+ njs_string("Float32Array");
+static const njs_value_t njs_typed_array_float64_tag =
+ njs_string("Float64Array");
+
+static njs_int_t
+njs_typed_array_get_string_tag(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ njs_value_t *this;
+
+ static const njs_value_t *tags[NJS_OBJ_TYPE_TYPED_ARRAY_SIZE] = {
+ &njs_typed_array_uint8_tag,
+ &njs_typed_array_uint8_clamped_tag,
+ &njs_typed_array_int8_tag,
+ &njs_typed_array_uint16_tag,
+ &njs_typed_array_int16_tag,
+ &njs_typed_array_uint32_tag,
+ &njs_typed_array_int32_tag,
+ &njs_typed_array_float32_tag,
+ &njs_typed_array_float64_tag,
+ };
+
+ this = njs_argument(args, 0);
+
+ if (!njs_is_typed_array(this)) {
+ njs_set_undefined(&vm->retval);
+ return NJS_OK;
+ }
+
+ vm->retval = *tags[njs_typed_array_index(njs_typed_array(this)->type)];
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_length(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ njs_value_t *this;
+ njs_typed_array_t *array;
+
+ this = njs_argument(args, 0);
+ if (!njs_is_typed_array(this)) {
+ njs_type_error(vm, "Method TypedArray.prototype.length called "
+ "on incompatible receiver");
+ return NJS_ERROR;
+ }
+
+ array = njs_typed_array(this);
+
+ njs_set_number(&vm->retval, njs_typed_array_length(array));
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_buffer(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ njs_value_t *this;
+ njs_typed_array_t *array;
+
+ this = njs_argument(args, 0);
+ if (!njs_is_typed_array(this)) {
+ njs_type_error(vm, "Method TypedArray.prototype.buffer called "
+ "on incompatible receiver");
+ return NJS_ERROR;
+ }
+
+ array = njs_typed_array(this);
+
+ njs_set_array_buffer(&vm->retval, njs_typed_array_buffer(array));
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_byte_length(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ njs_value_t *this;
+ njs_typed_array_t *array;
+
+ this = njs_argument(args, 0);
+ if (!njs_is_typed_array(this)) {
+ njs_type_error(vm, "Method TypedArray.prototype.byteLength called "
+ "on incompatible receiver");
+ return NJS_ERROR;
+ }
+
+ array = njs_typed_array(this);
+
+ njs_set_number(&vm->retval, array->byte_length);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_byte_offset(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ njs_value_t *this;
+ njs_typed_array_t *array;
+
+ this = njs_argument(args, 0);
+ if (!njs_is_typed_array(this)) {
+ njs_type_error(vm, "Method TypedArray.prototype.byteOffset called "
+ "on incompatible receiver");
+ return NJS_ERROR;
+ }
+
+ array = njs_typed_array(this);
+
+ njs_set_number(&vm->retval, array->offset
+ * njs_typed_array_element_size(array->type));
+
+ return NJS_OK;
+}
+
+
+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;
+
+ ret = njs_value_to_number(vm, setval, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ njs_typed_array_set(array, index, num);
+
+ njs_set_number(setval, num);
+
+ return NJS_OK;
+}
+
+
+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;
+ uint32_t i, length, src_length;
+ int64_t offset;
+ njs_int_t ret;
+ njs_value_t *this, *src, *value, index, prop;
+ njs_array_t *array;
+ njs_typed_array_t *self, *src_tarray;
+
+ this = njs_argument(args, 0);
+ if (njs_slow_path(!njs_is_typed_array(this))) {
+ njs_type_error(vm, "this is not a typed array");
+ return NJS_ERROR;
+ }
+
+ self = njs_typed_array(this);
+ src = njs_arg(args, nargs, 1);
+ value = njs_arg(args, nargs, 2);
+
+ ret = njs_value_to_integer(vm, value, &offset);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ if (njs_slow_path(offset < 0)) {
+ njs_range_error(vm, "offset is out of bounds");
+ return NJS_ERROR;
+ }
+
+ length = njs_typed_array_length(self);
+
+ if (njs_is_typed_array(src)) {
+ src_tarray = njs_typed_array(src);
+ src_length = njs_typed_array_length(src_tarray);
+
+ if (njs_slow_path((src_length > length)
+ || (offset > length - src_length)))
+ {
+ njs_range_error(vm, "source is too large");
+ return NJS_ERROR;
+ }
+
+ 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));
+ }
+
+ } else {
+ if (njs_is_array(src) && njs_object_hash_is_empty(src)) {
+ array = njs_array(src);
+ src_length = array->length;
+
+ if (njs_slow_path((src_length > length)
+ || (offset > length - src_length)))
+ {
+ njs_range_error(vm, "source is too large");
+ return NJS_ERROR;
+ }
+
+ length = njs_min(array->length, length - offset);
+
+ 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);
+ }
+ }
+
+ goto done;
+ }
+
+ ret = njs_value_to_object(vm, src);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ ret = njs_object_length(vm, src, &src_length);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (njs_slow_path((src_length > length)
+ || (offset > length - src_length)))
+ {
+ njs_range_error(vm, "source is too large");
+ return NJS_ERROR;
+ }
+
+ length = njs_min(src_length, length - offset);
+
+ for (i = 0; i < length; i++) {
+ njs_uint32_to_string(&index, i);
+
+ ret = njs_value_property(vm, src, &index, &prop);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return NJS_ERROR;
+ }
+
+ num = NAN;
+
+ if (ret == NJS_OK) {
+ ret = njs_value_to_number(vm, &prop, &num);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return NJS_ERROR;
+ }
+ }
+
+ njs_typed_array_set(self, offset + i, num);
+ }
+ }
+
+done:
+
+ njs_set_undefined(&vm->retval);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_fill(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ float f32;
+ int8_t i8;
+ double num;
+ int16_t i16;
+ int32_t i32;
+ uint8_t u8;
+ int64_t start, end;
+ uint32_t i, length;
+ njs_int_t ret;
+ njs_value_t *this, *setval, lvalue;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *buffer;
+
+ this = njs_argument(args, 0);
+ if (njs_slow_path(!njs_is_typed_array(this))) {
+ njs_type_error(vm, "this is not a typed array");
+ return NJS_ERROR;
+ }
+
+ array = njs_typed_array(this);
+ length = njs_typed_array_length(array);
+
+ setval = njs_lvalue_arg(&lvalue, args, nargs, 1);
+ ret = njs_value_to_number(vm, setval, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 2), &start);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ start = (start < 0) ? njs_max(length + start, 0) : njs_min(start, length);
+
+ if (njs_is_undefined(njs_arg(args, nargs, 3))) {
+ end = length;
+
+ } else {
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 3), &end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
+ end = (end < 0) ? njs_max(length + end, 0) : njs_min(end, length);
+
+ njs_set_typed_array(&vm->retval, array);
+
+ buffer = array->buffer;
+
+ switch (array->type) {
+ case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY:
+ if (num < 0) {
+ num = 0;
+
+ } else if (num > 255) {
+ num = 255;
+ }
+
+ u8 = lrint(num);
+
+ for (i = start; i < end; i++) {
+ buffer->u.u8[i] = u8;
+ }
+
+ break;
+
+ case NJS_OBJ_TYPE_UINT8_ARRAY:
+ case NJS_OBJ_TYPE_INT8_ARRAY:
+ i8 = njs_number_to_int32(num);
+
+ for (i = start; i < end; i++) {
+ buffer->u.u8[i] = i8;
+ }
+
+ break;
+
+ case NJS_OBJ_TYPE_UINT16_ARRAY:
+ case NJS_OBJ_TYPE_INT16_ARRAY:
+ i16 = njs_number_to_int32(num);
+
+ for (i = start; i < end; i++) {
+ buffer->u.u16[i] = i16;
+ }
+
+ break;
+
+ case NJS_OBJ_TYPE_UINT32_ARRAY:
+ case NJS_OBJ_TYPE_INT32_ARRAY:
+ i32 = njs_number_to_int32(num);
+
+ for (i = start; i < end; i++) {
+ buffer->u.u32[i] = i32;
+ }
+
+ break;
+
+ case NJS_OBJ_TYPE_FLOAT32_ARRAY:
+ f32 = num;
+
+ for (i = start; i < end; i++) {
+ buffer->u.f32[i] = f32;
+ }
+
+ break;
+
+ default:
+
+ /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */
+
+ for (i = start; i < end; i++) {
+ buffer->u.f64[i] = num;
+ }
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_species_create(njs_vm_t *vm, njs_value_t *exemplar,
+ int64_t count, njs_value_t *retval)
+{
+ njs_int_t ret;
+ njs_value_t this, constructor, argument;
+ njs_object_t *object;
+ njs_typed_array_t *array;
+
+ array = njs_typed_array(exemplar);
+
+ njs_set_function(&constructor, &vm->constructors[array->type]);
+
+ ret = njs_value_species_constructor(vm, exemplar, &constructor,
+ &constructor);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ object = njs_function_new_object(vm, &constructor);
+ if (njs_slow_path(object == NULL)) {
+ return NJS_ERROR;
+ }
+
+ njs_set_object(&this, object);
+ njs_set_number(&argument, count);
+
+ ret = njs_function_call2(vm, njs_function(&constructor), &this,
+ &argument, 1, retval, 1);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ if (!njs_is_typed_array(retval)) {
+ njs_type_error(vm, "Derived TypedArray constructor "
+ "returned not a typed array");
+ return NJS_ERROR;
+ }
+
+ array = njs_typed_array(retval);
+ if (njs_typed_array_length(array) < count) {
+ njs_type_error(vm, "Derived TypedArray constructor too small array");
+ return NJS_ERROR;
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_slice(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ int64_t start, end, count;
+ uint32_t i, element_size, length;
+ njs_int_t ret;
+ njs_value_t *this, *value;
+ njs_typed_array_t *array, *new_array;
+ njs_array_buffer_t *buffer, *new_buffer;
+
+ this = njs_argument(args, 0);
+ if (njs_slow_path(!njs_is_typed_array(this))) {
+ njs_type_error(vm, "this is not a typed array");
+ return NJS_ERROR;
+ }
+
+ array = njs_typed_array(this);
+ length = njs_typed_array_length(array);
+ buffer = njs_typed_array_buffer(array);
+
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &start);
+ if (njs_slow_path(ret != NJS_OK)) {
+ njs_range_error(vm, "invalid start");
+ return NJS_ERROR;
+ }
+
+ start = (start < 0) ? njs_max(length + start, 0) : njs_min(start, length);
+
+ value = njs_arg(args, nargs, 2);
+
+ if (njs_is_undefined(value)) {
+ end = length;
+
+ } else {
+ ret = njs_value_to_integer(vm, value, &end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ njs_range_error(vm, "invalid end");
+ return NJS_ERROR;
+ }
+ }
+
+ end = (end < 0) ? njs_max(length + end, 0) : njs_min(end, length);
+
+ count = njs_max(end - start, 0);
+
+ ret = njs_typed_array_species_create(vm, this, count, &vm->retval);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ new_array = njs_typed_array(&vm->retval);
+ new_buffer = njs_typed_array_buffer(new_array);
+ element_size = njs_typed_array_element_size(array->type);
+
+ if (njs_fast_path(array->type == new_array->type)) {
+ start = start * element_size;
+ count = count * element_size;
+
+ memcpy(&new_buffer->u.u8[0], &buffer->u.u8[start], count);
+
+ } else {
+ for (i = 0; i < count; i++) {
+ njs_typed_array_set(new_array, i,
+ njs_typed_array_get(array, i + start));
+ }
+ }
+
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_copy_within(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ int64_t length, to, from, final, count;
+ uint32_t element_size;
+ njs_int_t ret;
+ njs_value_t *this, *value;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *buffer;
+
+ this = njs_argument(args, 0);
+ if (njs_slow_path(!njs_is_typed_array(this))) {
+ njs_type_error(vm, "this is not a typed array");
+ return NJS_ERROR;
+ }
+
+ array = njs_typed_array(this);
+ length = njs_typed_array_length(array);
+
+ value = njs_arg(args, nargs, 1);
+
+ ret = njs_value_to_integer(vm, value, &to);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ to = to < 0 ? njs_max(to + length, 0) : njs_min(to, length);
+
+ value = njs_arg(args, nargs, 2);
+
+ ret = njs_value_to_integer(vm, value, &from);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ from = from < 0 ? njs_max(from + length, 0) : njs_min(from, length);
+
+ value = njs_arg(args, nargs, 3);
+
+ if (njs_is_undefined(value)) {
+ final = length;
+
+ } else {
+ ret = njs_value_to_integer(vm, value, &final);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+ }
+
+ final = (final < 0) ? njs_max(final + length, 0) : njs_min(final, length);
+
+ njs_set_typed_array(&vm->retval, array);
+
+ count = njs_min(final - from, length - to);
+
+ if (count <= 0) {
+ return NJS_OK;
+ }
+
+ buffer = njs_typed_array_buffer(array);
+ element_size = njs_typed_array_element_size(array->type);
+
+ to = to * element_size;
+ from = from * element_size;
+ count = count * element_size;
+
+ memmove(&buffer->u.u8[to], &buffer->u.u8[from], count);
+
+ return NJS_OK;
+}
+
+
+njs_int_t
+njs_typed_array_to_chain(njs_vm_t *vm, njs_chb_t *chain,
+ njs_typed_array_t *array, njs_value_t *sep)
+{
+ size_t size, length, arr_length;
+ uint32_t i;
+ njs_string_prop_t separator;
+
+ if (sep == NULL) {
+ sep = njs_value_arg(&njs_string_comma);
+ }
+
+ (void) njs_string_prop(&separator, sep);
+
+ arr_length = njs_typed_array_length(array);
+
+ if (arr_length == 0) {
+ return 0;
+ }
+
+ for (i = 0; i < arr_length; i++) {
+ njs_number_to_chain(vm, chain, njs_typed_array_get(array, i));
+ njs_chb_append(chain, separator.start, separator.size);
+ }
+
+ njs_chb_drop(chain, separator.size);
+
+ size = njs_chb_size(chain);
+
+ if (njs_utf8_length(separator.start, separator.size) >= 0) {
+ length = size - (separator.size - separator.length) * (arr_length - 1);
+
+ } else {
+ length = 0;
+ }
+
+ return length;
+}
+
+
+static njs_int_t
+njs_typed_array_prototype_join(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ u_char *p;
+ size_t size, length, arr_length;
+ njs_int_t ret;
+ njs_chb_t chain;
+ njs_value_t *this, *separator;
+ njs_typed_array_t *array;
+
+ this = njs_argument(args, 0);
+ if (njs_slow_path(!njs_is_typed_array(this))) {
+ njs_type_error(vm, "this is not a typed array");
+ return NJS_ERROR;
+ }
+
+ array = njs_typed_array(this);
+ arr_length = njs_typed_array_length(array);
+
+ separator = njs_arg(args, nargs, 1);
+
+ if (njs_slow_path(!njs_is_string(separator))) {
+ if (njs_is_undefined(separator)) {
+ separator = njs_value_arg(&njs_string_comma);
+
+ } else {
+ ret = njs_value_to_string(vm, separator, separator);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+ }
+
+ if (arr_length == 0) {
+ vm->retval = njs_string_empty;
+ return NJS_OK;
+ }
+
+ njs_chb_init(&chain, vm->mem_pool);
+
+ length = njs_typed_array_to_chain(vm, &chain, array, separator);
+ size = njs_chb_size(&chain);
+
+ p = njs_string_alloc(vm, &vm->retval, size, length);
+ if (njs_slow_path(p == NULL)) {
+ return NJS_ERROR;
+ }
+
+ njs_chb_join_to(&chain, p);
+ njs_chb_destroy(&chain);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_typed_array_constructor_intrinsic(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ njs_type_error(vm, "Abstract class TypedArray not directly constructable");
+
+ return NJS_ERROR;
+}
+
+
+static const njs_object_prop_t njs_typed_array_constructor_props[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("TypedArray"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 0, 0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_wellknown_symbol(NJS_SYMBOL_SPECIES),
+ .value = njs_value(NJS_INVALID, 1, NAN),
+ .getter = njs_native_function(njs_typed_array_get_this, 0),
+ .setter = njs_value(NJS_UNDEFINED, 0, NAN),
+ .writable = NJS_ATTRIBUTE_UNSET,
+ .configurable = 1,
+ .enumerable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_constructor_init = {
+ njs_typed_array_constructor_props,
+ njs_nitems(njs_typed_array_constructor_props),
+};
+
+
+static const njs_object_prop_t njs_typed_array_prototype_properties[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG),
+ .value = njs_value(NJS_INVALID, 1, NAN),
+ .getter = njs_native_function(njs_typed_array_get_string_tag,
+ 0),
+ .setter = njs_value(NJS_UNDEFINED, 0, NAN),
+ .writable = NJS_ATTRIBUTE_UNSET,
+ .configurable = 1,
+ .enumerable = 0,
+ },
+
+ {
+ .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("length"),
+ .value = njs_value(NJS_INVALID, 1, NAN),
+ .getter = njs_native_function(njs_typed_array_prototype_length, 0),
+ .setter = njs_value(NJS_UNDEFINED, 0, NAN),
+ .writable = NJS_ATTRIBUTE_UNSET,
+ .configurable = 1,
+ .enumerable = 0,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("set"),
+ .value = njs_native_function(njs_typed_array_prototype_set, 2),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("slice"),
+ .value = njs_native_function(njs_typed_array_prototype_slice, 2),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("copyWithin"),
+ .value = njs_native_function(njs_typed_array_prototype_copy_within, 2),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("fill"),
+ .value = njs_native_function(njs_typed_array_prototype_fill, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("join"),
+ .value = njs_native_function(njs_typed_array_prototype_join, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("toString"),
+ .value = njs_native_function(njs_array_prototype_to_string, 0),
+ .writable = 1,
+ .configurable = 1,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_prototype_init = {
+ njs_typed_array_prototype_properties,
+ njs_nitems(njs_typed_array_prototype_properties),
+};
+
+
+const njs_object_type_init_t njs_typed_array_type_init = {
+ .constructor = njs_native_ctor(njs_typed_array_constructor_intrinsic, 0, 0),
+ .prototype_props = &njs_typed_array_prototype_init,
+ .constructor_props = &njs_typed_array_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
+static const njs_object_prop_t njs_typed_array_u8_constructor_props[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Uint8Array"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 1, 3.0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 1),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_u8_constructor_init = {
+ njs_typed_array_u8_constructor_props,
+ njs_nitems(njs_typed_array_u8_constructor_props),
+};
+
+
+static const njs_object_prop_t njs_typed_array_u8_prototype_properties[] =
+{
+ {
+ .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_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 1),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_u8_prototype_init = {
+ njs_typed_array_u8_prototype_properties,
+ njs_nitems(njs_typed_array_u8_prototype_properties),
+};
+
+
+const njs_object_type_init_t njs_typed_array_u8_type_init = {
+ .constructor = njs_native_ctor(njs_typed_array_constructor, 3,
+ NJS_OBJ_TYPE_UINT8_ARRAY),
+ .prototype_props = &njs_typed_array_u8_prototype_init,
+ .constructor_props = &njs_typed_array_u8_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
+static const njs_object_prop_t njs_typed_array_u8c_constructor_props[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_long_string("Uint8ClampedArray"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 1, 3.0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 1),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_u8c_constructor_init = {
+ njs_typed_array_u8c_constructor_props,
+ njs_nitems(njs_typed_array_u8c_constructor_props),
+};
+
+
+static const njs_object_prop_t njs_typed_array_u8c_prototype_properties[] =
+{
+ {
+ .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_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 1),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_u8c_prototype_init = {
+ njs_typed_array_u8c_prototype_properties,
+ njs_nitems(njs_typed_array_u8c_prototype_properties),
+};
+
+
+const njs_object_type_init_t njs_typed_array_u8clamped_type_init = {
+ .constructor = njs_native_ctor(njs_typed_array_constructor, 3,
+ NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY),
+ .prototype_props = &njs_typed_array_u8c_prototype_init,
+ .constructor_props = &njs_typed_array_u8c_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
+static const njs_object_prop_t njs_typed_array_i8_constructor_props[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Int8Array"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 1, 3.0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 1),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_i8_constructor_init = {
+ njs_typed_array_i8_constructor_props,
+ njs_nitems(njs_typed_array_i8_constructor_props),
+};
+
+
+static const njs_object_prop_t njs_typed_array_i8_prototype_properties[] =
+{
+ {
+ .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_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 1),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_i8_prototype_init = {
+ njs_typed_array_i8_prototype_properties,
+ njs_nitems(njs_typed_array_i8_prototype_properties),
+};
+
+
+const njs_object_type_init_t njs_typed_array_i8_type_init = {
+ .constructor = njs_native_ctor(njs_typed_array_constructor, 3,
+ NJS_OBJ_TYPE_INT8_ARRAY),
+ .prototype_props = &njs_typed_array_i8_prototype_init,
+ .constructor_props = &njs_typed_array_i8_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
+static const njs_object_prop_t njs_typed_array_u16_constructor_props[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Uint16Array"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 1, 3.0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 2),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_u16_constructor_init = {
+ njs_typed_array_u16_constructor_props,
+ njs_nitems(njs_typed_array_u16_constructor_props),
+};
+
+
+static const njs_object_prop_t njs_typed_array_u16_prototype_properties[] =
+{
+ {
+ .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_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 2),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_u16_prototype_init = {
+ njs_typed_array_u16_prototype_properties,
+ njs_nitems(njs_typed_array_u16_prototype_properties),
+};
+
+
+const njs_object_type_init_t njs_typed_array_u16_type_init = {
+ .constructor = njs_native_ctor(njs_typed_array_constructor, 3,
+ NJS_OBJ_TYPE_UINT16_ARRAY),
+ .prototype_props = &njs_typed_array_u16_prototype_init,
+ .constructor_props = &njs_typed_array_u16_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
+static const njs_object_prop_t njs_typed_array_i16_constructor_props[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Int16Array"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 1, 3.0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 2),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_i16_constructor_init = {
+ njs_typed_array_i16_constructor_props,
+ njs_nitems(njs_typed_array_i16_constructor_props),
+};
+
+
+static const njs_object_prop_t njs_typed_array_i16_prototype_properties[] =
+{
+ {
+ .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_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 2),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_i16_prototype_init = {
+ njs_typed_array_i16_prototype_properties,
+ njs_nitems(njs_typed_array_i16_prototype_properties),
+};
+
+
+const njs_object_type_init_t njs_typed_array_i16_type_init = {
+ .constructor = njs_native_ctor(njs_typed_array_constructor, 3,
+ NJS_OBJ_TYPE_INT16_ARRAY),
+ .prototype_props = &njs_typed_array_i16_prototype_init,
+ .constructor_props = &njs_typed_array_i16_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
+static const njs_object_prop_t njs_typed_array_u32_constructor_props[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Uint32Array"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 1, 3.0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 4),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_u32_constructor_init = {
+ njs_typed_array_u32_constructor_props,
+ njs_nitems(njs_typed_array_u32_constructor_props),
+};
+
+
+static const njs_object_prop_t njs_typed_array_u32_prototype_properties[] =
+{
+ {
+ .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_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 4),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_u32_prototype_init = {
+ njs_typed_array_u32_prototype_properties,
+ njs_nitems(njs_typed_array_u32_prototype_properties),
+};
+
+
+const njs_object_type_init_t njs_typed_array_u32_type_init = {
+ .constructor = njs_native_ctor(njs_typed_array_constructor, 3,
+ NJS_OBJ_TYPE_UINT32_ARRAY),
+ .prototype_props = &njs_typed_array_u32_prototype_init,
+ .constructor_props = &njs_typed_array_u32_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
+static const njs_object_prop_t njs_typed_array_i32_constructor_props[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Int32Array"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 1, 3.0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 4),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_i32_constructor_init = {
+ njs_typed_array_i32_constructor_props,
+ njs_nitems(njs_typed_array_i32_constructor_props),
+};
+
+
+static const njs_object_prop_t njs_typed_array_i32_prototype_properties[] =
+{
+ {
+ .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_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 4),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_i32_prototype_init = {
+ njs_typed_array_i32_prototype_properties,
+ njs_nitems(njs_typed_array_i32_prototype_properties),
+};
+
+
+const njs_object_type_init_t njs_typed_array_i32_type_init = {
+ .constructor = njs_native_ctor(njs_typed_array_constructor, 3,
+ NJS_OBJ_TYPE_INT32_ARRAY),
+ .prototype_props = &njs_typed_array_i32_prototype_init,
+ .constructor_props = &njs_typed_array_i32_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
+static const njs_object_prop_t njs_typed_array_f32_constructor_props[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Float32Array"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 1, 3.0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 4),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_f32_constructor_init = {
+ njs_typed_array_f32_constructor_props,
+ njs_nitems(njs_typed_array_f32_constructor_props),
+};
+
+
+static const njs_object_prop_t njs_typed_array_f32_prototype_properties[] =
+{
+ {
+ .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_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 4),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_f32_prototype_init = {
+ njs_typed_array_f32_prototype_properties,
+ njs_nitems(njs_typed_array_f32_prototype_properties),
+};
+
+
+const njs_object_type_init_t njs_typed_array_f32_type_init = {
+ .constructor = njs_native_ctor(njs_typed_array_constructor, 3,
+ NJS_OBJ_TYPE_FLOAT32_ARRAY),
+ .prototype_props = &njs_typed_array_f32_prototype_init,
+ .constructor_props = &njs_typed_array_f32_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
+static const njs_object_prop_t njs_typed_array_f64_constructor_props[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Float64Array"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 1, 3.0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 8),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_f64_constructor_init = {
+ njs_typed_array_f64_constructor_props,
+ njs_nitems(njs_typed_array_f64_constructor_props),
+};
+
+
+static const njs_object_prop_t njs_typed_array_f64_prototype_properties[] =
+{
+ {
+ .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_long_string("BYTES_PER_ELEMENT"),
+ .value = njs_value(NJS_NUMBER, 1, 8),
+ .configurable = 0,
+ .enumerable = 0,
+ .writable = 0,
+ },
+};
+
+
+static const njs_object_init_t njs_typed_array_f64_prototype_init = {
+ njs_typed_array_f64_prototype_properties,
+ njs_nitems(njs_typed_array_f64_prototype_properties),
+};
+
+
+const njs_object_type_init_t njs_typed_array_f64_type_init = {
+ .constructor = njs_native_ctor(njs_typed_array_constructor, 3,
+ NJS_OBJ_TYPE_FLOAT64_ARRAY),
+ .prototype_props = &njs_typed_array_f64_prototype_init,
+ .constructor_props = &njs_typed_array_f64_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
--- /dev/null
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NJS_TYPED_ARRAY_H_INCLUDED_
+#define _NJS_TYPED_ARRAY_H_INCLUDED_
+
+
+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,
+ njs_typed_array_t *array, njs_value_t *sep);
+
+
+njs_inline unsigned
+njs_typed_array_element_size(njs_object_type_t type)
+{
+ switch (type) {
+ case NJS_OBJ_TYPE_UINT8_ARRAY:
+ case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY:
+ case NJS_OBJ_TYPE_INT8_ARRAY:
+ return 1;
+
+ case NJS_OBJ_TYPE_UINT16_ARRAY:
+ case NJS_OBJ_TYPE_INT16_ARRAY:
+ return 2;
+
+ case NJS_OBJ_TYPE_UINT32_ARRAY:
+ case NJS_OBJ_TYPE_INT32_ARRAY:
+ case NJS_OBJ_TYPE_FLOAT32_ARRAY:
+ return 4;
+
+ default:
+
+ /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */
+
+ return 8;
+ }
+}
+
+
+njs_inline uint32_t
+njs_typed_array_length(const njs_typed_array_t *array)
+{
+ return array->byte_length / njs_typed_array_element_size(array->type);
+}
+
+
+njs_inline double
+njs_typed_array_get(const njs_typed_array_t *array, uint32_t index)
+{
+ njs_array_buffer_t *buffer;
+
+ index += array->offset;
+
+ buffer = array->buffer;
+
+ switch (array->type) {
+ case NJS_OBJ_TYPE_UINT8_ARRAY:
+ case NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY:
+ return buffer->u.u8[index];
+
+ case NJS_OBJ_TYPE_INT8_ARRAY:
+ return buffer->u.i8[index];
+
+ case NJS_OBJ_TYPE_UINT16_ARRAY:
+ return buffer->u.u16[index];
+
+ case NJS_OBJ_TYPE_INT16_ARRAY:
+ return buffer->u.i16[index];
+
+ case NJS_OBJ_TYPE_UINT32_ARRAY:
+ return buffer->u.u32[index];
+
+ case NJS_OBJ_TYPE_INT32_ARRAY:
+ return buffer->u.i32[index];
+
+ case NJS_OBJ_TYPE_FLOAT32_ARRAY:
+ return buffer->u.f32[index];
+
+ default:
+
+ /* NJS_OBJ_TYPE_FLOAT64_ARRAY. */
+
+ return buffer->u.f64[index];
+ }
+
+ return NAN;
+}
+
+
+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 (v < 0) {
+ v = 0;
+ }
+
+ 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;
+extern const njs_object_type_init_t njs_typed_array_i8_type_init;
+extern const njs_object_type_init_t njs_typed_array_u16_type_init;
+extern const njs_object_type_init_t njs_typed_array_i16_type_init;
+extern const njs_object_type_init_t njs_typed_array_u32_type_init;
+extern const njs_object_type_init_t njs_typed_array_i32_type_init;
+extern const njs_object_type_init_t njs_typed_array_f32_type_init;
+extern const njs_object_type_init_t njs_typed_array_f64_type_init;
+
+
+#endif /* _NJS_TYPED_ARRAY_H_INCLUDED_ */
const njs_value_t *key);
static njs_int_t njs_array_property_query(njs_vm_t *vm,
njs_property_query_t *pq, njs_array_t *array, uint32_t index);
+static njs_int_t njs_typed_array_property_query(njs_vm_t *vm,
+ njs_property_query_t *pq, njs_typed_array_t *array, uint32_t index);
static njs_int_t njs_string_property_query(njs_vm_t *vm,
njs_property_query_t *pq, njs_value_t *object, uint32_t index);
static njs_int_t njs_external_property_query(njs_vm_t *vm,
return "array";
case NJS_ARRAY_BUFFER:
- return "object arraybuffer";
+ return "array buffer";
+
+ case NJS_TYPED_ARRAY:
+ return "typed array";
case NJS_OBJECT_BOOLEAN:
return "object boolean";
* in NJS_PROPERTY_QUERY_GET
* prop->type is NJS_PROPERTY or NJS_PROPERTY_HANDLER.
* in NJS_PROPERTY_QUERY_SET, NJS_PROPERTY_QUERY_DELETE
- * prop->type is NJS_PROPERTY, NJS_PROPERTY_REF or
+ * prop->type is NJS_PROPERTY, NJS_PROPERTY_REF,
+ * NJS_PROPERTY_TYPED_ARRAY_REF or
* NJS_PROPERTY_HANDLER.
* NJS_DECLINED property was not found in object,
* if pq->lhq.value != NULL it contains retval of type
njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *value,
njs_value_t *key)
{
+ double num;
uint32_t index;
njs_int_t ret;
njs_object_t *obj;
case NJS_STRING:
if (njs_fast_path(!njs_is_null_or_undefined_or_boolean(key))) {
- index = njs_key_to_index(key);
-
- if (njs_fast_path(index < NJS_STRING_MAX_LENGTH)) {
- return njs_string_property_query(vm, pq, value, index);
+ num = njs_key_to_index(key);
+ if (njs_fast_path(njs_number_is_integer_index(num, key))) {
+ return njs_string_property_query(vm, pq, value, num);
}
}
case NJS_OBJECT:
case NJS_ARRAY:
case NJS_ARRAY_BUFFER:
+ case NJS_TYPED_ARRAY:
case NJS_OBJECT_BOOLEAN:
case NJS_OBJECT_NUMBER:
case NJS_OBJECT_SYMBOL:
njs_object_property_query(njs_vm_t *vm, njs_property_query_t *pq,
njs_object_t *object, const njs_value_t *key)
{
- uint32_t index;
+ double num;
njs_int_t ret;
njs_bool_t own;
njs_array_t *array;
njs_object_t *proto;
njs_object_prop_t *prop;
+ njs_typed_array_t *tarray;
njs_object_value_t *ov;
pq->lhq.proto = &njs_object_hash_proto;
if (!njs_is_null_or_undefined_or_boolean(key)) {
switch (proto->type) {
case NJS_ARRAY:
- index = njs_key_to_index(key);
- if (njs_fast_path(index < NJS_ARRAY_MAX_INDEX)) {
+ num = njs_key_to_index(key);
+ if (njs_fast_path(njs_number_is_integer_index(num, key))) {
array = (njs_array_t *) proto;
- return njs_array_property_query(vm, pq, array, index);
+ return njs_array_property_query(vm, pq, array, num);
+ }
+
+ break;
+
+ case NJS_TYPED_ARRAY:
+ num = njs_key_to_index(key);
+ if (njs_fast_path(njs_number_is_integer_index(num, key))) {
+ tarray = (njs_typed_array_t *) proto;
+ return njs_typed_array_property_query(vm, pq, tarray, num);
+ }
+
+ if (!isnan(num)) {
+ return NJS_DECLINED;
}
break;
case NJS_OBJECT_STRING:
- index = njs_key_to_index(key);
- if (njs_fast_path(index < NJS_STRING_MAX_LENGTH)) {
+ num = njs_key_to_index(key);
+ if (njs_fast_path(njs_number_is_integer_index(num, key))) {
ov = (njs_object_value_t *) proto;
- ret = njs_string_property_query(vm, pq, &ov->value, index);
+ ret = njs_string_property_query(vm, pq, &ov->value, num);
if (njs_fast_path(ret != NJS_DECLINED)) {
return ret;
}
+static njs_int_t
+njs_typed_array_property_query(njs_vm_t *vm, njs_property_query_t *pq,
+ njs_typed_array_t *array, uint32_t index)
+{
+ njs_object_prop_t *prop;
+
+ if (index >= njs_typed_array_length(array)) {
+ return NJS_DECLINED;
+ }
+
+ prop = &pq->scratch;
+
+ if (pq->query == NJS_PROPERTY_QUERY_GET) {
+ njs_set_number(&prop->value, njs_typed_array_get(array, index));
+ prop->type = NJS_PROPERTY;
+
+ } else {
+ prop->value.data.u.typed_array = array;
+ prop->value.data.magic32 = index;
+ prop->type = NJS_PROPERTY_TYPED_ARRAY_REF;
+ }
+
+ prop->writable = 1;
+ prop->enumerable = 1;
+ prop->configurable = 0;
+
+ pq->lhq.value = prop;
+
+ return NJS_OK;
+}
+
+
static njs_int_t
njs_string_property_query(njs_vm_t *vm, njs_property_query_t *pq,
njs_value_t *object, uint32_t index)
*prop->value.data.u.value = *setval;
return NJS_OK;
+ case NJS_PROPERTY_TYPED_ARRAY_REF:
+ return njs_typed_array_set_value(vm,
+ njs_typed_array(&prop->value),
+ prop->value.data.magic32,
+ setval);
+
default:
njs_internal_error(vm, "unexpected property type \"%s\" "
"while setting",
goto found;
}
+ if (njs_slow_path(pq.own && njs_is_typed_array(value)
+ && njs_is_string(key)))
+ {
+ /* Integer-Indexed Exotic Objects [[DefineOwnProperty]]. */
+ if (!isnan(njs_string_to_index(key))) {
+ return NJS_OK;
+ }
+ }
+
break;
case NJS_ERROR:
*/
typedef enum {
- NJS_NULL = 0x00,
- NJS_UNDEFINED = 0x01,
+ NJS_NULL,
+ NJS_UNDEFINED,
/* The order of the above type is used in njs_is_null_or_undefined(). */
- NJS_BOOLEAN = 0x02,
+ NJS_BOOLEAN,
/*
* The order of the above type is used in
* njs_is_null_or_undefined_or_boolean().
*/
- NJS_NUMBER = 0x03,
+ NJS_NUMBER,
/*
* The order of the above type is used in njs_is_numeric().
* Booleans, null and void values can be used in mathematical operations:
* a numeric value of the null and false values is zero,
* a numeric value of the void value is NaN.
*/
- NJS_SYMBOL = 0x04,
+ NJS_SYMBOL,
- NJS_STRING = 0x05,
+ NJS_STRING,
/* The order of the above type is used in njs_is_primitive(). */
- NJS_DATA = 0x06,
+ NJS_DATA,
/* The type is external code. */
- NJS_EXTERNAL = 0x07,
+ NJS_EXTERNAL,
/*
* The invalid value type is used:
* to detect non-declared explicitly or implicitly variables,
* for native property getters.
*/
- NJS_INVALID = 0x08,
+ NJS_INVALID,
/*
* The object types are >= NJS_OBJECT, this is used in njs_is_object().
* is used in vm->prototypes and vm->constructors arrays.
*/
NJS_OBJECT = 0x10,
- NJS_ARRAY = 0x11,
- NJS_OBJECT_BOOLEAN = 0x12,
- NJS_OBJECT_NUMBER = 0x13,
- NJS_OBJECT_SYMBOL = 0x14,
- NJS_OBJECT_STRING = 0x15,
- NJS_FUNCTION = 0x16,
- NJS_REGEXP = 0x17,
- NJS_DATE = 0x18,
- NJS_PROMISE = 0x19,
- NJS_OBJECT_VALUE = 0x1A,
- NJS_ARRAY_BUFFER = 0x1B,
+ NJS_ARRAY,
+#define NJS_OBJECT_WRAPPER_MIN (NJS_OBJECT_BOOLEAN)
+ NJS_OBJECT_BOOLEAN,
+ NJS_OBJECT_NUMBER,
+ NJS_OBJECT_SYMBOL,
+ NJS_OBJECT_STRING,
+#define NJS_OBJECT_WRAPPER_MAX (NJS_OBJECT_STRING + 1)
+#define NJS_OBJECT_SPECIAL_MIN (NJS_FUNCTION)
+ NJS_FUNCTION,
+ NJS_REGEXP,
+ NJS_DATE,
+ NJS_TYPED_ARRAY,
+#define NJS_OBJECT_SPECIAL_MAX (NJS_TYPED_ARRAY + 1)
+ NJS_PROMISE,
+ NJS_OBJECT_VALUE,
+ NJS_ARRAY_BUFFER,
NJS_VALUE_TYPE_MAX
} njs_value_type_t;
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_regexp_s njs_regexp_t;
typedef struct njs_date_s njs_date_t;
typedef struct njs_object_value_s njs_promise_t;
njs_object_t *object;
njs_array_t *array;
njs_array_buffer_t *array_buffer;
+ njs_typed_array_t *typed_array;
njs_object_value_t *object_value;
njs_function_t *function;
njs_function_lambda_t *lambda;
};
+struct njs_typed_array_s {
+ njs_object_t object;
+ njs_array_buffer_t *buffer;
+ size_t offset; // byte_offset / element_size
+ size_t byte_length;
+ uint8_t type;
+};
+
+
typedef struct {
union {
uint32_t count;
typedef enum {
NJS_PROPERTY = 0,
NJS_PROPERTY_REF,
+ NJS_PROPERTY_TYPED_ARRAY_REF,
NJS_PROPERTY_HANDLER,
NJS_WHITEOUT,
} njs_object_prop_type_t;
((value)->type == NJS_ARRAY_BUFFER)
+#define njs_is_typed_array(value) \
+ ((value)->type == NJS_TYPED_ARRAY)
+
+
#define njs_is_function(value) \
((value)->type == NJS_FUNCTION)
((value)->data.u.array_buffer)
+#define njs_typed_array(value) \
+ ((value)->data.u.typed_array)
+
+
+#define njs_typed_array_buffer(value) \
+ ((value)->buffer)
+
+
#define njs_array_start(value) \
((value)->data.u.array->start)
}
+njs_inline void
+njs_set_typed_array(njs_value_t *value, njs_typed_array_t *array)
+{
+ value->data.u.typed_array = array;
+ value->type = NJS_TYPED_ARRAY;
+ value->data.truth = 1;
+}
+
+
njs_inline void
njs_set_function(njs_value_t *value, njs_function_t *function)
{
njs_inline njs_int_t
-njs_value_to_index(njs_vm_t *vm, njs_value_t *value, uint32_t *dst)
+njs_value_to_index(njs_vm_t *vm, njs_value_t *value, uint64_t *dst)
{
int64_t integer_index;
njs_int_t ret;
return NJS_ERROR;
}
- *dst = (uint32_t) integer_index;
+ *dst = integer_index;
}
return NJS_OK;
typedef enum {
NJS_OBJ_TYPE_OBJECT = 0,
NJS_OBJ_TYPE_ARRAY,
- NJS_OBJ_TYPE_ARRAY_BUFFER,
NJS_OBJ_TYPE_BOOLEAN,
NJS_OBJ_TYPE_NUMBER,
NJS_OBJ_TYPE_SYMBOL,
NJS_OBJ_TYPE_REGEXP,
NJS_OBJ_TYPE_DATE,
NJS_OBJ_TYPE_PROMISE,
+ NJS_OBJ_TYPE_ARRAY_BUFFER,
+
NJS_OBJ_TYPE_CRYPTO_HASH,
#define NJS_OBJ_TYPE_HIDDEN_MIN (NJS_OBJ_TYPE_CRYPTO_HASH)
NJS_OBJ_TYPE_CRYPTO_HMAC,
-#define NJS_OBJ_TYPE_HIDDEN_MAX (NJS_OBJ_TYPE_CRYPTO_HMAC + 1)
+ NJS_OBJ_TYPE_TYPED_ARRAY,
+#define NJS_OBJ_TYPE_HIDDEN_MAX (NJS_OBJ_TYPE_TYPED_ARRAY + 1)
+#define NJS_OBJ_TYPE_NORMAL_MAX (NJS_OBJ_TYPE_HIDDEN_MAX)
+
+#define NJS_OBJ_TYPE_TYPED_ARRAY_MIN (NJS_OBJ_TYPE_UINT8_ARRAY)
+#define njs_typed_array_index(type) (type - NJS_OBJ_TYPE_TYPED_ARRAY_MIN)
+ NJS_OBJ_TYPE_UINT8_ARRAY,
+ NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY,
+ NJS_OBJ_TYPE_INT8_ARRAY,
+ NJS_OBJ_TYPE_UINT16_ARRAY,
+ NJS_OBJ_TYPE_INT16_ARRAY,
+ NJS_OBJ_TYPE_UINT32_ARRAY,
+ NJS_OBJ_TYPE_INT32_ARRAY,
+ NJS_OBJ_TYPE_FLOAT32_ARRAY,
+ NJS_OBJ_TYPE_FLOAT64_ARRAY,
+#define NJS_OBJ_TYPE_TYPED_ARRAY_MAX (NJS_OBJ_TYPE_FLOAT64_ARRAY + 1)
+#define NJS_OBJ_TYPE_TYPED_ARRAY_SIZE (NJS_OBJ_TYPE_TYPED_ARRAY_MAX \
+ - NJS_OBJ_TYPE_TYPED_ARRAY_MIN)
NJS_OBJ_TYPE_ERROR,
NJS_OBJ_TYPE_EVAL_ERROR,
NJS_OBJ_TYPE_INTERNAL_ERROR,
NJS_OBJ_TYPE_TYPE_ERROR,
NJS_OBJ_TYPE_URI_ERROR,
NJS_OBJ_TYPE_MEMORY_ERROR,
-#define NJS_OBJ_TYPE_MAX (NJS_OBJ_TYPE_MEMORY_ERROR + 1)
+ NJS_OBJ_TYPE_MAX,
} njs_object_type_t;
njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
njs_value_t *init)
{
+ double num;
uint32_t index, size;
+ njs_int_t ret;
njs_array_t *array;
njs_value_t *val, name;
- njs_jump_off_t ret;
njs_object_prop_t *prop;
njs_lvlhsh_query_t lhq;
switch (value->type) {
case NJS_ARRAY:
- index = njs_key_to_index(key);
- if (njs_slow_path(index == NJS_ARRAY_INVALID_INDEX)) {
+ num = njs_key_to_index(key);
+ if (njs_slow_path(!njs_number_is_integer_index(num, key))) {
njs_internal_error(vm,
"invalid index while property initialization");
return NJS_ERROR;
}
+ index = (uint32_t) num;
array = value->data.u.array;
if (index >= array->length) {
&njs_string_object,
&njs_string_object,
&njs_string_object,
+ &njs_string_object,
+ &njs_string_object,
};
vm->retval = *types[value->type];
static njs_str_t while_loop = njs_str(
"var i = 0; while (i < 100000000) { i++ }; i");
+ static njs_str_t typed_array_10M = njs_str(
+ "var arr = new Uint8Array(10000000); var count = 0, length = arr.length;"
+ "arr.fill(2);"
+ "for (var i = 0; i < length; i++) { count += arr[i]; } count");
+
+ static njs_str_t array_10M = njs_str(
+ "var arr = new Array(10000000); var count = 0, length = arr.length;"
+ "arr.fill(2);"
+ "for (var i = 0; i < length; i++) { count += arr[i]; } count");
+
static njs_str_t fibo_result = njs_str("3524578");
static njs_str_t json_result = njs_str("123");
static njs_str_t loop_result = njs_str("100000000");
+ static njs_str_t sum_result = njs_str("20000000");
if (argc > 1) {
case 'u':
return njs_unit_test_benchmark(&fibo_utf8, &fibo_result,
"fibobench utf8 strings", 1);
+
+ case 't':
+ return njs_unit_test_benchmark(&typed_array_10M, &sum_result,
+ "typed_array_10M", 1);
+
+ case 'A':
+ return njs_unit_test_benchmark(&array_10M, &sum_result,
+ "array_10M", 1);
}
}
njs_printf("unknown agrument\n");
+
return EXIT_FAILURE;
}
"(1).X()"),
njs_str("123") },
- /* Indexes. */
+ /* Indices. */
{ njs_str("var a = []; a[-1] = 2; a[-1] == a['-1']"),
njs_str("true") },
{ njs_str("var a = []; a[NaN] = 2; a[NaN] == a['NaN']"),
njs_str("true") },
+#define NJS_NOT_CANONICAL_INDICES "['+0', '-0', '1.', '0.', '0.0', '4294967295', " \
+ " '4294967296', '-1', '1.1', '9223372036854775808']"
+
+ { njs_str("var a = [1,2]; "
+ NJS_NOT_CANONICAL_INDICES
+ ".every(v=>(a[v] === undefined))"),
+ njs_str("true") },
+
+ { njs_str("var a = [1,2]; "
+ NJS_NOT_CANONICAL_INDICES
+ ".every(v=>{a[v] = 'a'; return a[v] === 'a'})"),
+ njs_str("true") },
+
/* Number.toString(radix) method. */
{ njs_str("0..toString(2)"),
".map(pr=>buffer.slice(pr[0], pr[1]).byteLength)"),
njs_str("8,0,0,15,0,0") },
+ { njs_str("[false,NaN,1]"
+ ".map(v=>(new Uint8Array(v)).length)"),
+ njs_str("0,0,1") },
+
+#define NJS_TYPED_ARRAY_LIST "[Uint8Array,Uint8ClampedArray,Int8Array," \
+ " Uint16Array,Int16Array,Uint32Array," \
+ " Int32Array, Float32Array,Float64Array]"
+
+#define NJS_INT_TYPED_ARRAY_LIST "[Uint8Array,Uint8ClampedArray,Int8Array," \
+ " Uint16Array,Int16Array,Uint32Array," \
+ " Int32Array]"
+
+#define NJS_FLOAT_TYPED_ARRAY_LIST "[Float32Array,Float64Array]"
+
+ { njs_str("var TypedArray = Object.getPrototypeOf(Uint8Array);"
+ "[TypedArray.name, TypedArray.length]"),
+ njs_str("TypedArray,0") },
+
+ { njs_str("Object.getPrototypeOf(Uint8Array)()"),
+ njs_str("TypeError: Abstract class TypedArray not directly constructable") },
+
+ { njs_str("var TypedArray = Object.getPrototypeOf(Uint8Array);"
+ NJS_TYPED_ARRAY_LIST
+ ".every(v=>Object.getPrototypeOf(v) === TypedArray)"),
+ njs_str("true") },
+
+ { njs_str("var TypedArray = Object.getPrototypeOf(Uint8Array);"
+ NJS_TYPED_ARRAY_LIST
+ ".every(v=>Object.getPrototypeOf(v.prototype) === TypedArray.prototype)"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v.prototype.constructor(0); "
+ " return njs.dump(a) === `${v.name} []`})"),
+ njs_str("true") },
+
+ { njs_str("var global = this;"
+ NJS_TYPED_ARRAY_LIST
+ ".every(v=>ArrayBuffer.isView(new global[v.name]))"),
+ njs_str("true") },
+
+ { njs_str("var global = this;"
+ NJS_TYPED_ARRAY_LIST
+ ".every(v=>global[v.name][Symbol.species].name === v.name)"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v({length:2, '0':1, '1':2}); "
+ " return a[0] == 1 && a[1] == 2 && a.length == 2})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{try{ new v({length:Math.pow(2,53)}) } "
+ " catch(e) {return e.name == 'InternalError' || e.name == 'RangeError'}})"),
+ njs_str("true") },
+
+ { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v({length:5, 0: null, 2:42, 3:'7', 4:NaN, 5:Symbol('1')}); "
+ " return njs.dump(a) === `${v.name} [0,NaN,42,7,NaN]`})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var o = {length:2, '0':1}; Object.defineProperty(o, '1', {get(){throw 'Oops'}});"
+ " try {new v(o)} catch (e) { return e == 'Oops'}})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v(3); Object.defineProperty(a, '1', {value:1});"
+ " return njs.dump(a) === `${v.name} [0,1,0]`})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,1,1]); Object.defineProperty(a, '1', {});"
+ " return njs.dump(a) === `${v.name} [1,1,1]`})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{try {var a = new v([1,1]); Object.defineProperty(a, '1', {configurable:true})} "
+ " catch (e) { return e.message == 'Cannot redefine property: \"1\"'}})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{try {var a = new v([1,1]); Object.defineProperty(a, '1', {enumerable:false})} "
+ " catch (e) { return e.message == 'Cannot redefine property: \"1\"'}})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{try {var a = new v([1,1]); Object.defineProperty(a, '1', {writable:false})} "
+ " catch (e) { return e.message == 'Cannot redefine property: \"1\"'}})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{try {var a = new v([1,1]); Object.defineProperty(a, '1', {get(){return 22}})} "
+ " catch (e) { return e.message == 'Cannot redefine property: \"1\"'}})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v(3);"
+ " return [a.hasOwnProperty('1'), a.hasOwnProperty('4')].toString() === 'true,false'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var descs = Object.getOwnPropertyNames(v).sort().toString(); "
+ " return descs === 'BYTES_PER_ELEMENT,length,name,prototype'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".map(v=>{var a = new ArrayBuffer(8); return (new v(a).length)})"),
+ njs_str("8,8,8,4,4,2,2,2,1") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".map(v=>{var a = new v(1); a[0]--; return a[0]})"),
+ njs_str("255,0,-1,65535,-1,4294967295,-1,-1,-1") },
+
+ { njs_str(NJS_NOT_CANONICAL_INDICES
+ ".every(v=>{var a = new Uint8Array([1,2]); return a[v] === undefined})"),
+ njs_str("true") },
+
+ { njs_str(NJS_NOT_CANONICAL_INDICES
+ ".map(v=>{var a = new Uint8Array([1,2]); a[v] = 'a'; return a[v]})"),
+ njs_str("a,,a,a,a,,,,,a") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{v.prototype[10] = 'foo'; return (new v(16))[10] === 0})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{v.prototype[20] = 'foo'; return (new v(16))[20] === undefined})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{v.prototype.foo = 'bar'; return (new v(16)).foo === 'bar'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{v.prototype[-1] = 'foo'; return (new v(8))[-1] === undefined})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".map(v=>v.BYTES_PER_ELEMENT)"),
+ njs_str("1,1,1,2,2,4,4,4,8") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>v.length === 3)"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v(1); return --a[0] == -1})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v(4); a.fill(42); return (a[0] === 42 && a.length == 4)})"),
+ njs_str("true") },
+
+ { njs_str(NJS_INT_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v(1); a.fill({}); return a[0] === 0})"),
+ njs_str("true") },
+
+ { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v(1); a.fill({}); return isNaN(a[0])})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3]); a.fill({valueOf(){return 12}}, 1,2); "
+ " return (a[0] === 1 && a[1] === 12 && a[2] === 3 && a.length == 3)})"),
+ njs_str("true") },
+
+ { njs_str(NJS_INT_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3]); a.fill('qq', 1, 2); "
+ " return (a[0] === 1 && a[1] === 0 && a[2] === 3 && a.length == 3)})"),
+ njs_str("true") },
+
+ { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3]); a.fill('qq', 1, 2); "
+ " return (a[0] === 1 && isNaN(a[1]) && a[2] === 3 && a.length == 3)})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3]); var d = Object.getOwnPropertyDescriptors(a)[1];"
+ " return (d.value === 2 && d.writable && d.enumerable && !d.configurable)})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3]); return Object.keys(a).toString() === '0,1,2'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3]); return Object.values(a).toString() === '1,2,3'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3]); return Object.entries(a).toString() === '0,1,1,2,2,3'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{try {delete (new v(1))[0]} catch (e) { return e.name == 'TypeError'}})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{return delete (new v(1))[-1]; })"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v(8), b = new v(a.buffer); a[0] = 42; return b[0] === 42})"),
+ njs_str("true") },
+
+ { njs_str(NJS_INT_TYPED_ARRAY_LIST
+ ".map(v=>{var init = new Uint8Array([1,2,3]);"
+ " try { return new v(init.buffer, 0, 2)} catch (e) {return e.name}})"),
+ njs_str("1,2,1,2,1,2,RangeError,RangeError,RangeError,RangeError") },
+
+ { njs_str(NJS_INT_TYPED_ARRAY_LIST
+ ".map(v=>{var init = new Uint8Array([1,2,3]);"
+ " try { return new v(init.buffer, 1)} catch (e) {return e.name}})"),
+ njs_str("2,3,2,3,2,3,RangeError,RangeError,RangeError,RangeError") },
+
+ { njs_str(NJS_INT_TYPED_ARRAY_LIST
+ ".map(v=>{var init = new Uint32Array([0xaabbccdd]);"
+ " try { return new v(init.buffer, 0, 2)} catch (e) {return e.name}})"),
+ njs_str("221,204,221,204,-35,-52,52445,43707,-13091,-21829,RangeError,RangeError") },
+
+ { njs_str(NJS_INT_TYPED_ARRAY_LIST
+ ".map(v=>{var init = new Uint32Array([0xaabbccdd]);"
+ " try { return new v(init.buffer, 1, 2)} catch (e) {return e.name}})"),
+ njs_str("204,187,204,187,-52,-69,RangeError,RangeError,RangeError,RangeError") },
+
+ { njs_str(NJS_INT_TYPED_ARRAY_LIST
+ ".map(v=>{var init = new Uint32Array([0xaabbccdd,0xdeadbeef]);"
+ " try { return new v(init.buffer, 0, 2)} catch (e) {return e.name}})"),
+ njs_str("221,204,221,204,-35,-52,52445,43707,-13091,-21829,2864434397,3735928559,-1430532899,-559038737") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var buffer1 = new ArrayBuffer(8 * v.BYTES_PER_ELEMENT);"
+ " var ta1 = new v(buffer1);"
+ " var ta2 = new v(ta1.buffer, 4 * v.BYTES_PER_ELEMENT); "
+ " ta1[5] = 100; ta1[7] = 101;"
+ " return ta2.toString() === '0,100,0,101'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([42,11]); return a.toString() === '42,11'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v(3); a[1] = 42; return a.toString() === '0,42,0'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v(0); return a.toString() === ''})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([42,11]); return a.join('|') === '42|11'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([42,11]); return a.join('α').length === 5})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{return njs.dump(new v()) === `${v.name} []`})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{return njs.dump(new v([42,11])) === `${v.name} [42,11]`})"),
+ njs_str("true") },
+
+ { njs_str("var a = new Uint8Array(8); var b = new Uint32Array(a.buffer);"
+ "a[0] = 0xff; a[1] = 0xff; a[2] = 0xff; a[3] = 0xff; b[0];"),
+ njs_str("4294967295") },
+
+ { njs_str("[1,300,-100]"
+ ".map(v=>{var a = new Uint8Array(1); a[0] = v; return a[0];})"),
+ njs_str("1,44,156") },
+
+ { njs_str("[1,300,-100]"
+ ".map(v=>{var a = new Uint8ClampedArray(1); a[0] = v; return a[0];})"),
+ njs_str("1,255,0") },
+
+ { njs_str("[1,300,-100]"
+ ".map(v=>{var a = new Uint8ClampedArray(1); a.set([v], 0); return a[0];})"),
+ njs_str("1,255,0") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = [1,2,3,4]; var a = new v(4);"
+ " a.set(init); return a.toString() === '1,2,3,4'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = {length:4, 0:1,1:2,2:3,3:4}; var a = new v(4);"
+ " a.set(init); return a.toString() === '1,2,3,4'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = new v([1,2,3,4]); var a = new v(init);"
+ " return a.toString() === '1,2,3,4'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = new v([1,2,3,4]); var a = new v(4);"
+ " a.set(init); return a.toString() === '1,2,3,4'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = {length:2, 0:1,1:2}; var a = new v(4);"
+ " a.set(init,2); return a.toString() === '0,0,1,2'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_INT_TYPED_ARRAY_LIST
+ ".every(v=>{var init = {length:4, 0:1,1:2,3:4}; var a = new v(4);"
+ " a.set(init); return a.toString() === '1,2,0,4'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
+ ".every(v=>{var init = {length:4, 0:1,1:2,3:4}; var a = new v(4);"
+ " a.set(init); return a.toString() === '1,2,NaN,4'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = [1,2,3]; var a = new v(4);"
+ " a.set(init); return a.toString() === '1,2,3,0'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = new v([1,2,3]); var a = new v(4);"
+ " a.set(init); return a.toString() === '1,2,3,0'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = [1,2,3,4]; var a = new v(4);"
+ " a.set(init, 0); return a.toString() === '1,2,3,4'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = [1,2]; var a = new v(4);"
+ " a.set(init, 2); return a.toString() === '0,0,1,2'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = new v([1,2]); var a = new v(4);"
+ " a.set(init,2); return a.toString() === '0,0,1,2'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = [1,2,3,4]; var a = new v(4);"
+ " try {a.set(init,2)} catch (e) {return e.name == 'RangeError'};})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = [1,2,3,4]; var a = new v(4);"
+ " try {a.set(init,Infinity)} catch (e) {return e.name == 'RangeError'};})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = [1,2,3,4,5]; var a = new v(4);"
+ " try {a.set(init)} catch (e) {return e.name == 'RangeError'};})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = {length:5}; var a = new v(4);"
+ " try {a.set(init)} catch (e) {return e.name == 'RangeError'};})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = {length:3}; var a = new v(4);"
+ " try {a.set(init,2)} catch (e) {return e.name == 'RangeError'};})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = {length:3}; var a = new v(4);"
+ " try {a.set(init,Infinity)} catch (e) {return e.name == 'RangeError'};})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = new v([1,2,3,4,5]); var a = new v(4);"
+ " try {a.set(init)} catch (e) {return e.name == 'RangeError'};})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = new v([1,2,3]); var a = new v(4);"
+ " try {a.set(init,2)} catch (e) {return e.name == 'RangeError'};})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var init = new v([1,2,3]); var a = new v(4);"
+ " try {a.set(init,Infinity)} catch (e) {return e.name == 'RangeError'};})"),
+ njs_str("true") },
+
+ { njs_str("[-1,-1.00001,-Infinity]"
+ ".every(v=>{ try {(new Uint8Array(10)).set([], v)} catch (ee) {return ee.name === 'RangeError'}})"),
+ njs_str("true") },
+
+ { njs_str("[0.1,2.5,{},{'1': '10'},[1000]]"
+ ".map(v=>{var a = new Uint8Array(1); a.set([v], 0); return a[0]})"),
+ njs_str("0,2,0,0,232") },
+
+ { njs_str("[1.0, -1234.0]"
+ ".map(v=>{var a = new Float32Array(1); a[0] = v; var b = new Uint8Array(a.buffer);"
+ " return (b[0] << 24 | b[1] << 16| b[2] <<8 | b[3]).toString(16).padStart(8, '0');})"),
+ njs_str("0000803f,00409ac4") },
+
+ { njs_str("var a = new ArrayBuffer(0); a.slice(0, 0).byteLength"),
+ njs_str("0") },
+
+ { njs_str("var a = new ArrayBuffer(10); a.slice(1).byteLength"),
+ njs_str("9") },
+
+ { njs_str("var a = new ArrayBuffer(10); a.slice(1,2).byteLength"),
+ njs_str("1") },
+
+ { njs_str("var a = new ArrayBuffer(10); a.slice(0,-1).byteLength"),
+ njs_str("9") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".map(v=>{var buffer = new ArrayBuffer(8); var view = new v(buffer);"
+ " view[0] = 511; return new Uint8Array(buffer.slice(0,4))})"),
+ njs_str("255,0,0,0,255,0,0,0,255,0,0,0,255,1,0,0,255,1,0,0,255,1,0,0,255,1,0,0,0,128,255,67,0,0,0,0") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".map(v=>{var buffer = new ArrayBuffer(8); var view = new v(buffer);"
+ " view[view.length - 1] = 511; return new Uint8Array(buffer.slice(4))})"),
+ njs_str("0,0,0,255,0,0,0,255,0,0,0,255,0,0,255,1,0,0,255,1,255,1,0,0,255,1,0,0,0,128,255,67,0,240,127,64") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".map(v=>{var buffer = new ArrayBuffer(8); var view = new v(buffer);"
+ " view[0] = 511; return new Uint8Array(buffer.slice(0,-4))})"),
+ njs_str("255,0,0,0,255,0,0,0,255,0,0,0,255,1,0,0,255,1,0,0,255,1,0,0,255,1,0,0,0,128,255,67,0,0,0,0") },
+
+ { njs_str("var a = new Uint8Array(10); var b = a.slice(1); b.length"),
+ njs_str("9") },
+
+ { njs_str("var a = new Uint8Array(10); var b = a.slice(0,9); b.length"),
+ njs_str("9") },
+
+ { njs_str("var a = new Uint8Array(10); var b = a.slice(9,10); b.length"),
+ njs_str("1") },
+
+ { njs_str("var a = new Uint8Array(10); var b = a.slice(); b.length"),
+ njs_str("10") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([42]); "
+ " var r = a.slice();"
+ " return njs.dump(r) === `${v.name} [42]`;})"),
+ njs_str("true") },
+
+ { njs_str(NJS_INT_TYPED_ARRAY_LIST
+ ".map(v=>{var init = new Uint8Array([1,2,3,4,5,6,7,8]); var view = new v(init.buffer);"
+ " return view.slice(0,2)})"),
+ njs_str("1,2,1,2,1,2,513,1027,513,1027,67305985,134678021,67305985,134678021") },
+
+ { njs_str(NJS_INT_TYPED_ARRAY_LIST
+ ".map(v=>{var init = new Uint8Array([1,2,3,4,5,6,7,8]); var view = new v(init.buffer);"
+ " return view.slice(0,-2)})"),
+ njs_str("1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,513,1027,513,1027,,") },
+
+ { njs_str("var other = new Uint8Array([0xff,0xff,0xff,0xff]);"
+ NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([42]); "
+ " a.constructor = {[Symbol.species]: function () {return other;}}; "
+ " var r = a.slice(0,0);"
+ " return r == other && r.length == 4 && r[0] == 0xff;})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3]); "
+ " a.constructor = {[Symbol.species]: function () {return new v([0xff,0xee]);}}; "
+ " try {a.slice(0)} catch(e) {return e.name == 'TypeError'}})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3]); "
+ " a.constructor = {[Symbol.species]: function () {return new Date();}}; "
+ " try {a.slice(0)} catch(e) {return e.name == 'TypeError'}})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(2); "
+ " return a.toString() === '1,2,1,2'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(2,1); "
+ " return a.toString() === '1,2,2,3'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(2,1,2); "
+ " return a.toString() === '1,2,2,4'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(-1,1,2); "
+ " return a.toString() === '1,2,3,2'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(-1,-4,2); "
+ " return a.toString() === '1,2,3,1'})"),
+ njs_str("true") },
+
+ { njs_str(NJS_TYPED_ARRAY_LIST
+ ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(-1,-2); "
+ " return a.toString() === '1,2,3,3'})"),
+ njs_str("true") },
+
#if NJS_HAVE_LARGE_STACK
{ njs_str("var o = Object({length: 3});"
"Object.defineProperty(o, '0', {set: function(v){this[0] = 2 * v}});"
}
+static njs_int_t
+njs_string_to_index_test(njs_vm_t *vm, njs_opts_t *opts, njs_stat_t *stat)
+{
+ njs_str_t s, string;
+ njs_int_t ret;
+ njs_bool_t success, is_integer_index;
+ njs_uint_t i;
+
+ static const struct {
+ njs_value_t value;
+ njs_str_t expected;
+ njs_bool_t is_integer_index;
+ } tests[] = {
+ { njs_string(" 1"), njs_str("NaN"), 0 },
+ { njs_string(""), njs_str("NaN"), 0 },
+ { njs_string("+0"), njs_str("NaN"), 0 },
+ { njs_string("-"), njs_str("NaN"), 0 },
+
+ { njs_string("-0"), njs_str("-0"), 0 },
+ { njs_value(NJS_NUMBER, 0, -0.0), njs_str("-0"), 1 },
+
+ { njs_string("-1"), njs_str("-1"), 0 },
+ { njs_string("0"), njs_str("0"), 1 },
+ { njs_string("0."), njs_str("NaN"), 0 },
+ { njs_string("0.0"), njs_str("NaN"), 0 },
+ { njs_string("0x1"), njs_str("NaN"), 0 },
+ { njs_string("1 "), njs_str("NaN"), 0 },
+ { njs_string("1"), njs_str("1"), 1 },
+ { njs_string("1."), njs_str("NaN"), 0 },
+ { njs_string("1.1"), njs_str("1.1"), 0 },
+ { njs_string("100"), njs_str("100"), 1 },
+ { njs_string("1a"), njs_str("NaN"), 0 },
+ { njs_string("1e+19"), njs_str("NaN"), 0 },
+ { njs_string("1e+22"), njs_str("1e+22"), 0 },
+ { njs_string("1e22"), njs_str("NaN"), 0 },
+ { njs_string("4294967296"), njs_str("4294967296"), 0 },
+ };
+
+ for (i = 0; i < njs_nitems(tests); i++) {
+ if (njs_is_string(&tests[i].value)) {
+ njs_set_number(&vm->retval, njs_string_to_index(&tests[i].value));
+
+ ret = njs_vm_retval_dump(vm, &s, 0);
+ if (ret != NJS_OK) {
+ njs_printf("njs_string_to_index_test: "
+ "njs_vm_retval_dump() failed\n");
+ return NJS_ERROR;
+ }
+
+ success = njs_strstr_eq(&tests[i].expected, &s);
+
+ if (!success) {
+ njs_string_get(&tests[i].value, &string);
+ njs_printf("njs_string_to_index_test(\"%V\"):\n"
+ "expected: \"%V\"\n got: \"%V\"\n",
+ &string, &tests[i].expected, &s);
+
+ stat->failed++;
+ continue;
+ }
+ }
+
+ is_integer_index = njs_number_is_integer_index(njs_number(&vm->retval),
+ &tests[i].value);
+
+ if (tests[i].is_integer_index != is_integer_index) {
+ njs_string_get(&tests[i].value, &string);
+ njs_printf("njs_string_to_index_test2(\"%V\"):\n"
+ "expected: %b\n got: %b\n",
+ &string, tests[i].is_integer_index, is_integer_index);
+
+ stat->failed++;
+ continue;
+ }
+
+ stat->passed++;
+ }
+
+ return NJS_OK;
+}
+
+
static njs_int_t
njs_api_test(njs_opts_t *opts, njs_stat_t *stat)
{
njs_str("njs_file_dirname_test") },
{ njs_chb_test,
njs_str("njs_chb_test") },
+ { njs_string_to_index_test,
+ njs_str("njs_string_to_index_test") },
};
vm = NULL;