LCOV - code coverage report
Current view: top level - src/inspector - v8-inspector-impl.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 186 200 93.0 %
Date: 2019-04-19 Functions: 43 50 86.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2010-2011 Google Inc. All rights reserved.
       3             :  *
       4             :  * Redistribution and use in source and binary forms, with or without
       5             :  * modification, are permitted provided that the following conditions are
       6             :  * met:
       7             :  *
       8             :  *     * Redistributions of source code must retain the above copyright
       9             :  * notice, this list of conditions and the following disclaimer.
      10             :  *     * Redistributions in binary form must reproduce the above
      11             :  * copyright notice, this list of conditions and the following disclaimer
      12             :  * in the documentation and/or other materials provided with the
      13             :  * distribution.
      14             :  *     * Neither the name of Google Inc. nor the names of its
      15             :  * contributors may be used to endorse or promote products derived from
      16             :  * this software without specific prior written permission.
      17             :  *
      18             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      19             :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      20             :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      21             :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      22             :  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      23             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      24             :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      25             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      26             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      27             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      28             :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29             :  */
      30             : 
      31             : #include "src/inspector/v8-inspector-impl.h"
      32             : 
      33             : #include <vector>
      34             : 
      35             : #include "src/base/platform/mutex.h"
      36             : #include "src/inspector/inspected-context.h"
      37             : #include "src/inspector/string-util.h"
      38             : #include "src/inspector/v8-console-agent-impl.h"
      39             : #include "src/inspector/v8-console-message.h"
      40             : #include "src/inspector/v8-console.h"
      41             : #include "src/inspector/v8-debugger-agent-impl.h"
      42             : #include "src/inspector/v8-debugger.h"
      43             : #include "src/inspector/v8-inspector-session-impl.h"
      44             : #include "src/inspector/v8-profiler-agent-impl.h"
      45             : #include "src/inspector/v8-runtime-agent-impl.h"
      46             : #include "src/inspector/v8-stack-trace-impl.h"
      47             : 
      48             : #include "include/v8-platform.h"
      49             : 
      50             : namespace v8_inspector {
      51             : 
      52        3685 : std::unique_ptr<V8Inspector> V8Inspector::create(v8::Isolate* isolate,
      53             :                                                  V8InspectorClient* client) {
      54        7370 :   return std::unique_ptr<V8Inspector>(new V8InspectorImpl(isolate, client));
      55             : }
      56             : 
      57        3685 : V8InspectorImpl::V8InspectorImpl(v8::Isolate* isolate,
      58             :                                  V8InspectorClient* client)
      59             :     : m_isolate(isolate),
      60             :       m_client(client),
      61        3685 :       m_debugger(new V8Debugger(isolate, this)),
      62             :       m_capturingStackTracesCount(0),
      63             :       m_lastExceptionId(0),
      64             :       m_lastContextId(0),
      65        7370 :       m_isolateId(v8::debug::GetNextRandomInt64(m_isolate)) {
      66        3685 :   v8::debug::SetInspector(m_isolate, this);
      67        3685 :   v8::debug::SetConsoleDelegate(m_isolate, console());
      68        3685 : }
      69             : 
      70       11055 : V8InspectorImpl::~V8InspectorImpl() {
      71        3685 :   v8::debug::SetInspector(m_isolate, nullptr);
      72        3685 :   v8::debug::SetConsoleDelegate(m_isolate, nullptr);
      73        7370 : }
      74             : 
      75       66768 : int V8InspectorImpl::contextGroupId(v8::Local<v8::Context> context) const {
      76      133536 :   return contextGroupId(InspectedContext::contextId(context));
      77             : }
      78             : 
      79      130741 : int V8InspectorImpl::contextGroupId(int contextId) const {
      80             :   auto it = m_contextIdToGroupIdMap.find(contextId);
      81     3935666 :   return it != m_contextIdToGroupIdMap.end() ? it->second : 0;
      82             : }
      83             : 
      84         306 : v8::MaybeLocal<v8::Value> V8InspectorImpl::compileAndRunInternalScript(
      85             :     v8::Local<v8::Context> context, v8::Local<v8::String> source) {
      86             :   v8::Local<v8::UnboundScript> unboundScript;
      87         612 :   if (!v8::debug::CompileInspectorScript(m_isolate, source)
      88             :            .ToLocal(&unboundScript))
      89           5 :     return v8::MaybeLocal<v8::Value>();
      90             :   v8::MicrotasksScope microtasksScope(m_isolate,
      91         602 :                                       v8::MicrotasksScope::kDoNotRunMicrotasks);
      92             :   v8::Context::Scope contextScope(context);
      93         602 :   v8::Isolate::SafeForTerminationScope allowTermination(m_isolate);
      94         602 :   return unboundScript->BindToCurrentContext()->Run(context);
      95             : }
      96             : 
      97         943 : v8::MaybeLocal<v8::Script> V8InspectorImpl::compileScript(
      98             :     v8::Local<v8::Context> context, const String16& code,
      99             :     const String16& fileName) {
     100             :   v8::ScriptOrigin origin(
     101             :       toV8String(m_isolate, fileName), v8::Integer::New(m_isolate, 0),
     102             :       v8::Integer::New(m_isolate, 0),
     103             :       v8::False(m_isolate),                                         // sharable
     104             :       v8::Local<v8::Integer>(), toV8String(m_isolate, String16()),  // sourceMap
     105        4715 :       v8::True(m_isolate));  // opaqueresource
     106         943 :   v8::ScriptCompiler::Source source(toV8String(m_isolate, code), origin);
     107             :   return v8::ScriptCompiler::Compile(context, &source,
     108        1886 :                                      v8::ScriptCompiler::kNoCompileOptions);
     109             : }
     110             : 
     111         687 : void V8InspectorImpl::enableStackCapturingIfNeeded() {
     112         687 :   if (!m_capturingStackTracesCount)
     113         607 :     V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate,
     114         607 :                                                                 true);
     115         687 :   ++m_capturingStackTracesCount;
     116         687 : }
     117             : 
     118         687 : void V8InspectorImpl::disableStackCapturingIfNeeded() {
     119         687 :   if (!(--m_capturingStackTracesCount))
     120         607 :     V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate,
     121         607 :                                                                 false);
     122         687 : }
     123             : 
     124       68408 : void V8InspectorImpl::muteExceptions(int contextGroupId) {
     125       68408 :   m_muteExceptionsMap[contextGroupId]++;
     126       68408 : }
     127             : 
     128       68408 : void V8InspectorImpl::unmuteExceptions(int contextGroupId) {
     129       68408 :   m_muteExceptionsMap[contextGroupId]--;
     130       68408 : }
     131             : 
     132        8222 : V8ConsoleMessageStorage* V8InspectorImpl::ensureConsoleMessageStorage(
     133             :     int contextGroupId) {
     134             :   ConsoleStorageMap::iterator storageIt =
     135             :       m_consoleStorageMap.find(contextGroupId);
     136        8222 :   if (storageIt == m_consoleStorageMap.end())
     137             :     storageIt = m_consoleStorageMap
     138         926 :                     .insert(std::make_pair(
     139             :                         contextGroupId,
     140             :                         std::unique_ptr<V8ConsoleMessageStorage>(
     141         463 :                             new V8ConsoleMessageStorage(this, contextGroupId))))
     142             :                     .first;
     143        8222 :   return storageIt->second.get();
     144             : }
     145             : 
     146       20900 : bool V8InspectorImpl::hasConsoleMessageStorage(int contextGroupId) {
     147             :   ConsoleStorageMap::iterator storageIt =
     148             :       m_consoleStorageMap.find(contextGroupId);
     149       20900 :   return storageIt != m_consoleStorageMap.end();
     150             : }
     151             : 
     152         370 : std::unique_ptr<V8StackTrace> V8InspectorImpl::createStackTrace(
     153             :     v8::Local<v8::StackTrace> stackTrace) {
     154         740 :   return m_debugger->createStackTrace(stackTrace);
     155             : }
     156             : 
     157        3879 : std::unique_ptr<V8InspectorSession> V8InspectorImpl::connect(
     158             :     int contextGroupId, V8Inspector::Channel* channel,
     159             :     const StringView& state) {
     160        3879 :   int sessionId = ++m_lastSessionId;
     161             :   std::unique_ptr<V8InspectorSessionImpl> session =
     162             :       V8InspectorSessionImpl::create(this, contextGroupId, sessionId, channel,
     163        3879 :                                      state);
     164        7758 :   m_sessions[contextGroupId][sessionId] = session.get();
     165        3879 :   return std::move(session);
     166             : }
     167             : 
     168        3879 : void V8InspectorImpl::disconnect(V8InspectorSessionImpl* session) {
     169        7758 :   auto& map = m_sessions[session->contextGroupId()];
     170        7758 :   map.erase(session->sessionId());
     171        7698 :   if (map.empty()) m_sessions.erase(session->contextGroupId());
     172        3879 : }
     173             : 
     174     4076827 : InspectedContext* V8InspectorImpl::getContext(int groupId,
     175             :                                               int contextId) const {
     176     4076827 :   if (!groupId || !contextId) return nullptr;
     177             : 
     178             :   ContextsByGroupMap::const_iterator contextGroupIt = m_contexts.find(groupId);
     179     4076817 :   if (contextGroupIt == m_contexts.end()) return nullptr;
     180             : 
     181             :   ContextByIdMap::iterator contextIt = contextGroupIt->second->find(contextId);
     182     4076803 :   if (contextIt == contextGroupIt->second->end()) return nullptr;
     183             : 
     184     4076793 :   return contextIt->second.get();
     185             : }
     186             : 
     187     3738157 : InspectedContext* V8InspectorImpl::getContext(int contextId) const {
     188     3738157 :   return getContext(contextGroupId(contextId), contextId);
     189             : }
     190             : 
     191           0 : v8::MaybeLocal<v8::Context> V8InspectorImpl::contextById(int contextId) {
     192           0 :   InspectedContext* context = getContext(contextId);
     193           0 :   return context ? context->context() : v8::MaybeLocal<v8::Context>();
     194             : }
     195             : 
     196        3784 : void V8InspectorImpl::contextCreated(const V8ContextInfo& info) {
     197        3784 :   int contextId = ++m_lastContextId;
     198        3784 :   InspectedContext* context = new InspectedContext(this, info, contextId);
     199        3784 :   m_contextIdToGroupIdMap[contextId] = info.contextGroupId;
     200             : 
     201        3784 :   ContextsByGroupMap::iterator contextIt = m_contexts.find(info.contextGroupId);
     202        3784 :   if (contextIt == m_contexts.end())
     203             :     contextIt = m_contexts
     204        7568 :                     .insert(std::make_pair(
     205             :                         info.contextGroupId,
     206             :                         std::unique_ptr<ContextByIdMap>(new ContextByIdMap())))
     207             :                     .first;
     208             :   const auto& contextById = contextIt->second;
     209             : 
     210             :   DCHECK(contextById->find(contextId) == contextById->cend());
     211        7568 :   (*contextById)[contextId].reset(context);
     212        3784 :   forEachSession(
     213        8916 :       info.contextGroupId, [&context](V8InspectorSessionImpl* session) {
     214        5132 :         session->runtimeAgent()->addBindings(context);
     215        5132 :         session->runtimeAgent()->reportExecutionContextCreated(context);
     216        6350 :       });
     217        3784 : }
     218             : 
     219          15 : void V8InspectorImpl::contextDestroyed(v8::Local<v8::Context> context) {
     220          15 :   int contextId = InspectedContext::contextId(context);
     221          15 :   int groupId = contextGroupId(context);
     222          15 :   contextCollected(groupId, contextId);
     223          15 : }
     224             : 
     225          20 : void V8InspectorImpl::contextCollected(int groupId, int contextId) {
     226             :   m_contextIdToGroupIdMap.erase(contextId);
     227             : 
     228             :   ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(groupId);
     229          20 :   if (storageIt != m_consoleStorageMap.end())
     230          40 :     storageIt->second->contextDestroyed(contextId);
     231             : 
     232          20 :   InspectedContext* inspectedContext = getContext(groupId, contextId);
     233          20 :   if (!inspectedContext) return;
     234             : 
     235          50 :   forEachSession(groupId, [&inspectedContext](V8InspectorSessionImpl* session) {
     236          60 :     session->runtimeAgent()->reportExecutionContextDestroyed(inspectedContext);
     237          20 :   });
     238          20 :   discardInspectedContext(groupId, contextId);
     239             : }
     240             : 
     241           4 : void V8InspectorImpl::resetContextGroup(int contextGroupId) {
     242             :   m_consoleStorageMap.erase(contextGroupId);
     243             :   m_muteExceptionsMap.erase(contextGroupId);
     244             :   std::vector<int> contextIdsToClear;
     245           4 :   forEachContext(contextGroupId,
     246           4 :                  [&contextIdsToClear](InspectedContext* context) {
     247           8 :                    contextIdsToClear.push_back(context->contextId());
     248           4 :                  });
     249           8 :   m_debugger->wasmTranslation()->Clear(m_isolate, contextIdsToClear);
     250           4 :   forEachSession(contextGroupId,
     251           8 :                  [](V8InspectorSessionImpl* session) { session->reset(); });
     252             :   m_contexts.erase(contextGroupId);
     253           4 : }
     254             : 
     255           0 : void V8InspectorImpl::idleStarted() { m_isolate->SetIdle(true); }
     256             : 
     257           0 : void V8InspectorImpl::idleFinished() { m_isolate->SetIdle(false); }
     258             : 
     259         370 : unsigned V8InspectorImpl::exceptionThrown(
     260             :     v8::Local<v8::Context> context, const StringView& message,
     261             :     v8::Local<v8::Value> exception, const StringView& detailedMessage,
     262             :     const StringView& url, unsigned lineNumber, unsigned columnNumber,
     263             :     std::unique_ptr<V8StackTrace> stackTrace, int scriptId) {
     264         370 :   int groupId = contextGroupId(context);
     265         740 :   if (!groupId || m_muteExceptionsMap[groupId]) return 0;
     266             :   std::unique_ptr<V8StackTraceImpl> stackTraceImpl(
     267             :       static_cast<V8StackTraceImpl*>(stackTrace.release()));
     268             :   unsigned exceptionId = nextExceptionId();
     269             :   std::unique_ptr<V8ConsoleMessage> consoleMessage =
     270             :       V8ConsoleMessage::createForException(
     271         740 :           m_client->currentTimeMS(), toString16(detailedMessage),
     272         740 :           toString16(url), lineNumber, columnNumber, std::move(stackTraceImpl),
     273         740 :           scriptId, m_isolate, toString16(message),
     274        1850 :           InspectedContext::contextId(context), exception, exceptionId);
     275         370 :   ensureConsoleMessageStorage(groupId)->addMessage(std::move(consoleMessage));
     276             :   return exceptionId;
     277             : }
     278             : 
     279         105 : void V8InspectorImpl::exceptionRevoked(v8::Local<v8::Context> context,
     280             :                                        unsigned exceptionId,
     281             :                                        const StringView& message) {
     282         105 :   int groupId = contextGroupId(context);
     283         105 :   if (!groupId) return;
     284             : 
     285             :   std::unique_ptr<V8ConsoleMessage> consoleMessage =
     286             :       V8ConsoleMessage::createForRevokedException(
     287         315 :           m_client->currentTimeMS(), toString16(message), exceptionId);
     288         105 :   ensureConsoleMessageStorage(groupId)->addMessage(std::move(consoleMessage));
     289             : }
     290             : 
     291           0 : std::unique_ptr<V8StackTrace> V8InspectorImpl::captureStackTrace(
     292             :     bool fullStack) {
     293           0 :   return m_debugger->captureStackTrace(fullStack);
     294             : }
     295             : 
     296          60 : V8StackTraceId V8InspectorImpl::storeCurrentStackTrace(
     297             :     const StringView& description) {
     298          60 :   return m_debugger->storeCurrentStackTrace(description);
     299             : }
     300             : 
     301          60 : void V8InspectorImpl::externalAsyncTaskStarted(const V8StackTraceId& parent) {
     302          60 :   m_debugger->externalAsyncTaskStarted(parent);
     303          60 : }
     304             : 
     305          60 : void V8InspectorImpl::externalAsyncTaskFinished(const V8StackTraceId& parent) {
     306          60 :   m_debugger->externalAsyncTaskFinished(parent);
     307          60 : }
     308             : 
     309        2020 : void V8InspectorImpl::asyncTaskScheduled(const StringView& taskName, void* task,
     310             :                                          bool recurring) {
     311        2020 :   if (!task) return;
     312        4040 :   m_debugger->asyncTaskScheduled(taskName, task, recurring);
     313             : }
     314             : 
     315           0 : void V8InspectorImpl::asyncTaskCanceled(void* task) {
     316           0 :   if (!task) return;
     317           0 :   m_debugger->asyncTaskCanceled(task);
     318             : }
     319             : 
     320        2020 : void V8InspectorImpl::asyncTaskStarted(void* task) {
     321        2020 :   if (!task) return;
     322        2020 :   m_debugger->asyncTaskStarted(task);
     323             : }
     324             : 
     325        2020 : void V8InspectorImpl::asyncTaskFinished(void* task) {
     326        2020 :   if (!task) return;
     327        2020 :   m_debugger->asyncTaskFinished(task);
     328             : }
     329             : 
     330           0 : void V8InspectorImpl::allAsyncTasksCanceled() {
     331           0 :   m_debugger->allAsyncTasksCanceled();
     332           0 : }
     333             : 
     334         680 : v8::Local<v8::Context> V8InspectorImpl::regexContext() {
     335         680 :   if (m_regexContext.IsEmpty())
     336         190 :     m_regexContext.Reset(m_isolate, v8::Context::New(m_isolate));
     337        1360 :   return m_regexContext.Get(m_isolate);
     338             : }
     339             : 
     340          20 : void V8InspectorImpl::discardInspectedContext(int contextGroupId,
     341             :                                               int contextId) {
     342          20 :   if (!getContext(contextGroupId, contextId)) return;
     343             :   m_contexts[contextGroupId]->erase(contextId);
     344          20 :   if (m_contexts[contextGroupId]->empty()) m_contexts.erase(contextGroupId);
     345             : }
     346             : 
     347      113962 : V8InspectorSessionImpl* V8InspectorImpl::sessionById(int contextGroupId,
     348             :                                                      int sessionId) {
     349             :   auto it = m_sessions.find(contextGroupId);
     350      113962 :   if (it == m_sessions.end()) return nullptr;
     351             :   auto it2 = it->second.find(sessionId);
     352      113952 :   return it2 == it->second.end() ? nullptr : it2->second;
     353             : }
     354             : 
     355        4948 : V8Console* V8InspectorImpl::console() {
     356        4948 :   if (!m_console) m_console.reset(new V8Console(this));
     357        4948 :   return m_console.get();
     358             : }
     359             : 
     360       52057 : void V8InspectorImpl::forEachContext(
     361             :     int contextGroupId,
     362             :     const std::function<void(InspectedContext*)>& callback) {
     363             :   auto it = m_contexts.find(contextGroupId);
     364       52076 :   if (it == m_contexts.end()) return;
     365             :   std::vector<int> ids;
     366       52038 :   ids.reserve(it->second->size());
     367      104076 :   for (auto& contextIt : *(it->second)) ids.push_back(contextIt.first);
     368             : 
     369             :   // Retrieve by ids each time since |callback| may destroy some contexts.
     370      104076 :   for (auto& contextId : ids) {
     371             :     it = m_contexts.find(contextGroupId);
     372       52038 :     if (it == m_contexts.end()) continue;
     373             :     auto contextIt = it->second->find(contextId);
     374       52038 :     if (contextIt != it->second->end()) callback(contextIt->second.get());
     375             :   }
     376             : }
     377             : 
     378      218510 : void V8InspectorImpl::forEachSession(
     379             :     int contextGroupId,
     380             :     const std::function<void(V8InspectorSessionImpl*)>& callback) {
     381             :   auto it = m_sessions.find(contextGroupId);
     382      220206 :   if (it == m_sessions.end()) return;
     383             :   std::vector<int> ids;
     384      216814 :   ids.reserve(it->second.size());
     385      434328 :   for (auto& sessionIt : it->second) ids.push_back(sessionIt.first);
     386             : 
     387             :   // Retrieve by ids each time since |callback| may destroy some contexts.
     388      434328 :   for (auto& sessionId : ids) {
     389             :     it = m_sessions.find(contextGroupId);
     390      217514 :     if (it == m_sessions.end()) continue;
     391             :     auto sessionIt = it->second.find(sessionId);
     392      217514 :     if (sessionIt != it->second.end()) callback(sessionIt->second);
     393             :   }
     394             : }
     395             : 
     396       20308 : V8InspectorImpl::EvaluateScope::EvaluateScope(
     397             :     const InjectedScript::Scope& scope)
     398             :     : m_scope(scope),
     399             :       m_isolate(scope.inspector()->isolate()),
     400       40616 :       m_safeForTerminationScope(m_isolate) {}
     401             : 
     402          60 : struct V8InspectorImpl::EvaluateScope::CancelToken {
     403             :   v8::base::Mutex m_mutex;
     404             :   bool m_canceled = false;
     405             : };
     406             : 
     407       60924 : V8InspectorImpl::EvaluateScope::~EvaluateScope() {
     408       40616 :   if (m_scope.tryCatch().HasTerminated()) {
     409          74 :     m_scope.inspector()->debugger()->reportTermination();
     410             :   }
     411       20308 :   if (m_cancelToken) {
     412          30 :     v8::base::MutexGuard lock(&m_cancelToken->m_mutex);
     413          30 :     m_cancelToken->m_canceled = true;
     414          30 :     m_isolate->CancelTerminateExecution();
     415             :   }
     416       20308 : }
     417             : 
     418          60 : class V8InspectorImpl::EvaluateScope::TerminateTask : public v8::Task {
     419             :  public:
     420             :   TerminateTask(v8::Isolate* isolate, std::shared_ptr<CancelToken> token)
     421          30 :       : m_isolate(isolate), m_token(std::move(token)) {}
     422             : 
     423          30 :   void Run() override {
     424             :     // CancelToken contains m_canceled bool which may be changed from main
     425             :     // thread, so lock mutex first.
     426          30 :     v8::base::MutexGuard lock(&m_token->m_mutex);
     427          30 :     if (m_token->m_canceled) return;
     428          27 :     m_isolate->TerminateExecution();
     429             :   }
     430             : 
     431             :  private:
     432             :   v8::Isolate* m_isolate;
     433             :   std::shared_ptr<CancelToken> m_token;
     434             : };
     435             : 
     436          30 : protocol::Response V8InspectorImpl::EvaluateScope::setTimeout(double timeout) {
     437          30 :   if (m_isolate->IsExecutionTerminating()) {
     438           0 :     return protocol::Response::Error("Execution was terminated");
     439             :   }
     440          60 :   m_cancelToken.reset(new CancelToken());
     441          60 :   v8::debug::GetCurrentPlatform()->CallDelayedOnWorkerThread(
     442          90 :       v8::base::make_unique<TerminateTask>(m_isolate, m_cancelToken), timeout);
     443          30 :   return protocol::Response::OK();
     444             : }
     445             : 
     446             : }  // namespace v8_inspector

Generated by: LCOV version 1.10