diff options
Diffstat (limited to 'deps/v8/test/cctest/test-debug.cc')
-rw-r--r-- | deps/v8/test/cctest/test-debug.cc | 1887 |
1 files changed, 161 insertions, 1726 deletions
diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index 3b43d9d11f..54904f9b84 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -30,8 +30,6 @@ #include "src/v8.h" #include "src/api.h" -#include "src/base/platform/condition-variable.h" -#include "src/base/platform/platform.h" #include "src/compilation-cache.h" #include "src/debug/debug-interface.h" #include "src/debug/debug.h" @@ -40,11 +38,6 @@ #include "src/utils.h" #include "test/cctest/cctest.h" -using ::v8::base::Mutex; -using ::v8::base::LockGuard; -using ::v8::base::ConditionVariable; -using ::v8::base::OS; -using ::v8::base::Semaphore; using ::v8::internal::EmbeddedVector; using ::v8::internal::Object; using ::v8::internal::Handle; @@ -52,8 +45,6 @@ using ::v8::internal::Heap; using ::v8::internal::JSGlobalProxy; using ::v8::internal::Code; using ::v8::internal::Debug; -using ::v8::internal::CommandMessage; -using ::v8::internal::CommandMessageQueue; using ::v8::internal::StackFrame; using ::v8::internal::StepAction; using ::v8::internal::StepIn; // From StepAction enum @@ -321,8 +312,8 @@ static void ChangeBreakOnExceptionFromJS(v8::Isolate* isolate, bool caught, // Change break on exception using the native API call. static void ChangeBreakOnExceptionFromAPI( - v8::Isolate* isolate, v8::DebugInterface::ExceptionBreakState state) { - v8::DebugInterface::ChangeBreakOnException(isolate, state); + v8::Isolate* isolate, v8::debug::ExceptionBreakState state) { + v8::debug::ChangeBreakOnException(isolate, state); } // Prepare to step to next break location. @@ -408,9 +399,6 @@ void CheckDebuggerUnloaded(bool check_functions) { // Check that the debugger has been fully unloaded. static void CheckDebuggerUnloaded(v8::Isolate* isolate, bool check_functions = false) { - // Let debugger to unload itself synchronously - v8::Debug::ProcessDebugMessages(isolate); - v8::internal::CheckDebuggerUnloaded(check_functions); } @@ -1612,20 +1600,6 @@ TEST(EnableDisableScriptBreakPoint) { f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); CHECK_EQ(2, break_point_hit_count); - // Reload the script and get f again checking that the disabling survives. - v8::Script::Compile(context, script, &origin) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); - f = v8::Local<v8::Function>::Cast( - env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked()); - f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(2, break_point_hit_count); - - EnableScriptBreakPointFromJS(isolate, sbp); - f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(3, break_point_hit_count); - v8::Debug::SetDebugEventListener(isolate, nullptr); CheckDebuggerUnloaded(isolate); } @@ -1683,100 +1657,6 @@ TEST(ConditionalScriptBreakPoint) { } CHECK_EQ(5, break_point_hit_count); - // Reload the script and get f again checking that the condition survives. - v8::Script::Compile(context, script, &origin) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); - f = v8::Local<v8::Function>::Cast( - env->Global() - ->Get(context, v8_str(env->GetIsolate(), "f")) - .ToLocalChecked()); - - break_point_hit_count = 0; - for (int i = 0; i < 10; i++) { - f->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked(); - } - CHECK_EQ(5, break_point_hit_count); - - v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); - CheckDebuggerUnloaded(env->GetIsolate()); -} - - -// Test that script break points survive when a script is reloaded. -TEST(ScriptBreakPointReload) { - break_point_hit_count = 0; - DebugLocalContext env; - v8::HandleScope scope(env->GetIsolate()); - env.ExposeDebug(); - - v8::Debug::SetDebugEventListener(env->GetIsolate(), - DebugEventBreakPointHitCount); - - v8::Local<v8::Context> context = env.context(); - v8::Local<v8::Function> f; - v8::Local<v8::String> script = v8_str(env->GetIsolate(), - "function f() {\n" - " function h() {\n" - " a = 0; // line 2\n" - " }\n" - " b = 1; // line 4\n" - " return h();\n" - "}"); - - v8::ScriptOrigin origin_1 = v8::ScriptOrigin(v8_str(env->GetIsolate(), "1")); - v8::ScriptOrigin origin_2 = v8::ScriptOrigin(v8_str(env->GetIsolate(), "2")); - - // Set a script break point before the script is loaded. - SetScriptBreakPointByNameFromJS(env->GetIsolate(), "1", 2, 0); - - // Compile the script and get the function. - v8::Script::Compile(context, script, &origin_1) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); - f = v8::Local<v8::Function>::Cast( - env->Global() - ->Get(context, v8_str(env->GetIsolate(), "f")) - .ToLocalChecked()); - - // Call f and check that the script break point is active. - break_point_hit_count = 0; - f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(1, break_point_hit_count); - - // Compile the script again with a different script data and get the - // function. - v8::Script::Compile(context, script, &origin_2) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); - f = v8::Local<v8::Function>::Cast( - env->Global() - ->Get(context, v8_str(env->GetIsolate(), "f")) - .ToLocalChecked()); - - // Call f and check that no break points are set. - break_point_hit_count = 0; - f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(0, break_point_hit_count); - - // Compile the script again and get the function. - v8::Script::Compile(context, script, &origin_1) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); - f = v8::Local<v8::Function>::Cast( - env->Global() - ->Get(context, v8_str(env->GetIsolate(), "f")) - .ToLocalChecked()); - - // Call f and check that the script break point is active. - break_point_hit_count = 0; - f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(1, break_point_hit_count); - v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); CheckDebuggerUnloaded(env->GetIsolate()); } @@ -1807,9 +1687,6 @@ TEST(ScriptBreakPointMultiple) { v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test")); - // Set a script break point before the scripts are loaded. - int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0); - // Compile the scripts with same script data and get the functions. v8::Script::Compile(context, script_f, &origin) .ToLocalChecked() @@ -1828,6 +1705,8 @@ TEST(ScriptBreakPointMultiple) { ->Get(context, v8_str(env->GetIsolate(), "g")) .ToLocalChecked()); + int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0); + // Call f and g and check that the script break point is active. break_point_hit_count = 0; f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); @@ -1883,17 +1762,17 @@ TEST(ScriptBreakPointLineOffset) { v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"), v8::Integer::New(env->GetIsolate(), 7)); - // Set two script break points before the script is loaded. - int sbp1 = - SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 8, 0); - int sbp2 = - SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0); - // Compile the script and get the function. v8::Script::Compile(context, script, &origin) .ToLocalChecked() ->Run(context) .ToLocalChecked(); + + int sbp1 = + SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 8, 0); + int sbp2 = + SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0); + f = v8::Local<v8::Function>::Cast( env->Global() ->Get(context, v8_str(env->GetIsolate(), "f")) @@ -1959,7 +1838,13 @@ TEST(ScriptBreakPointLine) { " }\n" " a=5; // line 12"); - // Set a couple script break point before the script is loaded. + // Compile the script and get the function. + break_point_hit_count = 0; + v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"), + v8::Integer::New(env->GetIsolate(), 0)); + v8::Local<v8::Script> compiled = + v8::Script::Compile(context, script, &origin).ToLocalChecked(); + int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 0, -1); int sbp2 = @@ -1967,14 +1852,8 @@ TEST(ScriptBreakPointLine) { int sbp3 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 5, -1); - // Compile the script and get the function. - break_point_hit_count = 0; - v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"), - v8::Integer::New(env->GetIsolate(), 0)); - v8::Script::Compile(context, script, &origin) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); + compiled->Run(context).ToLocalChecked(); + f = v8::Local<v8::Function>::Cast( env->Global() ->Get(context, v8_str(env->GetIsolate(), "f")) @@ -2020,39 +1899,21 @@ TEST(ScriptBreakPointLine) { g->Call(context, env->Global(), 0, NULL).ToLocalChecked(); CHECK_EQ(0, break_point_hit_count); - // Reload the script which should hit two break points. - break_point_hit_count = 0; - v8::Script::Compile(context, script, &origin) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); - CHECK_EQ(2, break_point_hit_count); - CHECK_EQ(0, StrLength(last_function_hit)); - // Set a break point in the code after the last function decleration. int sbp6 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 12, -1); - // Reload the script which should hit three break points. + // Reloading the script should not hit any break points. break_point_hit_count = 0; v8::Script::Compile(context, script, &origin) .ToLocalChecked() ->Run(context) .ToLocalChecked(); - CHECK_EQ(3, break_point_hit_count); - CHECK_EQ(0, StrLength(last_function_hit)); + CHECK_EQ(0, break_point_hit_count); - // Clear the last break points, and reload the script which should not hit any - // break points. ClearBreakPointFromJS(env->GetIsolate(), sbp1); ClearBreakPointFromJS(env->GetIsolate(), sbp5); ClearBreakPointFromJS(env->GetIsolate(), sbp6); - break_point_hit_count = 0; - v8::Script::Compile(context, script, &origin) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); - CHECK_EQ(0, break_point_hit_count); v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); CheckDebuggerUnloaded(env->GetIsolate()); @@ -2094,17 +1955,9 @@ TEST(ScriptBreakPointLineTopLevel) { f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); CHECK_EQ(0, break_point_hit_count); - // Recompile and run script and check that break point was hit. + // Recompile and run script and check that break point was not reapplied. break_point_hit_count = 0; CompileRunWithOrigin(script, "test.html"); - CHECK_EQ(1, break_point_hit_count); - - // Call f and check that there are still no break points. - break_point_hit_count = 0; - f = v8::Local<v8::Function>::Cast( - env->Global() - ->Get(context, v8_str(env->GetIsolate(), "f")) - .ToLocalChecked()); CHECK_EQ(0, break_point_hit_count); v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); @@ -2122,20 +1975,18 @@ TEST(ScriptBreakPointTopLevelCrash) { v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount); - v8::Local<v8::String> script_source = v8_str(env->GetIsolate(), - "function f() {\n" - " return 0;\n" - "}\n" - "f()"); - + CompileRunWithOrigin( + "function f() {\n" + " return 0;\n" + "}\n", + "test.html"); int sbp1 = - SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1); - { - v8::HandleScope scope(env->GetIsolate()); - break_point_hit_count = 0; - CompileRunWithOrigin(script_source, "test.html"); - CHECK_EQ(1, break_point_hit_count); - } + SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 1, -1); + break_point_hit_count = 0; + + CompileRun("f();"); + + CHECK_EQ(1, break_point_hit_count); int sbp2 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1); @@ -2492,171 +2343,6 @@ TEST(DebugEvaluateWithCodeGenerationDisallowed) { } -// Copies a C string to a 16-bit string. Does not check for buffer overflow. -// Does not use the V8 engine to convert strings, so it can be used -// in any thread. Returns the length of the string. -int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) { - int i; - for (i = 0; input_buffer[i] != '\0'; ++i) { - // ASCII does not use chars > 127, but be careful anyway. - output_buffer[i] = static_cast<unsigned char>(input_buffer[i]); - } - output_buffer[i] = 0; - return i; -} - - -// Copies a 16-bit string to a C string by dropping the high byte of -// each character. Does not check for buffer overflow. -// Can be used in any thread. Requires string length as an input. -int Utf16ToAscii(const uint16_t* input_buffer, int length, - char* output_buffer, int output_len = -1) { - if (output_len >= 0) { - if (length > output_len - 1) { - length = output_len - 1; - } - } - - for (int i = 0; i < length; ++i) { - output_buffer[i] = static_cast<char>(input_buffer[i]); - } - output_buffer[length] = '\0'; - return length; -} - - -// We match parts of the message to get evaluate result int value. -bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) { - if (strstr(message, "\"command\":\"evaluate\"") == NULL) { - return false; - } - const char* prefix = "\"text\":\""; - char* pos1 = strstr(message, prefix); - if (pos1 == NULL) { - return false; - } - pos1 += strlen(prefix); - char* pos2 = strchr(pos1, '"'); - if (pos2 == NULL) { - return false; - } - Vector<char> buf(buffer, buffer_size); - int len = static_cast<int>(pos2 - pos1); - if (len > buffer_size - 1) { - len = buffer_size - 1; - } - StrNCpy(buf, pos1, len); - buffer[buffer_size - 1] = '\0'; - return true; -} - - -struct EvaluateResult { - static const int kBufferSize = 20; - char buffer[kBufferSize]; -}; - -struct DebugProcessDebugMessagesData { - static const int kArraySize = 5; - int counter; - EvaluateResult results[kArraySize]; - - void reset() { - counter = 0; - } - EvaluateResult* current() { - return &results[counter % kArraySize]; - } - void next() { - counter++; - } -}; - -DebugProcessDebugMessagesData process_debug_messages_data; - -static void DebugProcessDebugMessagesHandler( - const v8::Debug::Message& message) { - v8::Local<v8::String> json = message.GetJSON(); - v8::String::Utf8Value utf8(json); - EvaluateResult* array_item = process_debug_messages_data.current(); - - bool res = GetEvaluateStringResult(*utf8, - array_item->buffer, - EvaluateResult::kBufferSize); - if (res) { - process_debug_messages_data.next(); - } -} - - -// Test that the evaluation of expressions works even from ProcessDebugMessages -// i.e. with empty stack. -TEST(DebugEvaluateWithoutStack) { - DebugLocalContext env; - v8::Debug::SetMessageHandler(env->GetIsolate(), - DebugProcessDebugMessagesHandler); - v8::HandleScope scope(env->GetIsolate()); - - const char* source = - "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }"; - - v8::Local<v8::Context> context = env.context(); - v8::Script::Compile(context, v8_str(env->GetIsolate(), source)) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); - - v8::Debug::ProcessDebugMessages(env->GetIsolate()); - - const int kBufferSize = 1000; - uint16_t buffer[kBufferSize]; - - const char* command_111 = "{\"seq\":111," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{" - " \"global\":true," - " \"expression\":\"v1\",\"disable_break\":true" - "}}"; - - v8::Isolate* isolate = CcTest::isolate(); - v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_111, buffer)); - - const char* command_112 = "{\"seq\":112," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{" - " \"global\":true," - " \"expression\":\"getAnimal()\",\"disable_break\":true" - "}}"; - - v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_112, buffer)); - - const char* command_113 = "{\"seq\":113," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{" - " \"global\":true," - " \"expression\":\"239 + 566\",\"disable_break\":true" - "}}"; - - v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_113, buffer)); - - v8::Debug::ProcessDebugMessages(isolate); - - CHECK_EQ(3, process_debug_messages_data.counter); - - CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0); - CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer), - 0); - CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0); - - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); - v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); - CheckDebuggerUnloaded(env->GetIsolate()); -} - - // Simple test of the stepping mechanism using only store ICs. TEST(DebugStepLinear) { DebugLocalContext env; @@ -3815,15 +3501,16 @@ TEST(PauseInScript) { const char* src = "(function (evt) {})"; const char* script_name = "StepInHandlerTest"; - // Set breakpoint in the script. - SetScriptBreakPointByNameFromJS(env->GetIsolate(), script_name, 0, -1); - break_point_hit_count = 0; - v8::ScriptOrigin origin(v8_str(env->GetIsolate(), script_name), v8::Integer::New(env->GetIsolate(), 0)); v8::Local<v8::Script> script = v8::Script::Compile(context, v8_str(env->GetIsolate(), src), &origin) .ToLocalChecked(); + + // Set breakpoint in the script. + SetScriptBreakPointByNameFromJS(env->GetIsolate(), script_name, 0, -1); + break_point_hit_count = 0; + v8::Local<v8::Value> r = script->Run(context).ToLocalChecked(); CHECK(r->IsFunction()); @@ -3995,7 +3682,7 @@ TEST(BreakOnException) { DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnExceptionFromAPI(env->GetIsolate(), - v8::DebugInterface::NoBreakOnException); + v8::debug::NoBreakOnException); caught->Call(context, env->Global(), 0, NULL).ToLocalChecked(); DebugEventCounterCheck(0, 0, 0); CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty()); @@ -4009,7 +3696,7 @@ TEST(BreakOnException) { DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnExceptionFromAPI(env->GetIsolate(), - v8::DebugInterface::BreakOnUncaughtException); + v8::debug::BreakOnUncaughtException); caught->Call(context, env->Global(), 0, NULL).ToLocalChecked(); DebugEventCounterCheck(0, 0, 0); CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty()); @@ -4023,7 +3710,7 @@ TEST(BreakOnException) { DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnExceptionFromAPI(env->GetIsolate(), - v8::DebugInterface::BreakOnAnyException); + v8::debug::BreakOnAnyException); caught->Call(context, env->Global(), 0, NULL).ToLocalChecked(); DebugEventCounterCheck(1, 0, 0); CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty()); @@ -4302,7 +3989,6 @@ TEST(DebugBreak) { // Set the debug break flag. v8::Debug::DebugBreak(env->GetIsolate()); - CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate())); // Call all functions with different argument count. break_point_hit_count = 0; @@ -4338,9 +4024,7 @@ TEST(DisableBreak) { // Set, test and cancel debug break. v8::Debug::DebugBreak(env->GetIsolate()); - CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate())); v8::Debug::CancelDebugBreak(env->GetIsolate()); - CHECK(!v8::Debug::CheckDebugBreak(env->GetIsolate())); // Set the debug break flag. v8::Debug::DebugBreak(env->GetIsolate()); @@ -4353,7 +4037,7 @@ TEST(DisableBreak) { { v8::Debug::DebugBreak(env->GetIsolate()); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate()); - v8::internal::DisableBreak disable_break(isolate->debug(), true); + v8::internal::DisableBreak disable_break(isolate->debug()); f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); CHECK_EQ(1, break_point_hit_count); } @@ -4942,787 +4626,10 @@ TEST(NoHiddenProperties) { } -// Multithreaded tests of JSON debugger protocol - -// Support classes - -// Provides synchronization between N threads, where N is a template parameter. -// The Wait() call blocks a thread until it is called for the Nth time, then all -// calls return. Each ThreadBarrier object can only be used once. -template <int N> -class ThreadBarrier final { - public: - ThreadBarrier() : num_blocked_(0) {} - - ~ThreadBarrier() { - LockGuard<Mutex> lock_guard(&mutex_); - if (num_blocked_ != 0) { - CHECK_EQ(N, num_blocked_); - } - } - - void Wait() { - LockGuard<Mutex> lock_guard(&mutex_); - CHECK_LT(num_blocked_, N); - num_blocked_++; - if (N == num_blocked_) { - // Signal and unblock all waiting threads. - cv_.NotifyAll(); - printf("BARRIER\n\n"); - fflush(stdout); - } else { // Wait for the semaphore. - while (num_blocked_ < N) { - cv_.Wait(&mutex_); - } - } - CHECK_EQ(N, num_blocked_); - } - - private: - ConditionVariable cv_; - Mutex mutex_; - int num_blocked_; - - STATIC_ASSERT(N > 0); - - DISALLOW_COPY_AND_ASSIGN(ThreadBarrier); -}; - - -// A set containing enough barriers and semaphores for any of the tests. -class Barriers { - public: - Barriers() : semaphore_1(0), semaphore_2(0) {} - ThreadBarrier<2> barrier_1; - ThreadBarrier<2> barrier_2; - ThreadBarrier<2> barrier_3; - ThreadBarrier<2> barrier_4; - ThreadBarrier<2> barrier_5; - v8::base::Semaphore semaphore_1; - v8::base::Semaphore semaphore_2; -}; - - -// We match parts of the message to decide if it is a break message. -bool IsBreakEventMessage(char *message) { - const char* type_event = "\"type\":\"event\""; - const char* event_break = "\"event\":\"break\""; - // Does the message contain both type:event and event:break? - return strstr(message, type_event) != NULL && - strstr(message, event_break) != NULL; -} - - -// We match parts of the message to decide if it is a exception message. -bool IsExceptionEventMessage(char *message) { - const char* type_event = "\"type\":\"event\""; - const char* event_exception = "\"event\":\"exception\""; - // Does the message contain both type:event and event:exception? - return strstr(message, type_event) != NULL && - strstr(message, event_exception) != NULL; -} - - -// We match the message wether it is an evaluate response message. -bool IsEvaluateResponseMessage(char* message) { - const char* type_response = "\"type\":\"response\""; - const char* command_evaluate = "\"command\":\"evaluate\""; - // Does the message contain both type:response and command:evaluate? - return strstr(message, type_response) != NULL && - strstr(message, command_evaluate) != NULL; -} - - -static int StringToInt(const char* s) { - return atoi(s); // NOLINT -} - - -// We match parts of the message to get evaluate result int value. -int GetEvaluateIntResult(char *message) { - const char* value = "\"value\":"; - char* pos = strstr(message, value); - if (pos == NULL) { - return -1; - } - int res = -1; - res = StringToInt(pos + strlen(value)); - return res; -} - - -// We match parts of the message to get hit breakpoint id. -int GetBreakpointIdFromBreakEventMessage(char *message) { - const char* breakpoints = "\"breakpoints\":["; - char* pos = strstr(message, breakpoints); - if (pos == NULL) { - return -1; - } - int res = -1; - res = StringToInt(pos + strlen(breakpoints)); - return res; -} - - -// We match parts of the message to get total frames number. -int GetTotalFramesInt(char *message) { - const char* prefix = "\"totalFrames\":"; - char* pos = strstr(message, prefix); - if (pos == NULL) { - return -1; - } - pos += strlen(prefix); - int res = StringToInt(pos); - return res; -} - - -// We match parts of the message to get source line. -int GetSourceLineFromBreakEventMessage(char *message) { - const char* source_line = "\"sourceLine\":"; - char* pos = strstr(message, source_line); - if (pos == NULL) { - return -1; - } - int res = -1; - res = StringToInt(pos + strlen(source_line)); - return res; -} - - -/* Test MessageQueues */ -/* Tests the message queues that hold debugger commands and - * response messages to the debugger. Fills queues and makes - * them grow. - */ -Barriers message_queue_barriers; - -// This is the debugger thread, that executes no v8 calls except -// placing JSON debugger commands in the queue. -class MessageQueueDebuggerThread : public v8::base::Thread { - public: - MessageQueueDebuggerThread() - : Thread(Options("MessageQueueDebuggerThread")) {} - void Run(); -}; - - -static void MessageHandler(const v8::Debug::Message& message) { - v8::Local<v8::String> json = message.GetJSON(); - v8::String::Utf8Value utf8(json); - if (IsBreakEventMessage(*utf8)) { - // Lets test script wait until break occurs to send commands. - // Signals when a break is reported. - message_queue_barriers.semaphore_2.Signal(); - } - - // Allow message handler to block on a semaphore, to test queueing of - // messages while blocked. - message_queue_barriers.semaphore_1.Wait(); -} - - -void MessageQueueDebuggerThread::Run() { - const int kBufferSize = 1000; - uint16_t buffer_1[kBufferSize]; - uint16_t buffer_2[kBufferSize]; - const char* command_1 = - "{\"seq\":117," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"1+2\"}}"; - const char* command_2 = - "{\"seq\":118," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"1+a\"}}"; - const char* command_3 = - "{\"seq\":119," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"c.d * b\"}}"; - const char* command_continue = - "{\"seq\":106," - "\"type\":\"request\"," - "\"command\":\"continue\"}"; - const char* command_single_step = - "{\"seq\":107," - "\"type\":\"request\"," - "\"command\":\"continue\"," - "\"arguments\":{\"stepaction\":\"next\"}}"; - - /* Interleaved sequence of actions by the two threads:*/ - // Main thread compiles and runs source_1 - message_queue_barriers.semaphore_1.Signal(); - message_queue_barriers.barrier_1.Wait(); - // Post 6 commands, filling the command queue and making it expand. - // These calls return immediately, but the commands stay on the queue - // until the execution of source_2. - // Note: AsciiToUtf16 executes before SendCommand, so command is copied - // to buffer before buffer is sent to SendCommand. - v8::Isolate* isolate = CcTest::isolate(); - v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1)); - v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2)); - v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2)); - v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2)); - v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2)); - message_queue_barriers.barrier_2.Wait(); - // Main thread compiles and runs source_2. - // Queued commands are executed at the start of compilation of source_2( - // beforeCompile event). - // Free the message handler to process all the messages from the queue. 7 - // messages are expected: 2 afterCompile events and 5 responses. - // All the commands added so far will fail to execute as long as call stack - // is empty on beforeCompile event. - for (int i = 0; i < 6 ; ++i) { - message_queue_barriers.semaphore_1.Signal(); - } - message_queue_barriers.barrier_3.Wait(); - // Main thread compiles and runs source_3. - // Don't stop in the afterCompile handler. - message_queue_barriers.semaphore_1.Signal(); - // source_3 includes a debugger statement, which causes a break event. - // Wait on break event from hitting "debugger" statement - message_queue_barriers.semaphore_2.Wait(); - // These should execute after the "debugger" statement in source_2 - v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1)); - v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2)); - v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2)); - v8::Debug::SendCommand( - isolate, buffer_2, AsciiToUtf16(command_single_step, buffer_2)); - // Run after 2 break events, 4 responses. - for (int i = 0; i < 6 ; ++i) { - message_queue_barriers.semaphore_1.Signal(); - } - // Wait on break event after a single step executes. - message_queue_barriers.semaphore_2.Wait(); - v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_2, buffer_1)); - v8::Debug::SendCommand( - isolate, buffer_2, AsciiToUtf16(command_continue, buffer_2)); - // Run after 2 responses. - for (int i = 0; i < 2 ; ++i) { - message_queue_barriers.semaphore_1.Signal(); - } - // Main thread continues running source_3 to end, waits for this thread. -} - - -// This thread runs the v8 engine. -TEST(MessageQueues) { - MessageQueueDebuggerThread message_queue_debugger_thread; - - // Create a V8 environment - DebugLocalContext env; - v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetMessageHandler(env->GetIsolate(), MessageHandler); - message_queue_debugger_thread.Start(); - - const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;"; - const char* source_2 = "e = 17;"; - const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;"; - - // See MessageQueueDebuggerThread::Run for interleaved sequence of - // API calls and events in the two threads. - CompileRun(source_1); - message_queue_barriers.barrier_1.Wait(); - message_queue_barriers.barrier_2.Wait(); - CompileRun(source_2); - message_queue_barriers.barrier_3.Wait(); - CompileRun(source_3); - message_queue_debugger_thread.Join(); - fflush(stdout); -} - - -class TestClientData : public v8::Debug::ClientData { - public: - TestClientData() { - constructor_call_counter++; - } - virtual ~TestClientData() { - destructor_call_counter++; - } - - static void ResetCounters() { - constructor_call_counter = 0; - destructor_call_counter = 0; - } - - static int constructor_call_counter; - static int destructor_call_counter; -}; - -int TestClientData::constructor_call_counter = 0; -int TestClientData::destructor_call_counter = 0; - - -// Tests that MessageQueue doesn't destroy client data when expands and -// does destroy when it dies. -TEST(MessageQueueExpandAndDestroy) { - TestClientData::ResetCounters(); - { // Create a scope for the queue. - CommandMessageQueue queue(1); - queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), - new TestClientData())); - queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), - new TestClientData())); - queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), - new TestClientData())); - CHECK_EQ(0, TestClientData::destructor_call_counter); - queue.Get().Dispose(); - CHECK_EQ(1, TestClientData::destructor_call_counter); - queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), - new TestClientData())); - queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), - new TestClientData())); - queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), - new TestClientData())); - queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), - new TestClientData())); - queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), - new TestClientData())); - CHECK_EQ(1, TestClientData::destructor_call_counter); - queue.Get().Dispose(); - CHECK_EQ(2, TestClientData::destructor_call_counter); - } - // All the client data should be destroyed when the queue is destroyed. - CHECK_EQ(TestClientData::destructor_call_counter, - TestClientData::destructor_call_counter); -} - - -static int handled_client_data_instances_count = 0; -static void MessageHandlerCountingClientData( - const v8::Debug::Message& message) { - if (message.GetClientData() != NULL) { - handled_client_data_instances_count++; - } -} - - -// Tests that all client data passed to the debugger are sent to the handler. -TEST(SendClientDataToHandler) { - // Create a V8 environment - DebugLocalContext env; - v8::Isolate* isolate = env->GetIsolate(); - v8::HandleScope scope(isolate); - TestClientData::ResetCounters(); - handled_client_data_instances_count = 0; - v8::Debug::SetMessageHandler(isolate, MessageHandlerCountingClientData); - const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;"; - const int kBufferSize = 1000; - uint16_t buffer[kBufferSize]; - const char* command_1 = - "{\"seq\":117," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"1+2\"}}"; - const char* command_2 = - "{\"seq\":118," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"1+a\"}}"; - const char* command_continue = - "{\"seq\":106," - "\"type\":\"request\"," - "\"command\":\"continue\"}"; - - v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_1, buffer), - new TestClientData()); - v8::Debug::SendCommand( - isolate, buffer, AsciiToUtf16(command_2, buffer), NULL); - v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer), - new TestClientData()); - v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer), - new TestClientData()); - // All the messages will be processed on beforeCompile event. - CompileRun(source_1); - v8::Debug::SendCommand( - isolate, buffer, AsciiToUtf16(command_continue, buffer)); - CHECK_EQ(3, TestClientData::constructor_call_counter); - CHECK_EQ(TestClientData::constructor_call_counter, - handled_client_data_instances_count); - CHECK_EQ(TestClientData::constructor_call_counter, - TestClientData::destructor_call_counter); -} - - -/* Test ThreadedDebugging */ -/* This test interrupts a running infinite loop that is - * occupying the v8 thread by a break command from the - * debugger thread. It then changes the value of a - * global object, to make the loop terminate. - */ - -Barriers threaded_debugging_barriers; - -class V8Thread : public v8::base::Thread { - public: - V8Thread() : Thread(Options("V8Thread")) {} - void Run(); - v8::Isolate* isolate() { return isolate_; } - - private: - v8::Isolate* isolate_; -}; - -class DebuggerThread : public v8::base::Thread { - public: - explicit DebuggerThread(v8::Isolate* isolate) - : Thread(Options("DebuggerThread")), isolate_(isolate) {} - void Run(); - - private: - v8::Isolate* isolate_; -}; - - -static void ThreadedAtBarrier1( - const v8::FunctionCallbackInfo<v8::Value>& args) { - threaded_debugging_barriers.barrier_1.Wait(); -} - - -static void ThreadedMessageHandler(const v8::Debug::Message& message) { - static char print_buffer[1000]; - v8::String::Value json(message.GetJSON()); - Utf16ToAscii(*json, json.length(), print_buffer); - if (IsBreakEventMessage(print_buffer)) { - // Check that we are inside the while loop. - int source_line = GetSourceLineFromBreakEventMessage(print_buffer); - CHECK(4 <= source_line && source_line <= 10); - threaded_debugging_barriers.barrier_2.Wait(); - } -} - - -void V8Thread::Run() { - const char* source = - "flag = true;\n" - "\n" - "function foo() {\n" - " var x = 1;\n" - " while ( flag == true ) {\n" - " if ( x == 1 ) {\n" - " ThreadedAtBarrier1();\n" - " }\n" - " x = x + 1;\n" - " }\n" - "}\n" - "\n" - "foo();\n"; - - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - isolate_ = v8::Isolate::New(create_params); - threaded_debugging_barriers.barrier_3.Wait(); - { - v8::Isolate::Scope isolate_scope(isolate_); - DebugLocalContext env(isolate_); - v8::HandleScope scope(isolate_); - v8::Debug::SetMessageHandler(isolate_, &ThreadedMessageHandler); - v8::Local<v8::ObjectTemplate> global_template = - v8::ObjectTemplate::New(env->GetIsolate()); - global_template->Set( - v8_str(env->GetIsolate(), "ThreadedAtBarrier1"), - v8::FunctionTemplate::New(isolate_, ThreadedAtBarrier1)); - v8::Local<v8::Context> context = - v8::Context::New(isolate_, NULL, global_template); - v8::Context::Scope context_scope(context); - - CompileRun(source); - } - threaded_debugging_barriers.barrier_4.Wait(); - isolate_->Dispose(); -} - - -void DebuggerThread::Run() { - const int kBufSize = 1000; - uint16_t buffer[kBufSize]; - - const char* command_1 = - "{\"seq\":102," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"flag = false\"}}"; - const char* command_2 = "{\"seq\":103," - "\"type\":\"request\"," - "\"command\":\"continue\"}"; - - threaded_debugging_barriers.barrier_1.Wait(); - v8::Debug::DebugBreak(isolate_); - threaded_debugging_barriers.barrier_2.Wait(); - v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer)); - v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer)); - threaded_debugging_barriers.barrier_4.Wait(); -} - - -TEST(ThreadedDebugging) { - V8Thread v8_thread; - - // Create a V8 environment - v8_thread.Start(); - threaded_debugging_barriers.barrier_3.Wait(); - DebuggerThread debugger_thread(v8_thread.isolate()); - debugger_thread.Start(); - - v8_thread.Join(); - debugger_thread.Join(); -} - - -/* Test RecursiveBreakpoints */ -/* In this test, the debugger evaluates a function with a breakpoint, after - * hitting a breakpoint in another function. We do this with both values - * of the flag enabling recursive breakpoints, and verify that the second - * breakpoint is hit when enabled, and missed when disabled. - */ - -class BreakpointsV8Thread : public v8::base::Thread { - public: - BreakpointsV8Thread() : Thread(Options("BreakpointsV8Thread")) {} - void Run(); - - v8::Isolate* isolate() { return isolate_; } - - private: - v8::Isolate* isolate_; -}; - -class BreakpointsDebuggerThread : public v8::base::Thread { - public: - BreakpointsDebuggerThread(bool global_evaluate, v8::Isolate* isolate) - : Thread(Options("BreakpointsDebuggerThread")), - global_evaluate_(global_evaluate), - isolate_(isolate) {} - void Run(); - - private: - bool global_evaluate_; - v8::Isolate* isolate_; -}; - - -Barriers* breakpoints_barriers; -int break_event_breakpoint_id; -int evaluate_int_result; - -static void BreakpointsMessageHandler(const v8::Debug::Message& message) { - static char print_buffer[1000]; - v8::String::Value json(message.GetJSON()); - Utf16ToAscii(*json, json.length(), print_buffer); - - if (IsBreakEventMessage(print_buffer)) { - break_event_breakpoint_id = - GetBreakpointIdFromBreakEventMessage(print_buffer); - breakpoints_barriers->semaphore_1.Signal(); - } else if (IsEvaluateResponseMessage(print_buffer)) { - evaluate_int_result = GetEvaluateIntResult(print_buffer); - breakpoints_barriers->semaphore_1.Signal(); - } -} - - -void BreakpointsV8Thread::Run() { - const char* source_1 = "var y_global = 3;\n" - "function cat( new_value ) {\n" - " var x = new_value;\n" - " y_global = y_global + 4;\n" - " x = 3 * x + 1;\n" - " y_global = y_global + 5;\n" - " return x;\n" - "}\n" - "\n" - "function dog() {\n" - " var x = 1;\n" - " x = y_global;" - " var z = 3;" - " x += 100;\n" - " return x;\n" - "}\n" - "\n"; - const char* source_2 = "cat(17);\n" - "cat(19);\n"; - - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - isolate_ = v8::Isolate::New(create_params); - breakpoints_barriers->barrier_3.Wait(); - { - v8::Isolate::Scope isolate_scope(isolate_); - DebugLocalContext env(isolate_); - v8::HandleScope scope(isolate_); - v8::Debug::SetMessageHandler(isolate_, &BreakpointsMessageHandler); - - CompileRun(source_1); - breakpoints_barriers->barrier_1.Wait(); - breakpoints_barriers->barrier_2.Wait(); - CompileRun(source_2); - } - breakpoints_barriers->barrier_4.Wait(); - isolate_->Dispose(); -} - - -void BreakpointsDebuggerThread::Run() { - const int kBufSize = 1000; - uint16_t buffer[kBufSize]; - - const char* command_1 = "{\"seq\":101," - "\"type\":\"request\"," - "\"command\":\"setbreakpoint\"," - "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}"; - const char* command_2 = "{\"seq\":102," - "\"type\":\"request\"," - "\"command\":\"setbreakpoint\"," - "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}"; - const char* command_3; - if (this->global_evaluate_) { - command_3 = "{\"seq\":103," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false," - "\"global\":true}}"; - } else { - command_3 = "{\"seq\":103," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}"; - } - const char* command_4; - if (this->global_evaluate_) { - command_4 = "{\"seq\":104," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true," - "\"global\":true}}"; - } else { - command_4 = "{\"seq\":104," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}"; - } - const char* command_5 = "{\"seq\":105," - "\"type\":\"request\"," - "\"command\":\"continue\"}"; - const char* command_6 = "{\"seq\":106," - "\"type\":\"request\"," - "\"command\":\"continue\"}"; - const char* command_7; - if (this->global_evaluate_) { - command_7 = "{\"seq\":107," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true," - "\"global\":true}}"; - } else { - command_7 = "{\"seq\":107," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}"; - } - const char* command_8 = "{\"seq\":108," - "\"type\":\"request\"," - "\"command\":\"continue\"}"; - - - // v8 thread initializes, runs source_1 - breakpoints_barriers->barrier_1.Wait(); - // 1:Set breakpoint in cat() (will get id 1). - v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer)); - // 2:Set breakpoint in dog() (will get id 2). - v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer)); - breakpoints_barriers->barrier_2.Wait(); - // V8 thread starts compiling source_2. - // Automatic break happens, to run queued commands - // breakpoints_barriers->semaphore_1.Wait(); - // Commands 1 through 3 run, thread continues. - // v8 thread runs source_2 to breakpoint in cat(). - // message callback receives break event. - breakpoints_barriers->semaphore_1.Wait(); - // Must have hit breakpoint #1. - CHECK_EQ(1, break_event_breakpoint_id); - // 4:Evaluate dog() (which has a breakpoint). - v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_3, buffer)); - // V8 thread hits breakpoint in dog(). - breakpoints_barriers->semaphore_1.Wait(); // wait for break event - // Must have hit breakpoint #2. - CHECK_EQ(2, break_event_breakpoint_id); - // 5:Evaluate (x + 1). - v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_4, buffer)); - // Evaluate (x + 1) finishes. - breakpoints_barriers->semaphore_1.Wait(); - // Must have result 108. - CHECK_EQ(108, evaluate_int_result); - // 6:Continue evaluation of dog(). - v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_5, buffer)); - // Evaluate dog() finishes. - breakpoints_barriers->semaphore_1.Wait(); - // Must have result 107. - CHECK_EQ(107, evaluate_int_result); - // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint - // in cat(19). - v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_6, buffer)); - // Message callback gets break event. - breakpoints_barriers->semaphore_1.Wait(); // wait for break event - // Must have hit breakpoint #1. - CHECK_EQ(1, break_event_breakpoint_id); - // 8: Evaluate dog() with breaks disabled. - v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_7, buffer)); - // Evaluate dog() finishes. - breakpoints_barriers->semaphore_1.Wait(); - // Must have result 116. - CHECK_EQ(116, evaluate_int_result); - // 9: Continue evaluation of source2, reach end. - v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_8, buffer)); - breakpoints_barriers->barrier_4.Wait(); -} - - -void TestRecursiveBreakpointsGeneric(bool global_evaluate) { - BreakpointsV8Thread breakpoints_v8_thread; - - // Create a V8 environment - Barriers stack_allocated_breakpoints_barriers; - breakpoints_barriers = &stack_allocated_breakpoints_barriers; - - breakpoints_v8_thread.Start(); - breakpoints_barriers->barrier_3.Wait(); - BreakpointsDebuggerThread breakpoints_debugger_thread( - global_evaluate, breakpoints_v8_thread.isolate()); - breakpoints_debugger_thread.Start(); - - breakpoints_v8_thread.Join(); - breakpoints_debugger_thread.Join(); -} - - -TEST(RecursiveBreakpoints) { - TestRecursiveBreakpointsGeneric(false); -} - - -TEST(RecursiveBreakpointsGlobal) { - TestRecursiveBreakpointsGeneric(true); -} - - TEST(SetDebugEventListenerOnUninitializedVM) { v8::Debug::SetDebugEventListener(CcTest::isolate(), DummyDebugEventListener); } - -static void DummyMessageHandler(const v8::Debug::Message& message) { -} - - -TEST(SetMessageHandlerOnUninitializedVM) { - v8::Debug::SetMessageHandler(CcTest::isolate(), DummyMessageHandler); -} - - // Source for a JavaScript function which returns the data parameter of a // function called in the context of the debugger. If no data parameter is // passed it throws an exception. @@ -5931,19 +4838,6 @@ TEST(CallFunctionInDebugger) { } -// Debugger message handler which counts the number of breaks. -static void SendContinueCommand(); -static void MessageHandlerBreakPointHitCount( - const v8::Debug::Message& message) { - if (message.IsEvent() && message.GetEvent() == v8::Break) { - // Count the number of breaks. - break_point_hit_count++; - - SendContinueCommand(); - } -} - - // Test that clearing the debug event listener actually clears all break points // and related information. TEST(DebuggerUnload) { @@ -5983,132 +4877,41 @@ TEST(DebuggerUnload) { // outside a handle scope. v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); CheckDebuggerUnloaded(env->GetIsolate(), true); - - // Now set a debug message handler. - break_point_hit_count = 0; - v8::Debug::SetMessageHandler(env->GetIsolate(), - MessageHandlerBreakPointHitCount); - { - v8::HandleScope scope(env->GetIsolate()); - - // Get the test functions again. - v8::Local<v8::Function> foo(v8::Local<v8::Function>::Cast( - env->Global() - ->Get(context, v8_str(env->GetIsolate(), "foo")) - .ToLocalChecked())); - - foo->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(0, break_point_hit_count); - - // Set break points and run again. - SetBreakPoint(foo, 0); - SetBreakPoint(foo, 4); - foo->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(2, break_point_hit_count); - } - - // Remove the debug message handler without clearing breakpoints. Do this - // outside a handle scope. - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); - CheckDebuggerUnloaded(env->GetIsolate(), true); } +int event_listener_hit_count = 0; -// Sends continue command to the debugger. -static void SendContinueCommand() { - const int kBufferSize = 1000; - uint16_t buffer[kBufferSize]; - const char* command_continue = - "{\"seq\":0," - "\"type\":\"request\"," - "\"command\":\"continue\"}"; +// Debugger event listener which clears itself while active. +static void EventListenerClearingItself( + const v8::Debug::EventDetails& details) { + event_listener_hit_count++; - v8::Debug::SendCommand( - CcTest::isolate(), buffer, AsciiToUtf16(command_continue, buffer)); -} - - -// Debugger message handler which counts the number of times it is called. -static int message_handler_hit_count = 0; -static void MessageHandlerHitCount(const v8::Debug::Message& message) { - message_handler_hit_count++; - - static char print_buffer[1000]; - v8::String::Value json(message.GetJSON()); - Utf16ToAscii(*json, json.length(), print_buffer); - if (IsExceptionEventMessage(print_buffer)) { - // Send a continue command for exception events. - SendContinueCommand(); - } -} - - -// Test clearing the debug message handler. -TEST(DebuggerClearMessageHandler) { - DebugLocalContext env; - v8::HandleScope scope(env->GetIsolate()); - - // Check debugger is unloaded before it is used. - CheckDebuggerUnloaded(env->GetIsolate()); - - // Set a debug message handler. - v8::Debug::SetMessageHandler(env->GetIsolate(), MessageHandlerHitCount); - - // Run code to throw a unhandled exception. This should end up in the message - // handler. - CompileRun("throw 1"); - - // The message handler should be called. - CHECK_GT(message_handler_hit_count, 0); - - // Clear debug message handler. - message_handler_hit_count = 0; - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); - - // Run code to throw a unhandled exception. This should end up in the message - // handler. - CompileRun("throw 1"); - - // The message handler should not be called more. - CHECK_EQ(0, message_handler_hit_count); - - CheckDebuggerUnloaded(env->GetIsolate(), true); -} - - -// Debugger message handler which clears the message handler while active. -static void MessageHandlerClearingMessageHandler( - const v8::Debug::Message& message) { - message_handler_hit_count++; - - // Clear debug message handler. - v8::Debug::SetMessageHandler(message.GetIsolate(), nullptr); + // Clear debug event listener. + v8::Debug::SetDebugEventListener(details.GetIsolate(), nullptr); } // Test clearing the debug message handler while processing a debug event. -TEST(DebuggerClearMessageHandlerWhileActive) { +TEST(DebuggerClearEventListenerWhileActive) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); // Check debugger is unloaded before it is used. CheckDebuggerUnloaded(env->GetIsolate()); - // Set a debug message handler. - v8::Debug::SetMessageHandler(env->GetIsolate(), - MessageHandlerClearingMessageHandler); + // Set a debug event listener. + v8::Debug::SetDebugEventListener(env->GetIsolate(), + EventListenerClearingItself); - // Run code to throw a unhandled exception. This should end up in the message - // handler. + // Run code to throw an uncaught exception. This should trigger the listener. CompileRun("throw 1"); - // The message handler should be called. - CHECK_EQ(1, message_handler_hit_count); + // The event listener should have been called. + CHECK_EQ(1, event_listener_hit_count); CheckDebuggerUnloaded(env->GetIsolate(), true); } - // Test for issue http://code.google.com/p/v8/issues/detail?id=289. // Make sure that DebugGetLoadedScripts doesn't return scripts // with disposed external source. @@ -6258,26 +5061,18 @@ static v8::Local<v8::Value> expected_context_data; // Check that the expected context is the one generating the debug event. -static void ContextCheckMessageHandler(const v8::Debug::Message& message) { - CHECK(message.GetEventContext() == expected_context); - CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals( +static void ContextCheckEventListener( + const v8::Debug::EventDetails& event_details) { + CHECK(event_details.GetEventContext() == expected_context); + CHECK(event_details.GetEventContext()->GetEmbedderData(0)->StrictEquals( expected_context_data)); - message_handler_hit_count++; - - static char print_buffer[1000]; - v8::String::Value json(message.GetJSON()); - Utf16ToAscii(*json, json.length(), print_buffer); - - // Send a continue command for break events. - if (IsBreakEventMessage(print_buffer)) { - SendContinueCommand(); - } + event_listener_hit_count++; } // Test which creates two contexts and sets different embedder data on each. -// Checks that this data is set correctly and that when the debug message -// handler is called the expected context is the one active. +// Checks that this data is set correctly and that when the debug event +// listener is called the expected context is the one active. TEST(ContextData) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); @@ -6291,7 +5086,7 @@ TEST(ContextData) { context_1 = v8::Context::New(isolate, NULL, global_template, global_object); context_2 = v8::Context::New(isolate, NULL, global_template, global_object); - v8::Debug::SetMessageHandler(isolate, ContextCheckMessageHandler); + v8::Debug::SetDebugEventListener(isolate, ContextCheckEventListener); // Default data value is undefined. CHECK(context_1->GetEmbedderData(0)->IsUndefined()); @@ -6328,39 +5123,31 @@ TEST(ContextData) { } // Two times compile event and two times break event. - CHECK_GT(message_handler_hit_count, 4); + CHECK_GT(event_listener_hit_count, 3); - v8::Debug::SetMessageHandler(isolate, nullptr); + v8::Debug::SetDebugEventListener(isolate, nullptr); CheckDebuggerUnloaded(isolate); } - -// Debug message handler which issues a debug break when it hits a break event. -static int message_handler_break_hit_count = 0; -static void DebugBreakMessageHandler(const v8::Debug::Message& message) { +// Debug event listener which issues a debug break when it hits a break event. +static int event_listener_break_hit_count = 0; +static void DebugBreakEventListener(const v8::Debug::EventDetails& details) { // Schedule a debug break for break events. - if (message.IsEvent() && message.GetEvent() == v8::Break) { - message_handler_break_hit_count++; - if (message_handler_break_hit_count == 1) { - v8::Debug::DebugBreak(message.GetIsolate()); + if (details.GetEvent() == v8::Break) { + event_listener_break_hit_count++; + if (event_listener_break_hit_count == 1) { + v8::Debug::DebugBreak(details.GetIsolate()); } } - - // Issue a continue command if this event will not cause the VM to start - // running. - if (!message.WillStartRunning()) { - SendContinueCommand(); - } } - -// Test that a debug break can be scheduled while in a message handler. -TEST(DebugBreakInMessageHandler) { +// Test that a debug break can be scheduled while in a event listener. +TEST(DebugBreakInEventListener) { i::FLAG_turbo_inlining = false; // Make sure g is not inlined into f. DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetMessageHandler(env->GetIsolate(), DebugBreakMessageHandler); + v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugBreakEventListener); v8::Local<v8::Context> context = env.context(); // Test functions. @@ -6378,10 +5165,10 @@ TEST(DebugBreakInMessageHandler) { // Call f then g. The debugger statement in f will cause a break which will // cause another break. f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(2, message_handler_break_hit_count); + CHECK_EQ(2, event_listener_break_hit_count); // Calling g will not cause any additional breaks. g->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(2, message_handler_break_hit_count); + CHECK_EQ(2, event_listener_break_hit_count); } @@ -6458,18 +5245,21 @@ TEST(RegExpDebugBreak) { } #endif // V8_INTERPRETED_REGEXP +// Test which creates a context and sets embedder data on it. Checks that this +// data is set correctly and that when the debug event listener is called for +// break event in an eval statement the expected context is the one returned by +// Message.GetEventContext. +TEST(EvalContextData) { + v8::HandleScope scope(CcTest::isolate()); -// Common part of EvalContextData and NestedBreakEventContextData tests. -static void ExecuteScriptForContextCheck( - v8::Debug::MessageHandler message_handler) { - // Create a context. v8::Local<v8::Context> context_1; v8::Local<v8::ObjectTemplate> global_template = v8::Local<v8::ObjectTemplate>(); context_1 = v8::Context::New(CcTest::isolate(), NULL, global_template); - v8::Debug::SetMessageHandler(CcTest::isolate(), message_handler); + v8::Debug::SetDebugEventListener(CcTest::isolate(), + ContextCheckEventListener); // Default data value is undefined. CHECK(context_1->GetEmbedderData(0)->IsUndefined()); @@ -6491,124 +5281,42 @@ static void ExecuteScriptForContextCheck( f->Call(context_1, context_1->Global(), 0, NULL).ToLocalChecked(); } - v8::Debug::SetMessageHandler(CcTest::isolate(), nullptr); -} - - -// Test which creates a context and sets embedder data on it. Checks that this -// data is set correctly and that when the debug message handler is called for -// break event in an eval statement the expected context is the one returned by -// Message.GetEventContext. -TEST(EvalContextData) { - v8::HandleScope scope(CcTest::isolate()); - - ExecuteScriptForContextCheck(ContextCheckMessageHandler); + v8::Debug::SetDebugEventListener(CcTest::isolate(), nullptr); // One time compile event and one time break event. - CHECK_GT(message_handler_hit_count, 2); - CheckDebuggerUnloaded(CcTest::isolate()); -} - - -static bool sent_eval = false; -static int break_count = 0; -static int continue_command_send_count = 0; -// Check that the expected context is the one generating the debug event -// including the case of nested break event. -static void DebugEvalContextCheckMessageHandler( - const v8::Debug::Message& message) { - CHECK(message.GetEventContext() == expected_context); - CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals( - expected_context_data)); - message_handler_hit_count++; - - static char print_buffer[1000]; - v8::String::Value json(message.GetJSON()); - Utf16ToAscii(*json, json.length(), print_buffer); - - v8::Isolate* isolate = message.GetIsolate(); - if (IsBreakEventMessage(print_buffer)) { - break_count++; - if (!sent_eval) { - sent_eval = true; - - const int kBufferSize = 1000; - uint16_t buffer[kBufferSize]; - const char* eval_command = - "{\"seq\":0," - "\"type\":\"request\"," - "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"debugger;\"," - "\"global\":true,\"disable_break\":false}}"; - - // Send evaluate command. - v8::Debug::SendCommand( - isolate, buffer, AsciiToUtf16(eval_command, buffer)); - return; - } else { - // It's a break event caused by the evaluation request above. - SendContinueCommand(); - continue_command_send_count++; - } - } else if (IsEvaluateResponseMessage(print_buffer) && - continue_command_send_count < 2) { - // Response to the evaluation request. We're still on the breakpoint so - // send continue. - SendContinueCommand(); - continue_command_send_count++; - } -} - - -// Tests that context returned for break event is correct when the event occurs -// in 'evaluate' debugger request. -TEST(NestedBreakEventContextData) { - v8::HandleScope scope(CcTest::isolate()); - break_count = 0; - message_handler_hit_count = 0; - - ExecuteScriptForContextCheck(DebugEvalContextCheckMessageHandler); - - // One time compile event and two times break event. - CHECK_GT(message_handler_hit_count, 3); - - // One break from the source and another from the evaluate request. - CHECK_EQ(break_count, 2); + CHECK_GT(event_listener_hit_count, 2); CheckDebuggerUnloaded(CcTest::isolate()); } // Debug event listener which counts the after compile events. -int after_compile_message_count = 0; -static void AfterCompileMessageHandler(const v8::Debug::Message& message) { +int after_compile_event_count = 0; +static void AfterCompileEventListener(const v8::Debug::EventDetails& details) { // Count the number of scripts collected. - if (message.IsEvent()) { - if (message.GetEvent() == v8::AfterCompile) { - after_compile_message_count++; - } else if (message.GetEvent() == v8::Break) { - SendContinueCommand(); - } + if (details.GetEvent() == v8::AfterCompile) { + after_compile_event_count++; } } // Tests that after compile event is sent as many times as there are scripts // compiled. -TEST(AfterCompileMessageWhenMessageHandlerIsReset) { +TEST(AfterCompileEventWhenEventListenerIsReset) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Local<v8::Context> context = env.context(); - after_compile_message_count = 0; const char* script = "var a=1"; - v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); + v8::Debug::SetDebugEventListener(env->GetIsolate(), + AfterCompileEventListener); v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) .ToLocalChecked() ->Run(context) .ToLocalChecked(); - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); + v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); - v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); + v8::Debug::SetDebugEventListener(env->GetIsolate(), + AfterCompileEventListener); v8::Debug::DebugBreak(env->GetIsolate()); v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) .ToLocalChecked() @@ -6616,11 +5324,11 @@ TEST(AfterCompileMessageWhenMessageHandlerIsReset) { .ToLocalChecked(); // Setting listener to NULL should cause debugger unload. - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); + v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); CheckDebuggerUnloaded(env->GetIsolate()); // Compilation cache should be disabled when debugger is active. - CHECK_EQ(2, after_compile_message_count); + CHECK_EQ(2, after_compile_event_count); } @@ -6643,7 +5351,7 @@ static void CompileErrorEventCounter( // Tests that syntax error event is sent as many times as there are scripts // with syntax error compiled. -TEST(SyntaxErrorMessageOnSyntaxException) { +TEST(SyntaxErrorEventOnSyntaxException) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -6685,23 +5393,23 @@ TEST(SyntaxErrorMessageOnSyntaxException) { CHECK_EQ(3, compile_error_event_count); } - -// Tests that break event is sent when message handler is reset. -TEST(BreakMessageWhenMessageHandlerIsReset) { +// Tests that break event is sent when event listener is reset. +TEST(BreakEventWhenEventListenerIsReset) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Local<v8::Context> context = env.context(); - after_compile_message_count = 0; const char* script = "function f() {};"; - v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); + v8::Debug::SetDebugEventListener(env->GetIsolate(), + AfterCompileEventListener); v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) .ToLocalChecked() ->Run(context) .ToLocalChecked(); - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); + v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); - v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); + v8::Debug::SetDebugEventListener(env->GetIsolate(), + AfterCompileEventListener); v8::Debug::DebugBreak(env->GetIsolate()); v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( env->Global() @@ -6709,26 +5417,22 @@ TEST(BreakMessageWhenMessageHandlerIsReset) { .ToLocalChecked()); f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - // Setting message handler to NULL should cause debugger unload. - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); + // Setting event listener to NULL should cause debugger unload. + v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); CheckDebuggerUnloaded(env->GetIsolate()); // Compilation cache should be disabled when debugger is active. - CHECK_EQ(1, after_compile_message_count); + CHECK_EQ(1, after_compile_event_count); } static int exception_event_count = 0; -static void ExceptionMessageHandler(const v8::Debug::Message& message) { - if (message.IsEvent() && message.GetEvent() == v8::Exception) { - exception_event_count++; - SendContinueCommand(); - } +static void ExceptionEventListener(const v8::Debug::EventDetails& details) { + if (details.GetEvent() == v8::Exception) exception_event_count++; } - -// Tests that exception event is sent when message handler is reset. -TEST(ExceptionMessageWhenMessageHandlerIsReset) { +// Tests that exception event is sent when event listener is reset. +TEST(ExceptionEventWhenEventListenerIsReset) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -6739,22 +5443,23 @@ TEST(ExceptionMessageWhenMessageHandlerIsReset) { exception_event_count = 0; const char* script = "function f() {throw new Error()};"; - v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); + v8::Debug::SetDebugEventListener(env->GetIsolate(), + AfterCompileEventListener); v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) .ToLocalChecked() ->Run(context) .ToLocalChecked(); - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); + v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); - v8::Debug::SetMessageHandler(env->GetIsolate(), ExceptionMessageHandler); + v8::Debug::SetDebugEventListener(env->GetIsolate(), ExceptionEventListener); v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( env->Global() ->Get(context, v8_str(env->GetIsolate(), "f")) .ToLocalChecked()); CHECK(f->Call(context, env->Global(), 0, NULL).IsEmpty()); - // Setting message handler to NULL should cause debugger unload. - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); + // Setting event listener to NULL should cause debugger unload. + v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); CheckDebuggerUnloaded(env->GetIsolate()); CHECK_EQ(1, exception_event_count); @@ -6770,7 +5475,8 @@ TEST(ProvisionalBreakpointOnLineOutOfRange) { const char* script = "function f() {};"; const char* resource_name = "test_resource"; - v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); + v8::Debug::SetDebugEventListener(env->GetIsolate(), + AfterCompileEventListener); v8::Local<v8::Context> context = env.context(); // Set a couple of provisional breakpoint on lines out of the script lines @@ -6780,7 +5486,7 @@ TEST(ProvisionalBreakpointOnLineOutOfRange) { int sbp2 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5); - after_compile_message_count = 0; + after_compile_event_count = 0; v8::ScriptOrigin origin(v8_str(env->GetIsolate(), resource_name), v8::Integer::New(env->GetIsolate(), 10), @@ -6795,46 +5501,28 @@ TEST(ProvisionalBreakpointOnLineOutOfRange) { // If the script is compiled successfully there is exactly one after compile // event. In case of an exception in debugger code after compile event is not // sent. - CHECK_EQ(1, after_compile_message_count); + CHECK_EQ(1, after_compile_event_count); ClearBreakPointFromJS(env->GetIsolate(), sbp1); ClearBreakPointFromJS(env->GetIsolate(), sbp2); - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); + v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); + CheckDebuggerUnloaded(env->GetIsolate()); } - -static void BreakMessageHandler(const v8::Debug::Message& message) { - i::Isolate* isolate = CcTest::i_isolate(); - if (message.IsEvent() && message.GetEvent() == v8::Break) { - // Count the number of breaks. - break_point_hit_count++; - - i::HandleScope scope(isolate); - message.GetJSON(); - - SendContinueCommand(); - } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) { - i::HandleScope scope(isolate); - - int current_count = break_point_hit_count; - - // Force serialization to trigger some internal JS execution. - message.GetJSON(); - - CHECK_EQ(current_count, break_point_hit_count); - } +static void BreakEventListener(const v8::Debug::EventDetails& details) { + if (details.GetEvent() == v8::Break) break_point_hit_count++; } // Test that if DebugBreak is forced it is ignored when code from // debug-delay.js is executed. -TEST(NoDebugBreakInAfterCompileMessageHandler) { +TEST(NoDebugBreakInAfterCompileEventListener) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::Local<v8::Context> context = env.context(); // Register a debug event listener which sets the break flag and counts. - v8::Debug::SetMessageHandler(env->GetIsolate(), BreakMessageHandler); + v8::Debug::SetDebugEventListener(env->GetIsolate(), BreakEventListener); // Set the debug break flag. v8::Debug::DebugBreak(env->GetIsolate()); @@ -6852,237 +5540,12 @@ TEST(NoDebugBreakInAfterCompileMessageHandler) { // There should be one more break event when the script is evaluated in 'f'. CHECK_EQ(2, break_point_hit_count); - // Get rid of the debug message handler. - v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); + // Get rid of the debug event listener. + v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); CheckDebuggerUnloaded(env->GetIsolate()); } -static int counting_message_handler_counter; - -static void CountingMessageHandler(const v8::Debug::Message& message) { - if (message.IsResponse()) counting_message_handler_counter++; -} - - -// Test that debug messages get processed when ProcessDebugMessages is called. -TEST(ProcessDebugMessages) { - DebugLocalContext env; - v8::Isolate* isolate = env->GetIsolate(); - v8::HandleScope scope(isolate); - - counting_message_handler_counter = 0; - - v8::Debug::SetMessageHandler(isolate, CountingMessageHandler); - - const int kBufferSize = 1000; - uint16_t buffer[kBufferSize]; - const char* scripts_command = - "{\"seq\":0," - "\"type\":\"request\"," - "\"command\":\"scripts\"}"; - - // Send scripts command. - v8::Debug::SendCommand( - isolate, buffer, AsciiToUtf16(scripts_command, buffer)); - - CHECK_EQ(0, counting_message_handler_counter); - v8::Debug::ProcessDebugMessages(isolate); - // At least one message should come - CHECK_GE(counting_message_handler_counter, 1); - - counting_message_handler_counter = 0; - - v8::Debug::SendCommand( - isolate, buffer, AsciiToUtf16(scripts_command, buffer)); - v8::Debug::SendCommand( - isolate, buffer, AsciiToUtf16(scripts_command, buffer)); - CHECK_EQ(0, counting_message_handler_counter); - v8::Debug::ProcessDebugMessages(isolate); - // At least two messages should come - CHECK_GE(counting_message_handler_counter, 2); - - // Get rid of the debug message handler. - v8::Debug::SetMessageHandler(isolate, nullptr); - CheckDebuggerUnloaded(isolate); -} - - -class SendCommandThread; -static SendCommandThread* send_command_thread_ = NULL; - - -class SendCommandThread : public v8::base::Thread { - public: - explicit SendCommandThread(v8::Isolate* isolate) - : Thread(Options("SendCommandThread")), - semaphore_(0), - isolate_(isolate) {} - - static void CountingAndSignallingMessageHandler( - const v8::Debug::Message& message) { - if (message.IsResponse()) { - counting_message_handler_counter++; - send_command_thread_->semaphore_.Signal(); - } - } - - virtual void Run() { - semaphore_.Wait(); - const int kBufferSize = 1000; - uint16_t buffer[kBufferSize]; - const char* scripts_command = - "{\"seq\":0," - "\"type\":\"request\"," - "\"command\":\"scripts\"}"; - int length = AsciiToUtf16(scripts_command, buffer); - // Send scripts command. - - for (int i = 0; i < 20; i++) { - v8::base::ElapsedTimer timer; - timer.Start(); - CHECK_EQ(i, counting_message_handler_counter); - // Queue debug message. - v8::Debug::SendCommand(isolate_, buffer, length); - // Wait for the message handler to pick up the response. - semaphore_.Wait(); - i::PrintF("iteration %d took %f ms\n", i, - timer.Elapsed().InMillisecondsF()); - } - - isolate_->TerminateExecution(); - } - - void StartSending() { semaphore_.Signal(); } - - private: - v8::base::Semaphore semaphore_; - v8::Isolate* isolate_; -}; - - -static void StartSendingCommands( - const v8::FunctionCallbackInfo<v8::Value>& info) { - send_command_thread_->StartSending(); -} - - -TEST(ProcessDebugMessagesThreaded) { - DebugLocalContext env; - v8::Isolate* isolate = env->GetIsolate(); - v8::HandleScope scope(isolate); - v8::Local<v8::Context> context = env.context(); - - counting_message_handler_counter = 0; - - v8::Debug::SetMessageHandler( - isolate, SendCommandThread::CountingAndSignallingMessageHandler); - send_command_thread_ = new SendCommandThread(isolate); - send_command_thread_->Start(); - - v8::Local<v8::FunctionTemplate> start = - v8::FunctionTemplate::New(isolate, StartSendingCommands); - CHECK(env->Global() - ->Set(context, v8_str("start"), - start->GetFunction(context).ToLocalChecked()) - .FromJust()); - - CompileRun("start(); while (true) { }"); - - CHECK_EQ(20, counting_message_handler_counter); - - v8::Debug::SetMessageHandler(isolate, nullptr); - CheckDebuggerUnloaded(isolate); -} - - -struct BacktraceData { - static int frame_counter; - static void MessageHandler(const v8::Debug::Message& message) { - char print_buffer[1000]; - v8::String::Value json(message.GetJSON()); - Utf16ToAscii(*json, json.length(), print_buffer, 1000); - - if (strstr(print_buffer, "backtrace") == NULL) { - return; - } - frame_counter = GetTotalFramesInt(print_buffer); - } -}; - -int BacktraceData::frame_counter; - - -// Test that debug messages get processed when ProcessDebugMessages is called. -TEST(Backtrace) { - DebugLocalContext env; - v8::Isolate* isolate = env->GetIsolate(); - v8::HandleScope scope(isolate); - v8::Local<v8::Context> context = env.context(); - - v8::Debug::SetMessageHandler(isolate, BacktraceData::MessageHandler); - - const int kBufferSize = 1000; - uint16_t buffer[kBufferSize]; - const char* scripts_command = - "{\"seq\":0," - "\"type\":\"request\"," - "\"command\":\"backtrace\"}"; - - // Check backtrace from ProcessDebugMessages. - BacktraceData::frame_counter = -10; - v8::Debug::SendCommand( - isolate, - buffer, - AsciiToUtf16(scripts_command, buffer), - NULL); - v8::Debug::ProcessDebugMessages(isolate); - CHECK_EQ(BacktraceData::frame_counter, 0); - - v8::Local<v8::String> void0 = v8_str(env->GetIsolate(), "void(0)"); - v8::Local<v8::Script> script = CompileWithOrigin(void0, void0); - - // Check backtrace from "void(0)" script. - BacktraceData::frame_counter = -10; - v8::Debug::SendCommand( - isolate, - buffer, - AsciiToUtf16(scripts_command, buffer), - NULL); - script->Run(context).ToLocalChecked(); - CHECK_EQ(BacktraceData::frame_counter, 1); - - // Get rid of the debug message handler. - v8::Debug::SetMessageHandler(isolate, nullptr); - CheckDebuggerUnloaded(isolate); -} - - -TEST(GetMirror) { - DebugLocalContext env; - v8::Isolate* isolate = env->GetIsolate(); - v8::HandleScope scope(isolate); - v8::Local<v8::Context> context = env.context(); - v8::Local<v8::Value> obj = - v8::Debug::GetMirror(context, v8_str(isolate, "hodja")).ToLocalChecked(); - v8::ScriptCompiler::Source source(v8_str( - "function runTest(mirror) {" - " return mirror.isString() && (mirror.length() == 5);" - "}" - "" - "runTest;")); - v8::Local<v8::Function> run_test = v8::Local<v8::Function>::Cast( - v8::ScriptCompiler::CompileUnboundScript(isolate, &source) - .ToLocalChecked() - ->BindToCurrentContext() - ->Run(context) - .ToLocalChecked()); - v8::Local<v8::Value> result = - run_test->Call(context, env->Global(), 1, &obj).ToLocalChecked(); - CHECK(result->IsTrue()); -} - - // Test that the debug break flag works with function.apply. TEST(DebugBreakFunctionApply) { DebugLocalContext env; @@ -7200,62 +5663,6 @@ TEST(CallingContextIsNotDebugContext) { } -TEST(DebugContextIsPreservedBetweenAccesses) { - v8::HandleScope scope(CcTest::isolate()); - v8::Debug::SetDebugEventListener(CcTest::isolate(), - DebugEventBreakPointHitCount); - v8::Local<v8::Context> context1 = - v8::Debug::GetDebugContext(CcTest::isolate()); - v8::Local<v8::Context> context2 = - v8::Debug::GetDebugContext(CcTest::isolate()); - CHECK(v8::Utils::OpenHandle(*context1).is_identical_to( - v8::Utils::OpenHandle(*context2))); - v8::Debug::SetDebugEventListener(CcTest::isolate(), nullptr); -} - - -TEST(NoDebugContextWhenDebuggerDisabled) { - v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Context> context = - v8::Debug::GetDebugContext(CcTest::isolate()); - CHECK(context.IsEmpty()); -} - -static void DebugEventCheckContext( - const v8::Debug::EventDetails& event_details) { - if (event_details.GetEvent() == v8::Break) { - v8::Isolate* isolate = event_details.GetIsolate(); - CHECK(v8::Debug::GetDebuggedContext(isolate) - .ToLocalChecked() - ->Global() - ->Equals(isolate->GetCurrentContext(), - event_details.GetEventContext()->Global()) - .FromJust()); - } -} - -static void CheckContext(const v8::FunctionCallbackInfo<v8::Value>& args) { - CHECK(v8::Debug::GetDebuggedContext(args.GetIsolate()).IsEmpty()); -} - -TEST(DebuggedContext) { - DebugLocalContext env; - v8::Isolate* isolate = env->GetIsolate(); - - v8::Debug::SetDebugEventListener(isolate, DebugEventCheckContext); - - v8::Local<v8::Function> foo = - CompileFunction(&env, "function foo(){bar=0;}", "foo"); - - SetBreakPoint(foo, 0); - foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked(); - - v8::Local<v8::Function> fun = v8::FunctionTemplate::New(isolate, CheckContext) - ->GetFunction(env.context()) - .ToLocalChecked(); - fun->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked(); -} - static v8::Local<v8::Value> expected_callback_data; static void DebugEventContextChecker(const v8::Debug::EventDetails& details) { CHECK(details.GetEventContext() == expected_context); @@ -8237,3 +6644,31 @@ TEST(DebugStepOverFunctionWithCaughtException) { v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); CHECK_EQ(break_point_hit_count, 4); } + +bool out_of_memory_callback_called = false; +void OutOfMemoryCallback(void* data) { + out_of_memory_callback_called = true; + reinterpret_cast<v8::Isolate*>(data)->IncreaseHeapLimitForDebugging(); +} + +UNINITIALIZED_TEST(DebugSetOutOfMemoryListener) { + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + create_params.constraints.set_max_old_space_size(10); + v8::Isolate* isolate = v8::Isolate::New(create_params); + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + { + v8::Isolate::Scope i_scope(isolate); + v8::HandleScope scope(isolate); + LocalContext context(isolate); + v8::debug::SetOutOfMemoryCallback(isolate, OutOfMemoryCallback, + reinterpret_cast<void*>(isolate)); + CHECK(!out_of_memory_callback_called); + // The following allocation fails unless the out-of-memory callback + // increases the heap limit. + int length = 10 * i::MB / i::kPointerSize; + i_isolate->factory()->NewFixedArray(length, i::TENURED); + CHECK(out_of_memory_callback_called); + } + isolate->Dispose(); +} |