Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions jerry-core/debugger/debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,15 @@ jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer to the recei
} /* jerry_debugger_send_backtrace */

/**
* Send result of evaluated expression.
* Send result of evaluated expression or throw an error.
*
* @return true - if no error is occured
* false - otherwise
*/
static bool
jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated string */
size_t eval_string_size) /**< evaluated string size */
jerry_debugger_send_eval_or_throw (const lit_utf8_byte_t *eval_string_p, /**< evaluated string */
size_t eval_string_size, /**< evaluated string size */
bool *is_eval) /**< [in,out] throw or eval call */
{
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE));
Expand All @@ -160,11 +161,21 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s

if (!ECMA_IS_VALUE_ERROR (result))
{
if (!*is_eval)
{
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_THROW_ERROR_FLAG);
JERRY_CONTEXT (error_value) = result;
JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_STOP);
JERRY_CONTEXT (debugger_stop_context) = NULL;
return true;
}

ecma_value_t to_string_value = ecma_op_to_string (result);
ecma_free_value (result);
result = to_string_value;
}

*is_eval = true;
ecma_value_t message = result;
uint8_t type = JERRY_DEBUGGER_EVAL_OK;

Expand Down Expand Up @@ -211,7 +222,7 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s
ecma_free_value (message);

return success;
} /* jerry_debugger_send_eval */
} /* jerry_debugger_send_eval_or_throw */

/**
* Suspend execution for a given time.
Expand Down Expand Up @@ -268,6 +279,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
if (*expected_message_type_p != 0)
{
JERRY_ASSERT (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART
|| *expected_message_type_p == JERRY_DEBUGGER_THROW_PART
|| *expected_message_type_p == JERRY_DEBUGGER_CLIENT_SOURCE_PART);

jerry_debugger_uint8_data_t *uint8_data_p = (jerry_debugger_uint8_data_t *) *message_data_p;
Expand Down Expand Up @@ -314,9 +326,19 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
}

bool result = false;
bool is_eval = true;
if (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART)
{
result = jerry_debugger_send_eval (string_p, uint8_data_p->uint8_size);
result = jerry_debugger_send_eval_or_throw (string_p, uint8_data_p->uint8_size, &is_eval);
}
else if (*expected_message_type_p == JERRY_DEBUGGER_THROW_PART)
{
is_eval = false;
result = jerry_debugger_send_eval_or_throw (string_p, uint8_data_p->uint8_size, &is_eval);
if (!is_eval)
{
*resume_exec_p = true;
}
}
else
{
Expand Down Expand Up @@ -513,6 +535,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
}

case JERRY_DEBUGGER_EVAL:
case JERRY_DEBUGGER_THROW:
{
if (message_size < sizeof (jerry_debugger_receive_eval_first_t) + 1)
{
Expand All @@ -525,6 +548,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece

uint32_t eval_size;
memcpy (&eval_size, eval_first_p->eval_size, sizeof (uint32_t));
bool is_eval = (recv_buffer_p[0] == JERRY_DEBUGGER_EVAL);

if (eval_size <= JERRY_DEBUGGER_MAX_RECEIVE_SIZE - sizeof (jerry_debugger_receive_eval_first_t))
{
Expand All @@ -534,8 +558,13 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
jerry_debugger_close_connection ();
return false;
}
bool ret_val = jerry_debugger_send_eval_or_throw ((lit_utf8_byte_t *) (eval_first_p + 1), eval_size, &is_eval);
if (!is_eval)
{
*resume_exec_p = true;
}

return jerry_debugger_send_eval ((lit_utf8_byte_t *) (eval_first_p + 1), eval_size);
return ret_val;
}

jerry_debugger_uint8_data_t *eval_uint8_data_p;
Expand All @@ -552,7 +581,8 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
message_size - sizeof (jerry_debugger_receive_eval_first_t));

*message_data_p = eval_uint8_data_p;
*expected_message_type_p = JERRY_DEBUGGER_EVAL_PART;
*expected_message_type_p = is_eval ? JERRY_DEBUGGER_EVAL_PART : JERRY_DEBUGGER_THROW_PART;

return true;
}

Expand Down
3 changes: 3 additions & 0 deletions jerry-core/debugger/debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ typedef enum
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_THROW_ERROR_FLAG = 1u << 10, /**< debugger client sent an error throw */
} jerry_debugger_flags_t;

/**
Expand Down Expand Up @@ -186,6 +187,8 @@ typedef enum
JERRY_DEBUGGER_EVAL_PART = 18, /**< next message of evaluating a string */

JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT, /**< number of different type of input messages */
JERRY_DEBUGGER_THROW = 19, /**< first message of the throw string */
JERRY_DEBUGGER_THROW_PART = 20, /**< next part of the throw message */
} jerry_debugger_header_type_t;

/**
Expand Down
26 changes: 26 additions & 0 deletions jerry-core/vm/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2495,6 +2495,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
frame_ctx_p->byte_code_p = byte_code_start_p;

jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT);
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_THROW_ERROR_FLAG)
{
result = JERRY_CONTEXT (error_value);
goto error;
}
#endif /* JERRY_DEBUGGER */
continue;
}
Expand All @@ -2517,6 +2522,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|| JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p)))
{
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT);
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_THROW_ERROR_FLAG)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are multiple jerry_debugger_breakpoint_hits in the vm. What happns when the others are called and an exception is thrown?

{
result = JERRY_CONTEXT (error_value);
goto error;
}
continue;
}

Expand All @@ -2538,6 +2548,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|| JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p)))
{
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT);
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_THROW_ERROR_FLAG)
{
result = JERRY_CONTEXT (error_value);
goto error;
}
}
#endif /* JERRY_DEBUGGER */
continue;
Expand Down Expand Up @@ -2677,9 +2692,20 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
&& !(frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE)
&& !(JERRY_CONTEXT (debugger_flags) & (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION | JERRY_DEBUGGER_VM_IGNORE)))
{
/* Save the error to a local value, because the engine enters breakpoint mode after,
therefore an evaluation error, or user-created error throw would overwrite it. */
ecma_value_t current_error_value = JERRY_CONTEXT (error_value);
if (jerry_debugger_send_exception_string ())
{
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_EXCEPTION_HIT);
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_THROW_ERROR_FLAG)
{
ecma_free_value (current_error_value);
}
else
{
JERRY_CONTEXT (error_value) = current_error_value;
}
}
}
#endif /* JERRY_DEBUGGER */
Expand Down
8 changes: 8 additions & 0 deletions jerry-debugger/jerry-client-ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
JERRY_DEBUGGER_GET_BACKTRACE = 16
JERRY_DEBUGGER_EVAL = 17
JERRY_DEBUGGER_EVAL_PART = 18
JERRY_DEBUGGER_THROW = 19
JERRY_DEBUGGER_THROW_PART = 20

MAX_BUFFER_SIZE = 128
WEBSOCKET_BINARY_FRAME = 2
Expand Down Expand Up @@ -449,6 +451,8 @@ def _send_string(self, args, message_type):

if message_type == JERRY_DEBUGGER_EVAL:
message_type = JERRY_DEBUGGER_EVAL_PART
elif message_type == JERRY_DEBUGGER_THROW:
message_type = JERRY_DEBUGGER_THROW_PART
else:
message_type = JERRY_DEBUGGER_CLIENT_SOURCE_PART

Expand Down Expand Up @@ -477,6 +481,10 @@ def do_eval(self, args):

do_e = do_eval

def do_throw(self, args):
""" Throw an exception """
self._send_string(args, JERRY_DEBUGGER_THROW)

def do_exception(self, args):
""" Config the exception handler module """
if not args:
Expand Down
6 changes: 3 additions & 3 deletions tests/debugger/do_help.expected
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Stopped at tests/debugger/do_help.js:15

Documented commands (type help <topic>):
========================================
b bt delete e f list n s src
backtrace c display eval finish memstats next scroll step
break continue dump exception help ms quit source
b bt delete e f list n s src
backtrace c display eval finish memstats next scroll step
break continue dump exception help ms quit source throw

(jerry-debugger) quit
1 change: 1 addition & 0 deletions tests/debugger/do_throw.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
throw new Error('Once upon a time there lived in a certain village a little country girl, the prettiest creature who was ever seen. Her mother was excessively fond of her; and her grandmother doted on her still more. This good woman had a little red riding hood made for her. It suited the girl so extremely well that everybody called her Little Red Riding Hood. One day her mother, having made some cakes, said to her, "Go, my dear, and see how your grandmother is doing, for I hear she has been very ill. Take her a cake, and this little pot of butter."')
3 changes: 3 additions & 0 deletions tests/debugger/do_throw.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Connecting to: localhost:5001
Stopped at tests/debugger/do_throw.js:19
(jerry-debugger) throw new Error('Once upon a time there lived in a certain village a little country girl, the prettiest creature who was ever seen. Her mother was excessively fond of her; and her grandmother doted on her still more. This good woman had a little red riding hood made for her. It suited the girl so extremely well that everybody called her Little Red Riding Hood. One day her mother, having made some cakes, said to her, "Go, my dear, and see how your grandmother is doing, for I hear she has been very ill. Take her a cake, and this little pot of butter."')
19 changes: 19 additions & 0 deletions tests/debugger/do_throw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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.

function inevitable() {
print("An error will be thrown.");
}

inevitable();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious: why is any code needed in this file for this test case?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we could leave it empty as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it hurts to keep the current file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just wondering... I thought perhaps it was needed to get a breakpoint opcode emitted or something.