Revision: 4693
Author: [email protected]
Date: Thu May 20 10:15:46 2010
Log: Provide debug event listener with access to the debuggee context. Also
introduce new event listener setter that allows to set a callback that
accepts single parameter encapsulating all debug event details so that
additional information can later be passed to the listener without breaking
compatibility with existing clients.
Review URL: http://codereview.chromium.org/2108024
http://code.google.com/p/v8/source/detail?r=4693
Modified:
/branches/bleeding_edge/include/v8-debug.h
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/debug.cc
/branches/bleeding_edge/src/debug.h
/branches/bleeding_edge/test/cctest/test-debug.cc
=======================================
--- /branches/bleeding_edge/include/v8-debug.h Wed Mar 24 06:09:02 2010
+++ /branches/bleeding_edge/include/v8-debug.h Thu May 20 10:15:46 2010
@@ -143,6 +143,39 @@
};
+ /**
+ * An event details object passed to the debug event listener.
+ */
+ class EventDetails {
+ public:
+ /**
+ * Event type.
+ */
+ virtual DebugEvent GetEvent() const = 0;
+
+ /**
+ * Access to execution state and event data of the debug event. Don't
store
+ * these cross callbacks as their content becomes invalid.
+ */
+ virtual Handle<Object> GetExecutionState() const = 0;
+ virtual Handle<Object> GetEventData() const = 0;
+
+ /**
+ * Get the context active when the debug event happened. Note this is
not
+ * the current active context as the JavaScript part of the debugger is
+ * running in it's own context which is entered at this point.
+ */
+ virtual Handle<Context> GetEventContext() const = 0;
+
+ /**
+ * Client data passed with the corresponding callbak whet it was
registered.
+ */
+ virtual Handle<Value> GetCallbackData() const = 0;
+
+ virtual ~EventDetails() {}
+ };
+
+
/**
* Debug event callback function.
*
@@ -157,6 +190,15 @@
Handle<Object> event_data,
Handle<Value> data);
+ /**
+ * Debug event callback function.
+ *
+ * \param event_details object providing information about the debug
event
+ *
+ * A EventCallback2 does not take possession of the event data,
+ * and must not rely on the data persisting after the handler returns.
+ */
+ typedef void (*EventCallback2)(const EventDetails& event_details);
/**
* Debug message callback function.
@@ -165,7 +207,7 @@
* \param length length of the message
* \param client_data the data value passed when registering the message
handler
- * A MessageHandler does not take posession of the message string,
+ * A MessageHandler does not take possession of the message string,
* and must not rely on the data persisting after the handler returns.
*
* This message handler is deprecated. Use MessageHandler2 instead.
@@ -178,7 +220,7 @@
*
* \param message the debug message handler message object
- * A MessageHandler does not take posession of the message data,
+ * A MessageHandler does not take possession of the message data,
* and must not rely on the data persisting after the handler returns.
*/
typedef void (*MessageHandler2)(const Message& message);
@@ -196,6 +238,8 @@
// Set a C debug event listener.
static bool SetDebugEventListener(EventCallback that,
Handle<Value> data = Handle<Value>());
+ static bool SetDebugEventListener2(EventCallback2 that,
+ Handle<Value> data = Handle<Value>());
// Set a JavaScript debug event listener.
static bool SetDebugEventListener(v8::Handle<v8::Object> that,
=======================================
--- /branches/bleeding_edge/src/api.cc Tue May 18 07:19:33 2010
+++ /branches/bleeding_edge/src/api.cc Thu May 20 10:15:46 2010
@@ -3992,10 +3992,40 @@
// --- D e b u g S u p p o r t ---
#ifdef ENABLE_DEBUGGER_SUPPORT
+
+static v8::Debug::EventCallback event_callback = NULL;
+
+static void EventCallbackWrapper(const v8::Debug::EventDetails&
event_details) {
+ if (event_callback) {
+ event_callback(event_details.GetEvent(),
+ event_details.GetExecutionState(),
+ event_details.GetEventData(),
+ event_details.GetCallbackData());
+ }
+}
+
+
bool Debug::SetDebugEventListener(EventCallback that, Handle<Value> data) {
EnsureInitialized("v8::Debug::SetDebugEventListener()");
ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false);
ENTER_V8;
+
+ event_callback = that;
+
+ HandleScope scope;
+ i::Handle<i::Object> proxy = i::Factory::undefined_value();
+ if (that != NULL) {
+ proxy = i::Factory::NewProxy(FUNCTION_ADDR(EventCallbackWrapper));
+ }
+ i::Debugger::SetEventListener(proxy, Utils::OpenHandle(*data));
+ return true;
+}
+
+
+bool Debug::SetDebugEventListener2(EventCallback2 that, Handle<Value>
data) {
+ EnsureInitialized("v8::Debug::SetDebugEventListener2()");
+ ON_BAILOUT("v8::Debug::SetDebugEventListener2()", return false);
+ ENTER_V8;
HandleScope scope;
i::Handle<i::Object> proxy = i::Factory::undefined_value();
if (that != NULL) {
=======================================
--- /branches/bleeding_edge/src/debug.cc Thu May 6 03:50:22 2010
+++ /branches/bleeding_edge/src/debug.cc Thu May 20 10:15:46 2010
@@ -70,6 +70,17 @@
static Handle<Code> ComputeCallDebugPrepareStepIn(int argc) {
CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugPrepareStepIn(argc), Code);
}
+
+
+static v8::Handle<v8::Context> GetDebugEventContext() {
+ Handle<Context> context = Debug::debugger_entry()->GetContext();
+ // Top::context() may have been NULL when "script collected" event
occured.
+ if (*context == NULL) {
+ return v8::Local<v8::Context>();
+ }
+ Handle<Context> global_context(context->global_context());
+ return v8::Utils::ToLocal(global_context);
+}
BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
@@ -2112,12 +2123,14 @@
if (event_listener_->IsProxy()) {
// C debug event listener.
Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_));
- 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(event_data),
-
v8::Utils::ToLocal(Handle<Object>::cast(event_listener_data_)));
+ v8::Debug::EventCallback2 callback =
+
FUNCTION_CAST<v8::Debug::EventCallback2>(callback_obj->proxy());
+ EventDetailsImpl event_details(
+ event,
+ Handle<JSObject>::cast(exec_state),
+ event_data,
+ event_listener_data_);
+ callback(event_details);
} else {
// JavaScript debug event listener.
ASSERT(event_listener_->IsJSFunction());
@@ -2643,20 +2656,51 @@
v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
- Handle<Context> context = Debug::debugger_entry()->GetContext();
- // Top::context() may have been NULL when "script collected" event
occured.
- if (*context == NULL) {
- ASSERT(event_ == v8::ScriptCollected);
- return v8::Local<v8::Context>();
- }
- Handle<Context> global_context(context->global_context());
- return v8::Utils::ToLocal(global_context);
+ v8::Handle<v8::Context> context = GetDebugEventContext();
+ // Top::context() may be NULL when "script collected" event occures.
+ ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
+ return GetDebugEventContext();
}
v8::Debug::ClientData* MessageImpl::GetClientData() const {
return client_data_;
}
+
+
+EventDetailsImpl::EventDetailsImpl(DebugEvent event,
+ Handle<JSObject> exec_state,
+ Handle<JSObject> event_data,
+ Handle<Object> callback_data)
+ : event_(event),
+ exec_state_(exec_state),
+ event_data_(event_data),
+ callback_data_(callback_data) {}
+
+
+DebugEvent EventDetailsImpl::GetEvent() const {
+ return event_;
+}
+
+
+v8::Handle<v8::Object> EventDetailsImpl::GetExecutionState() const {
+ return v8::Utils::ToLocal(exec_state_);
+}
+
+
+v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
+ return v8::Utils::ToLocal(event_data_);
+}
+
+
+v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
+ return GetDebugEventContext();
+}
+
+
+v8::Handle<v8::Value> EventDetailsImpl::GetCallbackData() const {
+ return v8::Utils::ToLocal(callback_data_);
+}
CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
=======================================
--- /branches/bleeding_edge/src/debug.h Wed May 19 02:07:33 2010
+++ /branches/bleeding_edge/src/debug.h Thu May 20 10:15:46 2010
@@ -524,6 +524,27 @@
};
+// Details of the debug event delivered to the debug event listener.
+class EventDetailsImpl : public v8::Debug::EventDetails {
+ public:
+ EventDetailsImpl(DebugEvent event,
+ Handle<JSObject> exec_state,
+ Handle<JSObject> event_data,
+ Handle<Object> callback_data);
+ virtual DebugEvent GetEvent() const;
+ virtual v8::Handle<v8::Object> GetExecutionState() const;
+ virtual v8::Handle<v8::Object> GetEventData() const;
+ virtual v8::Handle<v8::Context> GetEventContext() const;
+ virtual v8::Handle<v8::Value> GetCallbackData() const;
+ private:
+ DebugEvent event_; // Debug event causing the break.
+ Handle<JSObject> exec_state_; // Current execution state.
+ Handle<JSObject> event_data_; // Data associated with the event.
+ Handle<Object> callback_data_; // User data passed with the callback
when
+ // it was registered.
+};
+
+
// 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
=======================================
--- /branches/bleeding_edge/test/cctest/test-debug.cc Thu May 6 03:50:22
2010
+++ /branches/bleeding_edge/test/cctest/test-debug.cc Thu May 20 10:15:46
2010
@@ -6196,7 +6196,28 @@
v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
CHECK_EQ(*context1, *context2);
- // Make sure debugger is unloaded before running other tests.
- v8::internal::ForceUnloadDebugger();
+}
+
+
+static v8::Handle<v8::Value> expected_callback_data;
+static void DebugEventContextChecker(const v8::Debug::EventDetails&
details) {
+ CHECK(details.GetEventContext() == expected_context);
+ CHECK_EQ(expected_callback_data, details.GetCallbackData());
+}
+
+// Check that event details contain context where debug event occured.
+TEST(DebugEventContext) {
+ v8::HandleScope scope;
+ expected_callback_data = v8::Int32::New(2010);
+ v8::Debug::SetDebugEventListener2(DebugEventContextChecker,
+ expected_callback_data);
+ expected_context = v8::Context::New();
+ v8::Context::Scope context_scope(expected_context);
+
v8::Script::Compile(v8::String::New("(function(){debugger;})();"))->Run();
+ expected_context.Dispose();
+ expected_context.Clear();
+ v8::Debug::SetDebugEventListener(NULL);
+ expected_context_data = v8::Handle<v8::Value>();
CheckDebuggerUnloaded();
}
+
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev