Index: test/cctest/test-debug.cc |
=================================================================== |
--- test/cctest/test-debug.cc (revision 1255) |
+++ test/cctest/test-debug.cc (working copy) |
@@ -363,8 +363,66 @@ |
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 |
+ |
+// 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 |
// testing. |
class TestBreakLocationIterator: public v8::internal::BreakLocationIterator { |
@@ -823,6 +881,7 @@ |
break_point_hit_count = 0; |
v8::HandleScope scope; |
DebugLocalContext env; |
+ |
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount, |
v8::Undefined()); |
v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->Run(); |
@@ -846,6 +905,7 @@ |
CHECK_EQ(2, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -878,6 +938,7 @@ |
CHECK_EQ(2, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -910,6 +971,7 @@ |
CHECK_EQ(2, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -941,6 +1003,7 @@ |
CHECK_EQ(2, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -986,6 +1049,7 @@ |
CallWithBreakPoints(env->Global(), foo, 1, 25); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1043,6 +1107,7 @@ |
CallAndGC(env->Global(), foo); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1093,6 +1158,7 @@ |
CHECK_EQ(8, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
// Make sure that the break point numbers are consecutive. |
CHECK_EQ(1, bp1); |
@@ -1207,6 +1273,7 @@ |
CHECK_EQ(2, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
// Make sure that the break point numbers are consecutive. |
CHECK_EQ(1, sbp1); |
@@ -1272,6 +1339,7 @@ |
CHECK_EQ(3, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1333,6 +1401,7 @@ |
CHECK_EQ(5, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1387,6 +1456,7 @@ |
CHECK_EQ(5, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1445,6 +1515,7 @@ |
CHECK_EQ(1, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1510,6 +1581,7 @@ |
CHECK_EQ(2, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1565,6 +1637,7 @@ |
CHECK_EQ(1, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1670,6 +1743,7 @@ |
CHECK_EQ(0, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1695,6 +1769,7 @@ |
CHECK_EQ(0, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1722,6 +1797,7 @@ |
CHECK_EQ(3, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1836,6 +1912,7 @@ |
bar->Call(env->Global(), 2, argv_bar_3); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1861,10 +1938,12 @@ |
CHECK_EQ(4, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
// Register a debug event listener which just counts. |
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); |
+ SetBreakPoint(foo, 3); |
break_point_hit_count = 0; |
foo->Call(env->Global(), 0, NULL); |
@@ -1872,6 +1951,7 @@ |
CHECK_EQ(1, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1906,10 +1986,12 @@ |
#endif |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
// Register a debug event listener which just counts. |
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); |
+ SetBreakPoint(foo, 0); |
break_point_hit_count = 0; |
foo->Call(env->Global(), 0, NULL); |
@@ -1917,6 +1999,7 @@ |
CHECK_EQ(1, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -1957,6 +2040,7 @@ |
// Get rid of the debug event listener. |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -2009,6 +2093,7 @@ |
// Get rid of the debug event listener. |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -2046,6 +2131,7 @@ |
// Get rid of the debug event listener. |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -2091,6 +2177,7 @@ |
// Get rid of the debug event listener. |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -2137,6 +2224,7 @@ |
// Get rid of the debug event listener. |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(true); |
} |
@@ -2168,6 +2256,7 @@ |
// Get rid of the debug event listener. |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -2193,6 +2282,7 @@ |
CHECK_EQ(3, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
// Register a debug event listener which just counts. |
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); |
@@ -2204,6 +2294,7 @@ |
CHECK_EQ(1, break_point_hit_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -2350,6 +2441,7 @@ |
CHECK_EQ(1, message_callback_count); |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
v8::V8::RemoveMessageListeners(MessageCallbackCount); |
} |
@@ -2486,6 +2578,7 @@ |
// Get rid of the debug event listener. |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -2539,6 +2632,7 @@ |
// Get rid of the debug event listener. |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -2575,6 +2669,7 @@ |
// Get rid of the debug event listener. |
v8::Debug::SetDebugEventListener(NULL); |
+ CheckDebuggerUnloaded(); |
} |
@@ -3506,3 +3601,62 @@ |
// Test that a function with closure can be run in the debugger. |
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); |
+} |