• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "../../third_party/inspector_protocol/crdtp/cbor.h"
8 #include "../../third_party/inspector_protocol/crdtp/dispatch.h"
9 #include "../../third_party/inspector_protocol/crdtp/json.h"
10 #include "src/base/logging.h"
11 #include "src/base/macros.h"
12 #include "src/inspector/injected-script.h"
13 #include "src/inspector/inspected-context.h"
14 #include "src/inspector/protocol/Protocol.h"
15 #include "src/inspector/remote-object-id.h"
16 #include "src/inspector/search-util.h"
17 #include "src/inspector/string-util.h"
18 #include "src/inspector/v8-console-agent-impl.h"
19 #include "src/inspector/v8-debugger-agent-impl.h"
20 #include "src/inspector/v8-debugger.h"
21 #include "src/inspector/v8-heap-profiler-agent-impl.h"
22 #include "src/inspector/v8-inspector-impl.h"
23 #include "src/inspector/v8-profiler-agent-impl.h"
24 #include "src/inspector/v8-runtime-agent-impl.h"
25 #include "src/inspector/v8-schema-agent-impl.h"
26 
27 namespace v8_inspector {
28 namespace {
29 using v8_crdtp::span;
30 using v8_crdtp::SpanFrom;
31 using v8_crdtp::Status;
32 using v8_crdtp::cbor::CheckCBORMessage;
33 using v8_crdtp::json::ConvertCBORToJSON;
34 using v8_crdtp::json::ConvertJSONToCBOR;
35 
IsCBORMessage(StringView msg)36 bool IsCBORMessage(StringView msg) {
37   return msg.is8Bit() && msg.length() >= 2 && msg.characters8()[0] == 0xd8 &&
38          msg.characters8()[1] == 0x5a;
39 }
40 
ConvertToCBOR(StringView state,std::vector<uint8_t> * cbor)41 Status ConvertToCBOR(StringView state, std::vector<uint8_t>* cbor) {
42   return state.is8Bit()
43              ? ConvertJSONToCBOR(
44                    span<uint8_t>(state.characters8(), state.length()), cbor)
45              : ConvertJSONToCBOR(
46                    span<uint16_t>(state.characters16(), state.length()), cbor);
47 }
48 
ParseState(StringView state)49 std::unique_ptr<protocol::DictionaryValue> ParseState(StringView state) {
50   std::vector<uint8_t> converted;
51   span<uint8_t> cbor;
52   if (IsCBORMessage(state))
53     cbor = span<uint8_t>(state.characters8(), state.length());
54   else if (ConvertToCBOR(state, &converted).ok())
55     cbor = SpanFrom(converted);
56   if (!cbor.empty()) {
57     std::unique_ptr<protocol::Value> value =
58         protocol::Value::parseBinary(cbor.data(), cbor.size());
59     std::unique_ptr<protocol::DictionaryValue> dictionaryValue =
60         protocol::DictionaryValue::cast(std::move(value));
61     if (dictionaryValue) return dictionaryValue;
62   }
63   return protocol::DictionaryValue::create();
64 }
65 }  // namespace
66 
67 // static
canDispatchMethod(StringView method)68 bool V8InspectorSession::canDispatchMethod(StringView method) {
69   return stringViewStartsWith(method,
70                               protocol::Runtime::Metainfo::commandPrefix) ||
71          stringViewStartsWith(method,
72                               protocol::Debugger::Metainfo::commandPrefix) ||
73          stringViewStartsWith(method,
74                               protocol::Profiler::Metainfo::commandPrefix) ||
75          stringViewStartsWith(
76              method, protocol::HeapProfiler::Metainfo::commandPrefix) ||
77          stringViewStartsWith(method,
78                               protocol::Console::Metainfo::commandPrefix) ||
79          stringViewStartsWith(method,
80                               protocol::Schema::Metainfo::commandPrefix);
81 }
82 
83 // static
executionContextId(v8::Local<v8::Context> context)84 int V8ContextInfo::executionContextId(v8::Local<v8::Context> context) {
85   return InspectedContext::contextId(context);
86 }
87 
create(V8InspectorImpl * inspector,int contextGroupId,int sessionId,V8Inspector::Channel * channel,StringView state)88 std::unique_ptr<V8InspectorSessionImpl> V8InspectorSessionImpl::create(
89     V8InspectorImpl* inspector, int contextGroupId, int sessionId,
90     V8Inspector::Channel* channel, StringView state) {
91   return std::unique_ptr<V8InspectorSessionImpl>(new V8InspectorSessionImpl(
92       inspector, contextGroupId, sessionId, channel, state));
93 }
94 
V8InspectorSessionImpl(V8InspectorImpl * inspector,int contextGroupId,int sessionId,V8Inspector::Channel * channel,StringView savedState)95 V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector,
96                                                int contextGroupId,
97                                                int sessionId,
98                                                V8Inspector::Channel* channel,
99                                                StringView savedState)
100     : m_contextGroupId(contextGroupId),
101       m_sessionId(sessionId),
102       m_inspector(inspector),
103       m_channel(channel),
104       m_customObjectFormatterEnabled(false),
105       m_dispatcher(this),
106       m_state(ParseState(savedState)),
107       m_runtimeAgent(nullptr),
108       m_debuggerAgent(nullptr),
109       m_heapProfilerAgent(nullptr),
110       m_profilerAgent(nullptr),
111       m_consoleAgent(nullptr),
112       m_schemaAgent(nullptr) {
113   m_state->getBoolean("use_binary_protocol", &use_binary_protocol_);
114 
115   m_runtimeAgent.reset(new V8RuntimeAgentImpl(
116       this, this, agentState(protocol::Runtime::Metainfo::domainName)));
117   protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get());
118 
119   m_debuggerAgent.reset(new V8DebuggerAgentImpl(
120       this, this, agentState(protocol::Debugger::Metainfo::domainName)));
121   protocol::Debugger::Dispatcher::wire(&m_dispatcher, m_debuggerAgent.get());
122 
123   m_profilerAgent.reset(new V8ProfilerAgentImpl(
124       this, this, agentState(protocol::Profiler::Metainfo::domainName)));
125   protocol::Profiler::Dispatcher::wire(&m_dispatcher, m_profilerAgent.get());
126 
127   m_heapProfilerAgent.reset(new V8HeapProfilerAgentImpl(
128       this, this, agentState(protocol::HeapProfiler::Metainfo::domainName)));
129   protocol::HeapProfiler::Dispatcher::wire(&m_dispatcher,
130                                            m_heapProfilerAgent.get());
131 
132   m_consoleAgent.reset(new V8ConsoleAgentImpl(
133       this, this, agentState(protocol::Console::Metainfo::domainName)));
134   protocol::Console::Dispatcher::wire(&m_dispatcher, m_consoleAgent.get());
135 
136   m_schemaAgent.reset(new V8SchemaAgentImpl(
137       this, this, agentState(protocol::Schema::Metainfo::domainName)));
138   protocol::Schema::Dispatcher::wire(&m_dispatcher, m_schemaAgent.get());
139 
140   if (savedState.length()) {
141     m_runtimeAgent->restore();
142     m_debuggerAgent->restore();
143     m_heapProfilerAgent->restore();
144     m_profilerAgent->restore();
145     m_consoleAgent->restore();
146   }
147 }
148 
~V8InspectorSessionImpl()149 V8InspectorSessionImpl::~V8InspectorSessionImpl() {
150   v8::Isolate::Scope scope(m_inspector->isolate());
151   discardInjectedScripts();
152   m_consoleAgent->disable();
153   m_profilerAgent->disable();
154   m_heapProfilerAgent->disable();
155   m_debuggerAgent->disable();
156   m_runtimeAgent->disable();
157   m_inspector->disconnect(this);
158 }
159 
160 std::unique_ptr<V8InspectorSession::CommandLineAPIScope>
initializeCommandLineAPIScope(int executionContextId)161 V8InspectorSessionImpl::initializeCommandLineAPIScope(int executionContextId) {
162   auto scope =
163       std::make_unique<InjectedScript::ContextScope>(this, executionContextId);
164   auto result = scope->initialize();
165   if (!result.IsSuccess()) {
166     return nullptr;
167   }
168 
169   scope->installCommandLineAPI();
170 
171   return scope;
172 }
173 
agentState(const String16 & name)174 protocol::DictionaryValue* V8InspectorSessionImpl::agentState(
175     const String16& name) {
176   protocol::DictionaryValue* state = m_state->getObject(name);
177   if (!state) {
178     std::unique_ptr<protocol::DictionaryValue> newState =
179         protocol::DictionaryValue::create();
180     state = newState.get();
181     m_state->setObject(name, std::move(newState));
182   }
183   return state;
184 }
185 
serializeForFrontend(std::unique_ptr<protocol::Serializable> message)186 std::unique_ptr<StringBuffer> V8InspectorSessionImpl::serializeForFrontend(
187     std::unique_ptr<protocol::Serializable> message) {
188   std::vector<uint8_t> cbor = message->Serialize();
189   DCHECK(CheckCBORMessage(SpanFrom(cbor)).ok());
190   if (use_binary_protocol_) return StringBufferFrom(std::move(cbor));
191   std::vector<uint8_t> json;
192   Status status = ConvertCBORToJSON(SpanFrom(cbor), &json);
193   DCHECK(status.ok());
194   USE(status);
195   // TODO(johannes): It should be OK to make a StringBuffer from |json|
196   // directly, since it's 7 Bit US-ASCII with anything else escaped.
197   // However it appears that the Node.js tests (or perhaps even production)
198   // assume that the StringBuffer is 16 Bit. It probably accesses
199   // characters16() somehwere without checking is8Bit. Until it's fixed
200   // we take a detour via String16 which makes the StringBuffer 16 bit.
201   String16 string16(reinterpret_cast<const char*>(json.data()), json.size());
202   return StringBufferFrom(std::move(string16));
203 }
204 
SendProtocolResponse(int callId,std::unique_ptr<protocol::Serializable> message)205 void V8InspectorSessionImpl::SendProtocolResponse(
206     int callId, std::unique_ptr<protocol::Serializable> message) {
207   m_channel->sendResponse(callId, serializeForFrontend(std::move(message)));
208 }
209 
SendProtocolNotification(std::unique_ptr<protocol::Serializable> message)210 void V8InspectorSessionImpl::SendProtocolNotification(
211     std::unique_ptr<protocol::Serializable> message) {
212   m_channel->sendNotification(serializeForFrontend(std::move(message)));
213 }
214 
FallThrough(int callId,const v8_crdtp::span<uint8_t> method,v8_crdtp::span<uint8_t> message)215 void V8InspectorSessionImpl::FallThrough(int callId,
216                                          const v8_crdtp::span<uint8_t> method,
217                                          v8_crdtp::span<uint8_t> message) {
218   // There's no other layer to handle the command.
219   UNREACHABLE();
220 }
221 
FlushProtocolNotifications()222 void V8InspectorSessionImpl::FlushProtocolNotifications() {
223   m_channel->flushProtocolNotifications();
224 }
225 
reset()226 void V8InspectorSessionImpl::reset() {
227   m_debuggerAgent->reset();
228   m_runtimeAgent->reset();
229   discardInjectedScripts();
230 }
231 
discardInjectedScripts()232 void V8InspectorSessionImpl::discardInjectedScripts() {
233   m_inspectedObjects.clear();
234   int sessionId = m_sessionId;
235   m_inspector->forEachContext(m_contextGroupId,
236                               [&sessionId](InspectedContext* context) {
237                                 context->discardInjectedScript(sessionId);
238                               });
239 }
240 
findInjectedScript(int contextId,InjectedScript * & injectedScript)241 Response V8InspectorSessionImpl::findInjectedScript(
242     int contextId, InjectedScript*& injectedScript) {
243   injectedScript = nullptr;
244   InspectedContext* context =
245       m_inspector->getContext(m_contextGroupId, contextId);
246   if (!context)
247     return Response::ServerError("Cannot find context with specified id");
248   injectedScript = context->getInjectedScript(m_sessionId);
249   if (!injectedScript) {
250     injectedScript = context->createInjectedScript(m_sessionId);
251     if (m_customObjectFormatterEnabled)
252       injectedScript->setCustomObjectFormatterEnabled(true);
253   }
254   return Response::Success();
255 }
256 
findInjectedScript(RemoteObjectIdBase * objectId,InjectedScript * & injectedScript)257 Response V8InspectorSessionImpl::findInjectedScript(
258     RemoteObjectIdBase* objectId, InjectedScript*& injectedScript) {
259   if (objectId->isolateId() != m_inspector->isolateId())
260     return Response::ServerError("Cannot find context with specified id");
261   return findInjectedScript(objectId->contextId(), injectedScript);
262 }
263 
releaseObjectGroup(StringView objectGroup)264 void V8InspectorSessionImpl::releaseObjectGroup(StringView objectGroup) {
265   releaseObjectGroup(toString16(objectGroup));
266 }
267 
releaseObjectGroup(const String16 & objectGroup)268 void V8InspectorSessionImpl::releaseObjectGroup(const String16& objectGroup) {
269   int sessionId = m_sessionId;
270   m_inspector->forEachContext(
271       m_contextGroupId, [&objectGroup, &sessionId](InspectedContext* context) {
272         InjectedScript* injectedScript = context->getInjectedScript(sessionId);
273         if (injectedScript) injectedScript->releaseObjectGroup(objectGroup);
274       });
275 }
276 
unwrapObject(std::unique_ptr<StringBuffer> * error,StringView objectId,v8::Local<v8::Value> * object,v8::Local<v8::Context> * context,std::unique_ptr<StringBuffer> * objectGroup)277 bool V8InspectorSessionImpl::unwrapObject(
278     std::unique_ptr<StringBuffer>* error, StringView objectId,
279     v8::Local<v8::Value>* object, v8::Local<v8::Context>* context,
280     std::unique_ptr<StringBuffer>* objectGroup) {
281   String16 objectGroupString;
282   Response response = unwrapObject(toString16(objectId), object, context,
283                                    objectGroup ? &objectGroupString : nullptr);
284   if (response.IsError()) {
285     if (error) {
286       const std::string& msg = response.Message();
287       *error = StringBufferFrom(String16::fromUTF8(msg.data(), msg.size()));
288     }
289     return false;
290   }
291   if (objectGroup)
292     *objectGroup = StringBufferFrom(std::move(objectGroupString));
293   return true;
294 }
295 
unwrapObject(const String16 & objectId,v8::Local<v8::Value> * object,v8::Local<v8::Context> * context,String16 * objectGroup)296 Response V8InspectorSessionImpl::unwrapObject(const String16& objectId,
297                                               v8::Local<v8::Value>* object,
298                                               v8::Local<v8::Context>* context,
299                                               String16* objectGroup) {
300   std::unique_ptr<RemoteObjectId> remoteId;
301   Response response = RemoteObjectId::parse(objectId, &remoteId);
302   if (!response.IsSuccess()) return response;
303   InjectedScript* injectedScript = nullptr;
304   response = findInjectedScript(remoteId.get(), injectedScript);
305   if (!response.IsSuccess()) return response;
306   response = injectedScript->findObject(*remoteId, object);
307   if (!response.IsSuccess()) return response;
308   *context = injectedScript->context()->context();
309   if (objectGroup) *objectGroup = injectedScript->objectGroupName(*remoteId);
310   return Response::Success();
311 }
312 
313 std::unique_ptr<protocol::Runtime::API::RemoteObject>
wrapObject(v8::Local<v8::Context> context,v8::Local<v8::Value> value,StringView groupName,bool generatePreview)314 V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context,
315                                    v8::Local<v8::Value> value,
316                                    StringView groupName, bool generatePreview) {
317   return wrapObject(context, value, toString16(groupName), generatePreview);
318 }
319 
320 std::unique_ptr<protocol::Runtime::RemoteObject>
wrapObject(v8::Local<v8::Context> context,v8::Local<v8::Value> value,const String16 & groupName,bool generatePreview)321 V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context,
322                                    v8::Local<v8::Value> value,
323                                    const String16& groupName,
324                                    bool generatePreview) {
325   InjectedScript* injectedScript = nullptr;
326   findInjectedScript(InspectedContext::contextId(context), injectedScript);
327   if (!injectedScript) return nullptr;
328   std::unique_ptr<protocol::Runtime::RemoteObject> result;
329   injectedScript->wrapObject(
330       value, groupName,
331       generatePreview ? WrapMode::kWithPreview : WrapMode::kNoPreview, &result);
332   return result;
333 }
334 
335 std::unique_ptr<protocol::Runtime::RemoteObject>
wrapTable(v8::Local<v8::Context> context,v8::Local<v8::Object> table,v8::MaybeLocal<v8::Array> columns)336 V8InspectorSessionImpl::wrapTable(v8::Local<v8::Context> context,
337                                   v8::Local<v8::Object> table,
338                                   v8::MaybeLocal<v8::Array> columns) {
339   InjectedScript* injectedScript = nullptr;
340   findInjectedScript(InspectedContext::contextId(context), injectedScript);
341   if (!injectedScript) return nullptr;
342   return injectedScript->wrapTable(table, columns);
343 }
344 
setCustomObjectFormatterEnabled(bool enabled)345 void V8InspectorSessionImpl::setCustomObjectFormatterEnabled(bool enabled) {
346   m_customObjectFormatterEnabled = enabled;
347   int sessionId = m_sessionId;
348   m_inspector->forEachContext(
349       m_contextGroupId, [&enabled, &sessionId](InspectedContext* context) {
350         InjectedScript* injectedScript = context->getInjectedScript(sessionId);
351         if (injectedScript)
352           injectedScript->setCustomObjectFormatterEnabled(enabled);
353       });
354 }
355 
reportAllContexts(V8RuntimeAgentImpl * agent)356 void V8InspectorSessionImpl::reportAllContexts(V8RuntimeAgentImpl* agent) {
357   m_inspector->forEachContext(m_contextGroupId,
358                               [&agent](InspectedContext* context) {
359                                 agent->reportExecutionContextCreated(context);
360                               });
361 }
362 
dispatchProtocolMessage(StringView message)363 void V8InspectorSessionImpl::dispatchProtocolMessage(StringView message) {
364   using v8_crdtp::span;
365   using v8_crdtp::SpanFrom;
366   span<uint8_t> cbor;
367   std::vector<uint8_t> converted_cbor;
368   if (IsCBORMessage(message)) {
369     use_binary_protocol_ = true;
370     m_state->setBoolean("use_binary_protocol", true);
371     cbor = span<uint8_t>(message.characters8(), message.length());
372   } else {
373     // We're ignoring the return value of the conversion function
374     // intentionally. It means the |parsed_message| below will be nullptr.
375     auto status = ConvertToCBOR(message, &converted_cbor);
376     if (!status.ok()) {
377       m_channel->sendNotification(
378           serializeForFrontend(v8_crdtp::CreateErrorNotification(
379               v8_crdtp::DispatchResponse::ParseError(status.ToASCIIString()))));
380       return;
381     }
382     cbor = SpanFrom(converted_cbor);
383   }
384   v8_crdtp::Dispatchable dispatchable(cbor);
385   if (!dispatchable.ok()) {
386     if (dispatchable.HasCallId()) {
387       m_channel->sendNotification(serializeForFrontend(
388           v8_crdtp::CreateErrorNotification(dispatchable.DispatchError())));
389     } else {
390       m_channel->sendResponse(
391           dispatchable.CallId(),
392           serializeForFrontend(v8_crdtp::CreateErrorResponse(
393               dispatchable.CallId(), dispatchable.DispatchError())));
394     }
395     return;
396   }
397   m_dispatcher.Dispatch(dispatchable).Run();
398 }
399 
state()400 std::vector<uint8_t> V8InspectorSessionImpl::state() {
401   return m_state->Serialize();
402 }
403 
404 std::vector<std::unique_ptr<protocol::Schema::API::Domain>>
supportedDomains()405 V8InspectorSessionImpl::supportedDomains() {
406   std::vector<std::unique_ptr<protocol::Schema::Domain>> domains =
407       supportedDomainsImpl();
408   std::vector<std::unique_ptr<protocol::Schema::API::Domain>> result;
409   for (size_t i = 0; i < domains.size(); ++i)
410     result.push_back(std::move(domains[i]));
411   return result;
412 }
413 
414 std::vector<std::unique_ptr<protocol::Schema::Domain>>
supportedDomainsImpl()415 V8InspectorSessionImpl::supportedDomainsImpl() {
416   std::vector<std::unique_ptr<protocol::Schema::Domain>> result;
417   result.push_back(protocol::Schema::Domain::create()
418                        .setName(protocol::Runtime::Metainfo::domainName)
419                        .setVersion(protocol::Runtime::Metainfo::version)
420                        .build());
421   result.push_back(protocol::Schema::Domain::create()
422                        .setName(protocol::Debugger::Metainfo::domainName)
423                        .setVersion(protocol::Debugger::Metainfo::version)
424                        .build());
425   result.push_back(protocol::Schema::Domain::create()
426                        .setName(protocol::Profiler::Metainfo::domainName)
427                        .setVersion(protocol::Profiler::Metainfo::version)
428                        .build());
429   result.push_back(protocol::Schema::Domain::create()
430                        .setName(protocol::HeapProfiler::Metainfo::domainName)
431                        .setVersion(protocol::HeapProfiler::Metainfo::version)
432                        .build());
433   result.push_back(protocol::Schema::Domain::create()
434                        .setName(protocol::Schema::Metainfo::domainName)
435                        .setVersion(protocol::Schema::Metainfo::version)
436                        .build());
437   return result;
438 }
439 
addInspectedObject(std::unique_ptr<V8InspectorSession::Inspectable> inspectable)440 void V8InspectorSessionImpl::addInspectedObject(
441     std::unique_ptr<V8InspectorSession::Inspectable> inspectable) {
442   m_inspectedObjects.insert(m_inspectedObjects.begin(), std::move(inspectable));
443   if (m_inspectedObjects.size() > kInspectedObjectBufferSize)
444     m_inspectedObjects.resize(kInspectedObjectBufferSize);
445 }
446 
inspectedObject(unsigned num)447 V8InspectorSession::Inspectable* V8InspectorSessionImpl::inspectedObject(
448     unsigned num) {
449   if (num >= m_inspectedObjects.size()) return nullptr;
450   return m_inspectedObjects[num].get();
451 }
452 
schedulePauseOnNextStatement(StringView breakReason,StringView breakDetails)453 void V8InspectorSessionImpl::schedulePauseOnNextStatement(
454     StringView breakReason, StringView breakDetails) {
455   std::vector<uint8_t> cbor;
456   ConvertToCBOR(breakDetails, &cbor);
457   m_debuggerAgent->schedulePauseOnNextStatement(
458       toString16(breakReason),
459       protocol::DictionaryValue::cast(
460           protocol::Value::parseBinary(cbor.data(), cbor.size())));
461 }
462 
cancelPauseOnNextStatement()463 void V8InspectorSessionImpl::cancelPauseOnNextStatement() {
464   m_debuggerAgent->cancelPauseOnNextStatement();
465 }
466 
breakProgram(StringView breakReason,StringView breakDetails)467 void V8InspectorSessionImpl::breakProgram(StringView breakReason,
468                                           StringView breakDetails) {
469   std::vector<uint8_t> cbor;
470   ConvertToCBOR(breakDetails, &cbor);
471   m_debuggerAgent->breakProgram(
472       toString16(breakReason),
473       protocol::DictionaryValue::cast(
474           protocol::Value::parseBinary(cbor.data(), cbor.size())));
475 }
476 
setSkipAllPauses(bool skip)477 void V8InspectorSessionImpl::setSkipAllPauses(bool skip) {
478   m_debuggerAgent->setSkipAllPauses(skip);
479 }
480 
resume(bool terminateOnResume)481 void V8InspectorSessionImpl::resume(bool terminateOnResume) {
482   m_debuggerAgent->resume(terminateOnResume);
483 }
484 
stepOver()485 void V8InspectorSessionImpl::stepOver() { m_debuggerAgent->stepOver({}); }
486 
487 std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>>
searchInTextByLines(StringView text,StringView query,bool caseSensitive,bool isRegex)488 V8InspectorSessionImpl::searchInTextByLines(StringView text, StringView query,
489                                             bool caseSensitive, bool isRegex) {
490   // TODO(dgozman): search may operate on StringView and avoid copying |text|.
491   std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
492       searchInTextByLinesImpl(this, toString16(text), toString16(query),
493                               caseSensitive, isRegex);
494   std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>> result;
495   for (size_t i = 0; i < matches.size(); ++i)
496     result.push_back(std::move(matches[i]));
497   return result;
498 }
499 
triggerPreciseCoverageDeltaUpdate(StringView occasion)500 void V8InspectorSessionImpl::triggerPreciseCoverageDeltaUpdate(
501     StringView occasion) {
502   m_profilerAgent->triggerPreciseCoverageDeltaUpdate(toString16(occasion));
503 }
504 
505 }  // namespace v8_inspector
506