As long as all debugger messages are handled by a single static method we need a...
authoryurys@chromium.org <yurys@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 21 Apr 2009 14:06:48 +0000 (14:06 +0000)
committeryurys@chromium.org <yurys@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 21 Apr 2009 14:06:48 +0000 (14:06 +0000)
Review URL: http://codereview.chromium.org/67266

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1755 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8-debug.h
src/api.cc
src/debug-agent.cc
src/debug-agent.h
src/debug.cc
src/debug.h
test/cctest/test-debug.cc

index 4c639c1..fc93d76 100644 (file)
@@ -79,48 +79,60 @@ enum DebugEvent {
 };
 
 
-/**
- * Debug event callback function.
- *
- * \param event the type of the debug event that triggered the callback
- *   (enum DebugEvent)
- * \param exec_state execution state (JavaScript object)
- * \param event_data event specific data (JavaScript object)
- * \param data value passed by the user to SetDebugEventListener
- */
-typedef void (*DebugEventCallback)(DebugEvent event,
-                                   Handle<Object> exec_state,
-                                   Handle<Object> event_data,
-                                   Handle<Value> data);
-
-
-/**
- * Debug message callback function.
- *
- * \param message the debug message
- * \param length length of the message
- * \param data the data value passed when registering the message handler
- * A DebugMessageHandler does not take posession of the message string,
- * and must not rely on the data persisting after the handler returns.
- */
-typedef void (*DebugMessageHandler)(const uint16_t* message, int length,
-                                    void* data);
-
-/**
- * Debug host dispatch callback function.
- *
- * \param dispatch the dispatch value
- * \param data the data value passed when registering the dispatch handler
- */
-typedef void (*DebugHostDispatchHandler)(void* dispatch,
-                                         void* data);
-
-
-
 class EXPORT Debug {
  public:
+  /**
+   * A client object passed to the v8 debugger whose ownership will be taken by
+   * it. v8 is always responsible for deleting the object.
+   */
+  class ClientData {
+   public:
+    virtual ~ClientData() {}
+  };
+
+
+  /**
+   * Debug event callback function.
+   *
+   * \param event the type of the debug event that triggered the callback
+   *   (enum DebugEvent)
+   * \param exec_state execution state (JavaScript object)
+   * \param event_data event specific data (JavaScript object)
+   * \param data value passed by the user to SetDebugEventListener
+   */
+  typedef void (*EventCallback)(DebugEvent event,
+                                     Handle<Object> exec_state,
+                                     Handle<Object> event_data,
+                                     Handle<Value> data);
+
+
+  /**
+   * Debug message callback function.
+   *
+   * \param message the debug message
+   * \param length length of the message
+   * \param data the data value passed when registering the message handler
+   * \param client_data the data value passed into Debug::SendCommand along
+   *     with the request that led to the message or NULL if the message is an
+   *     asynchronous event. The debugger takes ownership of the data and will
+   *     delete it before dying even if there is no message handler.
+   * A MessageHandler does not take posession of the message string,
+   * and must not rely on the data persisting after the handler returns.
+   */
+  typedef void (*MessageHandler)(const uint16_t* message, int length,
+                                      ClientData* client_data);
+
+  /**
+   * Debug host dispatch callback function.
+   *
+   * \param dispatch the dispatch value
+   * \param data the data value passed when registering the dispatch handler
+   */
+  typedef void (*HostDispatchHandler)(ClientData* dispatch);
+
+
   // Set a C debug event listener.
-  static bool SetDebugEventListener(DebugEventCallback that,
+  static bool SetDebugEventListener(EventCallback that,
                                     Handle<Value> data = Handle<Value>());
 
   // Set a JavaScript debug event listener.
@@ -131,14 +143,14 @@ class EXPORT Debug {
   static void DebugBreak();
 
   // Message based interface. The message protocol is JSON.
-  static void SetMessageHandler(DebugMessageHandler handler, void* data = NULL,
+  static void SetMessageHandler(MessageHandler handler,
                                 bool message_handler_thread = true);
-  static void SendCommand(const uint16_t* command, int length);
+  static void SendCommand(const uint16_t* command, int length,
+                          ClientData* client_data = NULL);
 
   // Dispatch interface.
-  static void SetHostDispatchHandler(DebugHostDispatchHandler handler,
-                                     void* data = NULL);
-  static void SendHostDispatch(void* dispatch);
+  static void SetHostDispatchHandler(HostDispatchHandler handler);
+  static void SendHostDispatch(ClientData* dispatch);
 
  /**
   * Run a JavaScript function in the debugger.
index 9fd1ee0..7845525 100644 (file)
@@ -3230,7 +3230,7 @@ Local<Value> Exception::Error(v8::Handle<v8::String> raw_message) {
 // --- D e b u g   S u p p o r t ---
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
-bool Debug::SetDebugEventListener(DebugEventCallback that, Handle<Value> data) {
+bool Debug::SetDebugEventListener(EventCallback that, Handle<Value> data) {
   EnsureInitialized("v8::Debug::SetDebugEventListener()");
   ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false);
   ENTER_V8;
@@ -3260,29 +3260,30 @@ void Debug::DebugBreak() {
 }
 
 
-void Debug::SetMessageHandler(v8::DebugMessageHandler handler, void* data,
+void Debug::SetMessageHandler(v8::Debug::MessageHandler handler,
                               bool message_handler_thread) {
   EnsureInitialized("v8::Debug::SetMessageHandler");
   ENTER_V8;
-  i::Debugger::SetMessageHandler(handler, data, message_handler_thread);
+  i::Debugger::SetMessageHandler(handler, message_handler_thread);
 }
 
 
-void Debug::SendCommand(const uint16_t* command, int length) {
+void Debug::SendCommand(const uint16_t* command, int length,
+                        ClientData* client_data) {
   if (!i::V8::HasBeenSetup()) return;
-  i::Debugger::ProcessCommand(i::Vector<const uint16_t>(command, length));
+  i::Debugger::ProcessCommand(i::Vector<const uint16_t>(command, length),
+                              client_data);
 }
 
 
-void Debug::SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
-                                   void* data) {
+void Debug::SetHostDispatchHandler(HostDispatchHandler handler) {
   EnsureInitialized("v8::Debug::SetHostDispatchHandler");
   ENTER_V8;
-  i::Debugger::SetHostDispatchHandler(handler, data);
+  i::Debugger::SetHostDispatchHandler(handler);
 }
 
 
-void Debug::SendHostDispatch(void* dispatch) {
+void Debug::SendHostDispatch(ClientData* dispatch) {
   if (!i::V8::HasBeenSetup()) return;
   i::Debugger::ProcessHostDispatch(dispatch);
 }
index 24d89b0..9838746 100644 (file)
@@ -35,10 +35,12 @@ 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 uint16_t* message, int length,
-                                 void *data) {
-  reinterpret_cast<DebuggerAgent*>(data)->DebuggerMessage(message, length);
+                                 v8::Debug::ClientData* client_data) {
+  DebuggerAgent::instance_->DebuggerMessage(message, length);
 }
 
+// static
+DebuggerAgent* DebuggerAgent::instance_ = NULL;
 
 // Debugger agent main thread.
 void DebuggerAgent::Run() {
index 54dc683..08f1372 100644 (file)
@@ -46,8 +46,14 @@ class DebuggerAgent: public Thread {
       : name_(StrDup(name)), port_(port),
         server_(OS::CreateSocket()), terminate_(false),
         session_access_(OS::CreateMutex()), session_(NULL),
-        terminate_now_(OS::CreateSemaphore(0)) {}
-  ~DebuggerAgent() { delete server_; }
+        terminate_now_(OS::CreateSemaphore(0)) {
+    ASSERT(instance_ == NULL);
+    instance_ = this;
+  }
+  ~DebuggerAgent() {
+     instance_ = NULL;
+     delete server_;
+  }
 
   void Shutdown();
 
@@ -66,9 +72,11 @@ class DebuggerAgent: public Thread {
   DebuggerAgentSession* session_;  // Current active session if any.
   Semaphore* terminate_now_;  // Semaphore to signal termination.
 
+  static DebuggerAgent* instance_;
+
   friend class DebuggerAgentSession;
   friend void DebuggerAgentMessageHandler(const uint16_t* message, int length,
-                                          void *data);
+                                          v8::Debug::ClientData* client_data);
 
   DISALLOW_COPY_AND_ASSIGN(DebuggerAgent);
 };
index 99ae423..5ab4d34 100644 (file)
@@ -1398,11 +1398,9 @@ bool Debugger::compiling_natives_ = false;
 bool Debugger::is_loading_debugger_ = false;
 bool Debugger::never_unload_debugger_ = false;
 DebugMessageThread* Debugger::message_thread_ = NULL;
-v8::DebugMessageHandler Debugger::message_handler_ = NULL;
+v8::Debug::MessageHandler Debugger::message_handler_ = NULL;
 bool Debugger::message_handler_cleared_ = false;
-void* Debugger::message_handler_data_ = NULL;
-v8::DebugHostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
-void* Debugger::host_dispatch_handler_data_ = NULL;
+v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
 DebuggerAgent* Debugger::agent_ = NULL;
 LockingMessageQueue Debugger::command_queue_(kQueueInitialSize);
 LockingMessageQueue Debugger::message_queue_(kQueueInitialSize);
@@ -1704,8 +1702,8 @@ void Debugger::ProcessDebugEvent(v8::DebugEvent event,
     if (event_listener_->IsProxy()) {
       // C debug event listener.
       Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_));
-      v8::DebugEventCallback callback =
-            FUNCTION_CAST<v8::DebugEventCallback>(callback_obj->proxy());
+      v8::Debug::EventCallback callback =
+            FUNCTION_CAST<v8::Debug::EventCallback>(callback_obj->proxy());
       callback(event,
                v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
                v8::Utils::ToLocal(Handle<JSObject>::cast(event_data)),
@@ -1813,18 +1811,20 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
     StackGuard::Continue(DEBUGCOMMAND);
 
     // Get the command from the queue.
-    Vector<uint16_t> command = command_queue_.Get();
+    Message command = command_queue_.Get();
     Logger::DebugTag("Got request from command queue, in interactive loop.");
     if (!Debugger::IsDebuggerActive()) {
+      // Delete command text and user data.
+      command.Dispose();
       return;
     }
 
     // Check if the command is a host dispatch.
-    if (command[0] == 0) {
+    if (command.IsHostDispatch()) {
       if (Debugger::host_dispatch_handler_) {
-        int32_t dispatch = (command[1] << 16) | command[2];
-        Debugger::host_dispatch_handler_(reinterpret_cast<void*>(dispatch),
-                                         Debugger::host_dispatch_handler_data_);
+        Debugger::host_dispatch_handler_(command.client_data());
+        // Delete the dispatch.
+        command.Dispose();
       }
       if (auto_continue && !HasCommands()) {
         return;
@@ -1839,8 +1839,10 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
     v8::TryCatch try_catch;
     fun_name = v8::String::New("processDebugRequest");
     fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
-    request = v8::String::New(reinterpret_cast<uint16_t*>(command.start()),
-                              command.length());
+    
+    request = v8::String::New(command.text().start(),
+                              command.text().length());
+    command.text().Dispose();
     static const int kArgc = 1;
     v8::Handle<Value> argv[kArgc] = { request };
     v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
@@ -1876,13 +1878,8 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
       response = try_catch.Exception()->ToString();
     }
 
-    // Convert text result to C string.
-    v8::String::Value val(response);
-    Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
-                        response->Length());
-
     // Return the result.
-    SendMessage(str);
+    SendMessage(Message::NewOutput(response, command.client_data()));
 
     // Return from debug event processing if either the VM is put into the
     // runnning state (through a continue command) or auto continue is active
@@ -1928,12 +1925,11 @@ void Debugger::SetEventListener(Handle<Object> callback,
 }
 
 
-void Debugger::SetMessageHandler(v8::DebugMessageHandler handler, void* data,
+void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler,
                                  bool message_handler_thread) {
   ScopedLock with(debugger_access_);
 
   message_handler_ = handler;
-  message_handler_data_ = data;
   if (handler != NULL) {
     if (!message_thread_ && message_handler_thread) {
       message_thread_ = new DebugMessageThread();
@@ -1952,10 +1948,8 @@ void Debugger::SetMessageHandler(v8::DebugMessageHandler handler, void* data,
 }
 
 
-void Debugger::SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
-                                      void* data) {
+void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler) {
   host_dispatch_handler_ = handler;
-  host_dispatch_handler_data_ = data;
 }
 
 
@@ -1963,26 +1957,28 @@ void Debugger::SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
 // public API. Messages are kept internally as Vector<uint16_t> strings, which
 // are allocated in various places and deallocated by the calling function
 // sometime after this call.
-void Debugger::InvokeMessageHandler(Vector<uint16_t> message) {
+void Debugger::InvokeMessageHandler(Message message) {
   ScopedLock with(debugger_access_);
 
   if (message_handler_ != NULL) {
-    message_handler_(message.start(), message.length(), message_handler_data_);
+    message_handler_(message.text().start(),
+                     message.text().length(),
+                     message.client_data());
   }
+  message.Dispose();
 }
 
 
-void Debugger::SendMessage(Vector<uint16_t> message) {
+void Debugger::SendMessage(Message message) {
   if (message_thread_ == NULL) {
     // If there is no message thread just invoke the message handler from the
     // V8 thread.
     InvokeMessageHandler(message);
   } else {
-    // Put a copy of the message coming from V8 on the queue. The new copy of
-    // the event string is destroyed by the message thread.
-    Vector<uint16_t> message_copy = message.Clone();
+    // Put the message coming from V8 on the queue. The text and user data will
+    // be destroyed by the message thread.
     Logger::DebugTag("Put message on event message_queue.");
-    message_queue_.Put(message_copy);
+    message_queue_.Put(message);
     message_received_->Signal();
   }
 }
@@ -2005,12 +2001,11 @@ bool Debugger::SendEventMessage(Handle<Object> event_data) {
       if (FLAG_trace_debug_json) {
         PrintLn(json_event_string);
       }
-      v8::String::Value val(json_event_string);
-      Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
-                           json_event_string->Length());
-      SendMessage(str);
+      SendMessage(Message::NewOutput(
+          json_event_string,
+          NULL /* no user data since there was no request */));
     } else {
-      SendMessage(Vector<uint16_t>::empty());
+      SendMessage(Message::NewEmptyMessage());
     }
   } else {
     PrintLn(try_catch.Exception());
@@ -2026,13 +2021,15 @@ bool Debugger::SendEventMessage(Handle<Object> event_data) {
 // by the API client thread.  This is where the API client hands off
 // processing of the command to the DebugMessageThread thread.
 // The new copy of the command is destroyed in HandleCommand().
-void Debugger::ProcessCommand(Vector<const uint16_t> command) {
-  // Make a copy of the command. Need to cast away const for Clone to work.
-  Vector<uint16_t> command_copy =
+void Debugger::ProcessCommand(Vector<const uint16_t> command,
+                              v8::Debug::ClientData* client_data) {
+  // Need to cast away const.
+  Message message = Message::NewCommand(
       Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
-                       command.length()).Clone();
+                       command.length()),
+      client_data);
   Logger::DebugTag("Put command on command_queue.");
-  command_queue_.Put(command_copy);
+  command_queue_.Put(message);
   command_received_->Signal();
 
   // Set the debug command break flag to have the command processed.
@@ -2047,14 +2044,10 @@ bool Debugger::HasCommands() {
 }
 
 
-void Debugger::ProcessHostDispatch(void* dispatch) {
+void Debugger::ProcessHostDispatch(v8::Debug::ClientData* dispatch) {
   // Puts a host dispatch comming from the public API on the queue.
-  uint16_t hack[3];
-  hack[0] = 0;
-  hack[1] = reinterpret_cast<uint32_t>(dispatch) >> 16;
-  hack[2] = reinterpret_cast<uint32_t>(dispatch) & 0xFFFF;
   Logger::DebugTag("Put dispatch on command_queue.");
-  command_queue_.Put(Vector<uint16_t>(hack, 3).Clone());
+  command_queue_.Put(Message::NewHostDispatch(dispatch));
   command_received_->Signal();
 
   // Set the debug command break flag to have the host dispatch processed.
@@ -2134,9 +2127,11 @@ void DebugMessageThread::Run() {
     // Wait and Get are paired so that semaphore count equals queue length.
     Debugger::message_received_->Wait();
     Logger::DebugTag("Get message from event message_queue.");
-    Vector<uint16_t> message = Debugger::message_queue_.Get();
-    if (message.length() > 0) {
+    Message message = Debugger::message_queue_.Get();
+    if (message.text().length() > 0) {
       Debugger::InvokeMessageHandler(message);
+    } else {
+      message.Dispose();
     }
   }
 }
@@ -2144,22 +2139,84 @@ void DebugMessageThread::Run() {
 
 void DebugMessageThread::Stop() {
   keep_running_ = false;
-  Debugger::SendMessage(Vector<uint16_t>(NULL, 0));
+  Debugger::SendMessage(Message::NewEmptyMessage());
   Join();
 }
 
 
+Message::Message() : text_(Vector<uint16_t>::empty()),
+                     client_data_(NULL),
+                     is_host_dispatch_(false) {
+}
+
+
+Message::Message(const Vector<uint16_t>& text,
+                 v8::Debug::ClientData* data,
+                 bool is_host_dispatch)
+    : text_(text),
+      client_data_(data),
+      is_host_dispatch_(is_host_dispatch) {
+}
+
+
+Message::~Message() {
+}
+
+
+void Message::Dispose() {
+  text_.Dispose();
+  delete client_data_;
+  client_data_ = NULL;
+}
+
+
+bool Message::IsHostDispatch() const {
+  return is_host_dispatch_;
+}
+
+
+Message Message::NewCommand(const Vector<uint16_t>& command,
+                            v8::Debug::ClientData* data) {
+  return Message(command.Clone(), data, false);
+}
+
+
+Message Message::NewHostDispatch(v8::Debug::ClientData* dispatch) {
+  return Message(Vector<uint16_t>::empty(), dispatch, true);
+}
+
+
+Message Message::NewOutput(v8::Handle<v8::String> output,
+                           v8::Debug::ClientData* data) {
+  Vector<uint16_t> text;
+  if (!output.IsEmpty()) {
+    text = Vector<uint16_t>::New(output->Length() + 1);
+    output->Write(text.start());
+  }
+  return Message(text, data, false);
+}
+
+
+Message Message::NewEmptyMessage() {
+  return Message();
+}
+
+
 MessageQueue::MessageQueue(int size) : start_(0), end_(0), size_(size) {
-  messages_ = NewArray<Vector<uint16_t> >(size);
+  messages_ = NewArray<Message>(size);
 }
 
 
 MessageQueue::~MessageQueue() {
+  while(!IsEmpty()) {
+    Message m = Get();
+    m.Dispose();
+  }
   DeleteArray(messages_);
 }
 
 
-Vector<uint16_t> MessageQueue::Get() {
+Message MessageQueue::Get() {
   ASSERT(!IsEmpty());
   int result = start_;
   start_ = (start_ + 1) % size_;
@@ -2167,7 +2224,7 @@ Vector<uint16_t> MessageQueue::Get() {
 }
 
 
-void MessageQueue::Put(const Vector<uint16_t>& message) {
+void MessageQueue::Put(const Message& message) {
   if ((end_ + 1) % size_ == start_) {
     Expand();
   }
@@ -2181,9 +2238,11 @@ void MessageQueue::Expand() {
   while (!IsEmpty()) {
     new_queue.Put(Get());
   }
-  Vector<uint16_t>* array_to_free = messages_;
+  Message* array_to_free = messages_;
   *this = new_queue;
   new_queue.messages_ = array_to_free;
+  // Make the new_queue empty so that it doesn't call Dispose on any messages.
+  new_queue.start_ = new_queue.end_;
   // Automatic destructor called on new_queue, freeing array_to_free.
 }
 
@@ -2204,18 +2263,18 @@ bool LockingMessageQueue::IsEmpty() const {
 }
 
 
-Vector<uint16_t> LockingMessageQueue::Get() {
+Message LockingMessageQueue::Get() {
   ScopedLock sl(lock_);
-  Vector<uint16_t> result = queue_.Get();
-  Logger::DebugEvent("Get", result);
+  Message result = queue_.Get();
+  Logger::DebugEvent("Get", result.text());
   return result;
 }
 
 
-void LockingMessageQueue::Put(const Vector<uint16_t>& message) {
+void LockingMessageQueue::Put(const Message& message) {
   ScopedLock sl(lock_);
   queue_.Put(message);
-  Logger::DebugEvent("Put", message);
+  Logger::DebugEvent("Put", message.text());
 }
 
 
index e46b816..69e5c0e 100644 (file)
@@ -397,6 +397,36 @@ class Debug {
 };
 
 
+// Message send by user to v8 debugger or debugger output message.
+// In addition to command text it may contain a pointer to some user data
+// which are expected to be passed along with the command reponse to message
+// handler.
+class Message {
+ public:
+  static Message NewCommand(const Vector<uint16_t>& command,
+                            v8::Debug::ClientData* data);
+  static Message NewHostDispatch(v8::Debug::ClientData* dispatch);
+  static Message NewOutput(v8::Handle<v8::String> output,
+                           v8::Debug::ClientData* data);
+  static Message NewEmptyMessage();
+  Message();
+  ~Message();
+
+  // Deletes user data and disposes of the text.
+  void Dispose();
+  bool IsHostDispatch() const;
+  Vector<uint16_t> text() const { return text_; }
+  v8::Debug::ClientData* client_data() const { return client_data_; }
+ private:
+  Message(const Vector<uint16_t>& text,
+          v8::Debug::ClientData* data,
+          bool is_host_dispatch);
+
+  Vector<uint16_t> text_;
+  v8::Debug::ClientData* client_data_;
+  bool is_host_dispatch_;
+};
+
 // A Queue of Vector<uint16_t> objects.  A thread-safe version is
 // LockingMessageQueue, based on this class.
 class MessageQueue BASE_EMBEDDED {
@@ -404,14 +434,14 @@ class MessageQueue BASE_EMBEDDED {
   explicit MessageQueue(int size);
   ~MessageQueue();
   bool IsEmpty() const { return start_ == end_; }
-  Vector<uint16_t> Get();
-  void Put(const Vector<uint16_t>& message);
+  Message Get();
+  void Put(const Message& message);
   void Clear() { start_ = end_ = 0; }  // Queue is empty after Clear().
  private:
   // Doubles the size of the message queue, and copies the messages.
   void Expand();
 
-  Vector<uint16_t>* messages_;
+  Message* messages_;
   int start_;
   int end_;
   int size_;  // The size of the queue buffer.  Queue can hold size-1 messages.
@@ -427,8 +457,8 @@ class LockingMessageQueue BASE_EMBEDDED {
   explicit LockingMessageQueue(int size);
   ~LockingMessageQueue();
   bool IsEmpty() const;
-  Vector<uint16_t> Get();
-  void Put(const Vector<uint16_t>& message);
+  Message Get();
+  void Put(const Message& message);
   void Clear();
  private:
   MessageQueue queue_;
@@ -473,29 +503,29 @@ class Debugger {
                                    Handle<Object> event_data,
                                    bool auto_continue);
   static void SetEventListener(Handle<Object> callback, Handle<Object> data);
-  static void SetMessageHandler(v8::DebugMessageHandler handler, void* data,
+  static void SetMessageHandler(v8::Debug::MessageHandler handler,
                                 bool message_handler_thread);
   static void TearDown();
-  static void SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
-                                     void* data);
+  static void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler);
 
   // Invoke the message handler function.
-  static void InvokeMessageHandler(Vector< uint16_t> message);
+  static void InvokeMessageHandler(Message message);
 
   // Send a message to the message handler eiher through the message thread or
   // directly.
-  static void SendMessage(Vector<uint16_t> message);
+  static void SendMessage(Message message);
 
   // Send the JSON message for a debug event.
   static bool SendEventMessage(Handle<Object> event_data);
 
   // Add a debugger command to the command queue.
-  static void ProcessCommand(Vector<const uint16_t> command);
+  static void ProcessCommand(Vector<const uint16_t> command,
+                             v8::Debug::ClientData* client_data = NULL);
 
   // Check whether there are commands in the command queue.
   static bool HasCommands();
 
-  static void ProcessHostDispatch(void* dispatch);
+  static void ProcessHostDispatch(v8::Debug::ClientData* dispatch);
   static Handle<Object> Call(Handle<JSFunction> fun,
                              Handle<Object> data,
                              bool* pending_exception);
@@ -539,11 +569,9 @@ class Debugger {
   static bool is_loading_debugger_;  // Are we loading the debugger?
   static bool never_unload_debugger_;  // Can we unload the debugger?
   static DebugMessageThread* message_thread_;
-  static v8::DebugMessageHandler message_handler_;
+  static v8::Debug::MessageHandler message_handler_;
   static bool message_handler_cleared_;  // Was message handler cleared?
-  static void* message_handler_data_;
-  static v8::DebugHostDispatchHandler host_dispatch_handler_;
-  static void* host_dispatch_handler_data_;
+  static v8::Debug::HostDispatchHandler host_dispatch_handler_;
 
   static DebuggerAgent* agent_;
 
index c153593..bc10555 100644 (file)
@@ -45,10 +45,13 @@ using ::v8::internal::JSGlobalProxy;
 using ::v8::internal::Code;
 using ::v8::internal::Debug;
 using ::v8::internal::Debugger;
+using ::v8::internal::Message;
+using ::v8::internal::MessageQueue;
 using ::v8::internal::StepAction;
 using ::v8::internal::StepIn;  // From StepAction enum
 using ::v8::internal::StepNext;  // From StepAction enum
 using ::v8::internal::StepOut;  // From StepAction enum
+using ::v8::internal::Vector;
 
 
 // Size of temp buffer for formatting small strings.
@@ -3375,7 +3378,8 @@ class MessageQueueDebuggerThread : public v8::internal::Thread {
   void Run();
 };
 
-static void MessageHandler(const uint16_t* message, int length, void *data) {
+static void MessageHandler(const uint16_t* message, int length,
+                           v8::Debug::ClientData* client_data) {
   static char print_buffer[1000];
   Utf16ToAscii(message, length, print_buffer);
   if (IsBreakEventMessage(print_buffer)) {
@@ -3390,7 +3394,6 @@ static void MessageHandler(const uint16_t* message, int length, void *data) {
   fflush(stdout);
 }
 
-
 void MessageQueueDebuggerThread::Run() {
   const int kBufferSize = 1000;
   uint16_t buffer_1[kBufferSize];
@@ -3481,6 +3484,114 @@ TEST(MessageQueues) {
   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.
+    MessageQueue queue(1);
+    queue.Put(Message::NewCommand(Vector<uint16_t>::empty(),
+                                  new TestClientData()));
+    queue.Put(Message::NewCommand(Vector<uint16_t>::empty(),
+                                  new TestClientData()));
+    queue.Put(Message::NewHostDispatch(new TestClientData()));
+    ASSERT_EQ(0, TestClientData::destructor_call_counter);
+    queue.Get().Dispose();
+    ASSERT_EQ(1, TestClientData::destructor_call_counter);
+    queue.Put(Message::NewHostDispatch(new TestClientData()));
+    queue.Put(Message::NewHostDispatch(new TestClientData()));
+    queue.Put(Message::NewHostDispatch(new TestClientData()));
+    queue.Put(Message::NewOutput(v8::Handle<v8::String>(),
+                                 new TestClientData()));
+    queue.Put(Message::NewEmptyMessage());
+    ASSERT_EQ(1, TestClientData::destructor_call_counter);
+    queue.Get().Dispose();
+    ASSERT_EQ(2, TestClientData::destructor_call_counter);
+  }
+  // All the client data should be destroyed when the queue is destroyed.
+  ASSERT_EQ(TestClientData::destructor_call_counter,
+            TestClientData::destructor_call_counter);
+}
+
+
+static int handled_client_data_instances_count = 0;
+static void MessageHandlerCountingClientData(
+    const uint16_t* message,
+    int length,
+    v8::Debug::ClientData* client_data) {
+  if (client_data) {
+    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
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  TestClientData::ResetCounters();
+  handled_client_data_instances_count = 0;
+  v8::Debug::SetMessageHandler(MessageHandlerCountingClientData,
+                               false /* message_handler_thread */);
+  const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5; debugger;";
+  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(buffer, AsciiToUtf16(command_1, buffer),
+                         new TestClientData());
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer), NULL);
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
+                         new TestClientData());
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
+                         new TestClientData());
+  v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
+  CompileRun(source_1);
+  ASSERT_EQ(3, TestClientData::constructor_call_counter);
+  ASSERT_EQ(TestClientData::constructor_call_counter,
+            handled_client_data_instances_count);
+  ASSERT_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
@@ -3508,7 +3619,7 @@ static v8::Handle<v8::Value> ThreadedAtBarrier1(const v8::Arguments& args) {
 
 
 static void ThreadedMessageHandler(const uint16_t* message, int length,
-                                   void *data) {
+                                   v8::Debug::ClientData* client_data) {
   static char print_buffer[1000];
   Utf16ToAscii(message, length, print_buffer);
   if (IsBreakEventMessage(print_buffer)) {
@@ -3606,7 +3717,7 @@ Barriers* breakpoints_barriers;
 
 static void BreakpointsMessageHandler(const uint16_t* message,
                                       int length,
-                                      void *data) {
+                                      v8::Debug::ClientData* client_data) {
   static char print_buffer[1000];
   Utf16ToAscii(message, length, print_buffer);
   printf("%s\n", print_buffer);
@@ -3752,7 +3863,8 @@ TEST(SetDebugEventListenerOnUninitializedVM) {
 
 
 static void DummyMessageHandler(const uint16_t* message,
-                                int length, void *data) {
+                                int length,
+                                v8::Debug::ClientData* client_data) {
 }
 
 
@@ -3978,7 +4090,8 @@ TEST(DebuggerUnload) {
 // Debugger message handler which counts the number of times it is called.
 static int message_handler_hit_count = 0;
 static void MessageHandlerHitCount(const uint16_t* message,
-                                   int length, void* data) {
+                                   int length,
+                                   v8::Debug::ClientData* client_data) {
   message_handler_hit_count++;
 
   const int kBufferSize = 1000;
@@ -4026,9 +4139,10 @@ TEST(DebuggerClearMessageHandler) {
 
 
 // Debugger message handler which clears the message handler while active.
-static void MessageHandlerClearingMessageHandler(const uint16_t* message,
-                                                 int length,
-                                                 void* data) {
+static void MessageHandlerClearingMessageHandler(
+    const uint16_t* message,
+    int length,
+    v8::Debug::ClientData* client_data) {
   message_handler_hit_count++;
 
   // Clear debug message handler.
@@ -4059,7 +4173,7 @@ TEST(DebuggerClearMessageHandlerWhileActive) {
 
 
 int host_dispatch_hit_count = 0;
-static void HostDispatchHandlerHitCount(void* dispatch, void *data) {
+static void HostDispatchHandlerHitCount(v8::Debug::ClientData* dispatch) {
   host_dispatch_hit_count++;
 }
 
@@ -4085,8 +4199,7 @@ TEST(DebuggerHostDispatch) {
 
   // Setup message and host dispatch handlers.
   v8::Debug::SetMessageHandler(DummyMessageHandler);
-  v8::Debug::SetHostDispatchHandler(HostDispatchHandlerHitCount,
-                                    NULL);
+  v8::Debug::SetHostDispatchHandler(HostDispatchHandlerHitCount);
 
   // Send a host dispatch by itself.
   v8::Debug::SendHostDispatch(NULL);