From 33fba3bfa1b3b104051e69d14142cdff0ac0ccac Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Wed, 14 May 2014 16:28:46 +0000 Subject: [PATCH] Remove DebuggerAgent. R=svenpanne@chromium.org Review URL: https://codereview.chromium.org/279423004 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21315 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8-debug.h | 34 ---- samples/lineprocessor.cc | 41 ---- src/api.cc | 24 +-- src/d8-debug.cc | 215 --------------------- src/d8-debug.h | 113 ----------- src/d8-readline.cc | 2 +- src/d8.cc | 31 +-- src/d8.h | 1 - src/debug-agent.cc | 481 ---------------------------------------------- src/debug-agent.h | 93 --------- src/debug.cc | 121 +----------- src/debug.h | 55 +----- src/execution.cc | 3 + src/flag-definitions.h | 4 - src/isolate.h | 2 - test/cctest/test-debug.cc | 315 ++++++++---------------------- tools/gyp/v8.gyp | 2 - 17 files changed, 92 insertions(+), 1445 deletions(-) delete mode 100644 src/debug-agent.cc delete mode 100644 src/debug-agent.h diff --git a/include/v8-debug.h b/include/v8-debug.h index 980d4b9..aea5684 100644 --- a/include/v8-debug.h +++ b/include/v8-debug.h @@ -201,20 +201,6 @@ class V8_EXPORT Debug { const uint16_t* command, int length, ClientData* client_data = NULL); - /** - * Register a callback function to be called when a debug message has been - * received and is ready to be processed. For the debug messages to be - * processed V8 needs to be entered, and in certain embedding scenarios this - * callback can be used to make sure V8 is entered for the debug message to - * be processed. Note that debug messages will only be processed if there is - * a V8 break. This can happen automatically by using the option - * --debugger-auto-break. - * \param provide_locker requires that V8 acquires v8::Locker for you before - * calling handler - */ - static void SetDebugMessageDispatchHandler( - DebugMessageDispatchHandler handler, bool provide_locker = false); - /** * Run a JavaScript function in the debugger. * \param fun the function to call @@ -241,22 +227,6 @@ class V8_EXPORT Debug { */ static Local GetMirror(v8::Handle obj); - /** - * Enable the V8 builtin debug agent. The debugger agent will listen on the - * supplied TCP/IP port for remote debugger connection. - * \param name the name of the embedding application - * \param port the TCP/IP port to listen on - * \param wait_for_connection whether V8 should pause on a first statement - * allowing remote debugger to connect before anything interesting happened - */ - static bool EnableAgent(const char* name, int port, - bool wait_for_connection = false); - - /** - * Disable the V8 builtin debug agent. The TCP/IP connection will be closed. - */ - static void DisableAgent(); - /** * Makes V8 process all pending debug messages. * @@ -275,10 +245,6 @@ class V8_EXPORT Debug { * until V8 gets control again; however, embedding application may improve * this by manually calling this method. * - * It makes sense to call this method whenever a new debug message arrived and - * V8 is not already running. Method v8::Debug::SetDebugMessageDispatchHandler - * should help with the former condition. - * * Technically this method in many senses is equivalent to executing empty * script: * 1. It does nothing except for processing all pending debug messages. diff --git a/samples/lineprocessor.cc b/samples/lineprocessor.cc index 7e820b3..6f8fd35 100644 --- a/samples/lineprocessor.cc +++ b/samples/lineprocessor.cc @@ -109,28 +109,6 @@ bool RunCppCycle(v8::Handle script, v8::Persistent debug_message_context; -void DispatchDebugMessages() { - // We are in some random thread. We should already have v8::Locker acquired - // (we requested this when registered this callback). We was called - // because new debug messages arrived; they may have already been processed, - // but we shouldn't worry about this. - // - // All we have to do is to set context and call ProcessDebugMessages. - // - // We should decide which V8 context to use here. This is important for - // "evaluate" command, because it must be executed some context. - // In our sample we have only one context, so there is nothing really to - // think about. - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::HandleScope handle_scope(isolate); - v8::Local context = - v8::Local::New(isolate, debug_message_context); - v8::Context::Scope scope(context); - - v8::Debug::ProcessDebugMessages(); -} - - int RunMain(int argc, char* argv[]) { v8::V8::SetFlagsFromCommandLine(&argc, argv, true); v8::Isolate* isolate = v8::Isolate::New(); @@ -142,10 +120,6 @@ int RunMain(int argc, char* argv[]) { v8::Handle script_name; int script_param_counter = 0; - int port_number = -1; - bool wait_for_connection = false; - bool support_callback = false; - MainCycleType cycle_type = CycleInCpp; for (int i = 1; i < argc; i++) { @@ -158,13 +132,6 @@ int RunMain(int argc, char* argv[]) { cycle_type = CycleInCpp; } else if (strcmp(str, "--main-cycle-in-js") == 0) { cycle_type = CycleInJs; - } else if (strcmp(str, "--callback") == 0) { - support_callback = true; - } else if (strcmp(str, "--wait-for-connection") == 0) { - wait_for_connection = true; - } else if (strcmp(str, "-p") == 0 && i + 1 < argc) { - port_number = atoi(argv[i + 1]); // NOLINT - i++; } else if (strncmp(str, "--", 2) == 0) { printf("Warning: unknown flag %s.\nTry --help for options\n", str); } else if (strcmp(str, "-e") == 0 && i + 1 < argc) { @@ -214,14 +181,6 @@ int RunMain(int argc, char* argv[]) { debug_message_context.Reset(isolate, context); - if (support_callback) { - v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true); - } - - if (port_number != -1) { - v8::Debug::EnableAgent("lineprocessor", port_number, wait_for_connection); - } - bool report_exceptions = true; v8::Handle script; diff --git a/src/api.cc b/src/api.cc index 68d80d8..b559015 100644 --- a/src/api.cc +++ b/src/api.cc @@ -6824,22 +6824,11 @@ void Debug::SendCommand(Isolate* isolate, int length, ClientData* client_data) { i::Isolate* internal_isolate = reinterpret_cast(isolate); - internal_isolate->debugger()->ProcessCommand( + internal_isolate->debugger()->EnqueueCommandMessage( i::Vector(command, length), client_data); } -void Debug::SetDebugMessageDispatchHandler( - DebugMessageDispatchHandler handler, bool provide_locker) { - i::Isolate* isolate = i::Isolate::Current(); - EnsureInitializedForIsolate(isolate, - "v8::Debug::SetDebugMessageDispatchHandler"); - ENTER_V8(isolate); - isolate->debugger()->SetDebugMessageDispatchHandler( - handler, provide_locker); -} - - Local Debug::Call(v8::Handle fun, v8::Handle data) { i::Isolate* isolate = i::Isolate::Current(); @@ -6891,17 +6880,6 @@ Local Debug::GetMirror(v8::Handle obj) { } -bool Debug::EnableAgent(const char* name, int port, bool wait_for_connection) { - return i::Isolate::Current()->debugger()->StartAgent(name, port, - wait_for_connection); -} - - -void Debug::DisableAgent() { - return i::Isolate::Current()->debugger()->StopAgent(); -} - - void Debug::ProcessDebugMessages() { i::Execution::ProcessDebugMessages(i::Isolate::Current(), true); } diff --git a/src/d8-debug.cc b/src/d8-debug.cc index 7c1beaf..41ec670 100644 --- a/src/d8-debug.cc +++ b/src/d8-debug.cc @@ -4,27 +4,16 @@ #include "d8.h" #include "d8-debug.h" -#include "debug-agent.h" -#include "platform/socket.h" - namespace v8 { -static bool was_running = true; - void PrintPrompt(bool is_running) { const char* prompt = is_running? "> " : "dbg> "; - was_running = is_running; printf("%s", prompt); fflush(stdout); } -void PrintPrompt() { - PrintPrompt(was_running); -} - - void HandleDebugEvent(const Debug::EventDetails& event_details) { // TODO(svenpanne) There should be a way to retrieve this in the callback. Isolate* isolate = Isolate::GetCurrent(); @@ -140,208 +129,4 @@ void HandleDebugEvent(const Debug::EventDetails& event_details) { } } - -void RunRemoteDebugger(Isolate* isolate, int port) { - RemoteDebugger debugger(isolate, port); - debugger.Run(); -} - - -void RemoteDebugger::Run() { - bool ok; - - // Connect to the debugger agent. - conn_ = new i::Socket; - static const int kPortStrSize = 6; - char port_str[kPortStrSize]; - i::OS::SNPrintF(i::Vector(port_str, kPortStrSize), "%d", port_); - ok = conn_->Connect("localhost", port_str); - if (!ok) { - printf("Unable to connect to debug agent %d\n", i::Socket::GetLastError()); - return; - } - - // Start the receiver thread. - ReceiverThread receiver(this); - receiver.Start(); - - // Start the keyboard thread. - KeyboardThread keyboard(this); - keyboard.Start(); - PrintPrompt(); - - // Process events received from debugged VM and from the keyboard. - bool terminate = false; - while (!terminate) { - event_available_.Wait(); - RemoteDebuggerEvent* event = GetEvent(); - switch (event->type()) { - case RemoteDebuggerEvent::kMessage: - HandleMessageReceived(event->data()); - break; - case RemoteDebuggerEvent::kKeyboard: - HandleKeyboardCommand(event->data()); - break; - case RemoteDebuggerEvent::kDisconnect: - terminate = true; - break; - - default: - UNREACHABLE(); - } - delete event; - } - - delete conn_; - conn_ = NULL; - // Wait for the receiver thread to end. - receiver.Join(); -} - - -void RemoteDebugger::MessageReceived(i::SmartArrayPointer message) { - RemoteDebuggerEvent* event = - new RemoteDebuggerEvent(RemoteDebuggerEvent::kMessage, message); - AddEvent(event); -} - - -void RemoteDebugger::KeyboardCommand(i::SmartArrayPointer command) { - RemoteDebuggerEvent* event = - new RemoteDebuggerEvent(RemoteDebuggerEvent::kKeyboard, command); - AddEvent(event); -} - - -void RemoteDebugger::ConnectionClosed() { - RemoteDebuggerEvent* event = - new RemoteDebuggerEvent(RemoteDebuggerEvent::kDisconnect, - i::SmartArrayPointer()); - AddEvent(event); -} - - -void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) { - i::LockGuard lock_guard(&event_access_); - if (head_ == NULL) { - ASSERT(tail_ == NULL); - head_ = event; - tail_ = event; - } else { - ASSERT(tail_ != NULL); - tail_->set_next(event); - tail_ = event; - } - event_available_.Signal(); -} - - -RemoteDebuggerEvent* RemoteDebugger::GetEvent() { - i::LockGuard lock_guard(&event_access_); - ASSERT(head_ != NULL); - RemoteDebuggerEvent* result = head_; - head_ = head_->next(); - if (head_ == NULL) { - ASSERT(tail_ == result); - tail_ = NULL; - } - return result; -} - - -void RemoteDebugger::HandleMessageReceived(char* message) { - Locker lock(isolate_); - HandleScope scope(isolate_); - - // Print the event details. - TryCatch try_catch; - Handle details = Shell::DebugMessageDetails( - isolate_, Handle::Cast(String::NewFromUtf8(isolate_, message))); - if (try_catch.HasCaught()) { - Shell::ReportException(isolate_, &try_catch); - PrintPrompt(); - return; - } - String::Utf8Value str(details->Get(String::NewFromUtf8(isolate_, "text"))); - if (str.length() == 0) { - // Empty string is used to signal not to process this event. - return; - } - if (*str != NULL) { - printf("%s\n", *str); - } else { - printf("???\n"); - } - - bool is_running = details->Get(String::NewFromUtf8(isolate_, "running")) - ->ToBoolean() - ->Value(); - PrintPrompt(is_running); -} - - -void RemoteDebugger::HandleKeyboardCommand(char* command) { - Locker lock(isolate_); - HandleScope scope(isolate_); - - // Convert the debugger command to a JSON debugger request. - TryCatch try_catch; - Handle request = Shell::DebugCommandToJSONRequest( - isolate_, String::NewFromUtf8(isolate_, command)); - if (try_catch.HasCaught()) { - Shell::ReportException(isolate_, &try_catch); - PrintPrompt(); - return; - } - - // If undefined is returned the command was handled internally and there is - // no JSON to send. - if (request->IsUndefined()) { - PrintPrompt(); - return; - } - - // Send the JSON debugger request. - i::DebuggerAgentUtil::SendMessage(conn_, Handle::Cast(request)); -} - - -void ReceiverThread::Run() { - // Receive the connect message (with empty body). - i::SmartArrayPointer message = - i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn()); - ASSERT(message.get() == NULL); - - while (true) { - // Receive a message. - i::SmartArrayPointer message = - i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn()); - if (message.get() == NULL) { - remote_debugger_->ConnectionClosed(); - return; - } - - // Pass the message to the main thread. - remote_debugger_->MessageReceived(message); - } -} - - -void KeyboardThread::Run() { - static const int kBufferSize = 256; - while (true) { - // read keyboard input. - char command[kBufferSize]; - char* str = fgets(command, kBufferSize, stdin); - if (str == NULL) { - break; - } - - // Pass the keyboard command to the main thread. - remote_debugger_->KeyboardCommand( - i::SmartArrayPointer(i::StrDup(command))); - } -} - - } // namespace v8 diff --git a/src/d8-debug.h b/src/d8-debug.h index c211be7..ab274e9 100644 --- a/src/d8-debug.h +++ b/src/d8-debug.h @@ -8,125 +8,12 @@ #include "d8.h" #include "debug.h" -#include "platform/socket.h" namespace v8 { - void HandleDebugEvent(const Debug::EventDetails& event_details); -// Start the remove debugger connecting to a V8 debugger agent on the specified -// port. -void RunRemoteDebugger(Isolate* isolate, int port); - -// Forward declerations. -class RemoteDebuggerEvent; -class ReceiverThread; - - -// Remote debugging class. -class RemoteDebugger { - public: - explicit RemoteDebugger(Isolate* isolate, int port) - : isolate_(isolate), - port_(port), - event_available_(0), - head_(NULL), tail_(NULL) {} - void Run(); - - // Handle events from the subordinate threads. - void MessageReceived(i::SmartArrayPointer message); - void KeyboardCommand(i::SmartArrayPointer command); - void ConnectionClosed(); - - private: - // Add new debugger event to the list. - void AddEvent(RemoteDebuggerEvent* event); - // Read next debugger event from the list. - RemoteDebuggerEvent* GetEvent(); - - // Handle a message from the debugged V8. - void HandleMessageReceived(char* message); - // Handle a keyboard command. - void HandleKeyboardCommand(char* command); - - // Get connection to agent in debugged V8. - i::Socket* conn() { return conn_; } - - Isolate* isolate_; - int port_; // Port used to connect to debugger V8. - i::Socket* conn_; // Connection to debugger agent in debugged V8. - - // Linked list of events from debugged V8 and from keyboard input. Access to - // the list is guarded by a mutex and a semaphore signals new items in the - // list. - i::Mutex event_access_; - i::Semaphore event_available_; - RemoteDebuggerEvent* head_; - RemoteDebuggerEvent* tail_; - - friend class ReceiverThread; -}; - - -// Thread reading from debugged V8 instance. -class ReceiverThread: public i::Thread { - public: - explicit ReceiverThread(RemoteDebugger* remote_debugger) - : Thread("d8:ReceiverThrd"), - remote_debugger_(remote_debugger) {} - ~ReceiverThread() {} - - void Run(); - - private: - RemoteDebugger* remote_debugger_; -}; - - -// Thread reading keyboard input. -class KeyboardThread: public i::Thread { - public: - explicit KeyboardThread(RemoteDebugger* remote_debugger) - : Thread("d8:KeyboardThrd"), - remote_debugger_(remote_debugger) {} - ~KeyboardThread() {} - - void Run(); - - private: - RemoteDebugger* remote_debugger_; -}; - - -// Events processed by the main deubgger thread. -class RemoteDebuggerEvent { - public: - RemoteDebuggerEvent(int type, i::SmartArrayPointer data) - : type_(type), data_(data), next_(NULL) { - ASSERT(type == kMessage || type == kKeyboard || type == kDisconnect); - } - - static const int kMessage = 1; - static const int kKeyboard = 2; - static const int kDisconnect = 3; - - int type() { return type_; } - char* data() { return data_.get(); } - - private: - void set_next(RemoteDebuggerEvent* event) { next_ = event; } - RemoteDebuggerEvent* next() { return next_; } - - int type_; - i::SmartArrayPointer data_; - RemoteDebuggerEvent* next_; - - friend class RemoteDebugger; -}; - - } // namespace v8 diff --git a/src/d8-readline.cc b/src/d8-readline.cc index cb59f6e..225c6f0 100644 --- a/src/d8-readline.cc +++ b/src/d8-readline.cc @@ -83,7 +83,7 @@ bool ReadLineEditor::Close() { Handle ReadLineEditor::Prompt(const char* prompt) { char* result = NULL; { // Release lock for blocking input. - Unlocker unlock(Isolate::GetCurrent()); + Unlocker unlock(isolate_); result = readline(prompt); } if (result == NULL) return Handle(); diff --git a/src/d8.cc b/src/d8.cc index bbc121e..8ea77fd 100644 --- a/src/d8.cc +++ b/src/d8.cc @@ -638,16 +638,6 @@ Local Shell::DebugCommandToJSONRequest(Isolate* isolate, } -void Shell::DispatchDebugMessages() { - Isolate* isolate = v8::Isolate::GetCurrent(); - HandleScope handle_scope(isolate); - v8::Local context = - v8::Local::New(isolate, Shell::evaluation_context_); - v8::Context::Scope context_scope(context); - v8::Debug::ProcessDebugMessages(); -} - - int32_t* Counter::Bind(const char* name, bool is_histogram) { int i; for (i = 0; i < kMaxNameSize - 1 && name[i]; i++) @@ -796,9 +786,7 @@ void Shell::InstallUtilityScript(Isolate* isolate) { script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE)); // Start the in-process debugger if requested. - if (i::FLAG_debugger && !i::FLAG_debugger_agent) { - v8::Debug::SetDebugEventListener(HandleDebugEvent); - } + if (i::FLAG_debugger) v8::Debug::SetDebugEventListener(HandleDebugEvent); } #endif // !V8_SHARED @@ -920,12 +908,6 @@ void Shell::InitializeDebugger(Isolate* isolate) { Handle global_template = CreateGlobalTemplate(isolate); utility_context_.Reset(isolate, Context::New(isolate, NULL, global_template)); - - // Start the debugger agent if requested. - if (i::FLAG_debugger_agent) { - v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true); - v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true); - } #endif // !V8_SHARED } @@ -1552,19 +1534,8 @@ int Shell::Main(int argc, char* argv[]) { result = RunMain(isolate, argc, argv); } - -#ifndef V8_SHARED - // Run remote debugger if requested, but never on --test - if (i::FLAG_remote_debugger && !options.test_shell) { - InstallUtilityScript(isolate); - RunRemoteDebugger(isolate, i::FLAG_debugger_port); - return 0; - } -#endif // !V8_SHARED - // Run interactive shell if explicitly requested or if no script has been // executed, but never on --test - if (( options.interactive_shell || !options.script_executed ) && !options.test_shell ) { #ifndef V8_SHARED diff --git a/src/d8.h b/src/d8.h index 75d007f..014bda0 100644 --- a/src/d8.h +++ b/src/d8.h @@ -265,7 +265,6 @@ class Shell : public i::AllStatic { Handle message); static Local DebugCommandToJSONRequest(Isolate* isolate, Handle command); - static void DispatchDebugMessages(); static void PerformanceNow(const v8::FunctionCallbackInfo& args); #endif // !V8_SHARED diff --git a/src/debug-agent.cc b/src/debug-agent.cc deleted file mode 100644 index 94f334b..0000000 --- a/src/debug-agent.cc +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "v8.h" -#include "debug.h" -#include "debug-agent.h" -#include "platform/socket.h" - -namespace v8 { -namespace internal { - -// Public V8 debugger API message handler function. This function just delegates -// to the debugger agent through it's data parameter. -void DebuggerAgentMessageHandler(const v8::Debug::Message& message) { - Isolate* isolate = reinterpret_cast(message.GetIsolate()); - DebuggerAgent* agent = isolate->debugger_agent_instance(); - ASSERT(agent != NULL); - agent->DebuggerMessage(message); -} - - -DebuggerAgent::DebuggerAgent(Isolate* isolate, const char* name, int port) - : Thread(name), - isolate_(isolate), - name_(StrDup(name)), - port_(port), - server_(new Socket), - terminate_(false), - session_(NULL), - terminate_now_(0), - listening_(0) { - ASSERT(isolate_->debugger_agent_instance() == NULL); - isolate_->set_debugger_agent_instance(this); -} - - -DebuggerAgent::~DebuggerAgent() { - isolate_->set_debugger_agent_instance(NULL); - delete server_; -} - - -// Debugger agent main thread. -void DebuggerAgent::Run() { - // Allow this socket to reuse port even if still in TIME_WAIT. - server_->SetReuseAddress(true); - - // First bind the socket to the requested port. - bool bound = false; - while (!bound && !terminate_) { - bound = server_->Bind(port_); - - // If an error occurred wait a bit before retrying. The most common error - // would be that the port is already in use so this avoids a busy loop and - // make the agent take over the port when it becomes free. - if (!bound) { - const TimeDelta kTimeout = TimeDelta::FromSeconds(1); - PrintF("Failed to open socket on port %d, " - "waiting %d ms before retrying\n", port_, - static_cast(kTimeout.InMilliseconds())); - if (!terminate_now_.WaitFor(kTimeout)) { - if (terminate_) return; - } - } - } - - // Accept connections on the bound port. - while (!terminate_) { - bool ok = server_->Listen(1); - listening_.Signal(); - if (ok) { - // Accept the new connection. - Socket* client = server_->Accept(); - ok = client != NULL; - if (ok) { - // Create and start a new session. - CreateSession(client); - } - } - } -} - - -void DebuggerAgent::Shutdown() { - // Set the termination flag. - terminate_ = true; - - // Signal termination and make the server exit either its listen call or its - // binding loop. This makes sure that no new sessions can be established. - terminate_now_.Signal(); - server_->Shutdown(); - Join(); - - // Close existing session if any. - CloseSession(); -} - - -void DebuggerAgent::WaitUntilListening() { - listening_.Wait(); -} - -static const char* kCreateSessionMessage = - "Remote debugging session already active\r\n"; - -void DebuggerAgent::CreateSession(Socket* client) { - LockGuard session_access_guard(&session_access_); - - // If another session is already established terminate this one. - if (session_ != NULL) { - int len = StrLength(kCreateSessionMessage); - int res = client->Send(kCreateSessionMessage, len); - delete client; - USE(res); - return; - } - - // Create a new session and hook up the debug message handler. - session_ = new DebuggerAgentSession(this, client); - isolate_->debugger()->SetMessageHandler(DebuggerAgentMessageHandler); - session_->Start(); -} - - -void DebuggerAgent::CloseSession() { - LockGuard session_access_guard(&session_access_); - - // Terminate the session. - if (session_ != NULL) { - session_->Shutdown(); - session_->Join(); - delete session_; - session_ = NULL; - } -} - - -void DebuggerAgent::DebuggerMessage(const v8::Debug::Message& message) { - LockGuard session_access_guard(&session_access_); - - // Forward the message handling to the session. - if (session_ != NULL) { - v8::String::Value val(message.GetJSON()); - session_->DebuggerMessage(Vector(const_cast(*val), - val.length())); - } -} - - -DebuggerAgentSession::~DebuggerAgentSession() { - delete client_; -} - - -void DebuggerAgent::OnSessionClosed(DebuggerAgentSession* session) { - // Don't do anything during termination. - if (terminate_) { - return; - } - - // Terminate the session. - LockGuard session_access_guard(&session_access_); - ASSERT(session == session_); - if (session == session_) { - session_->Shutdown(); - delete session_; - session_ = NULL; - } -} - - -void DebuggerAgentSession::Run() { - // Send the hello message. - bool ok = DebuggerAgentUtil::SendConnectMessage(client_, agent_->name_.get()); - if (!ok) return; - - while (true) { - // Read data from the debugger front end. - SmartArrayPointer message = - DebuggerAgentUtil::ReceiveMessage(client_); - - const char* msg = message.get(); - bool is_closing_session = (msg == NULL); - - if (msg == NULL) { - // If we lost the connection, then simulate a disconnect msg: - msg = "{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}"; - - } else { - // Check if we're getting a disconnect request: - const char* disconnectRequestStr = - "\"type\":\"request\",\"command\":\"disconnect\"}"; - const char* result = strstr(msg, disconnectRequestStr); - if (result != NULL) { - is_closing_session = true; - } - } - - // Convert UTF-8 to UTF-16. - unibrow::Utf8Decoder<128> decoder(msg, StrLength(msg)); - int utf16_length = decoder.Utf16Length(); - ScopedVector temp(utf16_length + 1); - decoder.WriteUtf16(temp.start(), utf16_length); - - // Send the request received to the debugger. - v8::Debug::SendCommand(reinterpret_cast(agent_->isolate()), - temp.start(), - utf16_length, - NULL); - - if (is_closing_session) { - // Session is closed. - agent_->OnSessionClosed(this); - return; - } - } -} - - -void DebuggerAgentSession::DebuggerMessage(Vector message) { - DebuggerAgentUtil::SendMessage(client_, message); -} - - -void DebuggerAgentSession::Shutdown() { - // Shutdown the socket to end the blocking receive. - client_->Shutdown(); -} - - -const char* const DebuggerAgentUtil::kContentLength = "Content-Length"; - - -SmartArrayPointer DebuggerAgentUtil::ReceiveMessage(Socket* conn) { - int received; - - // Read header. - int content_length = 0; - while (true) { - const int kHeaderBufferSize = 80; - char header_buffer[kHeaderBufferSize]; - int header_buffer_position = 0; - char c = '\0'; // One character receive buffer. - char prev_c = '\0'; // Previous character. - - // Read until CRLF. - while (!(c == '\n' && prev_c == '\r')) { - prev_c = c; - received = conn->Receive(&c, 1); - if (received == 0) { - PrintF("Error %d\n", Socket::GetLastError()); - return SmartArrayPointer(); - } - - // Add character to header buffer. - if (header_buffer_position < kHeaderBufferSize) { - header_buffer[header_buffer_position++] = c; - } - } - - // Check for end of header (empty header line). - if (header_buffer_position == 2) { // Receive buffer contains CRLF. - break; - } - - // Terminate header. - ASSERT(header_buffer_position > 1); // At least CRLF is received. - ASSERT(header_buffer_position <= kHeaderBufferSize); - header_buffer[header_buffer_position - 2] = '\0'; - - // Split header. - char* key = header_buffer; - char* value = NULL; - for (int i = 0; header_buffer[i] != '\0'; i++) { - if (header_buffer[i] == ':') { - header_buffer[i] = '\0'; - value = header_buffer + i + 1; - while (*value == ' ') { - value++; - } - break; - } - } - - // Check that key is Content-Length. - if (strcmp(key, kContentLength) == 0) { - // Get the content length value if present and within a sensible range. - if (value == NULL || strlen(value) > 7) { - return SmartArrayPointer(); - } - for (int i = 0; value[i] != '\0'; i++) { - // Bail out if illegal data. - if (value[i] < '0' || value[i] > '9') { - return SmartArrayPointer(); - } - content_length = 10 * content_length + (value[i] - '0'); - } - } else { - // For now just print all other headers than Content-Length. - PrintF("%s: %s\n", key, value != NULL ? value : "(no value)"); - } - } - - // Return now if no body. - if (content_length == 0) { - return SmartArrayPointer(); - } - - // Read body. - char* buffer = NewArray(content_length + 1); - received = ReceiveAll(conn, buffer, content_length); - if (received < content_length) { - PrintF("Error %d\n", Socket::GetLastError()); - return SmartArrayPointer(); - } - buffer[content_length] = '\0'; - - return SmartArrayPointer(buffer); -} - - -bool DebuggerAgentUtil::SendConnectMessage(Socket* conn, - const char* embedding_host) { - static const int kBufferSize = 80; - char buffer[kBufferSize]; // Sending buffer. - bool ok; - int len; - - // Send the header. - len = OS::SNPrintF(Vector(buffer, kBufferSize), - "Type: connect\r\n"); - ok = conn->Send(buffer, len); - if (!ok) return false; - - len = OS::SNPrintF(Vector(buffer, kBufferSize), - "V8-Version: %s\r\n", v8::V8::GetVersion()); - ok = conn->Send(buffer, len); - if (!ok) return false; - - len = OS::SNPrintF(Vector(buffer, kBufferSize), - "Protocol-Version: 1\r\n"); - ok = conn->Send(buffer, len); - if (!ok) return false; - - if (embedding_host != NULL) { - len = OS::SNPrintF(Vector(buffer, kBufferSize), - "Embedding-Host: %s\r\n", embedding_host); - ok = conn->Send(buffer, len); - if (!ok) return false; - } - - len = OS::SNPrintF(Vector(buffer, kBufferSize), - "%s: 0\r\n", kContentLength); - ok = conn->Send(buffer, len); - if (!ok) return false; - - // Terminate header with empty line. - len = OS::SNPrintF(Vector(buffer, kBufferSize), "\r\n"); - ok = conn->Send(buffer, len); - if (!ok) return false; - - // No body for connect message. - - return true; -} - - -bool DebuggerAgentUtil::SendMessage(Socket* conn, - const Vector message) { - static const int kBufferSize = 80; - char buffer[kBufferSize]; // Sending buffer both for header and body. - - // Calculate the message size in UTF-8 encoding. - int utf8_len = 0; - int previous = unibrow::Utf16::kNoPreviousCharacter; - for (int i = 0; i < message.length(); i++) { - uint16_t character = message[i]; - utf8_len += unibrow::Utf8::Length(character, previous); - previous = character; - } - - // Send the header. - int len = OS::SNPrintF(Vector(buffer, kBufferSize), - "%s: %d\r\n", kContentLength, utf8_len); - if (conn->Send(buffer, len) < len) { - return false; - } - - // Terminate header with empty line. - len = OS::SNPrintF(Vector(buffer, kBufferSize), "\r\n"); - if (conn->Send(buffer, len) < len) { - return false; - } - - // Send message body as UTF-8. - int buffer_position = 0; // Current buffer position. - previous = unibrow::Utf16::kNoPreviousCharacter; - for (int i = 0; i < message.length(); i++) { - // Write next UTF-8 encoded character to buffer. - uint16_t character = message[i]; - buffer_position += - unibrow::Utf8::Encode(buffer + buffer_position, character, previous); - ASSERT(buffer_position <= kBufferSize); - - // Send buffer if full or last character is encoded. - if (kBufferSize - buffer_position < - unibrow::Utf16::kMaxExtraUtf8BytesForOneUtf16CodeUnit || - i == message.length() - 1) { - if (unibrow::Utf16::IsLeadSurrogate(character)) { - const int kEncodedSurrogateLength = - unibrow::Utf16::kUtf8BytesToCodeASurrogate; - ASSERT(buffer_position >= kEncodedSurrogateLength); - len = buffer_position - kEncodedSurrogateLength; - if (conn->Send(buffer, len) < len) { - return false; - } - for (int i = 0; i < kEncodedSurrogateLength; i++) { - buffer[i] = buffer[buffer_position + i]; - } - buffer_position = kEncodedSurrogateLength; - } else { - len = buffer_position; - if (conn->Send(buffer, len) < len) { - return false; - } - buffer_position = 0; - } - } - previous = character; - } - - return true; -} - - -bool DebuggerAgentUtil::SendMessage(Socket* conn, - const v8::Handle request) { - static const int kBufferSize = 80; - char buffer[kBufferSize]; // Sending buffer both for header and body. - - // Convert the request to UTF-8 encoding. - v8::String::Utf8Value utf8_request(request); - - // Send the header. - int len = OS::SNPrintF(Vector(buffer, kBufferSize), - "Content-Length: %d\r\n", utf8_request.length()); - if (conn->Send(buffer, len) < len) { - return false; - } - - // Terminate header with empty line. - len = OS::SNPrintF(Vector(buffer, kBufferSize), "\r\n"); - if (conn->Send(buffer, len) < len) { - return false; - } - - // Send message body as UTF-8. - len = utf8_request.length(); - if (conn->Send(*utf8_request, len) < len) { - return false; - } - - return true; -} - - -// Receive the full buffer before returning unless an error occours. -int DebuggerAgentUtil::ReceiveAll(Socket* conn, char* data, int len) { - int total_received = 0; - while (total_received < len) { - int received = conn->Receive(data + total_received, len - total_received); - if (received == 0) { - return total_received; - } - total_received += received; - } - return total_received; -} - -} } // namespace v8::internal diff --git a/src/debug-agent.h b/src/debug-agent.h deleted file mode 100644 index 3e3f25a..0000000 --- a/src/debug-agent.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_DEBUG_AGENT_H_ -#define V8_DEBUG_AGENT_H_ - -#include "../include/v8-debug.h" -#include "platform.h" - -namespace v8 { -namespace internal { - -// Forward decelrations. -class DebuggerAgentSession; -class Socket; - - -// Debugger agent which starts a socket listener on the debugger port and -// handles connection from a remote debugger. -class DebuggerAgent: public Thread { - public: - DebuggerAgent(Isolate* isolate, const char* name, int port); - ~DebuggerAgent(); - - void Shutdown(); - void WaitUntilListening(); - - Isolate* isolate() { return isolate_; } - - private: - void Run(); - void CreateSession(Socket* socket); - void DebuggerMessage(const v8::Debug::Message& message); - void CloseSession(); - void OnSessionClosed(DebuggerAgentSession* session); - - Isolate* isolate_; - SmartArrayPointer name_; // Name of the embedding application. - int port_; // Port to use for the agent. - Socket* server_; // Server socket for listen/accept. - bool terminate_; // Termination flag. - RecursiveMutex session_access_; // Mutex guarding access to session_. - DebuggerAgentSession* session_; // Current active session if any. - Semaphore terminate_now_; // Semaphore to signal termination. - Semaphore listening_; - - friend class DebuggerAgentSession; - friend void DebuggerAgentMessageHandler(const v8::Debug::Message& message); - - DISALLOW_COPY_AND_ASSIGN(DebuggerAgent); -}; - - -// Debugger agent session. The session receives requests from the remote -// debugger and sends debugger events/responses to the remote debugger. -class DebuggerAgentSession: public Thread { - public: - DebuggerAgentSession(DebuggerAgent* agent, Socket* client) - : Thread("v8:DbgAgntSessn"), - agent_(agent), client_(client) {} - ~DebuggerAgentSession(); - - void DebuggerMessage(Vector message); - void Shutdown(); - - private: - void Run(); - - void DebuggerMessage(Vector message); - - DebuggerAgent* agent_; - Socket* client_; - - DISALLOW_COPY_AND_ASSIGN(DebuggerAgentSession); -}; - - -// Utility methods factored out to be used by the D8 shell as well. -class DebuggerAgentUtil { - public: - static const char* const kContentLength; - - static SmartArrayPointer ReceiveMessage(Socket* conn); - static bool SendConnectMessage(Socket* conn, const char* embedding_host); - static bool SendMessage(Socket* conn, const Vector message); - static bool SendMessage(Socket* conn, const v8::Handle message); - static int ReceiveAll(Socket* conn, char* data, int len); -}; - -} } // namespace v8::internal - -#endif // V8_DEBUG_AGENT_H_ diff --git a/src/debug.cc b/src/debug.cc index c112b4d..e3cbf32 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -2632,9 +2632,6 @@ Debugger::Debugger(Isolate* isolate) never_unload_debugger_(false), message_handler_(NULL), debugger_unload_pending_(false), - debug_message_dispatch_handler_(NULL), - message_dispatch_helper_thread_(NULL), - agent_(NULL), command_queue_(isolate->logger(), kQueueInitialSize), command_received_(0), event_command_queue_(isolate->logger(), kQueueInitialSize), @@ -3189,7 +3186,7 @@ void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler) { // Send an empty command to the debugger if in a break to make JavaScript // run again if the debugger is closed. if (isolate_->debug()->InDebugger()) { - ProcessCommand(Vector::empty()); + EnqueueCommandMessage(Vector::empty()); } } } @@ -3211,18 +3208,6 @@ void Debugger::ListenersChanged() { } -void Debugger::SetDebugMessageDispatchHandler( - v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) { - LockGuard lock_guard(&dispatch_handler_access_); - debug_message_dispatch_handler_ = handler; - - if (provide_locker && message_dispatch_helper_thread_ == NULL) { - message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_); - message_dispatch_helper_thread_->Start(); - } -} - - // Calls the registered debug message handler. This callback is part of the // public API. void Debugger::InvokeMessageHandler(MessageImpl message) { @@ -3238,8 +3223,8 @@ void Debugger::InvokeMessageHandler(MessageImpl message) { // a copy of the command string managed by the debugger. Up to this // point, the command data was managed by the API client. Called // by the API client thread. -void Debugger::ProcessCommand(Vector command, - v8::Debug::ClientData* client_data) { +void Debugger::EnqueueCommandMessage(Vector command, + v8::Debug::ClientData* client_data) { // Need to cast away const. CommandMessage message = CommandMessage::New( Vector(const_cast(command.start()), @@ -3253,18 +3238,6 @@ void Debugger::ProcessCommand(Vector command, if (!isolate_->debug()->InDebugger()) { isolate_->stack_guard()->RequestDebugCommand(); } - - MessageDispatchHelperThread* dispatch_thread; - { - LockGuard lock_guard(&dispatch_handler_access_); - dispatch_thread = message_dispatch_helper_thread_; - } - - if (dispatch_thread == NULL) { - CallMessageDispatchHandler(); - } else { - dispatch_thread->Schedule(); - } } @@ -3312,60 +3285,6 @@ MaybeHandle Debugger::Call(Handle fun, } -static void StubMessageHandler2(const v8::Debug::Message& message) { - // Simply ignore message. -} - - -bool Debugger::StartAgent(const char* name, int port, - bool wait_for_connection) { - if (wait_for_connection) { - // Suspend V8 if it is already running or set V8 to suspend whenever - // it starts. - // Provide stub message handler; V8 auto-continues each suspend - // when there is no message handler; we doesn't need it. - // Once become suspended, V8 will stay so indefinitely long, until remote - // debugger connects and issues "continue" command. - Debugger::message_handler_ = StubMessageHandler2; - v8::Debug::DebugBreak(reinterpret_cast(isolate_)); - } - - if (agent_ == NULL) { - agent_ = new DebuggerAgent(isolate_, name, port); - agent_->Start(); - } - return true; -} - - -void Debugger::StopAgent() { - if (agent_ != NULL) { - agent_->Shutdown(); - agent_->Join(); - delete agent_; - agent_ = NULL; - } -} - - -void Debugger::WaitForAgent() { - if (agent_ != NULL) - agent_->WaitUntilListening(); -} - - -void Debugger::CallMessageDispatchHandler() { - v8::Debug::DebugMessageDispatchHandler handler; - { - LockGuard lock_guard(&dispatch_handler_access_); - handler = Debugger::debug_message_dispatch_handler_; - } - if (handler != NULL) { - handler(); - } -} - - EnterDebugger::EnterDebugger(Isolate* isolate) : isolate_(isolate), prev_(isolate_->debug()->debugger_entry()), @@ -3703,38 +3622,4 @@ void LockingCommandMessageQueue::Clear() { queue_.Clear(); } - -MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate) - : Thread("v8:MsgDispHelpr"), - isolate_(isolate), sem_(0), - already_signalled_(false) { -} - - -void MessageDispatchHelperThread::Schedule() { - { - LockGuard lock_guard(&mutex_); - if (already_signalled_) { - return; - } - already_signalled_ = true; - } - sem_.Signal(); -} - - -void MessageDispatchHelperThread::Run() { - while (true) { - sem_.Wait(); - { - LockGuard lock_guard(&mutex_); - already_signalled_ = false; - } - { - Locker locker(reinterpret_cast(isolate_)); - isolate_->debugger()->CallMessageDispatchHandler(); - } - } -} - } } // namespace v8::internal diff --git a/src/debug.h b/src/debug.h index 7277323..35b29c0 100644 --- a/src/debug.h +++ b/src/debug.h @@ -8,7 +8,6 @@ #include "allocation.h" #include "arguments.h" #include "assembler.h" -#include "debug-agent.h" #include "execution.h" #include "factory.h" #include "flags.h" @@ -783,16 +782,10 @@ class Debugger { bool auto_continue); void SetEventListener(Handle callback, Handle data); void SetMessageHandler(v8::Debug::MessageHandler handler); - void SetDebugMessageDispatchHandler( - v8::Debug::DebugMessageDispatchHandler handler, - bool provide_locker); - - // Invoke the message handler function. - void InvokeMessageHandler(MessageImpl message); // Add a debugger command to the command queue. - void ProcessCommand(Vector command, - v8::Debug::ClientData* client_data = NULL); + void EnqueueCommandMessage(Vector command, + v8::Debug::ClientData* client_data = NULL); // Check whether there are commands in the command queue. bool HasCommands(); @@ -803,18 +796,6 @@ class Debugger { MUST_USE_RESULT MaybeHandle Call(Handle fun, Handle data); - // Start the debugger agent listening on the provided port. - bool StartAgent(const char* name, int port, - bool wait_for_connection = false); - - // Stop the debugger agent. - void StopAgent(); - - // Blocks until the agent has started listening for connections - void WaitForAgent(); - - void CallMessageDispatchHandler(); - Handle GetDebugContext(); // Unload the debugger if possible. Only called when no debugger is currently @@ -882,6 +863,9 @@ class Debugger { Handle event_data); void ListenersChanged(); + // Invoke the message handler function. + void InvokeMessageHandler(MessageImpl message); + RecursiveMutex debugger_access_; // Mutex guarding debugger variables. Handle event_listener_; // Global handle to listener. Handle event_listener_data_; @@ -892,12 +876,6 @@ class Debugger { v8::Debug::MessageHandler message_handler_; bool debugger_unload_pending_; // Was message handler cleared? - Mutex dispatch_handler_access_; // Mutex guarding dispatch handler. - v8::Debug::DebugMessageDispatchHandler debug_message_dispatch_handler_; - MessageDispatchHelperThread* message_dispatch_helper_thread_; - - DebuggerAgent* agent_; - static const int kQueueInitialSize = 4; LockingCommandMessageQueue command_queue_; Semaphore command_received_; // Signaled for each command received. @@ -994,29 +972,6 @@ class Debug_Address { Debug::AddressId id_; }; -// The optional thread that Debug Agent may use to temporary call V8 to process -// pending debug requests if debuggee is not running V8 at the moment. -// Techincally it does not call V8 itself, rather it asks embedding program -// to do this via v8::Debug::HostDispatchHandler -class MessageDispatchHelperThread: public Thread { - public: - explicit MessageDispatchHelperThread(Isolate* isolate); - ~MessageDispatchHelperThread() {} - - void Schedule(); - - private: - void Run(); - - Isolate* isolate_; - Semaphore sem_; - Mutex mutex_; - bool already_signalled_; - - DISALLOW_COPY_AND_ASSIGN(MessageDispatchHelperThread); -}; - - } } // namespace v8::internal #endif // V8_DEBUG_H_ diff --git a/src/execution.cc b/src/execution.cc index b88cdd5..8f8c153 100644 --- a/src/execution.cc +++ b/src/execution.cc @@ -714,6 +714,9 @@ void Execution::DebugBreakHelper(Isolate* isolate) { void Execution::ProcessDebugMessages(Isolate* isolate, bool debug_command_only) { + // Assert that we are on the main thread of the isolate. + ASSERT(ThreadId::Current().Equals(isolate->thread_id())); + isolate->stack_guard()->ClearDebugCommand(); StackLimitCheck check(isolate); diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 31058ae..1423658 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -660,10 +660,6 @@ DEFINE_bool(help, false, "Print usage message, including flags, on console") DEFINE_bool(dump_counters, false, "Dump counters on exit") DEFINE_bool(debugger, false, "Enable JavaScript debugger") -DEFINE_bool(remote_debugger, false, "Connect JavaScript debugger to the " - "debugger agent in another process") -DEFINE_bool(debugger_agent, false, "Enable debugger agent") -DEFINE_int(debugger_port, 5858, "Port to use for remote debugging") DEFINE_string(map_counters, "", "Map counters to a file") DEFINE_args(js_arguments, diff --git a/src/isolate.h b/src/isolate.h index 3bed763..9b58321 100644 --- a/src/isolate.h +++ b/src/isolate.h @@ -75,7 +75,6 @@ typedef void* ExternalReferenceRedirectorPointer(); class Debug; class Debugger; -class DebuggerAgent; #if !defined(__arm__) && V8_TARGET_ARCH_ARM || \ !defined(__aarch64__) && V8_TARGET_ARCH_ARM64 || \ @@ -358,7 +357,6 @@ typedef List DebugObjectCache; V(bool, fp_stubs_generated, false) \ V(int, max_available_threads, 0) \ V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu) \ - V(DebuggerAgent*, debugger_agent_instance, NULL) \ V(InterruptCallback, api_interrupt_callback, NULL) \ V(void*, api_interrupt_callback_data, NULL) \ ISOLATE_INIT_SIMULATOR_LIST(V) diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index e080ebe..1ee4810 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -5788,242 +5788,6 @@ TEST(DebuggerClearMessageHandlerWhileActive) { } -/* Test DebugMessageDispatch */ -/* In this test, the V8 thread waits for a message from the debug thread. - * The DebugMessageDispatchHandler is executed from the debugger thread - * which signals the V8 thread to wake up. - */ - -class DebugMessageDispatchV8Thread : public v8::internal::Thread { - public: - DebugMessageDispatchV8Thread() : Thread("DebugMessageDispatchV8Thread") { } - void Run(); -}; - -class DebugMessageDispatchDebuggerThread : public v8::internal::Thread { - public: - DebugMessageDispatchDebuggerThread() - : Thread("DebugMessageDispatchDebuggerThread") { } - void Run(); -}; - -Barriers* debug_message_dispatch_barriers; - - -static void DebugMessageHandler() { - debug_message_dispatch_barriers->semaphore_1.Signal(); -} - - -void DebugMessageDispatchV8Thread::Run() { - v8::Isolate::Scope isolate_scope(CcTest::isolate()); - DebugLocalContext env; - v8::HandleScope scope(env->GetIsolate()); - - // Set up debug message dispatch handler. - v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler); - - CompileRun("var y = 1 + 2;\n"); - debug_message_dispatch_barriers->barrier_1.Wait(); - debug_message_dispatch_barriers->semaphore_1.Wait(); - debug_message_dispatch_barriers->barrier_2.Wait(); -} - - -void DebugMessageDispatchDebuggerThread::Run() { - debug_message_dispatch_barriers->barrier_1.Wait(); - SendContinueCommand(); - debug_message_dispatch_barriers->barrier_2.Wait(); -} - - -TEST(DebuggerDebugMessageDispatch) { - DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread; - DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread; - - // Create a V8 environment - Barriers stack_allocated_debug_message_dispatch_barriers; - debug_message_dispatch_barriers = - &stack_allocated_debug_message_dispatch_barriers; - - debug_message_dispatch_v8_thread.Start(); - debug_message_dispatch_debugger_thread.Start(); - - debug_message_dispatch_v8_thread.Join(); - debug_message_dispatch_debugger_thread.Join(); -} - - -TEST(DebuggerAgent) { - v8::V8::Initialize(); - i::Debugger* debugger = CcTest::i_isolate()->debugger(); - // Make sure these ports is not used by other tests to allow tests to run in - // parallel. - const int kPort1 = 5858 + FlagDependentPortOffset(); - const int kPort2 = 5857 + FlagDependentPortOffset(); - const int kPort3 = 5856 + FlagDependentPortOffset(); - - // Make a string with the port2 number. - const int kPortBufferLen = 6; - char port2_str[kPortBufferLen]; - OS::SNPrintF(i::Vector(port2_str, kPortBufferLen), "%d", kPort2); - - bool ok; - - // Test starting and stopping the agent without any client connection. - debugger->StartAgent("test", kPort1); - debugger->StopAgent(); - // Test starting the agent, connecting a client and shutting down the agent - // with the client connected. - ok = debugger->StartAgent("test", kPort2); - CHECK(ok); - debugger->WaitForAgent(); - i::Socket* client = new i::Socket; - ok = client->Connect("localhost", port2_str); - CHECK(ok); - // It is important to wait for a message from the agent. Otherwise, - // we can close the server socket during "accept" syscall, making it failing - // (at least on Linux), and the test will work incorrectly. - char buf; - ok = client->Receive(&buf, 1) == 1; - CHECK(ok); - debugger->StopAgent(); - delete client; - - // Test starting and stopping the agent with the required port already - // occoupied. - i::Socket* server = new i::Socket; - ok = server->Bind(kPort3); - CHECK(ok); - - debugger->StartAgent("test", kPort3); - debugger->StopAgent(); - - delete server; -} - - -class DebuggerAgentProtocolServerThread : public i::Thread { - public: - explicit DebuggerAgentProtocolServerThread(int port) - : Thread("DebuggerAgentProtocolServerThread"), - port_(port), - server_(NULL), - client_(NULL), - listening_(0) { - } - ~DebuggerAgentProtocolServerThread() { - // Close both sockets. - delete client_; - delete server_; - } - - void Run(); - void WaitForListening() { listening_.Wait(); } - char* body() { return body_.get(); } - - private: - int port_; - i::SmartArrayPointer body_; - i::Socket* server_; // Server socket used for bind/accept. - i::Socket* client_; // Single client connection used by the test. - i::Semaphore listening_; // Signalled when the server is in listen mode. -}; - - -void DebuggerAgentProtocolServerThread::Run() { - bool ok; - - // Create the server socket and bind it to the requested port. - server_ = new i::Socket; - CHECK(server_ != NULL); - ok = server_->Bind(port_); - CHECK(ok); - - // Listen for new connections. - ok = server_->Listen(1); - CHECK(ok); - listening_.Signal(); - - // Accept a connection. - client_ = server_->Accept(); - CHECK(client_ != NULL); - - // Receive a debugger agent protocol message. - i::DebuggerAgentUtil::ReceiveMessage(client_); -} - - -TEST(DebuggerAgentProtocolOverflowHeader) { - // Make sure this port is not used by other tests to allow tests to run in - // parallel. - const int kPort = 5860 + FlagDependentPortOffset(); - static const char* kLocalhost = "localhost"; - - // Make a string with the port number. - const int kPortBufferLen = 6; - char port_str[kPortBufferLen]; - OS::SNPrintF(i::Vector(port_str, kPortBufferLen), "%d", kPort); - - // Create a socket server to receive a debugger agent message. - DebuggerAgentProtocolServerThread* server = - new DebuggerAgentProtocolServerThread(kPort); - server->Start(); - server->WaitForListening(); - - // Connect. - i::Socket* client = new i::Socket; - CHECK(client != NULL); - bool ok = client->Connect(kLocalhost, port_str); - CHECK(ok); - - // Send headers which overflow the receive buffer. - static const int kBufferSize = 1000; - char buffer[kBufferSize]; - - // Long key and short value: XXXX....XXXX:0\r\n. - for (int i = 0; i < kBufferSize - 4; i++) { - buffer[i] = 'X'; - } - buffer[kBufferSize - 4] = ':'; - buffer[kBufferSize - 3] = '0'; - buffer[kBufferSize - 2] = '\r'; - buffer[kBufferSize - 1] = '\n'; - int result = client->Send(buffer, kBufferSize); - CHECK_EQ(kBufferSize, result); - - // Short key and long value: X:XXXX....XXXX\r\n. - buffer[0] = 'X'; - buffer[1] = ':'; - for (int i = 2; i < kBufferSize - 2; i++) { - buffer[i] = 'X'; - } - buffer[kBufferSize - 2] = '\r'; - buffer[kBufferSize - 1] = '\n'; - result = client->Send(buffer, kBufferSize); - CHECK_EQ(kBufferSize, result); - - // Add empty body to request. - const char* content_length_zero_header = "Content-Length:0\r\n"; - int length = StrLength(content_length_zero_header); - result = client->Send(content_length_zero_header, length); - CHECK_EQ(length, result); - result = client->Send("\r\n", 2); - CHECK_EQ(2, result); - - // Wait until data is received. - server->Join(); - - // Check for empty body. - CHECK(server->body() == NULL); - - // Close the client before the server to avoid TIME_WAIT issues. - client->Shutdown(); - delete client; - delete server; -} - - // 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. @@ -6783,7 +6547,7 @@ TEST(NoDebugBreakInAfterCompileMessageHandler) { static int counting_message_handler_counter; static void CountingMessageHandler(const v8::Debug::Message& message) { - counting_message_handler_counter++; + if (message.IsResponse()) counting_message_handler_counter++; } @@ -6830,6 +6594,83 @@ TEST(ProcessDebugMessages) { } +class SendCommandThread : public v8::internal::Thread { + public: + explicit SendCommandThread(v8::Isolate* isolate) + : Thread("SendCommandThread"), + semaphore_(0), + isolate_(isolate) { } + + static void ProcessDebugMessages(v8::Isolate* isolate, void* data) { + v8::Debug::ProcessDebugMessages(); + reinterpret_cast(data)->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 < 100; i++) { + CHECK_EQ(i, counting_message_handler_counter); + // Queue debug message. + v8::Debug::SendCommand(isolate_, buffer, length); + // Synchronize with the main thread to force message processing. + isolate_->RequestInterrupt(ProcessDebugMessages, &semaphore_); + semaphore_.Wait(); + } + + v8::V8::TerminateExecution(isolate_); + } + + void StartSending() { + semaphore_.Signal(); + } + + private: + v8::internal::Semaphore semaphore_; + v8::Isolate* isolate_; +}; + + +static SendCommandThread* send_command_thread_ = NULL; + +static void StartSendingCommands( + const v8::FunctionCallbackInfo& info) { + send_command_thread_->StartSending(); +} + + +TEST(ProcessDebugMessagesThreaded) { + DebugLocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + + counting_message_handler_counter = 0; + + v8::Debug::SetMessageHandler2(CountingMessageHandler); + send_command_thread_ = new SendCommandThread(isolate); + send_command_thread_->Start(); + + v8::Handle start = + v8::FunctionTemplate::New(isolate, StartSendingCommands); + env->Global()->Set(v8_str("start"), start->GetFunction()); + + CompileRun("start(); while (true) { }"); + + CHECK_EQ(100, counting_message_handler_counter); + + v8::Debug::SetMessageHandler2(NULL); + CheckDebuggerUnloaded(); +} + + struct BacktraceData { static int frame_counter; static void MessageHandler(const v8::Debug::Message& message) { diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index e6a5bd1..722cde1 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -313,8 +313,6 @@ '../../src/dateparser-inl.h', '../../src/dateparser.cc', '../../src/dateparser.h', - '../../src/debug-agent.cc', - '../../src/debug-agent.h', '../../src/debug.cc', '../../src/debug.h', '../../src/deoptimizer.cc', -- 2.7.4