Author: [email protected]
Date: Tue Apr 21 07:06:48 2009
New Revision: 1755
Modified:
branches/bleeding_edge/include/v8-debug.h
branches/bleeding_edge/src/api.cc
branches/bleeding_edge/src/debug-agent.cc
branches/bleeding_edge/src/debug-agent.h
branches/bleeding_edge/src/debug.cc
branches/bleeding_edge/src/debug.h
branches/bleeding_edge/test/cctest/test-debug.cc
Log:
As long as all debugger messages are handled by a single static method we
need a way to identify request sender to route the response to the right
handler. To accomplish this clients can send some additional data along
with command text and debugger will later pass this data to the message
handler along with the response text.
Review URL: http://codereview.chromium.org/67266
Modified: branches/bleeding_edge/include/v8-debug.h
==============================================================================
--- branches/bleeding_edge/include/v8-debug.h (original)
+++ branches/bleeding_edge/include/v8-debug.h Tue Apr 21 07:06:48 2009
@@ -79,48 +79,60 @@
};
-/**
- * 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 @@
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.
Modified: branches/bleeding_edge/src/api.cc
==============================================================================
--- branches/bleeding_edge/src/api.cc (original)
+++ branches/bleeding_edge/src/api.cc Tue Apr 21 07:06:48 2009
@@ -3230,7 +3230,7 @@
// --- 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::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);
}
Modified: branches/bleeding_edge/src/debug-agent.cc
==============================================================================
--- branches/bleeding_edge/src/debug-agent.cc (original)
+++ branches/bleeding_edge/src/debug-agent.cc Tue Apr 21 07:06:48 2009
@@ -35,10 +35,12 @@
// 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() {
Modified: branches/bleeding_edge/src/debug-agent.h
==============================================================================
--- branches/bleeding_edge/src/debug-agent.h (original)
+++ branches/bleeding_edge/src/debug-agent.h Tue Apr 21 07:06:48 2009
@@ -46,8 +46,14 @@
: 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 @@
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);
};
Modified: branches/bleeding_edge/src/debug.cc
==============================================================================
--- branches/bleeding_edge/src/debug.cc (original)
+++ branches/bleeding_edge/src/debug.cc Tue Apr 21 07:06:48 2009
@@ -1398,11 +1398,9 @@
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 @@
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 @@
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 @@
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 @@
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::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::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 @@
// 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 @@
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 @@
// 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 @@
}
-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 @@
// 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::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 @@
}
-void MessageQueue::Put(const Vector<uint16_t>& message) {
+void MessageQueue::Put(const Message& message) {
if ((end_ + 1) % size_ == start_) {
Expand();
}
@@ -2181,9 +2238,11 @@
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 @@
}
-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());
}
Modified: branches/bleeding_edge/src/debug.h
==============================================================================
--- branches/bleeding_edge/src/debug.h (original)
+++ branches/bleeding_edge/src/debug.h Tue Apr 21 07:06:48 2009
@@ -397,6 +397,36 @@
};
+// 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 @@
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 @@
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 @@
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 @@
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_;
Modified: branches/bleeding_edge/test/cctest/test-debug.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-debug.cc (original)
+++ branches/bleeding_edge/test/cctest/test-debug.cc Tue Apr 21 07:06:48
2009
@@ -45,10 +45,13 @@
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 @@
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 @@
fflush(stdout);
}
-
void MessageQueueDebuggerThread::Run() {
const int kBufferSize = 1000;
uint16_t buffer_1[kBufferSize];
@@ -3481,6 +3484,114 @@
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 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 @@
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 @@
static void DummyMessageHandler(const uint16_t* message,
- int length, void *data) {
+ int length,
+ v8::Debug::ClientData* client_data) {
}
@@ -3978,7 +4090,8 @@
// 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 @@
// 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 @@
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 @@
// 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);
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---