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