From 1a16688bc0da122c31ab0c96af4287346f14ce28 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Tue, 23 Jan 2018 00:08:24 -0800 Subject: [PATCH] Fix inserting pending breakpoints. Before this patch the JS execution is started right after the parsing is completed. The problem is that some parts of the JS code is executed before the debugger had any chance to insert pending breakpoints due to network latency. This patch adds a delay after parsing when at least one pendding breakpoint is available. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/api/jerry-debugger.c | 16 ++- jerry-core/debugger/debugger-ws.c | 8 +- jerry-core/debugger/debugger.c | 73 ++++++++---- jerry-core/debugger/debugger.h | 97 ++++++++++----- jerry-core/jcontext/jcontext.h | 6 +- jerry-core/parser/js/js-parser.c | 24 +++- jerry-debugger/jerry-client-ws.html | 53 +++++---- jerry-debugger/jerry-client-ws.py | 112 +++++++++++------- tests/debugger/do_pending_breakpoints.cmd | 6 +- .../debugger/do_pending_breakpoints.expected | 21 ++-- tests/debugger/do_pending_breakpoints.js | 2 +- 11 files changed, 271 insertions(+), 147 deletions(-) diff --git a/jerry-core/api/jerry-debugger.c b/jerry-core/api/jerry-debugger.c index 0e9802f1ae..627727b5dc 100644 --- a/jerry-core/api/jerry-debugger.c +++ b/jerry-core/api/jerry-debugger.c @@ -43,7 +43,7 @@ jerry_debugger_stop (void) if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; } #endif /* JERRY_DEBUGGER */ @@ -59,7 +59,7 @@ jerry_debugger_continue (void) if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; } #endif /* JERRY_DEBUGGER */ @@ -77,11 +77,11 @@ jerry_debugger_stop_at_breakpoint (bool enable_stop_at_breakpoint) /**< enable/d { if (enable_stop_at_breakpoint) { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_IGNORE); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE); } else { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_VM_IGNORE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE); } } #else /* !JERRY_DEBUGGER */ @@ -122,7 +122,7 @@ jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_CLIENT_SOURCE_MODE); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); jerry_debugger_uint8_data_t *client_source_data_p = NULL; jerry_debugger_wait_for_source_status_t ret_type = JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED; @@ -142,8 +142,7 @@ jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONTEXT_RESET_MODE)) { ret_type = JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED; - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) - & ~JERRY_DEBUGGER_CONTEXT_RESET_MODE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CONTEXT_RESET_MODE); break; } @@ -151,8 +150,7 @@ jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_NO_SOURCE)) { ret_type = JERRY_DEBUGGER_SOURCE_END; - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) - & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); break; } diff --git a/jerry-core/debugger/debugger-ws.c b/jerry-core/debugger/debugger-ws.c index 411724924f..04fdf0aab1 100644 --- a/jerry-core/debugger/debugger-ws.c +++ b/jerry-core/debugger/debugger-ws.c @@ -69,7 +69,7 @@ jerry_debugger_close_connection_tcp (bool log_error) /**< log error */ { JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); - JERRY_CONTEXT (debugger_flags) = (uint8_t) JERRY_DEBUGGER_VM_IGNORE; + JERRY_CONTEXT (debugger_flags) = JERRY_DEBUGGER_VM_IGNORE; if (log_error) { @@ -360,7 +360,7 @@ jerry_debugger_accept_connection (void) close (server_socket); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_CONNECTED); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CONNECTED); bool is_handshake_ok = false; @@ -399,7 +399,7 @@ jerry_debugger_accept_connection (void) jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Connected from: %s\n", inet_ntoa (addr.sin_addr)); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; return true; @@ -444,7 +444,7 @@ jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p) /**< [out] { JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); - JERRY_ASSERT (message_data_p != NULL ? (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE) + JERRY_ASSERT (message_data_p != NULL ? !!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE) : !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE)); JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY; diff --git a/jerry-core/debugger/debugger.c b/jerry-core/debugger/debugger.c index 06e7c58eac..f58957411b 100644 --- a/jerry-core/debugger/debugger.c +++ b/jerry-core/debugger/debugger.c @@ -34,8 +34,8 @@ * The number of message types in the debugger should reflect the * debugger versioning. */ -JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 26 - && JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 16 +JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 27 + && JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 18 && JERRY_DEBUGGER_VERSION == 1, debugger_version_correlates_to_message_type_count); @@ -154,9 +154,9 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE)); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_IGNORE); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE); ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p, eval_string_size, true, false); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_VM_IGNORE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE); if (!ECMA_IS_VALUE_ERROR (result)) { @@ -325,8 +325,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec else { result = true; - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) - & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); *resume_exec_p = true; } @@ -407,7 +406,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec { JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; *resume_exec_p = false; return true; @@ -417,7 +416,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec { JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; *resume_exec_p = true; return true; @@ -427,7 +426,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec { JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; *resume_exec_p = true; return true; @@ -437,7 +436,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec { JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = JERRY_CONTEXT (vm_top_context_p); *resume_exec_p = true; return true; @@ -456,20 +455,51 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t); JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_exception_config_t, exception_config_p); - uint8_t debugger_flags = JERRY_CONTEXT (debugger_flags); - if (exception_config_p->enable == 0) { - debugger_flags = (uint8_t) (debugger_flags | JERRY_DEBUGGER_VM_IGNORE_EXCEPTION); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION); jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Stop at exception disabled\n"); } else { - debugger_flags = (uint8_t) (debugger_flags & ~JERRY_DEBUGGER_VM_IGNORE_EXCEPTION); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION); jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Stop at exception enabled\n"); } - JERRY_CONTEXT (debugger_flags) = debugger_flags; + return true; + } + + case JERRY_DEBUGGER_PARSER_CONFIG: + { + JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_parser_config_t); + JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_parser_config_t, parser_config_p); + + if (parser_config_p->enable_wait != 0) + { + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_PARSER_WAIT); + jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Waiting after parsing enabled\n"); + } + else + { + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_PARSER_WAIT); + jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Waiting after parsing disabled\n"); + } + + return true; + } + + case JERRY_DEBUGGER_PARSER_RESUME: + { + JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); + + if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_PARSER_WAIT_MODE)) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Not in parser wait mode\n"); + jerry_debugger_close_connection (); + return false; + } + + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_PARSER_WAIT_MODE); return true; } @@ -568,8 +598,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec } else { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) - & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); *resume_exec_p = true; } return true; @@ -586,8 +615,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_CLIENT_NO_SOURCE); + JERRY_DEBUGGER_UPDATE_FLAGS (JERRY_DEBUGGER_CLIENT_NO_SOURCE, JERRY_DEBUGGER_CLIENT_SOURCE_MODE); *resume_exec_p = true; @@ -605,8 +633,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_CONTEXT_RESET_MODE); + JERRY_DEBUGGER_UPDATE_FLAGS (JERRY_DEBUGGER_CONTEXT_RESET_MODE, JERRY_DEBUGGER_CLIENT_SOURCE_MODE); *resume_exec_p = true; @@ -652,7 +679,7 @@ jerry_debugger_breakpoint_hit (uint8_t message_type) /**< message type */ return; } - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_BREAKPOINT_MODE); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_BREAKPOINT_MODE); jerry_debugger_uint8_data_t *uint8_data = NULL; @@ -667,7 +694,7 @@ jerry_debugger_breakpoint_hit (uint8_t message_type) /**< message type */ uint8_data->uint8_size + sizeof (jerry_debugger_uint8_data_t)); } - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_BREAKPOINT_MODE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_BREAKPOINT_MODE); JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY; } /* jerry_debugger_breakpoint_hit */ diff --git a/jerry-core/debugger/debugger.h b/jerry-core/debugger/debugger.h index 404964b9df..0e18050dff 100644 --- a/jerry-core/debugger/debugger.h +++ b/jerry-core/debugger/debugger.h @@ -93,18 +93,41 @@ typedef enum JERRY_DEBUGGER_VM_STOP = 1u << 2, /**< stop at the next breakpoint regardless it is enabled */ JERRY_DEBUGGER_VM_IGNORE = 1u << 3, /**< ignore all breakpoints */ JERRY_DEBUGGER_VM_IGNORE_EXCEPTION = 1u << 4, /**< debugger stop at an exception */ - JERRY_DEBUGGER_CLIENT_SOURCE_MODE = 1u << 5, /**< debugger waiting for client code */ - JERRY_DEBUGGER_CLIENT_NO_SOURCE = 1u << 6, /**< debugger leaving the client source loop */ - JERRY_DEBUGGER_CONTEXT_RESET_MODE = 1u << 7, /**< debugger and engine reinitialization mode */ + JERRY_DEBUGGER_PARSER_WAIT = 1u << 5, /**< debugger should wait after parsing is completed */ + JERRY_DEBUGGER_PARSER_WAIT_MODE = 1u << 6, /**< debugger is waiting after parsing is completed */ + JERRY_DEBUGGER_CLIENT_SOURCE_MODE = 1u << 7, /**< debugger waiting for client code */ + JERRY_DEBUGGER_CLIENT_NO_SOURCE = 1u << 8, /**< debugger leaving the client source loop */ + JERRY_DEBUGGER_CONTEXT_RESET_MODE = 1u << 9, /**< debugger and engine reinitialization mode */ } jerry_debugger_flags_t; +/** + * Set debugger flags. + */ +#define JERRY_DEBUGGER_SET_FLAGS(flags) \ + JERRY_CONTEXT (debugger_flags) = (JERRY_CONTEXT (debugger_flags) | (uint32_t) (flags)) + +/** + * Clear debugger flags. + */ +#define JERRY_DEBUGGER_CLEAR_FLAGS(flags) \ + JERRY_CONTEXT (debugger_flags) = (JERRY_CONTEXT (debugger_flags) & (uint32_t) ~(flags)) + +/** + * Set and clear debugger flags. + */ +#define JERRY_DEBUGGER_UPDATE_FLAGS(flags_to_set, flags_to_clear) \ + JERRY_CONTEXT (debugger_flags) = ((JERRY_CONTEXT (debugger_flags) | (uint32_t) (flags_to_set)) \ + & (uint32_t) ~(flags_to_clear)) + /** * Types for the package. */ typedef enum { /* Messages sent by the server to client. */ + /* This is a handshake message, sent once during initialization. */ JERRY_DEBUGGER_CONFIGURATION = 1, /**< debugger configuration */ + /* These messages are sent by the parser. */ JERRY_DEBUGGER_PARSE_ERROR = 2, /**< parse error */ JERRY_DEBUGGER_BYTE_CODE_CP = 3, /**< byte code compressed pointer */ JERRY_DEBUGGER_PARSE_FUNCTION = 4, /**< parsing a new function */ @@ -116,19 +139,21 @@ typedef enum JERRY_DEBUGGER_SOURCE_CODE_NAME_END = 10, /**< source code name last fragment */ JERRY_DEBUGGER_FUNCTION_NAME = 11, /**< function name fragment */ JERRY_DEBUGGER_FUNCTION_NAME_END = 12, /**< function name last fragment */ - JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 13, /**< invalidate byte code compressed pointer */ - JERRY_DEBUGGER_MEMSTATS_RECEIVE = 14, /**< memstats sent to the client*/ - JERRY_DEBUGGER_BREAKPOINT_HIT = 15, /**< notify breakpoint hit */ - JERRY_DEBUGGER_EXCEPTION_HIT = 16, /**< notify exception hit */ - JERRY_DEBUGGER_EXCEPTION_STR = 17, /**< exception string fragment */ - JERRY_DEBUGGER_EXCEPTION_STR_END = 18, /**< exception string last fragment */ - JERRY_DEBUGGER_BACKTRACE = 19, /**< backtrace data */ - JERRY_DEBUGGER_BACKTRACE_END = 20, /**< last backtrace data */ - JERRY_DEBUGGER_EVAL_RESULT = 21, /**< eval result */ - JERRY_DEBUGGER_EVAL_RESULT_END = 22, /**< last part of eval result */ - JERRY_DEBUGGER_WAIT_FOR_SOURCE = 23, /**< engine waiting for a source code */ - JERRY_DEBUGGER_OUTPUT_RESULT = 24, /**< output sent by the program to the debugger */ - JERRY_DEBUGGER_OUTPUT_RESULT_END = 25, /**< last output result data */ + JERRY_DEBUGGER_WAITING_AFTER_PARSE = 13, /**< engine waiting for a parser resume */ + /* These messages are generic messages. */ + JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 14, /**< invalidate byte code compressed pointer */ + JERRY_DEBUGGER_MEMSTATS_RECEIVE = 15, /**< memstats sent to the client*/ + JERRY_DEBUGGER_BREAKPOINT_HIT = 16, /**< notify breakpoint hit */ + JERRY_DEBUGGER_EXCEPTION_HIT = 17, /**< notify exception hit */ + JERRY_DEBUGGER_EXCEPTION_STR = 18, /**< exception string fragment */ + JERRY_DEBUGGER_EXCEPTION_STR_END = 19, /**< exception string last fragment */ + JERRY_DEBUGGER_BACKTRACE = 20, /**< backtrace data */ + JERRY_DEBUGGER_BACKTRACE_END = 21, /**< last backtrace data */ + JERRY_DEBUGGER_EVAL_RESULT = 22, /**< eval result */ + JERRY_DEBUGGER_EVAL_RESULT_END = 23, /**< last part of eval result */ + JERRY_DEBUGGER_WAIT_FOR_SOURCE = 24, /**< engine waiting for a source code */ + JERRY_DEBUGGER_OUTPUT_RESULT = 25, /**< output sent by the program to the debugger */ + JERRY_DEBUGGER_OUTPUT_RESULT_END = 26, /**< last output result data */ JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT, /**< number of different type of output messages by the debugger */ @@ -138,22 +163,26 @@ typedef enum JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1, /**< free byte code compressed pointer */ JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2, /**< update breakpoint status */ JERRY_DEBUGGER_EXCEPTION_CONFIG = 3, /**< exception handler config */ - JERRY_DEBUGGER_MEMSTATS = 4, /**< list memory statistics */ - JERRY_DEBUGGER_STOP = 5, /**< stop execution */ - JERRY_DEBUGGER_CLIENT_SOURCE = 6, /**< first message of client source */ - JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7, /**< next message of client source */ - JERRY_DEBUGGER_NO_MORE_SOURCES = 8, /**< no more sources notification */ - JERRY_DEBUGGER_CONTEXT_RESET = 9, /**< context reset request */ + JERRY_DEBUGGER_PARSER_CONFIG = 4, /**< parser config */ + JERRY_DEBUGGER_MEMSTATS = 5, /**< list memory statistics */ + JERRY_DEBUGGER_STOP = 6, /**< stop execution */ + /* The following message is only available in waiting after parse mode. */ + JERRY_DEBUGGER_PARSER_RESUME = 7, /**< stop waiting after parse */ + /* The following four messages are only available in client switch mode. */ + JERRY_DEBUGGER_CLIENT_SOURCE = 8, /**< first message of client source */ + JERRY_DEBUGGER_CLIENT_SOURCE_PART = 9, /**< next message of client source */ + JERRY_DEBUGGER_NO_MORE_SOURCES = 10, /**< no more sources notification */ + JERRY_DEBUGGER_CONTEXT_RESET = 11, /**< context reset request */ /* The following messages are only available in breakpoint * mode and they switch the engine to run mode. */ - JERRY_DEBUGGER_CONTINUE = 10, /**< continue execution */ - JERRY_DEBUGGER_STEP = 11, /**< next breakpoint, step into functions */ - JERRY_DEBUGGER_NEXT = 12, /**< next breakpoint in the same context */ + JERRY_DEBUGGER_CONTINUE = 12, /**< continue execution */ + JERRY_DEBUGGER_STEP = 13, /**< next breakpoint, step into functions */ + JERRY_DEBUGGER_NEXT = 14, /**< next breakpoint in the same context */ /* The following messages are only available in breakpoint * mode and this mode is kept after the message is processed. */ - JERRY_DEBUGGER_GET_BACKTRACE = 13, /**< get backtrace */ - JERRY_DEBUGGER_EVAL = 14, /**< first message of evaluating a string */ - JERRY_DEBUGGER_EVAL_PART = 15, /**< next message of evaluating a string */ + JERRY_DEBUGGER_GET_BACKTRACE = 15, /**< get backtrace */ + JERRY_DEBUGGER_EVAL = 16, /**< first message of evaluating a string */ + JERRY_DEBUGGER_EVAL_PART = 17, /**< next message of evaluating a string */ JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT, /**< number of different type of input messages */ } jerry_debugger_header_type_t; @@ -313,12 +342,24 @@ typedef struct jerry_debugger_frame_t frames[JERRY_DEBUGGER_SEND_MAX (jerry_debugger_frame_t)]; /**< frames */ } jerry_debugger_send_backtrace_t; +/** + * Incoming message: set behaviour when exception occures. + */ typedef struct { uint8_t type; /**< type of the message */ uint8_t enable; /**< non-zero: enable stop at exception */ } jerry_debugger_receive_exception_config_t; +/** + * Incoming message: set parser configuration. + */ +typedef struct +{ + uint8_t type; /**< type of the message */ + uint8_t enable_wait; /**< non-zero: wait after parsing is completed */ +} jerry_debugger_receive_parser_config_t; + /** * Incoming message: get backtrace. */ diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 72e58a1ff0..01d611b23f 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -116,11 +116,11 @@ typedef struct vm_frame_ctx_t *debugger_stop_context; /**< stop only if the current context is equal to this context */ jmem_cpointer_t debugger_byte_code_free_head; /**< head of byte code free linked list */ jmem_cpointer_t debugger_byte_code_free_tail; /**< tail of byte code free linked list */ - uint8_t debugger_flags; /**< debugger flags */ - uint8_t debugger_message_delay; /**< call receive message when reaches zero */ + uint32_t debugger_flags; /**< debugger flags */ uint16_t debugger_receive_buffer_offset; /**< receive buffer offset */ - int debugger_connection; /**< holds the file descriptor of the socket communication */ uint16_t debugger_port; /**< debugger socket communication port */ + uint8_t debugger_message_delay; /**< call receive message when reaches zero */ + int debugger_connection; /**< holds the file descriptor of the socket communication */ #endif /* JERRY_DEBUGGER */ #ifdef JMEM_STATS diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index ef763c3a70..5d31ed847a 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -2275,7 +2275,7 @@ parser_save_context (parser_context_t *context_p, /**< context */ JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE); #ifdef JERRY_DEBUGGER - if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED + if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && context_p->breakpoint_info_count > 0) { parser_send_breakpoints (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST); @@ -2756,6 +2756,28 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */ return ecma_raise_syntax_error (""); #endif /* JERRY_ENABLE_ERROR_MESSAGES */ } + +#ifdef JERRY_DEBUGGER + if ((JERRY_CONTEXT (debugger_flags) & (JERRY_DEBUGGER_CONNECTED | JERRY_DEBUGGER_PARSER_WAIT)) + == (JERRY_DEBUGGER_CONNECTED | JERRY_DEBUGGER_PARSER_WAIT)) + { + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_PARSER_WAIT_MODE); + jerry_debugger_send_type (JERRY_DEBUGGER_WAITING_AFTER_PARSE); + + while (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_PARSER_WAIT_MODE) + { + jerry_debugger_receive (NULL); + + if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)) + { + break; + } + + jerry_debugger_sleep (); + } + } +#endif /* JERRY_DEBUGGER */ + return ECMA_VALUE_TRUE; #else /* JERRY_DISABLE_JS_PARSER */ JERRY_UNUSED (arg_list_p); diff --git a/jerry-debugger/jerry-client-ws.html b/jerry-debugger/jerry-client-ws.html index f4fe9a87ad..c0fd2861f6 100644 --- a/jerry-debugger/jerry-client-ws.html +++ b/jerry-debugger/jerry-client-ws.html @@ -51,19 +51,20 @@

JerryScript HTML (WebSocket) Debugger Client

var JERRY_DEBUGGER_SOURCE_CODE_NAME_END = 10; var JERRY_DEBUGGER_FUNCTION_NAME = 11; var JERRY_DEBUGGER_FUNCTION_NAME_END = 12; -var JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 13; -var JERRY_DEBUGGER_MEMSTATS_RECEIVE = 14; -var JERRY_DEBUGGER_BREAKPOINT_HIT = 15; -var JERRY_DEBUGGER_EXCEPTION_HIT = 16; -var JERRY_DEBUGGER_EXCEPTION_STR = 17; -var JERRY_DEBUGGER_EXCEPTION_STR_END = 18; -var JERRY_DEBUGGER_BACKTRACE = 19; -var JERRY_DEBUGGER_BACKTRACE_END = 20; -var JERRY_DEBUGGER_EVAL_RESULT = 21; -var JERRY_DEBUGGER_EVAL_RESULT_END = 22; -var JERRY_DEBUGGER_WAIT_FOR_SOURCE = 23; -var JERRY_DEBUGGER_OUTPUT_RESULT = 24; -var JERRY_DEBUGGER_OUTPUT_RESULT_END = 25; +var JERRY_DEBUGGER_WAITING_AFTER_PARSE = 13; +var JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 14; +var JERRY_DEBUGGER_MEMSTATS_RECEIVE = 15; +var JERRY_DEBUGGER_BREAKPOINT_HIT = 16; +var JERRY_DEBUGGER_EXCEPTION_HIT = 17; +var JERRY_DEBUGGER_EXCEPTION_STR = 18; +var JERRY_DEBUGGER_EXCEPTION_STR_END = 19; +var JERRY_DEBUGGER_BACKTRACE = 20; +var JERRY_DEBUGGER_BACKTRACE_END = 21; +var JERRY_DEBUGGER_EVAL_RESULT = 22; +var JERRY_DEBUGGER_EVAL_RESULT_END = 23; +var JERRY_DEBUGGER_WAIT_FOR_SOURCE = 24; +var JERRY_DEBUGGER_OUTPUT_RESULT = 25; +var JERRY_DEBUGGER_OUTPUT_RESULT_END = 26; // Subtypes of eval var JERRY_DEBUGGER_EVAL_OK = 1; @@ -80,18 +81,20 @@

JerryScript HTML (WebSocket) Debugger Client

var JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1; var JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2; var JERRY_DEBUGGER_EXCEPTION_CONFIG = 3; -var JERRY_DEBUGGER_MEMSTATS = 4; -var JERRY_DEBUGGER_STOP = 5; -var JERRY_DEBUGGER_CLIENT_SOURCE = 6; -var JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7; -var JERRY_DEBUGGER_NO_MORE_SOURCES = 8; -var JERRY_DEBUGGER_CONTEXT_RESET = 9; -var JERRY_DEBUGGER_CONTINUE = 10; -var JERRY_DEBUGGER_STEP = 11; -var JERRY_DEBUGGER_NEXT = 12; -var JERRY_DEBUGGER_GET_BACKTRACE = 13; -var JERRY_DEBUGGER_EVAL = 14; -var JERRY_DEBUGGER_EVAL_PART = 15; +var JERRY_DEBUGGER_PARSER_CONFIG = 4; +var JERRY_DEBUGGER_MEMSTATS = 5; +var JERRY_DEBUGGER_STOP = 6; +var JERRY_DEBUGGER_PARSER_RESUME = 7; +var JERRY_DEBUGGER_CLIENT_SOURCE = 8; +var JERRY_DEBUGGER_CLIENT_SOURCE_PART = 9; +var JERRY_DEBUGGER_NO_MORE_SOURCES = 10; +var JERRY_DEBUGGER_CONTEXT_RESET = 11; +var JERRY_DEBUGGER_CONTINUE = 12; +var JERRY_DEBUGGER_STEP = 13; +var JERRY_DEBUGGER_NEXT = 14; +var JERRY_DEBUGGER_GET_BACKTRACE = 15; +var JERRY_DEBUGGER_EVAL = 16; +var JERRY_DEBUGGER_EVAL_PART = 17; var textBox = document.getElementById("log"); var commandBox = document.getElementById("command"); diff --git a/jerry-debugger/jerry-client-ws.py b/jerry-debugger/jerry-client-ws.py index b1b1b9a119..cdea8a65e0 100755 --- a/jerry-debugger/jerry-client-ws.py +++ b/jerry-debugger/jerry-client-ws.py @@ -41,19 +41,20 @@ JERRY_DEBUGGER_SOURCE_CODE_NAME_END = 10 JERRY_DEBUGGER_FUNCTION_NAME = 11 JERRY_DEBUGGER_FUNCTION_NAME_END = 12 -JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 13 -JERRY_DEBUGGER_MEMSTATS_RECEIVE = 14 -JERRY_DEBUGGER_BREAKPOINT_HIT = 15 -JERRY_DEBUGGER_EXCEPTION_HIT = 16 -JERRY_DEBUGGER_EXCEPTION_STR = 17 -JERRY_DEBUGGER_EXCEPTION_STR_END = 18 -JERRY_DEBUGGER_BACKTRACE = 19 -JERRY_DEBUGGER_BACKTRACE_END = 20 -JERRY_DEBUGGER_EVAL_RESULT = 21 -JERRY_DEBUGGER_EVAL_RESULT_END = 22 -JERRY_DEBUGGER_WAIT_FOR_SOURCE = 23 -JERRY_DEBUGGER_OUTPUT_RESULT = 24 -JERRY_DEBUGGER_OUTPUT_RESULT_END = 25 +JERRY_DEBUGGER_WAITING_AFTER_PARSE = 13 +JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 14 +JERRY_DEBUGGER_MEMSTATS_RECEIVE = 15 +JERRY_DEBUGGER_BREAKPOINT_HIT = 16 +JERRY_DEBUGGER_EXCEPTION_HIT = 17 +JERRY_DEBUGGER_EXCEPTION_STR = 18 +JERRY_DEBUGGER_EXCEPTION_STR_END = 19 +JERRY_DEBUGGER_BACKTRACE = 20 +JERRY_DEBUGGER_BACKTRACE_END = 21 +JERRY_DEBUGGER_EVAL_RESULT = 22 +JERRY_DEBUGGER_EVAL_RESULT_END = 23 +JERRY_DEBUGGER_WAIT_FOR_SOURCE = 24 +JERRY_DEBUGGER_OUTPUT_RESULT = 25 +JERRY_DEBUGGER_OUTPUT_RESULT_END = 26 # Subtypes of eval JERRY_DEBUGGER_EVAL_OK = 1 @@ -71,18 +72,20 @@ JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1 JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2 JERRY_DEBUGGER_EXCEPTION_CONFIG = 3 -JERRY_DEBUGGER_MEMSTATS = 4 -JERRY_DEBUGGER_STOP = 5 -JERRY_DEBUGGER_CLIENT_SOURCE = 6 -JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7 -JERRY_DEBUGGER_NO_MORE_SOURCES = 8 -JERRY_DEBUGGER_CONTEXT_RESET = 9 -JERRY_DEBUGGER_CONTINUE = 10 -JERRY_DEBUGGER_STEP = 11 -JERRY_DEBUGGER_NEXT = 12 -JERRY_DEBUGGER_GET_BACKTRACE = 13 -JERRY_DEBUGGER_EVAL = 14 -JERRY_DEBUGGER_EVAL_PART = 15 +JERRY_DEBUGGER_PARSER_CONFIG = 4 +JERRY_DEBUGGER_MEMSTATS = 5 +JERRY_DEBUGGER_STOP = 6 +JERRY_DEBUGGER_PARSER_RESUME = 7 +JERRY_DEBUGGER_CLIENT_SOURCE = 8 +JERRY_DEBUGGER_CLIENT_SOURCE_PART = 9 +JERRY_DEBUGGER_NO_MORE_SOURCES = 10 +JERRY_DEBUGGER_CONTEXT_RESET = 11 +JERRY_DEBUGGER_CONTINUE = 12 +JERRY_DEBUGGER_STEP = 13 +JERRY_DEBUGGER_NEXT = 14 +JERRY_DEBUGGER_GET_BACKTRACE = 15 +JERRY_DEBUGGER_EVAL = 16 +JERRY_DEBUGGER_EVAL_PART = 17 MAX_BUFFER_SIZE = 128 WEBSOCKET_BINARY_FRAME = 2 @@ -315,6 +318,8 @@ def do_delete(self, args): self.debugger.send_breakpoint(breakpoint) elif breakpoint_index in self.debugger.pending_breakpoint_list: del self.debugger.pending_breakpoint_list[breakpoint_index] + if not self.debugger.pending_breakpoint_list: + self.debugger.send_parser_config(0) else: print("Error: Breakpoint %d not found" % (breakpoint_index)) @@ -636,7 +641,9 @@ def delete_active(self): self.send_breakpoint(breakpoint) def delete_pending(self): - self.pending_breakpoint_list.clear() + if self.pending_breakpoint_list: + self.pending_breakpoint_list.clear() + self.send_parser_config(0) def breakpoint_pending_exists(self, breakpoint): for existing_bp in self.pending_breakpoint_list.values(): @@ -684,13 +691,22 @@ def send_exception_config(self, enable): enable) self.send_message(message) + def send_parser_config(self, enable): + message = struct.pack(self.byte_order + "BBIBB", + WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT, + WEBSOCKET_FIN_BIT + 1 + 1, + 0, + JERRY_DEBUGGER_PARSER_CONFIG, + enable) + self.send_message(message) + def set_colors(self): - self.green = '\033[92m' self.nocolor = '\033[0m' + self.green = '\033[92m' self.red = '\033[31m' self.yellow = '\033[93m' - self.green_bg = '\033[42m' - self.yellow_bg = '\033[43m' + self.green_bg = '\033[42m\033[30m' + self.yellow_bg = '\033[43m\033[30m' self.blue = '\033[94m' def get_message(self, blocking): @@ -843,29 +859,29 @@ def parse_source(debugger, data): debugger.line_list.insert(line, breakpoint) # Try to set the pending breakpoints - if len(debugger.pending_breakpoint_list) != 0: + if debugger.pending_breakpoint_list: logging.debug("Pending breakpoints list: %s", debugger.pending_breakpoint_list) bp_list = debugger.pending_breakpoint_list - for breakpoint in bp_list: + for breakpoint_index, breakpoint in bp_list.items(): for src in debugger.function_list.values(): - if src.source_name == bp_list[breakpoint].source_name: + if src.source_name == breakpoint.source_name: source_lines = len(src.source) else: source_lines = 0 - if bp_list[breakpoint].line: - if bp_list[breakpoint].line <= source_lines: - tmp_bp = breakpoint - breakpoint = bp_list[breakpoint].source_name + ":" + str(bp_list[breakpoint].line) - if set_breakpoint(debugger, breakpoint, True): - del tmp_bp - elif bp_list[breakpoint].function: - tmp_bp = breakpoint - breakpoint = bp_list[breakpoint].function - if set_breakpoint(debugger, breakpoint, True): - del tmp_bp + if breakpoint.line: + if breakpoint.line <= source_lines: + command = breakpoint.source_name + ":" + str(breakpoint.line) + if set_breakpoint(debugger, command, True): + del bp_list[breakpoint_index] + elif breakpoint.function: + command = breakpoint.function + if set_breakpoint(debugger, command, True): + del bp_list[breakpoint_index] + if not bp_list: + debugger.send_parser_config(0) else: logging.debug("No pending breakpoints") @@ -971,14 +987,19 @@ def set_breakpoint(debugger, string, pending): if not found and not pending: print("No breakpoint found, do you want to add a %spending breakpoint%s? (y or [n])" % \ - (debugger.yellow, debugger.nocolor)) + (debugger.yellow, debugger.nocolor)) + ans = sys.stdin.readline() if ans in ['yes\n', 'y\n']: + if not debugger.pending_breakpoint_list: + debugger.send_parser_config(1) + if line: breakpoint = JerryPendingBreakpoint(int(line.group(2)), line.group(1)) else: breakpoint = JerryPendingBreakpoint(function=string) enable_breakpoint(debugger, breakpoint) + elif not found and pending: return False @@ -1062,6 +1083,9 @@ def main(): JERRY_DEBUGGER_FUNCTION_NAME_END]: parse_source(debugger, data) + elif buffer_type == JERRY_DEBUGGER_WAITING_AFTER_PARSE: + debugger.send_command(JERRY_DEBUGGER_PARSER_RESUME) + elif buffer_type == JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP: release_function(debugger, data) diff --git a/tests/debugger/do_pending_breakpoints.cmd b/tests/debugger/do_pending_breakpoints.cmd index e57e4d578d..fd879372d5 100644 --- a/tests/debugger/do_pending_breakpoints.cmd +++ b/tests/debugger/do_pending_breakpoints.cmd @@ -1,7 +1,9 @@ +break :1 +y break f y list -n -n +c +list c c diff --git a/tests/debugger/do_pending_breakpoints.expected b/tests/debugger/do_pending_breakpoints.expected index e5bbea63ff..33efcc2632 100644 --- a/tests/debugger/do_pending_breakpoints.expected +++ b/tests/debugger/do_pending_breakpoints.expected @@ -1,17 +1,24 @@ Connecting to: localhost:5001 Stopped at tests/debugger/do_pending_breakpoints.js:15 +(jerry-debugger) break :1 +No breakpoint found, do you want to add a pending breakpoint? (y or [n]) +Pending breakpoint at :1 (jerry-debugger) break f No breakpoint found, do you want to add a pending breakpoint? (y or [n]) Pending breakpoint at f() (jerry-debugger) list === Pending breakpoints === - 1: f() (pending) -(jerry-debugger) n + 1: :1 (pending) + 2: f() (pending) +(jerry-debugger) c out: pending-breakpoints -Stopped at tests/debugger/do_pending_breakpoints.js:17 -(jerry-debugger) n -Breakpoint 2 at :1 (in f() at line:1, col:1) -Stopped at tests/debugger/do_pending_breakpoints.js:19 +Breakpoint 3 at :1 +Breakpoint 4 at :3 (in f() at line:2, col:1) +Stopped at breakpoint:3 :1 +(jerry-debugger) list +=== Active breakpoints === + 3: :1 + 4: :3 (in f() at line:2, col:1) (jerry-debugger) c -Stopped at breakpoint:2 :1 (in f() at line:1, col:1) +Stopped at breakpoint:4 :3 (in f() at line:2, col:1) (jerry-debugger) c diff --git a/tests/debugger/do_pending_breakpoints.js b/tests/debugger/do_pending_breakpoints.js index a7062166a5..0e0826e46f 100644 --- a/tests/debugger/do_pending_breakpoints.js +++ b/tests/debugger/do_pending_breakpoints.js @@ -14,7 +14,7 @@ print("pending-breakpoints"); -eval("function f(){ return 5 }"); +eval("1;\nfunction f()\n{ return 5 }"); var bird = "colibri"; f();