diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index aa909d777..6607bf4a5 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -58,6 +58,7 @@ Possible compile time enabled feature types: - JERRY_FEATURE_TYPEDARRAY - Typedarray support - JERRY_FEATURE_DATE - Date support - JERRY_FEATURE_REGEXP - RegExp support + - JERRY_FEATURE_LINE_INFO - line info available ## jerry_parse_opts_t @@ -5434,6 +5435,31 @@ main (void) - [jerry_run](#jerry_run) - [jerry_vm_exec_stop_callback_t](#jerry_vm_exec_stop_callback_t) +## jerry_get_backtrace + +**Summary** + +Get backtrace. The backtrace is an array of strings where +each string contains the position of the corresponding frame. +The array length is zero if the backtrace is not available. + +This function is typically called from native callbacks. + +**Prototype** + +```c +jerry_value_t +jerry_get_backtrace (uint32_t max_depth); +``` + +- `max_depth` - backtrace collection stops after reaching this value, 0 = unlimited +- return value + - a new array + +**See also** + +- [jerry_create_external_function](#jerry_create_external_function) + # ArrayBuffer and TypedArray functions diff --git a/jerry-core/CMakeLists.txt b/jerry-core/CMakeLists.txt index 7c57bd8ae..dff2438d0 100644 --- a/jerry-core/CMakeLists.txt +++ b/jerry-core/CMakeLists.txt @@ -22,6 +22,7 @@ set(FEATURE_DEBUGGER OFF CACHE BOOL "Enable JerryScript debugger set(FEATURE_ERROR_MESSAGES OFF CACHE BOOL "Enable error messages?") set(FEATURE_EXTERNAL_CONTEXT OFF CACHE BOOL "Enable external context?") set(FEATURE_JS_PARSER ON CACHE BOOL "Enable js-parser?") +set(FEATURE_LINE_INFO OFF CACHE BOOL "Enable line info?") set(FEATURE_MEM_STATS OFF CACHE BOOL "Enable memory statistics?") set(FEATURE_MEM_STRESS_TEST OFF CACHE BOOL "Enable mem-stress test?") set(FEATURE_PARSER_DUMP OFF CACHE BOOL "Enable parser byte-code dumps?") @@ -63,6 +64,7 @@ message(STATUS "FEATURE_DEBUGGER " ${FEATURE_DEBUGGER}) message(STATUS "FEATURE_ERROR_MESSAGES " ${FEATURE_ERROR_MESSAGES}) message(STATUS "FEATURE_EXTERNAL_CONTEXT " ${FEATURE_EXTERNAL_CONTEXT}) message(STATUS "FEATURE_JS_PARSER " ${FEATURE_JS_PARSER}) +message(STATUS "FEATURE_LINE_INFO " ${FEATURE_LINE_INFO}) message(STATUS "FEATURE_MEM_STATS " ${FEATURE_MEM_STATS}) message(STATUS "FEATURE_MEM_STRESS_TEST " ${FEATURE_MEM_STRESS_TEST}) message(STATUS "FEATURE_PARSER_DUMP " ${FEATURE_PARSER_DUMP} ${FEATURE_PARSER_DUMP_MESSAGE}) @@ -174,6 +176,11 @@ if(NOT FEATURE_JS_PARSER) set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_DISABLE_JS_PARSER) endif() +# JS line info +if(FEATURE_LINE_INFO) + set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_ENABLE_LINE_INFO) +endif() + # Memory statistics if(FEATURE_MEM_STATS) set(DEFINES_JERRY ${DEFINES_JERRY} JMEM_STATS) diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index 4bcb54e18..d9afd120b 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -726,6 +726,10 @@ jerry_generate_snapshot_with_args (const jerry_char_t *resource_name_p, /**< scr JERRY_UNUSED (resource_name_p); JERRY_UNUSED (resource_name_length); +#ifdef JERRY_ENABLE_LINE_INFO + JERRY_CONTEXT (resource_name) = ECMA_VALUE_UNDEFINED; +#endif /* JERRY_ENABLE_LINE_INFO */ + snapshot_globals_t globals; ecma_value_t parse_status; ecma_compiled_code_t *bytecode_data_p; @@ -1579,6 +1583,11 @@ jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source #ifdef JERRY_ENABLE_SNAPSHOT_SAVE ecma_value_t parse_status; ecma_compiled_code_t *bytecode_data_p; + +#ifdef JERRY_ENABLE_LINE_INFO + JERRY_CONTEXT (resource_name) = ECMA_VALUE_UNDEFINED; +#endif /* JERRY_ENABLE_LINE_INFO */ + parse_status = parser_parse_script (NULL, 0, source_p, diff --git a/jerry-core/api/jerry-snapshot.h b/jerry-core/api/jerry-snapshot.h index 1fe60e5ec..919855769 100644 --- a/jerry-core/api/jerry-snapshot.h +++ b/jerry-core/api/jerry-snapshot.h @@ -41,7 +41,7 @@ typedef struct /** * Jerry snapshot format version. */ -#define JERRY_SNAPSHOT_VERSION (11u) +#define JERRY_SNAPSHOT_VERSION (12u) /** * Snapshot configuration flags. diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 7070b76a2..3ae749b45 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -415,6 +415,11 @@ jerry_parse (const jerry_char_t *resource_name_p, /**< resource name (usually a #ifndef JERRY_DISABLE_JS_PARSER jerry_assert_api_available (); +#if defined JERRY_ENABLE_LINE_INFO && !defined JERRY_DISABLE_JS_PARSER + JERRY_CONTEXT (resource_name) = ecma_find_or_create_literal_string (resource_name_p, + (lit_utf8_size_t) resource_name_length); +#endif /* JERRY_ENABLE_LINE_INFO && !JERRY_DISABLE_JS_PARSER */ + ecma_compiled_code_t *bytecode_data_p; ecma_value_t parse_status; @@ -482,6 +487,11 @@ jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (u ecma_compiled_code_t *bytecode_data_p; ecma_value_t parse_status; +#ifdef JERRY_ENABLE_LINE_INFO + JERRY_CONTEXT (resource_name) = ecma_find_or_create_literal_string (resource_name_p, + (lit_utf8_size_t) resource_name_length); +#endif /* JERRY_ENABLE_LINE_INFO */ + if (arg_list_p == NULL) { /* Must not be a NULL value. */ @@ -874,6 +884,9 @@ bool jerry_is_feature_enabled (const jerry_feature_t feature) #ifndef CONFIG_DISABLE_REGEXP_BUILTIN || feature == JERRY_FEATURE_REGEXP #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ +#ifdef JERRY_ENABLE_LINE_INFO + || feature == JERRY_FEATURE_LINE_INFO +#endif /* JERRY_ENABLE_LINE_INFO */ ); } /* jerry_is_feature_enabled */ @@ -2845,6 +2858,18 @@ jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, /**< per #endif /* JERRY_VM_EXEC_STOP */ } /* jerry_set_vm_exec_stop_callback */ +/** + * Get backtrace. The backtrace is an array of strings where + * each string contains the position of the corresponding frame. + * The array length is zero if the backtrace is not available. + * + * @return array value + */ +jerry_value_t +jerry_get_backtrace (uint32_t max_depth) +{ + return vm_get_backtrace (max_depth); +} /* jerry_get_backtrace */ /** * Check if the given value is an ArrayBuffer object. diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function.c b/jerry-core/ecma/builtin-objects/ecma-builtin-function.c index fa203d409..eed3378be 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function.c @@ -21,8 +21,12 @@ #include "ecma-function-object.h" #include "ecma-lex-env.h" #include "ecma-try-catch-macro.h" -#include "lit-magic-strings.h" #include "js-parser.h" +#include "lit-magic-strings.h" + +#ifdef JERRY_ENABLE_LINE_INFO +#include "jcontext.h" +#endif /* JERRY_ENABLE_LINE_INFO */ #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" @@ -155,6 +159,10 @@ ecma_builtin_function_dispatch_construct (const ecma_value_t *arguments_list_p, ECMA_STRING_TO_UTF8_STRING (arguments_str_p, arguments_buffer_p, arguments_buffer_size); ECMA_STRING_TO_UTF8_STRING (function_body_str_p, function_body_buffer_p, function_body_buffer_size); +#ifdef JERRY_ENABLE_LINE_INFO + JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); +#endif /* JERRY_ENABLE_LINE_INFO */ + ecma_compiled_code_t *bytecode_data_p = NULL; ecma_value_t ret_value = parser_parse_script (arguments_buffer_p, diff --git a/jerry-core/ecma/operations/ecma-eval.c b/jerry-core/ecma/operations/ecma-eval.c index 4e4a34b63..994d39861 100644 --- a/jerry-core/ecma/operations/ecma-eval.c +++ b/jerry-core/ecma/operations/ecma-eval.c @@ -23,6 +23,10 @@ #include "js-parser.h" #include "vm.h" +#ifdef JERRY_ENABLE_LINE_INFO +#include "jcontext.h" +#endif /* JERRY_ENABLE_LINE_INFO */ + /** \addtogroup ecma ECMA * @{ * @@ -88,6 +92,10 @@ ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters b bool is_strict_call = (is_direct && is_called_from_strict_mode_code); +#ifdef JERRY_ENABLE_LINE_INFO + JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); +#endif /* JERRY_ENABLE_LINE_INFO */ + ecma_value_t parse_status = parser_parse_script (NULL, 0, code_p, diff --git a/jerry-core/ecma/operations/ecma-exceptions.c b/jerry-core/ecma/operations/ecma-exceptions.c index 9bb4746bc..f3e782b6b 100644 --- a/jerry-core/ecma/operations/ecma-exceptions.c +++ b/jerry-core/ecma/operations/ecma-exceptions.c @@ -24,6 +24,10 @@ #include "jcontext.h" #include "jrt.h" +#ifdef JERRY_ENABLE_LINE_INFO +#include "vm.h" +#endif /* JERRY_ENABLE_LINE_INFO */ + /** \addtogroup ecma ECMA * @{ * @@ -134,6 +138,24 @@ ecma_new_standard_error (ecma_standard_error_t error_type) /**< native error typ ((ecma_extended_object_t *) new_error_obj_p)->u.class_prop.class_id = LIT_MAGIC_STRING_ERROR_UL; +#ifdef JERRY_ENABLE_LINE_INFO + /* The "stack" identifier is not a magic string. */ + const char *stack_id_p = "stack"; + + ecma_string_t *stack_str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) stack_id_p, 5); + + ecma_property_value_t *prop_value_p = ecma_create_named_data_property (new_error_obj_p, + stack_str_p, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + NULL); + ecma_deref_ecma_string (stack_str_p); + + ecma_value_t backtrace_value = vm_get_backtrace (0); + + prop_value_p->value = backtrace_value; + ecma_deref_object (ecma_get_object_from_value (backtrace_value)); +#endif /* JERRY_ENABLE_LINE_INFO */ + return new_error_obj_p; } /* ecma_new_standard_error */ diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index b349b16af..bba7861f7 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -95,6 +95,7 @@ typedef enum JERRY_FEATURE_TYPEDARRAY, /**< Typedarray support */ JERRY_FEATURE_DATE, /**< Date support */ JERRY_FEATURE_REGEXP, /**< Regexp support */ + JERRY_FEATURE_LINE_INFO, /**< line info available */ JERRY_FEATURE__COUNT /**< number of features. NOTE: must be at the end of the list */ } jerry_feature_t; @@ -465,7 +466,7 @@ bool jerry_delete_property (const jerry_value_t obj_val, const jerry_value_t pro bool jerry_delete_property_by_index (const jerry_value_t obj_val, uint32_t index); jerry_value_t jerry_get_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); -jerry_value_t jerry_get_property_by_index (const jerry_value_t obj_val, uint32_t index); +jerry_value_t jerry_get_property_by_index (const jerry_value_t obj_val, uint32_t index); jerry_value_t jerry_set_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val, const jerry_value_t value_to_set); jerry_value_t jerry_set_property_by_index (const jerry_value_t obj_val, uint32_t index, @@ -531,6 +532,7 @@ jerry_instance_t *jerry_create_instance (uint32_t heap_size, jerry_instance_allo * Miscellaneous functions. */ void jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, void *user_p, uint32_t frequency); +jerry_value_t jerry_get_backtrace (uint32_t max_depth); /** * Array buffer components. diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index f37ac27d2..917c5e9c1 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -124,6 +124,10 @@ typedef struct int debugger_connection; /**< holds the file descriptor of the socket communication */ #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + ecma_value_t resource_name; /**< resource name (usually a file name) */ +#endif /* JERRY_ENABLE_LINE_INFO */ + #ifdef JMEM_STATS jmem_heap_stats_t jmem_heap_stats; /**< heap's memory usage statistics */ #endif /* JMEM_STATS */ diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index e8f234f37..a8db0884d 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -539,6 +539,10 @@ /* Basic opcodes. */ \ CBC_OPCODE (CBC_EXT_DEBUGGER, CBC_NO_FLAG, 0, \ VM_OC_NONE) \ + CBC_OPCODE (CBC_EXT_RESOURCE_NAME, CBC_NO_FLAG, 0, \ + VM_OC_RESOURCE_NAME) \ + CBC_OPCODE (CBC_EXT_LINE, CBC_NO_FLAG, 0, \ + VM_OC_LINE) \ \ /* Binary compound assignment opcodes with pushing the result. */ \ CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_ADD, \ diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index dd3a7cd52..0a5d6b195 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -308,8 +308,12 @@ typedef struct /** extra data for each breakpoint */ parser_breakpoint_info_t breakpoint_info[JERRY_DEBUGGER_MAX_BUFFER_SIZE / sizeof (parser_breakpoint_info_t)]; uint16_t breakpoint_info_count; /**< current breakpoint index */ - parser_line_counter_t last_breakpoint_line; /**< last line where breakpoint was inserted */ + parser_line_counter_t last_breakpoint_line; /**< last line where breakpoint has been inserted */ #endif /* JERRY_DEBUGGER */ + +#ifdef JERRY_ENABLE_LINE_INFO + parser_line_counter_t last_line_info_line; /**< last line where line info has been inserted */ +#endif /* JERRY_ENABLE_LINE_INFO */ } parser_context_t; /** @@ -485,6 +489,12 @@ void parser_send_breakpoints (parser_context_t *context_p, jerry_debugger_header #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + +void parser_emit_line_info (parser_context_t *context_p, uint32_t line, bool flush_cbc); + +#endif /* JERRY_ENABLE_LINE_INFO */ + /** * @} * @} diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index e06810b38..28b978f45 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -17,9 +17,9 @@ #ifndef JERRY_DISABLE_JS_PARSER -#ifdef JERRY_DEBUGGER +#if defined (JERRY_DEBUGGER) || defined (JERRY_ENABLE_LINE_INFO) #include "jcontext.h" -#endif /*JERRY_DEBUGGER */ +#endif /* JERRY_DEBUGGER || JERRY_ENABLE_LINE_INFO */ /** \addtogroup parser Parser * @{ @@ -314,9 +314,9 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ JERRY_ASSERT (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); -#ifdef JERRY_DEBUGGER +#if defined (JERRY_DEBUGGER) || defined (JERRY_ENABLE_LINE_INFO) parser_line_counter_t ident_line_counter = context_p->token.line; -#endif /* JERRY_DEBUGGER */ +#endif /* JERRY_DEBUGGER || JERRY_ENABLE_LINE_INFO */ context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; @@ -347,6 +347,13 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ } #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + if (ident_line_counter != context_p->last_line_info_line) + { + parser_emit_line_info (context_p, ident_line_counter, false); + } +#endif /* JERRY_ENABLE_LINE_INFO */ + parser_parse_expression (context_p, PARSE_EXPR_STATEMENT | PARSE_EXPR_NO_COMMA | PARSE_EXPR_HAS_LITERAL); } @@ -1080,6 +1087,10 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * switch_case_was_found = false; default_case_was_found = false; +#ifdef JERRY_ENABLE_LINE_INFO + uint32_t last_line_info_line = context_p->last_line_info_line; +#endif /* JERRY_ENABLE_LINE_INFO */ + while (true) { parser_scan_until (context_p, &unused_range, LEXER_KEYW_CASE); @@ -1134,6 +1145,13 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * lexer_next_token (context_p); +#ifdef JERRY_ENABLE_LINE_INFO + if (context_p->token.line != context_p->last_line_info_line) + { + parser_emit_line_info (context_p, context_p->token.line, true); + } +#endif /* JERRY_ENABLE_LINE_INFO */ + parser_parse_expression (context_p, PARSE_EXPR); if (context_p->token.type != LEXER_COLON) @@ -1148,6 +1166,10 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * JERRY_ASSERT (switch_case_was_found || default_case_was_found); +#ifdef JERRY_ENABLE_LINE_INFO + context_p->last_line_info_line = last_line_info_line; +#endif /* JERRY_ENABLE_LINE_INFO */ + if (!switch_case_was_found) { /* There was no case statement, so the expression result @@ -1634,6 +1656,15 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ } #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + if (JERRY_CONTEXT (resource_name) != ECMA_VALUE_UNDEFINED) + { + parser_emit_cbc_ext (context_p, CBC_EXT_RESOURCE_NAME); + parser_flush_cbc (context_p); + } + context_p->last_line_info_line = 0; +#endif /* JERRY_ENABLE_LINE_INFO */ + while (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_STRING_LITERAL) { @@ -1685,6 +1716,9 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ context_p->last_breakpoint_line = context_p->token.line; } #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + parser_emit_line_info (context_p, context_p->token.line, false); +#endif /* JERRY_ENABLE_LINE_INFO */ lexer_construct_literal_object (context_p, &lit_location, LEXER_STRING_LITERAL); parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); @@ -1755,6 +1789,20 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ } #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + if (context_p->token.line != context_p->last_line_info_line + && context_p->token.type != LEXER_SEMICOLON + && context_p->token.type != LEXER_LEFT_BRACE + && context_p->token.type != LEXER_RIGHT_BRACE + && context_p->token.type != LEXER_KEYW_VAR + && context_p->token.type != LEXER_KEYW_FUNCTION + && context_p->token.type != LEXER_KEYW_CASE + && context_p->token.type != LEXER_KEYW_DEFAULT) + { + parser_emit_line_info (context_p, context_p->token.line, true); + } +#endif /* JERRY_ENABLE_LINE_INFO */ + switch (context_p->token.type) { case LEXER_SEMICOLON: diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index 4b2c55451..e3c25b545 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -17,6 +17,10 @@ #ifndef JERRY_DISABLE_JS_PARSER +#ifdef JERRY_ENABLE_LINE_INFO +#include "jcontext.h" +#endif /* JERRY_ENABLE_LINE_INFO */ + /** \addtogroup parser Parser * @{ * @@ -352,6 +356,57 @@ parser_emit_cbc_push_number (parser_context_t *context_p, /**< context */ } } /* parser_emit_cbc_push_number */ +#ifdef JERRY_ENABLE_LINE_INFO + +/** + * Append a line info data + */ +void +parser_emit_line_info (parser_context_t *context_p, /**< context */ + uint32_t line, /**< current line */ + bool flush_cbc) /**< flush last byte code */ +{ + if (JERRY_CONTEXT (resource_name) == ECMA_VALUE_UNDEFINED) + { + return; + } + + if (flush_cbc && context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE) + { + parser_flush_cbc (context_p); + } + +#ifdef PARSER_DUMP_BYTE_CODE + if (context_p->is_show_opcodes) + { + JERRY_DEBUG_MSG (" [%3d] CBC_EXT_LINE %d\n", (int) context_p->stack_depth, line); + } +#endif /* PARSER_DUMP_BYTE_CODE */ + + parser_emit_two_bytes (context_p, CBC_EXT_OPCODE, CBC_EXT_LINE); + context_p->byte_code_size += 2; + + context_p->last_line_info_line = line; + + do + { + uint8_t byte = (uint8_t) (line & CBC_LOWER_SEVEN_BIT_MASK); + + line >>= 7; + + if (line > 0) + { + byte = (uint8_t) (byte | CBC_HIGHEST_BIT_MASK); + } + + PARSER_APPEND_TO_BYTE_CODE (context_p, byte); + context_p->byte_code_size++; + } + while (line > 0); +} /* parser_emit_line_info */ + +#endif /* JERRY_ENABLE_LINE_INFO */ + /** * Append a byte code with a branch argument */ diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 37519c3eb..d09520d33 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1292,6 +1292,24 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code flags = cbc_ext_flags[ext_opcode]; JERRY_DEBUG_MSG (" %3d : %s", (int) cbc_offset, cbc_ext_names[ext_opcode]); byte_code_p += 2; + +#ifdef JERRY_ENABLE_LINE_INFO + if (ext_opcode == CBC_EXT_LINE) + { + uint32_t value = 0; + uint8_t byte; + + do + { + byte = *byte_code_p++; + value = (value << 7) | (byte & CBC_LOWER_SEVEN_BIT_MASK); + } + while (byte & CBC_HIGHEST_BIT_MASK); + + JERRY_DEBUG_MSG (" %d\n", (int) value); + continue; + } +#endif /* JERRY_ENABLE_LINE_INFO */ } if (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)) @@ -1488,6 +1506,23 @@ parser_post_processing (parser_context_t *context_p) /**< context */ flags = cbc_ext_flags[ext_opcode]; PARSER_NEXT_BYTE (page_p, offset); length++; + +#ifdef JERRY_ENABLE_LINE_INFO + if (ext_opcode == CBC_EXT_LINE) + { + uint8_t last_byte = 0; + + do + { + last_byte = page_p->bytes[offset]; + PARSER_NEXT_BYTE (page_p, offset); + length++; + } + while (last_byte & CBC_HIGHEST_BIT_MASK); + + continue; + } +#endif /* JERRY_ENABLE_LINE_INFO */ } while (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)) @@ -1639,6 +1674,13 @@ parser_post_processing (parser_context_t *context_p) /**< context */ total_size += context_p->argument_count * sizeof (ecma_value_t); } +#ifdef JERRY_ENABLE_LINE_INFO + if (JERRY_CONTEXT (resource_name) != ECMA_VALUE_UNDEFINED) + { + total_size += sizeof (ecma_value_t); + } +#endif /* JERRY_ENABLE_LINE_INFO */ + #ifdef JERRY_ENABLE_SNAPSHOT_SAVE total_size_used = total_size; #endif @@ -1802,6 +1844,25 @@ parser_post_processing (parser_context_t *context_p) /**< context */ opcode_p++; real_offset++; PARSER_NEXT_BYTE_UPDATE (page_p, offset, real_offset); + +#ifdef JERRY_ENABLE_LINE_INFO + if (ext_opcode == CBC_EXT_LINE) + { + uint8_t last_byte = 0; + + do + { + last_byte = page_p->bytes[offset]; + *dst_p++ = last_byte; + + real_offset++; + PARSER_NEXT_BYTE_UPDATE (page_p, offset, real_offset); + } + while (last_byte & CBC_HIGHEST_BIT_MASK); + + continue; + } +#endif /* JERRY_ENABLE_LINE_INFO */ } if (flags & CBC_HAS_BRANCH_ARG) @@ -1994,6 +2055,21 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } } +#ifdef JERRY_ENABLE_LINE_INFO + if (JERRY_CONTEXT (resource_name) != ECMA_VALUE_UNDEFINED) + { + ecma_value_t *resource_name_p = (ecma_value_t *) (((uint8_t *) compiled_code_p) + total_size); + + if ((context_p->status_flags & PARSER_ARGUMENTS_NEEDED) + && !(context_p->status_flags & PARSER_IS_STRICT)) + { + resource_name_p -= context_p->argument_count; + } + + resource_name_p[-1] = JERRY_CONTEXT (resource_name); + } +#endif /* JERRY_ENABLE_LINE_INFO */ + if (context_p->status_flags & PARSER_NAMED_FUNCTION_EXP) { ECMA_SET_INTERNAL_VALUE_POINTER (literal_pool_p[const_literal_end], diff --git a/jerry-core/vm/vm-defines.h b/jerry-core/vm/vm-defines.h index b0fd1fe34..9ad4c3a5e 100644 --- a/jerry-core/vm/vm-defines.h +++ b/jerry-core/vm/vm-defines.h @@ -51,6 +51,10 @@ typedef struct vm_frame_ctx_t struct vm_frame_ctx_t *prev_context_p; /**< previous context */ ecma_value_t this_binding; /**< this binding */ ecma_value_t call_block_result; /**< preserve block result during a call */ +#ifdef JERRY_ENABLE_LINE_INFO + ecma_value_t resource_name; /**< current resource name (usually a file name) */ + uint32_t current_line; /**< currently executed line */ +#endif /* JERRY_ENABLE_LINE_INFO */ uint16_t context_depth; /**< current context depth */ uint8_t is_eval_code; /**< eval mode flag */ uint8_t call_operation; /**< perform a call or construct operation */ diff --git a/jerry-core/vm/vm-utils.c b/jerry-core/vm/vm-utils.c new file mode 100644 index 000000000..a79a4b95a --- /dev/null +++ b/jerry-core/vm/vm-utils.c @@ -0,0 +1,133 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-array-object.h" +#include "ecma-helpers.h" +#include "jcontext.h" +#include "vm.h" + +/** + * Check whether currently executed code is strict mode code + * + * @return true - current code is executed in strict mode, + * false - otherwise + */ +bool +vm_is_strict_mode (void) +{ + JERRY_ASSERT (JERRY_CONTEXT (vm_top_context_p) != NULL); + + return JERRY_CONTEXT (vm_top_context_p)->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE; +} /* vm_is_strict_mode */ + +/** + * Check whether currently performed call (on top of call-stack) is performed in form, + * meeting conditions of 'Direct Call to Eval' (see also: ECMA-262 v5, 15.1.2.1.1) + * + * Warning: + * the function should only be called from implementation + * of built-in 'eval' routine of Global object + * + * @return true - currently performed call is performed through 'eval' identifier, + * without 'this' argument, + * false - otherwise + */ +inline bool __attr_always_inline___ +vm_is_direct_eval_form_call (void) +{ + return (JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL) != 0; +} /* vm_is_direct_eval_form_call */ + +/** + * Get backtrace. The backtrace is an array of strings where + * each string contains the position of the corresponding frame. + * The array length is zero if the backtrace is not available. + * + * @return array ecma value + */ +ecma_value_t +vm_get_backtrace (uint32_t max_depth) /**< maximum backtrace depth, 0 = unlimited */ +{ +#ifdef JERRY_ENABLE_LINE_INFO + ecma_value_t result_array = ecma_op_create_array_object (NULL, 0, false); + + if (max_depth == 0) + { + max_depth = UINT32_MAX; + } + + vm_frame_ctx_t *context_p = JERRY_CONTEXT (vm_top_context_p); + ecma_object_t *array_p = ecma_get_object_from_value (result_array); + uint32_t index = 0; + + while (context_p != NULL) + { + if (context_p->resource_name == ECMA_VALUE_UNDEFINED) + { + context_p = context_p->prev_context_p; + continue; + } + + ecma_string_t *str_p = ecma_get_string_from_value (context_p->resource_name); + + if (ecma_string_is_empty (str_p)) + { + const char *unknown_str_p = ":"; + str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) unknown_str_p, + (lit_utf8_size_t) strlen (unknown_str_p)); + } + else + { + ecma_ref_ecma_string (str_p); + str_p = ecma_append_magic_string_to_string (str_p, LIT_MAGIC_STRING_COLON_CHAR); + } + + ecma_string_t *line_str_p = ecma_new_ecma_string_from_uint32 (context_p->current_line); + str_p = ecma_concat_ecma_strings (str_p, line_str_p); + ecma_deref_ecma_string (line_str_p); + + ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); + ecma_property_value_t *prop_value_p; + prop_value_p = ecma_create_named_data_property (array_p, + index_str_p, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + ecma_deref_ecma_string (index_str_p); + + prop_value_p->value = ecma_make_string_value (str_p); + + context_p = context_p->prev_context_p; + index++; + + if (index >= max_depth) + { + break; + } + } + + if (index > 0) + { + JERRY_ASSERT (ecma_get_object_type (array_p) == ECMA_OBJECT_TYPE_ARRAY); + + ((ecma_extended_object_t *) array_p)->u.array.length = index; + } + + return result_array; +#else /* !JERRY_ENABLE_LINE_INFO */ + JERRY_UNUSED (max_depth); + + return ecma_op_create_array_object (NULL, 0, false); +#endif /* JERRY_ENABLE_LINE_INFO */ +} /* vm_get_backtrace */ diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 6755fb504..8b094df52 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -2596,6 +2596,52 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ #endif /* JERRY_DEBUGGER */ continue; } +#ifdef JERRY_ENABLE_LINE_INFO + case VM_OC_RESOURCE_NAME: + { + ecma_length_t formal_params_number = 0; + + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) + { + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; + + formal_params_number = args_p->argument_end; + } + else + { + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; + + formal_params_number = args_p->argument_end; + } + } + + uint8_t *byte_p = (uint8_t *) bytecode_header_p; + byte_p += ((size_t) bytecode_header_p->size) << JMEM_ALIGNMENT_LOG; + + ecma_value_t *resource_name_p = (ecma_value_t *) byte_p; + resource_name_p -= formal_params_number; + + frame_ctx_p->resource_name = resource_name_p[-1]; + continue; + } + case VM_OC_LINE: + { + uint32_t value = 0; + uint8_t byte; + + do + { + byte = *byte_code_p++; + value = (value << 7) | (byte & CBC_LOWER_SEVEN_BIT_MASK); + } + while (byte & CBC_HIGHEST_BIT_MASK); + + frame_ctx_p->current_line = value; + continue; + } +#endif /* JERRY_ENABLE_LINE_INFO */ default: { JERRY_UNREACHABLE (); @@ -2990,6 +3036,10 @@ vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data heade frame_ctx.lex_env_p = lex_env_p; frame_ctx.prev_context_p = JERRY_CONTEXT (vm_top_context_p); frame_ctx.this_binding = this_binding_value; +#ifdef JERRY_ENABLE_LINE_INFO + frame_ctx.resource_name = ECMA_VALUE_UNDEFINED; + frame_ctx.current_line = 0; +#endif /* JERRY_ENABLE_LINE_INFO */ frame_ctx.context_depth = 0; frame_ctx.is_eval_code = is_eval_code; frame_ctx.call_operation = VM_NO_EXEC_OP; @@ -3001,38 +3051,6 @@ vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data heade return vm_execute (&frame_ctx, arg_list_p, arg_list_len); } /* vm_run */ -/** - * Check whether currently executed code is strict mode code - * - * @return true - current code is executed in strict mode, - * false - otherwise - */ -bool -vm_is_strict_mode (void) -{ - JERRY_ASSERT (JERRY_CONTEXT (vm_top_context_p) != NULL); - - return JERRY_CONTEXT (vm_top_context_p)->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE; -} /* vm_is_strict_mode */ - -/** - * Check whether currently performed call (on top of call-stack) is performed in form, - * meeting conditions of 'Direct Call to Eval' (see also: ECMA-262 v5, 15.1.2.1.1) - * - * Warning: - * the function should only be called from implementation - * of built-in 'eval' routine of Global object - * - * @return true - currently performed call is performed through 'eval' identifier, - * without 'this' argument, - * false - otherwise - */ -inline bool __attr_always_inline___ -vm_is_direct_eval_form_call (void) -{ - return (JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL) != 0; -} /* vm_is_direct_eval_form_call */ - /** * @} * @} diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index d243b8d1d..1aedee480 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -203,8 +203,10 @@ typedef enum VM_OC_FINALLY, /**< finally */ VM_OC_CONTEXT_END, /**< context end */ VM_OC_JUMP_AND_EXIT_CONTEXT, /**< jump and exit context */ - VM_OC_BREAKPOINT_ENABLED, /**< enabled breakpoint for debugger */ - VM_OC_BREAKPOINT_DISABLED, /**< disabled breakpoint for debugger */ + VM_OC_BREAKPOINT_ENABLED, /**< enabled breakpoint for debugger */ + VM_OC_BREAKPOINT_DISABLED, /**< disabled breakpoint for debugger */ + VM_OC_RESOURCE_NAME, /**< resource name of the current function */ + VM_OC_LINE, /**< line number of the next statement */ } vm_oc_types; /** @@ -286,6 +288,8 @@ ecma_value_t vm_run (const ecma_compiled_code_t *bytecode_header_p, ecma_value_t bool vm_is_strict_mode (void); bool vm_is_direct_eval_form_call (void); +ecma_value_t vm_get_backtrace (uint32_t max_depth); + /** * @} * @} diff --git a/jerry-main/main-unix.c b/jerry-main/main-unix.c index 8f3faa946..260cc190b 100644 --- a/jerry-main/main-unix.c +++ b/jerry-main/main-unix.c @@ -89,9 +89,58 @@ print_unhandled_exception (jerry_value_t error_value) /**< error value */ { assert (!jerry_value_has_error_flag (error_value)); + jerry_char_t err_str_buf[256]; + + if (jerry_value_is_object (error_value)) + { + jerry_value_t stack_str = jerry_create_string ((const jerry_char_t *) "stack"); + jerry_value_t backtrace_val = jerry_get_property (error_value, stack_str); + jerry_release_value (stack_str); + + if (!jerry_value_has_error_flag (backtrace_val) + && jerry_value_is_array (backtrace_val)) + { + printf ("Exception backtrace:\n"); + + uint32_t length = jerry_get_array_length (backtrace_val); + + /* This length should be enough. */ + if (length > 32) + { + length = 32; + } + + for (uint32_t i = 0; i < length; i++) + { + jerry_value_t item_val = jerry_get_property_by_index (backtrace_val, i); + + if (!jerry_value_has_error_flag (item_val) + && jerry_value_is_string (item_val)) + { + jerry_size_t str_size = jerry_get_string_size (item_val); + + if (str_size >= 256) + { + printf ("%3d: [Backtrace string too long]\n", i); + } + else + { + jerry_size_t string_end = jerry_string_to_char_buffer (item_val, err_str_buf, str_size); + assert (string_end == str_size); + err_str_buf[string_end] = 0; + + printf ("%3d: %s\n", i, err_str_buf); + } + } + + jerry_release_value (item_val); + } + } + jerry_release_value (backtrace_val); + } + jerry_value_t err_str_val = jerry_value_to_string (error_value); jerry_size_t err_str_size = jerry_get_string_size (err_str_val); - jerry_char_t err_str_buf[256]; if (err_str_size >= 256) { diff --git a/tests/unit-core/test-backtrace.c b/tests/unit-core/test-backtrace.c new file mode 100644 index 000000000..02fdf5fd7 --- /dev/null +++ b/tests/unit-core/test-backtrace.c @@ -0,0 +1,202 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include "jerryscript.h" +#include "test-common.h" + +static jerry_value_t +backtrace_handler (const jerry_value_t function_obj, /**< function object */ + const jerry_value_t this_val, /**< this value */ + const jerry_value_t args_p[], /**< argument list */ + const jerry_length_t args_count) /**< argument count */ +{ + JERRY_UNUSED (function_obj); + JERRY_UNUSED (this_val); + + uint32_t max_depth = 0; + + if (args_count > 0 && jerry_value_is_number (args_p[0])) + { + max_depth = (uint32_t) jerry_get_number_value (args_p[0]); + } + + return jerry_get_backtrace (max_depth); +} /* backtrace_handler */ + +static jerry_value_t +run (const char *resource_name_p, /**< resource name */ + const char *source_p) /**< source code */ +{ + jerry_value_t code = jerry_parse ((const jerry_char_t *) resource_name_p, + strlen (resource_name_p), + (const jerry_char_t *) source_p, + strlen (source_p), + JERRY_PARSE_NO_OPTS); + TEST_ASSERT (!jerry_value_has_error_flag (code)); + + jerry_value_t result = jerry_run (code); + jerry_release_value (code); + + return result; +} /* run */ + +static void +compare (jerry_value_t array, /**< array */ + uint32_t index, /**< item index */ + const char *str) /**< string to compare */ +{ + jerry_char_t buf[64]; + + size_t len = strlen (str); + + TEST_ASSERT (len < sizeof (buf)); + + jerry_value_t value = jerry_get_property_by_index (array, index); + + TEST_ASSERT (!jerry_value_has_error_flag (value) + && jerry_value_is_string (value)); + + TEST_ASSERT (jerry_get_string_size (value) == len); + + jerry_size_t str_len = jerry_string_to_char_buffer (value, buf, (jerry_size_t) len); + TEST_ASSERT (str_len == len); + + jerry_release_value (value); + + TEST_ASSERT (memcmp (buf, str, len) == 0); +} /* compare */ + +int +main (void) +{ + TEST_INIT (); + + TEST_ASSERT (jerry_is_feature_enabled (JERRY_FEATURE_LINE_INFO)); + + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t global = jerry_get_global_object (); + + jerry_value_t func = jerry_create_external_function (backtrace_handler); + jerry_value_t name = jerry_create_string ((const jerry_char_t *) "backtrace"); + jerry_value_t result = jerry_set_property (global, name, func); + TEST_ASSERT (!jerry_value_has_error_flag (result)); + + jerry_release_value (result); + jerry_release_value (name); + jerry_release_value (func); + + jerry_release_value (global); + + const char *source = ("function f() {\n" + " return backtrace(0);\n" + "}\n" + "\n" + "function g() {\n" + " return f();\n" + "}\n" + "\n" + "function h() {\n" + " return g();\n" + "}\n" + "\n" + "h();\n"); + + jerry_value_t backtrace = run ("something.js", source); + + TEST_ASSERT (!jerry_value_has_error_flag (backtrace) + && jerry_value_is_array (backtrace)); + + TEST_ASSERT (jerry_get_array_length (backtrace) == 4); + + compare (backtrace, 0, "something.js:2"); + compare (backtrace, 1, "something.js:6"); + compare (backtrace, 2, "something.js:10"); + compare (backtrace, 3, "something.js:13"); + + jerry_release_value (backtrace); + + /* Depth set to 2 this time. */ + + source = ("function f() {\n" + " return backtrace(2);\n" + "}\n" + "\n" + "function g() {\n" + " return f();\n" + "}\n" + "\n" + "function h() {\n" + " return g();\n" + "}\n" + "\n" + "h();\n"); + + backtrace = run ("something_else.js", source); + + TEST_ASSERT (!jerry_value_has_error_flag (backtrace) + && jerry_value_is_array (backtrace)); + + TEST_ASSERT (jerry_get_array_length (backtrace) == 2); + + compare (backtrace, 0, "something_else.js:2"); + compare (backtrace, 1, "something_else.js:6"); + + jerry_release_value (backtrace); + + jerry_cleanup (); + + jerry_init (JERRY_INIT_EMPTY); + + source = ("function f() {\n" + " undef_reference;\n" + "}\n" + "\n" + "function g() {\n" + " return f();\n" + "}\n" + "\n" + "g();\n"); + + jerry_value_t error = run ("bad.js", source); + + TEST_ASSERT (jerry_value_has_error_flag (error)); + + jerry_value_clear_error_flag (&error); + + TEST_ASSERT (jerry_value_is_object (error)); + + name = jerry_create_string ((const jerry_char_t *) "stack"); + backtrace = jerry_get_property (error, name); + + jerry_release_value (name); + jerry_release_value (error); + + TEST_ASSERT (!jerry_value_has_error_flag (backtrace) + && jerry_value_is_array (backtrace)); + + TEST_ASSERT (jerry_get_array_length (backtrace) == 3); + + compare (backtrace, 0, "bad.js:2"); + compare (backtrace, 1, "bad.js:6"); + compare (backtrace, 2, "bad.js:9"); + + jerry_release_value (backtrace); + + jerry_cleanup (); + + return 0; +} /* main */ diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index 61d7fed5d..cd44f3366 100644 --- a/tests/unit-core/test-snapshot.c +++ b/tests/unit-core/test-snapshot.c @@ -216,7 +216,7 @@ main (void) /* Check the snapshot data. Unused bytes should be filled with zeroes */ const uint8_t expected_data[] = { - 0x4A, 0x52, 0x52, 0x59, 0x0B, 0x00, 0x00, 0x00, + 0x4A, 0x52, 0x52, 0x59, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, diff --git a/tools/build.py b/tools/build.py index 1332a5e50..87bd70ebc 100755 --- a/tools/build.py +++ b/tools/build.py @@ -86,6 +86,8 @@ def get_arguments(): help='build default jerry port implementation (%(choices)s; default: %(default)s)') parser.add_argument('--js-parser', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper, help='enable js-parser (%(choices)s; default: %(default)s)') + parser.add_argument('--line-info', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper, + help='provide line info (%(choices)s; default: %(default)s)') parser.add_argument('--link-lib', metavar='OPT', action='append', default=[], help='add custom library to be linked') parser.add_argument('--linker-flag', metavar='OPT', action='append', default=[], @@ -152,6 +154,7 @@ def generate_build_options(arguments): build_options.append('-DEXTERNAL_COMPILE_FLAGS=' + ' '.join(arguments.compile_flag)) build_options.append('-DFEATURE_CPOINTER_32_BIT=%s' % arguments.cpointer_32bit) build_options.append('-DFEATURE_ERROR_MESSAGES=%s' % arguments.error_messages) + build_options.append('-DFEATURE_LINE_INFO=%s' % arguments.line_info) build_options.append('-DJERRY_CMDLINE=%s' % arguments.jerry_cmdline) build_options.append('-DJERRY_CMDLINE_TEST=%s' % arguments.jerry_cmdline_test) build_options.append('-DJERRY_CMDLINE_SNAPSHOT=%s' % arguments.jerry_cmdline_snapshot) diff --git a/tools/run-tests.py b/tools/run-tests.py index 31a6b6dd1..970dc2b29 100755 --- a/tools/run-tests.py +++ b/tools/run-tests.py @@ -34,11 +34,13 @@ def get_binary_path(bin_dir_path): # Test options for unittests JERRY_UNITTESTS_OPTIONS = [ Options('unittests', - ['--unittests', '--jerry-cmdline=off', '--error-messages=on', '--snapshot-save=on', - '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es2015-subset', '--mem-stats=on']), + ['--unittests', '--profile=es2015-subset', '--jerry-cmdline=off', '--error-messages=on', + '--snapshot-save=on', '--snapshot-exec=on', '--line-info=on', '--vm-exec-stop=on', + '--mem-stats=on']), Options('unittests-debug', - ['--unittests', '--jerry-cmdline=off', '--debug', '--error-messages=on', '--snapshot-save=on', - '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es2015-subset', '--mem-stats=on']), + ['--unittests', '--debug', '--profile=es2015-subset', '--jerry-cmdline=off', + '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--line-info=on', + '--vm-exec-stop=on', '--mem-stats=on']), Options('doctests', ['--doctests', '--jerry-cmdline=off', '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es2015-subset']), @@ -46,11 +48,13 @@ JERRY_UNITTESTS_OPTIONS = [ ['--doctests', '--jerry-cmdline=off', '--debug', '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es2015-subset']), Options('unittests-es5.1', - ['--unittests', '--jerry-cmdline=off', '--error-messages=on', '--snapshot-save=on', - '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es5.1', '--mem-stats=on']), + ['--unittests', '--profile=es5.1', '--jerry-cmdline=off', '--error-messages=on', + '--snapshot-save=on', '--snapshot-exec=on', '--line-info=on', '--vm-exec-stop=on', + '--mem-stats=on']), Options('unittests-es5.1-debug', - ['--unittests', '--jerry-cmdline=off', '--debug', '--error-messages=on', '--snapshot-save=on', - '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es5.1', '--mem-stats=on']), + ['--unittests', '--debug', '--profile=es5.1', '--jerry-cmdline=off', + '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--line-info=on', + '--vm-exec-stop=on', '--mem-stats=on']), Options('doctests-es5.1', ['--doctests', '--jerry-cmdline=off', '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on', '--profile=es5.1']),