Improve breakpoint generator of the debugger. (#1652)

Now the debugger generates a breakpoint for each function before
its first executable statement. This allows inspecting the function
arguments. Position (line and column) info is also added which
simplifies finding of anonymus functions. Several tests were
update to check more corner cases.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2017-03-13 11:36:34 +01:00
committed by GitHub
parent 57ea06782b
commit 679500b327
30 changed files with 409 additions and 226 deletions
@@ -52,6 +52,7 @@
#define PARSER_ARGUMENTS_NOT_NEEDED 0x04000u
#define PARSER_LEXICAL_ENV_NEEDED 0x08000u
#define PARSER_HAS_LATE_LIT_INIT 0x10000u
#define PARSER_DEBUGGER_BREAKPOINT_APPENDED 0x20000u
/* Expression parsing flags. */
#define PARSE_EXPR 0x00
+36 -27
View File
@@ -315,7 +315,7 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
#ifdef JERRY_DEBUGGER
parser_line_counter_t ident_line_counter = context_p->line;
parser_line_counter_t ident_line_counter = context_p->token.line;
#endif /* JERRY_DEBUGGER */
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR;
@@ -327,26 +327,23 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
if (context_p->token.type == LEXER_ASSIGN)
{
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& ident_line_counter != context_p->last_breakpoint_line)
{
if (ident_line_counter != context_p->last_breakpoint_line)
{
JERRY_DEBUG_MSG ("Insert var breakpoint: %d (%d)\n", ident_line_counter, context_p->last_breakpoint_line);
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
cbc_argument_t last_cbc = context_p->last_cbc;
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
cbc_argument_t last_cbc = context_p->last_cbc;
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
parser_flush_cbc (context_p);
parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
parser_flush_cbc (context_p);
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, ident_line_counter);
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, ident_line_counter);
context_p->last_cbc_opcode = CBC_PUSH_LITERAL;
context_p->last_cbc = last_cbc;
context_p->last_cbc_opcode = CBC_PUSH_LITERAL;
context_p->last_cbc = last_cbc;
context_p->last_breakpoint_line = ident_line_counter;
}
context_p->last_breakpoint_line = ident_line_counter;
}
#endif /* JERRY_DEBUGGER */
@@ -381,6 +378,11 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FUNCTION);
#ifdef JERRY_DEBUGGER
parser_line_counter_t debugger_line = context_p->token.line;
parser_line_counter_t debugger_column = context_p->token.column;
#endif /* JERRY_DEBUGGER */
lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
@@ -404,8 +406,13 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
jerry_debugger_send_function_name (name_p->u.char_p,
name_p->prop.length);
jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME,
name_p->u.char_p,
name_p->prop.length);
/* Reset token position for the function. */
context_p->token.line = debugger_line;
context_p->token.column = debugger_column;
}
#endif /* JERRY_DEBUGGER */
@@ -1618,6 +1625,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED;
context_p->last_breakpoint_line = 0;
}
#endif /* JERRY_DEBUGGER */
@@ -1656,22 +1664,23 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
|| context_p->token.type == LEXER_LEFT_SQUARE
|| context_p->token.type == LEXER_DOT)
{
/* The string is part of an expression statement. */
context_p->status_flags = status_flags;
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED
&& context_p->line != context_p->last_breakpoint_line)
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
JERRY_ASSERT (context_p->last_breakpoint_line == 0);
parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
parser_flush_cbc (context_p);
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, context_p->line);
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, context_p->token.line);
context_p->last_breakpoint_line = context_p->line;
context_p->last_breakpoint_line = context_p->token.line;
}
#endif /* JERRY_DEBUGGER */
/* The string is part of an expression statement. */
context_p->status_flags = status_flags;
lexer_construct_literal_object (context_p, &lit_location, LEXER_STRING_LITERAL);
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
/* The extra_value is used for saving the token. */
@@ -1723,7 +1732,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED
&& context_p->line != context_p->last_breakpoint_line
&& context_p->token.line != context_p->last_breakpoint_line
&& context_p->token.type != LEXER_SEMICOLON
&& context_p->token.type != LEXER_LEFT_BRACE
&& context_p->token.type != LEXER_RIGHT_BRACE
@@ -1735,9 +1744,9 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
parser_flush_cbc (context_p);
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, context_p->line);
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, context_p->token.line);
context_p->last_breakpoint_line = context_p->line;
context_p->last_breakpoint_line = context_p->token.line;
}
#endif /* JERRY_DEBUGGER */
+29 -23
View File
@@ -1251,8 +1251,8 @@ parser_post_processing (parser_context_t *context_p) /**< context */
uint16_t initialized_var_end;
uint16_t const_literal_end;
parser_mem_page_t *page_p;
parser_mem_page_t *last_page_p = context_p->byte_code.last_p;
size_t last_position = context_p->byte_code.last_position;
parser_mem_page_t *last_page_p;
size_t last_position;
size_t offset;
size_t length;
size_t total_size;
@@ -1273,6 +1273,18 @@ parser_post_processing (parser_context_t *context_p) /**< context */
JERRY_ASSERT (context_p->literal_count <= PARSER_MAXIMUM_NUMBER_OF_LITERALS);
#ifdef JERRY_DEBUGGER
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& !(context_p->status_flags & PARSER_DEBUGGER_BREAKPOINT_APPENDED))
{
/* Always provide at least one breakpoint. */
parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
parser_flush_cbc (context_p);
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, context_p->token.line);
context_p->last_breakpoint_line = context_p->token.line;
}
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& context_p->breakpoint_info_count > 0)
{
@@ -1281,6 +1293,9 @@ parser_post_processing (parser_context_t *context_p) /**< context */
}
#endif /* JERRY_DEBUGGER */
last_page_p = context_p->byte_code.last_p;
last_position = context_p->byte_code.last_position;
initializers_length = parser_compute_indicies (context_p,
&ident_end,
&uninitialized_var_end,
@@ -1897,7 +1912,6 @@ parser_parse_source (const uint8_t *source_p, /**< valid UTF-8 source code */
#ifdef JERRY_DEBUGGER
context.breakpoint_info_count = 0;
context.last_breakpoint_line = 0;
#endif /* JERRY_DEBUGGER */
PARSER_TRY (context.try_buffer)
@@ -2047,22 +2061,8 @@ parser_parse_function (parser_context_t *context_p, /**< context */
#endif /* PARSER_DUMP_BYTE_CODE */
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
/* This option has a high memory and performance costs,
* but it is necessary for executing eval operations by the debugger. */
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE;
if (context_p->line != context_p->last_breakpoint_line)
{
parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
parser_flush_cbc (context_p);
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, context_p->line);
context_p->last_breakpoint_line = context_p->line;
}
}
parser_line_counter_t debugger_line = context_p->token.line;
parser_line_counter_t debugger_column = context_p->token.column;
#endif /* JERRY_DEBUGGER */
lexer_next_token (context_p);
@@ -2078,8 +2078,9 @@ parser_parse_function (parser_context_t *context_p, /**< context */
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
jerry_debugger_send_function_name (context_p->lit_object.literal_p->u.char_p,
context_p->lit_object.literal_p->prop.length);
jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME,
context_p->lit_object.literal_p->u.char_p,
context_p->lit_object.literal_p->prop.length);
}
#endif /* JERRY_DEBUGGER */
@@ -2101,9 +2102,12 @@ parser_parse_function (parser_context_t *context_p, /**< context */
}
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& jerry_debugger_send_parse_function (debugger_line, debugger_column))
{
jerry_debugger_send_type (JERRY_DEBUGGER_PARSE_FUNCTION);
/* This option has a high memory and performance costs,
* but it is necessary for executing eval operations by the debugger. */
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE;
}
#endif /* JERRY_DEBUGGER */
@@ -2317,6 +2321,8 @@ parser_append_breakpoint_info (parser_context_t *context_p, /**< context */
{
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
context_p->status_flags |= PARSER_DEBUGGER_BREAKPOINT_APPENDED;
if (context_p->breakpoint_info_count >= JERRY_DEBUGGER_SEND_MAX (parser_list_t))
{
parser_send_breakpoints (context_p, type);