]> git.kaiwu.me - njs.git/commitdiff
Introduced line level backtrace.
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 18 Jun 2020 18:56:24 +0000 (18:56 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Thu, 18 Jun 2020 18:56:24 +0000 (18:56 +0000)
This closes #140 issue on Github.

12 files changed:
src/njs.h
src/njs_disassembler.c
src/njs_error.c
src/njs_function.c
src/njs_function.h
src/njs_generator.c
src/njs_generator.h
src/njs_vm.c
src/njs_vm.h
src/njs_vmcode.c
src/test/njs_unit_test.c
test/njs_expect_test.exp

index ebd1e32c5e249855e609b59b50b25a2fd9ef6883..e5d9bd36f6cacaadc8f8c141f7df970b6095c6e4 100644 (file)
--- a/src/njs.h
+++ b/src/njs.h
@@ -293,7 +293,6 @@ NJS_EXPORT njs_function_t *njs_vm_function_alloc(njs_vm_t *vm,
     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);
index 39e9fc102881bda16a2f0b2c9b0b075511365cab..b4b1a21bf388bbea290ca7f27466cc38957108cf 100644 (file)
@@ -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 *end)
     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 *end)
      * 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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         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 *end)
         }
 
         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 *end)
                 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 *end)
 
         } 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);
index ba53a90b3f01fd53df8cb52a7d0ee791f6e07d70..2b19c290769844f728afb861cb8ece7be69dc11a 100644 (file)
@@ -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_object_t *error, njs_value_t *retval)
     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_object_t *error, njs_value_t *retval)
 
     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_value_t *value)
         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_error_type_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;
+}
index ddb41771c1d90d7dd18e8ff624aa5508119c840b..0898d5e4a725813c845d8bb4d3f386e3c19cea5c 100644 (file)
@@ -371,6 +371,7 @@ njs_function_native_frame(njs_vm_t *vm, njs_function_t *function,
     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, njs_function_t *function,
     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, njs_value_t *args, njs_uint_t nargs,
     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, njs_value_t *args, njs_uint_t nargs,
 
     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)) {
index 95d9d6ab74c5f030eaeccb8c1a313bff2a14a10a..ce397a15b882a75b6630062124fa421c60e2fb4a 100644 (file)
@@ -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;
index 8e1715ac4447a7f8f0f5c114715cf3a9004e8bf9..8a163ffe3b71b79c44c9342eefd744aa0d3fa602 100644 (file)
@@ -57,6 +57,8 @@ static njs_int_t njs_generator(njs_vm_t *vm, njs_generator_t *generator,
     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_reference(njs_vm_t *vm,
 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_debug(njs_vm_t *vm,
 #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)
@@ -535,6 +539,54 @@ 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)
+{
+    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_generator_t *generator,
         }
 
         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, njs_generator_t *generator,
      * 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_generator_t *generator,
     }
 
     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 *vm, njs_generator_t *generator,
     }
 
     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 *vm, njs_generator_t *generator,
 
     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 *vm, njs_generator_t *generator,
 
     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 *vm, njs_generator_t *generator,
             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 *vm, njs_generator_t *generator,
             }
 
             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 *vm, njs_generator_t *generator,
     }
 
     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 *vm, njs_generator_t *generator,
     }
 
     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_generator_t *generator,
         }
 
         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 *vm, njs_generator_t *generator,
     }
 
     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 *vm, njs_generator_t *generator,
     }
 
     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, njs_generator_t *generator,
 
     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, njs_generator_t *generator,
          * 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, njs_generator_t *generator,
                 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, njs_generator_t *generator,
                 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, njs_generator_t *generator,
     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_t *vm, njs_generator_t *generator,
             /* 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_t *vm, njs_generator_t *generator,
         }
 
         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_t *vm, njs_generator_t *generator,
     }
 
     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_t *vm, njs_generator_t *generator,
     }
 
     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_generator_t *generator,
     }
 
     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 *vm, njs_generator_t *generator,
     }
 
     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_generator_t *generator,
     }
 
     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_generator_t *generator,
     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_generator_t *generator,
     }
 
     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 *vm, njs_generator_t *generator,
     }
 
     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_t *vm, njs_generator_t *generator,
     }
 
     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_t *vm, njs_generator_t *generator,
 
     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 *vm, njs_generator_t *generator,
 
         if (njs_slow_path(njs_parser_has_side_effect(right))) {
             njs_generate_code(generator, njs_vmcode_move_t, move,
-                              NJS_VMCODE_MOVE, 2);
+                              NJS_VMCODE_MOVE, 2, node);
             move->src = left->index;
 
             index = njs_generate_node_temp_index_get(vm, generator, left);
@@ -2116,7 +2161,7 @@ njs_generate_3addr_operation(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     njs_generate_code(generator, njs_vmcode_3addr_t, code,
-                      node->u.operation, 3);
+                      node->u.operation, 3, node);
 
     if (!swap) {
         code->src1 = left->index;
@@ -2158,7 +2203,7 @@ njs_generate_2addr_operation(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     njs_generate_code(generator, njs_vmcode_2addr_t, code,
-                      node->u.operation, 2);
+                      node->u.operation, 2, node);
     code->src = node->left->index;
 
     node->index = njs_generate_dest_index(vm, generator, node);
@@ -2198,7 +2243,7 @@ njs_generate_typeof_operation(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     njs_generate_code(generator, njs_vmcode_2addr_t, code,
-                      node->u.operation, 2);
+                      node->u.operation, 2, expr);
     code->src = node->left->index;
 
     node->index = njs_generate_dest_index(vm, generator, node);
@@ -2242,7 +2287,7 @@ njs_generate_inc_dec_operation(njs_vm_t *vm, njs_generator_t *generator,
         node->index = index;
 
         njs_generate_code(generator, njs_vmcode_3addr_t, code,
-                          node->u.operation, 3);
+                          node->u.operation, 3, node);
         code->dst = index;
         code->src1 = lvalue->index;
         code->src2 = lvalue->index;
@@ -2290,19 +2335,19 @@ found:
     }
 
     njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get,
-                      NJS_VMCODE_PROPERTY_GET, 3);
+                      NJS_VMCODE_PROPERTY_GET, 3, node);
     prop_get->value = index;
     prop_get->object = lvalue->left->index;
     prop_get->property = lvalue->right->index;
 
     njs_generate_code(generator, njs_vmcode_3addr_t, code,
-                      node->u.operation, 3);
+                      node->u.operation, 3, node);
     code->dst = dest_index;
     code->src1 = index;
     code->src2 = index;
 
     njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
-                      NJS_VMCODE_PROPERTY_SET, 3);
+                      NJS_VMCODE_PROPERTY_SET, 3, node);
     prop_set->value = index;
     prop_set->object = lvalue->left->index;
     prop_set->property = lvalue->right->index;
@@ -2349,10 +2394,6 @@ njs_generate_function_declaration(njs_vm_t *vm, njs_generator_t *generator,
         return ret;
     }
 
-    if (vm->debug != NULL) {
-        ret = njs_generate_function_debug(vm, &lex_entry->name, lambda, node);
-    }
-
     return ret;
 }
 
@@ -2361,41 +2402,53 @@ static njs_int_t
 njs_generate_function_scope(njs_vm_t *vm, njs_function_lambda_t *lambda,
     njs_parser_node_t *node, const njs_str_t *name)
 {
-    size_t           size;
-    njs_arr_t        *closure;
-    njs_int_t        ret;
-    njs_generator_t  generator;
-
-    node = node->right;
+    size_t             size;
+    njs_arr_t          *closure;
+    njs_bool_t         module;
+    njs_vm_code_t      *code;
+    njs_generator_t    generator;
+    njs_parser_node_t  *file_node;
 
     njs_memzero(&generator, sizeof(njs_generator_t));
 
-    ret = njs_generate_scope(vm, &generator, node->scope, name);
+    module = node->right->scope->module;
+    file_node = module ? node->right : node;
 
-    if (njs_fast_path(ret == NJS_OK)) {
-        size = 0;
-        closure = node->scope->values[1];
+    node = node->right;
 
-        if (closure != NULL) {
-            lambda->block_closures = 1;
-            lambda->closure_scope = closure->start;
-            size = (1 + closure->items) * sizeof(njs_value_t);
+    code = njs_generate_scope(vm, &generator, node->scope, name);
+    if (njs_slow_path(code == NULL)) {
+        if (!njs_is_error(&vm->retval)) {
+            njs_internal_error(vm, "njs_generate_scope() failed");
         }
 
-        lambda->closure_size = size;
+        return NJS_ERROR;
+    }
+
+    code->file = file_node->scope->file;
 
-        lambda->nesting = node->scope->nesting;
+    size = 0;
+    closure = node->scope->values[1];
 
-        lambda->start = generator.code_start;
-        lambda->local_size = generator.scope_size;
-        lambda->local_scope = generator.local_scope;
+    if (closure != NULL) {
+        lambda->block_closures = 1;
+        lambda->closure_scope = closure->start;
+        size = (1 + closure->items) * sizeof(njs_value_t);
     }
 
-    return ret;
+    lambda->closure_size = size;
+
+    lambda->nesting = node->scope->nesting;
+
+    lambda->start = generator.code_start;
+    lambda->local_size = generator.scope_size;
+    lambda->local_scope = generator.local_scope;
+
+    return NJS_OK;
 }
 
 
-njs_int_t
+njs_vm_code_t *
 njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_scope_t *scope, const njs_str_t *name)
 {
@@ -2403,7 +2456,7 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
     size_t          size;
     uintptr_t       scope_size;
     njs_int_t       ret;
-    njs_uint_t      n;
+    njs_uint_t      n, index;
     njs_value_t    *value;
     njs_vm_code_t  *code;
 
@@ -2411,7 +2464,8 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
 
     p = njs_mp_alloc(vm->mem_pool, generator->code_size);
     if (njs_slow_path(p == NULL)) {
-        return NJS_ERROR;
+        njs_memory_error(vm);
+        return NULL;
     }
 
     generator->code_start = p;
@@ -2419,13 +2473,46 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
 
     ret = njs_generate_lambda_variables(vm, generator, scope->top);
     if (njs_slow_path(ret != NJS_OK)) {
-        return NJS_ERROR;
+        return NULL;
+    }
+
+    if (vm->codes == NULL) {
+        vm->codes = njs_arr_create(vm->mem_pool, 4, sizeof(njs_vm_code_t));
+        if (njs_slow_path(vm->codes == NULL)) {
+            return NULL;
+        }
+    }
+
+    index = vm->codes->items;
+    code = njs_arr_add(vm->codes);
+    if (njs_slow_path(code == NULL)) {
+        njs_memory_error(vm);
+        return NULL;
+    }
+
+    code->lines = NULL;
+
+    if (vm->options.backtrace) {
+        code->lines = njs_arr_create(vm->mem_pool, 4,
+                                     sizeof(njs_vm_line_num_t));
+        if (njs_slow_path(code->lines == NULL)) {
+            njs_memory_error(vm);
+            return NULL;
+        }
+
+        generator->lines = code->lines;
     }
 
     if (njs_slow_path(njs_generator(vm, generator, scope->top) != NJS_OK)) {
-        return NJS_ERROR;
+        return NULL;
     }
 
+    code = njs_arr_item(vm->codes, index);
+    code->start = generator->code_start;
+    code->end = generator->code_end;
+    code->file = scope->file;
+    code->name = *name;
+
     generator->code_size = generator->code_end - generator->code_start;
 
     scope_size = njs_scope_offset(scope->next_index[0]);
@@ -2436,7 +2523,7 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
 
     generator->local_scope = njs_mp_alloc(vm->mem_pool, scope_size);
     if (njs_slow_path(generator->local_scope == NULL)) {
-        return NJS_ERROR;
+        return NULL;
     }
 
     generator->scope_size = scope_size;
@@ -2452,24 +2539,7 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
         njs_set_undefined(value++);
     }
 
-    if (vm->codes == NULL) {
-        vm->codes = njs_arr_create(vm->mem_pool, 4, sizeof(njs_vm_code_t));
-        if (njs_slow_path(vm->codes == NULL)) {
-            return NJS_ERROR;
-        }
-    }
-
-    code = njs_arr_add(vm->codes);
-    if (njs_slow_path(code == NULL)) {
-        return NJS_ERROR;
-    }
-
-    code->start = generator->code_start;
-    code->end = generator->code_end;
-    code->file = scope->file;
-    code->name = *name;
-
-    return NJS_OK;
+    return code;
 }
 
 
@@ -2498,18 +2568,18 @@ njs_generate_lambda_variables(njs_vm_t *vm, njs_generator_t *generator,
         if (var->argument != 0) {
             index = njs_scope_index((var->argument - 1), NJS_SCOPE_ARGUMENTS);
 
-            njs_generate_code_move(generator, move, var->index, index);
+            njs_generate_code_move(generator, move, var->index, index, node);
         }
 
         if (var->this_object) {
             njs_generate_code(generator, njs_vmcode_this_t, this,
-                              NJS_VMCODE_THIS, 1);
+                              NJS_VMCODE_THIS, 1, NULL);
             this->dst = var->index;
         }
 
         if (var->arguments_object) {
             njs_generate_code(generator, njs_vmcode_arguments_t, arguments,
-                              NJS_VMCODE_ARGUMENTS, 1);
+                              NJS_VMCODE_ARGUMENTS, 1, NULL);
             arguments->dst = var->index;
         }
 
@@ -2549,7 +2619,7 @@ njs_generate_return_statement(njs_vm_t *vm, njs_generator_t *generator,
 
     if (njs_fast_path(immediate == NULL)) {
         njs_generate_code(generator, njs_vmcode_return_t, code,
-                          NJS_VMCODE_RETURN, 1);
+                          NJS_VMCODE_RETURN, 1, node);
         code->retval = index;
         node->index = index;
 
@@ -2579,7 +2649,7 @@ njs_generate_return_statement(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     njs_generate_code(generator, njs_vmcode_try_return_t, try_return,
-                      NJS_VMCODE_TRY_RETURN, 2);
+                      NJS_VMCODE_TRY_RETURN, 2, node);
     try_return->retval = index;
     try_return->save = top->index;
     try_return->offset = offsetof(njs_vmcode_try_return_t, offset);
@@ -2624,7 +2694,7 @@ njs_generate_function_call(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     njs_generate_code(generator, njs_vmcode_function_frame_t, func,
-                      NJS_VMCODE_FUNCTION_FRAME, 2);
+                      NJS_VMCODE_FUNCTION_FRAME, 2, node);
     func_offset = njs_code_offset(generator, func);
     func->ctor = node->ctor;
     func->name = name->index;
@@ -2668,7 +2738,7 @@ njs_generate_method_call(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     njs_generate_code(generator, njs_vmcode_method_frame_t, method,
-                      NJS_VMCODE_METHOD_FRAME, 3);
+                      NJS_VMCODE_METHOD_FRAME, 3, prop);
     method_offset = njs_code_offset(generator, method);
     method->ctor = node->ctor;
     method->object = prop->left->index;
@@ -2715,7 +2785,7 @@ njs_generate_call(njs_vm_t *vm, njs_generator_t *generator,
 
         if (arg->index != arg->left->index) {
             njs_generate_code_move(generator, move, arg->index,
-                                   arg->left->index);
+                                   arg->left->index, node);
         }
     }
 
@@ -2727,26 +2797,26 @@ njs_generate_call(njs_vm_t *vm, njs_generator_t *generator,
     node->index = retval;
 
     njs_generate_code(generator, njs_vmcode_function_call_t, call,
-                      NJS_VMCODE_FUNCTION_CALL, 1);
+                      NJS_VMCODE_FUNCTION_CALL, 1, node);
     call->retval = retval;
 
     return nargs;
 }
 
 
-#define njs_generate_code_catch(generator, _code, _exception)                 \
+#define njs_generate_code_catch(generator, _code, _exception, node)           \
     do {                                                                      \
             njs_generate_code(generator, njs_vmcode_catch_t, _code,           \
-                              NJS_VMCODE_CATCH, 2);                           \
+                              NJS_VMCODE_CATCH, 2, node);                     \
             _code->offset = sizeof(njs_vmcode_catch_t);                       \
             _code->exception = _exception;                                    \
     } while (0)
 
 
-#define njs_generate_code_finally(generator, _code, _retval, _exit)           \
+#define njs_generate_code_finally(generator, _code, _retval, _exit, node)     \
     do {                                                                      \
             njs_generate_code(generator, njs_vmcode_finally_t, _code,         \
-                              NJS_VMCODE_FINALLY, 2);                         \
+                              NJS_VMCODE_FINALLY, 2, node);                   \
             _code->retval = _retval;                                          \
             _code->exit_value = _exit;                                        \
             _code->continue_offset = offsetof(njs_vmcode_finally_t,           \
@@ -2776,7 +2846,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_vmcode_try_trampoline_t  *try_break, *try_continue;
 
     njs_generate_code(generator, njs_vmcode_try_start_t, try_start,
-                      NJS_VMCODE_TRY_START, 2);
+                      NJS_VMCODE_TRY_START, 2, node);
     try_offset = njs_code_offset(generator, try_start);
 
     exception_index = njs_generate_temp_index_get(vm, generator, node);
@@ -2816,7 +2886,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
     try_cont_label = undef_label;
 
     njs_generate_code(generator, njs_vmcode_try_end_t, try_end,
-                      NJS_VMCODE_TRY_END, 0);
+                      NJS_VMCODE_TRY_END, 0, NULL);
     try_end_offset = njs_code_offset(generator, try_end);
 
     if (try_block->exit != NULL) {
@@ -2825,7 +2895,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
         njs_generate_patch_block(vm, generator, try_block->exit);
 
         njs_generate_code(generator, njs_vmcode_try_trampoline_t, try_break,
-                          NJS_VMCODE_TRY_BREAK, 2);
+                          NJS_VMCODE_TRY_BREAK, 2, NULL);
         try_break->exit_value = exit_index;
 
         try_break->offset = -sizeof(njs_vmcode_try_end_t);
@@ -2840,7 +2910,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
         njs_generate_patch_block(vm, generator, try_block->continuation);
 
         njs_generate_code(generator, njs_vmcode_try_trampoline_t, try_continue,
-                          NJS_VMCODE_TRY_CONTINUE, 2);
+                          NJS_VMCODE_TRY_CONTINUE, 2, NULL);
         try_continue->exit_value = exit_index;
 
         try_continue->offset = -sizeof(njs_vmcode_try_end_t);
@@ -2868,7 +2938,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
             return NJS_ERROR;
         }
 
-        njs_generate_code_catch(generator, catch, catch_index);
+        njs_generate_code_catch(generator, catch, catch_index, node);
 
         ret = njs_generator(vm, generator, node->right);
         if (njs_slow_path(ret != NJS_OK)) {
@@ -2879,7 +2949,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
 
         if (try_block->continuation != NULL || try_block->exit != NULL) {
             njs_generate_code_finally(generator, finally, exception_index,
-                                      exit_index);
+                                      exit_index, NULL);
 
             if (try_block->continuation != NULL) {
                 /*
@@ -2927,7 +2997,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
                 return NJS_ERROR;
             }
 
-            njs_generate_code_catch(generator, catch, catch_index);
+            njs_generate_code_catch(generator, catch, catch_index, node);
             catch_offset = njs_code_offset(generator, catch);
 
             ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_TRY,
@@ -2945,7 +3015,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
             }
 
             njs_generate_code(generator, njs_vmcode_try_end_t, catch_end,
-                              NJS_VMCODE_TRY_END, 0);
+                              NJS_VMCODE_TRY_END, 0, node->left->right);
             catch_end_offset = njs_code_offset(generator, catch_end);
 
             if (catch_block->exit != NULL) {
@@ -2954,7 +3024,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
                 njs_generate_patch_block(vm, generator, catch_block->exit);
 
                 njs_generate_code(generator, njs_vmcode_try_trampoline_t,
-                                  try_break, NJS_VMCODE_TRY_BREAK, 2);
+                                  try_break, NJS_VMCODE_TRY_BREAK, 2, NULL);
 
                 try_break->exit_value = exit_index;
 
@@ -2971,7 +3041,8 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
                                          catch_block->continuation);
 
                 njs_generate_code(generator, njs_vmcode_try_trampoline_t,
-                                  try_continue, NJS_VMCODE_TRY_CONTINUE, 2);
+                                  try_continue, NJS_VMCODE_TRY_CONTINUE, 2,
+                                  NULL);
 
                 try_continue->exit_value = exit_index;
 
@@ -2989,7 +3060,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
 
             /* TODO: release exception variable index. */
 
-            njs_generate_code_catch(generator, catch, exception_index);
+            njs_generate_code_catch(generator, catch, exception_index, NULL);
 
             njs_code_set_jump_offset(generator, njs_vmcode_try_end_t,
                                      catch_end_offset);
@@ -2997,7 +3068,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
         } else {
             /* A try/finally case. */
 
-            njs_generate_code_catch(generator, catch, exception_index);
+            njs_generate_code_catch(generator, catch, exception_index, NULL);
 
             catch_block = NULL;
         }
@@ -3010,7 +3081,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
         }
 
         njs_generate_code_finally(generator, finally, exception_index,
-                          exit_index);
+                                  exit_index, node);
 
         if (try_block->continuation != NULL
             || (catch_block && catch_block->continuation != NULL))
@@ -3085,7 +3156,7 @@ njs_generate_throw_statement(njs_vm_t *vm, njs_generator_t *generator,
 
     if (njs_fast_path(ret == NJS_OK)) {
         njs_generate_code(generator, njs_vmcode_throw_t, throw,
-                          NJS_VMCODE_THROW, 1);
+                          NJS_VMCODE_THROW, 1, node);
 
         node->index = node->right->index;
         throw->retval = node->index;
@@ -3123,7 +3194,7 @@ njs_generate_import_statement(njs_vm_t *vm, njs_generator_t *generator,
     module = (njs_module_t *) expr->index;
 
     njs_generate_code(generator, njs_vmcode_object_copy_t, copy,
-                      NJS_VMCODE_OBJECT_COPY, 2);
+                      NJS_VMCODE_OBJECT_COPY, 2, node);
     copy->retval = index;
     copy->object = module->index;
 
@@ -3147,7 +3218,7 @@ njs_generate_export_statement(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     njs_generate_code(generator, njs_vmcode_return_t, code,
-                      NJS_VMCODE_RETURN, 1);
+                      NJS_VMCODE_RETURN, 1, NULL);
     code->retval = obj->index;
     node->index = obj->index;
 
@@ -3319,7 +3390,8 @@ njs_generate_global_reference(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get,
-                 exception ? NJS_VMCODE_GLOBAL_GET: NJS_VMCODE_PROPERTY_GET, 3);
+                 exception ? NJS_VMCODE_GLOBAL_GET: NJS_VMCODE_PROPERTY_GET,
+                 3, node);
 
     prop_get->value = index;
     prop_get->object = NJS_INDEX_GLOBAL_OBJECT;
@@ -3365,7 +3437,7 @@ njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     njs_generate_code(generator, njs_vmcode_reference_error_t, ref_err,
-                      NJS_VMCODE_REFERENCE_ERROR, 0);
+                      NJS_VMCODE_REFERENCE_ERROR, 0, NULL);
 
     ref_err->token_line = node->token_line;
 
@@ -3385,30 +3457,3 @@ njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator,
 
     return njs_name_copy(vm, &ref_err->name, &lex_entry->name);
 }
-
-
-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)
-{
-    njs_function_debug_t  *debug;
-
-    debug = njs_arr_add(vm->debug);
-    if (njs_slow_path(debug == NULL)) {
-        return NJS_ERROR;
-    }
-
-    debug->lambda = lambda;
-    debug->line = node->token_line;
-
-    if (!vm->options.quiet) {
-        debug->file = node->scope->file;
-
-    } else {
-        debug->file = njs_str_value("");
-    }
-
-    debug->name = (name != NULL) ? *name : no_label;
-
-    return NJS_OK;
-}
index 043a9e8ff8f6c55ac854eaad9e50935305775d35..7b7b0c7ff825ec475cc8181e32633740f7319504 100644 (file)
@@ -18,6 +18,8 @@ struct njs_generator_s {
     njs_generator_block_t           *block;
     njs_arr_t                       *index_cache;
 
+    njs_arr_t                       *lines;
+
     size_t                          code_size;
     u_char                          *code_start;
     u_char                          *code_end;
@@ -29,8 +31,9 @@ struct njs_generator_s {
 };
 
 
-njs_int_t njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
+njs_vm_code_t *njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_scope_t *scope, const njs_str_t *name);
+uint32_t njs_lookup_line(njs_vm_code_t *code, uint32_t offset);
 
 
 #endif /* _NJS_GENERATOR_H_INCLUDED_ */
index 2dffb7d9ec26cf13a6faa87e904e6f4956835850..3a03ce181542fc9db3102ad34c2da277870890b0 100644 (file)
@@ -32,7 +32,6 @@ njs_vm_create(njs_vm_opt_t *options)
     njs_mp_t   *mp;
     njs_vm_t   *vm;
     njs_int_t  ret;
-    njs_arr_t  *debug;
 
     mp = njs_mp_fast_create(2 * njs_pagesize(), 128, 512, 16);
     if (njs_slow_path(mp == NULL)) {
@@ -74,16 +73,6 @@ njs_vm_create(njs_vm_opt_t *options)
 
     njs_set_undefined(&vm->retval);
 
-    if (options->backtrace) {
-        debug = njs_arr_create(vm->mem_pool, 4,
-                               sizeof(njs_function_debug_t));
-        if (njs_slow_path(debug == NULL)) {
-            return NULL;
-        }
-
-        vm->debug = debug;
-    }
-
     if (options->init) {
         ret = njs_vm_init(vm);
         if (njs_slow_path(ret != NJS_OK)) {
@@ -129,6 +118,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end)
     njs_chb_t           chain;
     njs_lexer_t         lexer;
     njs_parser_t        *parser, *prev;
+    njs_vm_code_t       *code;
     njs_generator_t     generator;
     njs_parser_scope_t  *scope;
 
@@ -174,19 +164,18 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end)
 
     *start = lexer.start;
 
-    /*
-     * Reset the code array to prevent it from being disassembled
-     * again in the next iteration of the accumulative mode.
-     */
-    vm->codes = NULL;
-
     njs_memzero(&generator, sizeof(njs_generator_t));
 
-    ret = njs_generate_scope(vm, &generator, scope, &njs_entry_main);
-    if (njs_slow_path(ret != NJS_OK)) {
+    code = njs_generate_scope(vm, &generator, scope, &njs_entry_main);
+    if (njs_slow_path(code == NULL)) {
+        if (!njs_is_error(&vm->retval)) {
+            njs_internal_error(vm, "njs_generate_scope() failed");
+        }
+
         goto fail;
     }
 
+    vm->main_index = code - (njs_vm_code_t *) vm->codes->start;
     vm->start = generator.code_start;
     vm->global_scope = generator.local_scope;
     vm->scope_size = generator.scope_size;
@@ -1123,130 +1112,6 @@ njs_vm_value_string_copy(njs_vm_t *vm, njs_str_t *retval,
 }
 
 
-njs_int_t
-njs_vm_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_function_t         *function;
-    njs_function_debug_t   *debug_entry;
-    njs_function_lambda_t  *lambda;
-    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;
-
-    if (function == NULL) {
-        be->name = njs_entry_main;
-        return NJS_OK;
-    }
-
-    if (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;
-    }
-
-    lambda = function->u.lambda;
-    debug_entry = vm->debug->start;
-
-    for (i = 0; i < vm->debug->items; i++) {
-        if (lambda == debug_entry[i].lambda) {
-            if (debug_entry[i].name.length != 0) {
-                be->name = debug_entry[i].name;
-
-            } else {
-                be->name = njs_entry_anonymous;
-            }
-
-            be->file = debug_entry[i].file;
-            be->line = debug_entry[i].line;
-
-            return NJS_OK;
-        }
-    }
-
-    be->name = njs_entry_unknown;
-
-    return NJS_OK;
-}
-
-
-njs_int_t
-njs_vm_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;
-}
-
-
-
-
 void *
 njs_lvlhsh_alloc(void *data, size_t size)
 {
index fabe159b664bee6763f9f4461fec906bc10a3e0e..28b8543c1ec1a795a175c1a5e1c4efb58ff8317d 100644 (file)
@@ -28,13 +28,6 @@ typedef struct njs_parser_node_s      njs_parser_node_t;
 typedef struct njs_generator_s        njs_generator_t;
 
 
-typedef struct {
-    njs_str_t                         name;
-    njs_str_t                         file;
-    uint32_t                          line;
-} njs_backtrace_entry_t;
-
-
 typedef enum {
     NJS_SCOPE_ABSOLUTE = 0,
     NJS_SCOPE_GLOBAL = 1,
@@ -171,22 +164,12 @@ enum njs_object_e {
       + njs_scope_offset(index)))
 
 
-typedef struct {
-    uint32_t                  line;
-    njs_str_t                 file;
-    njs_str_t                 name;
-    njs_function_lambda_t     *lambda;
-} njs_function_debug_t;
-
-
 struct njs_vm_s {
     /* njs_vm_t must be aligned to njs_value_t due to scratch value. */
     njs_value_t              retval;
 
     njs_arr_t                *paths;
 
-    u_char                   *start;
-
     njs_value_t              *scopes[NJS_SCOPES];
 
     njs_external_ptr_t       external;
@@ -217,6 +200,7 @@ struct njs_vm_s {
 
     njs_mp_t                 *mem_pool;
 
+    u_char                   *start;
     njs_value_t              *global_scope;
     size_t                   scope_size;
     size_t                   stack_size;
@@ -236,22 +220,28 @@ struct njs_vm_s {
     njs_object_t             string_object;
     njs_object_t             global_object;
 
+    njs_uint_t               main_index;
     njs_arr_t                *codes;  /* of njs_vm_code_t */
 
     njs_trace_t              trace;
     njs_random_t             random;
 
-    njs_arr_t                *debug;
-
     uint64_t                 symbol_generator;
 };
 
 
+typedef struct {
+    uint32_t                 offset;
+    uint32_t                 line;
+} njs_vm_line_num_t;
+
+
 typedef struct {
     u_char                   *start;
     u_char                   *end;
     njs_str_t                file;
     njs_str_t                name;
+    njs_arr_t                *lines;  /* of njs_vm_line_num_t */
 } njs_vm_code_t;
 
 
@@ -288,10 +278,6 @@ struct njs_vm_shared_s {
 
 void njs_vm_scopes_restore(njs_vm_t *vm, njs_native_frame_t *frame,
     njs_native_frame_t *previous);
-njs_int_t njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack,
-    njs_native_frame_t *native_frame);
-njs_int_t njs_vm_backtrace_to_string(njs_vm_t *vm, njs_arr_t *stack,
-    njs_str_t *dst);
 
 njs_int_t njs_builtin_objects_create(njs_vm_t *vm);
 njs_int_t njs_builtin_objects_clone(njs_vm_t *vm, njs_value_t *global);
index f2eb831a8619a2fc497f9ad20af2c409e8bc0b25..c4e38d43ce6fc07c8749eebda8761b3e0b3b1462 100644 (file)
@@ -645,7 +645,7 @@ next:
                     njs_internal_error(vm, "failed conversion of type \"%s\" "
                                        "to string while property define",
                                        njs_type_string(value2->type));
-                    return NJS_ERROR;
+                    goto error;
                 }
 
                 ret = njs_object_prop_define(vm, value1, &name, function,
@@ -773,6 +773,8 @@ next:
                 break;
 
             case NJS_VMCODE_FUNCTION_CALL:
+                vm->active_frame->native.pc = pc;
+
                 ret = njs_function_frame_invoke(vm, (njs_index_t) value2);
                 if (njs_slow_path(ret == NJS_ERROR)) {
                     goto error;
@@ -902,6 +904,7 @@ next:
 error:
 
     if (njs_is_error(&vm->retval)) {
+        vm->active_frame->native.pc = pc;
         (void) njs_error_stack_attach(vm, &vm->retval);
     }
 
index 90e6666e463700b13bb00f7431aa05c091b8cc50..2eef5c5a0410c054e73ea43f09df8eed3e3bc004 100644 (file)
@@ -17718,7 +17718,7 @@ static njs_unit_test_t  njs_shell_test[] =
       njs_str("TypeError: cannot get property \"a\" of undefined\n"
               "    at ff (:1)\n"
               "    at f (:1)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("function ff(o) {return o.a.a}" ENTER
               "function f(o) {try {return ff(o)} "
@@ -17726,57 +17726,57 @@ static njs_unit_test_t  njs_shell_test[] =
               "f({})" ENTER),
       njs_str("TypeError: cannot get property \"a\" of undefined\n"
               "    at f (:1)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("function f(ff, o) {return ff(o)}" ENTER
               "f(function (o) {return o.a.a}, {})" ENTER),
       njs_str("TypeError: cannot get property \"a\" of undefined\n"
               "    at anonymous (:1)\n"
               "    at f (:1)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("'str'.replace(/t/g,"
               "              function(m) {return m.a.a})" ENTER),
       njs_str("TypeError: cannot get property \"a\" of undefined\n"
               "    at anonymous (:1)\n"
               "    at String.prototype.replace (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("function f(o) {return Object.keys(o)}" ENTER
               "f()" ENTER),
       njs_str("TypeError: cannot convert undefined argument to object\n"
               "    at Object.keys (native)\n"
               "    at f (:1)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("''.repeat(-1)" ENTER),
       njs_str("RangeError\n"
               "    at String.prototype.repeat (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("Math.log({}.a.a)" ENTER),
       njs_str("TypeError: cannot get property \"a\" of undefined\n"
               "    at Math.log (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("var bound = Math.max.bind(null, {toString(){return {}}}); bound(1)" ENTER),
       njs_str("TypeError: Cannot convert object to primitive value\n"
               "    at Math.max (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("Object.prototype()" ENTER),
       njs_str("TypeError: (intermediate value)[\"prototype\"] is not a function\n"
-               "    at main (native)\n") },
+               "    at main (:1)\n") },
 
     { njs_str("eval()" ENTER),
       njs_str("InternalError: Not implemented\n"
               "    at eval (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("$r.method({}.a.a)" ENTER),
       njs_str("TypeError: cannot get property \"a\" of undefined\n"
               "    at $r3.method (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("new Function(\n\n@)" ENTER),
       njs_str("SyntaxError: Unexpected token \"@\" in 3") },
@@ -17784,48 +17784,48 @@ static njs_unit_test_t  njs_shell_test[] =
     { njs_str("require()" ENTER),
       njs_str("TypeError: missing path\n"
               "    at require (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("setTimeout()" ENTER),
       njs_str("TypeError: too few arguments\n"
               "    at setTimeout (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("require('crypto').createHash('sha')" ENTER),
       njs_str("TypeError: not supported algorithm: \"sha\"\n"
               "    at crypto.createHash (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("var h = require('crypto').createHash('sha1')" ENTER
               "h.update([])" ENTER),
       njs_str("TypeError: data must be a string\n"
               "    at Hash.prototype.update (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("require('crypto').createHmac('sha1', [])" ENTER),
       njs_str("TypeError: key must be a string\n"
               "    at crypto.createHmac (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("var h = require('crypto').createHmac('sha1', 'secret')" ENTER
               "h.update([])" ENTER),
       njs_str("TypeError: data must be a string\n"
               "    at Hmac.prototype.update (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("function f(o) {function f_in(o) {return o.a.a};"
               "               return f_in(o)}; f({})" ENTER),
       njs_str("TypeError: cannot get property \"a\" of undefined\n"
               "    at f_in (:1)\n"
               "    at f (:1)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("function f(o) {var ff = function (o) {return o.a.a};"
               "               return ff(o)}; f({})" ENTER),
       njs_str("TypeError: cannot get property \"a\" of undefined\n"
               "    at anonymous (:1)\n"
               "    at f (:1)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("var fs = require('fs');"
               "["
@@ -17850,7 +17850,7 @@ static njs_unit_test_t  njs_shell_test[] =
     { njs_str("parseInt({ toString: function() { return [1] } })" ENTER),
       njs_str("TypeError: Cannot convert object to primitive value\n"
               "    at parseInt (native)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("function f(n) { if (n == 0) { throw 'a'; } return f(n-1); }; f(2)" ENTER),
       njs_str("a") },
@@ -17866,18 +17866,42 @@ static njs_unit_test_t  njs_shell_test[] =
     { njs_str("/**/(function(){throw Error();})()" ENTER),
       njs_str("Error\n"
               "    at anonymous (:1)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("/***/(function(){throw Error();})()" ENTER),
       njs_str("Error\n"
               "    at anonymous (:1)\n"
-              "    at main (native)\n") },
+              "    at main (:1)\n") },
 
     { njs_str("/*\n**/(function(){throw Error();})()" ENTER),
       njs_str("Error\n"
               "    at anonymous (:2)\n"
-              "    at main (native)\n") },
+              "    at main (:2)\n") },
 
+    { njs_str("({})\n.a\n.a" ENTER),
+      njs_str("TypeError: cannot get property \"a\" of undefined\n"
+              "    at main (:3)\n") },
+
+    { njs_str("1\n+a" ENTER),
+      njs_str("ReferenceError: \"a\" is not defined in 2\n"
+              "    at main (:2)\n") },
+
+    { njs_str("function log(v) {}\nlog({}\n.a\n.a)" ENTER),
+      njs_str("TypeError: cannot get property \"a\" of undefined\n"
+              "    at main (:4)\n") },
+
+    { njs_str("\nfor (var i = 0;\n i < a;\n i++) { }\n" ENTER),
+      njs_str("ReferenceError: \"a\" is not defined in 3\n"
+              "    at main (:3)\n") },
+
+    { njs_str("\nfor (var i = 0;\n i < 5;\n a) {\n }" ENTER),
+      njs_str("ReferenceError: \"a\" is not defined in 4\n"
+              "    at main (:4)\n") },
+
+    { njs_str("Math\n.min(1,\na)" ENTER),
+      njs_str("ReferenceError: \"a\" is not defined in 3\n"
+              "    at Math.min (native)\n"
+              "    at main (:3)\n") },
 };
 
 
index 9723f66a840ff4bbded5769e809efc3a55cc81a1..0923d00c48fc33d0da4da3b4da92c0edc854d0d2 100644 (file)
@@ -748,13 +748,13 @@ njs_test {
 njs_run {"-c" "setTimeout(() => {console.log('A'.repeat(1024))}, 0); ref"} \
 "^Thrown:
 ReferenceError: \"ref\" is not defined in string:1
-    at main \\\(native\\\)\n$"
+    at main \\\(string:1\\\)\n$"
 
 njs_run {"-c" "setTimeout(() => {ref}, 0); setTimeout(() => {console.log('A'.repeat(1024))}, 0)"} \
 "^Thrown:
 ReferenceError: \"ref\" is not defined in string:1
     at anonymous \\\(string:1\\\)
-    at main \\\(native\\\)\n$"
+    at main \\\(string:1\\\)\n$"
 
 # Modules
 
@@ -771,7 +771,7 @@ njs_run {"./test/module/normal.js"} \
         "SyntaxError: Cannot find module \"hash.js\" in lib1.js:13"
 
 njs_run {"-p" "test/module/libs" "./test/module/exception.js"} \
-        "at error \\(sub1.js:5\\)"
+        "at error \\(sub1.js:6\\)"
 
 njs_run {"-p" "test/module" "./test/module/recursive.js"} \
         "SyntaxError: Cannot import itself \"./test/module/recursive.js\" in recursive.js:1"
@@ -815,11 +815,11 @@ njs_run {"test/script_args.js" "A" "B"} "AB"
 
 njs_test {
     {"1+1\r\n"
-     "00000 ADD*\r\n*2"}
+     "    1 | 00000 ADD*\r\n*2"}
     {"for (var n in [1]) {try {break} finally{}}\r\n"
-     "00000 ARRAY*\r\n*TRY BREAK*PROP NEXT*-*\r\n\r\nundefined"}
+     "    1 | 00000 ARRAY*\r\n*TRY BREAK*PROP NEXT*-*\r\n\r\nundefined"}
     {"(function() {try {return} finally{}})()\r\n"
-     "00000 TRY START*\r\n*TRY RETURN*STOP*\r\n\r\nundefined"}
+     "    1 | 00000 TRY START*\r\n*TRY RETURN*\r\n\r\nundefined"}
 } "-d"
 
 # modules
@@ -999,9 +999,9 @@ njs_run {"./test/js/promise_s13.js"} \
 
 njs_run {"./test/js/promise_s14.js"} \
 "TypeError: oops
-    at anonymous \\\(promise_s14.js:4\\\)
+    at anonymous \\\(promise_s14.js:5\\\)
     at native \\\(native\\\)
-    at main \\\(native\\\)
+    at main \\\(promise_s14.js:9\\\)
 
 Done"