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,
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 {
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
i::Isolate* isolate = node->isolate();
......
......@@ -5,6 +5,8 @@
#ifndef V8_DEBUG_DEBUG_INTERFACE_H_
#define V8_DEBUG_DEBUG_INTERFACE_H_
#include <functional>
#include "include/v8-debug.h"
#include "include/v8-util.h"
#include "include/v8.h"
......@@ -202,6 +204,12 @@ void GetLoadedScripts(Isolate* isolate, PersistentValueVector<Script>& scripts);
MaybeLocal<UnboundScript> CompileInspectorScript(Isolate* isolate,
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 v8
......
......@@ -1859,9 +1859,31 @@ int Debug::NextAsyncTaskId(Handle<JSObject> promise) {
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) {
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_);
DebugScope debug_scope(this);
if (debug_scope.failed()) return;
......@@ -2144,7 +2166,8 @@ void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) {
}
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()) {
// Note that the debug context could have already been loaded to
// bootstrap test cases.
......
......@@ -466,6 +466,8 @@ class Debug {
int NextAsyncTaskId(Handle<JSObject> promise);
void SetAsyncTaskListener(debug::AsyncTaskListener listener, void* data);
// Returns whether the operation succeeded. Compilation can only be triggered
// if a valid closure is passed as the second argument, otherwise the shared
// function needs to be compiled already.
......@@ -661,6 +663,9 @@ class Debug {
v8::Debug::MessageHandler message_handler_;
debug::AsyncTaskListener async_task_listener_ = nullptr;
void* async_task_listener_data_ = nullptr;
static const int kQueueInitialSize = 4;
base::Semaphore command_received_; // Signaled for each command received.
LockingCommandMessageQueue command_queue_;
......
......@@ -70,6 +70,8 @@ void V8Debugger::enable() {
v8::HandleScope scope(m_isolate);
v8::debug::SetDebugEventListener(m_isolate, &V8Debugger::v8DebugEventCallback,
v8::External::New(m_isolate, this));
v8::debug::SetAsyncTaskListener(m_isolate, &V8Debugger::v8AsyncTaskListener,
this);
m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate));
v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException);
m_pauseOnExceptionsState = v8::debug::NoBreakOnException;
......@@ -85,6 +87,7 @@ void V8Debugger::disable() {
allAsyncTasksCanceled();
m_wasmTranslation.Clear();
v8::debug::SetDebugEventListener(m_isolate, nullptr);
v8::debug::SetAsyncTaskListener(m_isolate, nullptr, nullptr);
}
bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); }
......@@ -533,16 +536,10 @@ void V8Debugger::handleV8DebugEvent(
v8::HandleScope scope(m_isolate);
v8::DebugEvent event = eventDetails.GetEvent();
if (event != v8::AsyncTaskEvent && event != v8::Break &&
event != v8::Exception && event != v8::AfterCompile &&
event != v8::CompileError)
if (event != v8::Break && event != v8::Exception &&
event != v8::AfterCompile && event != v8::CompileError)
return;
if (event == v8::AsyncTaskEvent) {
handleV8AsyncTaskEvent(eventDetails.GetEventData());
return;
}
v8::Local<v8::Context> eventContext = eventDetails.GetEventContext();
DCHECK(!eventContext.IsEmpty());
V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup(
......@@ -596,52 +593,35 @@ void V8Debugger::handleV8DebugEvent(
}
}
void V8Debugger::handleV8AsyncTaskEvent(v8::Local<v8::Object> eventData) {
if (!m_maxAsyncCallStackDepth) return;
// TODO(kozyatinskiy): remove usage of current context as soon as async event
// 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());
void V8Debugger::v8AsyncTaskListener(v8::debug::PromiseDebugActionType type,
int id, void* data) {
V8Debugger* debugger = static_cast<V8Debugger*>(data);
if (!debugger->m_maxAsyncCallStackDepth) return;
// Async task events from Promises are given misaligned pointers to prevent
// from overlapping with other Blink task identifiers. There is a single
// namespace of such ids, managed by src/js/promise.js.
void* ptr = reinterpret_cast<void*>(id * 2 + 1);
switch (type) {
case v8::debug::kDebugEnqueueAsyncFunction:
asyncTaskScheduled("async function", ptr, true);
debugger->asyncTaskScheduled("async function", ptr, true);
break;
case v8::debug::kDebugEnqueuePromiseResolve:
asyncTaskScheduled("Promise.resolve", ptr, true);
debugger->asyncTaskScheduled("Promise.resolve", ptr, true);
break;
case v8::debug::kDebugEnqueuePromiseReject:
asyncTaskScheduled("Promise.reject", ptr, true);
debugger->asyncTaskScheduled("Promise.reject", ptr, true);
break;
case v8::debug::kDebugEnqueuePromiseResolveThenableJob:
asyncTaskScheduled("PromiseResolveThenableJob", ptr, true);
debugger->asyncTaskScheduled("PromiseResolveThenableJob", ptr, true);
break;
case v8::debug::kDebugPromiseCollected:
asyncTaskCanceled(ptr);
debugger->asyncTaskCanceled(ptr);
break;
case v8::debug::kDebugWillHandle:
asyncTaskStarted(ptr);
debugger->asyncTaskStarted(ptr);
break;
case v8::debug::kDebugDidHandle:
asyncTaskFinished(ptr);
debugger->asyncTaskFinished(ptr);
break;
}
}
......
......@@ -114,7 +114,8 @@ class V8Debugger {
v8::Local<v8::Value> callInternalGetterFunction(v8::Local<v8::Object>,
const char* functionName);
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::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