Commit f3dcdf88 authored by kozyatinskiy's avatar kozyatinskiy Committed by Commit bot

[inspector] introduced debug::SetBreakEventListener,SetExceptionEventListener

Inspector is moved to per-event-type callbacks instead of general v8::debug::SetDebugEventListener. It allows to:
- remove any usage of v8::Debug::EventDetails in debug-interface,
- avoid redundant JS call on each event to get properties of event objects,
- introduce better pure C++ API for these events later.

BUG=v8:5510
R=yangguo@chromium.org,jgruber@chromium.org,dgozman@chromium.org

Review-Url: https://codereview.chromium.org/2622253004
Cr-Commit-Position: refs/heads/master@{#42483}
parent ea4f834c
...@@ -8987,19 +8987,6 @@ MaybeLocal<Array> Debug::GetInternalProperties(Isolate* v8_isolate, ...@@ -8987,19 +8987,6 @@ MaybeLocal<Array> Debug::GetInternalProperties(Isolate* v8_isolate,
return Utils::ToLocal(result); return Utils::ToLocal(result);
} }
bool debug::SetDebugEventListener(Isolate* isolate, debug::EventCallback that,
Local<Value> data) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
ENTER_V8(i_isolate);
i::HandleScope scope(i_isolate);
i::Handle<i::Object> foreign = i_isolate->factory()->undefined_value();
if (that != NULL) {
foreign = i_isolate->factory()->NewForeign(FUNCTION_ADDR(that));
}
i_isolate->debug()->SetEventListener(foreign, Utils::OpenHandle(*data, true));
return true;
}
Local<Context> debug::GetDebugContext(Isolate* isolate) { Local<Context> debug::GetDebugContext(Isolate* isolate) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
ENTER_V8(i_isolate); ENTER_V8(i_isolate);
...@@ -9331,20 +9318,11 @@ MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate, ...@@ -9331,20 +9318,11 @@ MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate,
RETURN_ESCAPED(ToApiHandle<UnboundScript>(result)); RETURN_ESCAPED(ToApiHandle<UnboundScript>(result));
} }
void debug::SetAsyncTaskListener(Isolate* v8_isolate, void debug::SetDebugEventListener(Isolate* v8_isolate,
debug::AsyncTaskListener listener, debug::DebugEventListener* listener) {
void* data) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8(isolate);
isolate->debug()->SetAsyncTaskListener(listener, data);
}
void debug::SetCompileEventListener(Isolate* v8_isolate,
debug::CompileEventListener listener,
void* data) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8(isolate); ENTER_V8(isolate);
isolate->debug()->SetCompileEventListener(listener, data); isolate->debug()->SetDebugEventListener(listener);
} }
Local<String> CpuProfileNode::GetFunctionName() const { Local<String> CpuProfileNode::GetFunctionName() const {
......
...@@ -16,52 +16,6 @@ ...@@ -16,52 +16,6 @@
namespace v8 { namespace v8 {
namespace debug { namespace debug {
/**
* An event details object passed to the debug event listener.
*/
class EventDetails : public v8::Debug::EventDetails {
public:
/**
* Event type.
*/
virtual v8::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 Local<Object> GetExecutionState() const = 0;
virtual Local<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 its own context which is entered at this point.
*/
virtual Local<Context> GetEventContext() const = 0;
/**
* Client data passed with the corresponding callback when it was
* registered.
*/
virtual Local<Value> GetCallbackData() const = 0;
virtual ~EventDetails() {}
};
/**
* Debug event callback function.
*
* \param event_details object providing information about the debug event
*
* A EventCallback does not take possession of the event data,
* and must not rely on the data persisting after the handler returns.
*/
typedef void (*EventCallback)(const EventDetails& event_details);
bool SetDebugEventListener(Isolate* isolate, EventCallback that,
Local<Value> data = Local<Value>());
/** /**
* Debugger is running in its own context which is entered while debugger * Debugger is running in its own context which is entered while debugger
* messages are being dispatched. This is an explicit getter for this * messages are being dispatched. This is an explicit getter for this
...@@ -193,17 +147,23 @@ void GetLoadedScripts(Isolate* isolate, PersistentValueVector<Script>& scripts); ...@@ -193,17 +147,23 @@ void GetLoadedScripts(Isolate* isolate, PersistentValueVector<Script>& scripts);
MaybeLocal<UnboundScript> CompileInspectorScript(Isolate* isolate, MaybeLocal<UnboundScript> CompileInspectorScript(Isolate* isolate,
Local<String> source); Local<String> source);
typedef std::function<void(debug::PromiseDebugActionType type, int id, class DebugEventListener {
void* data)> public:
AsyncTaskListener; virtual ~DebugEventListener() {}
void SetAsyncTaskListener(Isolate* isolate, AsyncTaskListener listener, virtual void PromiseEventOccurred(debug::PromiseDebugActionType type,
void* data); int id) {}
virtual void ScriptCompiled(v8::Local<Script> script,
typedef std::function<void(v8::Local<Script> script, bool has_compile_error, bool has_compile_error) {}
void* data)> virtual void BreakProgramRequested(v8::Local<v8::Context> paused_context,
CompileEventListener; v8::Local<v8::Object> exec_state,
void SetCompileEventListener(Isolate* isolate, CompileEventListener listener, v8::Local<v8::Value> break_points_hit) {}
void* data); virtual void ExceptionThrown(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object> exec_state,
v8::Local<v8::Value> exception,
bool is_promise_rejection, bool is_uncaught) {}
};
void SetDebugEventListener(Isolate* isolate, DebugEventListener* listener);
} // namespace debug } // namespace debug
} // namespace v8 } // namespace v8
......
...@@ -1715,6 +1715,16 @@ void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) { ...@@ -1715,6 +1715,16 @@ void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) {
} }
} }
namespace {
v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
// Isolate::context() may have been NULL when "script collected" event
// occured.
if (context.is_null()) return v8::Local<v8::Context>();
Handle<Context> native_context(context->native_context());
return v8::Utils::ToLocal(native_context);
}
} // anonymous namespace
void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
// We cannot generate debug events when JS execution is disallowed. // We cannot generate debug events when JS execution is disallowed.
...@@ -1754,6 +1764,21 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { ...@@ -1754,6 +1764,21 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
DebugScope debug_scope(this); DebugScope debug_scope(this);
if (debug_scope.failed()) return; if (debug_scope.failed()) return;
if (debug_event_listener_) {
HandleScope scope(isolate_);
// Create the execution state.
Handle<Object> exec_state;
// Bail out and don't call debugger if exception.
if (!MakeExecutionState().ToHandle(&exec_state)) return;
debug_event_listener_->ExceptionThrown(
GetDebugEventContext(isolate_),
v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
v8::Utils::ToLocal(exception), promise->IsJSObject(), uncaught);
if (!non_inspector_listener_exists()) return;
}
// Create the event data object. // Create the event data object.
Handle<Object> event_data; Handle<Object> event_data;
// Bail out and don't call debugger if exception. // Bail out and don't call debugger if exception.
...@@ -1777,6 +1802,24 @@ void Debug::OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue) { ...@@ -1777,6 +1802,24 @@ void Debug::OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue) {
PrintBreakLocation(); PrintBreakLocation();
#endif // DEBUG #endif // DEBUG
if (debug_event_listener_) {
HandleScope scope(isolate_);
// Create the execution state.
Handle<Object> exec_state;
// Bail out and don't call debugger if exception.
if (!MakeExecutionState().ToHandle(&exec_state)) return;
bool previous = in_debug_event_listener_;
in_debug_event_listener_ = true;
debug_event_listener_->BreakProgramRequested(
GetDebugEventContext(isolate_),
v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
v8::Utils::ToLocal(break_points_hit));
in_debug_event_listener_ = previous;
if (!non_inspector_listener_exists()) return;
}
HandleScope scope(isolate_); HandleScope scope(isolate_);
// Create the event data object. // Create the event data object.
Handle<Object> event_data; Handle<Object> event_data;
...@@ -1854,18 +1897,11 @@ int Debug::NextAsyncTaskId(Handle<JSObject> promise) { ...@@ -1854,18 +1897,11 @@ int Debug::NextAsyncTaskId(Handle<JSObject> promise) {
return async_id->value(); return async_id->value();
} }
void Debug::SetAsyncTaskListener(debug::AsyncTaskListener listener,
void* data) {
async_task_listener_ = listener;
async_task_listener_data_ = data;
UpdateState();
}
void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id) { void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id) {
if (in_debug_scope() || ignore_events()) return; if (in_debug_scope() || ignore_events()) return;
if (async_task_listener_) { if (debug_event_listener_) {
async_task_listener_(type, id, async_task_listener_data_); debug_event_listener_->PromiseEventOccurred(type, id);
if (!non_inspector_listener_exists()) return; if (!non_inspector_listener_exists()) return;
} }
...@@ -1920,7 +1956,7 @@ void Debug::CallEventCallback(v8::DebugEvent event, ...@@ -1920,7 +1956,7 @@ void Debug::CallEventCallback(v8::DebugEvent event,
in_debug_event_listener_ = true; in_debug_event_listener_ = true;
if (event_listener_->IsForeign()) { if (event_listener_->IsForeign()) {
// Invoke the C debug event listener. // Invoke the C debug event listener.
debug::EventCallback callback = FUNCTION_CAST<debug::EventCallback>( v8::Debug::EventCallback callback = FUNCTION_CAST<v8::Debug::EventCallback>(
Handle<Foreign>::cast(event_listener_)->foreign_address()); Handle<Foreign>::cast(event_listener_)->foreign_address());
EventDetailsImpl event_details(event, EventDetailsImpl event_details(event,
Handle<JSObject>::cast(exec_state), Handle<JSObject>::cast(exec_state),
...@@ -1945,13 +1981,6 @@ void Debug::CallEventCallback(v8::DebugEvent event, ...@@ -1945,13 +1981,6 @@ void Debug::CallEventCallback(v8::DebugEvent event,
in_debug_event_listener_ = previous; in_debug_event_listener_ = previous;
} }
void Debug::SetCompileEventListener(debug::CompileEventListener listener,
void* data) {
compile_event_listener_ = listener;
compile_event_listener_data_ = data;
UpdateState();
}
void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) {
if (ignore_events()) return; if (ignore_events()) return;
if (script->type() != i::Script::TYPE_NORMAL && if (script->type() != i::Script::TYPE_NORMAL &&
...@@ -1963,10 +1992,9 @@ void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { ...@@ -1963,10 +1992,9 @@ void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) {
DebugScope debug_scope(this); DebugScope debug_scope(this);
if (debug_scope.failed()) return; if (debug_scope.failed()) return;
if (compile_event_listener_) { if (debug_event_listener_) {
compile_event_listener_(ToApiHandle<debug::Script>(script), debug_event_listener_->ScriptCompiled(ToApiHandle<debug::Script>(script),
event != v8::AfterCompile, event != v8::AfterCompile);
compile_event_listener_data_);
if (!non_inspector_listener_exists()) return; if (!non_inspector_listener_exists()) return;
} }
...@@ -2162,10 +2190,14 @@ void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) { ...@@ -2162,10 +2190,14 @@ void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) {
} }
} }
void Debug::SetDebugEventListener(debug::DebugEventListener* listener) {
debug_event_listener_ = listener;
UpdateState();
}
void Debug::UpdateState() { void Debug::UpdateState() {
bool is_active = message_handler_ != nullptr || !event_listener_.is_null() || bool is_active = message_handler_ != nullptr || !event_listener_.is_null() ||
async_task_listener_ != nullptr || debug_event_listener_ != nullptr;
compile_event_listener_ != nullptr;
if (is_active || in_debug_scope()) { if (is_active || in_debug_scope()) {
// Note that the debug context could have already been loaded to // Note that the debug context could have already been loaded to
// bootstrap test cases. // bootstrap test cases.
...@@ -2503,17 +2535,6 @@ v8::Local<v8::String> MessageImpl::GetJSON() const { ...@@ -2503,17 +2535,6 @@ v8::Local<v8::String> MessageImpl::GetJSON() const {
} }
} }
namespace {
v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
// Isolate::context() may have been NULL when "script collected" event
// occured.
if (context.is_null()) return v8::Local<v8::Context>();
Handle<Context> native_context(context->native_context());
return v8::Utils::ToLocal(native_context);
}
} // anonymous namespace
v8::Local<v8::Context> MessageImpl::GetEventContext() const { v8::Local<v8::Context> MessageImpl::GetEventContext() const {
Isolate* isolate = event_data_->GetIsolate(); Isolate* isolate = event_data_->GetIsolate();
v8::Local<v8::Context> context = GetDebugEventContext(isolate); v8::Local<v8::Context> context = GetDebugEventContext(isolate);
......
...@@ -286,7 +286,7 @@ class MessageImpl : public v8::Debug::Message { ...@@ -286,7 +286,7 @@ class MessageImpl : public v8::Debug::Message {
}; };
// Details of the debug event delivered to the debug event listener. // Details of the debug event delivered to the debug event listener.
class EventDetailsImpl : public debug::EventDetails { class EventDetailsImpl : public v8::Debug::EventDetails {
public: public:
EventDetailsImpl(DebugEvent event, EventDetailsImpl(DebugEvent event,
Handle<JSObject> exec_state, Handle<JSObject> exec_state,
...@@ -466,9 +466,7 @@ class Debug { ...@@ -466,9 +466,7 @@ class Debug {
int NextAsyncTaskId(Handle<JSObject> promise); int NextAsyncTaskId(Handle<JSObject> promise);
void SetAsyncTaskListener(debug::AsyncTaskListener listener, void* data); void SetDebugEventListener(debug::DebugEventListener* listener);
void SetCompileEventListener(debug::CompileEventListener listener,
void* data);
// Returns whether the operation succeeded. Compilation can only be triggered // Returns whether the operation succeeded. Compilation can only be triggered
// if a valid closure is passed as the second argument, otherwise the shared // if a valid closure is passed as the second argument, otherwise the shared
...@@ -679,10 +677,7 @@ class Debug { ...@@ -679,10 +677,7 @@ class Debug {
v8::Debug::MessageHandler message_handler_; v8::Debug::MessageHandler message_handler_;
debug::AsyncTaskListener async_task_listener_ = nullptr; debug::DebugEventListener* debug_event_listener_ = nullptr;
void* async_task_listener_data_ = nullptr;
debug::CompileEventListener compile_event_listener_ = nullptr;
void* compile_event_listener_data_ = nullptr;
static const int kQueueInitialSize = 4; static const int kQueueInitialSize = 4;
base::Semaphore command_received_; // Signaled for each command received. base::Semaphore command_received_; // Signaled for each command received.
......
...@@ -239,11 +239,10 @@ DebuggerScript.setBreakpointsActivated = function(execState, info) ...@@ -239,11 +239,10 @@ DebuggerScript.setBreakpointsActivated = function(execState, info)
} }
/** /**
* @param {!BreakEvent} eventData * @param {!Array<!BreakPoint>|undefined} breakpoints
*/ */
DebuggerScript.getBreakpointNumbers = function(eventData) DebuggerScript.getBreakpointNumbers = function(breakpoints)
{ {
var breakpoints = eventData.breakPointsHit();
var numbers = []; var numbers = [];
if (!breakpoints) if (!breakpoints)
return numbers; return numbers;
......
...@@ -159,13 +159,6 @@ BreakPoint.prototype.script_break_point = function() {} ...@@ -159,13 +159,6 @@ BreakPoint.prototype.script_break_point = function() {}
BreakPoint.prototype.number = function() {} BreakPoint.prototype.number = function() {}
/** @interface */
function BreakEvent() {}
/** @return {!Array<!BreakPoint>|undefined} */
BreakEvent.prototype.breakPointsHit = function() {}
/** @interface */ /** @interface */
function ExecutionState() {} function ExecutionState() {}
......
...@@ -68,12 +68,7 @@ void V8Debugger::enable() { ...@@ -68,12 +68,7 @@ void V8Debugger::enable() {
if (m_enableCount++) return; if (m_enableCount++) return;
DCHECK(!enabled()); DCHECK(!enabled());
v8::HandleScope scope(m_isolate); v8::HandleScope scope(m_isolate);
v8::debug::SetDebugEventListener(m_isolate, &V8Debugger::v8DebugEventCallback, v8::debug::SetDebugEventListener(m_isolate, this);
v8::External::New(m_isolate, this));
v8::debug::SetAsyncTaskListener(m_isolate, &V8Debugger::v8AsyncTaskListener,
this);
v8::debug::SetCompileEventListener(m_isolate,
&V8Debugger::v8CompileEventListener, this);
v8::debug::SetOutOfMemoryCallback(m_isolate, &V8Debugger::v8OOMCallback, v8::debug::SetOutOfMemoryCallback(m_isolate, &V8Debugger::v8OOMCallback,
this); this);
m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate));
...@@ -91,8 +86,6 @@ void V8Debugger::disable() { ...@@ -91,8 +86,6 @@ void V8Debugger::disable() {
allAsyncTasksCanceled(); allAsyncTasksCanceled();
m_wasmTranslation.Clear(); m_wasmTranslation.Clear();
v8::debug::SetDebugEventListener(m_isolate, nullptr); v8::debug::SetDebugEventListener(m_isolate, nullptr);
v8::debug::SetAsyncTaskListener(m_isolate, nullptr, nullptr);
v8::debug::SetCompileEventListener(m_isolate, nullptr, nullptr);
v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr); v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr);
m_isolate->RestoreOriginalHeapLimit(); m_isolate->RestoreOriginalHeapLimit();
} }
...@@ -526,119 +519,77 @@ void V8Debugger::v8OOMCallback(void* data) { ...@@ -526,119 +519,77 @@ void V8Debugger::v8OOMCallback(void* data) {
thisPtr->setPauseOnNextStatement(true); thisPtr->setPauseOnNextStatement(true);
} }
void V8Debugger::v8DebugEventCallback( void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script,
const v8::debug::EventDetails& eventDetails) { bool has_compile_error) {
V8Debugger* thisPtr = toV8Debugger(eventDetails.GetCallbackData());
thisPtr->handleV8DebugEvent(eventDetails);
}
v8::Local<v8::Value> V8Debugger::callInternalGetterFunction(
v8::Local<v8::Object> object, const char* functionName) {
v8::MicrotasksScope microtasks(m_isolate,
v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Local<v8::Value> getterValue =
object
->Get(m_isolate->GetCurrentContext(),
toV8StringInternalized(m_isolate, functionName))
.ToLocalChecked();
DCHECK(!getterValue.IsEmpty() && getterValue->IsFunction());
return v8::Local<v8::Function>::Cast(getterValue)
->Call(m_isolate->GetCurrentContext(), object, 0, nullptr)
.ToLocalChecked();
}
void V8Debugger::handleV8DebugEvent(
const v8::debug::EventDetails& eventDetails) {
if (!enabled()) return;
v8::HandleScope scope(m_isolate);
v8::DebugEvent event = eventDetails.GetEvent();
if (event != v8::Break && event != v8::Exception) return;
v8::Local<v8::Context> eventContext = eventDetails.GetEventContext();
DCHECK(!eventContext.IsEmpty());
V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup(
m_inspector->contextGroupId(eventContext));
if (!agent) return;
if (event == v8::Exception) {
v8::Local<v8::Context> context = debuggerContext();
v8::Local<v8::Object> eventData = eventDetails.GetEventData();
v8::Local<v8::Value> exception =
callInternalGetterFunction(eventData, "exception");
v8::Local<v8::Value> promise =
callInternalGetterFunction(eventData, "promise");
bool isPromiseRejection = !promise.IsEmpty() && promise->IsObject();
v8::Local<v8::Value> uncaught =
callInternalGetterFunction(eventData, "uncaught");
bool isUncaught = uncaught->BooleanValue(context).FromJust();
handleProgramBreak(eventContext, eventDetails.GetExecutionState(),
exception, v8::Local<v8::Array>(), isPromiseRejection,
isUncaught);
} else if (event == v8::Break) {
v8::Local<v8::Value> argv[] = {eventDetails.GetEventData()};
v8::Local<v8::Value> hitBreakpoints;
if (!callDebuggerMethod("getBreakpointNumbers", 1, argv)
.ToLocal(&hitBreakpoints))
return;
DCHECK(hitBreakpoints->IsArray());
handleProgramBreak(eventContext, eventDetails.GetExecutionState(),
v8::Local<v8::Value>(), hitBreakpoints.As<v8::Array>());
}
}
void V8Debugger::v8CompileEventListener(v8::Local<v8::debug::Script> script,
bool has_compile_error, void* data) {
V8Debugger* debugger = static_cast<V8Debugger*>(data);
v8::Local<v8::Value> contextData; v8::Local<v8::Value> contextData;
if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) {
return; return;
} }
int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value());
int contextGroupId = debugger->m_inspector->contextGroupId(contextId); int contextGroupId = m_inspector->contextGroupId(contextId);
if (!contextGroupId) return; if (!contextGroupId) return;
V8DebuggerAgentImpl* agent = V8DebuggerAgentImpl* agent =
debugger->m_inspector->enabledDebuggerAgentForGroup(contextGroupId); m_inspector->enabledDebuggerAgentForGroup(contextGroupId);
if (!agent) return; if (!agent) return;
if (script->IsWasm()) { if (script->IsWasm()) {
debugger->m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), agent);
agent); } else if (m_ignoreScriptParsedEventsCounter == 0) {
} else if (debugger->m_ignoreScriptParsedEventsCounter == 0) {
agent->didParseSource( agent->didParseSource(
V8DebuggerScript::Create(debugger->m_isolate, script, inLiveEditScope), V8DebuggerScript::Create(m_isolate, script, inLiveEditScope),
!has_compile_error); !has_compile_error);
} }
} }
void V8Debugger::v8AsyncTaskListener(v8::debug::PromiseDebugActionType type, void V8Debugger::BreakProgramRequested(v8::Local<v8::Context> pausedContext,
int id, void* data) { v8::Local<v8::Object> execState,
V8Debugger* debugger = static_cast<V8Debugger*>(data); v8::Local<v8::Value> breakPointsHit) {
if (!debugger->m_maxAsyncCallStackDepth) return; v8::Local<v8::Value> argv[] = {breakPointsHit};
v8::Local<v8::Value> hitBreakpoints;
if (!callDebuggerMethod("getBreakpointNumbers", 1, argv)
.ToLocal(&hitBreakpoints)) {
return;
}
DCHECK(hitBreakpoints->IsArray());
handleProgramBreak(pausedContext, execState, v8::Local<v8::Value>(),
hitBreakpoints.As<v8::Array>());
}
void V8Debugger::ExceptionThrown(v8::Local<v8::Context> pausedContext,
v8::Local<v8::Object> execState,
v8::Local<v8::Value> exception,
bool isPromiseRejection, bool isUncaught) {
handleProgramBreak(pausedContext, execState, exception,
v8::Local<v8::Array>(), isPromiseRejection, isUncaught);
}
void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
int id) {
if (!m_maxAsyncCallStackDepth) return;
// Async task events from Promises are given misaligned pointers to prevent // Async task events from Promises are given misaligned pointers to prevent
// from overlapping with other Blink task identifiers. There is a single // from overlapping with other Blink task identifiers. There is a single
// namespace of such ids, managed by src/js/promise.js. // namespace of such ids, managed by src/js/promise.js.
void* ptr = reinterpret_cast<void*>(id * 2 + 1); void* ptr = reinterpret_cast<void*>(id * 2 + 1);
switch (type) { switch (type) {
case v8::debug::kDebugEnqueueAsyncFunction: case v8::debug::kDebugEnqueueAsyncFunction:
debugger->asyncTaskScheduled("async function", ptr, true); asyncTaskScheduled("async function", ptr, true);
break; break;
case v8::debug::kDebugEnqueuePromiseResolve: case v8::debug::kDebugEnqueuePromiseResolve:
debugger->asyncTaskScheduled("Promise.resolve", ptr, true); asyncTaskScheduled("Promise.resolve", ptr, true);
break; break;
case v8::debug::kDebugEnqueuePromiseReject: case v8::debug::kDebugEnqueuePromiseReject:
debugger->asyncTaskScheduled("Promise.reject", ptr, true); asyncTaskScheduled("Promise.reject", ptr, true);
break; break;
case v8::debug::kDebugEnqueuePromiseResolveThenableJob: case v8::debug::kDebugEnqueuePromiseResolveThenableJob:
debugger->asyncTaskScheduled("PromiseResolveThenableJob", ptr, true); asyncTaskScheduled("PromiseResolveThenableJob", ptr, true);
break; break;
case v8::debug::kDebugPromiseCollected: case v8::debug::kDebugPromiseCollected:
debugger->asyncTaskCanceled(ptr); asyncTaskCanceled(ptr);
break; break;
case v8::debug::kDebugWillHandle: case v8::debug::kDebugWillHandle:
debugger->asyncTaskStarted(ptr); asyncTaskStarted(ptr);
break; break;
case v8::debug::kDebugDidHandle: case v8::debug::kDebugDidHandle:
debugger->asyncTaskFinished(ptr); asyncTaskFinished(ptr);
break; break;
} }
} }
......
...@@ -26,7 +26,7 @@ class V8StackTraceImpl; ...@@ -26,7 +26,7 @@ class V8StackTraceImpl;
using protocol::Response; using protocol::Response;
class V8Debugger { class V8Debugger : public v8::debug::DebugEventListener {
public: public:
V8Debugger(v8::Isolate*, V8InspectorImpl*); V8Debugger(v8::Isolate*, V8InspectorImpl*);
~V8Debugger(); ~V8Debugger();
...@@ -112,14 +112,6 @@ class V8Debugger { ...@@ -112,14 +112,6 @@ class V8Debugger {
v8::Local<v8::Array> hitBreakpoints, v8::Local<v8::Array> hitBreakpoints,
bool isPromiseRejection = false, bool isPromiseRejection = false,
bool isUncaught = false); bool isUncaught = false);
static void v8DebugEventCallback(const v8::debug::EventDetails&);
v8::Local<v8::Value> callInternalGetterFunction(v8::Local<v8::Object>,
const char* functionName);
void handleV8DebugEvent(const v8::debug::EventDetails&);
static void v8AsyncTaskListener(v8::debug::PromiseDebugActionType type,
int id, void* data);
static void v8CompileEventListener(v8::Local<v8::debug::Script> script,
bool has_compile_error, void* data);
v8::Local<v8::Value> collectionEntries(v8::Local<v8::Context>, v8::Local<v8::Value> collectionEntries(v8::Local<v8::Context>,
v8::Local<v8::Object>); v8::Local<v8::Object>);
...@@ -141,6 +133,19 @@ class V8Debugger { ...@@ -141,6 +133,19 @@ class V8Debugger {
v8::MaybeLocal<v8::Value> generatorScopes(v8::Local<v8::Context>, v8::MaybeLocal<v8::Value> generatorScopes(v8::Local<v8::Context>,
v8::Local<v8::Value>); v8::Local<v8::Value>);
// v8::debug::DebugEventListener implementation.
void PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
int id) override;
void ScriptCompiled(v8::Local<v8::debug::Script> script,
bool has_compile_error) override;
void BreakProgramRequested(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object> exec_state,
v8::Local<v8::Value> break_points_hit) override;
void ExceptionThrown(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object> exec_state,
v8::Local<v8::Value> exception,
bool is_promise_rejection, bool is_uncaught) override;
v8::Isolate* m_isolate; v8::Isolate* m_isolate;
V8InspectorImpl* m_inspector; V8InspectorImpl* m_inspector;
int m_enableCount; int m_enableCount;
......
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