Commit f6a2ccf6 authored by yurys@chromium.org's avatar yurys@chromium.org

Provide debug event listener with access to the debuggee context. Also...

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
parent ac60f498
......@@ -143,6 +143,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<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 @@ class EXPORT Debug {
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 @@ 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<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,
......
......@@ -3992,10 +3992,40 @@ 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
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) {
......
......@@ -72,6 +72,17 @@ static Handle<Code> ComputeCallDebugPrepareStepIn(int argc) {
}
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,
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<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,14 +2656,10 @@ v8::Handle<v8::String> MessageImpl::GetJSON() const {
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();
}
......@@ -2659,6 +2668,41 @@ v8::Debug::ClientData* MessageImpl::GetClientData() const {
}
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()),
client_data_(NULL) {
}
......
......@@ -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<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
......
......@@ -6196,7 +6196,28 @@ TEST(DebugContextIsPreservedBetweenAccesses) {
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();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment