[inspector] Merge InspectorClientImpl into IsolateData
BUG=none Review-Url: https://codereview.chromium.org/2894773003 Cr-Commit-Position: refs/heads/master@{#45441}
This commit is contained in:
parent
eeefc74a11
commit
afbaedc8a5
@ -8,8 +8,6 @@ v8_executable("inspector-test") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"inspector-impl.cc",
|
||||
"inspector-impl.h",
|
||||
"inspector-test.cc",
|
||||
"isolate-data.cc",
|
||||
"isolate-data.h",
|
||||
|
@ -1,254 +0,0 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "test/inspector/inspector-impl.h"
|
||||
|
||||
#include "include/v8.h"
|
||||
|
||||
#include "src/vector.h"
|
||||
#include "test/inspector/isolate-data.h"
|
||||
#include "test/inspector/task-runner.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class ChannelImpl final : public v8_inspector::V8Inspector::Channel {
|
||||
public:
|
||||
ChannelImpl(InspectorClientImpl::FrontendChannel* frontend_channel,
|
||||
int session_id)
|
||||
: frontend_channel_(frontend_channel), session_id_(session_id) {}
|
||||
virtual ~ChannelImpl() = default;
|
||||
|
||||
private:
|
||||
void sendResponse(
|
||||
int callId,
|
||||
std::unique_ptr<v8_inspector::StringBuffer> message) override {
|
||||
frontend_channel_->SendMessageToFrontend(session_id_, message->string());
|
||||
}
|
||||
void sendNotification(
|
||||
std::unique_ptr<v8_inspector::StringBuffer> message) override {
|
||||
frontend_channel_->SendMessageToFrontend(session_id_, message->string());
|
||||
}
|
||||
void flushProtocolNotifications() override {}
|
||||
|
||||
InspectorClientImpl::FrontendChannel* frontend_channel_;
|
||||
int session_id_;
|
||||
DISALLOW_COPY_AND_ASSIGN(ChannelImpl);
|
||||
};
|
||||
|
||||
v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
|
||||
v8::internal::Vector<uint16_t> buffer =
|
||||
v8::internal::Vector<uint16_t>::New(str->Length());
|
||||
str->Write(buffer.start(), 0, str->Length());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void MessageHandler(v8::Local<v8::Message> message,
|
||||
v8::Local<v8::Value> exception) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Local<v8::Context> context = isolate->GetEnteredContext();
|
||||
if (context.IsEmpty()) return;
|
||||
v8_inspector::V8Inspector* inspector =
|
||||
IsolateData::FromContext(context)->inspector()->inspector();
|
||||
|
||||
v8::Local<v8::StackTrace> stack = message->GetStackTrace();
|
||||
int script_id =
|
||||
static_cast<int>(message->GetScriptOrigin().ScriptID()->Value());
|
||||
if (!stack.IsEmpty() && stack->GetFrameCount() > 0) {
|
||||
int top_script_id = stack->GetFrame(0)->GetScriptId();
|
||||
if (top_script_id == script_id) script_id = 0;
|
||||
}
|
||||
int line_number = message->GetLineNumber(context).FromMaybe(0);
|
||||
int column_number = 0;
|
||||
if (message->GetStartColumn(context).IsJust())
|
||||
column_number = message->GetStartColumn(context).FromJust() + 1;
|
||||
|
||||
v8_inspector::StringView detailed_message;
|
||||
v8::internal::Vector<uint16_t> message_text_string = ToVector(message->Get());
|
||||
v8_inspector::StringView message_text(message_text_string.start(),
|
||||
message_text_string.length());
|
||||
v8::internal::Vector<uint16_t> url_string;
|
||||
if (message->GetScriptOrigin().ResourceName()->IsString()) {
|
||||
url_string =
|
||||
ToVector(message->GetScriptOrigin().ResourceName().As<v8::String>());
|
||||
}
|
||||
v8_inspector::StringView url(url_string.start(), url_string.length());
|
||||
|
||||
inspector->exceptionThrown(context, message_text, exception, detailed_message,
|
||||
url, line_number, column_number,
|
||||
inspector->createStackTrace(stack), script_id);
|
||||
}
|
||||
|
||||
v8::Local<v8::String> ToString(v8::Isolate* isolate,
|
||||
const v8_inspector::StringView& string) {
|
||||
if (string.is8Bit())
|
||||
return v8::String::NewFromOneByte(isolate, string.characters8(),
|
||||
v8::NewStringType::kNormal,
|
||||
static_cast<int>(string.length()))
|
||||
.ToLocalChecked();
|
||||
else
|
||||
return v8::String::NewFromTwoByte(isolate, string.characters16(),
|
||||
v8::NewStringType::kNormal,
|
||||
static_cast<int>(string.length()))
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
||||
void Print(v8::Isolate* isolate, const v8_inspector::StringView& string) {
|
||||
v8::Local<v8::String> v8_string = ToString(isolate, string);
|
||||
v8::String::Utf8Value utf8_string(v8_string);
|
||||
fwrite(*utf8_string, sizeof(**utf8_string), utf8_string.length(), stdout);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
InspectorClientImpl::InspectorClientImpl(v8::Isolate* isolate,
|
||||
TaskRunner* task_runner,
|
||||
FrontendChannel* frontend_channel)
|
||||
: task_runner_(task_runner),
|
||||
isolate_(isolate),
|
||||
frontend_channel_(frontend_channel) {
|
||||
isolate_->AddMessageListener(MessageHandler);
|
||||
inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
|
||||
}
|
||||
|
||||
InspectorClientImpl::~InspectorClientImpl() {}
|
||||
|
||||
int InspectorClientImpl::ConnectSession(int context_group_id,
|
||||
const v8_inspector::StringView& state) {
|
||||
int session_id = ++last_session_id_;
|
||||
channels_[session_id].reset(new ChannelImpl(frontend_channel_, session_id));
|
||||
sessions_[session_id] =
|
||||
inspector_->connect(context_group_id, channels_[session_id].get(), state);
|
||||
context_group_by_session_[sessions_[session_id].get()] = context_group_id;
|
||||
return session_id;
|
||||
}
|
||||
|
||||
std::unique_ptr<v8_inspector::StringBuffer>
|
||||
InspectorClientImpl::DisconnectSession(int session_id) {
|
||||
auto it = sessions_.find(session_id);
|
||||
CHECK(it != sessions_.end());
|
||||
context_group_by_session_.erase(it->second.get());
|
||||
std::unique_ptr<v8_inspector::StringBuffer> result = it->second->stateJSON();
|
||||
sessions_.erase(it);
|
||||
channels_.erase(session_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
void InspectorClientImpl::SendMessage(int session_id,
|
||||
const v8_inspector::StringView& message) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end()) it->second->dispatchProtocolMessage(message);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::BreakProgram(
|
||||
int context_group_id, const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details) {
|
||||
for (int session_id : GetSessionIds(context_group_id)) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end()) it->second->breakProgram(reason, details);
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorClientImpl::SchedulePauseOnNextStatement(
|
||||
int context_group_id, const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details) {
|
||||
for (int session_id : GetSessionIds(context_group_id)) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end())
|
||||
it->second->schedulePauseOnNextStatement(reason, details);
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorClientImpl::CancelPauseOnNextStatement(int context_group_id) {
|
||||
for (int session_id : GetSessionIds(context_group_id)) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end()) it->second->cancelPauseOnNextStatement();
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorClientImpl::ContextCreated(v8::Local<v8::Context> context,
|
||||
int context_group_id) {
|
||||
v8_inspector::V8ContextInfo info(context, context_group_id,
|
||||
v8_inspector::StringView());
|
||||
info.hasMemoryOnConsole = true;
|
||||
inspector_->contextCreated(info);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::ContextDestroyed(v8::Local<v8::Context> context) {
|
||||
inspector_->contextDestroyed(context);
|
||||
}
|
||||
|
||||
std::vector<int> InspectorClientImpl::GetSessionIds(int context_group_id) {
|
||||
std::vector<int> result;
|
||||
for (auto& it : sessions_) {
|
||||
if (context_group_by_session_[it.second.get()] == context_group_id)
|
||||
result.push_back(it.first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool InspectorClientImpl::formatAccessorsAsProperties(
|
||||
v8::Local<v8::Value> object) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::Private> shouldFormatAccessorsPrivate = v8::Private::ForApi(
|
||||
isolate, v8::String::NewFromUtf8(isolate, "allowAccessorFormatting",
|
||||
v8::NewStringType::kNormal)
|
||||
.ToLocalChecked());
|
||||
CHECK(object->IsObject());
|
||||
return object.As<v8::Object>()
|
||||
->HasPrivate(context, shouldFormatAccessorsPrivate)
|
||||
.FromMaybe(false);
|
||||
}
|
||||
|
||||
v8::Local<v8::Context> InspectorClientImpl::ensureDefaultContextInGroup(
|
||||
int context_group_id) {
|
||||
CHECK(isolate_);
|
||||
return task_runner_->data()->GetContext(context_group_id);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::SetCurrentTimeMSForTest(double time) {
|
||||
current_time_ = time;
|
||||
current_time_set_for_test_ = true;
|
||||
}
|
||||
|
||||
double InspectorClientImpl::currentTimeMS() {
|
||||
if (current_time_set_for_test_) return current_time_;
|
||||
return v8::base::OS::TimeCurrentMillis();
|
||||
}
|
||||
|
||||
void InspectorClientImpl::SetMemoryInfoForTest(
|
||||
v8::Local<v8::Value> memory_info) {
|
||||
memory_info_.Reset(isolate_, memory_info);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::SetLogConsoleApiMessageCalls(bool log) {
|
||||
log_console_api_message_calls_ = log;
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::Value> InspectorClientImpl::memoryInfo(
|
||||
v8::Isolate* isolate, v8::Local<v8::Context>) {
|
||||
if (memory_info_.IsEmpty()) return v8::MaybeLocal<v8::Value>();
|
||||
return memory_info_.Get(isolate);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::runMessageLoopOnPause(int) {
|
||||
task_runner_->RunMessageLoop(true);
|
||||
}
|
||||
|
||||
void InspectorClientImpl::quitMessageLoopOnPause() {
|
||||
task_runner_->QuitMessageLoop();
|
||||
}
|
||||
|
||||
void InspectorClientImpl::consoleAPIMessage(
|
||||
int contextGroupId, v8::Isolate::MessageErrorLevel level,
|
||||
const v8_inspector::StringView& message,
|
||||
const v8_inspector::StringView& url, unsigned lineNumber,
|
||||
unsigned columnNumber, v8_inspector::V8StackTrace* stack) {
|
||||
if (!log_console_api_message_calls_) return;
|
||||
Print(isolate_, message);
|
||||
fprintf(stdout, " (");
|
||||
Print(isolate_, url);
|
||||
fprintf(stdout, ":%d:%d)", lineNumber, columnNumber);
|
||||
Print(isolate_, stack->toString()->string());
|
||||
fprintf(stdout, "\n");
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_TEST_INSPECTOR_PROTOCOL_INSPECTOR_IMPL_H_
|
||||
#define V8_TEST_INSPECTOR_PROTOCOL_INSPECTOR_IMPL_H_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "include/v8-inspector.h"
|
||||
#include "include/v8.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
|
||||
class TaskRunner;
|
||||
|
||||
class InspectorClientImpl : public v8_inspector::V8InspectorClient {
|
||||
public:
|
||||
class FrontendChannel {
|
||||
public:
|
||||
virtual ~FrontendChannel() = default;
|
||||
virtual void SendMessageToFrontend(
|
||||
int session_id, const v8_inspector::StringView& message) = 0;
|
||||
};
|
||||
|
||||
InspectorClientImpl(v8::Isolate* isolate, TaskRunner* task_runner,
|
||||
FrontendChannel* frontend_channel);
|
||||
virtual ~InspectorClientImpl();
|
||||
|
||||
v8_inspector::V8Inspector* inspector() const { return inspector_.get(); }
|
||||
int ConnectSession(int context_group_id,
|
||||
const v8_inspector::StringView& state);
|
||||
std::unique_ptr<v8_inspector::StringBuffer> DisconnectSession(int session_id);
|
||||
void SendMessage(int session_id, const v8_inspector::StringView& message);
|
||||
void BreakProgram(int context_group_id,
|
||||
const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details);
|
||||
void SchedulePauseOnNextStatement(int context_group_id,
|
||||
const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details);
|
||||
void CancelPauseOnNextStatement(int context_group_id);
|
||||
void SetCurrentTimeMSForTest(double time);
|
||||
void SetMemoryInfoForTest(v8::Local<v8::Value> memory_info);
|
||||
void SetLogConsoleApiMessageCalls(bool log);
|
||||
void ContextCreated(v8::Local<v8::Context> context, int context_group_id);
|
||||
void ContextDestroyed(v8::Local<v8::Context> context);
|
||||
|
||||
private:
|
||||
// V8InspectorClient implementation.
|
||||
bool formatAccessorsAsProperties(v8::Local<v8::Value>) override;
|
||||
v8::Local<v8::Context> ensureDefaultContextInGroup(
|
||||
int context_group_id) override;
|
||||
double currentTimeMS() override;
|
||||
v8::MaybeLocal<v8::Value> memoryInfo(v8::Isolate* isolate,
|
||||
v8::Local<v8::Context>) override;
|
||||
void runMessageLoopOnPause(int context_group_id) override;
|
||||
void quitMessageLoopOnPause() override;
|
||||
void consoleAPIMessage(int contextGroupId,
|
||||
v8::Isolate::MessageErrorLevel level,
|
||||
const v8_inspector::StringView& message,
|
||||
const v8_inspector::StringView& url,
|
||||
unsigned lineNumber, unsigned columnNumber,
|
||||
v8_inspector::V8StackTrace*) override;
|
||||
|
||||
std::vector<int> GetSessionIds(int context_group_id);
|
||||
|
||||
std::unique_ptr<v8_inspector::V8Inspector> inspector_;
|
||||
int last_session_id_ = 0;
|
||||
std::map<int, std::unique_ptr<v8_inspector::V8InspectorSession>> sessions_;
|
||||
std::map<v8_inspector::V8InspectorSession*, int> context_group_by_session_;
|
||||
std::map<int, std::unique_ptr<v8_inspector::V8Inspector::Channel>> channels_;
|
||||
TaskRunner* task_runner_;
|
||||
v8::Isolate* isolate_;
|
||||
v8::Global<v8::Value> memory_info_;
|
||||
FrontendChannel* frontend_channel_;
|
||||
bool current_time_set_for_test_ = false;
|
||||
double current_time_ = 0.0;
|
||||
bool log_console_api_message_calls_ = false;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(InspectorClientImpl);
|
||||
};
|
||||
|
||||
#endif // V8_TEST_INSPECTOR_PROTOCOL_INSPECTOR_IMPL_H_
|
@ -17,7 +17,7 @@
|
||||
#include "src/utils.h"
|
||||
#include "src/vector.h"
|
||||
|
||||
#include "test/inspector/inspector-impl.h"
|
||||
#include "test/inspector/isolate-data.h"
|
||||
#include "test/inspector/task-runner.h"
|
||||
|
||||
namespace {
|
||||
@ -98,8 +98,7 @@ class ConnectSessionTask : public TaskRunner::Task {
|
||||
private:
|
||||
void Run() override {
|
||||
v8_inspector::StringView state(state_.start(), state_.length());
|
||||
*session_id_ =
|
||||
data()->inspector()->ConnectSession(context_group_id_, state);
|
||||
*session_id_ = data()->ConnectSession(context_group_id_, state);
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
@ -122,7 +121,7 @@ class DisconnectSessionTask : public TaskRunner::Task {
|
||||
private:
|
||||
void Run() override {
|
||||
std::unique_ptr<v8_inspector::StringBuffer> state =
|
||||
data()->inspector()->DisconnectSession(session_id_);
|
||||
data()->DisconnectSession(session_id_);
|
||||
*state_ = ToVector(state->string());
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
@ -142,7 +141,7 @@ class SendMessageToBackendTask : public TaskRunner::Task {
|
||||
private:
|
||||
void Run() override {
|
||||
v8_inspector::StringView message_view(message_.start(), message_.length());
|
||||
data()->inspector()->SendMessage(session_id_, message_view);
|
||||
data()->SendMessage(session_id_, message_view);
|
||||
}
|
||||
|
||||
int session_id_;
|
||||
@ -166,8 +165,7 @@ class SchedulePauseOnNextStatementTask : public TaskRunner::Task {
|
||||
void Run() override {
|
||||
v8_inspector::StringView reason(reason_.start(), reason_.length());
|
||||
v8_inspector::StringView details(details_.start(), details_.length());
|
||||
data()->inspector()->SchedulePauseOnNextStatement(context_group_id_, reason,
|
||||
details);
|
||||
data()->SchedulePauseOnNextStatement(context_group_id_, reason, details);
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
@ -188,7 +186,7 @@ class CancelPauseOnNextStatementTask : public TaskRunner::Task {
|
||||
|
||||
private:
|
||||
void Run() override {
|
||||
data()->inspector()->CancelPauseOnNextStatement(context_group_id_);
|
||||
data()->CancelPauseOnNextStatement(context_group_id_);
|
||||
if (ready_semaphore_) ready_semaphore_->Signal();
|
||||
}
|
||||
|
||||
@ -412,7 +410,7 @@ class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||||
fprintf(stderr, "Internal error: setCurrentTimeMSForTest(time).");
|
||||
Exit();
|
||||
}
|
||||
backend_runner_->data()->inspector()->SetCurrentTimeMSForTest(
|
||||
backend_runner_->data()->SetCurrentTimeMS(
|
||||
args[0].As<v8::Number>()->Value());
|
||||
}
|
||||
|
||||
@ -422,7 +420,7 @@ class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||||
fprintf(stderr, "Internal error: setMemoryInfoForTest(value).");
|
||||
Exit();
|
||||
}
|
||||
backend_runner_->data()->inspector()->SetMemoryInfoForTest(args[0]);
|
||||
backend_runner_->data()->SetMemoryInfo(args[0]);
|
||||
}
|
||||
|
||||
static void SchedulePauseOnNextStatement(
|
||||
@ -461,7 +459,7 @@ class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||||
fprintf(stderr, "Internal error: setLogConsoleApiMessageCalls(bool).");
|
||||
Exit();
|
||||
}
|
||||
backend_runner_->data()->inspector()->SetLogConsoleApiMessageCalls(
|
||||
backend_runner_->data()->SetLogConsoleApiMessageCalls(
|
||||
args[0].As<v8::Boolean>()->Value());
|
||||
}
|
||||
|
||||
@ -647,15 +645,14 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||||
IsolateData* data = IsolateData::FromContext(context);
|
||||
data->inspector()->ContextCreated(context,
|
||||
data->GetContextGroupId(context));
|
||||
data->FireContextCreated(context, data->GetContextGroupId(context));
|
||||
}
|
||||
|
||||
static void FireContextDestroyed(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||||
IsolateData* data = IsolateData::FromContext(context);
|
||||
data->inspector()->ContextDestroyed(context);
|
||||
data->FireContextDestroyed(context);
|
||||
}
|
||||
|
||||
static void SetMaxAsyncTaskStacks(
|
||||
@ -666,7 +663,6 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
}
|
||||
v8_inspector::SetMaxAsyncTaskStacksForTest(
|
||||
IsolateData::FromContext(args.GetIsolate()->GetCurrentContext())
|
||||
->inspector()
|
||||
->inspector(),
|
||||
args[0].As<v8::Int32>()->Value());
|
||||
}
|
||||
@ -679,7 +675,6 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
}
|
||||
v8_inspector::DumpAsyncTaskStacksStateForTest(
|
||||
IsolateData::FromContext(args.GetIsolate()->GetCurrentContext())
|
||||
->inspector()
|
||||
->inspector());
|
||||
}
|
||||
|
||||
@ -694,8 +689,8 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
v8_inspector::StringView reason_view(reason.start(), reason.length());
|
||||
v8::internal::Vector<uint16_t> details = ToVector(args[1].As<v8::String>());
|
||||
v8_inspector::StringView details_view(details.start(), details.length());
|
||||
data->inspector()->BreakProgram(data->GetContextGroupId(context),
|
||||
reason_view, details_view);
|
||||
data->BreakProgram(data->GetContextGroupId(context), reason_view,
|
||||
details_view);
|
||||
}
|
||||
|
||||
static void CreateObjectWithStrictCheck(
|
||||
@ -727,12 +722,12 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||||
IsolateData* data = IsolateData::FromContext(context);
|
||||
int context_group_id = data->GetContextGroupId(context);
|
||||
data->inspector()->SchedulePauseOnNextStatement(context_group_id,
|
||||
reason_view, details_view);
|
||||
data->SchedulePauseOnNextStatement(context_group_id, reason_view,
|
||||
details_view);
|
||||
v8::MaybeLocal<v8::Value> result;
|
||||
result = args[0].As<v8::Function>()->Call(context, context->Global(), 0,
|
||||
nullptr);
|
||||
data->inspector()->CancelPauseOnNextStatement(context_group_id);
|
||||
data->CancelPauseOnNextStatement(context_group_id);
|
||||
}
|
||||
|
||||
static void AllowAccessorFormatting(
|
||||
@ -754,7 +749,7 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||||
}
|
||||
};
|
||||
|
||||
class FrontendChannelImpl : public InspectorClientImpl::FrontendChannel {
|
||||
class FrontendChannelImpl : public IsolateData::FrontendChannel {
|
||||
public:
|
||||
FrontendChannelImpl(TaskRunner* frontend_task_runner, int context_group_id)
|
||||
: frontend_task_runner_(frontend_task_runner),
|
||||
|
@ -20,8 +20,6 @@
|
||||
'../..',
|
||||
],
|
||||
'sources': [
|
||||
'inspector-impl.cc',
|
||||
'inspector-impl.h',
|
||||
'inspector-test.cc',
|
||||
'isolate-data.cc',
|
||||
'isolate-data.h',
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include "test/inspector/isolate-data.h"
|
||||
|
||||
#include "test/inspector/inspector-impl.h"
|
||||
#include "test/inspector/task-runner.h"
|
||||
|
||||
namespace {
|
||||
@ -19,22 +18,68 @@ v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
v8::Local<v8::String> ToString(v8::Isolate* isolate,
|
||||
const v8_inspector::StringView& string) {
|
||||
if (string.is8Bit())
|
||||
return v8::String::NewFromOneByte(isolate, string.characters8(),
|
||||
v8::NewStringType::kNormal,
|
||||
static_cast<int>(string.length()))
|
||||
.ToLocalChecked();
|
||||
else
|
||||
return v8::String::NewFromTwoByte(isolate, string.characters16(),
|
||||
v8::NewStringType::kNormal,
|
||||
static_cast<int>(string.length()))
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
||||
void Print(v8::Isolate* isolate, const v8_inspector::StringView& string) {
|
||||
v8::Local<v8::String> v8_string = ToString(isolate, string);
|
||||
v8::String::Utf8Value utf8_string(v8_string);
|
||||
fwrite(*utf8_string, sizeof(**utf8_string), utf8_string.length(), stdout);
|
||||
}
|
||||
|
||||
class ChannelImpl final : public v8_inspector::V8Inspector::Channel {
|
||||
public:
|
||||
ChannelImpl(IsolateData::FrontendChannel* frontend_channel, int session_id)
|
||||
: frontend_channel_(frontend_channel), session_id_(session_id) {}
|
||||
virtual ~ChannelImpl() = default;
|
||||
|
||||
private:
|
||||
void sendResponse(
|
||||
int callId,
|
||||
std::unique_ptr<v8_inspector::StringBuffer> message) override {
|
||||
frontend_channel_->SendMessageToFrontend(session_id_, message->string());
|
||||
}
|
||||
void sendNotification(
|
||||
std::unique_ptr<v8_inspector::StringBuffer> message) override {
|
||||
frontend_channel_->SendMessageToFrontend(session_id_, message->string());
|
||||
}
|
||||
void flushProtocolNotifications() override {}
|
||||
|
||||
IsolateData::FrontendChannel* frontend_channel_;
|
||||
int session_id_;
|
||||
DISALLOW_COPY_AND_ASSIGN(ChannelImpl);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
IsolateData::IsolateData(TaskRunner* task_runner,
|
||||
IsolateData::SetupGlobalTasks setup_global_tasks,
|
||||
v8::StartupData* startup_data,
|
||||
InspectorClientImpl::FrontendChannel* channel)
|
||||
FrontendChannel* channel)
|
||||
: task_runner_(task_runner),
|
||||
setup_global_tasks_(std::move(setup_global_tasks)) {
|
||||
setup_global_tasks_(std::move(setup_global_tasks)),
|
||||
frontend_channel_(channel) {
|
||||
v8::Isolate::CreateParams params;
|
||||
params.array_buffer_allocator =
|
||||
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
|
||||
params.snapshot_blob = startup_data;
|
||||
isolate_ = v8::Isolate::New(params);
|
||||
isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
|
||||
if (channel)
|
||||
inspector_.reset(new InspectorClientImpl(isolate_, task_runner, channel));
|
||||
if (frontend_channel_) {
|
||||
isolate_->AddMessageListener(&IsolateData::MessageHandler);
|
||||
inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
|
||||
}
|
||||
}
|
||||
|
||||
IsolateData* IsolateData::FromContext(v8::Local<v8::Context> context) {
|
||||
@ -58,7 +103,7 @@ int IsolateData::CreateContextGroup() {
|
||||
context->SetAlignedPointerInEmbedderData(
|
||||
kContextGroupIdIndex, reinterpret_cast<void*>(context_group_id * 2));
|
||||
contexts_[context_group_id].Reset(isolate_, context);
|
||||
if (inspector_) inspector_->ContextCreated(context, context_group_id);
|
||||
if (inspector_) FireContextCreated(context, context_group_id);
|
||||
return context_group_id;
|
||||
}
|
||||
|
||||
@ -86,6 +131,7 @@ void IsolateData::RegisterModule(v8::Local<v8::Context> context,
|
||||
modules_[name] = v8::Global<v8::Module>(isolate_, module);
|
||||
}
|
||||
|
||||
// static
|
||||
v8::MaybeLocal<v8::Module> IsolateData::ModuleResolveCallback(
|
||||
v8::Local<v8::Context> context, v8::Local<v8::String> specifier,
|
||||
v8::Local<v8::Module> referrer) {
|
||||
@ -93,3 +139,177 @@ v8::MaybeLocal<v8::Module> IsolateData::ModuleResolveCallback(
|
||||
IsolateData* data = IsolateData::FromContext(context);
|
||||
return data->modules_[ToVector(specifier)].Get(data->isolate_);
|
||||
}
|
||||
|
||||
int IsolateData::ConnectSession(int context_group_id,
|
||||
const v8_inspector::StringView& state) {
|
||||
int session_id = ++last_session_id_;
|
||||
channels_[session_id].reset(new ChannelImpl(frontend_channel_, session_id));
|
||||
sessions_[session_id] =
|
||||
inspector_->connect(context_group_id, channels_[session_id].get(), state);
|
||||
context_group_by_session_[sessions_[session_id].get()] = context_group_id;
|
||||
return session_id;
|
||||
}
|
||||
|
||||
std::unique_ptr<v8_inspector::StringBuffer> IsolateData::DisconnectSession(
|
||||
int session_id) {
|
||||
auto it = sessions_.find(session_id);
|
||||
CHECK(it != sessions_.end());
|
||||
context_group_by_session_.erase(it->second.get());
|
||||
std::unique_ptr<v8_inspector::StringBuffer> result = it->second->stateJSON();
|
||||
sessions_.erase(it);
|
||||
channels_.erase(session_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
void IsolateData::SendMessage(int session_id,
|
||||
const v8_inspector::StringView& message) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end()) it->second->dispatchProtocolMessage(message);
|
||||
}
|
||||
|
||||
void IsolateData::BreakProgram(int context_group_id,
|
||||
const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details) {
|
||||
for (int session_id : GetSessionIds(context_group_id)) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end()) it->second->breakProgram(reason, details);
|
||||
}
|
||||
}
|
||||
|
||||
void IsolateData::SchedulePauseOnNextStatement(
|
||||
int context_group_id, const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details) {
|
||||
for (int session_id : GetSessionIds(context_group_id)) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end())
|
||||
it->second->schedulePauseOnNextStatement(reason, details);
|
||||
}
|
||||
}
|
||||
|
||||
void IsolateData::CancelPauseOnNextStatement(int context_group_id) {
|
||||
for (int session_id : GetSessionIds(context_group_id)) {
|
||||
auto it = sessions_.find(session_id);
|
||||
if (it != sessions_.end()) it->second->cancelPauseOnNextStatement();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void IsolateData::MessageHandler(v8::Local<v8::Message> message,
|
||||
v8::Local<v8::Value> exception) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Local<v8::Context> context = isolate->GetEnteredContext();
|
||||
if (context.IsEmpty()) return;
|
||||
v8_inspector::V8Inspector* inspector =
|
||||
IsolateData::FromContext(context)->inspector_.get();
|
||||
|
||||
v8::Local<v8::StackTrace> stack = message->GetStackTrace();
|
||||
int script_id =
|
||||
static_cast<int>(message->GetScriptOrigin().ScriptID()->Value());
|
||||
if (!stack.IsEmpty() && stack->GetFrameCount() > 0) {
|
||||
int top_script_id = stack->GetFrame(0)->GetScriptId();
|
||||
if (top_script_id == script_id) script_id = 0;
|
||||
}
|
||||
int line_number = message->GetLineNumber(context).FromMaybe(0);
|
||||
int column_number = 0;
|
||||
if (message->GetStartColumn(context).IsJust())
|
||||
column_number = message->GetStartColumn(context).FromJust() + 1;
|
||||
|
||||
v8_inspector::StringView detailed_message;
|
||||
v8::internal::Vector<uint16_t> message_text_string = ToVector(message->Get());
|
||||
v8_inspector::StringView message_text(message_text_string.start(),
|
||||
message_text_string.length());
|
||||
v8::internal::Vector<uint16_t> url_string;
|
||||
if (message->GetScriptOrigin().ResourceName()->IsString()) {
|
||||
url_string =
|
||||
ToVector(message->GetScriptOrigin().ResourceName().As<v8::String>());
|
||||
}
|
||||
v8_inspector::StringView url(url_string.start(), url_string.length());
|
||||
|
||||
inspector->exceptionThrown(context, message_text, exception, detailed_message,
|
||||
url, line_number, column_number,
|
||||
inspector->createStackTrace(stack), script_id);
|
||||
}
|
||||
|
||||
void IsolateData::FireContextCreated(v8::Local<v8::Context> context,
|
||||
int context_group_id) {
|
||||
v8_inspector::V8ContextInfo info(context, context_group_id,
|
||||
v8_inspector::StringView());
|
||||
info.hasMemoryOnConsole = true;
|
||||
inspector_->contextCreated(info);
|
||||
}
|
||||
|
||||
void IsolateData::FireContextDestroyed(v8::Local<v8::Context> context) {
|
||||
inspector_->contextDestroyed(context);
|
||||
}
|
||||
|
||||
std::vector<int> IsolateData::GetSessionIds(int context_group_id) {
|
||||
std::vector<int> result;
|
||||
for (auto& it : sessions_) {
|
||||
if (context_group_by_session_[it.second.get()] == context_group_id)
|
||||
result.push_back(it.first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsolateData::formatAccessorsAsProperties(v8::Local<v8::Value> object) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::Private> shouldFormatAccessorsPrivate = v8::Private::ForApi(
|
||||
isolate, v8::String::NewFromUtf8(isolate, "allowAccessorFormatting",
|
||||
v8::NewStringType::kNormal)
|
||||
.ToLocalChecked());
|
||||
CHECK(object->IsObject());
|
||||
return object.As<v8::Object>()
|
||||
->HasPrivate(context, shouldFormatAccessorsPrivate)
|
||||
.FromMaybe(false);
|
||||
}
|
||||
|
||||
v8::Local<v8::Context> IsolateData::ensureDefaultContextInGroup(
|
||||
int context_group_id) {
|
||||
return GetContext(context_group_id);
|
||||
}
|
||||
|
||||
void IsolateData::SetCurrentTimeMS(double time) {
|
||||
current_time_ = time;
|
||||
current_time_set_ = true;
|
||||
}
|
||||
|
||||
double IsolateData::currentTimeMS() {
|
||||
if (current_time_set_) return current_time_;
|
||||
return v8::base::OS::TimeCurrentMillis();
|
||||
}
|
||||
|
||||
void IsolateData::SetMemoryInfo(v8::Local<v8::Value> memory_info) {
|
||||
memory_info_.Reset(isolate_, memory_info);
|
||||
}
|
||||
|
||||
void IsolateData::SetLogConsoleApiMessageCalls(bool log) {
|
||||
log_console_api_message_calls_ = log;
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::Value> IsolateData::memoryInfo(v8::Isolate* isolate,
|
||||
v8::Local<v8::Context>) {
|
||||
if (memory_info_.IsEmpty()) return v8::MaybeLocal<v8::Value>();
|
||||
return memory_info_.Get(isolate);
|
||||
}
|
||||
|
||||
void IsolateData::runMessageLoopOnPause(int) {
|
||||
task_runner_->RunMessageLoop(true);
|
||||
}
|
||||
|
||||
void IsolateData::quitMessageLoopOnPause() { task_runner_->QuitMessageLoop(); }
|
||||
|
||||
void IsolateData::consoleAPIMessage(int contextGroupId,
|
||||
v8::Isolate::MessageErrorLevel level,
|
||||
const v8_inspector::StringView& message,
|
||||
const v8_inspector::StringView& url,
|
||||
unsigned lineNumber, unsigned columnNumber,
|
||||
v8_inspector::V8StackTrace* stack) {
|
||||
if (!log_console_api_message_calls_) return;
|
||||
Print(isolate_, message);
|
||||
fprintf(stdout, " (");
|
||||
Print(isolate_, url);
|
||||
fprintf(stdout, ":%d:%d)", lineNumber, columnNumber);
|
||||
Print(isolate_, stack->toString()->string());
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
@ -10,12 +10,13 @@
|
||||
#include "include/v8-inspector.h"
|
||||
#include "include/v8-platform.h"
|
||||
#include "include/v8.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
#include "src/vector.h"
|
||||
#include "test/inspector/inspector-impl.h"
|
||||
|
||||
class TaskRunner;
|
||||
|
||||
class IsolateData {
|
||||
class IsolateData : public v8_inspector::V8InspectorClient {
|
||||
public:
|
||||
class SetupGlobalTask {
|
||||
public:
|
||||
@ -25,14 +26,22 @@ class IsolateData {
|
||||
};
|
||||
using SetupGlobalTasks = std::vector<std::unique_ptr<SetupGlobalTask>>;
|
||||
|
||||
class FrontendChannel {
|
||||
public:
|
||||
virtual ~FrontendChannel() = default;
|
||||
virtual void SendMessageToFrontend(
|
||||
int session_id, const v8_inspector::StringView& message) = 0;
|
||||
};
|
||||
|
||||
IsolateData(TaskRunner* task_runner, SetupGlobalTasks setup_global_tasks,
|
||||
v8::StartupData* startup_data,
|
||||
InspectorClientImpl::FrontendChannel* channel);
|
||||
v8::StartupData* startup_data, FrontendChannel* channel);
|
||||
static IsolateData* FromContext(v8::Local<v8::Context> context);
|
||||
|
||||
v8::Isolate* isolate() const { return isolate_; }
|
||||
InspectorClientImpl* inspector() const { return inspector_.get(); }
|
||||
v8_inspector::V8Inspector* inspector() const { return inspector_.get(); }
|
||||
TaskRunner* task_runner() const { return task_runner_; }
|
||||
|
||||
// Setting things up.
|
||||
int CreateContextGroup();
|
||||
v8::Local<v8::Context> GetContext(int context_group_id);
|
||||
int GetContextGroupId(v8::Local<v8::Context> context);
|
||||
@ -40,6 +49,26 @@ class IsolateData {
|
||||
v8::internal::Vector<uint16_t> name,
|
||||
v8::ScriptCompiler::Source* source);
|
||||
|
||||
// Working with V8Inspector api.
|
||||
int ConnectSession(int context_group_id,
|
||||
const v8_inspector::StringView& state);
|
||||
std::unique_ptr<v8_inspector::StringBuffer> DisconnectSession(int session_id);
|
||||
void SendMessage(int session_id, const v8_inspector::StringView& message);
|
||||
void BreakProgram(int context_group_id,
|
||||
const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details);
|
||||
void SchedulePauseOnNextStatement(int context_group_id,
|
||||
const v8_inspector::StringView& reason,
|
||||
const v8_inspector::StringView& details);
|
||||
void CancelPauseOnNextStatement(int context_group_id);
|
||||
|
||||
// Test utilities.
|
||||
void SetCurrentTimeMS(double time);
|
||||
void SetMemoryInfo(v8::Local<v8::Value> memory_info);
|
||||
void SetLogConsoleApiMessageCalls(bool log);
|
||||
void FireContextCreated(v8::Local<v8::Context> context, int context_group_id);
|
||||
void FireContextDestroyed(v8::Local<v8::Context> context);
|
||||
|
||||
private:
|
||||
struct VectorCompare {
|
||||
bool operator()(const v8::internal::Vector<uint16_t>& lhs,
|
||||
@ -53,15 +82,46 @@ class IsolateData {
|
||||
static v8::MaybeLocal<v8::Module> ModuleResolveCallback(
|
||||
v8::Local<v8::Context> context, v8::Local<v8::String> specifier,
|
||||
v8::Local<v8::Module> referrer);
|
||||
static void MessageHandler(v8::Local<v8::Message> message,
|
||||
v8::Local<v8::Value> exception);
|
||||
std::vector<int> GetSessionIds(int context_group_id);
|
||||
|
||||
// V8InspectorClient implementation.
|
||||
bool formatAccessorsAsProperties(v8::Local<v8::Value>) override;
|
||||
v8::Local<v8::Context> ensureDefaultContextInGroup(
|
||||
int context_group_id) override;
|
||||
double currentTimeMS() override;
|
||||
v8::MaybeLocal<v8::Value> memoryInfo(v8::Isolate* isolate,
|
||||
v8::Local<v8::Context>) override;
|
||||
void runMessageLoopOnPause(int context_group_id) override;
|
||||
void quitMessageLoopOnPause() override;
|
||||
void consoleAPIMessage(int contextGroupId,
|
||||
v8::Isolate::MessageErrorLevel level,
|
||||
const v8_inspector::StringView& message,
|
||||
const v8_inspector::StringView& url,
|
||||
unsigned lineNumber, unsigned columnNumber,
|
||||
v8_inspector::V8StackTrace*) override;
|
||||
|
||||
TaskRunner* task_runner_;
|
||||
SetupGlobalTasks setup_global_tasks_;
|
||||
v8::Isolate* isolate_;
|
||||
std::unique_ptr<InspectorClientImpl> inspector_;
|
||||
std::unique_ptr<v8_inspector::V8Inspector> inspector_;
|
||||
int last_context_group_id_ = 0;
|
||||
std::map<int, v8::Global<v8::Context>> contexts_;
|
||||
std::map<v8::internal::Vector<uint16_t>, v8::Global<v8::Module>,
|
||||
VectorCompare>
|
||||
modules_;
|
||||
int last_session_id_ = 0;
|
||||
std::map<int, std::unique_ptr<v8_inspector::V8InspectorSession>> sessions_;
|
||||
std::map<v8_inspector::V8InspectorSession*, int> context_group_by_session_;
|
||||
std::map<int, std::unique_ptr<v8_inspector::V8Inspector::Channel>> channels_;
|
||||
v8::Global<v8::Value> memory_info_;
|
||||
FrontendChannel* frontend_channel_;
|
||||
bool current_time_set_ = false;
|
||||
double current_time_ = 0.0;
|
||||
bool log_console_api_message_calls_ = false;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(IsolateData);
|
||||
};
|
||||
|
||||
#endif // V8_TEST_INSPECTOR_PROTOCOL_ISOLATE_DATA_H_
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
#include "test/inspector/task-runner.h"
|
||||
|
||||
#include "test/inspector/inspector-impl.h"
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#include <unistd.h> // NOLINT
|
||||
#endif // !defined(_WIN32) && !defined(_WIN64)
|
||||
@ -41,7 +39,7 @@ TaskRunner::TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks,
|
||||
bool catch_exceptions,
|
||||
v8::base::Semaphore* ready_semaphore,
|
||||
v8::StartupData* startup_data,
|
||||
InspectorClientImpl::FrontendChannel* channel)
|
||||
IsolateData::FrontendChannel* channel)
|
||||
: Thread(Options("Task Runner")),
|
||||
setup_global_tasks_(std::move(setup_global_tasks)),
|
||||
startup_data_(startup_data),
|
||||
@ -123,16 +121,16 @@ TaskRunner::Task* TaskRunner::GetNext(bool only_protocol) {
|
||||
AsyncTask::AsyncTask(IsolateData* data, const char* task_name)
|
||||
: instrumenting_(data && task_name) {
|
||||
if (!instrumenting_) return;
|
||||
data->inspector()->inspector()->asyncTaskScheduled(
|
||||
data->inspector()->asyncTaskScheduled(
|
||||
v8_inspector::StringView(reinterpret_cast<const uint8_t*>(task_name),
|
||||
strlen(task_name)),
|
||||
this, false);
|
||||
}
|
||||
|
||||
void AsyncTask::Run() {
|
||||
if (instrumenting_) data()->inspector()->inspector()->asyncTaskStarted(this);
|
||||
if (instrumenting_) data()->inspector()->asyncTaskStarted(this);
|
||||
AsyncRun();
|
||||
if (instrumenting_) data()->inspector()->inspector()->asyncTaskFinished(this);
|
||||
if (instrumenting_) data()->inspector()->asyncTaskFinished(this);
|
||||
}
|
||||
|
||||
ExecuteStringTask::ExecuteStringTask(
|
||||
|
@ -41,7 +41,7 @@ class TaskRunner : public v8::base::Thread {
|
||||
TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks,
|
||||
bool catch_exceptions, v8::base::Semaphore* ready_semaphore,
|
||||
v8::StartupData* startup_data,
|
||||
InspectorClientImpl::FrontendChannel* channel);
|
||||
IsolateData::FrontendChannel* channel);
|
||||
virtual ~TaskRunner();
|
||||
IsolateData* data() const { return data_.get(); }
|
||||
|
||||
@ -63,7 +63,7 @@ class TaskRunner : public v8::base::Thread {
|
||||
|
||||
IsolateData::SetupGlobalTasks setup_global_tasks_;
|
||||
v8::StartupData* startup_data_;
|
||||
InspectorClientImpl::FrontendChannel* channel_;
|
||||
IsolateData::FrontendChannel* channel_;
|
||||
bool catch_exceptions_;
|
||||
v8::base::Semaphore* ready_semaphore_;
|
||||
std::unique_ptr<IsolateData> data_;
|
||||
|
Loading…
Reference in New Issue
Block a user