Chromium Code Reviews| Index: test/cctest/test-debug.cc |
| diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc |
| index 3b43d9d11fb73ba89905a394d277db285d5ec1b4..20570da5668850683a77d65a91e0fd3875de477d 100644 |
| --- a/test/cctest/test-debug.cc |
| +++ b/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 |
| @@ -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); |
| } |
| @@ -2492,171 +2480,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; |
| @@ -4942,787 +4765,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 +4977,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 +5016,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 +5200,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 +5225,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 +5262,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, 4); |
| - 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 +5304,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 +5384,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 +5420,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 +5463,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 +5490,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 +5532,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; |
|
jgruber
2016/11/24 09:53:08
Why does this test work if after_compile_event_cou
Yang
2016/11/24 09:56:17
cctests are supposed to be called one by one, to p
|
| 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 +5556,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 +5582,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 +5614,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 +5625,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 +5640,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,212 +5679,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(); |