blob: 2b19c290769844f728afb861cb8ece7be69dc11a [file] [log] [blame]
/*
* Copyright (C) Dmitry Volyntsev
* Copyright (C) NGINX, Inc.
*/
#include <njs_main.h>
typedef struct {
njs_str_t name;
njs_str_t file;
uint32_t line;
} njs_backtrace_entry_t;
static njs_int_t njs_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack,
njs_native_frame_t *native_frame);
static njs_int_t njs_backtrace_to_string(njs_vm_t *vm, njs_arr_t *backtrace,
njs_str_t *dst);
static const njs_value_t njs_error_message_string = njs_string("message");
static const njs_value_t njs_error_name_string = njs_string("name");
static const njs_value_t njs_error_stack_string = njs_string("stack");
void
njs_error_new(njs_vm_t *vm, njs_value_t *dst, njs_object_type_t type,
u_char *start, size_t size)
{
ssize_t length;
njs_int_t ret;
njs_value_t string;
njs_object_t *error;
length = njs_utf8_length(start, size);
if (njs_slow_path(length < 0)) {
length = 0;
}
ret = njs_string_new(vm, &string, start, size, length);
if (njs_slow_path(ret != NJS_OK)) {
return;
}
error = njs_error_alloc(vm, type, NULL, &string);
if (njs_slow_path(error == NULL)) {
return;
}
njs_set_object(dst, error);
}
void
njs_error_fmt_new(njs_vm_t *vm, njs_value_t *dst, njs_object_type_t type,
const char *fmt, ...)
{
va_list args;
u_char buf[NJS_MAX_ERROR_STR], *p;
p = buf;
if (fmt != NULL) {
va_start(args, fmt);
p = njs_vsprintf(buf, buf + sizeof(buf), fmt, args);
va_end(args);
}
njs_error_new(vm, dst, type, buf, p - buf);
}
static njs_int_t
njs_error_stack_new(njs_vm_t *vm, njs_object_t *error, njs_value_t *retval)
{
njs_int_t ret;
njs_str_t string;
njs_arr_t *stack;
njs_value_t value;
njs_native_frame_t *frame;
njs_set_object(&value, error);
ret = njs_error_to_string(vm, retval, &value);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
stack = njs_arr_create(vm->mem_pool, 4, sizeof(njs_backtrace_entry_t));
if (njs_slow_path(stack == NULL)) {
return NJS_ERROR;
}
frame = vm->top_frame;
for ( ;; ) {
if ((frame->native || frame->pc != NULL)
&& njs_add_backtrace_entry(vm, stack, frame) != NJS_OK)
{
break;
}
frame = frame->previous;
if (frame == NULL) {
break;
}
}
njs_string_get(retval, &string);
ret = njs_backtrace_to_string(vm, stack, &string);
njs_arr_destroy(stack);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
return njs_string_set(vm, retval, string.start, string.length);
}
njs_int_t
njs_error_stack_attach(njs_vm_t *vm, njs_value_t *value)
{
njs_int_t ret;
njs_object_t *error;
njs_object_prop_t *prop;
njs_lvlhsh_query_t lhq;
if (njs_slow_path(!njs_is_error(value))) {
return NJS_DECLINED;
}
if (njs_slow_path(!vm->options.backtrace || vm->start == NULL)) {
return NJS_OK;
}
error = njs_object(value);
lhq.replace = 0;
lhq.pool = vm->mem_pool;
lhq.proto = &njs_object_hash_proto;
lhq.key = njs_str_value("stack");
lhq.key_hash = NJS_STACK_HASH;
prop = njs_object_prop_alloc(vm, &njs_error_stack_string,
&njs_value_undefined, 1);
if (njs_slow_path(prop == NULL)) {
return NJS_ERROR;
}
prop->enumerable = 0;
ret = njs_error_stack_new(vm, error, &prop->value);
if (njs_slow_path(ret == NJS_ERROR)) {
njs_internal_error(vm, "njs_error_stack_new() failed");
return NJS_ERROR;
}
if (ret == NJS_OK) {
lhq.value = prop;
ret = njs_lvlhsh_insert(&error->hash, &lhq);
if (njs_slow_path(ret == NJS_ERROR)) {
njs_internal_error(vm, "lvlhsh insert failed");
return NJS_ERROR;
}
}
return NJS_OK;
}
njs_int_t
njs_error_stack(njs_vm_t *vm, njs_value_t *value, njs_value_t *stack)
{
njs_int_t ret;
ret = njs_value_property(vm, value, njs_value_arg(&njs_error_stack_string),
stack);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
if (!njs_is_string(stack)) {
return NJS_DECLINED;
}
return NJS_OK;
}
njs_object_t *
njs_error_alloc(njs_vm_t *vm, njs_object_type_t type, const njs_value_t *name,
const njs_value_t *message)
{
njs_int_t ret;
njs_object_t *error;
njs_object_prop_t *prop;
njs_lvlhsh_query_t lhq;
error = njs_mp_alloc(vm->mem_pool, sizeof(njs_object_t));
if (njs_slow_path(error == NULL)) {
goto memory_error;
}
njs_lvlhsh_init(&error->hash);
njs_lvlhsh_init(&error->shared_hash);
error->type = NJS_OBJECT;
error->shared = 0;
error->extensible = 1;
error->fast_array = 0;
error->error_data = 1;
error->__proto__ = &vm->prototypes[type].object;
error->slots = NULL;
lhq.replace = 0;
lhq.pool = vm->mem_pool;
lhq.proto = &njs_object_hash_proto;
if (name != NULL) {
lhq.key = njs_str_value("name");
lhq.key_hash = NJS_NAME_HASH;
prop = njs_object_prop_alloc(vm, &njs_error_name_string, name, 1);
if (njs_slow_path(prop == NULL)) {
goto memory_error;
}
lhq.value = prop;
ret = njs_lvlhsh_insert(&error->hash, &lhq);
if (njs_slow_path(ret != NJS_OK)) {
njs_internal_error(vm, "lvlhsh insert failed");
return NULL;
}
}
if (message!= NULL) {
lhq.key = njs_str_value("message");
lhq.key_hash = NJS_MESSAGE_HASH;
prop = njs_object_prop_alloc(vm, &njs_error_message_string, message, 1);
if (njs_slow_path(prop == NULL)) {
goto memory_error;
}
prop->enumerable = 0;
lhq.value = prop;
ret = njs_lvlhsh_insert(&error->hash, &lhq);
if (njs_slow_path(ret != NJS_OK)) {
njs_internal_error(vm, "lvlhsh insert failed");
return NULL;
}
}
return error;
memory_error:
njs_memory_error(vm);
return NULL;
}
static njs_int_t
njs_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t type)
{
njs_int_t ret;
njs_value_t *value;
njs_object_t *error;
value = njs_arg(args, nargs, 1);
if (njs_slow_path(!njs_is_string(value))) {
if (!njs_is_undefined(value)) {
ret = njs_value_to_string(vm, value, value);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
}
}
error = njs_error_alloc(vm, type, NULL,
njs_is_defined(value) ? value : NULL);
if (njs_slow_path(error == NULL)) {
return NJS_ERROR;
}
njs_set_object(&vm->retval, error);
return NJS_OK;
}
static const njs_object_prop_t njs_error_constructor_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("Error"),
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("length"),
.value = njs_value(NJS_NUMBER, 1, 1.0),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
.value = njs_prop_handler(njs_object_prototype_create),
},
};
const njs_object_init_t njs_error_constructor_init = {
njs_error_constructor_properties,
njs_nitems(njs_error_constructor_properties),
};
static const njs_object_prop_t njs_eval_error_constructor_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("EvalError"),
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("length"),
.value = njs_value(NJS_NUMBER, 1, 1.0),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
.value = njs_prop_handler(njs_object_prototype_create),
},
};
const njs_object_init_t njs_eval_error_constructor_init = {
njs_eval_error_constructor_properties,
njs_nitems(njs_eval_error_constructor_properties),
};
static const njs_object_prop_t njs_internal_error_constructor_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("InternalError"),
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("length"),
.value = njs_value(NJS_NUMBER, 1, 1.0),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
.value = njs_prop_handler(njs_object_prototype_create),
},
};
const njs_object_init_t njs_internal_error_constructor_init = {
njs_internal_error_constructor_properties,
njs_nitems(njs_internal_error_constructor_properties),
};
static const njs_object_prop_t njs_range_error_constructor_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("RangeError"),
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("length"),
.value = njs_value(NJS_NUMBER, 1, 1.0),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
.value = njs_prop_handler(njs_object_prototype_create),
},
};
const njs_object_init_t njs_range_error_constructor_init = {
njs_range_error_constructor_properties,
njs_nitems(njs_range_error_constructor_properties),
};
static const njs_object_prop_t njs_reference_error_constructor_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("ReferenceError"),
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("length"),
.value = njs_value(NJS_NUMBER, 1, 1.0),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
.value = njs_prop_handler(njs_object_prototype_create),
},
};
const njs_object_init_t njs_reference_error_constructor_init = {
njs_reference_error_constructor_properties,
njs_nitems(njs_reference_error_constructor_properties),
};
static const njs_object_prop_t njs_syntax_error_constructor_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("SyntaxError"),
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("length"),
.value = njs_value(NJS_NUMBER, 1, 1.0),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
.value = njs_prop_handler(njs_object_prototype_create),
},
};
const njs_object_init_t njs_syntax_error_constructor_init = {
njs_syntax_error_constructor_properties,
njs_nitems(njs_syntax_error_constructor_properties),
};
static const njs_object_prop_t njs_type_error_constructor_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("TypeError"),
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("length"),
.value = njs_value(NJS_NUMBER, 1, 1.0),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
.value = njs_prop_handler(njs_object_prototype_create),
},
};
const njs_object_init_t njs_type_error_constructor_init = {
njs_type_error_constructor_properties,
njs_nitems(njs_type_error_constructor_properties),
};
static const njs_object_prop_t njs_uri_error_constructor_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("URIError"),
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("length"),
.value = njs_value(NJS_NUMBER, 1, 1.0),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
.value = njs_prop_handler(njs_object_prototype_create),
},
};
const njs_object_init_t njs_uri_error_constructor_init = {
njs_uri_error_constructor_properties,
njs_nitems(njs_uri_error_constructor_properties),
};
void
njs_memory_error_set(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;
njs_lvlhsh_init(&object->hash);
njs_lvlhsh_init(&object->shared_hash);
object->__proto__ = &prototypes[NJS_OBJ_TYPE_INTERNAL_ERROR].object;
object->slots = NULL;
object->type = NJS_OBJECT;
object->shared = 1;
/*
* Marking it nonextensible to differentiate
* it from ordinary internal errors.
*/
object->extensible = 0;
object->fast_array = 0;
object->error_data = 1;
njs_set_object(value, object);
}
void
njs_memory_error(njs_vm_t *vm)
{
njs_memory_error_set(vm, &vm->retval);
}
static njs_int_t
njs_memory_error_constructor(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused)
{
njs_memory_error_set(vm, &vm->retval);
return NJS_OK;
}
static njs_int_t
njs_memory_error_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop,
njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
int32_t index;
njs_function_t *function;
const njs_value_t *proto;
/* MemoryError has no its own prototype. */
index = NJS_OBJ_TYPE_INTERNAL_ERROR;
function = njs_function(value);
proto = njs_property_prototype_create(vm, &function->object.hash,
&vm->prototypes[index].object);
if (proto == NULL) {
proto = &njs_value_undefined;
}
*retval = *proto;
return NJS_OK;
}
static const njs_object_prop_t njs_memory_error_constructor_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("MemoryError"),
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("length"),
.value = njs_value(NJS_NUMBER, 1, 1.0),
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
.value = njs_prop_handler(njs_memory_error_prototype_create),
},
};
const njs_object_init_t njs_memory_error_constructor_init = {
njs_memory_error_constructor_properties,
njs_nitems(njs_memory_error_constructor_properties),
};
static njs_int_t
njs_error_prototype_value_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
vm->retval = args[0];
return NJS_OK;
}
static njs_int_t
njs_error_to_string2(njs_vm_t *vm, njs_value_t *retval,
const njs_value_t *error, njs_bool_t want_stack)
{
size_t length;
u_char *p;
njs_int_t ret;
njs_value_t value1, value2;
njs_value_t *name_value, *message_value;
njs_string_prop_t name, message;
njs_lvlhsh_query_t lhq;
static const njs_value_t default_name = njs_string("Error");
if (want_stack) {
ret = njs_error_stack(vm, njs_value_arg(error), retval);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
if (ret == NJS_OK) {
return NJS_OK;
}
}
njs_object_property_init(&lhq, &njs_string_name, NJS_NAME_HASH);
ret = njs_object_property(vm, error, &lhq, &value1);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
name_value = (ret == NJS_OK) ? &value1 : njs_value_arg(&default_name);
if (njs_slow_path(!njs_is_string(name_value))) {
ret = njs_value_to_string(vm, &value1, name_value);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
name_value = &value1;
}
(void) njs_string_prop(&name, name_value);
lhq.key_hash = NJS_MESSAGE_HASH;
lhq.key = njs_str_value("message");
ret = njs_object_property(vm, error, &lhq, &value2);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
message_value = (ret == NJS_OK) ? &value2
: njs_value_arg(&njs_string_empty);
if (njs_slow_path(!njs_is_string(message_value))) {
ret = njs_value_to_string(vm, &value2, message_value);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
message_value = &value2;
}
(void) njs_string_prop(&message, message_value);
if (name.size == 0) {
*retval = *message_value;
return NJS_OK;
}
if (message.size == 0) {
*retval = *name_value;
return NJS_OK;
}
if (name.length != 0 && message.length != 0) {
length = name.length + message.length + 2;
} else {
length = 0;
}
p = njs_string_alloc(vm, retval, name.size + message.size + 2, length);
if (njs_fast_path(p != NULL)) {
p = njs_cpymem(p, name.start, name.size);
*p++ = ':';
*p++ = ' ';
memcpy(p, message.start, message.size);
return NJS_OK;
}
njs_memory_error(vm);
return NJS_ERROR;
}
static njs_int_t
njs_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
if (nargs < 1 || !njs_is_object(&args[0])) {
njs_type_error(vm, "\"this\" argument is not an object");
return NJS_ERROR;
}
return njs_error_to_string2(vm, &vm->retval, &args[0], 0);
}
njs_int_t
njs_error_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *error)
{
return njs_error_to_string2(vm, retval, error, 1);
}
static const njs_object_prop_t njs_error_prototype_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("Error"),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("constructor"),
.value = njs_prop_handler(njs_object_prototype_create_constructor),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("message"),
.value = njs_string(""),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("valueOf"),
.value = njs_native_function(njs_error_prototype_value_of, 0),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("toString"),
.value = njs_native_function(njs_error_prototype_to_string, 0),
.writable = 1,
.configurable = 1,
},
};
const njs_object_init_t njs_error_prototype_init = {
njs_error_prototype_properties,
njs_nitems(njs_error_prototype_properties),
};
const njs_object_type_init_t njs_error_type_init = {
.constructor = njs_native_ctor(njs_error_constructor, 1,
NJS_OBJ_TYPE_ERROR),
.constructor_props = &njs_error_constructor_init,
.prototype_props = &njs_error_prototype_init,
.prototype_value = { .object = { .type = NJS_OBJECT } },
};
static const njs_object_prop_t njs_eval_error_prototype_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("EvalError"),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("message"),
.value = njs_string(""),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("constructor"),
.value = njs_prop_handler(njs_object_prototype_create_constructor),
.writable = 1,
.configurable = 1,
},
};
const njs_object_init_t njs_eval_error_prototype_init = {
njs_eval_error_prototype_properties,
njs_nitems(njs_eval_error_prototype_properties),
};
const njs_object_type_init_t njs_eval_error_type_init = {
.constructor = njs_native_ctor(njs_error_constructor, 1,
NJS_OBJ_TYPE_EVAL_ERROR),
.constructor_props = &njs_eval_error_constructor_init,
.prototype_props = &njs_eval_error_prototype_init,
.prototype_value = { .object = { .type = NJS_OBJECT } },
};
static njs_int_t
njs_internal_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused)
{
if (nargs >= 1 && njs_is_object(&args[0])) {
/* MemoryError is a nonextensible internal error. */
if (!njs_object(&args[0])->extensible) {
static const njs_value_t name = njs_string("MemoryError");
vm->retval = name;
return NJS_OK;
}
}
return njs_error_prototype_to_string(vm, args, nargs, unused);
}
static const njs_object_prop_t njs_internal_error_prototype_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("InternalError"),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("message"),
.value = njs_string(""),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("toString"),
.value = njs_native_function(njs_internal_error_prototype_to_string, 0),
.writable = 1,
.configurable = 1,
},
};
const njs_object_init_t njs_internal_error_prototype_init = {
njs_internal_error_prototype_properties,
njs_nitems(njs_internal_error_prototype_properties),
};
const njs_object_type_init_t njs_internal_error_type_init = {
.constructor = njs_native_ctor(njs_error_constructor, 1,
NJS_OBJ_TYPE_INTERNAL_ERROR),
.constructor_props = &njs_internal_error_constructor_init,
.prototype_props = &njs_internal_error_prototype_init,
.prototype_value = { .object = { .type = NJS_OBJECT } },
};
const njs_object_type_init_t njs_memory_error_type_init = {
.constructor = njs_native_ctor(njs_memory_error_constructor, 1, 0),
.constructor_props = &njs_memory_error_constructor_init,
.prototype_props = &njs_internal_error_prototype_init,
.prototype_value = { .object = { .type = NJS_OBJECT } },
};
static const njs_object_prop_t njs_range_error_prototype_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("RangeError"),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("message"),
.value = njs_string(""),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("constructor"),
.value = njs_prop_handler(njs_object_prototype_create_constructor),
.writable = 1,
.configurable = 1,
},
};
const njs_object_init_t njs_range_error_prototype_init = {
njs_range_error_prototype_properties,
njs_nitems(njs_range_error_prototype_properties),
};
const njs_object_type_init_t njs_range_error_type_init = {
.constructor = njs_native_ctor(njs_error_constructor, 1,
NJS_OBJ_TYPE_RANGE_ERROR),
.constructor_props = &njs_range_error_constructor_init,
.prototype_props = &njs_range_error_prototype_init,
.prototype_value = { .object = { .type = NJS_OBJECT } },
};
static const njs_object_prop_t njs_reference_error_prototype_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("ReferenceError"),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("message"),
.value = njs_string(""),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("constructor"),
.value = njs_prop_handler(njs_object_prototype_create_constructor),
.writable = 1,
.configurable = 1,
},
};
const njs_object_init_t njs_reference_error_prototype_init = {
njs_reference_error_prototype_properties,
njs_nitems(njs_reference_error_prototype_properties),
};
const njs_object_type_init_t njs_reference_error_type_init = {
.constructor = njs_native_ctor(njs_error_constructor, 1,
NJS_OBJ_TYPE_REF_ERROR),
.constructor_props = &njs_reference_error_constructor_init,
.prototype_props = &njs_reference_error_prototype_init,
.prototype_value = { .object = { .type = NJS_OBJECT } },
};
static const njs_object_prop_t njs_syntax_error_prototype_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("SyntaxError"),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("message"),
.value = njs_string(""),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("constructor"),
.value = njs_prop_handler(njs_object_prototype_create_constructor),
.writable = 1,
.configurable = 1,
},
};
const njs_object_init_t njs_syntax_error_prototype_init = {
njs_syntax_error_prototype_properties,
njs_nitems(njs_syntax_error_prototype_properties),
};
const njs_object_type_init_t njs_syntax_error_type_init = {
.constructor = njs_native_ctor(njs_error_constructor, 1,
NJS_OBJ_TYPE_SYNTAX_ERROR),
.constructor_props = &njs_syntax_error_constructor_init,
.prototype_props = &njs_syntax_error_prototype_init,
.prototype_value = { .object = { .type = NJS_OBJECT } },
};
static const njs_object_prop_t njs_type_error_prototype_properties[] =
{
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("TypeError"),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("message"),
.value = njs_string(""),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("constructor"),
.value = njs_prop_handler(njs_object_prototype_create_constructor),
.writable = 1,
.configurable = 1,
},
};
const njs_object_init_t njs_type_error_prototype_init = {
njs_type_error_prototype_properties,
njs_nitems(njs_type_error_prototype_properties),
};
const njs_object_type_init_t njs_type_error_type_init = {
.constructor = njs_native_ctor(njs_error_constructor, 1,
NJS_OBJ_TYPE_TYPE_ERROR),
.constructor_props = &njs_type_error_constructor_init,
.prototype_props = &njs_type_error_prototype_init,
.prototype_value = { .object = { .type = NJS_OBJECT } },
};
static const njs_object_prop_t njs_uri_error_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_string("message"),
.value = njs_string(""),
.writable = 1,
.configurable = 1,
},
{
.type = NJS_PROPERTY,
.name = njs_string("name"),
.value = njs_string("URIError"),
.writable = 1,
.configurable = 1,
},
};
const njs_object_init_t njs_uri_error_prototype_init = {
njs_uri_error_prototype_properties,
njs_nitems(njs_uri_error_prototype_properties),
};
const njs_object_type_init_t njs_uri_error_type_init = {
.constructor = njs_native_ctor(njs_error_constructor, 1,
NJS_OBJ_TYPE_URI_ERROR),
.constructor_props = &njs_uri_error_constructor_init,
.prototype_props = &njs_uri_error_prototype_init,
.prototype_value = { .object = { .type = NJS_OBJECT } },
};
static njs_int_t
njs_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack,
njs_native_frame_t *native_frame)
{
njs_int_t ret;
njs_uint_t i;
njs_vm_code_t *code;
njs_function_t *function;
njs_backtrace_entry_t *be;
function = native_frame->function;
be = njs_arr_add(stack);
if (njs_slow_path(be == NULL)) {
return NJS_ERROR;
}
be->line = 0;
be->file = njs_str_value("");
if (function != NULL && function->native) {
while (function->bound != NULL) {
function = function->u.bound_target;
}
ret = njs_builtin_match_native_function(vm, function, &be->name);
if (ret == NJS_OK) {
return NJS_OK;
}
be->name = njs_entry_native;
return NJS_OK;
}
code = vm->codes->start;
for (i = 0; i < vm->codes->items; i++, code++) {
if (code->start <= native_frame->pc
&& native_frame->pc < code->end)
{
be->name = code->name;
be->line = njs_lookup_line(code, native_frame->pc - code->start);
if (!vm->options.quiet) {
be->file = code->file;
}
return NJS_OK;
}
}
be->name = njs_entry_unknown;
return NJS_OK;
}
static njs_int_t
njs_backtrace_to_string(njs_vm_t *vm, njs_arr_t *backtrace, njs_str_t *dst)
{
size_t count;
njs_chb_t chain;
njs_uint_t i;
njs_backtrace_entry_t *be, *prev;
if (backtrace->items == 0) {
return NJS_OK;
}
njs_chb_init(&chain, vm->mem_pool);
njs_chb_append_str(&chain, dst);
njs_chb_append(&chain, "\n", 1);
count = 0;
prev = NULL;
be = backtrace->start;
for (i = 0; i < backtrace->items; i++) {
if (i != 0 && prev->name.start == be->name.start
&& prev->line == be->line)
{
count++;
} else {
if (count != 0) {
njs_chb_sprintf(&chain, 64, " repeats %uz times\n", count);
count = 0;
}
njs_chb_sprintf(&chain, 10 + be->name.length, " at %V ",
&be->name);
if (be->line != 0) {
njs_chb_sprintf(&chain, 12 + be->file.length,
"(%V:%uD)\n", &be->file, be->line);
} else {
njs_chb_append(&chain, "(native)\n", 9);
}
}
prev = be;
be++;
}
njs_chb_join(&chain, dst);
njs_chb_destroy(&chain);
return NJS_OK;
}