Commit ceef7cb8 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Make the debugger completely unload when the debug event listener is unregistered.

Added a number of handle scopes to the debugger code to keep handles local to the function using them.

Fixed SetDebugEventListener to actually unregister when passed a NULL pointer. Previously this NULL pointer was wrapped in a Proxy.

BUG=1242702
Review URL: http://codereview.chromium.org/21347

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1269 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent be576757
...@@ -2888,8 +2888,11 @@ bool Debug::SetDebugEventListener(DebugEventCallback that, Handle<Value> data) { ...@@ -2888,8 +2888,11 @@ bool Debug::SetDebugEventListener(DebugEventCallback that, Handle<Value> data) {
EnsureInitialized("v8::Debug::SetDebugEventListener()"); EnsureInitialized("v8::Debug::SetDebugEventListener()");
ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false); ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false);
HandleScope scope; HandleScope scope;
i::Debugger::SetEventListener(i::Factory::NewProxy(FUNCTION_ADDR(that)), i::Handle<i::Object> proxy = i::Factory::undefined_value();
Utils::OpenHandle(*data)); if (that != NULL) {
proxy = i::Factory::NewProxy(FUNCTION_ADDR(that));
}
i::Debugger::SetEventListener(proxy, Utils::OpenHandle(*data));
return true; return true;
} }
......
...@@ -51,6 +51,13 @@ void BreakLocationIterator::ClearDebugBreakAtReturn() { ...@@ -51,6 +51,13 @@ void BreakLocationIterator::ClearDebugBreakAtReturn() {
} }
bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
// Currently debug break is not supported in frame exit code on ARM.
return false;
}
#define __ masm-> #define __ masm->
......
...@@ -37,7 +37,7 @@ namespace v8 { namespace internal { ...@@ -37,7 +37,7 @@ namespace v8 { namespace internal {
// A debug break in the frame exit code is identified by a call instruction. // A debug break in the frame exit code is identified by a call instruction.
bool BreakLocationIterator::IsDebugBreakAtReturn() { bool BreakLocationIterator::IsDebugBreakAtReturn() {
// Opcode E8 is call. // Opcode E8 is call.
return (*(rinfo()->pc()) == 0xE8); return Debug::IsDebugBreakAtReturn(rinfo());
} }
...@@ -59,6 +59,14 @@ void BreakLocationIterator::ClearDebugBreakAtReturn() { ...@@ -59,6 +59,14 @@ void BreakLocationIterator::ClearDebugBreakAtReturn() {
} }
// Check whether the JS frame exit code has been patched with a debug break.
bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
// Opcode E8 is call.
return (*(rinfo->pc()) == 0xE8);
}
#define __ masm-> #define __ masm->
......
...@@ -314,6 +314,8 @@ void BreakLocationIterator::ClearDebugBreak() { ...@@ -314,6 +314,8 @@ void BreakLocationIterator::ClearDebugBreak() {
void BreakLocationIterator::PrepareStepIn() { void BreakLocationIterator::PrepareStepIn() {
HandleScope scope;
// Step in can only be prepared if currently positioned on an IC call or // Step in can only be prepared if currently positioned on an IC call or
// construct call. // construct call.
Address target = rinfo()->target_address(); Address target = rinfo()->target_address();
...@@ -363,6 +365,17 @@ Object* BreakLocationIterator::BreakPointObjects() { ...@@ -363,6 +365,17 @@ Object* BreakLocationIterator::BreakPointObjects() {
} }
// Clear out all the debug break code. This is ONLY supposed to be used when
// shutting down the debugger as it will leave the break point information in
// DebugInfo even though the code is patched back to the non break point state.
void BreakLocationIterator::ClearAllDebugBreak() {
while (!Done()) {
ClearDebugBreak();
Next();
}
}
bool BreakLocationIterator::RinfoDone() const { bool BreakLocationIterator::RinfoDone() const {
ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done()); ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
return reloc_iterator_->done(); return reloc_iterator_->done();
...@@ -589,6 +602,9 @@ void Debug::Unload() { ...@@ -589,6 +602,9 @@ void Debug::Unload() {
return; return;
} }
// Get rid of all break points and related information.
ClearAllBreakPoints();
// Clear debugger context global handle. // Clear debugger context global handle.
GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location())); GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
debug_context_ = Handle<Context>(); debug_context_ = Handle<Context>();
...@@ -715,6 +731,8 @@ Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) { ...@@ -715,6 +731,8 @@ Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
// Check whether a single break point object is triggered. // Check whether a single break point object is triggered.
bool Debug::CheckBreakPoint(Handle<Object> break_point_object) { bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
HandleScope scope;
// Ignore check if break point object is not a JSObject. // Ignore check if break point object is not a JSObject.
if (!break_point_object->IsJSObject()) return true; if (!break_point_object->IsJSObject()) return true;
...@@ -765,6 +783,8 @@ Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) { ...@@ -765,6 +783,8 @@ Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared, void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
int source_position, int source_position,
Handle<Object> break_point_object) { Handle<Object> break_point_object) {
HandleScope scope;
if (!EnsureDebugInfo(shared)) { if (!EnsureDebugInfo(shared)) {
// Return if retrieving debug info failed. // Return if retrieving debug info failed.
return; return;
...@@ -785,6 +805,8 @@ void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared, ...@@ -785,6 +805,8 @@ void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
void Debug::ClearBreakPoint(Handle<Object> break_point_object) { void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
HandleScope scope;
DebugInfoListNode* node = debug_info_list_; DebugInfoListNode* node = debug_info_list_;
while (node != NULL) { while (node != NULL) {
Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(), Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
...@@ -817,6 +839,22 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) { ...@@ -817,6 +839,22 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
} }
void Debug::ClearAllBreakPoints() {
DebugInfoListNode* node = debug_info_list_;
while (node != NULL) {
// Remove all debug break code.
BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
it.ClearAllDebugBreak();
node = node->next();
}
// Remove all debug info.
while (debug_info_list_ != NULL) {
RemoveDebugInfo(debug_info_list_->debug_info());
}
}
void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) { void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
// Make sure the function has setup the debug info. // Make sure the function has setup the debug info.
if (!EnsureDebugInfo(shared)) { if (!EnsureDebugInfo(shared)) {
...@@ -1214,6 +1252,8 @@ void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) { ...@@ -1214,6 +1252,8 @@ void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
HandleScope scope;
// Get the executing function in which the debug break occurred. // Get the executing function in which the debug break occurred.
Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared()); Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
...@@ -1289,6 +1329,7 @@ bool Debug::IsDebugGlobal(GlobalObject* global) { ...@@ -1289,6 +1329,7 @@ bool Debug::IsDebugGlobal(GlobalObject* global) {
void Debug::ClearMirrorCache() { void Debug::ClearMirrorCache() {
HandleScope scope;
ASSERT(Top::context() == *Debug::debug_context()); ASSERT(Top::context() == *Debug::debug_context());
// Clear the mirror cache. // Clear the mirror cache.
...@@ -1588,6 +1629,8 @@ void Debugger::OnNewFunction(Handle<JSFunction> function) { ...@@ -1588,6 +1629,8 @@ void Debugger::OnNewFunction(Handle<JSFunction> function) {
void Debugger::ProcessDebugEvent(v8::DebugEvent event, void Debugger::ProcessDebugEvent(v8::DebugEvent event,
Handle<Object> event_data) { Handle<Object> event_data) {
HandleScope scope;
// Create the execution state. // Create the execution state.
bool caught_exception = false; bool caught_exception = false;
Handle<Object> exec_state = MakeExecutionState(&caught_exception); Handle<Object> exec_state = MakeExecutionState(&caught_exception);
...@@ -1704,6 +1747,9 @@ void Debugger::UpdateActiveDebugger() { ...@@ -1704,6 +1747,9 @@ void Debugger::UpdateActiveDebugger() {
if (!debugger_active() && message_thread_) { if (!debugger_active() && message_thread_) {
message_thread_->OnDebuggerInactive(); message_thread_->OnDebuggerInactive();
} }
if (!debugger_active()) {
Debug::Unload();
}
} }
...@@ -1808,6 +1854,8 @@ void DebugMessageThread::Run() { ...@@ -1808,6 +1854,8 @@ void DebugMessageThread::Run() {
void DebugMessageThread::DebugEvent(v8::DebugEvent event, void DebugMessageThread::DebugEvent(v8::DebugEvent event,
Handle<Object> exec_state, Handle<Object> exec_state,
Handle<Object> event_data) { Handle<Object> event_data) {
HandleScope scope;
if (!Debug::Load()) return; if (!Debug::Load()) return;
// Process the individual events. // Process the individual events.
......
...@@ -89,6 +89,7 @@ class BreakLocationIterator { ...@@ -89,6 +89,7 @@ class BreakLocationIterator {
bool HasBreakPoint(); bool HasBreakPoint();
bool IsDebugBreak(); bool IsDebugBreak();
Object* BreakPointObjects(); Object* BreakPointObjects();
void ClearAllDebugBreak();
inline int code_position() { return pc() - debug_info_->code()->entry(); } inline int code_position() { return pc() - debug_info_->code()->entry(); }
...@@ -172,6 +173,7 @@ class Debug { ...@@ -172,6 +173,7 @@ class Debug {
int source_position, int source_position,
Handle<Object> break_point_object); Handle<Object> break_point_object);
static void ClearBreakPoint(Handle<Object> break_point_object); static void ClearBreakPoint(Handle<Object> break_point_object);
static void ClearAllBreakPoints();
static void FloodWithOneShot(Handle<SharedFunctionInfo> shared); static void FloodWithOneShot(Handle<SharedFunctionInfo> shared);
static void FloodHandlerWithOneShot(); static void FloodHandlerWithOneShot();
static void ChangeBreakOnException(ExceptionBreakType type, bool enable); static void ChangeBreakOnException(ExceptionBreakType type, bool enable);
...@@ -186,6 +188,7 @@ class Debug { ...@@ -186,6 +188,7 @@ class Debug {
static bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared); static bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
static bool IsDebugBreak(Address addr); static bool IsDebugBreak(Address addr);
static bool IsDebugBreakAtReturn(RelocInfo* rinfo);
// Check whether a code stub with the specified major key is a possible break // Check whether a code stub with the specified major key is a possible break
// point location. // point location.
...@@ -257,6 +260,7 @@ class Debug { ...@@ -257,6 +260,7 @@ class Debug {
friend class Debugger; friend class Debugger;
friend Handle<FixedArray> GetDebuggedFunctions(); // Found in test-debug.cc friend Handle<FixedArray> GetDebuggedFunctions(); // Found in test-debug.cc
friend void CheckDebuggerUnloaded(bool); // Found in test-debug.cc
// Threading support. // Threading support.
static char* ArchiveDebug(char* to); static char* ArchiveDebug(char* to);
......
...@@ -363,8 +363,66 @@ static Handle<Code> ComputeCallDebugBreak(int argc) { ...@@ -363,8 +363,66 @@ static Handle<Code> ComputeCallDebugBreak(int argc) {
Code); Code);
} }
// Check that the debugger is loaded.
static void CheckDebuggerLoaded() {
CHECK(Debug::debug_context().is_null());
}
// Check that the debugger has been fully unloaded.
static void CheckDebuggerUnloaded(bool check_functions) {
// Check that the debugger context is cleared and that there is no debug
// information stored for the debugger.
CHECK(Debug::debug_context().is_null());
CHECK_EQ(NULL, Debug::debug_info_list_);
// Collect garbage to ensure weak handles are cleared.
Heap::CollectAllGarbage();
Heap::CollectAllGarbage();
// Iterate the head and check that there are no debugger related objects left.
HeapIterator iterator;
while (iterator.has_next()) {
HeapObject* obj = iterator.next();
CHECK(obj != NULL);
CHECK(!obj->IsDebugInfo());
CHECK(!obj->IsBreakPointInfo());
// If deep check of functions is requested check that no debug break code
// is left in all functions.
if (check_functions) {
if (obj->IsJSFunction()) {
JSFunction* fun = JSFunction::cast(obj);
for (RelocIterator it(fun->shared()->code()); !it.done(); it.next()) {
RelocInfo::Mode rmode = it.rinfo()->rmode();
if (RelocInfo::IsCodeTarget(rmode)) {
CHECK(!Debug::IsDebugBreak(it.rinfo()->target_address()));
} else if (RelocInfo::IsJSReturn(rmode)) {
CHECK(!Debug::IsDebugBreakAtReturn(it.rinfo()));
}
}
}
}
}
}
} } // namespace v8::internal } } // namespace v8::internal
// Check that the debugger is loaded.
static void CheckDebuggerLoaded() {
v8::internal::CheckDebuggerLoaded();
}
// Check that the debugger has been fully unloaded.
static void CheckDebuggerUnloaded(bool check_functions = false) {
v8::internal::CheckDebuggerUnloaded(check_functions);
}
// Inherit from BreakLocationIterator to get access to protected parts for // Inherit from BreakLocationIterator to get access to protected parts for
// testing. // testing.
class TestBreakLocationIterator: public v8::internal::BreakLocationIterator { class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
...@@ -823,6 +881,7 @@ TEST(BreakPointICStore) { ...@@ -823,6 +881,7 @@ TEST(BreakPointICStore) {
break_point_hit_count = 0; break_point_hit_count = 0;
v8::HandleScope scope; v8::HandleScope scope;
DebugLocalContext env; DebugLocalContext env;
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount, v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined()); v8::Undefined());
v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->Run(); v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->Run();
...@@ -846,6 +905,7 @@ TEST(BreakPointICStore) { ...@@ -846,6 +905,7 @@ TEST(BreakPointICStore) {
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -878,6 +938,7 @@ TEST(BreakPointICLoad) { ...@@ -878,6 +938,7 @@ TEST(BreakPointICLoad) {
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -910,6 +971,7 @@ TEST(BreakPointICCall) { ...@@ -910,6 +971,7 @@ TEST(BreakPointICCall) {
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -941,6 +1003,7 @@ TEST(BreakPointReturn) { ...@@ -941,6 +1003,7 @@ TEST(BreakPointReturn) {
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -986,6 +1049,7 @@ TEST(GCDuringBreakPointProcessing) { ...@@ -986,6 +1049,7 @@ TEST(GCDuringBreakPointProcessing) {
CallWithBreakPoints(env->Global(), foo, 1, 25); CallWithBreakPoints(env->Global(), foo, 1, 25);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1043,6 +1107,7 @@ TEST(BreakPointSurviveGC) { ...@@ -1043,6 +1107,7 @@ TEST(BreakPointSurviveGC) {
CallAndGC(env->Global(), foo); CallAndGC(env->Global(), foo);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1093,6 +1158,7 @@ TEST(BreakPointThroughJavaScript) { ...@@ -1093,6 +1158,7 @@ TEST(BreakPointThroughJavaScript) {
CHECK_EQ(8, break_point_hit_count); CHECK_EQ(8, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
// Make sure that the break point numbers are consecutive. // Make sure that the break point numbers are consecutive.
CHECK_EQ(1, bp1); CHECK_EQ(1, bp1);
...@@ -1207,6 +1273,7 @@ TEST(ScriptBreakPointThroughJavaScript) { ...@@ -1207,6 +1273,7 @@ TEST(ScriptBreakPointThroughJavaScript) {
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
// Make sure that the break point numbers are consecutive. // Make sure that the break point numbers are consecutive.
CHECK_EQ(1, sbp1); CHECK_EQ(1, sbp1);
...@@ -1272,6 +1339,7 @@ TEST(EnableDisableScriptBreakPoint) { ...@@ -1272,6 +1339,7 @@ TEST(EnableDisableScriptBreakPoint) {
CHECK_EQ(3, break_point_hit_count); CHECK_EQ(3, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1333,6 +1401,7 @@ TEST(ConditionalScriptBreakPoint) { ...@@ -1333,6 +1401,7 @@ TEST(ConditionalScriptBreakPoint) {
CHECK_EQ(5, break_point_hit_count); CHECK_EQ(5, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1387,6 +1456,7 @@ TEST(ScriptBreakPointIgnoreCount) { ...@@ -1387,6 +1456,7 @@ TEST(ScriptBreakPointIgnoreCount) {
CHECK_EQ(5, break_point_hit_count); CHECK_EQ(5, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1445,6 +1515,7 @@ TEST(ScriptBreakPointReload) { ...@@ -1445,6 +1515,7 @@ TEST(ScriptBreakPointReload) {
CHECK_EQ(1, break_point_hit_count); CHECK_EQ(1, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1510,6 +1581,7 @@ TEST(ScriptBreakPointMultiple) { ...@@ -1510,6 +1581,7 @@ TEST(ScriptBreakPointMultiple) {
CHECK_EQ(2, break_point_hit_count); CHECK_EQ(2, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1565,6 +1637,7 @@ TEST(ScriptBreakPointLineOffset) { ...@@ -1565,6 +1637,7 @@ TEST(ScriptBreakPointLineOffset) {
CHECK_EQ(1, break_point_hit_count); CHECK_EQ(1, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1670,6 +1743,7 @@ TEST(ScriptBreakPointLine) { ...@@ -1670,6 +1743,7 @@ TEST(ScriptBreakPointLine) {
CHECK_EQ(0, break_point_hit_count); CHECK_EQ(0, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1695,6 +1769,7 @@ TEST(RemoveBreakPointInBreak) { ...@@ -1695,6 +1769,7 @@ TEST(RemoveBreakPointInBreak) {
CHECK_EQ(0, break_point_hit_count); CHECK_EQ(0, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1722,6 +1797,7 @@ TEST(DebuggerStatement) { ...@@ -1722,6 +1797,7 @@ TEST(DebuggerStatement) {
CHECK_EQ(3, break_point_hit_count); CHECK_EQ(3, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1836,6 +1912,7 @@ TEST(DebugEvaluate) { ...@@ -1836,6 +1912,7 @@ TEST(DebugEvaluate) {
bar->Call(env->Global(), 2, argv_bar_3); bar->Call(env->Global(), 2, argv_bar_3);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1861,10 +1938,12 @@ TEST(DebugStepLinear) { ...@@ -1861,10 +1938,12 @@ TEST(DebugStepLinear) {
CHECK_EQ(4, break_point_hit_count); CHECK_EQ(4, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
// Register a debug event listener which just counts. // Register a debug event listener which just counts.
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
SetBreakPoint(foo, 3);
break_point_hit_count = 0; break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL); foo->Call(env->Global(), 0, NULL);
...@@ -1872,6 +1951,7 @@ TEST(DebugStepLinear) { ...@@ -1872,6 +1951,7 @@ TEST(DebugStepLinear) {
CHECK_EQ(1, break_point_hit_count); CHECK_EQ(1, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1906,10 +1986,12 @@ TEST(DebugStepLinearMixedICs) { ...@@ -1906,10 +1986,12 @@ TEST(DebugStepLinearMixedICs) {
#endif #endif
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
// Register a debug event listener which just counts. // Register a debug event listener which just counts.
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
SetBreakPoint(foo, 0);
break_point_hit_count = 0; break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL); foo->Call(env->Global(), 0, NULL);
...@@ -1917,6 +1999,7 @@ TEST(DebugStepLinearMixedICs) { ...@@ -1917,6 +1999,7 @@ TEST(DebugStepLinearMixedICs) {
CHECK_EQ(1, break_point_hit_count); CHECK_EQ(1, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -1957,6 +2040,7 @@ TEST(DebugStepIf) { ...@@ -1957,6 +2040,7 @@ TEST(DebugStepIf) {
// Get rid of the debug event listener. // Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -2009,6 +2093,7 @@ TEST(DebugStepSwitch) { ...@@ -2009,6 +2093,7 @@ TEST(DebugStepSwitch) {
// Get rid of the debug event listener. // Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -2046,6 +2131,7 @@ TEST(DebugStepFor) { ...@@ -2046,6 +2131,7 @@ TEST(DebugStepFor) {
// Get rid of the debug event listener. // Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -2091,6 +2177,7 @@ TEST(StepInOutSimple) { ...@@ -2091,6 +2177,7 @@ TEST(StepInOutSimple) {
// Get rid of the debug event listener. // Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -2137,6 +2224,7 @@ TEST(StepInOutTree) { ...@@ -2137,6 +2224,7 @@ TEST(StepInOutTree) {
// Get rid of the debug event listener. // Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded(true);
} }
...@@ -2168,6 +2256,7 @@ TEST(StepInOutBranch) { ...@@ -2168,6 +2256,7 @@ TEST(StepInOutBranch) {
// Get rid of the debug event listener. // Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -2193,6 +2282,7 @@ TEST(DebugStepNatives) { ...@@ -2193,6 +2282,7 @@ TEST(DebugStepNatives) {
CHECK_EQ(3, break_point_hit_count); CHECK_EQ(3, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
// Register a debug event listener which just counts. // Register a debug event listener which just counts.
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
...@@ -2204,6 +2294,7 @@ TEST(DebugStepNatives) { ...@@ -2204,6 +2294,7 @@ TEST(DebugStepNatives) {
CHECK_EQ(1, break_point_hit_count); CHECK_EQ(1, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -2350,6 +2441,7 @@ TEST(BreakOnException) { ...@@ -2350,6 +2441,7 @@ TEST(BreakOnException) {
CHECK_EQ(1, message_callback_count); CHECK_EQ(1, message_callback_count);
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
v8::V8::RemoveMessageListeners(MessageCallbackCount); v8::V8::RemoveMessageListeners(MessageCallbackCount);
} }
...@@ -2486,6 +2578,7 @@ TEST(StepWithException) { ...@@ -2486,6 +2578,7 @@ TEST(StepWithException) {
// Get rid of the debug event listener. // Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -2539,6 +2632,7 @@ TEST(DebugBreak) { ...@@ -2539,6 +2632,7 @@ TEST(DebugBreak) {
// Get rid of the debug event listener. // Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -2575,6 +2669,7 @@ TEST(DisableBreak) { ...@@ -2575,6 +2669,7 @@ TEST(DisableBreak) {
// Get rid of the debug event listener. // Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL); v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
} }
...@@ -3506,3 +3601,62 @@ TEST(CallFunctionInDebugger) { ...@@ -3506,3 +3601,62 @@ TEST(CallFunctionInDebugger) {
// Test that a function with closure can be run in the debugger. // Test that a function with closure can be run in the debugger.
v8::Script::Compile(v8::String::New("CheckClosure()"))->Run(); v8::Script::Compile(v8::String::New("CheckClosure()"))->Run();
} }
// Test that clearing the debug event listener actually clears all break points
// and related information.
TEST(DebuggerUnload) {
v8::HandleScope scope;
DebugLocalContext env;
// Check debugger is unloaded before it is used.
CheckDebuggerUnloaded();
// Add debug event listener.
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
CheckDebuggerLoaded();
// Create a couple of functions for the test.
v8::Local<v8::Function> foo =
CompileFunction(&env, "function foo(){x=1}", "foo");
v8::Local<v8::Function> bar =
CompileFunction(&env, "function bar(){y=2}", "bar");
// Set some break points.
SetBreakPoint(foo, 0);
SetBreakPoint(foo, 4);
SetBreakPoint(bar, 0);
SetBreakPoint(bar, 4);
// Make sure that the break points are there.
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(2, break_point_hit_count);
bar->Call(env->Global(), 0, NULL);
CHECK_EQ(4, break_point_hit_count);
// Remove the debug event listener without clearing breakpoints.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded(true);
// Set a new debug event listener.
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
CheckDebuggerLoaded();
// Check that the break points was actually cleared.
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(0, break_point_hit_count);
// Set break points and run again.
SetBreakPoint(foo, 0);
SetBreakPoint(foo, 4);
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(2, break_point_hit_count);
// Remove the debug event listener without clearing breakpoints again.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded(true);
}
...@@ -153,9 +153,11 @@ assertFalse(exception, "exception in listener") ...@@ -153,9 +153,11 @@ assertFalse(exception, "exception in listener")
// Remove the debug event listener. // Remove the debug event listener.
Debug.setListener(null); Debug.setListener(null);
// Add debug event listener wich uses recursive breaks. // Set debug event listener wich uses recursive breaks.
listenerComplete = false;
Debug.setListener(listener_recurse); Debug.setListener(listener_recurse);
listenerComplete = false;
Debug.setBreakPoint(f, 2, 0);
debugger; debugger;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment