Author: [EMAIL PROTECTED]
Date: Thu Dec 11 00:03:24 2008
New Revision: 959
Modified:
branches/bleeding_edge/src/debug.cc
branches/bleeding_edge/src/debug.h
branches/bleeding_edge/src/runtime.cc
branches/bleeding_edge/test/cctest/test-debug.cc
Log:
Changed the debugger break handling to support situations where there are
no stack frames. This can happen when an exception is thrown when compiling
code.
This is related to Chromium issue 5349
(http://code.google.com/p/chromium/issues/detail?id=5349).
Review URL: http://codereview.chromium.org/13720
Modified: branches/bleeding_edge/src/debug.cc
==============================================================================
--- branches/bleeding_edge/src/debug.cc (original)
+++ branches/bleeding_edge/src/debug.cc Thu Dec 11 00:03:24 2008
@@ -849,7 +849,12 @@
void Debug::FloodHandlerWithOneShot() {
+ // Iterate through the JavaScript stack looking for handlers.
StackFrame::Id id = Top::break_frame_id();
+ if (id == StackFrame::NO_ID) {
+ // If there is no JavaScript stack don't do anything.
+ return;
+ }
for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) {
JavaScriptFrame* frame = it.frame();
if (frame->HasHandler()) {
@@ -886,6 +891,10 @@
// hitting a break point. In other situations (e.g. unhandled exception)
the
// debug frame is not present.
StackFrame::Id id = Top::break_frame_id();
+ if (id == StackFrame::NO_ID) {
+ // If there is no JavaScript stack don't do anything.
+ return;
+ }
JavaScriptFrameIterator frames_it(id);
JavaScriptFrame* frame = frames_it.frame();
Modified: branches/bleeding_edge/src/debug.h
==============================================================================
--- branches/bleeding_edge/src/debug.h (original)
+++ branches/bleeding_edge/src/debug.h Thu Dec 11 00:03:24 2008
@@ -489,16 +489,17 @@
// some reason could not be entered FailedToEnter will return true.
class EnterDebugger BASE_EMBEDDED {
public:
- EnterDebugger() : set_(!it_.done()) {
- // If there is no JavaScript frames on the stack don't switch to new
break
- // and break frame.
- if (set_) {
- // Store the previous break is and frame id.
- break_id_ = Top::break_id();
- break_frame_id_ = Top::break_frame_id();
-
- // Create the new break info.
+ EnterDebugger() : has_js_frames_(!it_.done()) {
+ // Store the previous break id and frame id.
+ break_id_ = Top::break_id();
+ break_frame_id_ = Top::break_frame_id();
+
+ // Create the new break info. If there is no JavaScript frames there
is no
+ // break frame id.
+ if (has_js_frames_) {
Top::new_break(it_.frame()->id());
+ } else {
+ Top::new_break(StackFrame::NO_ID);
}
// Make sure that debugger is loaded and enter the debugger context.
@@ -511,21 +512,19 @@
}
~EnterDebugger() {
- if (set_) {
- // Restore to the previous break state.
- Top::set_break(break_frame_id_, break_id_);
- }
+ // Restore to the previous break state.
+ Top::set_break(break_frame_id_, break_id_);
}
// Check whether the debugger could be entered.
inline bool FailedToEnter() { return load_failed_; }
// Check whether there are any JavaScript frames on the stack.
- inline bool HasJavaScriptFrames() { return set_; }
+ inline bool HasJavaScriptFrames() { return has_js_frames_; }
private:
JavaScriptFrameIterator it_;
- const bool set_; // Was the break actually set?
+ const bool has_js_frames_; // Were there any JavaScript frames?
StackFrame::Id break_frame_id_; // Previous break frame id.
int break_id_; // Previous break id.
bool load_failed_; // Did the debugger fail to load?
Modified: branches/bleeding_edge/src/runtime.cc
==============================================================================
--- branches/bleeding_edge/src/runtime.cc (original)
+++ branches/bleeding_edge/src/runtime.cc Thu Dec 11 00:03:24 2008
@@ -4764,10 +4764,8 @@
static Object* Runtime_CheckExecutionState(Arguments args) {
ASSERT(args.length() >= 1);
CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- // Check that the break id is valid and that there is a valid frame
- // where execution is broken.
- if (break_id != Top::break_id() ||
- Top::break_frame_id() == StackFrame::NO_ID) {
+ // Check that the break id is valid.
+ if (Top::break_id() == 0 || break_id != Top::break_id()) {
return Top::Throw(Heap::illegal_execution_state_symbol());
}
@@ -4786,6 +4784,10 @@
// Count all frames which are relevant to debugging stack trace.
int n = 0;
StackFrame::Id id = Top::break_frame_id();
+ if (id == StackFrame::NO_ID) {
+ // If there is no JavaScript stack frame count is 0.
+ return Smi::FromInt(0);
+ }
for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
return Smi::FromInt(n);
}
@@ -4827,6 +4829,10 @@
// Find the relevant frame with the requested index.
StackFrame::Id id = Top::break_frame_id();
+ if (id == StackFrame::NO_ID) {
+ // If there are no JavaScript stack frames return undefined.
+ return Heap::undefined_value();
+ }
int count = 0;
JavaScriptFrameIterator it(id);
for (; !it.done(); it.Advance()) {
Modified: branches/bleeding_edge/test/cctest/test-debug.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-debug.cc (original)
+++ branches/bleeding_edge/test/cctest/test-debug.cc Thu Dec 11 00:03:24
2008
@@ -434,6 +434,15 @@
"}";
v8::Local<v8::Function> frame_function_name;
+
+// Source for The JavaScript function which returns the number of frames.
+static const char* frame_count_source =
+ "function frame_count(exec_state) {"
+ " return exec_state.frameCount();"
+ "}";
+v8::Handle<v8::Function> frame_count;
+
+
// Global variable to store the last function hit - used by some tests.
char last_function_hit[80];
@@ -443,6 +452,9 @@
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ // When hitting a debug event listener there must be a break set.
+ CHECK(v8::internal::Top::is_break());
+
// Count the number of breaks.
if (event == v8::Break) {
break_point_hit_count++;
@@ -464,9 +476,11 @@
}
-// Debug event handler which counts a number of events.
+// Debug event handler which counts a number of events and collects the
stack
+// height if there is a function compiled for that.
int exception_hit_count = 0;
int uncaught_exception_hit_count = 0;
+int last_js_stack_height = -1;
static void DebugEventCounterClear() {
break_point_hit_count = 0;
@@ -478,6 +492,9 @@
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ // When hitting a debug event listener there must be a break set.
+ CHECK(v8::internal::Top::is_break());
+
// Count the number of breaks.
if (event == v8::Break) {
break_point_hit_count++;
@@ -493,6 +510,16 @@
uncaught_exception_hit_count++;
}
}
+
+ // Collect the JavsScript stack height if the function frame_count is
+ // compiled.
+ if (!frame_count.IsEmpty()) {
+ static const int kArgc = 1;
+ v8::Handle<v8::Value> argv[kArgc] = { exec_state };
+ // Using exec_state as receiver is just to have a receiver.
+ v8::Handle<v8::Value> result = frame_count->Call(exec_state, kArgc,
argv);
+ last_js_stack_height = result->Int32Value();
+ }
}
@@ -523,6 +550,9 @@
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ // When hitting a debug event listener there must be a break set.
+ CHECK(v8::internal::Top::is_break());
+
if (event == v8::Break) {
for (int i = 0; checks[i].expr != NULL; i++) {
const int argc = 3;
@@ -546,6 +576,9 @@
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ // When hitting a debug event listener there must be a break set.
+ CHECK(v8::internal::Top::is_break());
+
if (event == v8::Break) {
break_point_hit_count++;
v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(data);
@@ -561,6 +594,9 @@
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ // When hitting a debug event listener there must be a break set.
+ CHECK(v8::internal::Top::is_break());
+
if (event == v8::Break) {
break_point_hit_count++;
PrepareStep(step_action);
@@ -584,6 +620,9 @@
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ // When hitting a debug event listener there must be a break set.
+ CHECK(v8::internal::Top::is_break());
+
if (event == v8::Break || event == v8::Exception) {
// Check that the current function is the expected.
CHECK(break_point_hit_count <
@@ -611,6 +650,9 @@
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ // When hitting a debug event listener there must be a break set.
+ CHECK(v8::internal::Top::is_break());
+
// Perform a garbage collection when break point is hit and continue.
Based
// on the number of break points hit either scavenge or mark compact
// collector is used.
@@ -633,6 +675,9 @@
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
v8::Handle<v8::Value> data) {
+ // When hitting a debug event listener there must be a break set.
+ CHECK(v8::internal::Top::is_break());
+
if (event == v8::Break) {
// Count the number of breaks.
break_point_hit_count++;
@@ -2164,7 +2209,7 @@
// Test break on exceptions. For each exception break combination the
number
// of debug event exception callbacks and message callbacks are collected.
The
-// number of debug event exception callbacks are cused to check that the
+// number of debug event exception callbacks are used to check that the
// debugger is called correctly and the number of message callbacks is
used to
// check that uncaught exceptions are still returned even if there is a
break
// for them.
@@ -2309,6 +2354,60 @@
}
+// Test break on exception from compiler errors. When compiling using
+// v8::Script::Compile there is no JavaScript stack whereas when compiling
using
+// eval there are JavaScript frames.
+TEST(BreakOnCompileException) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ v8::internal::Top::TraceException(false);
+
+ // Create a function for checking the function when hitting a break
point.
+ frame_count = CompileFunction(&env, frame_count_source, "frame_count");
+
+ v8::V8::AddMessageListener(MessageCallbackCount);
+ v8::Debug::AddDebugEventListener(DebugEventCounter);
+
+ DebugEventCounterClear();
+ MessageCallbackCountClear();
+
+ // Check initial state.
+ CHECK_EQ(0, exception_hit_count);
+ CHECK_EQ(0, uncaught_exception_hit_count);
+ CHECK_EQ(0, message_callback_count);
+ CHECK_EQ(-1, last_js_stack_height);
+
+ // Throws SyntaxError: Unexpected end of input
+ v8::Script::Compile(v8::String::New("+++"));
+ CHECK_EQ(1, exception_hit_count);
+ CHECK_EQ(1, uncaught_exception_hit_count);
+ CHECK_EQ(1, message_callback_count);
+ CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
+
+ // Throws SyntaxError: Unexpected identifier
+ v8::Script::Compile(v8::String::New("x x"));
+ CHECK_EQ(2, exception_hit_count);
+ CHECK_EQ(2, uncaught_exception_hit_count);
+ CHECK_EQ(2, message_callback_count);
+ CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
+
+ // Throws SyntaxError: Unexpected end of input
+ v8::Script::Compile(v8::String::New("eval('+++')"))->Run();
+ CHECK_EQ(3, exception_hit_count);
+ CHECK_EQ(3, uncaught_exception_hit_count);
+ CHECK_EQ(3, message_callback_count);
+ CHECK_EQ(1, last_js_stack_height);
+
+ // Throws SyntaxError: Unexpected identifier
+ v8::Script::Compile(v8::String::New("eval('x x')"))->Run();
+ CHECK_EQ(4, exception_hit_count);
+ CHECK_EQ(4, uncaught_exception_hit_count);
+ CHECK_EQ(4, message_callback_count);
+ CHECK_EQ(1, last_js_stack_height);
+}
+
+
TEST(StepWithException) {
v8::HandleScope scope;
DebugLocalContext env;
@@ -3166,14 +3265,6 @@
int dummy_length = AsciiToUtf16(dummy_command, dummy_buffer);
v8::Debug::SendCommand(dummy_buffer, dummy_length);
}
-
-
-// Source for The JavaScript function which returns the number of frames.
-static const char* frame_count_source =
- "function frame_count(exec_state) {"
- " return exec_state.frameCount();"
- "}";
-v8::Handle<v8::Function> frame_count;
// Source for a JavaScript function which returns the source line for the
top
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---