[njs] Fixed exception handling.
Dmitry Volyntsev
xeioex at nginx.com
Fri Nov 17 16:06:04 UTC 2017
details: http://hg.nginx.org/njs/rev/a83775113025
branches:
changeset: 422:a83775113025
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Fri Nov 17 18:55:07 2017 +0300
description:
Fixed exception handling.
njs_vm_exception() is removed and combined with njs_vm_retval().
vm->exception is removed either, exceptions are now stored in
vm->retval. It simplifies the client logic, because previously
njs_vm_exception() had to be called if njs_vm_retval() fails.
Additonally, stack traces are now appended to the retval if an exception
happens.
diffstat:
nginx/ngx_http_js_module.c | 6 +-
nginx/ngx_stream_js_module.c | 8 +-
njs/njs.c | 56 +++-----------------
njs/njs_error.c | 36 ++++---------
njs/njs_function.c | 2 +
njs/njs_generator.c | 6 +-
njs/njs_parser.c | 108 ++++++++++++++++++++++++---------------
njs/njs_parser.h | 4 +
njs/njs_parser_expression.c | 25 ++++----
njs/njs_regexp.c | 34 +++++-------
njs/njs_variable.c | 16 ++--
njs/njs_vm.c | 19 -------
njs/njs_vm.h | 5 -
njs/njscript.c | 91 ++++++++++++++++++++++++++++----
njs/njscript.h | 1 -
njs/test/njs_benchmark.c | 9 +--
njs/test/njs_expect_test.exp | 16 +++++
njs/test/njs_interactive_test.c | 99 +++++++++++------------------------
njs/test/njs_unit_test.c | 46 +++++++++++-----
19 files changed, 293 insertions(+), 294 deletions(-)
diffs (truncated from 1269 to 1000 lines):
diff -r 84a95e20f93a -r a83775113025 nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c Fri Nov 17 18:55:07 2017 +0300
+++ b/nginx/ngx_http_js_module.c Fri Nov 17 18:55:07 2017 +0300
@@ -445,7 +445,7 @@ ngx_http_js_handler(ngx_http_request_t *
}
if (njs_vm_call(ctx->vm, func, ctx->args, 2) != NJS_OK) {
- njs_vm_exception(ctx->vm, &exception);
+ njs_vm_retval(ctx->vm, &exception);
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"js exception: %*s", exception.length, exception.start);
@@ -496,7 +496,7 @@ ngx_http_js_variable(ngx_http_request_t
}
if (njs_vm_call(ctx->vm, func, ctx->args, 2) != NJS_OK) {
- njs_vm_exception(ctx->vm, &exception);
+ njs_vm_retval(ctx->vm, &exception);
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"js exception: %*s", exception.length, exception.start);
@@ -1333,7 +1333,7 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_
rc = njs_vm_compile(jlcf->vm, &start, end);
if (rc != NJS_OK) {
- njs_vm_exception(jlcf->vm, &text);
+ njs_vm_retval(jlcf->vm, &text);
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"%*s, included",
diff -r 84a95e20f93a -r a83775113025 nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c Fri Nov 17 18:55:07 2017 +0300
+++ b/nginx/ngx_stream_js_module.c Fri Nov 17 18:55:07 2017 +0300
@@ -408,7 +408,7 @@ ngx_stream_js_phase_handler(ngx_stream_s
}
if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
- njs_vm_exception(ctx->vm, &exception);
+ njs_vm_retval(ctx->vm, &exception);
ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %*s",
exception.length, exception.start);
@@ -495,7 +495,7 @@ ngx_stream_js_body_filter(ngx_stream_ses
ctx->buf = in->buf;
if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
- njs_vm_exception(ctx->vm, &exception);
+ njs_vm_retval(ctx->vm, &exception);
ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %*s",
exception.length, exception.start);
@@ -593,7 +593,7 @@ ngx_stream_js_variable(ngx_stream_sessio
}
if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
- njs_vm_exception(ctx->vm, &exception);
+ njs_vm_retval(ctx->vm, &exception);
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
"js exception: %*s", exception.length, exception.start);
@@ -1043,7 +1043,7 @@ ngx_stream_js_include(ngx_conf_t *cf, ng
rc = njs_vm_compile(jscf->vm, &start, end);
if (rc != NJS_OK) {
- njs_vm_exception(jscf->vm, &text);
+ njs_vm_retval(jscf->vm, &text);
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"%*s, included",
diff -r 84a95e20f93a -r a83775113025 njs/njs.c
--- a/njs/njs.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs.c Fri Nov 17 18:55:07 2017 +0300
@@ -64,7 +64,6 @@ static nxt_int_t njs_interactive_shell(n
static nxt_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options);
static nxt_int_t njs_process_script(njs_vm_t *vm, njs_opts_t *opts,
const nxt_str_t *script, nxt_str_t *out);
-static void njs_print_backtrace(nxt_array_t *backtrace);
static nxt_int_t njs_editline_init(njs_vm_t *vm);
static char **njs_completion_handler(const char *text, int start, int end);
static char *njs_completion_generator(const char *text, int state);
@@ -240,10 +239,9 @@ njs_externals_init(njs_opts_t *opts, njs
static nxt_int_t
njs_interactive_shell(njs_opts_t *opts, njs_vm_opt_t *vm_options)
{
- njs_vm_t *vm;
- nxt_int_t ret;
- nxt_str_t line, out;
- nxt_array_t *backtrace;
+ njs_vm_t *vm;
+ nxt_int_t ret;
+ nxt_str_t line, out;
vm = njs_vm_create(vm_options);
if (vm == NULL) {
@@ -282,11 +280,6 @@ njs_interactive_shell(njs_opts_t *opts,
printf("%.*s\n", (int) out.length, out.start);
- backtrace = njs_vm_backtrace(vm);
- if (backtrace != NULL) {
- njs_print_backtrace(backtrace);
- }
-
/* editline allocs a new buffer every time. */
free(line.start);
}
@@ -307,7 +300,6 @@ njs_process_file(njs_opts_t *opts, njs_v
nxt_int_t ret;
nxt_str_t out, script;
struct stat sb;
- nxt_array_t *backtrace;
file = opts->file;
@@ -399,11 +391,6 @@ njs_process_file(njs_opts_t *opts, njs_v
if (!opts->disassemble) {
printf("%.*s\n", (int) out.length, out.start);
-
- backtrace = njs_vm_backtrace(vm);
- if (backtrace != NULL) {
- njs_print_backtrace(backtrace);
- }
}
ret = NXT_OK;
@@ -442,44 +429,19 @@ njs_process_script(njs_vm_t *vm, njs_opt
}
ret = njs_vm_run(vm);
-
- if (ret == NXT_OK) {
- if (njs_vm_retval(vm, out) != NXT_OK) {
- return NXT_ERROR;
- }
+ if (ret == NXT_AGAIN) {
+ return ret;
+ }
+ }
- } else {
- njs_vm_exception(vm, out);
- }
-
- } else {
- njs_vm_exception(vm, out);
+ if (njs_vm_retval(vm, out) != NXT_OK) {
+ return NXT_ERROR;
}
return NXT_OK;
}
-static void
-njs_print_backtrace(nxt_array_t *backtrace)
-{
- nxt_uint_t i;
- njs_backtrace_entry_t *be;
-
- be = backtrace->start;
-
- for (i = 0; i < backtrace->items; i++) {
- if (be[i].line != 0) {
- printf("at %.*s (:%d)\n", (int) be[i].name.length, be[i].name.start,
- be[i].line);
-
- } else {
- printf("at %.*s\n", (int) be[i].name.length, be[i].name.start);
- }
- }
-}
-
-
static nxt_int_t
njs_editline_init(njs_vm_t *vm)
{
diff -r 84a95e20f93a -r a83775113025 njs/njs_error.c
--- a/njs/njs_error.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_error.c Fri Nov 17 18:55:07 2017 +0300
@@ -37,7 +37,7 @@ njs_exception_error_create(njs_vm_t *vm,
size_t size;
va_list args;
nxt_int_t ret;
- njs_value_t string, *value;
+ njs_value_t string;
njs_object_t *error;
static char buf[256];
@@ -61,16 +61,9 @@ njs_exception_error_create(njs_vm_t *vm,
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;
+ vm->retval.data.u.object = error;
+ vm->retval.type = type;
+ vm->retval.data.truth = 1;
return;
@@ -495,9 +488,8 @@ const njs_object_init_t njs_uri_error_c
static void
-njs_init_memory_error(njs_vm_t *vm)
+njs_set_memory_error(njs_vm_t *vm)
{
- njs_value_t *value;
njs_object_t *object;
njs_object_prototype_t *prototypes;
@@ -516,21 +508,17 @@ njs_init_memory_error(njs_vm_t *vm)
*/
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;
+ vm->retval.data.type = NJS_OBJECT_INTERNAL_ERROR;
+ vm->retval.data.truth = 1;
+ vm->retval.data.u.number = NAN;
+ vm->retval.data.u.object = object;
}
void
njs_exception_memory_error(njs_vm_t *vm)
{
- njs_init_memory_error(vm);
-
- vm->exception = &vm->memory_error;
+ njs_set_memory_error(vm);
}
@@ -538,9 +526,7 @@ 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;
+ njs_set_memory_error(vm);
return NXT_OK;
}
diff -r 84a95e20f93a -r a83775113025 njs/njs_function.c
--- a/njs/njs_function.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_function.c Fri Nov 17 18:55:07 2017 +0300
@@ -701,6 +701,8 @@ njs_ret_t
njs_eval_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t unused)
{
+ njs_exception_internal_error(vm, "Not implemented", NULL);
+
return NXT_ERROR;
}
diff -r 84a95e20f93a -r a83775113025 njs/njs_generator.c
--- a/njs/njs_generator.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_generator.c Fri Nov 17 18:55:07 2017 +0300
@@ -1150,8 +1150,7 @@ njs_generate_continue_statement(njs_vm_t
}
}
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Illegal continue statement");
+ njs_parser_syntax_error(vm, parser, "Illegal continue statement", NULL);
return NXT_ERROR;
@@ -1194,8 +1193,7 @@ njs_generate_break_statement(njs_vm_t *v
}
}
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Illegal break statement");
+ njs_parser_syntax_error(vm, parser, "Illegal break statement", NULL);
return NXT_ERROR;
diff -r 84a95e20f93a -r a83775113025 njs/njs_parser.c
--- a/njs/njs_parser.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_parser.c Fri Nov 17 18:55:07 2017 +0300
@@ -21,6 +21,7 @@
#include <njs_string.h>
#include <njs_object.h>
#include <njs_function.h>
+#include <njs_error.h>
#include <njs_variable.h>
#include <njs_parser.h>
#include <njs_regexp.h>
@@ -196,9 +197,9 @@ njs_parser_scope_begin(njs_vm_t *vm, njs
break;
}
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR, "SyntaxError: "
- "The maximum function nesting level is \"%d\"",
- NJS_MAX_NESTING);
+ njs_parser_syntax_error(vm, parser,
+ "The maximum function nesting "
+ "level is \"%d\"", NJS_MAX_NESTING);
return NXT_ERROR;
}
@@ -310,7 +311,7 @@ njs_parser_statement_chain(njs_vm_t *vm,
}
}
- } else if (vm->exception == NULL) {
+ } else if (!njs_is_error(&vm->retval)) {
(void) njs_parser_unexpected_token(vm, parser, token);
}
@@ -770,8 +771,8 @@ njs_parser_return_statement(njs_vm_t *vm
scope = scope->parent)
{
if (scope->type == NJS_SCOPE_GLOBAL) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Illegal return statement");
+ njs_parser_syntax_error(vm, parser, "Illegal return statement",
+ NULL);
return NXT_ERROR;
}
@@ -1053,9 +1054,9 @@ njs_parser_switch_statement(njs_vm_t *vm
} else {
if (dflt != NULL) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: More than one default clause "
- "in switch statement");
+ njs_parser_syntax_error(vm, parser,
+ "More than one default clause "
+ "in switch statement", NULL);
return NJS_TOKEN_ILLEGAL;
}
@@ -1461,9 +1462,9 @@ njs_parser_for_in_statement(njs_vm_t *vm
node = parser->node->left;
if (node->token != NJS_TOKEN_NAME) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR, "ReferenceError: Invalid "
- "left-hand side \"%.*s\" in for-in statement",
- (int) name->length, name->start);
+ njs_parser_ref_error(vm, parser, "Invalid left-hand side \"%.*s\" "
+ "in for-in statement", (int) name->length,
+ name->start);
return NJS_TOKEN_ILLEGAL;
}
@@ -1686,8 +1687,8 @@ njs_parser_try_statement(njs_vm_t *vm, n
}
if (try->right == NULL) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Missing catch or finally after try");
+ njs_parser_syntax_error(vm, parser, "Missing catch or "
+ "finally after try", NULL);
return NJS_TOKEN_ILLEGAL;
}
@@ -1936,9 +1937,9 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa
break;
case NJS_TOKEN_UNTERMINATED_STRING:
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Unterminated string \"%.*s\"",
- (int) parser->lexer->text.length, parser->lexer->text.start);
+ njs_parser_syntax_error(vm, parser, "Unterminated string \"%.*s\"",
+ (int) parser->lexer->text.length,
+ parser->lexer->text.start);
return NJS_TOKEN_ILLEGAL;
@@ -2540,9 +2541,9 @@ njs_parser_escape_string_create(njs_vm_t
invalid:
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Invalid Unicode code point \"%.*s\"",
- (int) parser->lexer->text.length, parser->lexer->text.start);
+ njs_parser_syntax_error(vm, parser, "Invalid Unicode code point \"%.*s\"",
+ (int) parser->lexer->text.length,
+ parser->lexer->text.start);
return NJS_TOKEN_ILLEGAL;
}
@@ -2584,13 +2585,12 @@ njs_parser_unexpected_token(njs_vm_t *vm
njs_token_t token)
{
if (token != NJS_TOKEN_END) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Unexpected token \"%.*s\"",
- (int) parser->lexer->text.length, parser->lexer->text.start);
+ njs_parser_syntax_error(vm, parser, "Unexpected token \"%.*s\"",
+ (int) parser->lexer->text.length,
+ parser->lexer->text.start);
} else {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Unexpected end of input");
+ njs_parser_syntax_error(vm, parser, "Unexpected end of input", NULL);
}
return NJS_TOKEN_ILLEGAL;
@@ -2601,18 +2601,13 @@ u_char *
njs_parser_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td,
u_char *start)
{
- int n;
u_char *p;
- ssize_t size;
+ size_t size;
njs_vm_t *vm;
- p = start;
-
- if (td->level == NXT_LEVEL_CRIT) {
- size = sizeof("InternalError: ") - 1;
- memcpy(p, "InternalError: ", size);
- p = start + size;
- }
+ size = sizeof("InternalError: ") - 1;
+ memcpy(start, "InternalError: ", size);
+ p = start + size;
vm = trace->data;
@@ -2620,16 +2615,43 @@ njs_parser_trace_handler(nxt_trace_t *tr
p = trace->handler(trace, td, p);
if (vm->parser != NULL) {
- size = td->end - start;
-
- n = snprintf((char *) p, size, " in %u", vm->parser->lexer->line);
-
- if (n < size) {
- p += n;
- }
+ njs_exception_internal_error(vm, "%s in %u", start,
+ vm->parser->lexer->line);
+ } else {
+ njs_exception_internal_error(vm, "%s", start);
}
- njs_vm_throw_exception(vm, start, p - start);
-
return p;
}
+
+
+void
+njs_parser_syntax_error(njs_vm_t *vm, njs_parser_t *parser, const char* fmt,
+ ...)
+{
+ va_list args;
+
+ static char buf[256];
+
+ va_start(args, fmt);
+ (void) vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ njs_exception_syntax_error(vm, "%s in %u", buf, parser->lexer->line);
+}
+
+
+void
+njs_parser_ref_error(njs_vm_t *vm, njs_parser_t *parser, const char* fmt,
+ ...)
+{
+ va_list args;
+
+ static char buf[256];
+
+ va_start(args, fmt);
+ (void) vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ njs_exception_ref_error(vm, "%s in %u", buf, parser->lexer->line);
+}
diff -r 84a95e20f93a -r a83775113025 njs/njs_parser.h
--- a/njs/njs_parser.h Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_parser.h Fri Nov 17 18:55:07 2017 +0300
@@ -381,6 +381,10 @@ njs_index_t njs_variable_index(njs_vm_t
nxt_bool_t njs_parser_has_side_effect(njs_parser_node_t *node);
u_char *njs_parser_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td,
u_char *start);
+void njs_parser_syntax_error(njs_vm_t *vm, njs_parser_t *parser,
+ const char* fmt, ...);
+void njs_parser_ref_error(njs_vm_t *vm, njs_parser_t *parser, const char* fmt,
+ ...);
nxt_int_t njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node);
diff -r 84a95e20f93a -r a83775113025 njs/njs_parser_expression.c
--- a/njs/njs_parser_expression.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_parser_expression.c Fri Nov 17 18:55:07 2017 +0300
@@ -294,8 +294,8 @@ njs_parser_var_expression(njs_vm_t *vm,
}
if (!njs_parser_is_lvalue(parser->node)) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "ReferenceError: Invalid left-hand side in assignment");
+ njs_parser_ref_error(vm, parser,
+ "Invalid left-hand side in assignment", NULL);
return NJS_TOKEN_ILLEGAL;
}
@@ -432,8 +432,8 @@ njs_parser_assignment_expression(njs_vm_
}
if (!njs_parser_is_lvalue(parser->node)) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "ReferenceError: Invalid left-hand side in assignment");
+ njs_parser_ref_error(vm, parser, "Invalid left-hand side "
+ "in assignment", NULL);
return NJS_TOKEN_ILLEGAL;
}
@@ -756,9 +756,8 @@ njs_parser_unary_expression(njs_vm_t *vm
}
if (next == NJS_TOKEN_EXPONENTIATION) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Either left-hand side or entire exponentiation "
- "must be parenthesized");
+ njs_parser_syntax_error(vm, parser, "Either left-hand side or entire "
+ "exponentiation must be parenthesized");
return NJS_TOKEN_ILLEGAL;
}
@@ -796,8 +795,8 @@ njs_parser_unary_expression(njs_vm_t *vm
case NJS_TOKEN_NAME:
case NJS_TOKEN_UNDEFINED:
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Delete of an unqualified identifier");
+ njs_parser_syntax_error(vm, parser,
+ "Delete of an unqualified identifier", NULL);
return NJS_TOKEN_ILLEGAL;
@@ -856,8 +855,8 @@ njs_parser_inc_dec_expression(njs_vm_t *
}
if (!njs_parser_is_lvalue(parser->node)) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "ReferenceError: Invalid left-hand side in prefix operation");
+ njs_parser_ref_error(vm, parser, "Invalid left-hand side "
+ "in prefix operation", NULL);
return NJS_TOKEN_ILLEGAL;
}
@@ -911,8 +910,8 @@ njs_parser_post_inc_dec_expression(njs_v
}
if (!njs_parser_is_lvalue(parser->node)) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "ReferenceError: Invalid left-hand side in postfix operation");
+ njs_parser_ref_error(vm, parser, "Invalid left-hand side "
+ "in postfix operation", NULL);
return NJS_TOKEN_ILLEGAL;
}
diff -r 84a95e20f93a -r a83775113025 njs/njs_regexp.c
--- a/njs/njs_regexp.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_regexp.c Fri Nov 17 18:55:07 2017 +0300
@@ -178,9 +178,9 @@ njs_regexp_literal(njs_vm_t *vm, njs_par
flags = njs_regexp_flags(&p, lexer->end, 0);
if (nxt_slow_path(flags < 0)) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Invalid RegExp flags \"%.*s\"",
- p - lexer->start, lexer->start);
+ njs_parser_syntax_error(vm, parser,
+ "Invalid RegExp flags \"%.*s\"",
+ p - lexer->start, lexer->start);
return NJS_TOKEN_ILLEGAL;
}
@@ -199,9 +199,8 @@ njs_regexp_literal(njs_vm_t *vm, njs_par
}
}
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Unterminated RegExp \"%.*s\"",
- p - lexer->start - 1, lexer->start - 1);
+ njs_parser_syntax_error(vm, parser, "Unterminated RegExp \"%.*s\"",
+ p - lexer->start - 1, lexer->start - 1);
return NJS_TOKEN_ILLEGAL;
}
@@ -386,9 +385,8 @@ static u_char *
njs_regexp_compile_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td,
u_char *start)
{
- int n;
u_char *p;
- ssize_t size;
+ size_t size;
njs_vm_t *vm;
size = sizeof("SyntaxError: ") - 1;
@@ -398,20 +396,16 @@ njs_regexp_compile_trace_handler(nxt_tra
vm = trace->data;
trace = trace->next;
- p = trace->handler(trace, td, p);
+ p = trace->handler(trace, td, start);
if (vm->parser != NULL) {
- size = td->end - start;
-
- n = snprintf((char *) p, size, " in %u", vm->parser->lexer->line);
+ njs_exception_syntax_error(vm, "%s in %u", start,
+ vm->parser->lexer->line);
- if (n < size) {
- p += n;
- }
+ } else {
+ njs_exception_syntax_error(vm, "%s", start);
}
- njs_vm_throw_exception(vm, start, p - start);
-
return p;
}
@@ -442,8 +436,8 @@ njs_regexp_match_trace_handler(nxt_trace
size_t size;
njs_vm_t *vm;
- size = sizeof("RegExpError: ") - 1;
- memcpy(start, "RegExpError: ", size);
+ size = sizeof("InternalError: ") - 1;
+ memcpy(start, "InternalError: ", size);
p = start + size;
vm = trace->data;
@@ -451,7 +445,7 @@ njs_regexp_match_trace_handler(nxt_trace
trace = trace->next;
p = trace->handler(trace, td, p);
- njs_vm_throw_exception(vm, start, p - start);
+ njs_exception_internal_error(vm, (const char *) start, NULL);
return p;
}
diff -r 84a95e20f93a -r a83775113025 njs/njs_variable.c
--- a/njs/njs_variable.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_variable.c Fri Nov 17 18:55:07 2017 +0300
@@ -20,6 +20,7 @@
#include <njs_vm.h>
#include <njs_variable.h>
#include <njs_parser.h>
+#include <njs_error.h>
#include <string.h>
@@ -156,9 +157,9 @@ njs_variable_add(njs_vm_t *vm, njs_parse
/* ret == NXT_DECLINED. */
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "SyntaxError: Identifier \"%.*s\" has already been declared",
- (int) lhq.key.length, lhq.key.start);
+ njs_parser_syntax_error(vm, parser, "Identifier \"%.*s\" "
+ "has already been declared",
+ (int) lhq.key.length, lhq.key.start);
return NULL;
}
@@ -342,8 +343,8 @@ njs_variable_get(njs_vm_t *vm, njs_parse
index = (index >> NJS_SCOPE_SHIFT) + 1;
if (index > 255 || vs.scope->argument_closures == 0) {
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "InternalError: too many argument closures");
+ njs_exception_internal_error(vm, "too many argument closures",
+ NULL);
return NULL;
}
@@ -405,9 +406,8 @@ njs_variable_get(njs_vm_t *vm, njs_parse
not_found:
- nxt_alert(&vm->trace, NXT_LEVEL_ERROR,
- "ReferenceError: \"%.*s\" is not defined",
- (int) vs.lhq.key.length, vs.lhq.key.start);
+ njs_parser_ref_error(vm, vm->parser, "\"%.*s\" is not defined",
+ (int) vs.lhq.key.length, vs.lhq.key.start);
return NULL;
}
diff -r 84a95e20f93a -r a83775113025 njs/njs_vm.c
--- a/njs/njs_vm.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_vm.c Fri Nov 17 18:55:07 2017 +0300
@@ -3454,25 +3454,6 @@ njs_value_string_copy(njs_vm_t *vm, nxt_
}
-void
-njs_vm_throw_exception(njs_vm_t *vm, const u_char *buf, uint32_t size)
-{
- int32_t length;
- njs_value_t *value;
-
- value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t));
-
- if (nxt_fast_path(value != NULL)) {
- vm->exception = value;
-
- length = nxt_utf8_length(buf, size);
- length = (length >= 0) ? length : 0;
-
- (void) njs_string_new(vm, value, buf, size, length);
- }
-}
-
-
static njs_ret_t
njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_frame_t *frame)
{
diff -r 84a95e20f93a -r a83775113025 njs/njs_vm.h
--- a/njs/njs_vm.h Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njs_vm.h Fri Nov 17 18:55:07 2017 +0300
@@ -931,8 +931,6 @@ struct njs_vm_s {
njs_native_frame_t *top_frame;
njs_frame_t *active_frame;
- const njs_value_t *exception;
-
nxt_lvlhsh_t externals_hash;
nxt_lvlhsh_t variables_hash;
nxt_lvlhsh_t values_hash;
@@ -962,7 +960,6 @@ struct njs_vm_s {
* 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 */
@@ -1146,8 +1143,6 @@ njs_ret_t njs_value_to_ext_string(njs_vm
const njs_value_t *src);
void njs_number_set(njs_value_t *value, double num);
-void njs_vm_throw_exception(njs_vm_t *vm, const u_char *buf, uint32_t size);
-
nxt_int_t njs_builtin_objects_create(njs_vm_t *vm);
nxt_int_t njs_builtin_objects_clone(njs_vm_t *vm);
nxt_int_t njs_builtin_match_native_function(njs_vm_t *vm,
diff -r 84a95e20f93a -r a83775113025 njs/njscript.c
--- a/njs/njscript.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njscript.c Fri Nov 17 18:55:07 2017 +0300
@@ -24,6 +24,7 @@
#include <njs_parser.h>
#include <njs_regexp.h>
#include <string.h>
+#include <stdio.h>
static nxt_int_t njs_vm_init(njs_vm_t *vm);
@@ -198,6 +199,8 @@ njs_vm_create(njs_vm_opt_t *options)
if (nxt_slow_path(ret != NXT_OK)) {
return NULL;
}
+
+ vm->retval = njs_value_void;
}
}
@@ -246,6 +249,10 @@ njs_vm_compile(njs_vm_t *vm, u_char **st
parser->code_size = sizeof(njs_vmcode_stop_t);
parser->scope_offset = NJS_INDEX_GLOBAL_OFFSET;
+ if (vm->backtrace != NULL) {
+ nxt_array_reset(vm->backtrace);
+ }
+
node = njs_parser(vm, parser, prev);
if (nxt_slow_path(node == NULL)) {
goto fail;
@@ -264,10 +271,6 @@ njs_vm_compile(njs_vm_t *vm, u_char **st
*/
vm->code = NULL;
- if (vm->backtrace != NULL) {
- nxt_array_reset(vm->backtrace);
- }
-
ret = njs_generate_scope(vm, parser, node);
if (nxt_slow_path(ret != NXT_OK)) {
goto fail;
@@ -334,6 +337,8 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache
goto fail;
}
+ nvm->retval = njs_value_void;
+
return nvm;
}
@@ -402,8 +407,6 @@ njs_vm_init(njs_vm_t *vm)
vm->backtrace = backtrace;
}
- vm->retval = njs_value_void;
-
vm->trace.level = NXT_LEVEL_TRACE;
vm->trace.size = 2048;
vm->trace.handler = njs_parser_trace_handler;
@@ -464,6 +467,10 @@ njs_vm_run(njs_vm_t *vm)
nxt_thread_log_debug("RUN:");
+ if (vm->backtrace != NULL) {
+ nxt_array_reset(vm->backtrace);
+ }
+
ret = njs_vmcode_interpreter(vm);
if (nxt_slow_path(ret == NXT_AGAIN)) {
@@ -515,18 +522,76 @@ njs_vm_return_string(njs_vm_t *vm, u_cha
nxt_int_t
njs_vm_retval(njs_vm_t *vm, nxt_str_t *retval)
{
- return njs_value_to_ext_string(vm, retval, &vm->retval);
-}
+ u_char *p, *start;
+ size_t len;
+ nxt_int_t ret;
+ nxt_uint_t i;
+ nxt_array_t *backtrace;
+ njs_backtrace_entry_t *be;
+ if (vm->top_frame == NULL) {
+ /* An exception was thrown during compilation. */
-nxt_int_t
-njs_vm_exception(njs_vm_t *vm, nxt_str_t *retval)
-{
- if (vm->top_frame != NULL) {
+ njs_vm_init(vm);
+ }
+
+ ret = njs_value_to_ext_string(vm, retval, &vm->retval);
+
+ if (ret != NXT_OK) {
+ /* retval evaluation threw an exception. */
+
vm->top_frame->trap_tries = 0;
+
+ ret = njs_value_to_ext_string(vm, retval, &vm->retval);
+ if (ret != NXT_OK) {
+ return ret;
+ }
}
- return njs_value_to_ext_string(vm, retval, vm->exception);
+ backtrace = njs_vm_backtrace(vm);
+
+ if (backtrace != NULL) {
+
+ len = retval->length + 1;
+
+ be = backtrace->start;
+
+ for (i = 0; i < backtrace->items; i++) {
+ if (be[i].line != 0) {
+ len += sizeof(" at (:)\n") - 1 + 10 + be[i].name.length;
+
+ } else {
+ len += sizeof(" at (native)\n") - 1 + be[i].name.length;
+ }
+ }
+
+ p = nxt_mem_cache_alloc(vm->mem_cache_pool, len);
+ if (p == NULL) {
+ return NXT_ERROR;
+ }
+
+ start = p;
+
+ p = nxt_cpymem(p, retval->start, retval->length);
+ *p++ = '\n';
+
+ for (i = 0; i < backtrace->items; i++) {
+ if (be[i].line != 0) {
+ p += sprintf((char *) p, " at %.*s (:%u)\n",
+ (int) be[i].name.length, be[i].name.start,
+ be[i].line);
+
+ } else {
+ p += sprintf((char *) p, " at %.*s (native)\n",
+ (int) be[i].name.length, be[i].name.start);
+ }
+ }
+
+ retval->start = start;
+ retval->length = p - retval->start;
+ }
+
+ return NXT_OK;
}
diff -r 84a95e20f93a -r a83775113025 njs/njscript.h
--- a/njs/njscript.h Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/njscript.h Fri Nov 17 18:55:07 2017 +0300
@@ -110,7 +110,6 @@ NXT_EXPORT njs_function_t *njs_vm_functi
NXT_EXPORT njs_ret_t njs_vm_return_string(njs_vm_t *vm, u_char *start,
size_t size);
NXT_EXPORT nxt_int_t njs_vm_retval(njs_vm_t *vm, nxt_str_t *retval);
-NXT_EXPORT nxt_int_t njs_vm_exception(njs_vm_t *vm, nxt_str_t *retval);
NXT_EXPORT nxt_array_t *njs_vm_backtrace(njs_vm_t *vm);
NXT_EXPORT void njs_disassembler(njs_vm_t *vm);
diff -r 84a95e20f93a -r a83775113025 njs/test/njs_benchmark.c
--- a/njs/test/njs_benchmark.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/test/njs_benchmark.c Fri Nov 17 18:55:07 2017 +0300
@@ -111,13 +111,10 @@ njs_unit_test_benchmark(nxt_str_t *scrip
return NXT_ERROR;
}
- if (njs_vm_run(nvm) == NXT_OK) {
- if (njs_vm_retval(nvm, &s) != NXT_OK) {
- return NXT_ERROR;
- }
+ (void) njs_vm_run(nvm);
- } else {
- njs_vm_exception(nvm, &s);
+ if (njs_vm_retval(nvm, &s) != NXT_OK) {
+ return NXT_ERROR;
}
success = nxt_strstr_eq(result, &s);
diff -r 84a95e20f93a -r a83775113025 njs/test/njs_expect_test.exp
--- a/njs/test/njs_expect_test.exp Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/test/njs_expect_test.exp Fri Nov 17 18:55:07 2017 +0300
@@ -166,3 +166,19 @@ njs_test {
{"console.help()\r\n"
"console.help()\r\nVM built-in objects:"}
}
+
+# Exception in njs_vm_retval()
+njs_test {
+ {"var o = { toString: function() { return [1] } }\r\n"
+ "undefined\r\n>> "}
+ {"o\r\n"
+ "TypeError"}
+}
+
+# Backtraces are reset between invocations
+njs_test {
+ {"JSON.parse(Error())\r\n"
+ "JSON.parse(Error())\r\nSyntaxError: Unexpected token at position 0*at JSON.parse (native)"}
+ {"JSON.parse(Error()\r\n"
+ "JSON.parse(Error()\r\nSyntaxError: Unexpected token \"\" in 1"}
+}
diff -r 84a95e20f93a -r a83775113025 njs/test/njs_interactive_test.c
--- a/njs/test/njs_interactive_test.c Fri Nov 17 18:55:07 2017 +0300
+++ b/njs/test/njs_interactive_test.c Fri Nov 17 18:55:07 2017 +0300
@@ -121,69 +121,73 @@ static njs_interactive_test_t njs_test[
"function f(o) {return ff(o)}" ENTER
"f({})" ENTER),
nxt_string("TypeError\n"
- "at ff (:1)\n"
- "at f (:1)\n"
- "at main\n") },
+ " at ff (:1)\n"
+ " at f (:1)\n"
+ " at main (native)\n") },
{ nxt_string("function ff(o) {return o.a.a}" ENTER
"function f(o) {try {return ff(o)} "
"finally {return o.a.a}}" ENTER
"f({})" ENTER),
nxt_string("TypeError\n"
- "at f (:1)\n"
- "at main\n") },
+ " at f (:1)\n"
+ " at main (native)\n") },
More information about the nginx-devel
mailing list