Welcome! Log In Create A New Profile

Advanced

[njs] Introduced line level backtrace.

Dmitry Volyntsev
June 18, 2020 02:58PM
details: https://hg.nginx.org/njs/rev/ea2ec4c3ed7d
branches:
changeset: 1435:ea2ec4c3ed7d
user: Dmitry Volyntsev <xeioex@nginx.com>
date: Thu Jun 18 18:56:24 2020 +0000
description:
Introduced line level backtrace.

This closes #140 issue on Github.

diffstat:

src/njs.h | 1 -
src/njs_disassembler.c | 119 +++++++------
src/njs_error.c | 135 ++++++++++++++++-
src/njs_function.c | 17 +-
src/njs_function.h | 1 +
src/njs_generator.c | 383 ++++++++++++++++++++++++++--------------------
src/njs_generator.h | 5 +-
src/njs_vm.c | 151 +-----------------
src/njs_vm.h | 32 +--
src/njs_vmcode.c | 5 +-
src/test/njs_unit_test.c | 72 +++++--
test/njs_expect_test.exp | 16 +-
12 files changed, 503 insertions(+), 434 deletions(-)

diffs (truncated from 2138 to 1000 lines):

diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs.h
--- a/src/njs.h Wed Jun 17 14:38:23 2020 +0000
+++ b/src/njs.h Thu Jun 18 18:56:24 2020 +0000
@@ -293,7 +293,6 @@ NJS_EXPORT njs_function_t *njs_vm_functi
njs_function_native_t native);

NJS_EXPORT void njs_disassembler(njs_vm_t *vm);
-NJS_EXPORT void njs_disassemble(u_char *start, u_char *end);

NJS_EXPORT njs_int_t njs_vm_bind(njs_vm_t *vm, const njs_str_t *var_name,
const njs_value_t *value, njs_bool_t shared);
diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs_disassembler.c
--- a/src/njs_disassembler.c Wed Jun 17 14:38:23 2020 +0000
+++ b/src/njs_disassembler.c Thu Jun 18 18:56:24 2020 +0000
@@ -15,6 +15,9 @@ typedef struct {
} njs_code_name_t;


+static void njs_disassemble(njs_vm_code_t *code);
+
+
static njs_code_name_t code_names[] = {

{ NJS_VMCODE_OBJECT, sizeof(njs_vmcode_object_t),
@@ -143,11 +146,12 @@ njs_disassembler(njs_vm_t *vm)
njs_vm_code_t *code;

code = vm->codes->start;
- n = vm->codes->items;
+ code += vm->main_index;
+ n = vm->codes->items - vm->main_index;

while (n != 0) {
njs_printf("%V:%V\n", &code->file, &code->name);
- njs_disassemble(code->start, code->end);
+ njs_disassemble(code);
code++;
n--;
}
@@ -156,10 +160,11 @@ njs_disassembler(njs_vm_t *vm)
}


-void
-njs_disassemble(u_char *start, u_char *end)
+static void
+njs_disassemble(njs_vm_code_t *code)
{
- u_char *p;
+ u_char *p, *start, *end;
+ uint32_t line;
njs_str_t *name;
njs_uint_t n;
njs_code_name_t *code_name;
@@ -184,7 +189,8 @@ njs_disassemble(u_char *start, u_char *e
njs_vmcode_try_trampoline_t *try_tramp;
njs_vmcode_function_frame_t *function;

- p = start;
+ start = code->start;
+ end = code->end;

/*
* On some 32-bit platform uintptr_t is int and compilers warn
@@ -192,14 +198,17 @@ njs_disassemble(u_char *start, u_char *e
* there is no run-time overhead.
*/

+ p = start;
+
while (p < end) {
operation = *(njs_vmcode_operation_t *) p;
+ line = njs_lookup_line(code, p - start);

if (operation == NJS_VMCODE_ARRAY) {
array = (njs_vmcode_array_t *) p;

- njs_printf("%05uz ARRAY %04Xz %uz%s\n",
- p - start, (size_t) array->retval,
+ njs_printf("%5uD | %05uz ARRAY %04Xz %uz%s\n",
+ line, p - start, (size_t) array->retval,
(size_t) array->length, array->ctor ? " INIT" : "");

p += sizeof(njs_vmcode_array_t);
@@ -210,8 +219,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_IF_TRUE_JUMP) {
cond_jump = (njs_vmcode_cond_jump_t *) p;

- njs_printf("%05uz JUMP IF TRUE %04Xz %z\n",
- p - start, (size_t) cond_jump->cond,
+ njs_printf("%5uD | %05uz JUMP IF TRUE %04Xz %z\n",
+ line, p - start, (size_t) cond_jump->cond,
(size_t) cond_jump->offset);

p += sizeof(njs_vmcode_cond_jump_t);
@@ -222,8 +231,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_IF_FALSE_JUMP) {
cond_jump = (njs_vmcode_cond_jump_t *) p;

- njs_printf("%05uz JUMP IF FALSE %04Xz %z\n",
- p - start, (size_t) cond_jump->cond,
+ njs_printf("%5uD | %05uz JUMP IF FALSE %04Xz %z\n",
+ line, p - start, (size_t) cond_jump->cond,
(size_t) cond_jump->offset);

p += sizeof(njs_vmcode_cond_jump_t);
@@ -234,8 +243,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_JUMP) {
jump = (njs_vmcode_jump_t *) p;

- njs_printf("%05uz JUMP %z\n",
- p - start, (size_t) jump->offset);
+ njs_printf("%5uD | %05uz JUMP %z\n",
+ line, p - start, (size_t) jump->offset);

p += sizeof(njs_vmcode_jump_t);

@@ -245,8 +254,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_IF_EQUAL_JUMP) {
equal = (njs_vmcode_equal_jump_t *) p;

- njs_printf("%05uz JUMP IF EQUAL %04Xz %04Xz %z\n",
- p - start, (size_t) equal->value1,
+ njs_printf("%5uD | %05uz JUMP IF EQUAL %04Xz %04Xz %z\n",
+ line, p - start, (size_t) equal->value1,
(size_t) equal->value2, (size_t) equal->offset);

p += sizeof(njs_vmcode_equal_jump_t);
@@ -257,8 +266,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_TEST_IF_TRUE) {
test_jump = (njs_vmcode_test_jump_t *) p;

- njs_printf("%05uz TEST IF TRUE %04Xz %04Xz %z\n",
- p - start, (size_t) test_jump->retval,
+ njs_printf("%5uD | %05uz TEST IF TRUE %04Xz %04Xz %z\n",
+ line, p - start, (size_t) test_jump->retval,
(size_t) test_jump->value, (size_t) test_jump->offset);

p += sizeof(njs_vmcode_test_jump_t);
@@ -269,8 +278,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_TEST_IF_FALSE) {
test_jump = (njs_vmcode_test_jump_t *) p;

- njs_printf("%05uz TEST IF FALSE %04Xz %04Xz %z\n",
- p - start, (size_t) test_jump->retval,
+ njs_printf("%5uD | %05uz TEST IF FALSE %04Xz %04Xz %z\n",
+ line, p - start, (size_t) test_jump->retval,
(size_t) test_jump->value, (size_t) test_jump->offset);

p += sizeof(njs_vmcode_test_jump_t);
@@ -281,8 +290,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_COALESCE) {
test_jump = (njs_vmcode_test_jump_t *) p;

- njs_printf("%05uz COALESCE %04Xz %04Xz %z\n",
- p - start, (size_t) test_jump->retval,
+ njs_printf("%5uD | %05uz COALESCE %04Xz %04Xz %z\n",
+ line, p - start, (size_t) test_jump->retval,
(size_t) test_jump->value, (size_t) test_jump->offset);

p += sizeof(njs_vmcode_test_jump_t);
@@ -293,9 +302,9 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_FUNCTION_FRAME) {
function = (njs_vmcode_function_frame_t *) p;

- njs_printf("%05uz FUNCTION FRAME %04Xz %uz%s\n",
- p - start, (size_t) function->name, function->nargs,
- function->ctor ? " CTOR" : "");
+ njs_printf("%5uD | %05uz FUNCTION FRAME %04Xz %uz%s\n",
+ line, p - start, (size_t) function->name,
+ function->nargs, function->ctor ? " CTOR" : "");

p += sizeof(njs_vmcode_function_frame_t);

@@ -305,8 +314,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_METHOD_FRAME) {
method = (njs_vmcode_method_frame_t *) p;

- njs_printf("%05uz METHOD FRAME %04Xz %04Xz %uz%s\n",
- p - start, (size_t) method->object,
+ njs_printf("%5uD | %05uz METHOD FRAME %04Xz %04Xz %uz%s\n",
+ line, p - start, (size_t) method->object,
(size_t) method->method, method->nargs,
method->ctor ? " CTOR" : "");

@@ -317,8 +326,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_PROPERTY_FOREACH) {
prop_foreach = (njs_vmcode_prop_foreach_t *) p;

- njs_printf("%05uz PROP FOREACH %04Xz %04Xz %z\n",
- p - start, (size_t) prop_foreach->next,
+ njs_printf("%5uD | %05uz PROP FOREACH %04Xz %04Xz %z\n",
+ line, p - start, (size_t) prop_foreach->next,
(size_t) prop_foreach->object,
(size_t) prop_foreach->offset);

@@ -329,8 +338,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_PROPERTY_NEXT) {
prop_next = (njs_vmcode_prop_next_t *) p;

- njs_printf("%05uz PROP NEXT %04Xz %04Xz %04Xz %z\n",
- p - start, (size_t) prop_next->retval,
+ njs_printf("%5uD | %05uz PROP NEXT %04Xz %04Xz %04Xz %z\n",
+ line, p - start, (size_t) prop_next->retval,
(size_t) prop_next->object, (size_t) prop_next->next,
(size_t) prop_next->offset);

@@ -342,8 +351,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_PROPERTY_ACCESSOR) {
prop_accessor = (njs_vmcode_prop_accessor_t *) p;

- njs_printf("%05uz PROP %s ACCESSOR %04Xz %04Xz %04Xz\n",
- p - start,
+ njs_printf("%5uD | %05uz PROP %s ACCESSOR %04Xz %04Xz %04Xz\n",
+ line, p - start,
(prop_accessor->type == NJS_OBJECT_PROP_GETTER)
? "GET" : "SET",
(size_t) prop_accessor->value,
@@ -358,8 +367,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_TRY_START) {
try_start = (njs_vmcode_try_start_t *) p;

- njs_printf("%05uz TRY START %04Xz %04Xz %z\n",
- p - start, (size_t) try_start->exception_value,
+ njs_printf("%5uD | %05uz TRY START %04Xz %04Xz %z\n",
+ line, p - start, (size_t) try_start->exception_value,
(size_t) try_start->exit_value,
(size_t) try_start->offset);

@@ -371,8 +380,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_TRY_BREAK) {
try_tramp = (njs_vmcode_try_trampoline_t *) p;

- njs_printf("%05uz TRY BREAK %04Xz %z\n",
- p - start, (size_t) try_tramp->exit_value,
+ njs_printf("%5uD | %05uz TRY BREAK %04Xz %z\n",
+ line, p - start, (size_t) try_tramp->exit_value,
(size_t) try_tramp->offset);

p += sizeof(njs_vmcode_try_trampoline_t);
@@ -383,8 +392,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_TRY_CONTINUE) {
try_tramp = (njs_vmcode_try_trampoline_t *) p;

- njs_printf("%05uz TRY CONTINUE %04Xz %z\n",
- p - start, (size_t) try_tramp->exit_value,
+ njs_printf("%5uD | %05uz TRY CONTINUE %04Xz %z\n",
+ line, p - start, (size_t) try_tramp->exit_value,
(size_t) try_tramp->offset);

p += sizeof(njs_vmcode_try_trampoline_t);
@@ -395,8 +404,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_TRY_RETURN) {
try_return = (njs_vmcode_try_return_t *) p;

- njs_printf("%05uz TRY RETURN %04Xz %04Xz %z\n",
- p - start, (size_t) try_return->save,
+ njs_printf("%5uD | %05uz TRY RETURN %04Xz %04Xz %z\n",
+ line, p - start, (size_t) try_return->save,
(size_t) try_return->retval,
(size_t) try_return->offset);

@@ -408,8 +417,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_CATCH) {
catch = (njs_vmcode_catch_t *) p;

- njs_printf("%05uz CATCH %04Xz %z\n",
- p - start, (size_t) catch->exception,
+ njs_printf("%5uD | %05uz CATCH %04Xz %z\n",
+ line, p - start, (size_t) catch->exception,
(size_t) catch->offset);

p += sizeof(njs_vmcode_catch_t);
@@ -420,8 +429,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_TRY_END) {
try_end = (njs_vmcode_try_end_t *) p;

- njs_printf("%05uz TRY END %z\n",
- p - start, (size_t) try_end->offset);
+ njs_printf("%5uD | %05uz TRY END %z\n",
+ line, p - start, (size_t) try_end->offset);

p += sizeof(njs_vmcode_try_end_t);

@@ -431,8 +440,8 @@ njs_disassemble(u_char *start, u_char *e
if (operation == NJS_VMCODE_FINALLY) {
finally = (njs_vmcode_finally_t *) p;

- njs_printf("%05uz TRY FINALLY %04Xz %04Xz %z %z\n",
- p - start, (size_t) finally->retval,
+ njs_printf("%5uD | %05uz TRY FINALLY %04Xz %04Xz %z %z\n",
+ line, p - start, (size_t) finally->retval,
(size_t) finally->exit_value,
(size_t) finally->continue_offset,
(size_t) finally->break_offset);
@@ -443,7 +452,7 @@ njs_disassemble(u_char *start, u_char *e
}

if (operation == NJS_VMCODE_REFERENCE_ERROR) {
- njs_printf("%05uz REFERENCE ERROR\n", p - start);
+ njs_printf("%5uD | %05uz REFERENCE ERROR\n", line, p - start);

p += sizeof(njs_vmcode_reference_error_t);

@@ -460,23 +469,23 @@ njs_disassemble(u_char *start, u_char *e
if (code_name->size == sizeof(njs_vmcode_3addr_t)) {
code3 = (njs_vmcode_3addr_t *) p;

- njs_printf("%05uz %*s %04Xz %04Xz %04Xz\n",
- p - start, name->length, name->start,
+ njs_printf("%5uD | %05uz %*s %04Xz %04Xz %04Xz\n",
+ line, p - start, name->length, name->start,
(size_t) code3->dst, (size_t) code3->src1,
(size_t) code3->src2);

} else if (code_name->size == sizeof(njs_vmcode_2addr_t)) {
code2 = (njs_vmcode_2addr_t *) p;

- njs_printf("%05uz %*s %04Xz %04Xz\n",
- p - start, name->length, name->start,
+ njs_printf("%5uD | %05uz %*s %04Xz %04Xz\n",
+ line, p - start, name->length, name->start,
(size_t) code2->dst, (size_t) code2->src);

} else if (code_name->size == sizeof(njs_vmcode_1addr_t)) {
code1 = (njs_vmcode_1addr_t *) p;

- njs_printf("%05uz %*s %04Xz\n",
- p - start, name->length, name->start,
+ njs_printf("%5uD | %05uz %*s %04Xz\n",
+ line, p - start, name->length, name->start,
(size_t) code1->index);
}

@@ -490,7 +499,7 @@ njs_disassemble(u_char *start, u_char *e

} while (n != 0);

- njs_printf("%05uz UNKNOWN %04Xz\n",
+ njs_printf("%5uD | %05uz UNKNOWN %04Xz\n", line,
p - start, (size_t) (uintptr_t) operation);

p += sizeof(njs_vmcode_operation_t);
diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs_error.c
--- a/src/njs_error.c Wed Jun 17 14:38:23 2020 +0000
+++ b/src/njs_error.c Thu Jun 18 18:56:24 2020 +0000
@@ -8,6 +8,19 @@
#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");
@@ -84,7 +97,9 @@ njs_error_stack_new(njs_vm_t *vm, njs_ob
frame = vm->top_frame;

for ( ;; ) {
- if (njs_vm_add_backtrace_entry(vm, stack, frame) != NJS_OK) {
+ if ((frame->native || frame->pc != NULL)
+ && njs_add_backtrace_entry(vm, stack, frame) != NJS_OK)
+ {
break;
}

@@ -97,7 +112,7 @@ njs_error_stack_new(njs_vm_t *vm, njs_ob

njs_string_get(retval, &string);

- ret = njs_vm_backtrace_to_string(vm, stack, &string);
+ ret = njs_backtrace_to_string(vm, stack, &string);

njs_arr_destroy(stack);

@@ -121,7 +136,7 @@ njs_error_stack_attach(njs_vm_t *vm, njs
return NJS_DECLINED;
}

- if (vm->debug == NULL || vm->start == NULL) {
+ if (njs_slow_path(!vm->options.backtrace || vm->start == NULL)) {
return NJS_OK;
}

@@ -1147,3 +1162,117 @@ const njs_object_type_init_t njs_uri_er
.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;
+}
diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs_function.c
--- a/src/njs_function.c Wed Jun 17 14:38:23 2020 +0000
+++ b/src/njs_function.c Thu Jun 18 18:56:24 2020 +0000
@@ -371,6 +371,7 @@ njs_function_native_frame(njs_vm_t *vm,
frame->nargs = function->args_offset + nargs;
frame->ctor = ctor;
frame->native = 1;
+ frame->pc = NULL;

value = (njs_value_t *) ((u_char *) frame + NJS_NATIVE_FRAME_SIZE);
frame->arguments = value;
@@ -454,6 +455,7 @@ njs_function_lambda_frame(njs_vm_t *vm,
native_frame->nargs = nargs;
native_frame->ctor = ctor;
native_frame->native = 0;
+ native_frame->pc = NULL;

/* Function arguments. */

@@ -851,11 +853,11 @@ njs_function_constructor(njs_vm_t *vm, n
njs_value_t *body;
njs_lexer_t lexer;
njs_parser_t *parser;
+ njs_vm_code_t *code;
njs_function_t *function;
njs_generator_t generator;
njs_parser_scope_t *scope;
njs_function_lambda_t *lambda;
- njs_vmcode_function_t *code;

if (!vm->options.unsafe) {
body = njs_argument(args, nargs - 1);
@@ -949,15 +951,18 @@ njs_function_constructor(njs_vm_t *vm, n

njs_memzero(&generator, sizeof(njs_generator_t));

- ret = njs_generate_scope(vm, &generator, scope, &njs_entry_anonymous);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
+ code = njs_generate_scope(vm, &generator, scope, &njs_entry_anonymous);
+ if (njs_slow_path(code == NULL)) {
+ if (!njs_is_error(&vm->retval)) {
+ njs_internal_error(vm, "njs_generate_scope() failed");
+ }
+
+ return NJS_ERROR;
}

njs_chb_destroy(&chain);

- code = (njs_vmcode_function_t *) generator.code_start;
- lambda = code->lambda;
+ lambda = ((njs_vmcode_function_t *) generator.code_start)->lambda;

function = njs_function_alloc(vm, lambda, NULL, 0);
if (njs_slow_path(function == NULL)) {
diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs_function.h
--- a/src/njs_function.h Wed Jun 17 14:38:23 2020 +0000
+++ b/src/njs_function.h Thu Jun 18 18:56:24 2020 +0000
@@ -44,6 +44,7 @@ struct njs_function_lambda_s {

struct njs_native_frame_s {
u_char *free;
+ u_char *pc;

njs_function_t *function;
njs_native_frame_t *previous;
diff -r 02634f76f6d0 -r ea2ec4c3ed7d src/njs_generator.c
--- a/src/njs_generator.c Wed Jun 17 14:38:23 2020 +0000
+++ b/src/njs_generator.c Thu Jun 18 18:56:24 2020 +0000
@@ -57,6 +57,8 @@ static njs_int_t njs_generator(njs_vm_t
njs_parser_node_t *node);
static u_char *njs_generate_reserve(njs_vm_t *vm, njs_generator_t *generator,
size_t size);
+static njs_int_t njs_generate_code_map(njs_vm_t *vm, njs_generator_t *generator,
+ njs_parser_node_t *node, u_char *code);
static njs_int_t njs_generate_name(njs_vm_t *vm, njs_generator_t *generator,
njs_parser_node_t *node);
static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator,
@@ -179,18 +181,20 @@ static njs_int_t njs_generate_global_ref
static njs_int_t njs_generate_reference_error(njs_vm_t *vm,
njs_generator_t *generator, njs_parser_node_t *node);

-static njs_int_t njs_generate_function_debug(njs_vm_t *vm,
- const njs_str_t *name, njs_function_lambda_t *lambda,
- njs_parser_node_t *node);
-
-
-#define njs_generate_code(generator, type, _code, _op, nargs) \
+
+#define njs_generate_code(generator, type, _code, _op, nargs, nd) \
do { \
_code = (type *) njs_generate_reserve(vm, generator, sizeof(type)); \
if (njs_slow_path(_code == NULL)) { \
return NJS_ERROR; \
} \
\
+ if (njs_generate_code_map(vm, generator, nd, (u_char *) _code) \
+ != NJS_OK) \
+ { \
+ return NJS_ERROR; \
+ } \
+ \
generator->code_end += sizeof(type); \
\
_code->code.operation = _op; \
@@ -201,15 +205,15 @@ static njs_int_t njs_generate_function_d
#define njs_generate_code_jump(generator, _code, _offset) \
do { \
njs_generate_code(generator, njs_vmcode_jump_t, _code, \
- NJS_VMCODE_JUMP, 0); \
+ NJS_VMCODE_JUMP, 0, NULL); \
_code->offset = _offset; \
} while (0)


-#define njs_generate_code_move(generator, _code, _dst, _src) \
+#define njs_generate_code_move(generator, _code, _dst, _src, node) \
do { \
njs_generate_code(generator, njs_vmcode_move_t, _code, \
- NJS_VMCODE_MOVE, 2); \
+ NJS_VMCODE_MOVE, 2, node); \
_code->dst = _dst; \
_code->src = _src; \
} while (0)
@@ -536,6 +540,54 @@ njs_generate_reserve(njs_vm_t *vm, njs_g


static njs_int_t
+njs_generate_code_map(njs_vm_t *vm, njs_generator_t *generator,
+ njs_parser_node_t *node, u_char *code)
+{
+ njs_arr_t *map;
+ njs_vm_line_num_t *last;
+
+ map = generator->lines;
+
+ if (map != NULL && node != NULL) {
+ last = (map->items != 0) ? njs_arr_last(map) : NULL;
+ if (last == NULL || (node->token_line != last->line)) {
+ last = njs_arr_add(map);
+ if (njs_slow_path(last == NULL)) {
+ return NJS_ERROR;
+ }
+
+ last->line = node->token_line;
+ last->offset = njs_code_offset(generator, code);
+ }
+ }
+
+ return NJS_OK;
+}
+
+
+uint32_t
+njs_lookup_line(njs_vm_code_t *code, uint32_t offset)
+{
+ njs_uint_t n;
+ njs_vm_line_num_t *map;
+
+ n = (code->lines != NULL) ? code->lines->items : 0;
+ map = (njs_vm_line_num_t *) code->lines->start;
+
+ while (n != 0) {
+ if (offset >= map->offset && (n == 1 || offset < map[1].offset)) {
+ return map->line;
+ }
+
+ map++;
+ n--;
+ }
+
+ return 0;
+}
+
+
+static njs_int_t
njs_generate_name(njs_vm_t *vm, njs_generator_t *generator,
njs_parser_node_t *node)
{
@@ -552,7 +604,7 @@ njs_generate_name(njs_vm_t *vm, njs_gene
}

njs_generate_code(generator, njs_vmcode_object_copy_t, copy,
- NJS_VMCODE_OBJECT_COPY, 2);
+ NJS_VMCODE_OBJECT_COPY, 2, node);
copy->retval = node->index;
copy->object = var->index;

@@ -626,7 +678,8 @@ njs_generate_var_statement(njs_vm_t *vm,
* empty object or expression result is stored directly in variable.
*/
if (lvalue->index != expr->index) {
- njs_generate_code_move(generator, move, lvalue->index, expr->index);
+ njs_generate_code_move(generator, move, lvalue->index, expr->index,
+ lvalue);
}

node->index = expr->index;
@@ -653,7 +706,7 @@ njs_generate_if_statement(njs_vm_t *vm,
}

njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
- NJS_VMCODE_IF_FALSE_JUMP, 2);
+ NJS_VMCODE_IF_FALSE_JUMP, 2, node);
cond_jump->cond = node->left->index;

ret = njs_generate_node_index_release(vm, generator, node->left);
@@ -728,7 +781,7 @@ njs_generate_cond_expression(njs_vm_t *v
}

njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
- NJS_VMCODE_IF_FALSE_JUMP, 2);
+ NJS_VMCODE_IF_FALSE_JUMP, 2, node);

cond_jump_offset = njs_code_offset(generator, cond_jump);
cond_jump->cond = node->left->index;
@@ -755,7 +808,7 @@ njs_generate_cond_expression(njs_vm_t *v

if (node->index != branch->left->index) {
njs_generate_code_move(generator, move, node->index,
- branch->left->index);
+ branch->left->index, node);
}

ret = njs_generate_node_index_release(vm, generator, branch->left);
@@ -778,7 +831,7 @@ njs_generate_cond_expression(njs_vm_t *v

if (node->index != branch->right->index) {
njs_generate_code_move(generator, move, node->index,
- branch->right->index);
+ branch->right->index, node);
}

njs_code_set_jump_offset(generator, njs_vmcode_cond_jump_t, jump_offset);
@@ -822,7 +875,7 @@ njs_generate_switch_statement(njs_vm_t *
return NJS_ERROR;
}

- njs_generate_code_move(generator, move, index, expr->index);
+ njs_generate_code_move(generator, move, index, expr->index, swtch);
}

ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_SWITCH,
@@ -848,7 +901,7 @@ njs_generate_switch_statement(njs_vm_t *
}

njs_generate_code(generator, njs_vmcode_equal_jump_t, equal,
- NJS_VMCODE_IF_EQUAL_JUMP, 3);
+ NJS_VMCODE_IF_EQUAL_JUMP, 3, branch);
equal->offset = offsetof(njs_vmcode_equal_jump_t, offset);
equal->value1 = index;
equal->value2 = node->left->index;
@@ -971,7 +1024,7 @@ njs_generate_while_statement(njs_vm_t *v
}

njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
- NJS_VMCODE_IF_TRUE_JUMP, 2);
+ NJS_VMCODE_IF_TRUE_JUMP, 2, condition);
cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump);
cond_jump->cond = condition->index;

@@ -1017,7 +1070,7 @@ njs_generate_do_while_statement(njs_vm_t
}

njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
- NJS_VMCODE_IF_TRUE_JUMP, 2);
+ NJS_VMCODE_IF_TRUE_JUMP, 2, condition);
cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump);
cond_jump->cond = condition->index;

@@ -1111,7 +1164,7 @@ njs_generate_for_statement(njs_vm_t *vm,
}

njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
- NJS_VMCODE_IF_TRUE_JUMP, 2);
+ NJS_VMCODE_IF_TRUE_JUMP, 2, condition);
cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump);
cond_jump->cond = condition->index;

@@ -1156,7 +1209,7 @@ njs_generate_for_in_statement(njs_vm_t *
}

njs_generate_code(generator, njs_vmcode_prop_foreach_t, prop_foreach,
- NJS_VMCODE_PROPERTY_FOREACH, 2);
+ NJS_VMCODE_PROPERTY_FOREACH, 2, foreach);
prop_offset = njs_code_offset(generator, prop_foreach);
prop_foreach->object = foreach->right->index;

@@ -1188,7 +1241,7 @@ njs_generate_for_in_statement(njs_vm_t *
}

njs_generate_code(generator, njs_vmcode_prop_next_t, prop_next,
- NJS_VMCODE_PROPERTY_NEXT, 3);
+ NJS_VMCODE_PROPERTY_NEXT, 3, node->left->left);
prop_offset = njs_code_offset(generator, prop_next);
prop_next->retval = foreach->left->index;
prop_next->object = foreach->right->index;
@@ -1575,7 +1628,7 @@ njs_generate_stop_statement(njs_vm_t *vm

if (njs_fast_path(ret == NJS_OK)) {
njs_generate_code(generator, njs_vmcode_stop_t, stop,
- NJS_VMCODE_STOP, 1);
+ NJS_VMCODE_STOP, 1, node);

index = NJS_INDEX_NONE;
node = node->right;
@@ -1645,7 +1698,8 @@ njs_generate_assignment(njs_vm_t *vm, nj
* empty object or expression result is stored directly in variable.
*/
if (lvalue->index != expr->index) {
- njs_generate_code_move(generator, move, lvalue->index, expr->index);
+ njs_generate_code_move(generator, move, lvalue->index, expr->index,
+ expr);
}

node->index = expr->index;
@@ -1687,7 +1741,7 @@ njs_generate_assignment(njs_vm_t *vm, nj
return NJS_ERROR;
}

- njs_generate_code_move(generator, move, index, src);
+ njs_generate_code_move(generator, move, index, src, object);
}

if (property->token_type == NJS_TOKEN_NAME) {
@@ -1698,7 +1752,7 @@ njs_generate_assignment(njs_vm_t *vm, nj
return NJS_ERROR;
}

- njs_generate_code_move(generator, move, index, src);
+ njs_generate_code_move(generator, move, index, src, property);
}
}

@@ -1710,18 +1764,18 @@ njs_generate_assignment(njs_vm_t *vm, nj
switch (lvalue->token_type) {
case NJS_TOKEN_PROPERTY_INIT:
njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
- NJS_VMCODE_PROPERTY_INIT, 3);
+ NJS_VMCODE_PROPERTY_INIT, 3, expr);
break;

case NJS_TOKEN_PROTO_INIT:
njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
- NJS_VMCODE_PROTO_INIT, 3);
+ NJS_VMCODE_PROTO_INIT, 3, expr);
break;

default:
/* NJS_VMCODE_PROPERTY_SET */
njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
- NJS_VMCODE_PROPERTY_SET, 3);
+ NJS_VMCODE_PROPERTY_SET, 3, expr);
}

prop_set->value = expr->index;
@@ -1763,7 +1817,7 @@ njs_generate_operation_assignment(njs_vm
/* Preserve variable value if it may be changed by expression. */

njs_generate_code(generator, njs_vmcode_move_t, move,
- NJS_VMCODE_MOVE, 2);
+ NJS_VMCODE_MOVE, 2, expr);
move->src = lvalue->index;

index = njs_generate_temp_index_get(vm, generator, expr);
@@ -1780,7 +1834,7 @@ njs_generate_operation_assignment(njs_vm
}

njs_generate_code(generator, njs_vmcode_3addr_t, code,
- node->u.operation, 3);
+ node->u.operation, 3, expr);
code->dst = lvalue->index;
code->src1 = index;
code->src2 = expr->index;
@@ -1823,7 +1877,7 @@ njs_generate_operation_assignment(njs_vm
}

njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get,
- NJS_VMCODE_PROPERTY_GET, 3);
+ NJS_VMCODE_PROPERTY_GET, 3, property);
prop_get->value = index;
prop_get->object = object->index;
prop_get->property = property->index;
@@ -1836,13 +1890,13 @@ njs_generate_operation_assignment(njs_vm
}

njs_generate_code(generator, njs_vmcode_3addr_t, code,
- node->u.operation, 3);
+ node->u.operation, 3, expr);
code->dst = node->index;
code->src1 = node->index;
code->src2 = expr->index;

njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
- NJS_VMCODE_PROPERTY_SET, 3);
+ NJS_VMCODE_PROPERTY_SET, 3, expr);
prop_set->value = node->index;
prop_set->object = object->index;
prop_set->property = property->index;
@@ -1868,7 +1922,7 @@ njs_generate_object(njs_vm_t *vm, njs_ge
}

njs_generate_code(generator, njs_vmcode_object_t, object,
- NJS_VMCODE_OBJECT, 1);
+ NJS_VMCODE_OBJECT, 1, node);
object->retval = node->index;

/* Initialize object. */
@@ -1907,7 +1961,7 @@ njs_generate_property_accessor(njs_vm_t
}

njs_generate_code(generator, njs_vmcode_prop_accessor_t, accessor,
- NJS_VMCODE_PROPERTY_ACCESSOR, 3);
+ NJS_VMCODE_PROPERTY_ACCESSOR, 3, function);

accessor->value = function->index;
accessor->object = object->index;
@@ -1931,7 +1985,7 @@ njs_generate_array(njs_vm_t *vm, njs_gen
}

njs_generate_code(generator, njs_vmcode_array_t, array,
- NJS_VMCODE_ARRAY, 1);
+ NJS_VMCODE_ARRAY, 1, node);
array->ctor = node->ctor;
array->retval = node->index;
array->length = node->u.length;
@@ -1957,21 +2011,12 @@ njs_generate_function(njs_vm_t *vm, njs_
name = module ? &njs_entry_module : &njs_entry_anonymous;

ret = njs_generate_function_scope(vm, lambda, node, name);
-
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}

- if (vm->debug != NULL) {
- ret = njs_generate_function_debug(vm, name, lambda,
- module ? node->right : node);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
- }
-
njs_generate_code(generator, njs_vmcode_function_t, function,
- NJS_VMCODE_FUNCTION, 1);
+ NJS_VMCODE_FUNCTION, 1, node);
function->lambda = lambda;

node->index = njs_generate_object_dest_index(vm, generator, node);
@@ -1997,7 +2042,7 @@ njs_generate_regexp(njs_vm_t *vm, njs_ge
}

njs_generate_code(generator, njs_vmcode_regexp_t, regexp,
- NJS_VMCODE_REGEXP, 1);
+ NJS_VMCODE_REGEXP, 1, node);
regexp->retval = node->index;
regexp->pattern = node->u.value.data.u.data;

@@ -2018,7 +2063,7 @@ njs_generate_template_literal(njs_vm_t *
}

njs_generate_code(generator, njs_vmcode_template_literal_t, code,
- NJS_VMCODE_TEMPLATE_LITERAL, 1);
+ NJS_VMCODE_TEMPLATE_LITERAL, 1, node);
code->retval = node->left->index;

node->index = node->left->index;
@@ -2042,7 +2087,7 @@ njs_generate_test_jump_expression(njs_vm
}

njs_generate_code(generator, njs_vmcode_test_jump_t, test_jump,
- node->u.operation, 2);
+ node->u.operation, 2, node);
jump_offset = njs_code_offset(generator, test_jump);
test_jump->value = node->left->index;

@@ -2066,7 +2111,7 @@ njs_generate_test_jump_expression(njs_vm

if (node->index != node->right->index) {
njs_generate_code_move(generator, move, node->index,
- node->right->index);
+ node->right->index, node);
}

njs_code_set_jump_offset(generator, njs_vmcode_test_jump_t, jump_offset);
@@ -2098,7 +2143,7 @@ njs_generate_3addr_operation(njs_vm_t *v
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[njs] Introduced line level backtrace.

Dmitry Volyntsev 60 June 18, 2020 02:58PM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 67
Record Number of Users: 6 on February 13, 2018
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready