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

[inspector] introduced debug::SetAsyncTaskListener

If installed, this listener is called instead of general DebugEventListener.

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

Review-Url: https://codereview.chromium.org/2623313005
Cr-Commit-Position: refs/heads/master@{#42340}
parent 154cb854
...@@ -9308,6 +9308,14 @@ MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate, ...@@ -9308,6 +9308,14 @@ MaybeLocal<UnboundScript> debug::CompileInspectorScript(Isolate* v8_isolate,
RETURN_ESCAPED(ToApiHandle<UnboundScript>(result)); RETURN_ESCAPED(ToApiHandle<UnboundScript>(result));
} }
void debug::SetAsyncTaskListener(Isolate* v8_isolate,
debug::AsyncTaskListener listener,
void* data) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8(isolate);
isolate->debug()->SetAsyncTaskListener(listener, data);
}
Local<String> CpuProfileNode::GetFunctionName() const { Local<String> CpuProfileNode::GetFunctionName() const {
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this); const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
i::Isolate* isolate = node->isolate(); i::Isolate* isolate = node->isolate();
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef V8_DEBUG_DEBUG_INTERFACE_H_ #ifndef V8_DEBUG_DEBUG_INTERFACE_H_
#define V8_DEBUG_DEBUG_INTERFACE_H_ #define V8_DEBUG_DEBUG_INTERFACE_H_
#include <functional>
#include "include/v8-debug.h" #include "include/v8-debug.h"
#include "include/v8-util.h" #include "include/v8-util.h"
#include "include/v8.h" #include "include/v8.h"
...@@ -202,6 +204,12 @@ void GetLoadedScripts(Isolate* isolate, PersistentValueVector<Script>& scripts); ...@@ -202,6 +204,12 @@ 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,
void* data)>
AsyncTaskListener;
void SetAsyncTaskListener(Isolate* isolate, AsyncTaskListener listener,
void* data);
} // namespace debug } // namespace debug
} // namespace v8 } // namespace v8
......
...@@ -1859,9 +1859,31 @@ int Debug::NextAsyncTaskId(Handle<JSObject> promise) { ...@@ -1859,9 +1859,31 @@ 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_) {
async_task_listener_(type, id, async_task_listener_data_);
// There are three types of event listeners: C++ message_handler,
// JavaScript event listener and C++ event listener.
// Currently inspector still uses C++ event listener and installs
// more specific event listeners for part of events. Calling of
// C++ event listener is redundant when more specific event listener
// is presented. Other clients can install JavaScript event listener
// (e.g. some of NodeJS module).
bool non_inspector_listener_exists =
message_handler_ != nullptr ||
(event_listener_.is_null() && !event_listener_->IsForeign());
if (!non_inspector_listener_exists) return;
}
HandleScope scope(isolate_); HandleScope scope(isolate_);
DebugScope debug_scope(this); DebugScope debug_scope(this);
if (debug_scope.failed()) return; if (debug_scope.failed()) return;
...@@ -2144,7 +2166,8 @@ void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) { ...@@ -2144,7 +2166,8 @@ void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) {
} }
void Debug::UpdateState() { void Debug::UpdateState() {
bool is_active = message_handler_ != NULL || !event_listener_.is_null(); bool is_active = message_handler_ != nullptr || !event_listener_.is_null() ||
async_task_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.
......
...@@ -466,6 +466,8 @@ class Debug { ...@@ -466,6 +466,8 @@ class Debug {
int NextAsyncTaskId(Handle<JSObject> promise); int NextAsyncTaskId(Handle<JSObject> promise);
void SetAsyncTaskListener(debug::AsyncTaskListener 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
// function needs to be compiled already. // function needs to be compiled already.
...@@ -661,6 +663,9 @@ class Debug { ...@@ -661,6 +663,9 @@ class Debug {
v8::Debug::MessageHandler message_handler_; v8::Debug::MessageHandler message_handler_;
debug::AsyncTaskListener async_task_listener_ = nullptr;
void* async_task_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.
LockingCommandMessageQueue command_queue_; LockingCommandMessageQueue command_queue_;
......
...@@ -70,6 +70,8 @@ void V8Debugger::enable() { ...@@ -70,6 +70,8 @@ void V8Debugger::enable() {
v8::HandleScope scope(m_isolate); v8::HandleScope scope(m_isolate);
v8::debug::SetDebugEventListener(m_isolate, &V8Debugger::v8DebugEventCallback, v8::debug::SetDebugEventListener(m_isolate, &V8Debugger::v8DebugEventCallback,
v8::External::New(m_isolate, this)); v8::External::New(m_isolate, this));
v8::debug::SetAsyncTaskListener(m_isolate, &V8Debugger::v8AsyncTaskListener,
this);
m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate));
v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException);
m_pauseOnExceptionsState = v8::debug::NoBreakOnException; m_pauseOnExceptionsState = v8::debug::NoBreakOnException;
...@@ -85,6 +87,7 @@ void V8Debugger::disable() { ...@@ -85,6 +87,7 @@ 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);
} }
bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); }
...@@ -533,16 +536,10 @@ void V8Debugger::handleV8DebugEvent( ...@@ -533,16 +536,10 @@ void V8Debugger::handleV8DebugEvent(
v8::HandleScope scope(m_isolate); v8::HandleScope scope(m_isolate);
v8::DebugEvent event = eventDetails.GetEvent(); v8::DebugEvent event = eventDetails.GetEvent();
if (event != v8::AsyncTaskEvent && event != v8::Break && if (event != v8::Break && event != v8::Exception &&
event != v8::Exception && event != v8::AfterCompile && event != v8::AfterCompile && event != v8::CompileError)
event != v8::CompileError)
return; return;
if (event == v8::AsyncTaskEvent) {
handleV8AsyncTaskEvent(eventDetails.GetEventData());
return;
}
v8::Local<v8::Context> eventContext = eventDetails.GetEventContext(); v8::Local<v8::Context> eventContext = eventDetails.GetEventContext();
DCHECK(!eventContext.IsEmpty()); DCHECK(!eventContext.IsEmpty());
V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup(
...@@ -596,52 +593,35 @@ void V8Debugger::handleV8DebugEvent( ...@@ -596,52 +593,35 @@ void V8Debugger::handleV8DebugEvent(
} }
} }
void V8Debugger::handleV8AsyncTaskEvent(v8::Local<v8::Object> eventData) { void V8Debugger::v8AsyncTaskListener(v8::debug::PromiseDebugActionType type,
if (!m_maxAsyncCallStackDepth) return; int id, void* data) {
V8Debugger* debugger = static_cast<V8Debugger*>(data);
// TODO(kozyatinskiy): remove usage of current context as soon as async event if (!debugger->m_maxAsyncCallStackDepth) return;
// is migrated to pure C++ API.
v8::debug::PromiseDebugActionType type =
static_cast<v8::debug::PromiseDebugActionType>(
eventData
->Get(m_isolate->GetCurrentContext(),
toV8StringInternalized(m_isolate, "type_"))
.ToLocalChecked()
->ToInteger(m_isolate->GetCurrentContext())
.ToLocalChecked()
->Value());
int id = static_cast<int>(eventData
->Get(m_isolate->GetCurrentContext(),
toV8StringInternalized(m_isolate, "id_"))
.ToLocalChecked()
->ToInteger(m_isolate->GetCurrentContext())
.ToLocalChecked()
->Value());
// 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:
asyncTaskScheduled("async function", ptr, true); debugger->asyncTaskScheduled("async function", ptr, true);
break; break;
case v8::debug::kDebugEnqueuePromiseResolve: case v8::debug::kDebugEnqueuePromiseResolve:
asyncTaskScheduled("Promise.resolve", ptr, true); debugger->asyncTaskScheduled("Promise.resolve", ptr, true);
break; break;
case v8::debug::kDebugEnqueuePromiseReject: case v8::debug::kDebugEnqueuePromiseReject:
asyncTaskScheduled("Promise.reject", ptr, true); debugger->asyncTaskScheduled("Promise.reject", ptr, true);
break; break;
case v8::debug::kDebugEnqueuePromiseResolveThenableJob: case v8::debug::kDebugEnqueuePromiseResolveThenableJob:
asyncTaskScheduled("PromiseResolveThenableJob", ptr, true); debugger->asyncTaskScheduled("PromiseResolveThenableJob", ptr, true);
break; break;
case v8::debug::kDebugPromiseCollected: case v8::debug::kDebugPromiseCollected:
asyncTaskCanceled(ptr); debugger->asyncTaskCanceled(ptr);
break; break;
case v8::debug::kDebugWillHandle: case v8::debug::kDebugWillHandle:
asyncTaskStarted(ptr); debugger->asyncTaskStarted(ptr);
break; break;
case v8::debug::kDebugDidHandle: case v8::debug::kDebugDidHandle:
asyncTaskFinished(ptr); debugger->asyncTaskFinished(ptr);
break; break;
} }
} }
......
...@@ -114,7 +114,8 @@ class V8Debugger { ...@@ -114,7 +114,8 @@ class V8Debugger {
v8::Local<v8::Value> callInternalGetterFunction(v8::Local<v8::Object>, v8::Local<v8::Value> callInternalGetterFunction(v8::Local<v8::Object>,
const char* functionName); const char* functionName);
void handleV8DebugEvent(const v8::debug::EventDetails&); void handleV8DebugEvent(const v8::debug::EventDetails&);
void handleV8AsyncTaskEvent(v8::Local<v8::Object> eventData); static void v8AsyncTaskListener(v8::debug::PromiseDebugActionType type,
int id, 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>);
......
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