From: Dmitry Volyntsev Date: Fri, 17 Nov 2017 15:55:07 +0000 (+0300) Subject: Error builtin objects. X-Git-Tag: 0.1.15~11 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=160ba57ac362bd0f413da83b567d9c27fd363776;p=njs.git Error builtin objects. --- diff --git a/Makefile b/Makefile index b1083a5e..f73607de 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ $(NXT_BUILDDIR)/libnjs.a: \ $(NXT_BUILDDIR)/njs_function.o \ $(NXT_BUILDDIR)/njs_regexp.o \ $(NXT_BUILDDIR)/njs_date.o \ + $(NXT_BUILDDIR)/njs_error.o \ $(NXT_BUILDDIR)/njs_math.o \ $(NXT_BUILDDIR)/njs_extern.o \ $(NXT_BUILDDIR)/njs_variable.o \ @@ -53,6 +54,7 @@ $(NXT_BUILDDIR)/libnjs.a: \ $(NXT_BUILDDIR)/njs_function.o \ $(NXT_BUILDDIR)/njs_regexp.o \ $(NXT_BUILDDIR)/njs_date.o \ + $(NXT_BUILDDIR)/njs_error.o \ $(NXT_BUILDDIR)/njs_math.o \ $(NXT_BUILDDIR)/njs_extern.o \ $(NXT_BUILDDIR)/njs_variable.o \ @@ -271,6 +273,20 @@ $(NXT_BUILDDIR)/njs_date.o: \ -I$(NXT_LIB) -Injs $(NXT_PCRE_CFLAGS) \ njs/njs_date.c +$(NXT_BUILDDIR)/njs_error.o: \ + $(NXT_BUILDDIR)/libnxt.a \ + njs/njscript.h \ + njs/njs_vm.h \ + njs/njs_string.h \ + njs/njs_object.h \ + njs/njs_function.h \ + njs/njs_error.h \ + njs/njs_error.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/njs_error.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) -Injs $(NXT_PCRE_CFLAGS) \ + njs/njs_error.c + $(NXT_BUILDDIR)/njs_math.o: \ $(NXT_BUILDDIR)/libnxt.a \ njs/njscript.h \ diff --git a/njs/njs_array.c b/njs/njs_array.c index 8465e2d4..8b1d5597 100644 --- a/njs/njs_array.c +++ b/njs/njs_array.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -248,7 +249,7 @@ njs_array_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, size = (uint32_t) num; if ((double) size != num) { - vm->exception = &njs_exception_range_error; + njs_exception_range_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1713,7 +1714,7 @@ njs_array_prototype_reduce(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, n = njs_array_iterator_index(array, iter); if (n == NJS_ARRAY_INVALID_INDEX) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1774,7 +1775,7 @@ njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs) return NXT_OK; } - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1858,7 +1859,7 @@ njs_array_prototype_reduce_right(njs_vm_t *vm, njs_value_t *args, unused); type_error: - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } diff --git a/njs/njs_boolean.c b/njs/njs_boolean.c index f6839af5..ee1cb51e 100644 --- a/njs/njs_boolean.c +++ b/njs/njs_boolean.c @@ -18,6 +18,7 @@ #include #include #include +#include njs_ret_t @@ -98,7 +99,7 @@ njs_boolean_prototype_value_of(njs_vm_t *vm, njs_value_t *args, value = &value->data.u.object_value->value; } else { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } } @@ -123,7 +124,7 @@ njs_boolean_prototype_to_string(njs_vm_t *vm, njs_value_t *args, value = &value->data.u.object_value->value; } else { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } } diff --git a/njs/njs_builtin.c b/njs/njs_builtin.c index 1d36d447..de7da438 100644 --- a/njs/njs_builtin.c +++ b/njs/njs_builtin.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,15 @@ const njs_object_init_t *njs_prototype_init[] = { &njs_function_prototype_init, &njs_regexp_prototype_init, &njs_date_prototype_init, + &njs_error_prototype_init, + &njs_eval_error_prototype_init, + &njs_internal_error_prototype_init, + &njs_range_error_prototype_init, + &njs_ref_error_prototype_init, + &njs_syntax_error_prototype_init, + &njs_type_error_prototype_init, + &njs_uri_error_prototype_init, + &njs_memory_error_prototype_init, }; @@ -74,6 +84,15 @@ const njs_object_init_t *njs_constructor_init[] = { &njs_function_constructor_init, &njs_regexp_constructor_init, &njs_date_constructor_init, + &njs_error_constructor_init, + &njs_eval_error_constructor_init, + &njs_internal_error_constructor_init, + &njs_range_error_constructor_init, + &njs_ref_error_constructor_init, + &njs_syntax_error_constructor_init, + &njs_type_error_constructor_init, + &njs_uri_error_constructor_init, + &njs_memory_error_constructor_init, }; @@ -126,6 +145,16 @@ njs_builtin_objects_create(njs_vm_t *vm) { .date = { .time = NAN, .object = { .type = NJS_DATE } } }, + + { .object = { .type = NJS_OBJECT_ERROR } }, + { .object = { .type = NJS_OBJECT_EVAL_ERROR } }, + { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, + { .object = { .type = NJS_OBJECT_RANGE_ERROR } }, + { .object = { .type = NJS_OBJECT_REF_ERROR } }, + { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, + { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, + { .object = { .type = NJS_OBJECT_URI_ERROR } }, + { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, }; static const njs_function_init_t native_constructors[] = { @@ -139,6 +168,18 @@ njs_builtin_objects_create(njs_vm_t *vm) { njs_regexp_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } }, { njs_date_constructor, { 0 } }, + { njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_internal_error_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_range_error_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_ref_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_syntax_error_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_type_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_uri_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, }; static const njs_object_init_t *function_init[] = { @@ -309,6 +350,42 @@ njs_builtin_objects_create(njs_vm_t *vm) * Date.__proto__ -> Function_Prototype, * Date_Prototype.__proto__ -> Object_Prototype, * + * Error(), + * Error.__proto__ -> Function_Prototype, + * Error_Prototype.__proto__ -> Object_Prototype, + * + * EvalError(), + * EvalError.__proto__ -> Function_Prototype, + * EvalError_Prototype.__proto__ -> Error_Prototype, + * + * InternalError(), + * InternalError.__proto__ -> Function_Prototype, + * InternalError_Prototype.__proto__ -> Error_Prototype, + * + * RangeError(), + * RangeError.__proto__ -> Function_Prototype, + * RangeError_Prototype.__proto__ -> Error_Prototype, + * + * ReferenceError(), + * ReferenceError.__proto__ -> Function_Prototype, + * ReferenceError_Prototype.__proto__ -> Error_Prototype, + * + * SyntaxError(), + * SyntaxError.__proto__ -> Function_Prototype, + * SyntaxError_Prototype.__proto__ -> Error_Prototype, + * + * TypeError(), + * TypeError.__proto__ -> Function_Prototype, + * TypeError_Prototype.__proto__ -> Error_Prototype, + * + * URIError(), + * URIError.__proto__ -> Function_Prototype, + * URIError_Prototype.__proto__ -> Error_Prototype, + * + * MemoryError(), + * MemoryError.__proto__ -> Function_Prototype, + * MemoryError_Prototype.__proto__ -> Error_Prototype, + * * eval(), * eval.__proto__ -> Function_Prototype. */ @@ -319,7 +396,7 @@ njs_builtin_objects_clone(njs_vm_t *vm) size_t size; nxt_uint_t i; njs_value_t *values; - njs_object_t *object_prototype, *function_prototype; + njs_object_t *object_prototype, *function_prototype, *error_prototype; /* * Copy both prototypes and constructors arrays by one memcpy() @@ -332,10 +409,16 @@ njs_builtin_objects_clone(njs_vm_t *vm) object_prototype = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; - for (i = NJS_PROTOTYPE_ARRAY; i < NJS_PROTOTYPE_MAX; i++) { + for (i = NJS_PROTOTYPE_ARRAY; i < NJS_PROTOTYPE_EVAL_ERROR; i++) { vm->prototypes[i].object.__proto__ = object_prototype; } + error_prototype = &vm->prototypes[NJS_PROTOTYPE_ERROR].object; + + for (i = NJS_PROTOTYPE_EVAL_ERROR; i < NJS_PROTOTYPE_MAX; i++) { + vm->prototypes[i].object.__proto__ = error_prototype; + } + function_prototype = &vm->prototypes[NJS_CONSTRUCTOR_FUNCTION].object; values = vm->scopes[NJS_SCOPE_GLOBAL]; diff --git a/njs/njs_date.c b/njs/njs_date.c index 8a170805..b87b1f3a 100644 --- a/njs/njs_date.c +++ b/njs/njs_date.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1062,7 +1063,7 @@ njs_date_prototype_to_iso_string(njs_vm_t *vm, njs_value_t *args, return njs_string_new(vm, &vm->retval, buf, size, size); } - vm->exception = &njs_exception_range_error; + njs_exception_range_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1910,7 +1911,7 @@ njs_date_prototype_to_json(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, } } - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } diff --git a/njs/njs_error.c b/njs/njs_error.c new file mode 100644 index 00000000..dbb560c1 --- /dev/null +++ b/njs/njs_error.c @@ -0,0 +1,865 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) NGINX, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const njs_value_t njs_error_message_string = njs_string("message"); +static const njs_value_t njs_error_name_string = njs_string("name"); + + +void +njs_exception_error_create(njs_vm_t *vm, njs_value_type_t type, + const char* fmt, ...) +{ + size_t size; + va_list args; + nxt_int_t ret; + njs_value_t string, *value; + njs_object_t *error; + + static char buf[256]; + + if (fmt != NULL) { + va_start(args, fmt); + size = vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + } else { + size = 0; + } + + ret = njs_string_new(vm, &string, (const u_char *) buf, size, size); + if (nxt_slow_path(ret != NXT_OK)) { + goto memory_error; + } + + error = njs_error_alloc(vm, type, NULL, &string); + if (nxt_slow_path(error == NULL)) { + goto memory_error; + } + + value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t)); + if (nxt_slow_path(value == NULL)) { + goto memory_error; + } + + value->data.u.object = error; + value->type = type; + value->data.truth = 1; + + vm->exception = value; + + return; + +memory_error: + + njs_exception_memory_error(vm); +} + + +nxt_noinline njs_object_t * +njs_error_alloc(njs_vm_t *vm, njs_value_type_t type, const njs_value_t *name, + const njs_value_t *message) +{ + nxt_int_t ret; + njs_object_t *error; + njs_object_prop_t *prop; + nxt_lvlhsh_query_t lhq; + + error = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_object_t)); + if (nxt_slow_path(error == NULL)) { + return NULL; + } + + nxt_lvlhsh_init(&error->hash); + nxt_lvlhsh_init(&error->shared_hash); + error->type = type; + error->shared = 0; + error->extensible = 1; + error->__proto__ = &vm->prototypes[njs_error_prototype_index(type)].object; + + lhq.replace = 0; + lhq.pool = vm->mem_cache_pool; + + if (name != NULL) { + lhq.key = nxt_string_value("name"); + lhq.key_hash = NJS_NAME_HASH; + lhq.proto = &njs_object_hash_proto; + + prop = njs_object_prop_alloc(vm, &njs_error_name_string, name, 1); + if (nxt_slow_path(prop == NULL)) { + return NULL; + } + + lhq.value = prop; + + ret = nxt_lvlhsh_insert(&error->hash, &lhq); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + } + + if (message!= NULL) { + lhq.key = nxt_string_value("message"); + lhq.key_hash = NJS_MESSAGE_HASH; + lhq.proto = &njs_object_hash_proto; + + prop = njs_object_prop_alloc(vm, &njs_error_message_string, message, 1); + if (nxt_slow_path(prop == NULL)) { + return NULL; + } + + prop->enumerable = 0; + + lhq.value = prop; + + ret = nxt_lvlhsh_insert(&error->hash, &lhq); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + } + + return error; +} + + +static njs_ret_t +njs_error_create(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_value_type_t type) +{ + njs_object_t *error; + const njs_value_t *value; + + if (nargs == 1) { + value = &njs_string_empty; + + } else { + value = &args[1]; + } + + error = njs_error_alloc(vm, type, NULL, value); + if (nxt_slow_path(error == NULL)) { + njs_exception_memory_error(vm); + return NXT_ERROR; + } + + vm->retval.data.u.object = error; + vm->retval.type = type; + vm->retval.data.truth = 1; + + return NXT_OK; +} + + +njs_ret_t +njs_error_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + return njs_error_create(vm, args, nargs, NJS_OBJECT_ERROR); +} + + +static const njs_object_prop_t njs_error_constructor_properties[] = +{ + /* Error.name == "Error". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("Error"), + }, + + /* Error.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, + + /* Error.prototype. */ + { + .type = NJS_NATIVE_GETTER, + .name = njs_string("prototype"), + .value = njs_native_getter(njs_object_prototype_create), + }, +}; + + +const njs_object_init_t njs_error_constructor_init = { + nxt_string("Error"), + njs_error_constructor_properties, + nxt_nitems(njs_error_constructor_properties), +}; + + +njs_ret_t +njs_eval_error_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + return njs_error_create(vm, args, nargs, NJS_OBJECT_EVAL_ERROR); +} + + +static const njs_object_prop_t njs_eval_error_constructor_properties[] = +{ + /* EvalError.name == "EvalError". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("EvalError"), + }, + + /* EvalError.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, + + /* EvalError.prototype. */ + { + .type = NJS_NATIVE_GETTER, + .name = njs_string("prototype"), + .value = njs_native_getter(njs_object_prototype_create), + }, +}; + + +const njs_object_init_t njs_eval_error_constructor_init = { + nxt_string("EvalError"), + njs_eval_error_constructor_properties, + nxt_nitems(njs_eval_error_constructor_properties), +}; + + +njs_ret_t +njs_internal_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_error_create(vm, args, nargs, NJS_OBJECT_INTERNAL_ERROR); +} + + +static const njs_object_prop_t njs_internal_error_constructor_properties[] = +{ + /* InternalError.name == "InternalError". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("InternalError"), + }, + + /* InternalError.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, + + /* InternalError.prototype. */ + { + .type = NJS_NATIVE_GETTER, + .name = njs_string("prototype"), + .value = njs_native_getter(njs_object_prototype_create), + }, +}; + + +const njs_object_init_t njs_internal_error_constructor_init = { + nxt_string("InternalError"), + njs_internal_error_constructor_properties, + nxt_nitems(njs_internal_error_constructor_properties), +}; + + +njs_ret_t +njs_range_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_error_create(vm, args, nargs, NJS_OBJECT_RANGE_ERROR); +} + + +static const njs_object_prop_t njs_range_error_constructor_properties[] = +{ + /* RangeError.name == "RangeError". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("RangeError"), + }, + + /* RangeError.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, + + /* RangeError.prototype. */ + { + .type = NJS_NATIVE_GETTER, + .name = njs_string("prototype"), + .value = njs_native_getter(njs_object_prototype_create), + }, +}; + + +const njs_object_init_t njs_range_error_constructor_init = { + nxt_string("RangeError"), + njs_range_error_constructor_properties, + nxt_nitems(njs_range_error_constructor_properties), +}; + + +njs_ret_t +njs_ref_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_error_create(vm, args, nargs, NJS_OBJECT_REF_ERROR); +} + + +static const njs_object_prop_t njs_ref_error_constructor_properties[] = +{ + /* ReferenceError.name == "ReferenceError". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("ReferenceError"), + }, + + /* ReferenceError.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, + + /* ReferenceError.prototype. */ + { + .type = NJS_NATIVE_GETTER, + .name = njs_string("prototype"), + .value = njs_native_getter(njs_object_prototype_create), + }, +}; + + +const njs_object_init_t njs_ref_error_constructor_init = { + nxt_string("ReferenceError"), + njs_ref_error_constructor_properties, + nxt_nitems(njs_ref_error_constructor_properties), +}; + + +njs_ret_t +njs_syntax_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_error_create(vm, args, nargs, NJS_OBJECT_SYNTAX_ERROR); +} + + +static const njs_object_prop_t njs_syntax_error_constructor_properties[] = +{ + /* SyntaxError.name == "SyntaxError". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("SyntaxError"), + }, + + /* SyntaxError.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, + + /* SyntaxError.prototype. */ + { + .type = NJS_NATIVE_GETTER, + .name = njs_string("prototype"), + .value = njs_native_getter(njs_object_prototype_create), + }, +}; + + +const njs_object_init_t njs_syntax_error_constructor_init = { + nxt_string("SyntaxError"), + njs_syntax_error_constructor_properties, + nxt_nitems(njs_syntax_error_constructor_properties), +}; + + +njs_ret_t +njs_type_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_error_create(vm, args, nargs, NJS_OBJECT_TYPE_ERROR); +} + + +static const njs_object_prop_t njs_type_error_constructor_properties[] = +{ + /* TypeError.name == "TypeError". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("TypeError"), + }, + + /* TypeError.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, + + /* TypeError.prototype. */ + { + .type = NJS_NATIVE_GETTER, + .name = njs_string("prototype"), + .value = njs_native_getter(njs_object_prototype_create), + }, +}; + + +const njs_object_init_t njs_type_error_constructor_init = { + nxt_string("TypeError"), + njs_type_error_constructor_properties, + nxt_nitems(njs_type_error_constructor_properties), +}; + + +njs_ret_t +njs_uri_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_error_create(vm, args, nargs, NJS_OBJECT_URI_ERROR); +} + + +static const njs_object_prop_t njs_uri_error_constructor_properties[] = +{ + /* URIError.name == "URIError". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("URIError"), + }, + + /* URIError.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, + + /* URIError.prototype. */ + { + .type = NJS_NATIVE_GETTER, + .name = njs_string("prototype"), + .value = njs_native_getter(njs_object_prototype_create), + }, +}; + + +const njs_object_init_t njs_uri_error_constructor_init = { + nxt_string("URIError"), + njs_uri_error_constructor_properties, + nxt_nitems(njs_uri_error_constructor_properties), +}; + + +static void +njs_init_memory_error(njs_vm_t *vm) +{ + njs_value_t *value; + njs_object_t *object; + njs_object_prototype_t *prototypes; + + prototypes = vm->prototypes; + object = &vm->memory_error_object; + + nxt_lvlhsh_init(&object->hash); + nxt_lvlhsh_init(&object->shared_hash); + object->__proto__ = &prototypes[NJS_PROTOTYPE_MEMORY_ERROR].object; + object->type = NJS_OBJECT_INTERNAL_ERROR; + object->shared = 1; + + /* + * Marking it nonextensible to differentiate + * it from ordinary internal errors. + */ + object->extensible = 0; + + value = &vm->memory_error; + + value->data.type = NJS_OBJECT_INTERNAL_ERROR; + value->data.truth = 1; + value->data.u.number = NAN; + value->data.u.object = object; +} + + +void +njs_exception_memory_error(njs_vm_t *vm) +{ + njs_init_memory_error(vm); + + vm->exception = &vm->memory_error; +} + + +njs_ret_t +njs_memory_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + njs_init_memory_error(vm); + + vm->retval = vm->memory_error; + + return NXT_OK; +} + + +static const njs_object_prop_t njs_memory_error_constructor_properties[] = +{ + /* MemoryError.name == "MemoryError". */ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("MemoryError"), + }, + + /* MemoryError.length == 1. */ + { + .type = NJS_PROPERTY, + .name = njs_string("length"), + .value = njs_value(NJS_NUMBER, 1, 1.0), + }, + + /* MemoryError.prototype. */ + { + .type = NJS_NATIVE_GETTER, + .name = njs_string("prototype"), + .value = njs_native_getter(njs_object_prototype_create), + }, +}; + + +const njs_object_init_t njs_memory_error_constructor_init = { + nxt_string("MemoryError"), + njs_memory_error_constructor_properties, + nxt_nitems(njs_memory_error_constructor_properties), +}; + + +static njs_ret_t +njs_error_prototype_value_of(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + vm->retval = args[0]; + + return NXT_OK; +} + + +static njs_ret_t +njs_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + size_t size; + u_char *p; + nxt_str_t name, message; + const njs_value_t *name_value, *message_value; + njs_object_prop_t *prop; + nxt_lvlhsh_query_t lhq; + + static const njs_value_t default_name = njs_string("Error"); + + if (nargs < 1 || !njs_is_object(&args[0])) { + njs_exception_type_error(vm, NULL, NULL); + return NXT_ERROR; + } + + lhq.key_hash = NJS_NAME_HASH; + lhq.key = nxt_string_value("name"); + lhq.proto = &njs_object_hash_proto; + + prop = njs_object_property(vm, args[0].data.u.object, &lhq); + + if (prop != NULL) { + name_value = &prop->value; + + } else { + name_value = &default_name; + } + + njs_string_get(name_value, &name); + + lhq.key_hash = NJS_MESSAGE_HASH; + lhq.key = nxt_string_value("message"); + + prop = njs_object_property(vm, args[0].data.u.object, &lhq); + + if (prop != NULL) { + message_value = &prop->value; + + } else { + message_value = &njs_string_empty; + } + + njs_string_get(message_value, &message); + + if (name.length == 0) { + vm->retval = *message_value; + return NJS_OK; + } + + if (message.length == 0) { + vm->retval = *name_value; + return NJS_OK; + } + + size = name.length + message.length + 2; + + p = njs_string_alloc(vm, &vm->retval, size, size); + + if (nxt_fast_path(p != NULL)) { + p = nxt_cpymem(p, name.start, name.length); + *p++ = ':'; + *p++ = ' '; + memcpy(p, message.start, message.length); + + return NJS_OK; + } + + njs_exception_memory_error(vm); + return NJS_ERROR; +} + + +static const njs_object_prop_t njs_error_prototype_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("Error"), + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("message"), + .value = njs_string(""), + }, + + { + .type = NJS_METHOD, + .name = njs_string("valueOf"), + .value = njs_native_function(njs_error_prototype_value_of, 0, 0), + }, + + { + .type = NJS_METHOD, + .name = njs_string("toString"), + .value = njs_native_function(njs_error_prototype_to_string, 0, 0), + }, +}; + + +const njs_object_init_t njs_error_prototype_init = { + nxt_string("Error"), + njs_error_prototype_properties, + nxt_nitems(njs_error_prototype_properties), +}; + + +static const njs_object_prop_t njs_eval_error_prototype_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("EvalError"), + }, +}; + + +const njs_object_init_t njs_eval_error_prototype_init = { + nxt_string("EvalError"), + njs_eval_error_prototype_properties, + nxt_nitems(njs_eval_error_prototype_properties), +}; + + +static const njs_object_prop_t njs_internal_error_prototype_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("InternalError"), + }, +}; + + +const njs_object_init_t njs_internal_error_prototype_init = { + nxt_string("InternalError"), + njs_internal_error_prototype_properties, + nxt_nitems(njs_internal_error_prototype_properties), +}; + + +static const njs_object_prop_t njs_range_error_prototype_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("RangeError"), + }, +}; + + +const njs_object_init_t njs_range_error_prototype_init = { + nxt_string("RangeError"), + njs_range_error_prototype_properties, + nxt_nitems(njs_range_error_prototype_properties), +}; + + +static const njs_object_prop_t njs_ref_error_prototype_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("ReferenceError"), + }, +}; + + +const njs_object_init_t njs_ref_error_prototype_init = { + nxt_string("ReferenceError"), + njs_ref_error_prototype_properties, + nxt_nitems(njs_ref_error_prototype_properties), +}; + + +static const njs_object_prop_t njs_syntax_error_prototype_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("SyntaxError"), + }, +}; + + +const njs_object_init_t njs_syntax_error_prototype_init = { + nxt_string("SyntaxError"), + njs_syntax_error_prototype_properties, + nxt_nitems(njs_syntax_error_prototype_properties), +}; + + +static const njs_object_prop_t njs_type_error_prototype_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("TypeError"), + }, +}; + + +const njs_object_init_t njs_type_error_prototype_init = { + nxt_string("TypeError"), + njs_type_error_prototype_properties, + nxt_nitems(njs_type_error_prototype_properties), +}; + + +static const njs_object_prop_t njs_uri_error_prototype_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("URIError"), + }, +}; + + +const njs_object_init_t njs_uri_error_prototype_init = { + nxt_string("URIError"), + njs_uri_error_prototype_properties, + nxt_nitems(njs_uri_error_prototype_properties), +}; + + +static njs_ret_t +njs_memory_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + static const njs_value_t name = njs_string("MemoryError"); + + vm->retval = name; + + return NJS_OK; +} + + +static const njs_object_prop_t njs_memory_error_prototype_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("name"), + .value = njs_string("MemoryError"), + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("message"), + .value = njs_string(""), + }, + + { + .type = NJS_METHOD, + .name = njs_string("valueOf"), + .value = njs_native_function(njs_error_prototype_value_of, 0, 0), + }, + + { + .type = NJS_METHOD, + .name = njs_string("toString"), + .value = njs_native_function(njs_memory_error_prototype_to_string, + 0, 0), + }, +}; + + +const njs_object_init_t njs_memory_error_prototype_init = { + nxt_string("MemoryError"), + njs_memory_error_prototype_properties, + nxt_nitems(njs_memory_error_prototype_properties), +}; diff --git a/njs/njs_error.h b/njs/njs_error.h new file mode 100644 index 00000000..6179a8d6 --- /dev/null +++ b/njs/njs_error.h @@ -0,0 +1,77 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) NGINX, Inc. + */ + +#ifndef _NJS_ERROR_H_INCLUDED_ +#define _NJS_ERROR_H_INCLUDED_ + + +#define njs_exception_error(vm, fmt, ...) \ + njs_exception_error_create(vm, NJS_OBJECT_ERROR, fmt, __VA_ARGS__) +#define njs_exception_eval_error(vm, fmt, ...) \ + njs_exception_error_create(vm, NJS_OBJECT_EVAL_ERROR, fmt, __VA_ARGS__) +#define njs_exception_internal_error(vm, fmt, ...) \ + njs_exception_error_create(vm, NJS_OBJECT_INTERNAL_ERROR, fmt, __VA_ARGS__) +#define njs_exception_range_error(vm, fmt, ...) \ + njs_exception_error_create(vm, NJS_OBJECT_RANGE_ERROR, fmt, __VA_ARGS__) +#define njs_exception_ref_error(vm, fmt, ...) \ + njs_exception_error_create(vm, NJS_OBJECT_REF_ERROR, fmt, __VA_ARGS__) +#define njs_exception_syntax_error(vm, fmt, ...) \ + njs_exception_error_create(vm, NJS_OBJECT_SYNTAX_ERROR, fmt, __VA_ARGS__) +#define njs_exception_type_error(vm, fmt, ...) \ + njs_exception_error_create(vm, NJS_OBJECT_TYPE_ERROR, fmt, __VA_ARGS__) +#define njs_exception_uri_error(vm, fmt, ...) \ + njs_exception_error_create(vm, NJS_OBJECT_URI_ERROR, fmt, __VA_ARGS__) + +void njs_exception_error_create(njs_vm_t *vm, njs_value_type_t type, + const char* fmt, ...); + +void njs_exception_memory_error(njs_vm_t *vm); + +njs_object_t *njs_error_alloc(njs_vm_t *vm, njs_value_type_t type, + const njs_value_t *name, const njs_value_t *message); +njs_ret_t njs_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_eval_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_internal_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_range_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_ref_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_syntax_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_type_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_uri_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_memory_error_constructor(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); + + +extern const njs_object_init_t njs_error_constructor_init; +extern const njs_object_init_t njs_eval_error_constructor_init; +extern const njs_object_init_t njs_internal_error_constructor_init; +extern const njs_object_init_t njs_range_error_constructor_init; +extern const njs_object_init_t njs_ref_error_constructor_init; +extern const njs_object_init_t njs_syntax_error_constructor_init; +extern const njs_object_init_t njs_type_error_constructor_init; +extern const njs_object_init_t njs_uri_error_constructor_init; +extern const njs_object_init_t njs_memory_error_constructor_init; + + +extern const njs_object_init_t njs_error_prototype_init; +extern const njs_object_init_t njs_eval_error_prototype_init; +extern const njs_object_init_t njs_internal_error_prototype_init; +extern const njs_object_init_t njs_range_error_prototype_init; +extern const njs_object_init_t njs_ref_error_prototype_init; +extern const njs_object_init_t njs_syntax_error_prototype_init; +extern const njs_object_init_t njs_type_error_prototype_init; +extern const njs_object_init_t njs_uri_error_prototype_init; +extern const njs_object_init_t njs_memory_error_prototype_init; + + +#endif /* _NJS_BOOLEAN_H_INCLUDED_ */ diff --git a/njs/njs_function.c b/njs/njs_function.c index 4ccc9388..8a338295 100644 --- a/njs/njs_function.c +++ b/njs/njs_function.c @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -230,10 +231,6 @@ njs_function_frame(njs_vm_t *vm, njs_function_t *function, } -static const njs_value_t njs_exception_stack_size_exceeded = - njs_long_string("RangeError: Maximum call stack size exceeded"); - - nxt_noinline njs_native_frame_t * njs_function_frame_alloc(njs_vm_t *vm, size_t size) { @@ -251,7 +248,8 @@ njs_function_frame_alloc(njs_vm_t *vm, size_t size) spare_size = nxt_align_size(spare_size, NJS_FRAME_SPARE_SIZE); if (vm->stack_size + spare_size > NJS_MAX_STACK_SIZE) { - vm->exception = &njs_exception_stack_size_exceeded; + njs_exception_range_error(vm, "Maximum call stack size exceeded", + NULL); return NULL; } @@ -511,7 +509,7 @@ njs_function_prototype_call(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_function_t *function; if (!njs_is_function(&args[0])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -566,7 +564,7 @@ njs_function_prototype_apply(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, type_error: - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -624,7 +622,7 @@ njs_function_prototype_bind(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_function_t *function; if (!njs_is_function(&args[0])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } diff --git a/njs/njs_generator.c b/njs/njs_generator.c index 7219f567..0d98f3e0 100644 --- a/njs/njs_generator.c +++ b/njs/njs_generator.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -290,6 +291,15 @@ njs_generator(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node) case NJS_TOKEN_FUNCTION_CONSTRUCTOR: case NJS_TOKEN_REGEXP_CONSTRUCTOR: case NJS_TOKEN_DATE_CONSTRUCTOR: + case NJS_TOKEN_ERROR_CONSTRUCTOR: + case NJS_TOKEN_EVAL_ERROR_CONSTRUCTOR: + case NJS_TOKEN_INTERNAL_ERROR_CONSTRUCTOR: + case NJS_TOKEN_RANGE_ERROR_CONSTRUCTOR: + case NJS_TOKEN_REF_ERROR_CONSTRUCTOR: + case NJS_TOKEN_SYNTAX_ERROR_CONSTRUCTOR: + case NJS_TOKEN_TYPE_ERROR_CONSTRUCTOR: + case NJS_TOKEN_URI_ERROR_CONSTRUCTOR: + case NJS_TOKEN_MEMORY_ERROR_CONSTRUCTOR: case NJS_TOKEN_EXTERNAL: return NXT_OK; @@ -331,7 +341,7 @@ njs_generator(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node) default: nxt_thread_log_debug("unknown token: %d", node->token); - vm->exception = &njs_exception_syntax_error; + njs_exception_syntax_error(vm, "unknown token", NULL); return NXT_ERROR; } @@ -2071,7 +2081,7 @@ njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node) parser->code_size, code_size); if (nxt_slow_path(parser->code_size < code_size)) { - vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(vm, NULL, NULL); return NXT_ERROR; } diff --git a/njs/njs_json.c b/njs/njs_json.c index e07bc18a..636ab838 100644 --- a/njs/njs_json.c +++ b/njs/njs_json.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -147,8 +148,6 @@ static njs_json_state_t *njs_json_push_stringify_state(njs_vm_t *vm, njs_json_stringify_t *stringify, njs_value_t *value); static njs_json_state_t *njs_json_pop_stringify_state( njs_json_stringify_t *stringify); -static void njs_json_stringify_exception(njs_json_stringify_t *stringify, - const char* msg); static nxt_int_t njs_json_append_value(njs_json_stringify_t *stringify, njs_value_t *value); @@ -188,7 +187,7 @@ njs_json_parse(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t)); if (nxt_slow_path(value == NULL)) { - vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(vm); return NXT_ERROR; } @@ -256,7 +255,8 @@ njs_json_parse(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, memory_error: - vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(vm); + return NXT_ERROR; } @@ -342,7 +342,8 @@ njs_json_stringify(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, memory_error: - vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(vm); + return NXT_ERROR; } @@ -486,7 +487,7 @@ njs_json_parse_object(njs_json_parse_ctx_t *ctx, njs_value_t *value, u_char *p) ret = nxt_lvlhsh_insert(&object->hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - ctx->vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(ctx->vm, NULL, NULL); return NULL; } @@ -526,7 +527,7 @@ error_end: memory_error: - ctx->vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(ctx->vm); return NULL; } @@ -546,7 +547,7 @@ njs_json_parse_array(njs_json_parse_ctx_t *ctx, njs_value_t *value, u_char *p) array = njs_array_alloc(ctx->vm, 0, 0); if (nxt_slow_path(array == NULL)) { - ctx->vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(ctx->vm); return NULL; } @@ -569,7 +570,7 @@ njs_json_parse_array(njs_json_parse_ctx_t *ctx, njs_value_t *value, u_char *p) element = nxt_mem_cache_alloc(ctx->pool, sizeof(njs_value_t)); if (nxt_slow_path(element == NULL)) { - ctx->vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(ctx->vm); return NULL; } @@ -580,7 +581,7 @@ njs_json_parse_array(njs_json_parse_ctx_t *ctx, njs_value_t *value, u_char *p) ret = njs_array_add(ctx->vm, array, element); if (nxt_slow_path(ret != NXT_OK)) { - ctx->vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(ctx->vm, NULL, NULL); return NULL; } @@ -735,7 +736,7 @@ njs_json_parse_string(njs_json_parse_ctx_t *ctx, njs_value_t *value, u_char *p) start = nxt_mem_cache_alloc(ctx->pool, size); if (nxt_slow_path(start == NULL)) { - ctx->vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(ctx->vm);; return NULL; } @@ -820,7 +821,7 @@ njs_json_parse_string(njs_json_parse_ctx_t *ctx, njs_value_t *value, u_char *p) ret = njs_string_create(ctx->vm, value, start, size, length); if (nxt_slow_path(ret != NXT_OK)) { - ctx->vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(ctx->vm); return NULL; } @@ -991,7 +992,7 @@ njs_json_parse_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, } if (nxt_slow_path(ret != NXT_OK)) { - vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1029,14 +1030,14 @@ njs_json_parse_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, break; default: - vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(vm, NULL, NULL); return NXT_ERROR; } } memory_error: - vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(vm); return NXT_ERROR; } @@ -1071,7 +1072,7 @@ njs_json_parse_continuation_apply(njs_vm_t *vm, njs_json_parse_t *parse) break; default: - vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1131,34 +1132,14 @@ static void njs_json_parse_exception(njs_json_parse_ctx_t *ctx, const char* msg, u_char *pos) { - size_t size; - ssize_t length; - njs_ret_t ret; - njs_value_t *exception; - - static u_char buf[256]; - - exception = nxt_mem_cache_alloc(ctx->pool, sizeof(njs_value_t)); - if (nxt_slow_path(exception == NULL)) { - ctx->vm->exception = &njs_exception_memory_error; - return; - } + ssize_t length; length = nxt_utf8_length(ctx->start, pos - ctx->start); if (nxt_slow_path(length < 0)) { length = 0; } - size = snprintf((char *) buf, sizeof(buf), - "SyntaxError: %s at position %zu", msg, length); - - ret = njs_string_new(ctx->vm, exception, buf, size, size); - if (nxt_slow_path(ret != NXT_OK)) { - ctx->vm->exception = &njs_exception_memory_error; - return; - } - - ctx->vm->exception = exception; + njs_exception_syntax_error(ctx->vm, "%s at position %zu", msg, length); } @@ -1450,7 +1431,8 @@ done: memory_error: - vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(vm); + return NXT_ERROR; } @@ -1513,7 +1495,7 @@ njs_json_stringify_to_json(njs_vm_t *vm, njs_json_stringify_t* stringify, break; default: - vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1557,7 +1539,7 @@ njs_json_stringify_replacer(njs_vm_t *vm, njs_json_stringify_t* stringify, break; default: - vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1651,15 +1633,15 @@ njs_json_push_stringify_state(njs_vm_t *vm, njs_json_stringify_t *stringify, njs_json_state_t *state; if (stringify->stack.items >= 32) { - njs_json_stringify_exception(stringify, - "Nested too deep or a cyclic structure"); + njs_exception_type_error(stringify->vm, + "Nested too deep or a cyclic structure", NULL); return NULL; } state = nxt_array_add(&stringify->stack, &njs_array_mem_proto, vm->mem_cache_pool); if (nxt_slow_path(state == NULL)) { - vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(vm); return NULL; } @@ -1705,33 +1687,6 @@ njs_json_pop_stringify_state(njs_json_stringify_t *stringify) } -static void -njs_json_stringify_exception(njs_json_stringify_t *stringify, const char* msg) -{ - size_t size; - njs_ret_t ret; - njs_value_t *exception; - - static u_char buf[256]; - - exception = nxt_mem_cache_alloc(stringify->pool, sizeof(njs_value_t)); - if (nxt_slow_path(exception == NULL)) { - stringify->vm->exception = &njs_exception_memory_error; - return; - } - - size = snprintf((char *) buf, sizeof(buf), "TypeError: %s", msg); - - ret = njs_string_new(stringify->vm, exception, buf, size, size); - if (nxt_slow_path(ret != NXT_OK)) { - stringify->vm->exception = &njs_exception_memory_error; - return; - } - - stringify->vm->exception = exception; -} - - static nxt_int_t njs_json_append_value(njs_json_stringify_t *stringify, njs_value_t *value) { @@ -1768,7 +1723,8 @@ njs_json_append_value(njs_json_stringify_t *stringify, njs_value_t *value) return njs_json_buf_append(stringify, "null", 4); default: - njs_json_stringify_exception(stringify, "Non-serializable object"); + njs_exception_type_error(stringify->vm, "Non-serializable object", + NULL); return NXT_DECLINED; } } diff --git a/njs/njs_lexer_keyword.c b/njs/njs_lexer_keyword.c index 9bba043a..3cd84763 100644 --- a/njs/njs_lexer_keyword.c +++ b/njs/njs_lexer_keyword.c @@ -81,6 +81,15 @@ static const njs_keyword_t njs_keywords[] = { { nxt_string("Function"), NJS_TOKEN_FUNCTION_CONSTRUCTOR, 0 }, { nxt_string("RegExp"), NJS_TOKEN_REGEXP_CONSTRUCTOR, 0 }, { nxt_string("Date"), NJS_TOKEN_DATE_CONSTRUCTOR, 0 }, + { nxt_string("Error"), NJS_TOKEN_ERROR_CONSTRUCTOR, 0 }, + { nxt_string("EvalError"), NJS_TOKEN_EVAL_ERROR_CONSTRUCTOR, 0 }, + { nxt_string("InternalError"), NJS_TOKEN_INTERNAL_ERROR_CONSTRUCTOR, 0 }, + { nxt_string("RangeError"), NJS_TOKEN_RANGE_ERROR_CONSTRUCTOR, 0 }, + { nxt_string("ReferenceError"), NJS_TOKEN_REF_ERROR_CONSTRUCTOR, 0 }, + { nxt_string("SyntaxError"), NJS_TOKEN_SYNTAX_ERROR_CONSTRUCTOR, 0 }, + { nxt_string("TypeError"), NJS_TOKEN_TYPE_ERROR_CONSTRUCTOR, 0 }, + { nxt_string("URIError"), NJS_TOKEN_URI_ERROR_CONSTRUCTOR, 0 }, + { nxt_string("MemoryError"), NJS_TOKEN_MEMORY_ERROR_CONSTRUCTOR, 0 }, { nxt_string("eval"), NJS_TOKEN_EVAL, 0 }, { nxt_string("toString"), NJS_TOKEN_TO_STRING, 0 }, diff --git a/njs/njs_number.c b/njs/njs_number.c index bd731699..15059a9e 100644 --- a/njs/njs_number.c +++ b/njs/njs_number.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -557,7 +558,7 @@ njs_number_prototype_value_of(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, value = &value->data.u.object_value->value; } else { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } } @@ -583,7 +584,7 @@ njs_number_prototype_to_string(njs_vm_t *vm, njs_value_t *args, value = &value->data.u.object_value->value; } else { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } } @@ -592,7 +593,7 @@ njs_number_prototype_to_string(njs_vm_t *vm, njs_value_t *args, radix = args[1].data.u.number; if (radix < 2 || radix > 36 || radix != (int) radix) { - vm->exception = &njs_exception_range_error; + njs_exception_range_error(vm, NULL, NULL); return NXT_ERROR; } diff --git a/njs/njs_object.c b/njs/njs_object.c index bb6e84c2..6e962e1e 100644 --- a/njs/njs_object.c +++ b/njs/njs_object.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -223,7 +224,7 @@ njs_object_property(njs_vm_t *vm, njs_object_t *object, nxt_lvlhsh_query_t *lhq) } while (object != NULL); - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NULL; } @@ -263,7 +264,7 @@ njs_object_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, type = njs_object_value_type(value->type); } else { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -311,7 +312,7 @@ njs_object_create(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, } } - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -324,13 +325,13 @@ njs_object_keys(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_array_t *keys; if (nargs < 2 || !njs_is_object(&args[1])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } keys = njs_object_keys_array(vm, &args[1]); if (keys == NULL) { - vm->exception = &njs_exception_memory_error; + njs_exception_memory_error(vm); return NXT_ERROR; } @@ -428,12 +429,12 @@ njs_object_define_property(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, nxt_int_t ret; if (nargs < 4 || !njs_is_object(&args[1]) || !njs_is_object(&args[3])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } if (!args[1].data.u.object->extensible) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -461,12 +462,12 @@ njs_object_define_properties(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_object_prop_t *prop; if (nargs < 3 || !njs_is_object(&args[1]) || !njs_is_object(&args[2])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } if (!args[1].data.u.object->extensible) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -596,7 +597,7 @@ njs_object_get_own_property_descriptor(njs_vm_t *vm, njs_value_t *args, nxt_lvlhsh_query_t lhq; if (nargs < 3 || !njs_is_object(&args[1])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -725,7 +726,7 @@ njs_object_get_prototype_of(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, return NXT_OK; } - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -740,7 +741,7 @@ njs_object_freeze(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, nxt_lvlhsh_each_t lhe; if (nargs < 2 || !njs_is_object(&args[1])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -779,7 +780,7 @@ njs_object_is_frozen(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, const njs_value_t *retval; if (nargs < 2 || !njs_is_object(&args[1])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -826,7 +827,7 @@ njs_object_seal(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, nxt_lvlhsh_each_t lhe; if (nargs < 2 || !njs_is_object(&args[1])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -864,7 +865,7 @@ njs_object_is_sealed(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, const njs_value_t *retval; if (nargs < 2 || !njs_is_object(&args[1])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -906,7 +907,7 @@ njs_object_prevent_extensions(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { if (nargs < 2 || !njs_is_object(&args[1])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -925,7 +926,7 @@ njs_object_is_extensible(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, const njs_value_t *retval; if (nargs < 2 || !njs_is_object(&args[1])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1037,7 +1038,7 @@ njs_property_prototype_create(njs_vm_t *vm, nxt_lvlhsh_t *hash, } /* Memory allocation or NXT_DECLINED error. */ - vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(vm, NULL, NULL); return NULL; } @@ -1278,7 +1279,7 @@ njs_property_constructor_create(njs_vm_t *vm, nxt_lvlhsh_t *hash, } /* Memory allocation or NXT_DECLINED error. */ - vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(vm, NULL, NULL); return NULL; } @@ -1312,6 +1313,22 @@ static const njs_value_t njs_object_function_string = static const njs_value_t njs_object_regexp_string = njs_long_string("[object RegExp]"); static const njs_value_t njs_object_date_string = njs_string("[object Date]"); +static const njs_value_t njs_object_error_string = + njs_string("[object Error]"); +static const njs_value_t njs_object_eval_error_string = + njs_long_string("[object EvalError]"); +static const njs_value_t njs_object_internal_error_string = + njs_long_string("[object InternalError]"); +static const njs_value_t njs_object_range_error_string = + njs_long_string("[object RangeError]"); +static const njs_value_t njs_object_ref_error_string = + njs_long_string("[object RefError]"); +static const njs_value_t njs_object_syntax_error_string = + njs_long_string("[object SyntaxError]"); +static const njs_value_t njs_object_type_error_string = + njs_long_string("[object TypeError]"); +static const njs_value_t njs_object_uri_error_string = + njs_long_string("[object URIError]"); njs_ret_t @@ -1333,6 +1350,14 @@ njs_object_prototype_to_string(njs_vm_t *vm, njs_value_t *args, &njs_string_empty, &njs_object_function_string, &njs_string_empty, + &njs_string_empty, + &njs_string_empty, + &njs_string_empty, + &njs_string_empty, + &njs_string_empty, + &njs_string_empty, + &njs_string_empty, + &njs_string_empty, /* Objects. */ &njs_object_object_string, @@ -1343,6 +1368,14 @@ njs_object_prototype_to_string(njs_vm_t *vm, njs_value_t *args, &njs_object_function_string, &njs_object_regexp_string, &njs_object_date_string, + &njs_object_error_string, + &njs_object_eval_error_string, + &njs_object_internal_error_string, + &njs_object_range_error_string, + &njs_object_ref_error_string, + &njs_object_syntax_error_string, + &njs_object_type_error_string, + &njs_object_uri_error_string, }; index = args[0].type; diff --git a/njs/njs_object_hash.h b/njs/njs_object_hash.h index ba8f6c9b..eb8ec083 100644 --- a/njs/njs_object_hash.h +++ b/njs/njs_object_hash.h @@ -79,6 +79,25 @@ 'j'), 'o'), 'i'), 'n') +#define NJS_NAME_HASH \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add(NXT_DJB_HASH_INIT, \ + 'n'), 'a'), 'm'), 'e') + + +#define NJS_MESSAGE_HASH \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add(NXT_DJB_HASH_INIT, \ + 'm'), 'e'), 's'), 's'), 'a'), 'g'), 'e') + + #define NJS_PROTOTYPE_HASH \ nxt_djb_hash_add( \ nxt_djb_hash_add( \ diff --git a/njs/njs_parser.c b/njs/njs_parser.c index 4b99dd80..2134dc68 100644 --- a/njs/njs_parser.c +++ b/njs/njs_parser.c @@ -2024,6 +2024,42 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) node->index = NJS_INDEX_DATE; break; + case NJS_TOKEN_ERROR_CONSTRUCTOR: + node->index = NJS_INDEX_OBJECT_ERROR; + break; + + case NJS_TOKEN_EVAL_ERROR_CONSTRUCTOR: + node->index = NJS_INDEX_OBJECT_EVAL_ERROR; + break; + + case NJS_TOKEN_INTERNAL_ERROR_CONSTRUCTOR: + node->index = NJS_INDEX_OBJECT_INTERNAL_ERROR; + break; + + case NJS_TOKEN_RANGE_ERROR_CONSTRUCTOR: + node->index = NJS_INDEX_OBJECT_RANGE_ERROR; + break; + + case NJS_TOKEN_REF_ERROR_CONSTRUCTOR: + node->index = NJS_INDEX_OBJECT_REF_ERROR; + break; + + case NJS_TOKEN_SYNTAX_ERROR_CONSTRUCTOR: + node->index = NJS_INDEX_OBJECT_SYNTAX_ERROR; + break; + + case NJS_TOKEN_TYPE_ERROR_CONSTRUCTOR: + node->index = NJS_INDEX_OBJECT_TYPE_ERROR; + break; + + case NJS_TOKEN_URI_ERROR_CONSTRUCTOR: + node->index = NJS_INDEX_OBJECT_URI_ERROR; + break; + + case NJS_TOKEN_MEMORY_ERROR_CONSTRUCTOR: + node->index = NJS_INDEX_OBJECT_MEMORY_ERROR; + break; + case NJS_TOKEN_EVAL: case NJS_TOKEN_TO_STRING: case NJS_TOKEN_IS_NAN: diff --git a/njs/njs_parser.h b/njs/njs_parser.h index f39fa419..c0990a52 100644 --- a/njs/njs_parser.h +++ b/njs/njs_parser.h @@ -176,6 +176,15 @@ typedef enum { NJS_TOKEN_FUNCTION_CONSTRUCTOR, NJS_TOKEN_REGEXP_CONSTRUCTOR, NJS_TOKEN_DATE_CONSTRUCTOR, + NJS_TOKEN_ERROR_CONSTRUCTOR, + NJS_TOKEN_EVAL_ERROR_CONSTRUCTOR, + NJS_TOKEN_INTERNAL_ERROR_CONSTRUCTOR, + NJS_TOKEN_RANGE_ERROR_CONSTRUCTOR, + NJS_TOKEN_REF_ERROR_CONSTRUCTOR, + NJS_TOKEN_SYNTAX_ERROR_CONSTRUCTOR, + NJS_TOKEN_TYPE_ERROR_CONSTRUCTOR, + NJS_TOKEN_URI_ERROR_CONSTRUCTOR, + NJS_TOKEN_MEMORY_ERROR_CONSTRUCTOR, #define NJS_TOKEN_FIRST_FUNCTION NJS_TOKEN_EVAL diff --git a/njs/njs_regexp.c b/njs/njs_regexp.c index c64a449c..770d3693 100644 --- a/njs/njs_regexp.c +++ b/njs/njs_regexp.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -342,7 +343,7 @@ njs_regexp_pattern_create(njs_vm_t *vm, u_char *start, size_t length, if (nxt_fast_path(ret >= 0)) { if (nxt_slow_path((u_int) ret != pattern->ncaptures)) { - vm->exception = &njs_exception_internal_error; + njs_exception_internal_error(vm, NULL, NULL); nxt_mem_cache_free(vm->mem_cache_pool, pattern); return NULL; } @@ -578,7 +579,7 @@ njs_regexp_prototype_to_string(njs_vm_t *vm, njs_value_t *args, return njs_regexp_string_create(vm, &vm->retval, source, size, length); } - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -596,7 +597,7 @@ njs_regexp_prototype_test(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_regexp_pattern_t *pattern; if (!njs_is_regexp(&args[0])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -646,7 +647,7 @@ njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, nxt_regex_match_data_t *match_data; if (!njs_is_regexp(&args[0])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } diff --git a/njs/njs_string.c b/njs/njs_string.c index 040c3887..91573738 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -551,7 +552,7 @@ njs_string_prototype_value_of(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, value = &value->data.u.object_value->value; } else { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } } @@ -576,7 +577,7 @@ njs_string_prototype_concat(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_string_prop_t string; if (njs_is_null_or_void(&args[0])) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1166,7 +1167,7 @@ njs_string_from_char_code(njs_vm_t *vm, njs_value_t *args, range_error: - vm->exception = &njs_exception_range_error; + njs_exception_range_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1833,7 +1834,7 @@ njs_string_prototype_repeat(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, n = args[1].data.u.number; if (nxt_slow_path(n < 0 || n >= max)) { - vm->exception = &njs_exception_range_error; + njs_exception_range_error(vm, NULL, NULL); return NXT_ERROR; } } @@ -2537,7 +2538,7 @@ njs_string_replace_regexp_continuation(njs_vm_t *vm, njs_value_t *args, nxt_regex_match_data_free(r->match_data, vm->regex_context); - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -2649,7 +2650,7 @@ njs_string_replace_search_continuation(njs_vm_t *vm, njs_value_t *args, return njs_string_replace_join(vm, r); } - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -3600,7 +3601,7 @@ njs_string_decode(njs_vm_t *vm, njs_value_t *value, const uint32_t *reserve) uri_error: - vm->exception = &njs_exception_uri_error; + njs_exception_uri_error(vm, NULL, NULL); return NXT_ERROR; } diff --git a/njs/njs_vm.c b/njs/njs_vm.c index 7bc45db0..5fee478d 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -144,13 +145,7 @@ const njs_value_t njs_string_string = njs_string("string"); const njs_value_t njs_string_object = njs_string("object"); const njs_value_t njs_string_function = njs_string("function"); -const njs_value_t njs_exception_syntax_error = njs_string("SyntaxError"); -const njs_value_t njs_exception_reference_error = njs_string("ReferenceError"); -const njs_value_t njs_exception_type_error = njs_string("TypeError"); -const njs_value_t njs_exception_range_error = njs_string("RangeError"); -const njs_value_t njs_exception_uri_error = njs_string("URIError"); -const njs_value_t njs_exception_memory_error = njs_string("MemoryError"); -const njs_value_t njs_exception_internal_error = njs_string("InternalError"); +const njs_value_t njs_string_memory_error = njs_string("MemoryError"); /* @@ -679,7 +674,7 @@ njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object, njs_vmcode_prop_set_t *code; if (njs_is_primitive(object)) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -799,7 +794,7 @@ njs_vmcode_property_in(njs_vm_t *vm, njs_value_t *object, njs_value_t *property) case NJS_PRIMITIVE_VALUE: case NJS_STRING_VALUE: - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; @@ -1013,6 +1008,14 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object, case NJS_OBJECT_STRING: case NJS_REGEXP: case NJS_DATE: + case NJS_OBJECT_ERROR: + case NJS_OBJECT_EVAL_ERROR: + case NJS_OBJECT_INTERNAL_ERROR: + case NJS_OBJECT_RANGE_ERROR: + case NJS_OBJECT_REF_ERROR: + case NJS_OBJECT_SYNTAX_ERROR: + case NJS_OBJECT_TYPE_ERROR: + case NJS_OBJECT_URI_ERROR: obj = object->data.u.object; break; @@ -1036,7 +1039,7 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object, break; default: /* NJS_VOID, NJS_NULL. */ - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1319,7 +1322,7 @@ njs_vmcode_instance_of(njs_vm_t *vm, njs_value_t *object, nxt_lvlhsh_query_t lhq; if (!njs_is_function(constructor)) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -1476,6 +1479,14 @@ njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld) &njs_string_void, &njs_string_void, &njs_string_void, + &njs_string_void, + &njs_string_void, + &njs_string_void, + &njs_string_void, + &njs_string_void, + &njs_string_void, + &njs_string_void, + &njs_string_void, &njs_string_object, &njs_string_object, @@ -1485,6 +1496,14 @@ njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld) &njs_string_function, &njs_string_object, &njs_string_object, + &njs_string_object, + &njs_string_object, + &njs_string_object, + &njs_string_object, + &njs_string_object, + &njs_string_object, + &njs_string_object, + &njs_string_object, }; /* A zero index means non-declared variable. */ @@ -2226,7 +2245,7 @@ njs_function_frame_create(njs_vm_t *vm, njs_value_t *value, } } - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -2334,7 +2353,7 @@ njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object, njs_value_t *name) type_error: - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -2555,7 +2574,7 @@ trap: type_error: - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); return NXT_ERROR; } @@ -3154,7 +3173,7 @@ njs_primitive_value(njs_vm_t *vm, njs_value_t *value, nxt_uint_t hint) if (!njs_is_primitive(retval)) { for ( ;; ) { - vm->exception = &njs_exception_type_error; + njs_exception_type_error(vm, NULL, NULL); ret = NXT_ERROR; if (njs_is_object(value) && vm->top_frame->trap_tries < 2) { @@ -3260,6 +3279,14 @@ njs_value_to_ext_string(njs_vm_t *vm, nxt_str_t *dst, const njs_value_t *src) if (nxt_fast_path(src != NULL)) { + if (nxt_slow_path(src->type == NJS_OBJECT_INTERNAL_ERROR)) { + + /* MemoryError is a nonextensible internal error. */ + if (!src->data.u.object->extensible) { + src = &njs_string_memory_error; + } + } + value = *src; if (nxt_slow_path(!njs_is_primitive(&value))) { diff --git a/njs/njs_vm.h b/njs/njs_vm.h index 79a6f122..1fcd18c1 100644 --- a/njs/njs_vm.h +++ b/njs/njs_vm.h @@ -54,16 +54,16 @@ */ typedef enum { - NJS_NULL = 0x00, - NJS_VOID = 0x01, + NJS_NULL = 0x00, + NJS_VOID = 0x01, /* The order of the above type is used in njs_is_null_or_void(). */ - NJS_BOOLEAN = 0x02, + NJS_BOOLEAN = 0x02, /* * The order of the above type is used in njs_is_null_or_void_or_boolean(). */ - NJS_NUMBER = 0x03, + NJS_NUMBER = 0x03, /* * The order of the above type is used in njs_is_numeric(). * Booleans, null and void values can be used in mathematical operations: @@ -71,14 +71,14 @@ typedef enum { * a numeric value of the null and false values is zero, * a numeric value of the void value is NaN. */ - NJS_STRING = 0x04, + NJS_STRING = 0x04, /* The order of the above type is used in njs_is_primitive(). */ - /* Reserved 0x05, */ + /* Reserved 0x05, */ /* The type is external code. */ - NJS_EXTERNAL = 0x06, + NJS_EXTERNAL = 0x06, /* * The invalid value type is used: @@ -86,23 +86,31 @@ typedef enum { * to detect non-declared explicitly or implicitly variables, * for native property getters. */ - NJS_INVALID = 0x07, + NJS_INVALID = 0x07, /* - * The object types have the third bit set. It is used in njs_is_object(). + * The object types have the fourth bit set. It is used in njs_is_object(). * NJS_OBJECT_BOOLEAN, NJS_OBJECT_NUMBER, and NJS_OBJECT_STRING must be * in the same order as NJS_BOOLEAN, NJS_NUMBER, and NJS_STRING. It is * used in njs_primitive_prototype_index(). The order of object types * is used in vm->prototypes and vm->constructors arrays. */ - NJS_OBJECT = 0x08, - NJS_ARRAY = 0x09, - NJS_OBJECT_BOOLEAN = 0x0a, - NJS_OBJECT_NUMBER = 0x0b, - NJS_OBJECT_STRING = 0x0c, - NJS_FUNCTION = 0x0d, - NJS_REGEXP = 0x0e, - NJS_DATE = 0x0f, + NJS_OBJECT = 0x10, + NJS_ARRAY = 0x11, + NJS_OBJECT_BOOLEAN = 0x12, + NJS_OBJECT_NUMBER = 0x13, + NJS_OBJECT_STRING = 0x14, + NJS_FUNCTION = 0x15, + NJS_REGEXP = 0x16, + NJS_DATE = 0x17, + NJS_OBJECT_ERROR = 0x18, + NJS_OBJECT_EVAL_ERROR = 0x19, + NJS_OBJECT_INTERNAL_ERROR = 0x1a, + NJS_OBJECT_RANGE_ERROR = 0x1b, + NJS_OBJECT_REF_ERROR = 0x1c, + NJS_OBJECT_SYNTAX_ERROR = 0x1d, + NJS_OBJECT_TYPE_ERROR = 0x1e, + NJS_OBJECT_URI_ERROR = 0x1f, } njs_value_type_t; @@ -145,7 +153,7 @@ union njs_value_s { * the maximum size of short string to 13. */ struct { - njs_value_type_t type:8; /* 4 bits */ + njs_value_type_t type:8; /* 5 bits */ /* * The truth field is set during value assignment and then can be * quickly tested by logical and conditional operations regardless @@ -181,7 +189,7 @@ union njs_value_s { } data; struct { - njs_value_type_t type:8; /* 4 bits */ + njs_value_type_t type:8; /* 5 bits */ #define NJS_STRING_SHORT 14 #define NJS_STRING_LONG 15 @@ -192,7 +200,7 @@ union njs_value_s { u_char start[NJS_STRING_SHORT]; } short_string; - njs_value_type_t type:8; /* 4 bits */ + njs_value_type_t type:8; /* 5 bits */ }; @@ -402,6 +410,10 @@ typedef njs_ret_t (*njs_vmcode_operation_t)(njs_vm_t *vm, njs_value_t *value1, #define njs_is_string(value) \ ((value)->type == NJS_STRING) +#define njs_is_error(value) \ + ((value)->type >= NJS_OBJECT_ERROR \ + && (value)->type <= NJS_OBJECT_URI_ERROR) + /* * The truth field coincides with short_string.size and short_string.length @@ -760,7 +772,6 @@ typedef enum { #define njs_is_callee_argument_index(index) \ (((index) & NJS_SCOPE_CALLEE_ARGUMENTS) == NJS_SCOPE_CALLEE_ARGUMENTS) - enum njs_prototypes_e { NJS_PROTOTYPE_OBJECT = 0, NJS_PROTOTYPE_ARRAY, @@ -770,27 +781,50 @@ enum njs_prototypes_e { NJS_PROTOTYPE_FUNCTION, NJS_PROTOTYPE_REGEXP, NJS_PROTOTYPE_DATE, -#define NJS_PROTOTYPE_MAX (NJS_PROTOTYPE_DATE + 1) + NJS_PROTOTYPE_ERROR, + NJS_PROTOTYPE_EVAL_ERROR, + NJS_PROTOTYPE_INTERNAL_ERROR, + NJS_PROTOTYPE_RANGE_ERROR, + NJS_PROTOTYPE_REF_ERROR, + NJS_PROTOTYPE_SYNTAX_ERROR, + NJS_PROTOTYPE_TYPE_ERROR, + NJS_PROTOTYPE_URI_ERROR, + NJS_PROTOTYPE_MEMORY_ERROR, +#define NJS_PROTOTYPE_MAX (NJS_PROTOTYPE_MEMORY_ERROR + 1) }; #define njs_primitive_prototype_index(type) \ (NJS_PROTOTYPE_BOOLEAN + ((type) - NJS_BOOLEAN)) + +#define njs_error_prototype_index(type) \ + (NJS_PROTOTYPE_ERROR + ((type) - NJS_OBJECT_ERROR)) + + #define njs_prototype_type(index) \ (index + NJS_OBJECT) enum njs_constructor_e { - NJS_CONSTRUCTOR_OBJECT = NJS_PROTOTYPE_OBJECT, - NJS_CONSTRUCTOR_ARRAY = NJS_PROTOTYPE_ARRAY, - NJS_CONSTRUCTOR_BOOLEAN = NJS_PROTOTYPE_BOOLEAN, - NJS_CONSTRUCTOR_NUMBER = NJS_PROTOTYPE_NUMBER, - NJS_CONSTRUCTOR_STRING = NJS_PROTOTYPE_STRING, - NJS_CONSTRUCTOR_FUNCTION = NJS_PROTOTYPE_FUNCTION, - NJS_CONSTRUCTOR_REGEXP = NJS_PROTOTYPE_REGEXP, - NJS_CONSTRUCTOR_DATE = NJS_PROTOTYPE_DATE, -#define NJS_CONSTRUCTOR_MAX (NJS_CONSTRUCTOR_DATE + 1) + NJS_CONSTRUCTOR_OBJECT = NJS_PROTOTYPE_OBJECT, + NJS_CONSTRUCTOR_ARRAY = NJS_PROTOTYPE_ARRAY, + NJS_CONSTRUCTOR_BOOLEAN = NJS_PROTOTYPE_BOOLEAN, + NJS_CONSTRUCTOR_NUMBER = NJS_PROTOTYPE_NUMBER, + NJS_CONSTRUCTOR_STRING = NJS_PROTOTYPE_STRING, + NJS_CONSTRUCTOR_FUNCTION = NJS_PROTOTYPE_FUNCTION, + NJS_CONSTRUCTOR_REGEXP = NJS_PROTOTYPE_REGEXP, + NJS_CONSTRUCTOR_DATE = NJS_PROTOTYPE_DATE, + NJS_CONSTRUCTOR_ERROR = NJS_PROTOTYPE_ERROR, + NJS_CONSTRUCTOR_EVAL_ERROR = NJS_PROTOTYPE_EVAL_ERROR, + NJS_CONSTRUCTOR_INTERNAL_ERROR = NJS_PROTOTYPE_INTERNAL_ERROR, + NJS_CONSTRUCTOR_RANGE_ERROR = NJS_PROTOTYPE_RANGE_ERROR, + NJS_CONSTRUCTOR_REF_ERROR = NJS_PROTOTYPE_REF_ERROR, + NJS_CONSTRUCTOR_SYNTAX_ERROR = NJS_PROTOTYPE_SYNTAX_ERROR, + NJS_CONSTRUCTOR_TYPE_ERROR = NJS_PROTOTYPE_TYPE_ERROR, + NJS_CONSTRUCTOR_URI_ERROR = NJS_PROTOTYPE_URI_ERROR, + NJS_CONSTRUCTOR_MEMORY_ERROR = NJS_PROTOTYPE_MEMORY_ERROR, +#define NJS_CONSTRUCTOR_MAX (NJS_CONSTRUCTOR_MEMORY_ERROR + 1) }; @@ -833,6 +867,23 @@ enum njs_function_e { njs_global_scope_index(NJS_CONSTRUCTOR_FUNCTION) #define NJS_INDEX_REGEXP njs_global_scope_index(NJS_CONSTRUCTOR_REGEXP) #define NJS_INDEX_DATE njs_global_scope_index(NJS_CONSTRUCTOR_DATE) +#define NJS_INDEX_OBJECT_ERROR njs_global_scope_index(NJS_CONSTRUCTOR_ERROR) +#define NJS_INDEX_OBJECT_EVAL_ERROR \ + njs_global_scope_index(NJS_CONSTRUCTOR_EVAL_ERROR) +#define NJS_INDEX_OBJECT_INTERNAL_ERROR \ + njs_global_scope_index(NJS_CONSTRUCTOR_INTERNAL_ERROR) +#define NJS_INDEX_OBJECT_RANGE_ERROR \ + njs_global_scope_index(NJS_CONSTRUCTOR_RANGE_ERROR) +#define NJS_INDEX_OBJECT_REF_ERROR \ + njs_global_scope_index(NJS_CONSTRUCTOR_REF_ERROR) +#define NJS_INDEX_OBJECT_SYNTAX_ERROR \ + njs_global_scope_index(NJS_CONSTRUCTOR_SYNTAX_ERROR) +#define NJS_INDEX_OBJECT_TYPE_ERROR \ + njs_global_scope_index(NJS_CONSTRUCTOR_TYPE_ERROR) +#define NJS_INDEX_OBJECT_URI_ERROR \ + njs_global_scope_index(NJS_CONSTRUCTOR_URI_ERROR) +#define NJS_INDEX_OBJECT_MEMORY_ERROR \ + njs_global_scope_index(NJS_CONSTRUCTOR_MEMORY_ERROR) #define NJS_INDEX_GLOBAL_RETVAL njs_global_scope_index(NJS_CONSTRUCTOR_MAX) #define NJS_INDEX_GLOBAL_OFFSET njs_scope_index(NJS_CONSTRUCTOR_MAX + 1, 0) @@ -906,6 +957,14 @@ struct njs_vm_s { nxt_regex_context_t *regex_context; nxt_regex_match_data_t *single_match_data; + /* + * MemoryError is statically allocated immutable Error object + * with the generic type NJS_OBJECT_INTERNAL_ERROR but its own prototype + * object NJS_PROTOTYPE_MEMORY_ERROR. + */ + njs_value_t memory_error; + njs_object_t memory_error_object; + nxt_array_t *code; /* of njs_vm_code_t */ nxt_trace_t trace; @@ -1117,14 +1176,8 @@ extern const njs_value_t njs_string_native; extern const njs_value_t njs_string_minus_infinity; extern const njs_value_t njs_string_plus_infinity; extern const njs_value_t njs_string_nan; - -extern const njs_value_t njs_exception_syntax_error; -extern const njs_value_t njs_exception_reference_error; -extern const njs_value_t njs_exception_type_error; -extern const njs_value_t njs_exception_range_error; -extern const njs_value_t njs_exception_uri_error; -extern const njs_value_t njs_exception_memory_error; -extern const njs_value_t njs_exception_internal_error; +extern const njs_value_t njs_string_internal_error; +extern const njs_value_t njs_string_memory_error; extern const nxt_mem_proto_t njs_array_mem_proto; extern const nxt_lvlhsh_proto_t njs_object_hash_proto; diff --git a/njs/njscript.c b/njs/njscript.c index 4f54dfc7..2dd1f509 100644 --- a/njs/njscript.c +++ b/njs/njscript.c @@ -522,6 +522,10 @@ njs_vm_retval(njs_vm_t *vm, nxt_str_t *retval) nxt_int_t njs_vm_exception(njs_vm_t *vm, nxt_str_t *retval) { + if (vm->top_frame != NULL) { + vm->top_frame->trap_tries = 0; + } + return njs_value_to_ext_string(vm, retval, vm->exception); } diff --git a/njs/test/njs_expect_test.exp b/njs/test/njs_expect_test.exp index 30c85191..5081a7b9 100644 --- a/njs/test/njs_expect_test.exp +++ b/njs/test/njs_expect_test.exp @@ -51,8 +51,8 @@ njs_test { } njs_test { - {"M\t" - "M\aath"} + {"Ma\t" + "Ma\ath"} } njs_test { @@ -86,8 +86,8 @@ njs_test { } njs_test { - {"M\t" - "M\aath"} + {"Ma\t" + "Ma\ath"} {".\t\t" "Math.__proto__*Math.cbrt*Math.fround*Math.log2"} } diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 6a2385ec..6e06776e 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -5161,6 +5161,262 @@ static njs_unit_test_t njs_test[] = { nxt_string("var chars = '𐒠'; chars.length +' '+ chars.charCodeAt(0)"), nxt_string("1 66720") }, + /* Error object. */ + + { nxt_string("Error()"), + nxt_string("Error") }, + + { nxt_string("new Error()"), + nxt_string("Error") }, + + { nxt_string("Error('e')"), + nxt_string("Error: e") }, + + { nxt_string("var e = Error('e'); e.name = 'E'; e"), + nxt_string("E: e") }, + + { nxt_string("var e = Error('e'); e.name = ''; e"), + nxt_string("e") }, + + { nxt_string("var e = Error(); e.name = ''; e"), + nxt_string("") }, + + { nxt_string("var e = Error(); e.name = ''; e.message = 'e'; e"), + nxt_string("e") }, + + { nxt_string("Error('e').name + ': ' + Error('e').message"), + nxt_string("Error: e") }, + + { nxt_string("Error(1)"), + nxt_string("Error: 1") }, + + { nxt_string("Error.__proto__ == Function.prototype"), + nxt_string("true") }, + + { nxt_string("Error.prototype.name"), + nxt_string("Error") }, + + { nxt_string("Error.prototype.message"), + nxt_string("") }, + + { nxt_string("Error.prototype.constructor == Error"), + nxt_string("true") }, + + { nxt_string("Error().__proto__ == Error.prototype"), + nxt_string("true") }, + + { nxt_string("Error().__proto__.__proto__ == Object.prototype"), + nxt_string("true") }, + + { nxt_string("EvalError('e')"), + nxt_string("EvalError: e") }, + + { nxt_string("InternalError('e')"), + nxt_string("InternalError: e") }, + + { nxt_string("RangeError('e')"), + nxt_string("RangeError: e") }, + + { nxt_string("ReferenceError('e')"), + nxt_string("ReferenceError: e") }, + + { nxt_string("SyntaxError('e')"), + nxt_string("SyntaxError: e") }, + + { nxt_string("TypeError('e')"), + nxt_string("TypeError: e") }, + + { nxt_string("URIError('e')"), + nxt_string("URIError: e") }, + + { nxt_string("MemoryError('e')"), + nxt_string("MemoryError") }, + + { nxt_string("EvalError('e').name + ': ' + EvalError('e').message"), + nxt_string("EvalError: e") }, + + { nxt_string("InternalError('e').name + ': ' + InternalError('e').message"), + nxt_string("InternalError: e") }, + + { nxt_string("RangeError('e').name + ': ' + RangeError('e').message"), + nxt_string("RangeError: e") }, + + { nxt_string("ReferenceError('e').name + ': ' + ReferenceError('e').message"), + nxt_string("ReferenceError: e") }, + + { nxt_string("SyntaxError('e').name + ': ' + SyntaxError('e').message"), + nxt_string("SyntaxError: e") }, + + { nxt_string("TypeError('e').name + ': ' + TypeError('e').message"), + nxt_string("TypeError: e") }, + + { nxt_string("URIError('e').name + ': ' + URIError('e').message"), + nxt_string("URIError: e") }, + + { nxt_string("MemoryError('e').name + ': ' + MemoryError('e').message"), + nxt_string("MemoryError: ") }, + + { nxt_string("var e = EvalError('e'); e.name = 'E'; e"), + nxt_string("E: e") }, + + { nxt_string("var e = InternalError('e'); e.name = 'E'; e"), + nxt_string("E: e") }, + + { nxt_string("var e = RangeError('e'); e.name = 'E'; e"), + nxt_string("E: e") }, + + { nxt_string("var e = ReferenceError('e'); e.name = 'E'; e"), + nxt_string("E: e") }, + + { nxt_string("var e = SyntaxError('e'); e.name = 'E'; e"), + nxt_string("E: e") }, + + { nxt_string("var e = TypeError('e'); e.name = 'E'; e"), + nxt_string("E: e") }, + + { nxt_string("var e = URIError('e'); e.name = 'E'; e"), + nxt_string("E: e") }, + + /* Memory object is immutable. */ + + { nxt_string("var e = MemoryError('e'); e.name = 'E'; e.message = 'e'; e"), + nxt_string("MemoryError") }, + + { nxt_string("EvalError.prototype.name"), + nxt_string("EvalError") }, + + { nxt_string("InternalError.prototype.name"), + nxt_string("InternalError") }, + + { nxt_string("RangeError.prototype.name"), + nxt_string("RangeError") }, + + { nxt_string("ReferenceError.prototype.name"), + nxt_string("ReferenceError") }, + + { nxt_string("SyntaxError.prototype.name"), + nxt_string("SyntaxError") }, + + { nxt_string("TypeError.prototype.name"), + nxt_string("TypeError") }, + + { nxt_string("URIError.prototype.name"), + nxt_string("URIError") }, + + { nxt_string("MemoryError.prototype.name"), + nxt_string("MemoryError") }, + + { nxt_string("EvalError.prototype.message"), + nxt_string("") }, + + { nxt_string("InternalError.prototype.message"), + nxt_string("") }, + + { nxt_string("RangeError.prototype.message"), + nxt_string("") }, + + { nxt_string("ReferenceError.prototype.message"), + nxt_string("") }, + + { nxt_string("SyntaxError.prototype.message"), + nxt_string("") }, + + { nxt_string("TypeError.prototype.message"), + nxt_string("") }, + + { nxt_string("URIError.prototype.message"), + nxt_string("") }, + + { nxt_string("MemoryError.prototype.message"), + nxt_string("") }, + + { nxt_string("EvalError.prototype.constructor == EvalError"), + nxt_string("true") }, + + { nxt_string("RangeError.prototype.constructor == RangeError"), + nxt_string("true") }, + + { nxt_string("ReferenceError.prototype.constructor == ReferenceError"), + nxt_string("true") }, + + { nxt_string("SyntaxError.prototype.constructor == SyntaxError"), + nxt_string("true") }, + + { nxt_string("TypeError.prototype.constructor == TypeError"), + nxt_string("true") }, + + { nxt_string("URIError.prototype.constructor == URIError"), + nxt_string("true") }, + + { nxt_string("EvalError().__proto__ == EvalError.prototype"), + nxt_string("true") }, + + { nxt_string("RangeError().__proto__ == RangeError.prototype"), + nxt_string("true") }, + + { nxt_string("ReferenceError().__proto__ == ReferenceError.prototype"), + nxt_string("true") }, + + { nxt_string("SyntaxError().__proto__ == SyntaxError.prototype"), + nxt_string("true") }, + + { nxt_string("TypeError().__proto__ == TypeError.prototype"), + nxt_string("true") }, + + { nxt_string("URIError().__proto__ == URIError.prototype"), + nxt_string("true") }, + + { nxt_string("EvalError().__proto__.__proto__ == Error.prototype"), + nxt_string("true") }, + + { nxt_string("RangeError().__proto__.__proto__ == Error.prototype"), + nxt_string("true") }, + + { nxt_string("ReferenceError().__proto__.__proto__ == Error.prototype"), + nxt_string("true") }, + + { nxt_string("SyntaxError().__proto__.__proto__ == Error.prototype"), + nxt_string("true") }, + + { nxt_string("TypeError().__proto__.__proto__ == Error.prototype"), + nxt_string("true") }, + + { nxt_string("URIError().__proto__.__proto__ == Error.prototype"), + nxt_string("true") }, + + { nxt_string("MemoryError().__proto__ == MemoryError.prototype"), + nxt_string("true") }, + + { nxt_string("MemoryError().__proto__.__proto__ == Error.prototype"), + nxt_string("true") }, + + { nxt_string("typeof Error()"), + nxt_string("object") }, + + { nxt_string("typeof EvalError()"), + nxt_string("object") }, + + { nxt_string("typeof InternalError()"), + nxt_string("object") }, + + { nxt_string("typeof RangeError()"), + nxt_string("object") }, + + { nxt_string("typeof ReferenceError()"), + nxt_string("object") }, + + { nxt_string("typeof SyntaxError()"), + nxt_string("object") }, + + { nxt_string("typeof TypeError()"), + nxt_string("object") }, + + { nxt_string("typeof URIError()"), + nxt_string("object") }, + + { nxt_string("typeof MemoryError()"), + nxt_string("object") }, + /* Exceptions. */ { nxt_string("throw null"), @@ -5169,6 +5425,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a; try { throw null } catch (e) { a = e } a"), nxt_string("null") }, + { nxt_string("var a; try { throw Error('e') } catch (e) { a = e.message } a"), + nxt_string("e") }, + { nxt_string("try { throw null } catch (e) { throw e }"), nxt_string("") }, @@ -8202,6 +8461,21 @@ static njs_unit_test_t njs_test[] = { nxt_string("JSON.stringify(RegExp())"), nxt_string("{}") }, + { nxt_string("JSON.stringify(SyntaxError('e'))"), + nxt_string("{}") }, + + { nxt_string("JSON.stringify(URIError('e'))"), + nxt_string("{}") }, + + { nxt_string("var e = URIError('e'); e.name = 'E'; JSON.stringify(e)"), + nxt_string("{\"name\":\"E\"}") }, + + { nxt_string("var e = URIError('e'); e.message = 'E'; JSON.stringify(e)"), + nxt_string("{}") }, + + { nxt_string("var e = URIError('e'); e.foo = 'E'; JSON.stringify(e)"), + nxt_string("{\"foo\":\"E\"}") }, + /* Ignoring named properties of an array. */ { nxt_string("var a = [1,2]; a.a = 1;" diff --git a/nxt/nxt_string.h b/nxt/nxt_string.h index db1cdd70..ec953cf3 100644 --- a/nxt/nxt_string.h +++ b/nxt/nxt_string.h @@ -40,6 +40,9 @@ nxt_upper_case(u_char c) } +#define nxt_cpymem(dst, src, n) (((u_char *) memcpy(dst, src, n)) + (n)) + + #define nxt_strstr_eq(s1, s2) \ (((s1)->length == (s2)->length) \ && (memcmp((s1)->start, (s2)->start, (s1)->length) == 0))