mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Add line info support. (#2286)
Add line info data to byte, which allows getting a backtrace info directly from the engine. Snapshots are not supported. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
parent
095b730f9d
commit
5e097dc354
@ -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
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -41,7 +41,7 @@ typedef struct
|
||||
/**
|
||||
* Jerry snapshot format version.
|
||||
*/
|
||||
#define JERRY_SNAPSHOT_VERSION (11u)
|
||||
#define JERRY_SNAPSHOT_VERSION (12u)
|
||||
|
||||
/**
|
||||
* Snapshot configuration flags.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 */
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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, \
|
||||
|
||||
@ -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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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],
|
||||
|
||||
@ -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 */
|
||||
|
||||
133
jerry-core/vm/vm-utils.c
Normal file
133
jerry-core/vm/vm-utils.c
Normal file
@ -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 = "<unknown>:";
|
||||
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 */
|
||||
@ -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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
202
tests/unit-core/test-backtrace.c
Normal file
202
tests/unit-core/test-backtrace.c
Normal file
@ -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 */
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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']),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user