OLD | NEW |
1 // Copyright 2017 the V8 project authors. All rights reserved. | 1 // Copyright 2017 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "test/inspector/isolate-data.h" | 5 #include "test/inspector/isolate-data.h" |
6 | 6 |
7 #include "test/inspector/inspector-impl.h" | |
8 #include "test/inspector/task-runner.h" | 7 #include "test/inspector/task-runner.h" |
9 | 8 |
10 namespace { | 9 namespace { |
11 | 10 |
12 const int kIsolateDataIndex = 2; | 11 const int kIsolateDataIndex = 2; |
13 const int kContextGroupIdIndex = 3; | 12 const int kContextGroupIdIndex = 3; |
14 | 13 |
15 v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) { | 14 v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) { |
16 v8::internal::Vector<uint16_t> buffer = | 15 v8::internal::Vector<uint16_t> buffer = |
17 v8::internal::Vector<uint16_t>::New(str->Length()); | 16 v8::internal::Vector<uint16_t>::New(str->Length()); |
18 str->Write(buffer.start(), 0, str->Length()); | 17 str->Write(buffer.start(), 0, str->Length()); |
19 return buffer; | 18 return buffer; |
20 } | 19 } |
21 | 20 |
| 21 v8::Local<v8::String> ToString(v8::Isolate* isolate, |
| 22 const v8_inspector::StringView& string) { |
| 23 if (string.is8Bit()) |
| 24 return v8::String::NewFromOneByte(isolate, string.characters8(), |
| 25 v8::NewStringType::kNormal, |
| 26 static_cast<int>(string.length())) |
| 27 .ToLocalChecked(); |
| 28 else |
| 29 return v8::String::NewFromTwoByte(isolate, string.characters16(), |
| 30 v8::NewStringType::kNormal, |
| 31 static_cast<int>(string.length())) |
| 32 .ToLocalChecked(); |
| 33 } |
| 34 |
| 35 void Print(v8::Isolate* isolate, const v8_inspector::StringView& string) { |
| 36 v8::Local<v8::String> v8_string = ToString(isolate, string); |
| 37 v8::String::Utf8Value utf8_string(v8_string); |
| 38 fwrite(*utf8_string, sizeof(**utf8_string), utf8_string.length(), stdout); |
| 39 } |
| 40 |
| 41 class ChannelImpl final : public v8_inspector::V8Inspector::Channel { |
| 42 public: |
| 43 ChannelImpl(IsolateData::FrontendChannel* frontend_channel, int session_id) |
| 44 : frontend_channel_(frontend_channel), session_id_(session_id) {} |
| 45 virtual ~ChannelImpl() = default; |
| 46 |
| 47 private: |
| 48 void sendResponse( |
| 49 int callId, |
| 50 std::unique_ptr<v8_inspector::StringBuffer> message) override { |
| 51 frontend_channel_->SendMessageToFrontend(session_id_, message->string()); |
| 52 } |
| 53 void sendNotification( |
| 54 std::unique_ptr<v8_inspector::StringBuffer> message) override { |
| 55 frontend_channel_->SendMessageToFrontend(session_id_, message->string()); |
| 56 } |
| 57 void flushProtocolNotifications() override {} |
| 58 |
| 59 IsolateData::FrontendChannel* frontend_channel_; |
| 60 int session_id_; |
| 61 DISALLOW_COPY_AND_ASSIGN(ChannelImpl); |
| 62 }; |
| 63 |
22 } // namespace | 64 } // namespace |
23 | 65 |
24 IsolateData::IsolateData(TaskRunner* task_runner, | 66 IsolateData::IsolateData(TaskRunner* task_runner, |
25 IsolateData::SetupGlobalTasks setup_global_tasks, | 67 IsolateData::SetupGlobalTasks setup_global_tasks, |
26 v8::StartupData* startup_data, | 68 v8::StartupData* startup_data, |
27 InspectorClientImpl::FrontendChannel* channel) | 69 FrontendChannel* channel) |
28 : task_runner_(task_runner), | 70 : task_runner_(task_runner), |
29 setup_global_tasks_(std::move(setup_global_tasks)) { | 71 setup_global_tasks_(std::move(setup_global_tasks)), |
| 72 frontend_channel_(channel) { |
30 v8::Isolate::CreateParams params; | 73 v8::Isolate::CreateParams params; |
31 params.array_buffer_allocator = | 74 params.array_buffer_allocator = |
32 v8::ArrayBuffer::Allocator::NewDefaultAllocator(); | 75 v8::ArrayBuffer::Allocator::NewDefaultAllocator(); |
33 params.snapshot_blob = startup_data; | 76 params.snapshot_blob = startup_data; |
34 isolate_ = v8::Isolate::New(params); | 77 isolate_ = v8::Isolate::New(params); |
35 isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped); | 78 isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped); |
36 if (channel) | 79 if (frontend_channel_) { |
37 inspector_.reset(new InspectorClientImpl(isolate_, task_runner, channel)); | 80 isolate_->AddMessageListener(&IsolateData::MessageHandler); |
| 81 inspector_ = v8_inspector::V8Inspector::create(isolate_, this); |
| 82 } |
38 } | 83 } |
39 | 84 |
40 IsolateData* IsolateData::FromContext(v8::Local<v8::Context> context) { | 85 IsolateData* IsolateData::FromContext(v8::Local<v8::Context> context) { |
41 return static_cast<IsolateData*>( | 86 return static_cast<IsolateData*>( |
42 context->GetAlignedPointerFromEmbedderData(kIsolateDataIndex)); | 87 context->GetAlignedPointerFromEmbedderData(kIsolateDataIndex)); |
43 } | 88 } |
44 | 89 |
45 int IsolateData::CreateContextGroup() { | 90 int IsolateData::CreateContextGroup() { |
46 v8::HandleScope handle_scope(isolate_); | 91 v8::HandleScope handle_scope(isolate_); |
47 v8::Local<v8::ObjectTemplate> global_template = | 92 v8::Local<v8::ObjectTemplate> global_template = |
48 v8::ObjectTemplate::New(isolate_); | 93 v8::ObjectTemplate::New(isolate_); |
49 for (auto it = setup_global_tasks_.begin(); it != setup_global_tasks_.end(); | 94 for (auto it = setup_global_tasks_.begin(); it != setup_global_tasks_.end(); |
50 ++it) { | 95 ++it) { |
51 (*it)->Run(isolate_, global_template); | 96 (*it)->Run(isolate_, global_template); |
52 } | 97 } |
53 v8::Local<v8::Context> context = | 98 v8::Local<v8::Context> context = |
54 v8::Context::New(isolate_, nullptr, global_template); | 99 v8::Context::New(isolate_, nullptr, global_template); |
55 context->SetAlignedPointerInEmbedderData(kIsolateDataIndex, this); | 100 context->SetAlignedPointerInEmbedderData(kIsolateDataIndex, this); |
56 int context_group_id = ++last_context_group_id_; | 101 int context_group_id = ++last_context_group_id_; |
57 // Should be 2-byte aligned. | 102 // Should be 2-byte aligned. |
58 context->SetAlignedPointerInEmbedderData( | 103 context->SetAlignedPointerInEmbedderData( |
59 kContextGroupIdIndex, reinterpret_cast<void*>(context_group_id * 2)); | 104 kContextGroupIdIndex, reinterpret_cast<void*>(context_group_id * 2)); |
60 contexts_[context_group_id].Reset(isolate_, context); | 105 contexts_[context_group_id].Reset(isolate_, context); |
61 if (inspector_) inspector_->ContextCreated(context, context_group_id); | 106 if (inspector_) FireContextCreated(context, context_group_id); |
62 return context_group_id; | 107 return context_group_id; |
63 } | 108 } |
64 | 109 |
65 v8::Local<v8::Context> IsolateData::GetContext(int context_group_id) { | 110 v8::Local<v8::Context> IsolateData::GetContext(int context_group_id) { |
66 return contexts_[context_group_id].Get(isolate_); | 111 return contexts_[context_group_id].Get(isolate_); |
67 } | 112 } |
68 | 113 |
69 int IsolateData::GetContextGroupId(v8::Local<v8::Context> context) { | 114 int IsolateData::GetContextGroupId(v8::Local<v8::Context> context) { |
70 return static_cast<int>( | 115 return static_cast<int>( |
71 reinterpret_cast<intptr_t>( | 116 reinterpret_cast<intptr_t>( |
72 context->GetAlignedPointerFromEmbedderData(kContextGroupIdIndex)) / | 117 context->GetAlignedPointerFromEmbedderData(kContextGroupIdIndex)) / |
73 2); | 118 2); |
74 } | 119 } |
75 | 120 |
76 void IsolateData::RegisterModule(v8::Local<v8::Context> context, | 121 void IsolateData::RegisterModule(v8::Local<v8::Context> context, |
77 v8::internal::Vector<uint16_t> name, | 122 v8::internal::Vector<uint16_t> name, |
78 v8::ScriptCompiler::Source* source) { | 123 v8::ScriptCompiler::Source* source) { |
79 v8::Local<v8::Module> module; | 124 v8::Local<v8::Module> module; |
80 if (!v8::ScriptCompiler::CompileModule(isolate(), source).ToLocal(&module)) | 125 if (!v8::ScriptCompiler::CompileModule(isolate(), source).ToLocal(&module)) |
81 return; | 126 return; |
82 if (!module->Instantiate(context, &IsolateData::ModuleResolveCallback)) | 127 if (!module->Instantiate(context, &IsolateData::ModuleResolveCallback)) |
83 return; | 128 return; |
84 v8::Local<v8::Value> result; | 129 v8::Local<v8::Value> result; |
85 if (!module->Evaluate(context).ToLocal(&result)) return; | 130 if (!module->Evaluate(context).ToLocal(&result)) return; |
86 modules_[name] = v8::Global<v8::Module>(isolate_, module); | 131 modules_[name] = v8::Global<v8::Module>(isolate_, module); |
87 } | 132 } |
88 | 133 |
| 134 // static |
89 v8::MaybeLocal<v8::Module> IsolateData::ModuleResolveCallback( | 135 v8::MaybeLocal<v8::Module> IsolateData::ModuleResolveCallback( |
90 v8::Local<v8::Context> context, v8::Local<v8::String> specifier, | 136 v8::Local<v8::Context> context, v8::Local<v8::String> specifier, |
91 v8::Local<v8::Module> referrer) { | 137 v8::Local<v8::Module> referrer) { |
92 std::string str = *v8::String::Utf8Value(specifier); | 138 std::string str = *v8::String::Utf8Value(specifier); |
93 IsolateData* data = IsolateData::FromContext(context); | 139 IsolateData* data = IsolateData::FromContext(context); |
94 return data->modules_[ToVector(specifier)].Get(data->isolate_); | 140 return data->modules_[ToVector(specifier)].Get(data->isolate_); |
95 } | 141 } |
| 142 |
| 143 int IsolateData::ConnectSession(int context_group_id, |
| 144 const v8_inspector::StringView& state) { |
| 145 int session_id = ++last_session_id_; |
| 146 channels_[session_id].reset(new ChannelImpl(frontend_channel_, session_id)); |
| 147 sessions_[session_id] = |
| 148 inspector_->connect(context_group_id, channels_[session_id].get(), state); |
| 149 context_group_by_session_[sessions_[session_id].get()] = context_group_id; |
| 150 return session_id; |
| 151 } |
| 152 |
| 153 std::unique_ptr<v8_inspector::StringBuffer> IsolateData::DisconnectSession( |
| 154 int session_id) { |
| 155 auto it = sessions_.find(session_id); |
| 156 CHECK(it != sessions_.end()); |
| 157 context_group_by_session_.erase(it->second.get()); |
| 158 std::unique_ptr<v8_inspector::StringBuffer> result = it->second->stateJSON(); |
| 159 sessions_.erase(it); |
| 160 channels_.erase(session_id); |
| 161 return result; |
| 162 } |
| 163 |
| 164 void IsolateData::SendMessage(int session_id, |
| 165 const v8_inspector::StringView& message) { |
| 166 auto it = sessions_.find(session_id); |
| 167 if (it != sessions_.end()) it->second->dispatchProtocolMessage(message); |
| 168 } |
| 169 |
| 170 void IsolateData::BreakProgram(int context_group_id, |
| 171 const v8_inspector::StringView& reason, |
| 172 const v8_inspector::StringView& details) { |
| 173 for (int session_id : GetSessionIds(context_group_id)) { |
| 174 auto it = sessions_.find(session_id); |
| 175 if (it != sessions_.end()) it->second->breakProgram(reason, details); |
| 176 } |
| 177 } |
| 178 |
| 179 void IsolateData::SchedulePauseOnNextStatement( |
| 180 int context_group_id, const v8_inspector::StringView& reason, |
| 181 const v8_inspector::StringView& details) { |
| 182 for (int session_id : GetSessionIds(context_group_id)) { |
| 183 auto it = sessions_.find(session_id); |
| 184 if (it != sessions_.end()) |
| 185 it->second->schedulePauseOnNextStatement(reason, details); |
| 186 } |
| 187 } |
| 188 |
| 189 void IsolateData::CancelPauseOnNextStatement(int context_group_id) { |
| 190 for (int session_id : GetSessionIds(context_group_id)) { |
| 191 auto it = sessions_.find(session_id); |
| 192 if (it != sessions_.end()) it->second->cancelPauseOnNextStatement(); |
| 193 } |
| 194 } |
| 195 |
| 196 // static |
| 197 void IsolateData::MessageHandler(v8::Local<v8::Message> message, |
| 198 v8::Local<v8::Value> exception) { |
| 199 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 200 v8::Local<v8::Context> context = isolate->GetEnteredContext(); |
| 201 if (context.IsEmpty()) return; |
| 202 v8_inspector::V8Inspector* inspector = |
| 203 IsolateData::FromContext(context)->inspector_.get(); |
| 204 |
| 205 v8::Local<v8::StackTrace> stack = message->GetStackTrace(); |
| 206 int script_id = |
| 207 static_cast<int>(message->GetScriptOrigin().ScriptID()->Value()); |
| 208 if (!stack.IsEmpty() && stack->GetFrameCount() > 0) { |
| 209 int top_script_id = stack->GetFrame(0)->GetScriptId(); |
| 210 if (top_script_id == script_id) script_id = 0; |
| 211 } |
| 212 int line_number = message->GetLineNumber(context).FromMaybe(0); |
| 213 int column_number = 0; |
| 214 if (message->GetStartColumn(context).IsJust()) |
| 215 column_number = message->GetStartColumn(context).FromJust() + 1; |
| 216 |
| 217 v8_inspector::StringView detailed_message; |
| 218 v8::internal::Vector<uint16_t> message_text_string = ToVector(message->Get()); |
| 219 v8_inspector::StringView message_text(message_text_string.start(), |
| 220 message_text_string.length()); |
| 221 v8::internal::Vector<uint16_t> url_string; |
| 222 if (message->GetScriptOrigin().ResourceName()->IsString()) { |
| 223 url_string = |
| 224 ToVector(message->GetScriptOrigin().ResourceName().As<v8::String>()); |
| 225 } |
| 226 v8_inspector::StringView url(url_string.start(), url_string.length()); |
| 227 |
| 228 inspector->exceptionThrown(context, message_text, exception, detailed_message, |
| 229 url, line_number, column_number, |
| 230 inspector->createStackTrace(stack), script_id); |
| 231 } |
| 232 |
| 233 void IsolateData::FireContextCreated(v8::Local<v8::Context> context, |
| 234 int context_group_id) { |
| 235 v8_inspector::V8ContextInfo info(context, context_group_id, |
| 236 v8_inspector::StringView()); |
| 237 info.hasMemoryOnConsole = true; |
| 238 inspector_->contextCreated(info); |
| 239 } |
| 240 |
| 241 void IsolateData::FireContextDestroyed(v8::Local<v8::Context> context) { |
| 242 inspector_->contextDestroyed(context); |
| 243 } |
| 244 |
| 245 std::vector<int> IsolateData::GetSessionIds(int context_group_id) { |
| 246 std::vector<int> result; |
| 247 for (auto& it : sessions_) { |
| 248 if (context_group_by_session_[it.second.get()] == context_group_id) |
| 249 result.push_back(it.first); |
| 250 } |
| 251 return result; |
| 252 } |
| 253 |
| 254 bool IsolateData::formatAccessorsAsProperties(v8::Local<v8::Value> object) { |
| 255 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 256 v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| 257 v8::Local<v8::Private> shouldFormatAccessorsPrivate = v8::Private::ForApi( |
| 258 isolate, v8::String::NewFromUtf8(isolate, "allowAccessorFormatting", |
| 259 v8::NewStringType::kNormal) |
| 260 .ToLocalChecked()); |
| 261 CHECK(object->IsObject()); |
| 262 return object.As<v8::Object>() |
| 263 ->HasPrivate(context, shouldFormatAccessorsPrivate) |
| 264 .FromMaybe(false); |
| 265 } |
| 266 |
| 267 v8::Local<v8::Context> IsolateData::ensureDefaultContextInGroup( |
| 268 int context_group_id) { |
| 269 return GetContext(context_group_id); |
| 270 } |
| 271 |
| 272 void IsolateData::SetCurrentTimeMS(double time) { |
| 273 current_time_ = time; |
| 274 current_time_set_ = true; |
| 275 } |
| 276 |
| 277 double IsolateData::currentTimeMS() { |
| 278 if (current_time_set_) return current_time_; |
| 279 return v8::base::OS::TimeCurrentMillis(); |
| 280 } |
| 281 |
| 282 void IsolateData::SetMemoryInfo(v8::Local<v8::Value> memory_info) { |
| 283 memory_info_.Reset(isolate_, memory_info); |
| 284 } |
| 285 |
| 286 void IsolateData::SetLogConsoleApiMessageCalls(bool log) { |
| 287 log_console_api_message_calls_ = log; |
| 288 } |
| 289 |
| 290 v8::MaybeLocal<v8::Value> IsolateData::memoryInfo(v8::Isolate* isolate, |
| 291 v8::Local<v8::Context>) { |
| 292 if (memory_info_.IsEmpty()) return v8::MaybeLocal<v8::Value>(); |
| 293 return memory_info_.Get(isolate); |
| 294 } |
| 295 |
| 296 void IsolateData::runMessageLoopOnPause(int) { |
| 297 task_runner_->RunMessageLoop(true); |
| 298 } |
| 299 |
| 300 void IsolateData::quitMessageLoopOnPause() { task_runner_->QuitMessageLoop(); } |
| 301 |
| 302 void IsolateData::consoleAPIMessage(int contextGroupId, |
| 303 v8::Isolate::MessageErrorLevel level, |
| 304 const v8_inspector::StringView& message, |
| 305 const v8_inspector::StringView& url, |
| 306 unsigned lineNumber, unsigned columnNumber, |
| 307 v8_inspector::V8StackTrace* stack) { |
| 308 if (!log_console_api_message_calls_) return; |
| 309 Print(isolate_, message); |
| 310 fprintf(stdout, " ("); |
| 311 Print(isolate_, url); |
| 312 fprintf(stdout, ":%d:%d)", lineNumber, columnNumber); |
| 313 Print(isolate_, stack->toString()->string()); |
| 314 fprintf(stdout, "\n"); |
| 315 } |
OLD | NEW |