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