LCOV - code coverage report
Current view: top level - src/inspector - v8-debugger-agent-impl.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 786 839 93.7 %
Date: 2019-03-21 Functions: 65 69 94.2 %

          Line data    Source code
       1             : // Copyright 2015 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-debugger-agent-impl.h"
       6             : 
       7             : #include <algorithm>
       8             : 
       9             : #include "src/base/safe_conversions.h"
      10             : #include "src/debug/debug-interface.h"
      11             : #include "src/inspector/injected-script.h"
      12             : #include "src/inspector/inspected-context.h"
      13             : #include "src/inspector/protocol/Protocol.h"
      14             : #include "src/inspector/remote-object-id.h"
      15             : #include "src/inspector/search-util.h"
      16             : #include "src/inspector/string-util.h"
      17             : #include "src/inspector/v8-debugger-script.h"
      18             : #include "src/inspector/v8-debugger.h"
      19             : #include "src/inspector/v8-inspector-impl.h"
      20             : #include "src/inspector/v8-inspector-session-impl.h"
      21             : #include "src/inspector/v8-regex.h"
      22             : #include "src/inspector/v8-runtime-agent-impl.h"
      23             : #include "src/inspector/v8-stack-trace-impl.h"
      24             : #include "src/inspector/v8-value-utils.h"
      25             : 
      26             : #include "include/v8-inspector.h"
      27             : 
      28             : namespace v8_inspector {
      29             : 
      30             : using protocol::Array;
      31             : using protocol::Maybe;
      32             : using protocol::Debugger::BreakpointId;
      33             : using protocol::Debugger::CallFrame;
      34             : using protocol::Runtime::ExceptionDetails;
      35             : using protocol::Runtime::ScriptId;
      36             : using protocol::Runtime::RemoteObject;
      37             : using protocol::Debugger::Scope;
      38             : 
      39             : namespace DebuggerAgentState {
      40             : static const char pauseOnExceptionsState[] = "pauseOnExceptionsState";
      41             : static const char asyncCallStackDepth[] = "asyncCallStackDepth";
      42             : static const char blackboxPattern[] = "blackboxPattern";
      43             : static const char debuggerEnabled[] = "debuggerEnabled";
      44             : static const char skipAllPauses[] = "skipAllPauses";
      45             : 
      46             : static const char breakpointsByRegex[] = "breakpointsByRegex";
      47             : static const char breakpointsByUrl[] = "breakpointsByUrl";
      48             : static const char breakpointsByScriptHash[] = "breakpointsByScriptHash";
      49             : static const char breakpointHints[] = "breakpointHints";
      50             : 
      51             : }  // namespace DebuggerAgentState
      52             : 
      53             : static const char kBacktraceObjectGroup[] = "backtrace";
      54             : static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled";
      55             : static const char kDebuggerNotPaused[] =
      56             :     "Can only perform operation while paused.";
      57             : 
      58             : static const size_t kBreakpointHintMaxLength = 128;
      59             : static const intptr_t kBreakpointHintMaxSearchOffset = 80 * 10;
      60             : 
      61             : namespace {
      62             : 
      63      147125 : void TranslateLocation(protocol::Debugger::Location* location,
      64             :                        WasmTranslation* wasmTranslation) {
      65             :   String16 scriptId = location->getScriptId();
      66      147125 :   int lineNumber = location->getLineNumber();
      67      147125 :   int columnNumber = location->getColumnNumber(-1);
      68      147125 :   if (wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
      69             :           &scriptId, &lineNumber, &columnNumber)) {
      70             :     location->setScriptId(std::move(scriptId));
      71         372 :     location->setLineNumber(lineNumber);
      72         372 :     location->setColumnNumber(columnNumber);
      73             :   }
      74      147125 : }
      75             : 
      76             : enum class BreakpointType {
      77             :   kByUrl = 1,
      78             :   kByUrlRegex,
      79             :   kByScriptHash,
      80             :   kByScriptId,
      81             :   kDebugCommand,
      82             :   kMonitorCommand,
      83             :   kBreakpointAtEntry
      84             : };
      85             : 
      86        2132 : String16 generateBreakpointId(BreakpointType type,
      87             :                               const String16& scriptSelector, int lineNumber,
      88             :                               int columnNumber) {
      89        2132 :   String16Builder builder;
      90        2132 :   builder.appendNumber(static_cast<int>(type));
      91        2132 :   builder.append(':');
      92        2132 :   builder.appendNumber(lineNumber);
      93        2132 :   builder.append(':');
      94        2132 :   builder.appendNumber(columnNumber);
      95        2132 :   builder.append(':');
      96        2132 :   builder.append(scriptSelector);
      97        4264 :   return builder.toString();
      98             : }
      99             : 
     100         170 : String16 generateBreakpointId(BreakpointType type,
     101             :                               v8::Local<v8::Function> function) {
     102         170 :   String16Builder builder;
     103         170 :   builder.appendNumber(static_cast<int>(type));
     104         170 :   builder.append(':');
     105         170 :   builder.appendNumber(v8::debug::GetDebuggingId(function));
     106         340 :   return builder.toString();
     107             : }
     108             : 
     109        3361 : bool parseBreakpointId(const String16& breakpointId, BreakpointType* type,
     110             :                        String16* scriptSelector = nullptr,
     111             :                        int* lineNumber = nullptr, int* columnNumber = nullptr) {
     112             :   size_t typeLineSeparator = breakpointId.find(':');
     113        3361 :   if (typeLineSeparator == String16::kNotFound) return false;
     114             : 
     115        6712 :   int rawType = breakpointId.substring(0, typeLineSeparator).toInteger();
     116        3356 :   if (rawType < static_cast<int>(BreakpointType::kByUrl) ||
     117             :       rawType > static_cast<int>(BreakpointType::kBreakpointAtEntry)) {
     118             :     return false;
     119             :   }
     120        3351 :   if (type) *type = static_cast<BreakpointType>(rawType);
     121        3351 :   if (rawType == static_cast<int>(BreakpointType::kDebugCommand) ||
     122        3351 :       rawType == static_cast<int>(BreakpointType::kMonitorCommand) ||
     123             :       rawType == static_cast<int>(BreakpointType::kBreakpointAtEntry)) {
     124             :     // The script and source position is not encoded in this case.
     125             :     return true;
     126             :   }
     127             : 
     128        3271 :   size_t lineColumnSeparator = breakpointId.find(':', typeLineSeparator + 1);
     129        3271 :   if (lineColumnSeparator == String16::kNotFound) return false;
     130             :   size_t columnSelectorSeparator =
     131        3271 :       breakpointId.find(':', lineColumnSeparator + 1);
     132        3271 :   if (columnSelectorSeparator == String16::kNotFound) return false;
     133        3271 :   if (scriptSelector) {
     134        1756 :     *scriptSelector = breakpointId.substring(columnSelectorSeparator + 1);
     135             :   }
     136        3271 :   if (lineNumber) {
     137             :     *lineNumber = breakpointId
     138         220 :                       .substring(typeLineSeparator + 1,
     139         110 :                                  lineColumnSeparator - typeLineSeparator - 1)
     140         110 :                       .toInteger();
     141             :   }
     142        3271 :   if (columnNumber) {
     143             :     *columnNumber =
     144             :         breakpointId
     145         220 :             .substring(lineColumnSeparator + 1,
     146         110 :                        columnSelectorSeparator - lineColumnSeparator - 1)
     147         110 :             .toInteger();
     148             :   }
     149             :   return true;
     150             : }
     151             : 
     152         225 : bool positionComparator(const std::pair<int, int>& a,
     153             :                         const std::pair<int, int>& b) {
     154         225 :   if (a.first != b.first) return a.first < b.first;
     155          45 :   return a.second < b.second;
     156             : }
     157             : 
     158         215 : String16 breakpointHint(const V8DebuggerScript& script, int lineNumber,
     159             :                         int columnNumber) {
     160         215 :   int offset = script.offset(lineNumber, columnNumber);
     161         215 :   if (offset == V8DebuggerScript::kNoOffset) return String16();
     162             :   String16 hint =
     163         430 :       script.source(offset, kBreakpointHintMaxLength).stripWhiteSpace();
     164        5085 :   for (size_t i = 0; i < hint.length(); ++i) {
     165        2625 :     if (hint[i] == '\r' || hint[i] == '\n' || hint[i] == ';') {
     166         190 :       return hint.substring(0, i);
     167             :     }
     168             :   }
     169             :   return hint;
     170             : }
     171             : 
     172         150 : void adjustBreakpointLocation(const V8DebuggerScript& script,
     173             :                               const String16& hint, int* lineNumber,
     174             :                               int* columnNumber) {
     175         150 :   if (*lineNumber < script.startLine() || *lineNumber > script.endLine())
     176          90 :     return;
     177          95 :   if (hint.isEmpty()) return;
     178          95 :   intptr_t sourceOffset = script.offset(*lineNumber, *columnNumber);
     179          95 :   if (sourceOffset == V8DebuggerScript::kNoOffset) return;
     180             : 
     181             :   intptr_t searchRegionOffset = std::max(
     182         190 :       sourceOffset - kBreakpointHintMaxSearchOffset, static_cast<intptr_t>(0));
     183          95 :   size_t offset = sourceOffset - searchRegionOffset;
     184             :   String16 searchArea = script.source(searchRegionOffset,
     185          95 :                                       offset + kBreakpointHintMaxSearchOffset);
     186             : 
     187             :   size_t nextMatch = searchArea.find(hint, offset);
     188             :   size_t prevMatch = searchArea.reverseFind(hint, offset);
     189          95 :   if (nextMatch == String16::kNotFound && prevMatch == String16::kNotFound) {
     190             :     return;
     191             :   }
     192             :   size_t bestMatch;
     193          60 :   if (nextMatch == String16::kNotFound) {
     194             :     bestMatch = prevMatch;
     195          60 :   } else if (prevMatch == String16::kNotFound) {
     196             :     bestMatch = nextMatch;
     197             :   } else {
     198          45 :     bestMatch = nextMatch - offset < offset - prevMatch ? nextMatch : prevMatch;
     199             :   }
     200          60 :   bestMatch += searchRegionOffset;
     201             :   v8::debug::Location hintPosition =
     202          60 :       script.location(static_cast<int>(bestMatch));
     203          60 :   if (hintPosition.IsEmpty()) return;
     204          60 :   *lineNumber = hintPosition.GetLineNumber();
     205          60 :   *columnNumber = hintPosition.GetColumnNumber();
     206             : }
     207             : 
     208        2505 : String16 breakLocationType(v8::debug::BreakLocationType type) {
     209        2505 :   switch (type) {
     210             :     case v8::debug::kCallBreakLocation:
     211        1135 :       return protocol::Debugger::BreakLocation::TypeEnum::Call;
     212             :     case v8::debug::kReturnBreakLocation:
     213        1360 :       return protocol::Debugger::BreakLocation::TypeEnum::Return;
     214             :     case v8::debug::kDebuggerStatementBreakLocation:
     215          10 :       return protocol::Debugger::BreakLocation::TypeEnum::DebuggerStatement;
     216             :     case v8::debug::kCommonBreakLocation:
     217           0 :       return String16();
     218             :   }
     219           0 :   return String16();
     220             : }
     221             : 
     222      373236 : String16 scopeType(v8::debug::ScopeIterator::ScopeType type) {
     223      373236 :   switch (type) {
     224             :     case v8::debug::ScopeIterator::ScopeTypeGlobal:
     225      142778 :       return Scope::TypeEnum::Global;
     226             :     case v8::debug::ScopeIterator::ScopeTypeLocal:
     227       84109 :       return Scope::TypeEnum::Local;
     228             :     case v8::debug::ScopeIterator::ScopeTypeWith:
     229        2360 :       return Scope::TypeEnum::With;
     230             :     case v8::debug::ScopeIterator::ScopeTypeClosure:
     231        9952 :       return Scope::TypeEnum::Closure;
     232             :     case v8::debug::ScopeIterator::ScopeTypeCatch:
     233        1063 :       return Scope::TypeEnum::Catch;
     234             :     case v8::debug::ScopeIterator::ScopeTypeBlock:
     235        2664 :       return Scope::TypeEnum::Block;
     236             :     case v8::debug::ScopeIterator::ScopeTypeScript:
     237      129003 :       return Scope::TypeEnum::Script;
     238             :     case v8::debug::ScopeIterator::ScopeTypeEval:
     239          97 :       return Scope::TypeEnum::Eval;
     240             :     case v8::debug::ScopeIterator::ScopeTypeModule:
     241        1210 :       return Scope::TypeEnum::Module;
     242             :   }
     243           0 :   UNREACHABLE();
     244             :   return String16();
     245             : }
     246             : 
     247      147125 : Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator,
     248             :                      InjectedScript* injectedScript,
     249             :                      std::unique_ptr<Array<Scope>>* scopes) {
     250      147125 :   *scopes = Array<Scope>::create();
     251      147125 :   if (!injectedScript) return Response::OK();
     252      147034 :   if (iterator->Done()) return Response::OK();
     253             : 
     254      142778 :   String16 scriptId = String16::fromInteger(iterator->GetScriptId());
     255             : 
     256      889250 :   for (; !iterator->Done(); iterator->Advance()) {
     257      373236 :     std::unique_ptr<RemoteObject> object;
     258             :     Response result =
     259      373236 :         injectedScript->wrapObject(iterator->GetObject(), kBacktraceObjectGroup,
     260     1492944 :                                    WrapMode::kNoPreview, &object);
     261      373236 :     if (!result.isSuccess()) return result;
     262             : 
     263      373236 :     auto scope = Scope::create()
     264      746472 :                      .setType(scopeType(iterator->GetType()))
     265             :                      .setObject(std::move(object))
     266             :                      .build();
     267             : 
     268             :     String16 name = toProtocolStringWithTypeCheck(
     269      373236 :         isolate, iterator->GetFunctionDebugName());
     270      373236 :     if (!name.isEmpty()) scope->setName(name);
     271             : 
     272      373236 :     if (iterator->HasLocationInfo()) {
     273      155300 :       v8::debug::Location start = iterator->GetStartLocation();
     274      155300 :       scope->setStartLocation(protocol::Debugger::Location::create()
     275             :                                   .setScriptId(scriptId)
     276      155300 :                                   .setLineNumber(start.GetLineNumber())
     277      155300 :                                   .setColumnNumber(start.GetColumnNumber())
     278             :                                   .build());
     279             : 
     280      155300 :       v8::debug::Location end = iterator->GetEndLocation();
     281      155300 :       scope->setEndLocation(protocol::Debugger::Location::create()
     282             :                                 .setScriptId(scriptId)
     283      155300 :                                 .setLineNumber(end.GetLineNumber())
     284      155300 :                                 .setColumnNumber(end.GetColumnNumber())
     285             :                                 .build());
     286             :     }
     287      373236 :     (*scopes)->addItem(std::move(scope));
     288             :   }
     289      142778 :   return Response::OK();
     290             : }
     291             : 
     292         665 : protocol::DictionaryValue* getOrCreateObject(protocol::DictionaryValue* object,
     293             :                                              const String16& key) {
     294         665 :   protocol::DictionaryValue* value = object->getObject(key);
     295         665 :   if (value) return value;
     296             :   std::unique_ptr<protocol::DictionaryValue> newDictionary =
     297             :       protocol::DictionaryValue::create();
     298             :   value = newDictionary.get();
     299        1000 :   object->setObject(key, std::move(newDictionary));
     300             :   return value;
     301             : }
     302             : }  // namespace
     303             : 
     304        3866 : V8DebuggerAgentImpl::V8DebuggerAgentImpl(
     305             :     V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
     306             :     protocol::DictionaryValue* state)
     307             :     : m_inspector(session->inspector()),
     308             :       m_debugger(m_inspector->debugger()),
     309             :       m_session(session),
     310             :       m_enabled(false),
     311             :       m_state(state),
     312             :       m_frontend(frontendChannel),
     313       23196 :       m_isolate(m_inspector->isolate()) {}
     314             : 
     315             : V8DebuggerAgentImpl::~V8DebuggerAgentImpl() = default;
     316             : 
     317        3487 : void V8DebuggerAgentImpl::enableImpl() {
     318        3487 :   m_enabled = true;
     319        6974 :   m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
     320        3487 :   m_debugger->enable();
     321             : 
     322             :   std::vector<std::unique_ptr<V8DebuggerScript>> compiledScripts =
     323        6974 :       m_debugger->getCompiledScripts(m_session->contextGroupId(), this);
     324       37019 :   for (auto& script : compiledScripts) {
     325       67064 :     didParseSource(std::move(script), true);
     326             :   }
     327             : 
     328        3487 :   m_breakpointsActive = true;
     329        3487 :   m_debugger->setBreakpointsActive(true);
     330             : 
     331        3487 :   if (isPaused()) {
     332          20 :     didPause(0, v8::Local<v8::Value>(), std::vector<v8::debug::BreakpointId>(),
     333          10 :              v8::debug::kException, false, false, false);
     334             :   }
     335        3487 : }
     336             : 
     337        3496 : Response V8DebuggerAgentImpl::enable(Maybe<double> maxScriptsCacheSize,
     338             :                                      String16* outDebuggerId) {
     339        3496 :   m_maxScriptCacheSize = v8::base::saturated_cast<size_t>(
     340        3496 :       maxScriptsCacheSize.fromMaybe(std::numeric_limits<double>::max()));
     341        6992 :   *outDebuggerId = debuggerIdToString(
     342        6992 :       m_debugger->debuggerIdFor(m_session->contextGroupId()));
     343        3496 :   if (enabled()) return Response::OK();
     344             : 
     345        3472 :   if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
     346           0 :     return Response::Error("Script execution is prohibited");
     347             : 
     348        3472 :   enableImpl();
     349        3472 :   return Response::OK();
     350             : }
     351             : 
     352        5423 : Response V8DebuggerAgentImpl::disable() {
     353        5423 :   if (!enabled()) return Response::OK();
     354             : 
     355        6974 :   m_state->remove(DebuggerAgentState::breakpointsByRegex);
     356        6974 :   m_state->remove(DebuggerAgentState::breakpointsByUrl);
     357        6974 :   m_state->remove(DebuggerAgentState::breakpointsByScriptHash);
     358        6974 :   m_state->remove(DebuggerAgentState::breakpointHints);
     359             : 
     360        6974 :   m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState,
     361        3487 :                       v8::debug::NoBreakOnException);
     362        6974 :   m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0);
     363             : 
     364        3487 :   if (m_breakpointsActive) {
     365        3487 :     m_debugger->setBreakpointsActive(false);
     366        3487 :     m_breakpointsActive = false;
     367             :   }
     368             :   m_blackboxedPositions.clear();
     369        3487 :   m_blackboxPattern.reset();
     370             :   resetBlackboxedStateCache();
     371             :   m_scripts.clear();
     372        3487 :   m_cachedScriptIds.clear();
     373        3487 :   m_cachedScriptSize = 0;
     374        4757 :   for (const auto& it : m_debuggerBreakpointIdToBreakpointId) {
     375        1270 :     v8::debug::RemoveBreakpoint(m_isolate, it.first);
     376             :   }
     377             :   m_breakpointIdToDebuggerBreakpointIds.clear();
     378             :   m_debuggerBreakpointIdToBreakpointId.clear();
     379        3487 :   m_debugger->setAsyncCallStackDepth(this, 0);
     380        3487 :   clearBreakDetails();
     381        3487 :   m_skipAllPauses = false;
     382        6974 :   m_state->setBoolean(DebuggerAgentState::skipAllPauses, false);
     383        6974 :   m_state->remove(DebuggerAgentState::blackboxPattern);
     384        3487 :   m_enabled = false;
     385        6974 :   m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
     386        3487 :   m_debugger->disable();
     387        3487 :   return Response::OK();
     388             : }
     389             : 
     390          55 : void V8DebuggerAgentImpl::restore() {
     391             :   DCHECK(!m_enabled);
     392         110 :   if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false))
     393          40 :     return;
     394          15 :   if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
     395             :     return;
     396             : 
     397          15 :   enableImpl();
     398             : 
     399          15 :   int pauseState = v8::debug::NoBreakOnException;
     400          30 :   m_state->getInteger(DebuggerAgentState::pauseOnExceptionsState, &pauseState);
     401          15 :   setPauseOnExceptionsImpl(pauseState);
     402             : 
     403             :   m_skipAllPauses =
     404          30 :       m_state->booleanProperty(DebuggerAgentState::skipAllPauses, false);
     405             : 
     406          15 :   int asyncCallStackDepth = 0;
     407          30 :   m_state->getInteger(DebuggerAgentState::asyncCallStackDepth,
     408          15 :                       &asyncCallStackDepth);
     409          15 :   m_debugger->setAsyncCallStackDepth(this, asyncCallStackDepth);
     410             : 
     411             :   String16 blackboxPattern;
     412          30 :   if (m_state->getString(DebuggerAgentState::blackboxPattern,
     413             :                          &blackboxPattern)) {
     414           0 :     setBlackboxPattern(blackboxPattern);
     415             :   }
     416             : }
     417             : 
     418         138 : Response V8DebuggerAgentImpl::setBreakpointsActive(bool active) {
     419         138 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     420         138 :   if (m_breakpointsActive == active) return Response::OK();
     421         102 :   m_breakpointsActive = active;
     422         102 :   m_debugger->setBreakpointsActive(active);
     423         102 :   if (!active && !m_breakReason.empty()) {
     424           5 :     clearBreakDetails();
     425           5 :     m_debugger->setPauseOnNextCall(false, m_session->contextGroupId());
     426             :   }
     427         102 :   return Response::OK();
     428             : }
     429             : 
     430          35 : Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) {
     431          70 :   m_state->setBoolean(DebuggerAgentState::skipAllPauses, skip);
     432          35 :   m_skipAllPauses = skip;
     433          35 :   return Response::OK();
     434             : }
     435             : 
     436        1400 : static bool matches(V8InspectorImpl* inspector, const V8DebuggerScript& script,
     437             :                     BreakpointType type, const String16& selector) {
     438        1400 :   switch (type) {
     439             :     case BreakpointType::kByUrl:
     440        1295 :       return script.sourceURL() == selector;
     441             :     case BreakpointType::kByScriptHash:
     442          80 :       return script.hash() == selector;
     443             :     case BreakpointType::kByUrlRegex: {
     444         130 :       V8Regex regex(inspector, selector, true);
     445          65 :       return regex.match(script.sourceURL()) != -1;
     446             :     }
     447             :     default:
     448           0 :       UNREACHABLE();
     449             :       return false;
     450             :   }
     451             : }
     452             : 
     453         245 : Response V8DebuggerAgentImpl::setBreakpointByUrl(
     454             :     int lineNumber, Maybe<String16> optionalURL,
     455             :     Maybe<String16> optionalURLRegex, Maybe<String16> optionalScriptHash,
     456             :     Maybe<int> optionalColumnNumber, Maybe<String16> optionalCondition,
     457             :     String16* outBreakpointId,
     458             :     std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations) {
     459         245 :   *locations = Array<protocol::Debugger::Location>::create();
     460             : 
     461         245 :   int specified = (optionalURL.isJust() ? 1 : 0) +
     462         245 :                   (optionalURLRegex.isJust() ? 1 : 0) +
     463         245 :                   (optionalScriptHash.isJust() ? 1 : 0);
     464         245 :   if (specified != 1) {
     465             :     return Response::Error(
     466           0 :         "Either url or urlRegex or scriptHash must be specified.");
     467             :   }
     468         245 :   int columnNumber = 0;
     469         245 :   if (optionalColumnNumber.isJust()) {
     470          85 :     columnNumber = optionalColumnNumber.fromJust();
     471          85 :     if (columnNumber < 0) return Response::Error("Incorrect column number");
     472             :   }
     473             : 
     474             :   BreakpointType type = BreakpointType::kByUrl;
     475             :   String16 selector;
     476         245 :   if (optionalURLRegex.isJust()) {
     477          20 :     selector = optionalURLRegex.fromJust();
     478             :     type = BreakpointType::kByUrlRegex;
     479         225 :   } else if (optionalURL.isJust()) {
     480         215 :     selector = optionalURL.fromJust();
     481             :     type = BreakpointType::kByUrl;
     482          10 :   } else if (optionalScriptHash.isJust()) {
     483          10 :     selector = optionalScriptHash.fromJust();
     484             :     type = BreakpointType::kByScriptHash;
     485             :   }
     486             : 
     487         490 :   String16 condition = optionalCondition.fromMaybe(String16());
     488             :   String16 breakpointId =
     489         245 :       generateBreakpointId(type, selector, lineNumber, columnNumber);
     490             :   protocol::DictionaryValue* breakpoints;
     491         245 :   switch (type) {
     492             :     case BreakpointType::kByUrlRegex:
     493             :       breakpoints =
     494          40 :           getOrCreateObject(m_state, DebuggerAgentState::breakpointsByRegex);
     495          20 :       break;
     496             :     case BreakpointType::kByUrl:
     497         430 :       breakpoints = getOrCreateObject(
     498             :           getOrCreateObject(m_state, DebuggerAgentState::breakpointsByUrl),
     499         215 :           selector);
     500         215 :       break;
     501             :     case BreakpointType::kByScriptHash:
     502          20 :       breakpoints = getOrCreateObject(
     503             :           getOrCreateObject(m_state,
     504             :                             DebuggerAgentState::breakpointsByScriptHash),
     505          10 :           selector);
     506          10 :       break;
     507             :     default:
     508           0 :       UNREACHABLE();
     509             :       break;
     510             :   }
     511         245 :   if (breakpoints->get(breakpointId)) {
     512           0 :     return Response::Error("Breakpoint at specified location already exists.");
     513             :   }
     514             : 
     515             :   String16 hint;
     516        1535 :   for (const auto& script : m_scripts) {
     517        2280 :     if (!matches(m_inspector, *script.second, type, selector)) continue;
     518         300 :     if (!hint.isEmpty()) {
     519             :       adjustBreakpointLocation(*script.second, hint, &lineNumber,
     520          60 :                                &columnNumber);
     521             :     }
     522             :     std::unique_ptr<protocol::Debugger::Location> location = setBreakpointImpl(
     523         300 :         breakpointId, script.first, condition, lineNumber, columnNumber);
     524         300 :     if (location && type != BreakpointType::kByUrlRegex) {
     525         645 :       hint = breakpointHint(*script.second, lineNumber, columnNumber);
     526             :     }
     527         535 :     if (location) (*locations)->addItem(std::move(location));
     528             :   }
     529         245 :   breakpoints->setString(breakpointId, condition);
     530         245 :   if (!hint.isEmpty()) {
     531             :     protocol::DictionaryValue* breakpointHints =
     532         390 :         getOrCreateObject(m_state, DebuggerAgentState::breakpointHints);
     533         195 :     breakpointHints->setString(breakpointId, hint);
     534             :   }
     535             :   *outBreakpointId = breakpointId;
     536         245 :   return Response::OK();
     537             : }
     538             : 
     539        1887 : Response V8DebuggerAgentImpl::setBreakpoint(
     540             :     std::unique_ptr<protocol::Debugger::Location> location,
     541             :     Maybe<String16> optionalCondition, String16* outBreakpointId,
     542             :     std::unique_ptr<protocol::Debugger::Location>* actualLocation) {
     543             :   String16 breakpointId = generateBreakpointId(
     544        1887 :       BreakpointType::kByScriptId, location->getScriptId(),
     545        1887 :       location->getLineNumber(), location->getColumnNumber(0));
     546        1887 :   if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
     547             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
     548         288 :     return Response::Error("Breakpoint at specified location already exists.");
     549             :   }
     550        5229 :   *actualLocation = setBreakpointImpl(breakpointId, location->getScriptId(),
     551        5229 :                                       optionalCondition.fromMaybe(String16()),
     552             :                                       location->getLineNumber(),
     553             :                                       location->getColumnNumber(0));
     554        1743 :   if (!*actualLocation) return Response::Error("Could not resolve breakpoint");
     555             :   *outBreakpointId = breakpointId;
     556        1743 :   return Response::OK();
     557             : }
     558             : 
     559          20 : Response V8DebuggerAgentImpl::setBreakpointOnFunctionCall(
     560             :     const String16& functionObjectId, Maybe<String16> optionalCondition,
     561             :     String16* outBreakpointId) {
     562          40 :   InjectedScript::ObjectScope scope(m_session, functionObjectId);
     563          20 :   Response response = scope.initialize();
     564          20 :   if (!response.isSuccess()) return response;
     565          20 :   if (!scope.object()->IsFunction()) {
     566           0 :     return Response::Error("Could not find function with given id");
     567             :   }
     568             :   v8::Local<v8::Function> function =
     569          20 :       v8::Local<v8::Function>::Cast(scope.object());
     570             :   String16 breakpointId =
     571          20 :       generateBreakpointId(BreakpointType::kBreakpointAtEntry, function);
     572          20 :   if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
     573             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
     574          10 :     return Response::Error("Breakpoint at specified location already exists.");
     575             :   }
     576             :   v8::Local<v8::String> condition =
     577          60 :       toV8String(m_isolate, optionalCondition.fromMaybe(String16()));
     578          15 :   setBreakpointImpl(breakpointId, function, condition);
     579             :   *outBreakpointId = breakpointId;
     580          15 :   return Response::OK();
     581             : }
     582             : 
     583         803 : Response V8DebuggerAgentImpl::removeBreakpoint(const String16& breakpointId) {
     584         808 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     585             :   BreakpointType type;
     586             :   String16 selector;
     587         798 :   if (!parseBreakpointId(breakpointId, &type, &selector)) {
     588          10 :     return Response::OK();
     589             :   }
     590             :   protocol::DictionaryValue* breakpoints = nullptr;
     591         788 :   switch (type) {
     592             :     case BreakpointType::kByUrl: {
     593             :       protocol::DictionaryValue* breakpointsByUrl =
     594          80 :           m_state->getObject(DebuggerAgentState::breakpointsByUrl);
     595          40 :       if (breakpointsByUrl) {
     596          40 :         breakpoints = breakpointsByUrl->getObject(selector);
     597             :       }
     598             :     } break;
     599             :     case BreakpointType::kByScriptHash: {
     600             :       protocol::DictionaryValue* breakpointsByScriptHash =
     601          20 :           m_state->getObject(DebuggerAgentState::breakpointsByScriptHash);
     602          10 :       if (breakpointsByScriptHash) {
     603          10 :         breakpoints = breakpointsByScriptHash->getObject(selector);
     604             :       }
     605             :     } break;
     606             :     case BreakpointType::kByUrlRegex:
     607          30 :       breakpoints = m_state->getObject(DebuggerAgentState::breakpointsByRegex);
     608          15 :       break;
     609             :     default:
     610             :       break;
     611             :   }
     612         788 :   if (breakpoints) breakpoints->remove(breakpointId);
     613             :   protocol::DictionaryValue* breakpointHints =
     614        1576 :       m_state->getObject(DebuggerAgentState::breakpointHints);
     615         788 :   if (breakpointHints) breakpointHints->remove(breakpointId);
     616         788 :   removeBreakpointImpl(breakpointId);
     617         788 :   return Response::OK();
     618             : }
     619             : 
     620         858 : void V8DebuggerAgentImpl::removeBreakpointImpl(const String16& breakpointId) {
     621             :   DCHECK(enabled());
     622             :   BreakpointIdToDebuggerBreakpointIdsMap::iterator
     623             :       debuggerBreakpointIdsIterator =
     624             :           m_breakpointIdToDebuggerBreakpointIds.find(breakpointId);
     625         858 :   if (debuggerBreakpointIdsIterator ==
     626             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
     627             :     return;
     628             :   }
     629        1731 :   for (const auto& id : debuggerBreakpointIdsIterator->second) {
     630         873 :     v8::debug::RemoveBreakpoint(m_isolate, id);
     631             :     m_debuggerBreakpointIdToBreakpointId.erase(id);
     632             :   }
     633             :   m_breakpointIdToDebuggerBreakpointIds.erase(breakpointId);
     634             : }
     635             : 
     636         269 : Response V8DebuggerAgentImpl::getPossibleBreakpoints(
     637             :     std::unique_ptr<protocol::Debugger::Location> start,
     638             :     Maybe<protocol::Debugger::Location> end, Maybe<bool> restrictToFunction,
     639             :     std::unique_ptr<protocol::Array<protocol::Debugger::BreakLocation>>*
     640             :         locations) {
     641             :   String16 scriptId = start->getScriptId();
     642             : 
     643         538 :   if (start->getLineNumber() < 0 || start->getColumnNumber(0) < 0)
     644             :     return Response::Error(
     645           0 :         "start.lineNumber and start.columnNumber should be >= 0");
     646             : 
     647             :   v8::debug::Location v8Start(start->getLineNumber(),
     648         269 :                               start->getColumnNumber(0));
     649         269 :   v8::debug::Location v8End;
     650         269 :   if (end.isJust()) {
     651         106 :     if (end.fromJust()->getScriptId() != scriptId)
     652          10 :       return Response::Error("Locations should contain the same scriptId");
     653             :     int line = end.fromJust()->getLineNumber();
     654             :     int column = end.fromJust()->getColumnNumber(0);
     655         101 :     if (line < 0 || column < 0)
     656             :       return Response::Error(
     657           0 :           "end.lineNumber and end.columnNumber should be >= 0");
     658         101 :     v8End = v8::debug::Location(line, column);
     659             :   }
     660             :   auto it = m_scripts.find(scriptId);
     661         269 :   if (it == m_scripts.end()) return Response::Error("Script not found");
     662             :   std::vector<v8::debug::BreakLocation> v8Locations;
     663             :   {
     664         518 :     v8::HandleScope handleScope(m_isolate);
     665             :     int contextId = it->second->executionContextId();
     666         259 :     InspectedContext* inspected = m_inspector->getContext(contextId);
     667         259 :     if (!inspected) {
     668           0 :       return Response::Error("Cannot retrive script context");
     669             :     }
     670         259 :     v8::Context::Scope contextScope(inspected->context());
     671             :     v8::MicrotasksScope microtasks(m_isolate,
     672         518 :                                    v8::MicrotasksScope::kDoNotRunMicrotasks);
     673         518 :     v8::TryCatch tryCatch(m_isolate);
     674         259 :     it->second->getPossibleBreakpoints(
     675         518 :         v8Start, v8End, restrictToFunction.fromMaybe(false), &v8Locations);
     676             :   }
     677             : 
     678         259 :   *locations = protocol::Array<protocol::Debugger::BreakLocation>::create();
     679        8763 :   for (size_t i = 0; i < v8Locations.size(); ++i) {
     680             :     std::unique_ptr<protocol::Debugger::BreakLocation> breakLocation =
     681        4252 :         protocol::Debugger::BreakLocation::create()
     682             :             .setScriptId(scriptId)
     683        4252 :             .setLineNumber(v8Locations[i].GetLineNumber())
     684        4252 :             .setColumnNumber(v8Locations[i].GetColumnNumber())
     685             :             .build();
     686        4252 :     if (v8Locations[i].type() != v8::debug::kCommonBreakLocation) {
     687        5010 :       breakLocation->setType(breakLocationType(v8Locations[i].type()));
     688             :     }
     689        4252 :     (*locations)->addItem(std::move(breakLocation));
     690             :   }
     691         259 :   return Response::OK();
     692             : }
     693             : 
     694          60 : Response V8DebuggerAgentImpl::continueToLocation(
     695             :     std::unique_ptr<protocol::Debugger::Location> location,
     696             :     Maybe<String16> targetCallFrames) {
     697          60 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     698          60 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     699          60 :   ScriptsMap::iterator it = m_scripts.find(location->getScriptId());
     700          60 :   if (it == m_scripts.end()) {
     701           0 :     return Response::Error("Cannot continue to specified location");
     702             :   }
     703             :   V8DebuggerScript* script = it->second.get();
     704             :   int contextId = script->executionContextId();
     705          60 :   InspectedContext* inspected = m_inspector->getContext(contextId);
     706          60 :   if (!inspected)
     707           0 :     return Response::Error("Cannot continue to specified location");
     708         120 :   v8::HandleScope handleScope(m_isolate);
     709          60 :   v8::Context::Scope contextScope(inspected->context());
     710          60 :   return m_debugger->continueToLocation(
     711          60 :       m_session->contextGroupId(), script, std::move(location),
     712         180 :       targetCallFrames.fromMaybe(
     713         120 :           protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any));
     714             : }
     715             : 
     716          35 : Response V8DebuggerAgentImpl::getStackTrace(
     717             :     std::unique_ptr<protocol::Runtime::StackTraceId> inStackTraceId,
     718             :     std::unique_ptr<protocol::Runtime::StackTrace>* outStackTrace) {
     719          35 :   bool isOk = false;
     720          70 :   int64_t id = inStackTraceId->getId().toInteger64(&isOk);
     721          35 :   std::pair<int64_t, int64_t> debuggerId;
     722          35 :   if (inStackTraceId->hasDebuggerId()) {
     723             :     debuggerId =
     724         125 :         m_debugger->debuggerIdFor(inStackTraceId->getDebuggerId(String16()));
     725             :   } else {
     726          20 :     debuggerId = m_debugger->debuggerIdFor(m_session->contextGroupId());
     727             :   }
     728          35 :   V8StackTraceId v8StackTraceId(id, debuggerId);
     729          35 :   if (!isOk || v8StackTraceId.IsInvalid()) {
     730           0 :     return Response::Error("Invalid stack trace id");
     731             :   }
     732             :   auto stack =
     733          35 :       m_debugger->stackTraceFor(m_session->contextGroupId(), v8StackTraceId);
     734          35 :   if (!stack) {
     735           0 :     return Response::Error("Stack trace with given id is not found");
     736             :   }
     737          70 :   *outStackTrace = stack->buildInspectorObject(
     738          35 :       m_debugger, m_debugger->maxAsyncCallChainDepth());
     739          35 :   return Response::OK();
     740             : }
     741             : 
     742       11135 : bool V8DebuggerAgentImpl::isFunctionBlackboxed(const String16& scriptId,
     743             :                                                const v8::debug::Location& start,
     744             :                                                const v8::debug::Location& end) {
     745             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     746       11135 :   if (it == m_scripts.end()) {
     747             :     // Unknown scripts are blackboxed.
     748             :     return true;
     749             :   }
     750       11135 :   if (m_blackboxPattern) {
     751             :     const String16& scriptSourceURL = it->second->sourceURL();
     752        1415 :     if (!scriptSourceURL.isEmpty() &&
     753         485 :         m_blackboxPattern->match(scriptSourceURL) != -1)
     754             :       return true;
     755             :   }
     756             :   auto itBlackboxedPositions = m_blackboxedPositions.find(scriptId);
     757       10885 :   if (itBlackboxedPositions == m_blackboxedPositions.end()) return false;
     758             : 
     759             :   const std::vector<std::pair<int, int>>& ranges =
     760             :       itBlackboxedPositions->second;
     761             :   auto itStartRange = std::lower_bound(
     762             :       ranges.begin(), ranges.end(),
     763         220 :       std::make_pair(start.GetLineNumber(), start.GetColumnNumber()),
     764             :       positionComparator);
     765             :   auto itEndRange = std::lower_bound(
     766             :       itStartRange, ranges.end(),
     767         220 :       std::make_pair(end.GetLineNumber(), end.GetColumnNumber()),
     768             :       positionComparator);
     769             :   // Ranges array contains positions in script where blackbox state is changed.
     770             :   // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is
     771             :   // blackboxed...
     772         205 :   return itStartRange == itEndRange &&
     773             :          std::distance(ranges.begin(), itStartRange) % 2;
     774             : }
     775             : 
     776      111247 : bool V8DebuggerAgentImpl::acceptsPause(bool isOOMBreak) const {
     777      111417 :   return enabled() && (isOOMBreak || !m_skipAllPauses);
     778             : }
     779             : 
     780             : std::unique_ptr<protocol::Debugger::Location>
     781        2153 : V8DebuggerAgentImpl::setBreakpointImpl(const String16& breakpointId,
     782             :                                        const String16& scriptId,
     783             :                                        const String16& condition,
     784             :                                        int lineNumber, int columnNumber) {
     785        4306 :   v8::HandleScope handles(m_isolate);
     786             :   DCHECK(enabled());
     787             : 
     788             :   ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
     789        2153 :   if (scriptIterator == m_scripts.end()) return nullptr;
     790             :   V8DebuggerScript* script = scriptIterator->second.get();
     791        2153 :   if (lineNumber < script->startLine() || script->endLine() < lineNumber) {
     792             :     return nullptr;
     793             :   }
     794             : 
     795             :   v8::debug::BreakpointId debuggerBreakpointId;
     796        2078 :   v8::debug::Location location(lineNumber, columnNumber);
     797             :   int contextId = script->executionContextId();
     798        2078 :   InspectedContext* inspected = m_inspector->getContext(contextId);
     799        2078 :   if (!inspected) return nullptr;
     800             : 
     801             :   {
     802        2078 :     v8::Context::Scope contextScope(inspected->context());
     803        2078 :     if (!script->setBreakpoint(condition, &location, &debuggerBreakpointId)) {
     804             :       return nullptr;
     805             :     }
     806             :   }
     807             : 
     808             :   m_debuggerBreakpointIdToBreakpointId[debuggerBreakpointId] = breakpointId;
     809             :   m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back(
     810        2048 :       debuggerBreakpointId);
     811             : 
     812        2048 :   return protocol::Debugger::Location::create()
     813             :       .setScriptId(scriptId)
     814        2048 :       .setLineNumber(location.GetLineNumber())
     815        2048 :       .setColumnNumber(location.GetColumnNumber())
     816             :       .build();
     817             : }
     818             : 
     819          95 : void V8DebuggerAgentImpl::setBreakpointImpl(const String16& breakpointId,
     820             :                                             v8::Local<v8::Function> function,
     821             :                                             v8::Local<v8::String> condition) {
     822             :   v8::debug::BreakpointId debuggerBreakpointId;
     823          95 :   if (!v8::debug::SetFunctionBreakpoint(function, condition,
     824             :                                         &debuggerBreakpointId)) {
     825           0 :     return;
     826             :   }
     827             :   m_debuggerBreakpointIdToBreakpointId[debuggerBreakpointId] = breakpointId;
     828             :   m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back(
     829          95 :       debuggerBreakpointId);
     830             : }
     831             : 
     832           0 : Response V8DebuggerAgentImpl::searchInContent(
     833             :     const String16& scriptId, const String16& query,
     834             :     Maybe<bool> optionalCaseSensitive, Maybe<bool> optionalIsRegex,
     835             :     std::unique_ptr<Array<protocol::Debugger::SearchMatch>>* results) {
     836           0 :   v8::HandleScope handles(m_isolate);
     837             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     838           0 :   if (it == m_scripts.end())
     839           0 :     return Response::Error("No script for id: " + scriptId);
     840             : 
     841             :   std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
     842           0 :       searchInTextByLinesImpl(m_session, it->second->source(0), query,
     843             :                               optionalCaseSensitive.fromMaybe(false),
     844           0 :                               optionalIsRegex.fromMaybe(false));
     845           0 :   *results = protocol::Array<protocol::Debugger::SearchMatch>::create();
     846           0 :   for (size_t i = 0; i < matches.size(); ++i)
     847           0 :     (*results)->addItem(std::move(matches[i]));
     848           0 :   return Response::OK();
     849             : }
     850             : 
     851          55 : Response V8DebuggerAgentImpl::setScriptSource(
     852             :     const String16& scriptId, const String16& newContent, Maybe<bool> dryRun,
     853             :     Maybe<protocol::Array<protocol::Debugger::CallFrame>>* newCallFrames,
     854             :     Maybe<bool>* stackChanged,
     855             :     Maybe<protocol::Runtime::StackTrace>* asyncStackTrace,
     856             :     Maybe<protocol::Runtime::StackTraceId>* asyncStackTraceId,
     857             :     Maybe<protocol::Runtime::ExceptionDetails>* optOutCompileError) {
     858          55 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     859             : 
     860             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     861          55 :   if (it == m_scripts.end()) {
     862          10 :     return Response::Error("No script with given id found");
     863             :   }
     864             :   int contextId = it->second->executionContextId();
     865          50 :   InspectedContext* inspected = m_inspector->getContext(contextId);
     866          50 :   if (!inspected) {
     867           0 :     return Response::InternalError();
     868             :   }
     869         100 :   v8::HandleScope handleScope(m_isolate);
     870          50 :   v8::Local<v8::Context> context = inspected->context();
     871             :   v8::Context::Scope contextScope(context);
     872             : 
     873             :   v8::debug::LiveEditResult result;
     874         100 :   it->second->setSource(newContent, dryRun.fromMaybe(false), &result);
     875          50 :   if (result.status != v8::debug::LiveEditResult::OK) {
     876             :     *optOutCompileError =
     877          10 :         protocol::Runtime::ExceptionDetails::create()
     878          20 :             .setExceptionId(m_inspector->nextExceptionId())
     879          20 :             .setText(toProtocolString(m_isolate, result.message))
     880          10 :             .setLineNumber(result.line_number != -1 ? result.line_number - 1
     881          10 :                                                     : 0)
     882          10 :             .setColumnNumber(result.column_number != -1 ? result.column_number
     883          10 :                                                         : 0)
     884             :             .build();
     885          10 :     return Response::OK();
     886             :   } else {
     887          40 :     *stackChanged = result.stack_changed;
     888             :   }
     889          80 :   std::unique_ptr<Array<CallFrame>> callFrames;
     890          40 :   Response response = currentCallFrames(&callFrames);
     891          40 :   if (!response.isSuccess()) return response;
     892          40 :   *newCallFrames = std::move(callFrames);
     893          80 :   *asyncStackTrace = currentAsyncStackTrace();
     894          80 :   *asyncStackTraceId = currentExternalStackTrace();
     895          40 :   return Response::OK();
     896             : }
     897             : 
     898         104 : Response V8DebuggerAgentImpl::restartFrame(
     899             :     const String16& callFrameId,
     900             :     std::unique_ptr<Array<CallFrame>>* newCallFrames,
     901             :     Maybe<protocol::Runtime::StackTrace>* asyncStackTrace,
     902             :     Maybe<protocol::Runtime::StackTraceId>* asyncStackTraceId) {
     903         109 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     904         198 :   InjectedScript::CallFrameScope scope(m_session, callFrameId);
     905          99 :   Response response = scope.initialize();
     906          99 :   if (!response.isSuccess()) return response;
     907          99 :   int frameOrdinal = static_cast<int>(scope.frameOrdinal());
     908          99 :   auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
     909          99 :   if (it->Done()) {
     910           0 :     return Response::Error("Could not find call frame with given id");
     911             :   }
     912          99 :   if (!it->Restart()) {
     913          99 :     return Response::InternalError();
     914             :   }
     915           0 :   response = currentCallFrames(newCallFrames);
     916           0 :   if (!response.isSuccess()) return response;
     917           0 :   *asyncStackTrace = currentAsyncStackTrace();
     918           0 :   *asyncStackTraceId = currentExternalStackTrace();
     919           0 :   return Response::OK();
     920             : }
     921             : 
     922        1278 : Response V8DebuggerAgentImpl::getScriptSource(const String16& scriptId,
     923             :                                               String16* scriptSource) {
     924        1278 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     925             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     926        1278 :   if (it == m_scripts.end())
     927         376 :     return Response::Error("No script for id: " + scriptId);
     928        2180 :   *scriptSource = it->second->source(0);
     929        1090 :   return Response::OK();
     930             : }
     931             : 
     932         445 : void V8DebuggerAgentImpl::pushBreakDetails(
     933             :     const String16& breakReason,
     934             :     std::unique_ptr<protocol::DictionaryValue> breakAuxData) {
     935         890 :   m_breakReason.push_back(std::make_pair(breakReason, std::move(breakAuxData)));
     936         445 : }
     937             : 
     938           0 : void V8DebuggerAgentImpl::popBreakDetails() {
     939         100 :   if (m_breakReason.empty()) return;
     940             :   m_breakReason.pop_back();
     941             : }
     942             : 
     943      114095 : void V8DebuggerAgentImpl::clearBreakDetails() {
     944      114095 :   std::vector<BreakReason> emptyBreakReason;
     945             :   m_breakReason.swap(emptyBreakReason);
     946      114095 : }
     947             : 
     948         120 : void V8DebuggerAgentImpl::schedulePauseOnNextStatement(
     949             :     const String16& breakReason,
     950             :     std::unique_ptr<protocol::DictionaryValue> data) {
     951         240 :   if (isPaused() || !acceptsPause(false) || !m_breakpointsActive) return;
     952         120 :   if (m_breakReason.empty()) {
     953         100 :     m_debugger->setPauseOnNextCall(true, m_session->contextGroupId());
     954             :   }
     955         240 :   pushBreakDetails(breakReason, std::move(data));
     956             : }
     957             : 
     958          50 : void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
     959         100 :   if (isPaused() || !acceptsPause(false) || !m_breakpointsActive) return;
     960          45 :   if (m_breakReason.size() == 1) {
     961          15 :     m_debugger->setPauseOnNextCall(false, m_session->contextGroupId());
     962             :   }
     963             :   popBreakDetails();
     964             : }
     965             : 
     966         265 : Response V8DebuggerAgentImpl::pause() {
     967         265 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     968         265 :   if (isPaused()) return Response::OK();
     969         265 :   if (m_debugger->canBreakProgram()) {
     970           0 :     m_debugger->interruptAndBreak(m_session->contextGroupId());
     971             :   } else {
     972         265 :     if (m_breakReason.empty()) {
     973         260 :       m_debugger->setPauseOnNextCall(true, m_session->contextGroupId());
     974             :     }
     975         795 :     pushBreakDetails(protocol::Debugger::Paused::ReasonEnum::Other, nullptr);
     976             :   }
     977         265 :   return Response::OK();
     978             : }
     979             : 
     980        2242 : Response V8DebuggerAgentImpl::resume() {
     981        2285 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     982        4398 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
     983        2199 :   m_debugger->continueProgram(m_session->contextGroupId());
     984        2199 :   return Response::OK();
     985             : }
     986             : 
     987        7631 : Response V8DebuggerAgentImpl::stepOver() {
     988        7636 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     989       15252 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
     990        7626 :   m_debugger->stepOverStatement(m_session->contextGroupId());
     991        7626 :   return Response::OK();
     992             : }
     993             : 
     994       36294 : Response V8DebuggerAgentImpl::stepInto(Maybe<bool> inBreakOnAsyncCall) {
     995       36299 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     996       72578 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
     997       36289 :   m_debugger->stepIntoStatement(m_session->contextGroupId(),
     998       36289 :                                 inBreakOnAsyncCall.fromMaybe(false));
     999       36289 :   return Response::OK();
    1000             : }
    1001             : 
    1002         533 : Response V8DebuggerAgentImpl::stepOut() {
    1003         538 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
    1004        1056 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
    1005         528 :   m_debugger->stepOutOfFunction(m_session->contextGroupId());
    1006         528 :   return Response::OK();
    1007             : }
    1008             : 
    1009          95 : Response V8DebuggerAgentImpl::pauseOnAsyncCall(
    1010             :     std::unique_ptr<protocol::Runtime::StackTraceId> inParentStackTraceId) {
    1011          95 :   bool isOk = false;
    1012         190 :   int64_t stackTraceId = inParentStackTraceId->getId().toInteger64(&isOk);
    1013          95 :   if (!isOk) {
    1014           0 :     return Response::Error("Invalid stack trace id");
    1015             :   }
    1016          95 :   m_debugger->pauseOnAsyncCall(m_session->contextGroupId(), stackTraceId,
    1017         475 :                                inParentStackTraceId->getDebuggerId(String16()));
    1018          95 :   return Response::OK();
    1019             : }
    1020             : 
    1021        4745 : Response V8DebuggerAgentImpl::setPauseOnExceptions(
    1022             :     const String16& stringPauseState) {
    1023        4745 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
    1024             :   v8::debug::ExceptionBreakState pauseState;
    1025        9490 :   if (stringPauseState == "none") {
    1026             :     pauseState = v8::debug::NoBreakOnException;
    1027        7266 :   } else if (stringPauseState == "all") {
    1028             :     pauseState = v8::debug::BreakOnAnyException;
    1029        4658 :   } else if (stringPauseState == "uncaught") {
    1030             :     pauseState = v8::debug::BreakOnUncaughtException;
    1031             :   } else {
    1032           0 :     return Response::Error("Unknown pause on exceptions mode: " +
    1033           0 :                            stringPauseState);
    1034             :   }
    1035        4745 :   setPauseOnExceptionsImpl(pauseState);
    1036        4745 :   return Response::OK();
    1037             : }
    1038             : 
    1039        4760 : void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(int pauseState) {
    1040             :   // TODO(dgozman): this changes the global state and forces all context groups
    1041             :   // to pause. We should make this flag be per-context-group.
    1042        4760 :   m_debugger->setPauseOnExceptionsState(
    1043        4760 :       static_cast<v8::debug::ExceptionBreakState>(pauseState));
    1044        9520 :   m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, pauseState);
    1045        4760 : }
    1046             : 
    1047       11344 : Response V8DebuggerAgentImpl::evaluateOnCallFrame(
    1048             :     const String16& callFrameId, const String16& expression,
    1049             :     Maybe<String16> objectGroup, Maybe<bool> includeCommandLineAPI,
    1050             :     Maybe<bool> silent, Maybe<bool> returnByValue, Maybe<bool> generatePreview,
    1051             :     Maybe<bool> throwOnSideEffect, Maybe<double> timeout,
    1052             :     std::unique_ptr<RemoteObject>* result,
    1053             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
    1054       11349 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
    1055       22678 :   InjectedScript::CallFrameScope scope(m_session, callFrameId);
    1056       11339 :   Response response = scope.initialize();
    1057       11339 :   if (!response.isSuccess()) return response;
    1058       11334 :   if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
    1059       11334 :   if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
    1060             : 
    1061       11334 :   int frameOrdinal = static_cast<int>(scope.frameOrdinal());
    1062       11334 :   auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
    1063       11334 :   if (it->Done()) {
    1064           0 :     return Response::Error("Could not find call frame with given id");
    1065             :   }
    1066             : 
    1067             :   v8::MaybeLocal<v8::Value> maybeResultValue;
    1068             :   {
    1069       22668 :     V8InspectorImpl::EvaluateScope evaluateScope(scope);
    1070       11334 :     if (timeout.isJust()) {
    1071          30 :       response = evaluateScope.setTimeout(timeout.fromJust() / 1000.0);
    1072          15 :       if (!response.isSuccess()) return response;
    1073             :     }
    1074             :     maybeResultValue = it->Evaluate(toV8String(m_isolate, expression),
    1075       22668 :                                     throwOnSideEffect.fromMaybe(false));
    1076             :   }
    1077             :   // Re-initialize after running client's code, as it could have destroyed
    1078             :   // context or session.
    1079       22668 :   response = scope.initialize();
    1080       11334 :   if (!response.isSuccess()) return response;
    1081             :   WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
    1082       11334 :                                                    : WrapMode::kNoPreview;
    1083       11334 :   if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
    1084             :   return scope.injectedScript()->wrapEvaluateResult(
    1085       34002 :       maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), mode,
    1086       11334 :       result, exceptionDetails);
    1087             : }
    1088             : 
    1089         271 : Response V8DebuggerAgentImpl::setVariableValue(
    1090             :     int scopeNumber, const String16& variableName,
    1091             :     std::unique_ptr<protocol::Runtime::CallArgument> newValueArgument,
    1092             :     const String16& callFrameId) {
    1093         271 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
    1094         276 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
    1095         532 :   InjectedScript::CallFrameScope scope(m_session, callFrameId);
    1096         266 :   Response response = scope.initialize();
    1097         266 :   if (!response.isSuccess()) return response;
    1098             :   v8::Local<v8::Value> newValue;
    1099         522 :   response = scope.injectedScript()->resolveCallArgument(newValueArgument.get(),
    1100             :                                                          &newValue);
    1101         261 :   if (!response.isSuccess()) return response;
    1102             : 
    1103         256 :   int frameOrdinal = static_cast<int>(scope.frameOrdinal());
    1104         256 :   auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
    1105         256 :   if (it->Done()) {
    1106           0 :     return Response::Error("Could not find call frame with given id");
    1107             :   }
    1108         256 :   auto scopeIterator = it->GetScopeIterator();
    1109         526 :   while (!scopeIterator->Done() && scopeNumber > 0) {
    1110         135 :     --scopeNumber;
    1111         135 :     scopeIterator->Advance();
    1112             :   }
    1113         256 :   if (scopeNumber != 0) {
    1114          10 :     return Response::Error("Could not find scope with given number");
    1115             :   }
    1116             : 
    1117         502 :   if (!scopeIterator->SetVariableValue(toV8String(m_isolate, variableName),
    1118         729 :                                        newValue) ||
    1119         227 :       scope.tryCatch().HasCaught()) {
    1120          24 :     return Response::InternalError();
    1121             :   }
    1122         227 :   return Response::OK();
    1123             : }
    1124             : 
    1125          15 : Response V8DebuggerAgentImpl::setReturnValue(
    1126             :     std::unique_ptr<protocol::Runtime::CallArgument> protocolNewValue) {
    1127          15 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
    1128          15 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
    1129          30 :   v8::HandleScope handleScope(m_isolate);
    1130          15 :   auto iterator = v8::debug::StackTraceIterator::Create(m_isolate);
    1131          15 :   if (iterator->Done()) {
    1132           0 :     return Response::Error("Could not find top call frame");
    1133             :   }
    1134          30 :   if (iterator->GetReturnValue().IsEmpty()) {
    1135             :     return Response::Error(
    1136          10 :         "Could not update return value at non-return position");
    1137             :   }
    1138          20 :   InjectedScript::ContextScope scope(m_session, iterator->GetContextId());
    1139          10 :   Response response = scope.initialize();
    1140          10 :   if (!response.isSuccess()) return response;
    1141             :   v8::Local<v8::Value> newValue;
    1142          20 :   response = scope.injectedScript()->resolveCallArgument(protocolNewValue.get(),
    1143             :                                                          &newValue);
    1144          10 :   if (!response.isSuccess()) return response;
    1145          10 :   v8::debug::SetReturnValue(m_isolate, newValue);
    1146          10 :   return Response::OK();
    1147             : }
    1148             : 
    1149        1011 : Response V8DebuggerAgentImpl::setAsyncCallStackDepth(int depth) {
    1150        1682 :   if (!enabled() && !m_session->runtimeAgent()->enabled()) {
    1151        1322 :     return Response::Error(kDebuggerNotEnabled);
    1152             :   }
    1153         700 :   m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth);
    1154         350 :   m_debugger->setAsyncCallStackDepth(this, depth);
    1155         350 :   return Response::OK();
    1156             : }
    1157             : 
    1158         105 : Response V8DebuggerAgentImpl::setBlackboxPatterns(
    1159             :     std::unique_ptr<protocol::Array<String16>> patterns) {
    1160         105 :   if (!patterns->length()) {
    1161           0 :     m_blackboxPattern = nullptr;
    1162             :     resetBlackboxedStateCache();
    1163           0 :     m_state->remove(DebuggerAgentState::blackboxPattern);
    1164           0 :     return Response::OK();
    1165             :   }
    1166             : 
    1167         105 :   String16Builder patternBuilder;
    1168         105 :   patternBuilder.append('(');
    1169         115 :   for (size_t i = 0; i < patterns->length() - 1; ++i) {
    1170          10 :     patternBuilder.append(patterns->get(i));
    1171          10 :     patternBuilder.append("|");
    1172             :   }
    1173         210 :   patternBuilder.append(patterns->get(patterns->length() - 1));
    1174         105 :   patternBuilder.append(')');
    1175         105 :   String16 pattern = patternBuilder.toString();
    1176         105 :   Response response = setBlackboxPattern(pattern);
    1177         105 :   if (!response.isSuccess()) return response;
    1178             :   resetBlackboxedStateCache();
    1179         200 :   m_state->setString(DebuggerAgentState::blackboxPattern, pattern);
    1180         100 :   return Response::OK();
    1181             : }
    1182             : 
    1183         105 : Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) {
    1184             :   std::unique_ptr<V8Regex> regex(new V8Regex(
    1185         210 :       m_inspector, pattern, true /** caseSensitive */, false /** multiline */));
    1186         105 :   if (!regex->isValid())
    1187          10 :     return Response::Error("Pattern parser error: " + regex->errorMessage());
    1188         100 :   m_blackboxPattern = std::move(regex);
    1189         100 :   return Response::OK();
    1190             : }
    1191             : 
    1192           0 : void V8DebuggerAgentImpl::resetBlackboxedStateCache() {
    1193       59768 :   for (const auto& it : m_scripts) {
    1194       56177 :     it.second->resetBlackboxedStateCache();
    1195             :   }
    1196           0 : }
    1197             : 
    1198          55 : Response V8DebuggerAgentImpl::setBlackboxedRanges(
    1199             :     const String16& scriptId,
    1200             :     std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>>
    1201             :         inPositions) {
    1202             :   auto it = m_scripts.find(scriptId);
    1203          55 :   if (it == m_scripts.end())
    1204           0 :     return Response::Error("No script with passed id.");
    1205             : 
    1206          55 :   if (!inPositions->length()) {
    1207             :     m_blackboxedPositions.erase(scriptId);
    1208           0 :     it->second->resetBlackboxedStateCache();
    1209           0 :     return Response::OK();
    1210             :   }
    1211             : 
    1212             :   std::vector<std::pair<int, int>> positions;
    1213          55 :   positions.reserve(inPositions->length());
    1214         235 :   for (size_t i = 0; i < inPositions->length(); ++i) {
    1215             :     protocol::Debugger::ScriptPosition* position = inPositions->get(i);
    1216          95 :     if (position->getLineNumber() < 0)
    1217           0 :       return Response::Error("Position missing 'line' or 'line' < 0.");
    1218          95 :     if (position->getColumnNumber() < 0)
    1219          10 :       return Response::Error("Position missing 'column' or 'column' < 0.");
    1220             :     positions.push_back(
    1221         180 :         std::make_pair(position->getLineNumber(), position->getColumnNumber()));
    1222             :   }
    1223             : 
    1224         110 :   for (size_t i = 1; i < positions.size(); ++i) {
    1225         120 :     if (positions[i - 1].first < positions[i].first) continue;
    1226          20 :     if (positions[i - 1].first == positions[i].first &&
    1227          10 :         positions[i - 1].second < positions[i].second)
    1228             :       continue;
    1229             :     return Response::Error(
    1230          20 :         "Input positions array is not sorted or contains duplicate values.");
    1231             :   }
    1232             : 
    1233          40 :   m_blackboxedPositions[scriptId] = positions;
    1234          40 :   it->second->resetBlackboxedStateCache();
    1235          40 :   return Response::OK();
    1236             : }
    1237             : 
    1238       55485 : Response V8DebuggerAgentImpl::currentCallFrames(
    1239             :     std::unique_ptr<Array<CallFrame>>* result) {
    1240       55485 :   if (!isPaused()) {
    1241          15 :     *result = Array<CallFrame>::create();
    1242          15 :     return Response::OK();
    1243             :   }
    1244      110940 :   v8::HandleScope handles(m_isolate);
    1245       55470 :   *result = Array<CallFrame>::create();
    1246       55470 :   auto iterator = v8::debug::StackTraceIterator::Create(m_isolate);
    1247             :   int frameOrdinal = 0;
    1248      349720 :   for (; !iterator->Done(); iterator->Advance(), frameOrdinal++) {
    1249      147125 :     int contextId = iterator->GetContextId();
    1250      147125 :     InjectedScript* injectedScript = nullptr;
    1251      294159 :     if (contextId) m_session->findInjectedScript(contextId, injectedScript);
    1252             :     String16 callFrameId =
    1253      147125 :         RemoteCallFrameId::serialize(contextId, frameOrdinal);
    1254             : 
    1255      147125 :     v8::debug::Location loc = iterator->GetSourceLocation();
    1256             : 
    1257      294250 :     std::unique_ptr<Array<Scope>> scopes;
    1258      147125 :     auto scopeIterator = iterator->GetScopeIterator();
    1259             :     Response res =
    1260      294250 :         buildScopes(m_isolate, scopeIterator.get(), injectedScript, &scopes);
    1261      147125 :     if (!res.isSuccess()) return res;
    1262             : 
    1263      147125 :     std::unique_ptr<RemoteObject> protocolReceiver;
    1264      147125 :     if (injectedScript) {
    1265             :       v8::Local<v8::Value> receiver;
    1266      294068 :       if (iterator->GetReceiver().ToLocal(&receiver)) {
    1267             :         res =
    1268      433128 :             injectedScript->wrapObject(receiver, kBacktraceObjectGroup,
    1269             :                                        WrapMode::kNoPreview, &protocolReceiver);
    1270      144376 :         if (!res.isSuccess()) return res;
    1271             :       }
    1272             :     }
    1273      147125 :     if (!protocolReceiver) {
    1274             :       protocolReceiver = RemoteObject::create()
    1275        5498 :                              .setType(RemoteObject::TypeEnum::Undefined)
    1276             :                              .build();
    1277             :     }
    1278             : 
    1279      147125 :     v8::Local<v8::debug::Script> script = iterator->GetScript();
    1280             :     DCHECK(!script.IsEmpty());
    1281             :     std::unique_ptr<protocol::Debugger::Location> location =
    1282      147125 :         protocol::Debugger::Location::create()
    1283      294250 :             .setScriptId(String16::fromInteger(script->Id()))
    1284      147125 :             .setLineNumber(loc.GetLineNumber())
    1285      147125 :             .setColumnNumber(loc.GetColumnNumber())
    1286             :             .build();
    1287      294250 :     TranslateLocation(location.get(), m_debugger->wasmTranslation());
    1288      147125 :     String16 scriptId = String16::fromInteger(script->Id());
    1289             :     ScriptsMap::iterator scriptIterator =
    1290      147125 :         m_scripts.find(location->getScriptId());
    1291             :     String16 url;
    1292      147125 :     if (scriptIterator != m_scripts.end()) {
    1293             :       url = scriptIterator->second->sourceURL();
    1294             :     }
    1295             : 
    1296      147125 :     auto frame = CallFrame::create()
    1297             :                      .setCallFrameId(callFrameId)
    1298      294250 :                      .setFunctionName(toProtocolString(
    1299      147125 :                          m_isolate, iterator->GetFunctionDebugName()))
    1300             :                      .setLocation(std::move(location))
    1301             :                      .setUrl(url)
    1302      294250 :                      .setScopeChain(std::move(scopes))
    1303             :                      .setThis(std::move(protocolReceiver))
    1304             :                      .build();
    1305             : 
    1306      147125 :     v8::Local<v8::Function> func = iterator->GetFunction();
    1307      147125 :     if (!func.IsEmpty()) {
    1308             :       frame->setFunctionLocation(
    1309      146577 :           protocol::Debugger::Location::create()
    1310      293154 :               .setScriptId(String16::fromInteger(func->ScriptId()))
    1311      146577 :               .setLineNumber(func->GetScriptLineNumber())
    1312      146577 :               .setColumnNumber(func->GetScriptColumnNumber())
    1313             :               .build());
    1314             :     }
    1315             : 
    1316      147125 :     v8::Local<v8::Value> returnValue = iterator->GetReturnValue();
    1317      147125 :     if (!returnValue.IsEmpty() && injectedScript) {
    1318        5717 :       std::unique_ptr<RemoteObject> value;
    1319       17151 :       res = injectedScript->wrapObject(returnValue, kBacktraceObjectGroup,
    1320             :                                        WrapMode::kNoPreview, &value);
    1321        5717 :       if (!res.isSuccess()) return res;
    1322             :       frame->setReturnValue(std::move(value));
    1323             :     }
    1324      147125 :     (*result)->addItem(std::move(frame));
    1325             :   }
    1326       55470 :   return Response::OK();
    1327             : }
    1328             : 
    1329             : std::unique_ptr<protocol::Runtime::StackTrace>
    1330       55485 : V8DebuggerAgentImpl::currentAsyncStackTrace() {
    1331             :   std::shared_ptr<AsyncStackTrace> asyncParent =
    1332       55485 :       m_debugger->currentAsyncParent();
    1333       55485 :   if (!asyncParent) return nullptr;
    1334             :   return asyncParent->buildInspectorObject(
    1335         625 :       m_debugger, m_debugger->maxAsyncCallChainDepth() - 1);
    1336             : }
    1337             : 
    1338             : std::unique_ptr<protocol::Runtime::StackTraceId>
    1339       55485 : V8DebuggerAgentImpl::currentExternalStackTrace() {
    1340       55485 :   V8StackTraceId externalParent = m_debugger->currentExternalParent();
    1341       55485 :   if (externalParent.IsInvalid()) return nullptr;
    1342          25 :   return protocol::Runtime::StackTraceId::create()
    1343          50 :       .setId(stackTraceIdToString(externalParent.id))
    1344          50 :       .setDebuggerId(debuggerIdToString(externalParent.debugger_id))
    1345             :       .build();
    1346             : }
    1347             : 
    1348             : std::unique_ptr<protocol::Runtime::StackTraceId>
    1349       55445 : V8DebuggerAgentImpl::currentScheduledAsyncCall() {
    1350             :   v8_inspector::V8StackTraceId scheduledAsyncCall =
    1351       55445 :       m_debugger->scheduledAsyncCall();
    1352       55445 :   if (scheduledAsyncCall.IsInvalid()) return nullptr;
    1353             :   std::unique_ptr<protocol::Runtime::StackTraceId> asyncCallStackTrace =
    1354          95 :       protocol::Runtime::StackTraceId::create()
    1355         190 :           .setId(stackTraceIdToString(scheduledAsyncCall.id))
    1356             :           .build();
    1357             :   // TODO(kozyatinskiy): extract this check to IsLocal function.
    1358         180 :   if (scheduledAsyncCall.debugger_id.first ||
    1359          85 :       scheduledAsyncCall.debugger_id.second) {
    1360             :     asyncCallStackTrace->setDebuggerId(
    1361          20 :         debuggerIdToString(scheduledAsyncCall.debugger_id));
    1362             :   }
    1363             :   return asyncCallStackTrace;
    1364             : }
    1365             : 
    1366           0 : bool V8DebuggerAgentImpl::isPaused() const {
    1367      117901 :   return m_debugger->isPausedInContextGroup(m_session->contextGroupId());
    1368             : }
    1369             : 
    1370       55971 : void V8DebuggerAgentImpl::didParseSource(
    1371             :     std::unique_ptr<V8DebuggerScript> script, bool success) {
    1372      111756 :   v8::HandleScope handles(m_isolate);
    1373       55971 :   if (!success) {
    1374             :     DCHECK(!script->isSourceLoadedLazily());
    1375         186 :     String16 scriptSource = script->source(0);
    1376         558 :     script->setSourceURL(findSourceURL(scriptSource, false));
    1377         372 :     script->setSourceMappingURL(findSourceMapURL(scriptSource, false));
    1378             :   }
    1379             : 
    1380             :   int contextId = script->executionContextId();
    1381       55971 :   int contextGroupId = m_inspector->contextGroupId(contextId);
    1382             :   InspectedContext* inspected =
    1383       55971 :       m_inspector->getContext(contextGroupId, contextId);
    1384             :   std::unique_ptr<protocol::DictionaryValue> executionContextAuxData;
    1385       55971 :   if (inspected) {
    1386             :     // Script reused between different groups/sessions can have a stale
    1387             :     // execution context id.
    1388             :     executionContextAuxData = protocol::DictionaryValue::cast(
    1389      167898 :         protocol::StringUtil::parseJSON(inspected->auxData()));
    1390             :   }
    1391       55971 :   bool isLiveEdit = script->isLiveEdit();
    1392       55971 :   bool hasSourceURLComment = script->hasSourceURLComment();
    1393       55971 :   bool isModule = script->isModule();
    1394             :   String16 scriptId = script->scriptId();
    1395             :   String16 scriptURL = script->sourceURL();
    1396             : 
    1397             :   m_scripts[scriptId] = std::move(script);
    1398             :   // Release the strong reference to get notified when debugger is the only
    1399             :   // one that holds the script. Has to be done after script added to m_scripts.
    1400       55971 :   m_scripts[scriptId]->MakeWeak();
    1401             : 
    1402             :   ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
    1403             :   DCHECK(scriptIterator != m_scripts.end());
    1404             :   V8DebuggerScript* scriptRef = scriptIterator->second.get();
    1405             :   // V8 could create functions for parsed scripts before reporting and asks
    1406             :   // inspector about blackboxed state, we should reset state each time when we
    1407             :   // make any change that change isFunctionBlackboxed output - adding parsed
    1408             :   // script is changing.
    1409       55971 :   scriptRef->resetBlackboxedStateCache();
    1410             : 
    1411       55971 :   Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL();
    1412             :   Maybe<protocol::DictionaryValue> executionContextAuxDataParam(
    1413             :       std::move(executionContextAuxData));
    1414       55971 :   const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr;
    1415             :   const bool* hasSourceURLParam =
    1416       55971 :       hasSourceURLComment ? &hasSourceURLComment : nullptr;
    1417       55971 :   const bool* isModuleParam = isModule ? &isModule : nullptr;
    1418             :   std::unique_ptr<V8StackTraceImpl> stack =
    1419      111942 :       V8StackTraceImpl::capture(m_inspector->debugger(), contextGroupId, 1);
    1420             :   std::unique_ptr<protocol::Runtime::StackTrace> stackTrace =
    1421       48813 :       stack && !stack->isEmpty()
    1422             :           ? stack->buildInspectorObjectImpl(m_debugger, 0)
    1423      153367 :           : nullptr;
    1424             : 
    1425       55971 :   if (!success) {
    1426        1860 :     m_frontend.scriptFailedToParse(
    1427         372 :         scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
    1428         372 :         scriptRef->endLine(), scriptRef->endColumn(), contextId,
    1429         186 :         scriptRef->hash(), std::move(executionContextAuxDataParam),
    1430             :         std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam,
    1431         372 :         scriptRef->length(), std::move(stackTrace));
    1432             :     return;
    1433             :   }
    1434             : 
    1435             :   // TODO(herhut, dgozman): Report correct length for WASM if needed for
    1436             :   // coverage. Or do not send the length at all and change coverage instead.
    1437       55785 :   if (scriptRef->isSourceLoadedLazily()) {
    1438         588 :     m_frontend.scriptParsed(
    1439          84 :         scriptId, scriptURL, 0, 0, 0, 0, contextId, scriptRef->hash(),
    1440             :         std::move(executionContextAuxDataParam), isLiveEditParam,
    1441             :         std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam, 0,
    1442          84 :         std::move(stackTrace));
    1443             :   } else {
    1444      612711 :     m_frontend.scriptParsed(
    1445      111402 :         scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
    1446      111402 :         scriptRef->endLine(), scriptRef->endColumn(), contextId,
    1447       55701 :         scriptRef->hash(), std::move(executionContextAuxDataParam),
    1448             :         isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam,
    1449      111402 :         isModuleParam, scriptRef->length(), std::move(stackTrace));
    1450             :   }
    1451             : 
    1452             :   std::vector<protocol::DictionaryValue*> potentialBreakpoints;
    1453       55785 :   if (!scriptURL.isEmpty()) {
    1454             :     protocol::DictionaryValue* breakpointsByUrl =
    1455       36512 :         m_state->getObject(DebuggerAgentState::breakpointsByUrl);
    1456       18256 :     if (breakpointsByUrl) {
    1457         540 :       potentialBreakpoints.push_back(breakpointsByUrl->getObject(scriptURL));
    1458             :     }
    1459       36512 :     potentialBreakpoints.push_back(
    1460       36512 :         m_state->getObject(DebuggerAgentState::breakpointsByRegex));
    1461             :   }
    1462             :   protocol::DictionaryValue* breakpointsByScriptHash =
    1463      111570 :       m_state->getObject(DebuggerAgentState::breakpointsByScriptHash);
    1464       55785 :   if (breakpointsByScriptHash) {
    1465          50 :     potentialBreakpoints.push_back(
    1466          25 :         breakpointsByScriptHash->getObject(scriptRef->hash()));
    1467             :   }
    1468             :   protocol::DictionaryValue* breakpointHints =
    1469      111570 :       m_state->getObject(DebuggerAgentState::breakpointHints);
    1470       74336 :   for (auto breakpoints : potentialBreakpoints) {
    1471       18551 :     if (!breakpoints) continue;
    1472         330 :     for (size_t i = 0; i < breakpoints->size(); ++i) {
    1473         110 :       auto breakpointWithCondition = breakpoints->at(i);
    1474             :       String16 breakpointId = breakpointWithCondition.first;
    1475             : 
    1476             :       BreakpointType type;
    1477             :       String16 selector;
    1478         110 :       int lineNumber = 0;
    1479         110 :       int columnNumber = 0;
    1480             :       parseBreakpointId(breakpointId, &type, &selector, &lineNumber,
    1481         110 :                         &columnNumber);
    1482             : 
    1483         110 :       if (!matches(m_inspector, *scriptRef, type, selector)) continue;
    1484             :       String16 condition;
    1485         110 :       breakpointWithCondition.second->asString(&condition);
    1486             :       String16 hint;
    1487             :       bool hasHint =
    1488         110 :           breakpointHints && breakpointHints->getString(breakpointId, &hint);
    1489         110 :       if (hasHint) {
    1490          90 :         adjustBreakpointLocation(*scriptRef, hint, &lineNumber, &columnNumber);
    1491             :       }
    1492             :       std::unique_ptr<protocol::Debugger::Location> location =
    1493             :           setBreakpointImpl(breakpointId, scriptId, condition, lineNumber,
    1494         110 :                             columnNumber);
    1495         110 :       if (location)
    1496         140 :         m_frontend.breakpointResolved(breakpointId, std::move(location));
    1497             :     }
    1498             :   }
    1499             : }
    1500             : 
    1501       55445 : void V8DebuggerAgentImpl::didPause(
    1502             :     int contextId, v8::Local<v8::Value> exception,
    1503             :     const std::vector<v8::debug::BreakpointId>& hitBreakpoints,
    1504             :     v8::debug::ExceptionType exceptionType, bool isUncaught, bool isOOMBreak,
    1505             :     bool isAssert) {
    1506      110890 :   v8::HandleScope handles(m_isolate);
    1507             : 
    1508       55445 :   std::vector<BreakReason> hitReasons;
    1509             : 
    1510       55445 :   if (isOOMBreak) {
    1511           5 :     hitReasons.push_back(
    1512             :         std::make_pair(protocol::Debugger::Paused::ReasonEnum::OOM, nullptr));
    1513       55440 :   } else if (isAssert) {
    1514          60 :     hitReasons.push_back(std::make_pair(
    1515             :         protocol::Debugger::Paused::ReasonEnum::Assert, nullptr));
    1516       55380 :   } else if (!exception.IsEmpty()) {
    1517        1884 :     InjectedScript* injectedScript = nullptr;
    1518        3768 :     m_session->findInjectedScript(contextId, injectedScript);
    1519        1884 :     if (injectedScript) {
    1520             :       String16 breakReason =
    1521             :           exceptionType == v8::debug::kPromiseRejection
    1522             :               ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection
    1523        1884 :               : protocol::Debugger::Paused::ReasonEnum::Exception;
    1524        1884 :       std::unique_ptr<protocol::Runtime::RemoteObject> obj;
    1525             :       injectedScript->wrapObject(exception, kBacktraceObjectGroup,
    1526        5652 :                                  WrapMode::kNoPreview, &obj);
    1527             :       std::unique_ptr<protocol::DictionaryValue> breakAuxData;
    1528        1884 :       if (obj) {
    1529        3768 :         breakAuxData = obj->toValue();
    1530        3768 :         breakAuxData->setBoolean("uncaught", isUncaught);
    1531             :       } else {
    1532             :         breakAuxData = nullptr;
    1533             :       }
    1534             :       hitReasons.push_back(
    1535        1884 :           std::make_pair(breakReason, std::move(breakAuxData)));
    1536             :     }
    1537             :   }
    1538             : 
    1539       55445 :   std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create();
    1540             : 
    1541       58003 :   for (const auto& id : hitBreakpoints) {
    1542             :     auto breakpointIterator = m_debuggerBreakpointIdToBreakpointId.find(id);
    1543        2558 :     if (breakpointIterator == m_debuggerBreakpointIdToBreakpointId.end()) {
    1544        2508 :       continue;
    1545             :     }
    1546        2453 :     const String16& breakpointId = breakpointIterator->second;
    1547             :     hitBreakpointIds->addItem(breakpointId);
    1548             :     BreakpointType type;
    1549        2453 :     parseBreakpointId(breakpointId, &type);
    1550        2453 :     if (type != BreakpointType::kDebugCommand) continue;
    1551          50 :     hitReasons.push_back(std::make_pair(
    1552             :         protocol::Debugger::Paused::ReasonEnum::DebugCommand, nullptr));
    1553             :   }
    1554             : 
    1555       56265 :   for (size_t i = 0; i < m_breakReason.size(); ++i) {
    1556             :     hitReasons.push_back(std::move(m_breakReason[i]));
    1557             :   }
    1558       55445 :   clearBreakDetails();
    1559             : 
    1560       55445 :   String16 breakReason = protocol::Debugger::Paused::ReasonEnum::Other;
    1561             :   std::unique_ptr<protocol::DictionaryValue> breakAuxData;
    1562       55445 :   if (hitReasons.size() == 1) {
    1563             :     breakReason = hitReasons[0].first;
    1564             :     breakAuxData = std::move(hitReasons[0].second);
    1565       53056 :   } else if (hitReasons.size() > 1) {
    1566          20 :     breakReason = protocol::Debugger::Paused::ReasonEnum::Ambiguous;
    1567             :     std::unique_ptr<protocol::ListValue> reasons =
    1568             :         protocol::ListValue::create();
    1569          50 :     for (size_t i = 0; i < hitReasons.size(); ++i) {
    1570             :       std::unique_ptr<protocol::DictionaryValue> reason =
    1571             :           protocol::DictionaryValue::create();
    1572          40 :       reason->setString("reason", hitReasons[i].first);
    1573          20 :       if (hitReasons[i].second)
    1574          15 :         reason->setObject("auxData", std::move(hitReasons[i].second));
    1575          40 :       reasons->pushValue(std::move(reason));
    1576             :     }
    1577             :     breakAuxData = protocol::DictionaryValue::create();
    1578          30 :     breakAuxData->setArray("reasons", std::move(reasons));
    1579             :   }
    1580             : 
    1581      110890 :   std::unique_ptr<Array<CallFrame>> protocolCallFrames;
    1582       55445 :   Response response = currentCallFrames(&protocolCallFrames);
    1583       55445 :   if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create();
    1584             : 
    1585      388115 :   m_frontend.paused(std::move(protocolCallFrames), breakReason,
    1586             :                     std::move(breakAuxData), std::move(hitBreakpointIds),
    1587      221780 :                     currentAsyncStackTrace(), currentExternalStackTrace(),
    1588      166335 :                     currentScheduledAsyncCall());
    1589       55445 : }
    1590             : 
    1591       55158 : void V8DebuggerAgentImpl::didContinue() {
    1592       55158 :   clearBreakDetails();
    1593       55158 :   m_frontend.resumed();
    1594       55158 : }
    1595             : 
    1596          65 : void V8DebuggerAgentImpl::breakProgram(
    1597             :     const String16& breakReason,
    1598             :     std::unique_ptr<protocol::DictionaryValue> data) {
    1599          75 :   if (!enabled() || m_skipAllPauses || !m_debugger->canBreakProgram()) return;
    1600          55 :   std::vector<BreakReason> currentScheduledReason;
    1601             :   currentScheduledReason.swap(m_breakReason);
    1602         120 :   pushBreakDetails(breakReason, std::move(data));
    1603             : 
    1604          60 :   int contextGroupId = m_session->contextGroupId();
    1605             :   int sessionId = m_session->sessionId();
    1606          60 :   V8InspectorImpl* inspector = m_inspector;
    1607          60 :   m_debugger->breakProgram(contextGroupId);
    1608             :   // Check that session and |this| are still around.
    1609          65 :   if (!inspector->sessionById(contextGroupId, sessionId)) return;
    1610          55 :   if (!enabled()) return;
    1611             : 
    1612             :   popBreakDetails();
    1613             :   m_breakReason.swap(currentScheduledReason);
    1614          55 :   if (!m_breakReason.empty()) {
    1615           5 :     m_debugger->setPauseOnNextCall(true, m_session->contextGroupId());
    1616             :   }
    1617             : }
    1618             : 
    1619          80 : void V8DebuggerAgentImpl::setBreakpointFor(v8::Local<v8::Function> function,
    1620             :                                            v8::Local<v8::String> condition,
    1621             :                                            BreakpointSource source) {
    1622             :   String16 breakpointId = generateBreakpointId(
    1623             :       source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand
    1624             :                                              : BreakpointType::kMonitorCommand,
    1625          80 :       function);
    1626          80 :   if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
    1627             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
    1628             :     return;
    1629             :   }
    1630          80 :   setBreakpointImpl(breakpointId, function, condition);
    1631             : }
    1632             : 
    1633          70 : void V8DebuggerAgentImpl::removeBreakpointFor(v8::Local<v8::Function> function,
    1634             :                                               BreakpointSource source) {
    1635             :   String16 breakpointId = generateBreakpointId(
    1636             :       source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand
    1637             :                                              : BreakpointType::kMonitorCommand,
    1638          70 :       function);
    1639          70 :   removeBreakpointImpl(breakpointId);
    1640          70 : }
    1641             : 
    1642           4 : void V8DebuggerAgentImpl::reset() {
    1643           4 :   if (!enabled()) return;
    1644             :   m_blackboxedPositions.clear();
    1645             :   resetBlackboxedStateCache();
    1646             :   m_scripts.clear();
    1647           4 :   m_cachedScriptIds.clear();
    1648           4 :   m_cachedScriptSize = 0;
    1649             :   m_breakpointIdToDebuggerBreakpointIds.clear();
    1650             : }
    1651             : 
    1652       20850 : void V8DebuggerAgentImpl::ScriptCollected(const V8DebuggerScript* script) {
    1653             :   DCHECK_NE(m_scripts.find(script->scriptId()), m_scripts.end());
    1654       20850 :   m_cachedScriptIds.push_back(script->scriptId());
    1655             :   // TODO(alph): Properly calculate size when sources are one-byte strings.
    1656       20850 :   m_cachedScriptSize += script->length() * sizeof(uint16_t);
    1657             : 
    1658       21108 :   while (m_cachedScriptSize > m_maxScriptCacheSize) {
    1659             :     const String16& scriptId = m_cachedScriptIds.front();
    1660         129 :     size_t scriptSize = m_scripts[scriptId]->length() * sizeof(uint16_t);
    1661             :     DCHECK_GE(m_cachedScriptSize, scriptSize);
    1662         129 :     m_cachedScriptSize -= scriptSize;
    1663             :     m_scripts.erase(scriptId);
    1664         129 :     m_cachedScriptIds.pop_front();
    1665             :   }
    1666       20850 : }
    1667             : 
    1668             : }  // namespace v8_inspector

Generated by: LCOV version 1.10