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

Reply via email to