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 "src/inspector/V8InspectorSessionImpl.h" | |
6 | |
7 #include "src/inspector/InjectedScript.h" | |
8 #include "src/inspector/InspectedContext.h" | |
9 #include "src/inspector/RemoteObjectId.h" | |
10 #include "src/inspector/SearchUtil.h" | |
11 #include "src/inspector/StringUtil.h" | |
12 #include "src/inspector/V8ConsoleAgentImpl.h" | |
13 #include "src/inspector/V8Debugger.h" | |
14 #include "src/inspector/V8DebuggerAgentImpl.h" | |
15 #include "src/inspector/V8HeapProfilerAgentImpl.h" | |
16 #include "src/inspector/V8InspectorImpl.h" | |
17 #include "src/inspector/V8ProfilerAgentImpl.h" | |
18 #include "src/inspector/V8RuntimeAgentImpl.h" | |
19 #include "src/inspector/V8SchemaAgentImpl.h" | |
20 #include "src/inspector/protocol/Protocol.h" | |
21 | |
22 namespace v8_inspector { | |
23 | |
24 // static | |
25 bool V8InspectorSession::canDispatchMethod(const StringView& method) { | |
26 return stringViewStartsWith(method, | |
27 protocol::Runtime::Metainfo::commandPrefix) || | |
28 stringViewStartsWith(method, | |
29 protocol::Debugger::Metainfo::commandPrefix) || | |
30 stringViewStartsWith(method, | |
31 protocol::Profiler::Metainfo::commandPrefix) || | |
32 stringViewStartsWith( | |
33 method, protocol::HeapProfiler::Metainfo::commandPrefix) || | |
34 stringViewStartsWith(method, | |
35 protocol::Console::Metainfo::commandPrefix) || | |
36 stringViewStartsWith(method, | |
37 protocol::Schema::Metainfo::commandPrefix); | |
38 } | |
39 | |
40 std::unique_ptr<V8InspectorSessionImpl> V8InspectorSessionImpl::create( | |
41 V8InspectorImpl* inspector, int contextGroupId, | |
42 V8Inspector::Channel* channel, const StringView& state) { | |
43 return wrapUnique( | |
44 new V8InspectorSessionImpl(inspector, contextGroupId, channel, state)); | |
45 } | |
46 | |
47 V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector, | |
48 int contextGroupId, | |
49 V8Inspector::Channel* channel, | |
50 const StringView& savedState) | |
51 : m_contextGroupId(contextGroupId), | |
52 m_inspector(inspector), | |
53 m_channel(channel), | |
54 m_customObjectFormatterEnabled(false), | |
55 m_dispatcher(this), | |
56 m_state(nullptr), | |
57 m_runtimeAgent(nullptr), | |
58 m_debuggerAgent(nullptr), | |
59 m_heapProfilerAgent(nullptr), | |
60 m_profilerAgent(nullptr), | |
61 m_consoleAgent(nullptr), | |
62 m_schemaAgent(nullptr) { | |
63 if (savedState.length()) { | |
64 std::unique_ptr<protocol::Value> state = | |
65 protocol::parseJSON(toString16(savedState)); | |
66 if (state) m_state = protocol::DictionaryValue::cast(std::move(state)); | |
67 if (!m_state) m_state = protocol::DictionaryValue::create(); | |
68 } else { | |
69 m_state = protocol::DictionaryValue::create(); | |
70 } | |
71 | |
72 m_runtimeAgent = wrapUnique(new V8RuntimeAgentImpl( | |
73 this, this, agentState(protocol::Runtime::Metainfo::domainName))); | |
74 protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get()); | |
75 | |
76 m_debuggerAgent = wrapUnique(new V8DebuggerAgentImpl( | |
77 this, this, agentState(protocol::Debugger::Metainfo::domainName))); | |
78 protocol::Debugger::Dispatcher::wire(&m_dispatcher, m_debuggerAgent.get()); | |
79 | |
80 m_profilerAgent = wrapUnique(new V8ProfilerAgentImpl( | |
81 this, this, agentState(protocol::Profiler::Metainfo::domainName))); | |
82 protocol::Profiler::Dispatcher::wire(&m_dispatcher, m_profilerAgent.get()); | |
83 | |
84 m_heapProfilerAgent = wrapUnique(new V8HeapProfilerAgentImpl( | |
85 this, this, agentState(protocol::HeapProfiler::Metainfo::domainName))); | |
86 protocol::HeapProfiler::Dispatcher::wire(&m_dispatcher, | |
87 m_heapProfilerAgent.get()); | |
88 | |
89 m_consoleAgent = wrapUnique(new V8ConsoleAgentImpl( | |
90 this, this, agentState(protocol::Console::Metainfo::domainName))); | |
91 protocol::Console::Dispatcher::wire(&m_dispatcher, m_consoleAgent.get()); | |
92 | |
93 m_schemaAgent = wrapUnique(new V8SchemaAgentImpl( | |
94 this, this, agentState(protocol::Schema::Metainfo::domainName))); | |
95 protocol::Schema::Dispatcher::wire(&m_dispatcher, m_schemaAgent.get()); | |
96 | |
97 if (savedState.length()) { | |
98 m_runtimeAgent->restore(); | |
99 m_debuggerAgent->restore(); | |
100 m_heapProfilerAgent->restore(); | |
101 m_profilerAgent->restore(); | |
102 m_consoleAgent->restore(); | |
103 } | |
104 } | |
105 | |
106 V8InspectorSessionImpl::~V8InspectorSessionImpl() { | |
107 ErrorString errorString; | |
108 m_consoleAgent->disable(&errorString); | |
109 m_profilerAgent->disable(&errorString); | |
110 m_heapProfilerAgent->disable(&errorString); | |
111 m_debuggerAgent->disable(&errorString); | |
112 m_runtimeAgent->disable(&errorString); | |
113 | |
114 discardInjectedScripts(); | |
115 m_inspector->disconnect(this); | |
116 } | |
117 | |
118 protocol::DictionaryValue* V8InspectorSessionImpl::agentState( | |
119 const String16& name) { | |
120 protocol::DictionaryValue* state = m_state->getObject(name); | |
121 if (!state) { | |
122 std::unique_ptr<protocol::DictionaryValue> newState = | |
123 protocol::DictionaryValue::create(); | |
124 state = newState.get(); | |
125 m_state->setObject(name, std::move(newState)); | |
126 } | |
127 return state; | |
128 } | |
129 | |
130 void V8InspectorSessionImpl::sendProtocolResponse(int callId, | |
131 const String16& message) { | |
132 m_channel->sendProtocolResponse(callId, toStringView(message)); | |
133 } | |
134 | |
135 void V8InspectorSessionImpl::sendProtocolNotification(const String16& message) { | |
136 m_channel->sendProtocolNotification(toStringView(message)); | |
137 } | |
138 | |
139 void V8InspectorSessionImpl::flushProtocolNotifications() { | |
140 m_channel->flushProtocolNotifications(); | |
141 } | |
142 | |
143 void V8InspectorSessionImpl::reset() { | |
144 m_debuggerAgent->reset(); | |
145 m_runtimeAgent->reset(); | |
146 discardInjectedScripts(); | |
147 } | |
148 | |
149 void V8InspectorSessionImpl::discardInjectedScripts() { | |
150 m_inspectedObjects.clear(); | |
151 const V8InspectorImpl::ContextByIdMap* contexts = | |
152 m_inspector->contextGroup(m_contextGroupId); | |
153 if (!contexts) return; | |
154 | |
155 std::vector<int> keys; | |
156 keys.reserve(contexts->size()); | |
157 for (auto& idContext : *contexts) keys.push_back(idContext.first); | |
158 for (auto& key : keys) { | |
159 contexts = m_inspector->contextGroup(m_contextGroupId); | |
160 if (!contexts) continue; | |
161 auto contextIt = contexts->find(key); | |
162 if (contextIt != contexts->end()) | |
163 contextIt->second | |
164 ->discardInjectedScript(); // This may destroy some contexts. | |
165 } | |
166 } | |
167 | |
168 InjectedScript* V8InspectorSessionImpl::findInjectedScript( | |
169 ErrorString* errorString, int contextId) { | |
170 if (!contextId) { | |
171 *errorString = "Cannot find context with specified id"; | |
172 return nullptr; | |
173 } | |
174 | |
175 const V8InspectorImpl::ContextByIdMap* contexts = | |
176 m_inspector->contextGroup(m_contextGroupId); | |
177 if (!contexts) { | |
178 *errorString = "Cannot find context with specified id"; | |
179 return nullptr; | |
180 } | |
181 | |
182 auto contextsIt = contexts->find(contextId); | |
183 if (contextsIt == contexts->end()) { | |
184 *errorString = "Cannot find context with specified id"; | |
185 return nullptr; | |
186 } | |
187 | |
188 const std::unique_ptr<InspectedContext>& context = contextsIt->second; | |
189 if (!context->getInjectedScript()) { | |
190 context->createInjectedScript(); | |
191 if (!context->getInjectedScript()) { | |
192 *errorString = "Cannot access specified execution context"; | |
193 return nullptr; | |
194 } | |
195 if (m_customObjectFormatterEnabled) | |
196 context->getInjectedScript()->setCustomObjectFormatterEnabled(true); | |
197 } | |
198 return context->getInjectedScript(); | |
199 } | |
200 | |
201 InjectedScript* V8InspectorSessionImpl::findInjectedScript( | |
202 ErrorString* errorString, RemoteObjectIdBase* objectId) { | |
203 return objectId ? findInjectedScript(errorString, objectId->contextId()) | |
204 : nullptr; | |
205 } | |
206 | |
207 void V8InspectorSessionImpl::releaseObjectGroup(const StringView& objectGroup) { | |
208 releaseObjectGroup(toString16(objectGroup)); | |
209 } | |
210 | |
211 void V8InspectorSessionImpl::releaseObjectGroup(const String16& objectGroup) { | |
212 const V8InspectorImpl::ContextByIdMap* contexts = | |
213 m_inspector->contextGroup(m_contextGroupId); | |
214 if (!contexts) return; | |
215 | |
216 std::vector<int> keys; | |
217 for (auto& idContext : *contexts) keys.push_back(idContext.first); | |
218 for (auto& key : keys) { | |
219 contexts = m_inspector->contextGroup(m_contextGroupId); | |
220 if (!contexts) continue; | |
221 auto contextsIt = contexts->find(key); | |
222 if (contextsIt == contexts->end()) continue; | |
223 InjectedScript* injectedScript = contextsIt->second->getInjectedScript(); | |
224 if (injectedScript) | |
225 injectedScript->releaseObjectGroup( | |
226 objectGroup); // This may destroy some contexts. | |
227 } | |
228 } | |
229 | |
230 bool V8InspectorSessionImpl::unwrapObject( | |
231 std::unique_ptr<StringBuffer>* error, const StringView& objectId, | |
232 v8::Local<v8::Value>* object, v8::Local<v8::Context>* context, | |
233 std::unique_ptr<StringBuffer>* objectGroup) { | |
234 ErrorString errorString; | |
235 String16 objectGroupString; | |
236 bool result = | |
237 unwrapObject(&errorString, toString16(objectId), object, context, | |
238 objectGroup ? &objectGroupString : nullptr); | |
239 if (error) *error = StringBufferImpl::adopt(errorString); | |
240 if (objectGroup) *objectGroup = StringBufferImpl::adopt(objectGroupString); | |
241 return result; | |
242 } | |
243 | |
244 bool V8InspectorSessionImpl::unwrapObject(ErrorString* errorString, | |
245 const String16& objectId, | |
246 v8::Local<v8::Value>* object, | |
247 v8::Local<v8::Context>* context, | |
248 String16* objectGroup) { | |
249 std::unique_ptr<RemoteObjectId> remoteId = | |
250 RemoteObjectId::parse(errorString, objectId); | |
251 if (!remoteId) return false; | |
252 InjectedScript* injectedScript = | |
253 findInjectedScript(errorString, remoteId.get()); | |
254 if (!injectedScript) return false; | |
255 if (!injectedScript->findObject(errorString, *remoteId, object)) return false; | |
256 *context = injectedScript->context()->context(); | |
257 if (objectGroup) *objectGroup = injectedScript->objectGroupName(*remoteId); | |
258 return true; | |
259 } | |
260 | |
261 std::unique_ptr<protocol::Runtime::API::RemoteObject> | |
262 V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context, | |
263 v8::Local<v8::Value> value, | |
264 const StringView& groupName) { | |
265 return wrapObject(context, value, toString16(groupName), false); | |
266 } | |
267 | |
268 std::unique_ptr<protocol::Runtime::RemoteObject> | |
269 V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context, | |
270 v8::Local<v8::Value> value, | |
271 const String16& groupName, | |
272 bool generatePreview) { | |
273 ErrorString errorString; | |
274 InjectedScript* injectedScript = | |
275 findInjectedScript(&errorString, V8Debugger::contextId(context)); | |
276 if (!injectedScript) return nullptr; | |
277 return injectedScript->wrapObject(&errorString, value, groupName, false, | |
278 generatePreview); | |
279 } | |
280 | |
281 std::unique_ptr<protocol::Runtime::RemoteObject> | |
282 V8InspectorSessionImpl::wrapTable(v8::Local<v8::Context> context, | |
283 v8::Local<v8::Value> table, | |
284 v8::Local<v8::Value> columns) { | |
285 ErrorString errorString; | |
286 InjectedScript* injectedScript = | |
287 findInjectedScript(&errorString, V8Debugger::contextId(context)); | |
288 if (!injectedScript) return nullptr; | |
289 return injectedScript->wrapTable(table, columns); | |
290 } | |
291 | |
292 void V8InspectorSessionImpl::setCustomObjectFormatterEnabled(bool enabled) { | |
293 m_customObjectFormatterEnabled = enabled; | |
294 const V8InspectorImpl::ContextByIdMap* contexts = | |
295 m_inspector->contextGroup(m_contextGroupId); | |
296 if (!contexts) return; | |
297 for (auto& idContext : *contexts) { | |
298 InjectedScript* injectedScript = idContext.second->getInjectedScript(); | |
299 if (injectedScript) | |
300 injectedScript->setCustomObjectFormatterEnabled(enabled); | |
301 } | |
302 } | |
303 | |
304 void V8InspectorSessionImpl::reportAllContexts(V8RuntimeAgentImpl* agent) { | |
305 const V8InspectorImpl::ContextByIdMap* contexts = | |
306 m_inspector->contextGroup(m_contextGroupId); | |
307 if (!contexts) return; | |
308 for (auto& idContext : *contexts) | |
309 agent->reportExecutionContextCreated(idContext.second.get()); | |
310 } | |
311 | |
312 void V8InspectorSessionImpl::dispatchProtocolMessage( | |
313 const StringView& message) { | |
314 m_dispatcher.dispatch(protocol::parseJSON(message)); | |
315 } | |
316 | |
317 std::unique_ptr<StringBuffer> V8InspectorSessionImpl::stateJSON() { | |
318 String16 json = m_state->toJSONString(); | |
319 return StringBufferImpl::adopt(json); | |
320 } | |
321 | |
322 std::vector<std::unique_ptr<protocol::Schema::API::Domain>> | |
323 V8InspectorSessionImpl::supportedDomains() { | |
324 std::vector<std::unique_ptr<protocol::Schema::Domain>> domains = | |
325 supportedDomainsImpl(); | |
326 std::vector<std::unique_ptr<protocol::Schema::API::Domain>> result; | |
327 for (size_t i = 0; i < domains.size(); ++i) | |
328 result.push_back(std::move(domains[i])); | |
329 return result; | |
330 } | |
331 | |
332 std::vector<std::unique_ptr<protocol::Schema::Domain>> | |
333 V8InspectorSessionImpl::supportedDomainsImpl() { | |
334 std::vector<std::unique_ptr<protocol::Schema::Domain>> result; | |
335 result.push_back(protocol::Schema::Domain::create() | |
336 .setName(protocol::Runtime::Metainfo::domainName) | |
337 .setVersion(protocol::Runtime::Metainfo::version) | |
338 .build()); | |
339 result.push_back(protocol::Schema::Domain::create() | |
340 .setName(protocol::Debugger::Metainfo::domainName) | |
341 .setVersion(protocol::Debugger::Metainfo::version) | |
342 .build()); | |
343 result.push_back(protocol::Schema::Domain::create() | |
344 .setName(protocol::Profiler::Metainfo::domainName) | |
345 .setVersion(protocol::Profiler::Metainfo::version) | |
346 .build()); | |
347 result.push_back(protocol::Schema::Domain::create() | |
348 .setName(protocol::HeapProfiler::Metainfo::domainName) | |
349 .setVersion(protocol::HeapProfiler::Metainfo::version) | |
350 .build()); | |
351 result.push_back(protocol::Schema::Domain::create() | |
352 .setName(protocol::Schema::Metainfo::domainName) | |
353 .setVersion(protocol::Schema::Metainfo::version) | |
354 .build()); | |
355 return result; | |
356 } | |
357 | |
358 void V8InspectorSessionImpl::addInspectedObject( | |
359 std::unique_ptr<V8InspectorSession::Inspectable> inspectable) { | |
360 m_inspectedObjects.insert(m_inspectedObjects.begin(), std::move(inspectable)); | |
361 if (m_inspectedObjects.size() > kInspectedObjectBufferSize) | |
362 m_inspectedObjects.resize(kInspectedObjectBufferSize); | |
363 } | |
364 | |
365 V8InspectorSession::Inspectable* V8InspectorSessionImpl::inspectedObject( | |
366 unsigned num) { | |
367 if (num >= m_inspectedObjects.size()) return nullptr; | |
368 return m_inspectedObjects[num].get(); | |
369 } | |
370 | |
371 void V8InspectorSessionImpl::schedulePauseOnNextStatement( | |
372 const StringView& breakReason, const StringView& breakDetails) { | |
373 m_debuggerAgent->schedulePauseOnNextStatement( | |
374 toString16(breakReason), | |
375 protocol::DictionaryValue::cast(protocol::parseJSON(breakDetails))); | |
376 } | |
377 | |
378 void V8InspectorSessionImpl::cancelPauseOnNextStatement() { | |
379 m_debuggerAgent->cancelPauseOnNextStatement(); | |
380 } | |
381 | |
382 void V8InspectorSessionImpl::breakProgram(const StringView& breakReason, | |
383 const StringView& breakDetails) { | |
384 m_debuggerAgent->breakProgram( | |
385 toString16(breakReason), | |
386 protocol::DictionaryValue::cast(protocol::parseJSON(breakDetails))); | |
387 } | |
388 | |
389 void V8InspectorSessionImpl::setSkipAllPauses(bool skip) { | |
390 ErrorString errorString; | |
391 m_debuggerAgent->setSkipAllPauses(&errorString, skip); | |
392 } | |
393 | |
394 void V8InspectorSessionImpl::resume() { | |
395 ErrorString errorString; | |
396 m_debuggerAgent->resume(&errorString); | |
397 } | |
398 | |
399 void V8InspectorSessionImpl::stepOver() { | |
400 ErrorString errorString; | |
401 m_debuggerAgent->stepOver(&errorString); | |
402 } | |
403 | |
404 std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>> | |
405 V8InspectorSessionImpl::searchInTextByLines(const StringView& text, | |
406 const StringView& query, | |
407 bool caseSensitive, bool isRegex) { | |
408 // TODO(dgozman): search may operate on StringView and avoid copying |text|. | |
409 std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches = | |
410 searchInTextByLinesImpl(this, toString16(text), toString16(query), | |
411 caseSensitive, isRegex); | |
412 std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>> result; | |
413 for (size_t i = 0; i < matches.size(); ++i) | |
414 result.push_back(std::move(matches[i])); | |
415 return result; | |
416 } | |
417 | |
418 } // namespace v8_inspector | |
OLD | NEW |