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