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(); |