From f6a2ccf6b4a6ca1c34c0ea4b691f5c51b2d295e2 Mon Sep 17 00:00:00 2001 From: "yurys@chromium.org" Date: Thu, 20 May 2010 17:15:46 +0000 Subject: [PATCH] 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 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4693 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8-debug.h | 48 +++++++++++++++++++++++++++++-- src/api.cc | 30 ++++++++++++++++++++ src/debug.cc | 72 ++++++++++++++++++++++++++++++++++++++--------- src/debug.h | 21 ++++++++++++++ test/cctest/test-debug.cc | 25 ++++++++++++++-- 5 files changed, 178 insertions(+), 18 deletions(-) diff --git a/include/v8-debug.h b/include/v8-debug.h index f7b4fa1..c53b634 100644 --- a/include/v8-debug.h +++ b/include/v8-debug.h @@ -144,6 +144,39 @@ class EXPORT Debug { /** + * 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 GetExecutionState() const = 0; + virtual Handle 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 GetEventContext() const = 0; + + /** + * Client data passed with the corresponding callbak whet it was registered. + */ + virtual Handle GetCallbackData() const = 0; + + virtual ~EventDetails() {} + }; + + + /** * Debug event callback function. * * \param event the type of the debug event that triggered the callback @@ -157,6 +190,15 @@ class EXPORT Debug { Handle event_data, Handle 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 @@ class EXPORT Debug { * \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 @@ class EXPORT Debug { * * \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 @@ class EXPORT Debug { // Set a C debug event listener. static bool SetDebugEventListener(EventCallback that, Handle data = Handle()); + static bool SetDebugEventListener2(EventCallback2 that, + Handle data = Handle()); // Set a JavaScript debug event listener. static bool SetDebugEventListener(v8::Handle that, diff --git a/src/api.cc b/src/api.cc index 42c8aeb..d944d3c 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3992,10 +3992,40 @@ Local Exception::Error(v8::Handle raw_message) { // --- 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 data) { EnsureInitialized("v8::Debug::SetDebugEventListener()"); ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false); ENTER_V8; + + event_callback = that; + + HandleScope scope; + i::Handle 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 data) { + EnsureInitialized("v8::Debug::SetDebugEventListener2()"); + ON_BAILOUT("v8::Debug::SetDebugEventListener2()", return false); + ENTER_V8; HandleScope scope; i::Handle proxy = i::Factory::undefined_value(); if (that != NULL) { diff --git a/src/debug.cc b/src/debug.cc index bf1f893..8cb95ef 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -72,6 +72,17 @@ static Handle ComputeCallDebugPrepareStepIn(int argc) { } +static v8::Handle GetDebugEventContext() { + Handle context = Debug::debugger_entry()->GetContext(); + // Top::context() may have been NULL when "script collected" event occured. + if (*context == NULL) { + return v8::Local(); + } + Handle global_context(context->global_context()); + return v8::Utils::ToLocal(global_context); +} + + BreakLocationIterator::BreakLocationIterator(Handle debug_info, BreakLocatorType type) { debug_info_ = debug_info; @@ -2112,12 +2123,14 @@ void Debugger::ProcessDebugEvent(v8::DebugEvent event, if (event_listener_->IsProxy()) { // C debug event listener. Handle callback_obj(Handle::cast(event_listener_)); - v8::Debug::EventCallback callback = - FUNCTION_CAST(callback_obj->proxy()); - callback(event, - v8::Utils::ToLocal(Handle::cast(exec_state)), - v8::Utils::ToLocal(event_data), - v8::Utils::ToLocal(Handle::cast(event_listener_data_))); + v8::Debug::EventCallback2 callback = + FUNCTION_CAST(callback_obj->proxy()); + EventDetailsImpl event_details( + event, + Handle::cast(exec_state), + event_data, + event_listener_data_); + callback(event_details); } else { // JavaScript debug event listener. ASSERT(event_listener_->IsJSFunction()); @@ -2643,14 +2656,10 @@ v8::Handle MessageImpl::GetJSON() const { v8::Handle MessageImpl::GetEventContext() const { - Handle 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(); - } - Handle global_context(context->global_context()); - return v8::Utils::ToLocal(global_context); + v8::Handle context = GetDebugEventContext(); + // Top::context() may be NULL when "script collected" event occures. + ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected); + return GetDebugEventContext(); } @@ -2659,6 +2668,41 @@ v8::Debug::ClientData* MessageImpl::GetClientData() const { } +EventDetailsImpl::EventDetailsImpl(DebugEvent event, + Handle exec_state, + Handle event_data, + Handle callback_data) + : event_(event), + exec_state_(exec_state), + event_data_(event_data), + callback_data_(callback_data) {} + + +DebugEvent EventDetailsImpl::GetEvent() const { + return event_; +} + + +v8::Handle EventDetailsImpl::GetExecutionState() const { + return v8::Utils::ToLocal(exec_state_); +} + + +v8::Handle EventDetailsImpl::GetEventData() const { + return v8::Utils::ToLocal(event_data_); +} + + +v8::Handle EventDetailsImpl::GetEventContext() const { + return GetDebugEventContext(); +} + + +v8::Handle EventDetailsImpl::GetCallbackData() const { + return v8::Utils::ToLocal(callback_data_); +} + + CommandMessage::CommandMessage() : text_(Vector::empty()), client_data_(NULL) { } diff --git a/src/debug.h b/src/debug.h index 9b8d389..e2eecb8 100644 --- a/src/debug.h +++ b/src/debug.h @@ -524,6 +524,27 @@ class MessageImpl: public v8::Debug::Message { }; +// Details of the debug event delivered to the debug event listener. +class EventDetailsImpl : public v8::Debug::EventDetails { + public: + EventDetailsImpl(DebugEvent event, + Handle exec_state, + Handle event_data, + Handle callback_data); + virtual DebugEvent GetEvent() const; + virtual v8::Handle GetExecutionState() const; + virtual v8::Handle GetEventData() const; + virtual v8::Handle GetEventContext() const; + virtual v8::Handle GetCallbackData() const; + private: + DebugEvent event_; // Debug event causing the break. + Handle exec_state_; // Current execution state. + Handle event_data_; // Data associated with the event. + Handle 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 diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index d90be8e..4b4c950 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -6196,7 +6196,28 @@ TEST(DebugContextIsPreservedBetweenAccesses) { v8::Local context1 = v8::Debug::GetDebugContext(); v8::Local context2 = v8::Debug::GetDebugContext(); CHECK_EQ(*context1, *context2); - // Make sure debugger is unloaded before running other tests. - v8::internal::ForceUnloadDebugger(); +} + + +static v8::Handle 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(); CheckDebuggerUnloaded(); } + -- 2.7.4