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