Chromium Code Reviews| Index: src/d8.cc |
| diff --git a/src/d8.cc b/src/d8.cc |
| index 28ebfc05b9839327fb596ac491514e1b341fe1a9..58fef20cf9d877a1cd7b68fd7ca27587a0e151b6 100644 |
| --- a/src/d8.cc |
| +++ b/src/d8.cc |
| @@ -22,6 +22,7 @@ |
| #include "include/libplatform/libplatform.h" |
| #include "include/libplatform/v8-tracing.h" |
| +#include "include/v8-inspector.h" |
| #include "src/api.h" |
| #include "src/base/cpu.h" |
| #include "src/base/debug/stack_trace.h" |
| @@ -596,7 +597,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 +1761,122 @@ void Shell::RunShell(Isolate* isolate) { |
| printf("\n"); |
| } |
| +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) { |
| +#ifdef V8_INSPECTOR_ENABLED |
| + 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); |
|
jgruber
2016/10/19 07:33:03
Just curious - why aren't we using a standard sing
Yang
2016/10/20 07:29:30
d8 can run with --isolate option, in which case we
|
| + inspector_->contextCreated( |
| + v8_inspector::V8ContextInfo(context, 1, v8_inspector::StringView())); |
|
jgruber
2016/10/19 07:33:03
Please add a named constant to replace the 1 for t
Yang
2016/10/20 07:29:30
Done.
|
| + |
| + 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); |
| +#endif // V8_INSPECTOR_ENABLED |
| + } |
| + |
| + static v8_inspector::V8InspectorSession* GetSession(Local<Context> context) { |
|
jgruber
2016/10/19 07:33:03
Could this be private?
Yang
2016/10/20 07:29:30
Done.
|
| + InspectorClient* inspector_client = static_cast<InspectorClient*>( |
| + context->GetAlignedPointerFromEmbedderData(kInspectorClientIndex)); |
| + return inspector_client->session_.get(); |
| + } |
| + |
| + Local<Context> ensureDefaultContextInGroup(int groupId) override { |
| + CHECK(isolate_); |
| + return context_.Get(isolate_); |
| + } |
| + |
| + private: |
| + 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)); |
| + } |
| + |
| + 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_; |
| +}; |
| SourceGroup::~SourceGroup() { |
| delete thread_; |
| @@ -1842,7 +1960,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 +1974,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 +2371,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 +2423,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); |
| } |