From: Dmitry Volyntsev Date: Thu, 18 Jun 2020 18:56:24 +0000 (+0000) Subject: Introduced line level backtrace. X-Git-Tag: 0.4.2~23 X-Git-Url: http://git.kaiwu.me/postgresql/log/contrib/postgres_fdw/static/gitweb.js?a=commitdiff_plain;h=c24673808d6eac5d6b703a2b43d4947240083182;p=njs.git Introduced line level backtrace. This closes #140 issue on Github. --- diff --git a/src/njs.h b/src/njs.h index ebd1e32c..e5d9bd36 100644 --- 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); diff --git a/src/njs_disassembler.c b/src/njs_disassembler.c index 39e9fc10..b4b1a21b 100644 --- a/src/njs_disassembler.c +++ b/src/njs_disassembler.c @@ -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); diff --git a/src/njs_error.c b/src/njs_error.c index ba53a90b..2b19c290 100644 --- a/src/njs_error.c +++ b/src/njs_error.c @@ -8,6 +8,19 @@ #include +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; +} diff --git a/src/njs_function.c b/src/njs_function.c index ddb41771..0898d5e4 100644 --- a/src/njs_function.c +++ b/src/njs_function.c @@ -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)) { diff --git a/src/njs_function.h b/src/njs_function.h index 95d9d6ab..ce397a15 100644 --- a/src/njs_function.h +++ b/src/njs_function.h @@ -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 --git a/src/njs_generator.c b/src/njs_generator.c index 8e1715ac..8a163ffe 100644 --- a/src/njs_generator.c +++ b/src/njs_generator.c @@ -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; -} diff --git a/src/njs_generator.h b/src/njs_generator.h index 043a9e8f..7b7b0c7f 100644 --- a/src/njs_generator.h +++ b/src/njs_generator.h @@ -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_ */ diff --git a/src/njs_vm.c b/src/njs_vm.c index 2dffb7d9..3a03ce18 100644 --- a/src/njs_vm.c +++ b/src/njs_vm.c @@ -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) { diff --git a/src/njs_vm.h b/src/njs_vm.h index fabe159b..28b8543c 100644 --- a/src/njs_vm.h +++ b/src/njs_vm.h @@ -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); diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c index f2eb831a..c4e38d43 100644 --- a/src/njs_vmcode.c +++ b/src/njs_vmcode.c @@ -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); } diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 90e6666e..2eef5c5a 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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") }, }; diff --git a/test/njs_expect_test.exp b/test/njs_expect_test.exp index 9723f66a..0923d00c 100644 --- a/test/njs_expect_test.exp +++ b/test/njs_expect_test.exp @@ -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"