Index: src/d8.cc |
diff --git a/src/d8.cc b/src/d8.cc |
index 28ebfc05b9839327fb596ac491514e1b341fe1a9..bce9103f6499fbbafb869c2085d5a40e69e523df 100644 |
--- a/src/d8.cc |
+++ b/src/d8.cc |
@@ -34,6 +34,10 @@ |
#include "src/utils.h" |
#include "src/v8.h" |
+#ifdef V8_INSPECTOR_ENABLED |
+#include "include/v8-inspector.h" |
+#endif // V8_INSPECTOR_ENABLED |
+ |
#if !defined(_WIN32) && !defined(_WIN64) |
#include <unistd.h> // NOLINT |
#else |
@@ -596,7 +600,8 @@ class ModuleEmbedderData { |
enum { |
// The debugger reserves the first slot in the Context embedder data. |
kDebugIdIndex = Context::kDebugIdIndex, |
- kModuleEmbedderDataIndex |
+ kModuleEmbedderDataIndex, |
+ kInspectorClientIndex |
}; |
void InitializeModuleEmbedderData(Local<Context> context) { |
@@ -1759,6 +1764,130 @@ void Shell::RunShell(Isolate* isolate) { |
printf("\n"); |
} |
+#ifdef V8_INSPECTOR_ENABLED |
+class InspectorFrontend final : public v8_inspector::V8Inspector::Channel { |
+ public: |
+ explicit InspectorFrontend(Local<Context> context) { |
+ isolate_ = context->GetIsolate(); |
+ context_.Reset(isolate_, context); |
+ } |
+ virtual ~InspectorFrontend() = default; |
+ |
+ private: |
+ void sendProtocolResponse(int callId, |
+ const v8_inspector::StringView& message) override { |
+ Send(message); |
+ } |
+ void sendProtocolNotification( |
+ const v8_inspector::StringView& message) override { |
+ Send(message); |
+ } |
+ void flushProtocolNotifications() override {} |
+ |
+ void Send(const v8_inspector::StringView& string) { |
+ int length = static_cast<int>(string.length()); |
+ DCHECK(length < v8::String::kMaxLength); |
+ Local<String> message = |
+ (string.is8Bit() |
+ ? v8::String::NewFromOneByte( |
+ isolate_, |
+ reinterpret_cast<const uint8_t*>(string.characters8()), |
+ v8::NewStringType::kNormal, length) |
+ : v8::String::NewFromTwoByte( |
+ isolate_, |
+ reinterpret_cast<const uint16_t*>(string.characters16()), |
+ v8::NewStringType::kNormal, length)) |
+ .ToLocalChecked(); |
+ Local<String> callback_name = |
+ v8::String::NewFromUtf8(isolate_, "receive", v8::NewStringType::kNormal) |
+ .ToLocalChecked(); |
+ Local<Context> context = context_.Get(isolate_); |
+ Local<Value> callback = |
+ context->Global()->Get(context, callback_name).ToLocalChecked(); |
+ if (callback->IsFunction()) { |
+ v8::TryCatch try_catch(isolate_); |
+ Local<Value> args[] = {message}; |
+ if (Local<Function>::Cast(callback) |
+ ->Call(context, Undefined(isolate_), 1, args) |
+ .IsEmpty()) { |
+ try_catch.ReThrow(); |
+ } |
+ } |
+ } |
+ |
+ Isolate* isolate_; |
+ Global<Context> context_; |
+}; |
+ |
+class InspectorClient : public v8_inspector::V8InspectorClient { |
+ public: |
+ InspectorClient(Local<Context> context, bool connect) { |
+ if (!connect) return; |
+ isolate_ = context->GetIsolate(); |
+ channel_.reset(new InspectorFrontend(context)); |
+ inspector_ = v8_inspector::V8Inspector::create(isolate_, this); |
+ session_ = |
+ inspector_->connect(1, channel_.get(), v8_inspector::StringView()); |
+ context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this); |
+ inspector_->contextCreated(v8_inspector::V8ContextInfo( |
+ context, kContextGroupId, v8_inspector::StringView())); |
+ |
+ Local<Value> function = |
+ FunctionTemplate::New(isolate_, SendInspectorMessage) |
+ ->GetFunction(context) |
+ .ToLocalChecked(); |
+ Local<String> function_name = |
+ String::NewFromUtf8(isolate_, "send", NewStringType::kNormal) |
+ .ToLocalChecked(); |
+ CHECK(context->Global()->Set(context, function_name, function).FromJust()); |
+ |
+ context_.Reset(isolate_, context); |
+ } |
+ |
+ private: |
+ static v8_inspector::V8InspectorSession* GetSession(Local<Context> context) { |
+ InspectorClient* inspector_client = static_cast<InspectorClient*>( |
+ context->GetAlignedPointerFromEmbedderData(kInspectorClientIndex)); |
+ return inspector_client->session_.get(); |
+ } |
+ |
+ Local<Context> ensureDefaultContextInGroup(int group_id) override { |
+ DCHECK(isolate_); |
+ DCHECK_EQ(kContextGroupId, group_id); |
+ return context_.Get(isolate_); |
+ } |
+ |
+ static void SendInspectorMessage( |
+ const v8::FunctionCallbackInfo<v8::Value>& args) { |
+ Isolate* isolate = args.GetIsolate(); |
+ v8::HandleScope handle_scope(isolate); |
+ Local<Context> context = isolate->GetCurrentContext(); |
+ args.GetReturnValue().Set(Undefined(isolate)); |
+ Local<String> message = args[0]->ToString(context).ToLocalChecked(); |
+ v8_inspector::V8InspectorSession* session = |
+ InspectorClient::GetSession(context); |
+ int length = message->Length(); |
+ std::unique_ptr<uint16_t> buffer(new uint16_t[length]); |
+ message->Write(buffer.get(), 0, length); |
+ v8_inspector::StringView message_view(buffer.get(), length); |
+ session->dispatchProtocolMessage(message_view); |
+ args.GetReturnValue().Set(True(isolate)); |
+ } |
+ |
+ static const int kContextGroupId = 1; |
+ |
+ std::unique_ptr<v8_inspector::V8Inspector> inspector_; |
+ std::unique_ptr<v8_inspector::V8InspectorSession> session_; |
+ std::unique_ptr<v8_inspector::V8Inspector::Channel> channel_; |
+ Global<Context> context_; |
+ Isolate* isolate_; |
+}; |
+#else // V8_INSPECTOR_ENABLED |
+class InspectorClient { |
+ public: |
+ InspectorClient(Local<Context> context, bool connect) { CHECK(!connect); } |
+}; |
+#endif // V8_INSPECTOR_ENABLED |
SourceGroup::~SourceGroup() { |
delete thread_; |
@@ -1842,7 +1971,6 @@ base::Thread::Options SourceGroup::GetThreadOptions() { |
return base::Thread::Options("IsolateThread", 2 * MB); |
} |
- |
void SourceGroup::ExecuteInThread() { |
Isolate::CreateParams create_params; |
create_params.array_buffer_allocator = Shell::array_buffer_allocator; |
@@ -1857,6 +1985,8 @@ void SourceGroup::ExecuteInThread() { |
Local<Context> context = Shell::CreateEvaluationContext(isolate); |
{ |
Context::Scope cscope(context); |
+ InspectorClient inspector_client(context, |
+ Shell::options.enable_inspector); |
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate)); |
Execute(isolate); |
} |
@@ -2252,6 +2382,9 @@ bool Shell::SetOptions(int argc, char* argv[]) { |
} else if (strncmp(argv[i], "--trace-config=", 15) == 0) { |
options.trace_config = argv[i] + 15; |
argv[i] = NULL; |
+ } else if (strcmp(argv[i], "--enable-inspector") == 0) { |
+ options.enable_inspector = true; |
+ argv[i] = NULL; |
} |
} |
@@ -2301,6 +2434,7 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) { |
} |
{ |
Context::Scope cscope(context); |
+ InspectorClient inspector_client(context, options.enable_inspector); |
PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate)); |
options.isolate_sources[0].Execute(isolate); |
} |