LCOV - code coverage report
Current view: top level - src/inspector - v8-debugger-agent-impl.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 712 767 92.8 %
Date: 2017-10-20 Functions: 59 64 92.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/debug/debug-interface.h"
      10             : #include "src/inspector/injected-script.h"
      11             : #include "src/inspector/inspected-context.h"
      12             : #include "src/inspector/protocol/Protocol.h"
      13             : #include "src/inspector/remote-object-id.h"
      14             : #include "src/inspector/search-util.h"
      15             : #include "src/inspector/string-util.h"
      16             : #include "src/inspector/v8-debugger-script.h"
      17             : #include "src/inspector/v8-debugger.h"
      18             : #include "src/inspector/v8-inspector-impl.h"
      19             : #include "src/inspector/v8-inspector-session-impl.h"
      20             : #include "src/inspector/v8-regex.h"
      21             : #include "src/inspector/v8-runtime-agent-impl.h"
      22             : #include "src/inspector/v8-stack-trace-impl.h"
      23             : #include "src/inspector/v8-value-utils.h"
      24             : 
      25             : #include "include/v8-inspector.h"
      26             : 
      27             : namespace v8_inspector {
      28             : 
      29             : using protocol::Array;
      30             : using protocol::Maybe;
      31             : using protocol::Debugger::BreakpointId;
      32             : using protocol::Debugger::CallFrame;
      33             : using protocol::Runtime::ExceptionDetails;
      34             : using protocol::Runtime::ScriptId;
      35             : using protocol::Runtime::RemoteObject;
      36             : using protocol::Debugger::Scope;
      37             : 
      38             : namespace DebuggerAgentState {
      39             : static const char pauseOnExceptionsState[] = "pauseOnExceptionsState";
      40             : static const char asyncCallStackDepth[] = "asyncCallStackDepth";
      41             : static const char blackboxPattern[] = "blackboxPattern";
      42             : static const char debuggerEnabled[] = "debuggerEnabled";
      43             : static const char skipAllPauses[] = "skipAllPauses";
      44             : 
      45             : static const char breakpointsByRegex[] = "breakpointsByRegex";
      46             : static const char breakpointsByUrl[] = "breakpointsByUrl";
      47             : static const char breakpointsByScriptHash[] = "breakpointsByScriptHash";
      48             : static const char breakpointHints[] = "breakpointHints";
      49             : 
      50             : }  // namespace DebuggerAgentState
      51             : 
      52             : static const char kBacktraceObjectGroup[] = "backtrace";
      53             : static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled";
      54             : static const char kDebuggerNotPaused[] =
      55             :     "Can only perform operation while paused.";
      56             : 
      57             : static const size_t kBreakpointHintMaxLength = 128;
      58             : static const intptr_t kBreakpointHintMaxSearchOffset = 80 * 10;
      59             : 
      60             : namespace {
      61             : 
      62      250156 : void TranslateLocation(protocol::Debugger::Location* location,
      63             :                        WasmTranslation* wasmTranslation) {
      64             :   String16 scriptId = location->getScriptId();
      65      125078 :   int lineNumber = location->getLineNumber();
      66      125078 :   int columnNumber = location->getColumnNumber(-1);
      67      125078 :   if (wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
      68             :           &scriptId, &lineNumber, &columnNumber)) {
      69             :     location->setScriptId(std::move(scriptId));
      70         328 :     location->setLineNumber(lineNumber);
      71         328 :     location->setColumnNumber(columnNumber);
      72             :   }
      73      125078 : }
      74             : 
      75             : enum class BreakpointType {
      76             :   kByUrl = 1,
      77             :   kByUrlRegex,
      78             :   kByScriptHash,
      79             :   kByScriptId,
      80             :   kDebugCommand,
      81             :   kMonitorCommand
      82             : };
      83             : 
      84        2043 : String16 generateBreakpointId(BreakpointType type,
      85             :                               const String16& scriptSelector, int lineNumber,
      86             :                               int columnNumber) {
      87        2043 :   String16Builder builder;
      88        2043 :   builder.appendNumber(static_cast<int>(type));
      89        2043 :   builder.append(':');
      90        2043 :   builder.appendNumber(lineNumber);
      91        2043 :   builder.append(':');
      92        2043 :   builder.appendNumber(columnNumber);
      93        2043 :   builder.append(':');
      94        2043 :   builder.append(scriptSelector);
      95        4086 :   return builder.toString();
      96             : }
      97             : 
      98        2952 : bool parseBreakpointId(const String16& breakpointId, BreakpointType* type,
      99             :                        String16* scriptSelector = nullptr,
     100             :                        int* lineNumber = nullptr, int* columnNumber = nullptr) {
     101             :   size_t typeLineSeparator = breakpointId.find(':');
     102        2952 :   if (typeLineSeparator == String16::kNotFound) return false;
     103        2947 :   size_t lineColumnSeparator = breakpointId.find(':', typeLineSeparator + 1);
     104        2947 :   if (lineColumnSeparator == String16::kNotFound) return false;
     105             :   size_t columnSelectorSeparator =
     106        2947 :       breakpointId.find(':', lineColumnSeparator + 1);
     107        2947 :   if (columnSelectorSeparator == String16::kNotFound) return false;
     108             : 
     109        2947 :   if (type) {
     110        5894 :     int rawType = breakpointId.substring(0, typeLineSeparator).toInteger();
     111        2947 :     if (rawType < static_cast<int>(BreakpointType::kByUrl) ||
     112             :         rawType > static_cast<int>(BreakpointType::kMonitorCommand)) {
     113             :       return false;
     114             :     }
     115        2942 :     *type = static_cast<BreakpointType>(rawType);
     116             :   }
     117        2942 :   if (scriptSelector) {
     118        1288 :     *scriptSelector = breakpointId.substring(columnSelectorSeparator + 1);
     119             :   }
     120        2942 :   if (lineNumber) {
     121             :     *lineNumber = breakpointId
     122             :                       .substring(typeLineSeparator + 1,
     123          85 :                                  lineColumnSeparator - typeLineSeparator - 1)
     124         170 :                       .toInteger();
     125             :   }
     126        2942 :   if (columnNumber) {
     127             :     *columnNumber =
     128             :         breakpointId
     129             :             .substring(lineColumnSeparator + 1,
     130          85 :                        columnSelectorSeparator - lineColumnSeparator - 1)
     131         170 :             .toInteger();
     132             :   }
     133             :   return true;
     134             : }
     135             : 
     136         225 : bool positionComparator(const std::pair<int, int>& a,
     137             :                         const std::pair<int, int>& b) {
     138         225 :   if (a.first != b.first) return a.first < b.first;
     139          45 :   return a.second < b.second;
     140             : }
     141             : 
     142         180 : String16 breakpointHint(const V8DebuggerScript& script, int lineNumber,
     143             :                         int columnNumber) {
     144         180 :   int offset = script.offset(lineNumber, columnNumber);
     145         180 :   if (offset == V8DebuggerScript::kNoOffset) return String16();
     146         175 :   const String16& source = script.source();
     147             :   String16 hint =
     148         350 :       source.substring(offset, kBreakpointHintMaxLength).stripWhiteSpace();
     149        3580 :   for (size_t i = 0; i < hint.length(); ++i) {
     150        1735 :     if (hint[i] == '\r' || hint[i] == '\n' || hint[i] == ';') {
     151         120 :       return hint.substring(0, i);
     152             :     }
     153             :   }
     154          55 :   return hint;
     155             : }
     156             : 
     157         210 : void adjustBreakpointLocation(const V8DebuggerScript& script,
     158             :                               const String16& hint, int* lineNumber,
     159             :                               int* columnNumber) {
     160         210 :   if (*lineNumber < script.startLine() || *lineNumber > script.endLine())
     161          20 :     return;
     162          65 :   if (hint.isEmpty()) return;
     163          65 :   intptr_t sourceOffset = script.offset(*lineNumber, *columnNumber);
     164          65 :   if (sourceOffset == V8DebuggerScript::kNoOffset) return;
     165             : 
     166             :   intptr_t searchRegionOffset = std::max(
     167         130 :       sourceOffset - kBreakpointHintMaxSearchOffset, static_cast<intptr_t>(0));
     168          65 :   size_t offset = sourceOffset - searchRegionOffset;
     169          65 :   String16 searchArea = script.source().substring(
     170         130 :       searchRegionOffset, offset + kBreakpointHintMaxSearchOffset);
     171             : 
     172             :   size_t nextMatch = searchArea.find(hint, offset);
     173             :   size_t prevMatch = searchArea.reverseFind(hint, offset);
     174          65 :   if (nextMatch == String16::kNotFound && prevMatch == String16::kNotFound) {
     175             :     return;
     176             :   }
     177             :   size_t bestMatch;
     178          50 :   if (nextMatch == String16::kNotFound) {
     179             :     bestMatch = prevMatch;
     180          50 :   } else if (prevMatch == String16::kNotFound) {
     181             :     bestMatch = nextMatch;
     182             :   } else {
     183          45 :     bestMatch = nextMatch - offset < offset - prevMatch ? nextMatch : prevMatch;
     184             :   }
     185          50 :   bestMatch += searchRegionOffset;
     186             :   v8::debug::Location hintPosition =
     187          50 :       script.location(static_cast<int>(bestMatch));
     188          50 :   if (hintPosition.IsEmpty()) return;
     189          50 :   *lineNumber = hintPosition.GetLineNumber();
     190          50 :   *columnNumber = hintPosition.GetColumnNumber();
     191             : }
     192             : 
     193        1765 : String16 breakLocationType(v8::debug::BreakLocationType type) {
     194        1765 :   switch (type) {
     195             :     case v8::debug::kCallBreakLocation:
     196         890 :       return protocol::Debugger::BreakLocation::TypeEnum::Call;
     197             :     case v8::debug::kReturnBreakLocation:
     198         865 :       return protocol::Debugger::BreakLocation::TypeEnum::Return;
     199             :     case v8::debug::kDebuggerStatementBreakLocation:
     200          10 :       return protocol::Debugger::BreakLocation::TypeEnum::DebuggerStatement;
     201             :     case v8::debug::kCommonBreakLocation:
     202           0 :       return String16();
     203             :   }
     204           0 :   return String16();
     205             : }
     206             : 
     207             : }  // namespace
     208             : 
     209      326546 : String16 scopeType(v8::debug::ScopeIterator::ScopeType type) {
     210      326546 :   switch (type) {
     211             :     case v8::debug::ScopeIterator::ScopeTypeGlobal:
     212      124566 :       return Scope::TypeEnum::Global;
     213             :     case v8::debug::ScopeIterator::ScopeTypeLocal:
     214       71124 :       return Scope::TypeEnum::Local;
     215             :     case v8::debug::ScopeIterator::ScopeTypeWith:
     216        2310 :       return Scope::TypeEnum::With;
     217             :     case v8::debug::ScopeIterator::ScopeTypeClosure:
     218       10369 :       return Scope::TypeEnum::Closure;
     219             :     case v8::debug::ScopeIterator::ScopeTypeCatch:
     220        1052 :       return Scope::TypeEnum::Catch;
     221             :     case v8::debug::ScopeIterator::ScopeTypeBlock:
     222        2396 :       return Scope::TypeEnum::Block;
     223             :     case v8::debug::ScopeIterator::ScopeTypeScript:
     224      113432 :       return Scope::TypeEnum::Script;
     225             :     case v8::debug::ScopeIterator::ScopeTypeEval:
     226          97 :       return Scope::TypeEnum::Eval;
     227             :     case v8::debug::ScopeIterator::ScopeTypeModule:
     228        1200 :       return Scope::TypeEnum::Module;
     229             :   }
     230           0 :   UNREACHABLE();
     231             :   return String16();
     232             : }
     233             : 
     234             : namespace {
     235             : 
     236      125171 : Response buildScopes(v8::debug::ScopeIterator* iterator,
     237             :                      InjectedScript* injectedScript,
     238             :                      std::unique_ptr<Array<Scope>>* scopes) {
     239             :   *scopes = Array<Scope>::create();
     240      125171 :   if (!injectedScript) return Response::OK();
     241      326436 :   for (; !iterator->Done(); iterator->Advance()) {
     242      326505 :     std::unique_ptr<RemoteObject> object;
     243             :     Response result = injectedScript->wrapObject(
     244      979515 :         iterator->GetObject(), kBacktraceObjectGroup, false, false, &object);
     245      326505 :     if (!result.isSuccess()) return result;
     246             :     auto scope = Scope::create()
     247      979308 :                      .setType(scopeType(iterator->GetType()))
     248             :                      .setObject(std::move(object))
     249             :                      .build();
     250      326436 :     v8::Local<v8::Function> closure = iterator->GetFunction();
     251      326436 :     if (!closure.IsEmpty()) {
     252       88213 :       String16 name = toProtocolStringWithTypeCheck(closure->GetDebugName());
     253       88213 :       if (!name.isEmpty()) scope->setName(name);
     254       88213 :       String16 scriptId = String16::fromInteger(closure->ScriptId());
     255       88213 :       v8::debug::Location start = iterator->GetStartLocation();
     256             :       scope->setStartLocation(protocol::Debugger::Location::create()
     257       88213 :                                   .setScriptId(scriptId)
     258       88213 :                                   .setLineNumber(start.GetLineNumber())
     259       88213 :                                   .setColumnNumber(start.GetColumnNumber())
     260             :                                   .build());
     261       88213 :       v8::debug::Location end = iterator->GetEndLocation();
     262             :       scope->setEndLocation(protocol::Debugger::Location::create()
     263       88213 :                                 .setScriptId(scriptId)
     264       88213 :                                 .setLineNumber(end.GetLineNumber())
     265       88213 :                                 .setColumnNumber(end.GetColumnNumber())
     266             :                                 .build());
     267             :     }
     268      326436 :     (*scopes)->addItem(std::move(scope));
     269             :   }
     270      124988 :   return Response::OK();
     271             : }
     272             : 
     273          10 : bool liveEditExceptionToDetails(
     274             :     V8InspectorImpl* inspector, v8::Local<v8::Context> context,
     275             :     v8::Local<v8::Value> exceptionValue,
     276             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
     277          10 :   if (!exceptionValue->IsObject()) return false;
     278          10 :   v8::Isolate* isolate = context->GetIsolate();
     279             :   v8::Local<v8::Object> exception = exceptionValue.As<v8::Object>();
     280             :   v8::Local<v8::Value> detailsValue;
     281          30 :   if (!exception->Get(context, toV8String(isolate, "details"))
     282          30 :            .ToLocal(&detailsValue) ||
     283          10 :       !detailsValue->IsObject()) {
     284             :     return false;
     285             :   }
     286             :   v8::Local<v8::Object> details = detailsValue.As<v8::Object>();
     287             :   v8::Local<v8::Value> message;
     288          30 :   if (!details->Get(context, toV8String(isolate, "syntaxErrorMessage"))
     289          30 :            .ToLocal(&message) ||
     290             :       !message->IsString()) {
     291             :     return false;
     292             :   }
     293             :   v8::Local<v8::Value> positionValue;
     294          30 :   if (!details->Get(context, toV8String(isolate, "position"))
     295          30 :            .ToLocal(&positionValue) ||
     296          10 :       !positionValue->IsObject()) {
     297             :     return false;
     298             :   }
     299             :   v8::Local<v8::Value> startPositionValue;
     300          10 :   if (!positionValue.As<v8::Object>()
     301          30 :            ->Get(context, toV8String(isolate, "start"))
     302          30 :            .ToLocal(&startPositionValue) ||
     303          10 :       !startPositionValue->IsObject()) {
     304             :     return false;
     305             :   }
     306             :   v8::Local<v8::Object> startPosition = startPositionValue.As<v8::Object>();
     307             :   v8::Local<v8::Value> lineValue;
     308          30 :   if (!startPosition->Get(context, toV8String(isolate, "line"))
     309          30 :            .ToLocal(&lineValue) ||
     310          10 :       !lineValue->IsInt32()) {
     311             :     return false;
     312             :   }
     313             :   v8::Local<v8::Value> columnValue;
     314          30 :   if (!startPosition->Get(context, toV8String(isolate, "column"))
     315          30 :            .ToLocal(&columnValue) ||
     316          10 :       !columnValue->IsInt32()) {
     317             :     return false;
     318             :   }
     319             :   *exceptionDetails =
     320             :       protocol::Runtime::ExceptionDetails::create()
     321          20 :           .setExceptionId(inspector->nextExceptionId())
     322          20 :           .setText(toProtocolString(message.As<v8::String>()))
     323          30 :           .setLineNumber(lineValue->Int32Value(context).FromJust() - 1)
     324          30 :           .setColumnNumber(columnValue->Int32Value(context).FromJust() - 1)
     325             :           .build();
     326          10 :   return true;
     327             : }
     328             : 
     329         375 : protocol::DictionaryValue* getOrCreateObject(protocol::DictionaryValue* object,
     330             :                                              const String16& key) {
     331         375 :   protocol::DictionaryValue* value = object->getObject(key);
     332         375 :   if (value) return value;
     333             :   std::unique_ptr<protocol::DictionaryValue> newDictionary =
     334         285 :       protocol::DictionaryValue::create();
     335             :   value = newDictionary.get();
     336         570 :   object->setObject(key, std::move(newDictionary));
     337             :   return value;
     338             : }
     339             : }  // namespace
     340             : 
     341        3406 : V8DebuggerAgentImpl::V8DebuggerAgentImpl(
     342        3406 :     V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
     343             :     protocol::DictionaryValue* state)
     344             :     : m_inspector(session->inspector()),
     345        3406 :       m_debugger(m_inspector->debugger()),
     346             :       m_session(session),
     347             :       m_enabled(false),
     348             :       m_state(state),
     349             :       m_frontend(frontendChannel),
     350       30654 :       m_isolate(m_inspector->isolate()) {}
     351             : 
     352       13624 : V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {}
     353             : 
     354        3126 : void V8DebuggerAgentImpl::enableImpl() {
     355        3126 :   m_enabled = true;
     356        6252 :   m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
     357        3126 :   m_debugger->enable();
     358             : 
     359             :   std::vector<std::unique_ptr<V8DebuggerScript>> compiledScripts;
     360        3126 :   m_debugger->getCompiledScripts(m_session->contextGroupId(), compiledScripts);
     361       22300 :   for (size_t i = 0; i < compiledScripts.size(); i++)
     362       16048 :     didParseSource(std::move(compiledScripts[i]), true);
     363             : 
     364        3126 :   m_breakpointsActive = true;
     365        3126 :   m_debugger->setBreakpointsActive(true);
     366             : 
     367        3126 :   if (isPaused()) {
     368             :     didPause(0, v8::Local<v8::Value>(), std::vector<v8::debug::BreakpointId>(),
     369          10 :              false, false, false, false);
     370        3126 :   }
     371        3126 : }
     372             : 
     373        3130 : Response V8DebuggerAgentImpl::enable() {
     374        3130 :   if (enabled()) return Response::OK();
     375             : 
     376        3116 :   if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
     377           0 :     return Response::Error("Script execution is prohibited");
     378             : 
     379        3116 :   enableImpl();
     380        3116 :   return Response::OK();
     381             : }
     382             : 
     383        4498 : Response V8DebuggerAgentImpl::disable() {
     384        4498 :   if (!enabled()) return Response::OK();
     385             : 
     386        6252 :   m_state->remove(DebuggerAgentState::breakpointsByRegex);
     387        6252 :   m_state->remove(DebuggerAgentState::breakpointsByUrl);
     388        6252 :   m_state->remove(DebuggerAgentState::breakpointsByScriptHash);
     389        6252 :   m_state->remove(DebuggerAgentState::breakpointHints);
     390             : 
     391             :   m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState,
     392        6252 :                       v8::debug::NoBreakOnException);
     393        6252 :   m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0);
     394             : 
     395        3126 :   if (isPaused()) m_debugger->continueProgram(m_session->contextGroupId());
     396        3126 :   if (m_breakpointsActive) {
     397        3126 :     m_debugger->setBreakpointsActive(false);
     398        3126 :     m_breakpointsActive = false;
     399             :   }
     400        3126 :   m_debugger->disable();
     401             :   m_blackboxedPositions.clear();
     402             :   m_blackboxPattern.reset();
     403             :   resetBlackboxedStateCache();
     404             :   m_scripts.clear();
     405        7517 :   for (const auto& it : m_debuggerBreakpointIdToBreakpointId) {
     406        1265 :     v8::debug::RemoveBreakpoint(m_isolate, it.first);
     407             :   }
     408             :   m_breakpointIdToDebuggerBreakpointIds.clear();
     409             :   m_debuggerBreakpointIdToBreakpointId.clear();
     410        3126 :   m_debugger->setAsyncCallStackDepth(this, 0);
     411        3126 :   clearBreakDetails();
     412        3126 :   m_skipAllPauses = false;
     413        6252 :   m_state->setBoolean(DebuggerAgentState::skipAllPauses, false);
     414        6252 :   m_state->remove(DebuggerAgentState::blackboxPattern);
     415        3126 :   m_enabled = false;
     416        6252 :   m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
     417        3126 :   return Response::OK();
     418             : }
     419             : 
     420          40 : void V8DebuggerAgentImpl::restore() {
     421             :   DCHECK(!m_enabled);
     422          80 :   if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false))
     423          30 :     return;
     424          10 :   if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
     425             :     return;
     426             : 
     427          10 :   enableImpl();
     428             : 
     429          10 :   int pauseState = v8::debug::NoBreakOnException;
     430          20 :   m_state->getInteger(DebuggerAgentState::pauseOnExceptionsState, &pauseState);
     431          10 :   setPauseOnExceptionsImpl(pauseState);
     432             : 
     433             :   m_skipAllPauses =
     434          20 :       m_state->booleanProperty(DebuggerAgentState::skipAllPauses, false);
     435             : 
     436          10 :   int asyncCallStackDepth = 0;
     437             :   m_state->getInteger(DebuggerAgentState::asyncCallStackDepth,
     438          20 :                       &asyncCallStackDepth);
     439          10 :   m_debugger->setAsyncCallStackDepth(this, asyncCallStackDepth);
     440             : 
     441          10 :   String16 blackboxPattern;
     442          20 :   if (m_state->getString(DebuggerAgentState::blackboxPattern,
     443          20 :                          &blackboxPattern)) {
     444           0 :     setBlackboxPattern(blackboxPattern);
     445             :   }
     446             : }
     447             : 
     448         138 : Response V8DebuggerAgentImpl::setBreakpointsActive(bool active) {
     449         138 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     450         138 :   if (m_breakpointsActive == active) return Response::OK();
     451         102 :   m_breakpointsActive = active;
     452         102 :   m_debugger->setBreakpointsActive(active);
     453         153 :   if (!active && !m_breakReason.empty()) {
     454           5 :     clearBreakDetails();
     455           5 :     m_debugger->setPauseOnNextStatement(false, m_session->contextGroupId());
     456             :   }
     457         102 :   return Response::OK();
     458             : }
     459             : 
     460          35 : Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) {
     461          70 :   m_state->setBoolean(DebuggerAgentState::skipAllPauses, skip);
     462          35 :   m_skipAllPauses = skip;
     463          35 :   return Response::OK();
     464             : }
     465             : 
     466         680 : static bool matches(V8InspectorImpl* inspector, const V8DebuggerScript& script,
     467             :                     BreakpointType type, const String16& selector) {
     468         680 :   switch (type) {
     469             :     case BreakpointType::kByUrl:
     470        1310 :       return script.sourceURL() == selector;
     471             :     case BreakpointType::kByScriptHash:
     472          50 :       return script.hash() == selector;
     473             :     case BreakpointType::kByUrlRegex: {
     474           0 :       V8Regex regex(inspector, selector, true);
     475           0 :       return regex.match(script.sourceURL()) != -1;
     476             :     }
     477             :     default:
     478           0 :       UNREACHABLE();
     479             :       return false;
     480             :   }
     481             : }
     482             : 
     483         135 : Response V8DebuggerAgentImpl::setBreakpointByUrl(
     484             :     int lineNumber, Maybe<String16> optionalURL,
     485             :     Maybe<String16> optionalURLRegex, Maybe<String16> optionalScriptHash,
     486             :     Maybe<int> optionalColumnNumber, Maybe<String16> optionalCondition,
     487             :     String16* outBreakpointId,
     488             :     std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations) {
     489             :   *locations = Array<protocol::Debugger::Location>::create();
     490             : 
     491         405 :   int specified = (optionalURL.isJust() ? 1 : 0) +
     492         405 :                   (optionalURLRegex.isJust() ? 1 : 0) +
     493         280 :                   (optionalScriptHash.isJust() ? 1 : 0);
     494         135 :   if (specified != 1) {
     495             :     return Response::Error(
     496           0 :         "Either url or urlRegex or scriptHash must be specified.");
     497             :   }
     498         135 :   int columnNumber = 0;
     499         135 :   if (optionalColumnNumber.isJust()) {
     500          60 :     columnNumber = optionalColumnNumber.fromJust();
     501          60 :     if (columnNumber < 0) return Response::Error("Incorrect column number");
     502             :   }
     503             : 
     504             :   BreakpointType type = BreakpointType::kByUrl;
     505         135 :   String16 selector;
     506         135 :   if (optionalURLRegex.isJust()) {
     507           0 :     selector = optionalURLRegex.fromJust();
     508             :     type = BreakpointType::kByUrlRegex;
     509         135 :   } else if (optionalURL.isJust()) {
     510         250 :     selector = optionalURL.fromJust();
     511             :     type = BreakpointType::kByUrl;
     512          10 :   } else if (optionalScriptHash.isJust()) {
     513          20 :     selector = optionalScriptHash.fromJust();
     514             :     type = BreakpointType::kByScriptHash;
     515             :   }
     516             : 
     517         270 :   String16 condition = optionalCondition.fromMaybe(String16());
     518             :   String16 breakpointId =
     519         135 :       generateBreakpointId(type, selector, lineNumber, columnNumber);
     520             :   protocol::DictionaryValue* breakpoints;
     521         135 :   switch (type) {
     522             :     case BreakpointType::kByUrlRegex:
     523             :       breakpoints =
     524           0 :           getOrCreateObject(m_state, DebuggerAgentState::breakpointsByRegex);
     525           0 :       break;
     526             :     case BreakpointType::kByUrl:
     527             :       breakpoints = getOrCreateObject(
     528             :           getOrCreateObject(m_state, DebuggerAgentState::breakpointsByUrl),
     529         250 :           selector);
     530         125 :       break;
     531             :     case BreakpointType::kByScriptHash:
     532             :       breakpoints = getOrCreateObject(
     533             :           getOrCreateObject(m_state,
     534             :                             DebuggerAgentState::breakpointsByScriptHash),
     535          20 :           selector);
     536          10 :       break;
     537             :     default:
     538           0 :       UNREACHABLE();
     539             :       break;
     540             :   }
     541         135 :   if (breakpoints->get(breakpointId)) {
     542           0 :     return Response::Error("Breakpoint at specified location already exists.");
     543             :   }
     544             : 
     545         135 :   String16 hint;
     546         865 :   for (const auto& script : m_scripts) {
     547        1010 :     if (!matches(m_inspector, *script.second, type, selector)) continue;
     548         180 :     if (!hint.isEmpty()) {
     549             :       adjustBreakpointLocation(*script.second, hint, &lineNumber,
     550          30 :                                &columnNumber);
     551             :     }
     552             :     std::unique_ptr<protocol::Debugger::Location> location = setBreakpointImpl(
     553         180 :         breakpointId, script.first, condition, lineNumber, columnNumber);
     554         180 :     if (type != BreakpointType::kByUrlRegex) {
     555         540 :       hint = breakpointHint(*script.second, lineNumber, columnNumber);
     556             :     }
     557         310 :     if (location) (*locations)->addItem(std::move(location));
     558             :   }
     559         135 :   breakpoints->setString(breakpointId, condition);
     560         135 :   if (!hint.isEmpty()) {
     561             :     protocol::DictionaryValue* breakpointHints =
     562         210 :         getOrCreateObject(m_state, DebuggerAgentState::breakpointHints);
     563         105 :     breakpointHints->setString(breakpointId, hint);
     564             :   }
     565         135 :   *outBreakpointId = breakpointId;
     566         135 :   return Response::OK();
     567             : }
     568             : 
     569        1803 : Response V8DebuggerAgentImpl::setBreakpoint(
     570             :     std::unique_ptr<protocol::Debugger::Location> location,
     571             :     Maybe<String16> optionalCondition, String16* outBreakpointId,
     572             :     std::unique_ptr<protocol::Debugger::Location>* actualLocation) {
     573             :   String16 breakpointId = generateBreakpointId(
     574             :       BreakpointType::kByScriptId, location->getScriptId(),
     575        5409 :       location->getLineNumber(), location->getColumnNumber(0));
     576        1803 :   if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
     577             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
     578         288 :     return Response::Error("Breakpoint at specified location already exists.");
     579             :   }
     580        9954 :   *actualLocation = setBreakpointImpl(breakpointId, location->getScriptId(),
     581             :                                       optionalCondition.fromMaybe(String16()),
     582             :                                       location->getLineNumber(),
     583             :                                       location->getColumnNumber(0));
     584        1659 :   if (!*actualLocation) return Response::Error("Could not resolve breakpoint");
     585        1659 :   *outBreakpointId = breakpointId;
     586        1659 :   return Response::OK();
     587             : }
     588             : 
     589         574 : Response V8DebuggerAgentImpl::removeBreakpoint(const String16& breakpointId) {
     590         579 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     591             :   BreakpointType type;
     592         569 :   String16 selector;
     593         569 :   if (!parseBreakpointId(breakpointId, &type, &selector)) {
     594          10 :     return Response::OK();
     595             :   }
     596             :   protocol::DictionaryValue* breakpoints = nullptr;
     597         559 :   switch (type) {
     598             :     case BreakpointType::kByUrl: {
     599             :       protocol::DictionaryValue* breakpointsByUrl =
     600          50 :           m_state->getObject(DebuggerAgentState::breakpointsByUrl);
     601          25 :       if (breakpointsByUrl) {
     602          25 :         breakpoints = breakpointsByUrl->getObject(selector);
     603             :       }
     604             :     } break;
     605             :     case BreakpointType::kByScriptHash: {
     606             :       protocol::DictionaryValue* breakpointsByScriptHash =
     607          20 :           m_state->getObject(DebuggerAgentState::breakpointsByScriptHash);
     608          10 :       if (breakpointsByScriptHash) {
     609          10 :         breakpoints = breakpointsByScriptHash->getObject(selector);
     610             :       }
     611             :     } break;
     612             :     case BreakpointType::kByUrlRegex:
     613           0 :       breakpoints = m_state->getObject(DebuggerAgentState::breakpointsByRegex);
     614           0 :       break;
     615             :     default:
     616             :       break;
     617             :   }
     618         559 :   if (breakpoints) breakpoints->remove(breakpointId);
     619             :   protocol::DictionaryValue* breakpointHints =
     620        1118 :       m_state->getObject(DebuggerAgentState::breakpointHints);
     621         559 :   if (breakpointHints) breakpointHints->remove(breakpointId);
     622         559 :   removeBreakpointImpl(breakpointId);
     623         559 :   return Response::OK();
     624             : }
     625             : 
     626         609 : void V8DebuggerAgentImpl::removeBreakpointImpl(const String16& breakpointId) {
     627             :   DCHECK(enabled());
     628             :   BreakpointIdToDebuggerBreakpointIdsMap::iterator
     629             :       debuggerBreakpointIdsIterator =
     630             :           m_breakpointIdToDebuggerBreakpointIds.find(breakpointId);
     631         609 :   if (debuggerBreakpointIdsIterator ==
     632             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
     633         609 :     return;
     634             :   }
     635        1842 :   for (const auto& id : debuggerBreakpointIdsIterator->second) {
     636         624 :     v8::debug::RemoveBreakpoint(m_isolate, id);
     637             :     m_debuggerBreakpointIdToBreakpointId.erase(id);
     638             :   }
     639             :   m_breakpointIdToDebuggerBreakpointIds.erase(breakpointId);
     640             : }
     641             : 
     642         260 : Response V8DebuggerAgentImpl::getPossibleBreakpoints(
     643             :     std::unique_ptr<protocol::Debugger::Location> start,
     644             :     Maybe<protocol::Debugger::Location> end, Maybe<bool> restrictToFunction,
     645             :     std::unique_ptr<protocol::Array<protocol::Debugger::BreakLocation>>*
     646             :         locations) {
     647             :   String16 scriptId = start->getScriptId();
     648             : 
     649         520 :   if (start->getLineNumber() < 0 || start->getColumnNumber(0) < 0)
     650             :     return Response::Error(
     651           0 :         "start.lineNumber and start.columnNumber should be >= 0");
     652             : 
     653             :   v8::debug::Location v8Start(start->getLineNumber(),
     654         260 :                               start->getColumnNumber(0));
     655         260 :   v8::debug::Location v8End;
     656         260 :   if (end.isJust()) {
     657         110 :     if (end.fromJust()->getScriptId() != scriptId)
     658          10 :       return Response::Error("Locations should contain the same scriptId");
     659         105 :     int line = end.fromJust()->getLineNumber();
     660             :     int column = end.fromJust()->getColumnNumber(0);
     661         105 :     if (line < 0 || column < 0)
     662             :       return Response::Error(
     663           0 :           "end.lineNumber and end.columnNumber should be >= 0");
     664         105 :     v8End = v8::debug::Location(line, column);
     665             :   }
     666             :   auto it = m_scripts.find(scriptId);
     667         260 :   if (it == m_scripts.end()) return Response::Error("Script not found");
     668             :   std::vector<v8::debug::BreakLocation> v8Locations;
     669             :   {
     670         250 :     v8::HandleScope handleScope(m_isolate);
     671             :     v8::Local<v8::Context> debuggerContext =
     672         250 :         v8::debug::GetDebugContext(m_isolate);
     673             :     v8::Context::Scope contextScope(debuggerContext);
     674             :     v8::MicrotasksScope microtasks(m_isolate,
     675         500 :                                    v8::MicrotasksScope::kDoNotRunMicrotasks);
     676         500 :     v8::TryCatch tryCatch(m_isolate);
     677             :     it->second->getPossibleBreakpoints(
     678         750 :         v8Start, v8End, restrictToFunction.fromMaybe(false), &v8Locations);
     679             :   }
     680             : 
     681             :   *locations = protocol::Array<protocol::Debugger::BreakLocation>::create();
     682        6320 :   for (size_t i = 0; i < v8Locations.size(); ++i) {
     683             :     std::unique_ptr<protocol::Debugger::BreakLocation> breakLocation =
     684             :         protocol::Debugger::BreakLocation::create()
     685        3035 :             .setScriptId(scriptId)
     686        6070 :             .setLineNumber(v8Locations[i].GetLineNumber())
     687        3035 :             .setColumnNumber(v8Locations[i].GetColumnNumber())
     688             :             .build();
     689        6070 :     if (v8Locations[i].type() != v8::debug::kCommonBreakLocation) {
     690        3530 :       breakLocation->setType(breakLocationType(v8Locations[i].type()));
     691             :     }
     692        3035 :     (*locations)->addItem(std::move(breakLocation));
     693             :   }
     694         250 :   return Response::OK();
     695             : }
     696             : 
     697          60 : Response V8DebuggerAgentImpl::continueToLocation(
     698             :     std::unique_ptr<protocol::Debugger::Location> location,
     699          60 :     Maybe<String16> targetCallFrames) {
     700          60 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     701          60 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     702          60 :   ScriptsMap::iterator it = m_scripts.find(location->getScriptId());
     703          60 :   if (it == m_scripts.end()) {
     704           0 :     return Response::Error("Cannot continue to specified location");
     705             :   }
     706          60 :   V8DebuggerScript* script = it->second.get();
     707             :   int contextId = script->executionContextId();
     708          60 :   InspectedContext* inspected = m_inspector->getContext(contextId);
     709          60 :   if (!inspected)
     710           0 :     return Response::Error("Cannot continue to specified location");
     711          60 :   v8::Context::Scope contextScope(inspected->context());
     712             :   return m_debugger->continueToLocation(
     713             :       m_session->contextGroupId(), script, std::move(location),
     714             :       targetCallFrames.fromMaybe(
     715         300 :           protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any));
     716             : }
     717             : 
     718       11681 : bool V8DebuggerAgentImpl::isFunctionBlackboxed(const String16& scriptId,
     719             :                                                const v8::debug::Location& start,
     720             :                                                const v8::debug::Location& end) {
     721             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     722       11681 :   if (it == m_scripts.end()) {
     723             :     // Unknown scripts are blackboxed.
     724             :     return true;
     725             :   }
     726       11661 :   if (m_blackboxPattern) {
     727         660 :     const String16& scriptSourceURL = it->second->sourceURL();
     728        1008 :     if (!scriptSourceURL.isEmpty() &&
     729         348 :         m_blackboxPattern->match(scriptSourceURL) != -1)
     730             :       return true;
     731             :   }
     732             :   auto itBlackboxedPositions = m_blackboxedPositions.find(scriptId);
     733       11489 :   if (itBlackboxedPositions == m_blackboxedPositions.end()) return false;
     734             : 
     735         315 :   const std::vector<std::pair<int, int>>& ranges =
     736             :       itBlackboxedPositions->second;
     737             :   auto itStartRange = std::lower_bound(
     738             :       ranges.begin(), ranges.end(),
     739         110 :       std::make_pair(start.GetLineNumber(), start.GetColumnNumber()),
     740         220 :       positionComparator);
     741             :   auto itEndRange = std::lower_bound(
     742             :       itStartRange, ranges.end(),
     743         110 :       std::make_pair(end.GetLineNumber(), end.GetColumnNumber()),
     744         220 :       positionComparator);
     745             :   // Ranges array contains positions in script where blackbox state is changed.
     746             :   // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is
     747             :   // blackboxed...
     748         205 :   return itStartRange == itEndRange &&
     749         110 :          std::distance(ranges.begin(), itStartRange) % 2;
     750             : }
     751             : 
     752       99855 : bool V8DebuggerAgentImpl::acceptsPause(bool isOOMBreak) const {
     753       99855 :   return enabled() && (isOOMBreak || !m_skipAllPauses);
     754             : }
     755             : 
     756             : std::unique_ptr<protocol::Debugger::Location>
     757        1979 : V8DebuggerAgentImpl::setBreakpointImpl(const String16& breakpointId,
     758             :                                        const String16& scriptId,
     759             :                                        const String16& condition,
     760             :                                        int lineNumber, int columnNumber) {
     761        1979 :   v8::HandleScope handles(m_isolate);
     762             :   DCHECK(enabled());
     763             : 
     764             :   ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
     765        1979 :   if (scriptIterator == m_scripts.end()) return nullptr;
     766        5862 :   V8DebuggerScript* script = scriptIterator->second.get();
     767        3953 :   if (lineNumber < script->startLine() || script->endLine() < lineNumber) {
     768             :     return nullptr;
     769             :   }
     770             : 
     771             :   v8::debug::BreakpointId debuggerBreakpointId;
     772        1909 :   v8::debug::Location location(lineNumber, columnNumber);
     773             :   int contextId = script->executionContextId();
     774        1909 :   InspectedContext* inspected = m_inspector->getContext(contextId);
     775        1909 :   if (!inspected) return nullptr;
     776             : 
     777             :   {
     778        1909 :     v8::Context::Scope contextScope(inspected->context());
     779        1909 :     if (!script->setBreakpoint(condition, &location, &debuggerBreakpointId)) {
     780             :       return nullptr;
     781             :     }
     782             :   }
     783             : 
     784        1889 :   m_debuggerBreakpointIdToBreakpointId[debuggerBreakpointId] = breakpointId;
     785             :   m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back(
     786        1889 :       debuggerBreakpointId);
     787             : 
     788             :   return protocol::Debugger::Location::create()
     789        1889 :       .setScriptId(scriptId)
     790        1889 :       .setLineNumber(location.GetLineNumber())
     791        1889 :       .setColumnNumber(location.GetColumnNumber())
     792        1979 :       .build();
     793             : }
     794             : 
     795           0 : Response V8DebuggerAgentImpl::searchInContent(
     796             :     const String16& scriptId, const String16& query,
     797             :     Maybe<bool> optionalCaseSensitive, Maybe<bool> optionalIsRegex,
     798             :     std::unique_ptr<Array<protocol::Debugger::SearchMatch>>* results) {
     799           0 :   v8::HandleScope handles(m_isolate);
     800             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     801           0 :   if (it == m_scripts.end())
     802           0 :     return Response::Error("No script for id: " + scriptId);
     803             : 
     804             :   std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
     805           0 :       searchInTextByLinesImpl(m_session, it->second->source(), query,
     806             :                               optionalCaseSensitive.fromMaybe(false),
     807           0 :                               optionalIsRegex.fromMaybe(false));
     808             :   *results = protocol::Array<protocol::Debugger::SearchMatch>::create();
     809           0 :   for (size_t i = 0; i < matches.size(); ++i)
     810           0 :     (*results)->addItem(std::move(matches[i]));
     811           0 :   return Response::OK();
     812             : }
     813             : 
     814          45 : Response V8DebuggerAgentImpl::setScriptSource(
     815             :     const String16& scriptId, const String16& newContent, Maybe<bool> dryRun,
     816             :     Maybe<protocol::Array<protocol::Debugger::CallFrame>>* newCallFrames,
     817             :     Maybe<bool>* stackChanged,
     818             :     Maybe<protocol::Runtime::StackTrace>* asyncStackTrace,
     819          45 :     Maybe<protocol::Runtime::ExceptionDetails>* optOutCompileError) {
     820          45 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     821             : 
     822             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     823          45 :   if (it == m_scripts.end()) {
     824          10 :     return Response::Error("No script with given id found");
     825             :   }
     826          40 :   if (it->second->isModule()) {
     827             :     // TODO(kozyatinskiy): LiveEdit should support ES6 module
     828          10 :     return Response::Error("Editing module's script is not supported.");
     829             :   }
     830          35 :   int contextId = it->second->executionContextId();
     831          35 :   InspectedContext* inspected = m_inspector->getContext(contextId);
     832          35 :   if (!inspected) {
     833           0 :     return Response::InternalError();
     834             :   }
     835          35 :   v8::HandleScope handleScope(m_isolate);
     836          35 :   v8::Local<v8::Context> context = inspected->context();
     837             :   v8::Context::Scope contextScope(context);
     838          70 :   v8::TryCatch tryCatch(m_isolate);
     839             : 
     840          35 :   bool stackChangedValue = false;
     841             :   it->second->setSource(newContent, dryRun.fromMaybe(false),
     842          70 :                         &stackChangedValue);
     843          35 :   if (tryCatch.HasCaught()) {
     844          10 :     if (liveEditExceptionToDetails(m_inspector, context, tryCatch.Exception(),
     845          10 :                                    optOutCompileError)) {
     846          10 :       return Response::OK();
     847             :     }
     848           0 :     v8::Local<v8::Message> message = tryCatch.Message();
     849           0 :     if (!message.IsEmpty())
     850           0 :       return Response::Error(toProtocolStringWithTypeCheck(message->Get()));
     851             :     else
     852           0 :       return Response::InternalError();
     853             :   } else {
     854          25 :     *stackChanged = stackChangedValue;
     855             :   }
     856          25 :   std::unique_ptr<Array<CallFrame>> callFrames;
     857          25 :   Response response = currentCallFrames(&callFrames);
     858          25 :   if (!response.isSuccess()) return response;
     859             :   *newCallFrames = std::move(callFrames);
     860          50 :   *asyncStackTrace = currentAsyncStackTrace();
     861          60 :   return Response::OK();
     862             : }
     863             : 
     864         104 : Response V8DebuggerAgentImpl::restartFrame(
     865             :     const String16& callFrameId,
     866             :     std::unique_ptr<Array<CallFrame>>* newCallFrames,
     867             :     Maybe<protocol::Runtime::StackTrace>* asyncStackTrace) {
     868         109 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     869          99 :   InjectedScript::CallFrameScope scope(m_session, callFrameId);
     870          99 :   Response response = scope.initialize();
     871          99 :   if (!response.isSuccess()) return response;
     872          99 :   int frameOrdinal = static_cast<int>(scope.frameOrdinal());
     873          99 :   auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
     874          99 :   if (it->Done()) {
     875           0 :     return Response::Error("Could not find call frame with given id");
     876             :   }
     877          99 :   if (!it->Restart()) {
     878           0 :     return Response::InternalError();
     879             :   }
     880         198 :   response = currentCallFrames(newCallFrames);
     881          99 :   if (!response.isSuccess()) return response;
     882         198 :   *asyncStackTrace = currentAsyncStackTrace();
     883         198 :   return Response::OK();
     884             : }
     885             : 
     886         895 : Response V8DebuggerAgentImpl::getScriptSource(const String16& scriptId,
     887         895 :                                               String16* scriptSource) {
     888         895 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     889             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     890         895 :   if (it == m_scripts.end())
     891           0 :     return Response::Error("No script for id: " + scriptId);
     892         895 :   *scriptSource = it->second->source();
     893         895 :   return Response::OK();
     894             : }
     895             : 
     896         370 : void V8DebuggerAgentImpl::pushBreakDetails(
     897             :     const String16& breakReason,
     898             :     std::unique_ptr<protocol::DictionaryValue> breakAuxData) {
     899         740 :   m_breakReason.push_back(std::make_pair(breakReason, std::move(breakAuxData)));
     900         370 : }
     901             : 
     902           0 : void V8DebuggerAgentImpl::popBreakDetails() {
     903         100 :   if (m_breakReason.empty()) return;
     904             :   m_breakReason.pop_back();
     905             : }
     906             : 
     907      102630 : void V8DebuggerAgentImpl::clearBreakDetails() {
     908             :   std::vector<BreakReason> emptyBreakReason;
     909      102630 :   m_breakReason.swap(emptyBreakReason);
     910      102630 : }
     911             : 
     912         115 : void V8DebuggerAgentImpl::schedulePauseOnNextStatement(
     913             :     const String16& breakReason,
     914             :     std::unique_ptr<protocol::DictionaryValue> data) {
     915         345 :   if (isPaused() || !acceptsPause(false) || !m_breakpointsActive) return;
     916         115 :   if (m_breakReason.empty()) {
     917          95 :     m_debugger->setPauseOnNextStatement(true, m_session->contextGroupId());
     918             :   }
     919         230 :   pushBreakDetails(breakReason, std::move(data));
     920             : }
     921             : 
     922          45 : void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
     923         135 :   if (isPaused() || !acceptsPause(false) || !m_breakpointsActive) return;
     924          90 :   if (m_breakReason.size() == 1) {
     925          15 :     m_debugger->setPauseOnNextStatement(false, m_session->contextGroupId());
     926             :   }
     927             :   popBreakDetails();
     928             : }
     929             : 
     930         195 : Response V8DebuggerAgentImpl::pause() {
     931         195 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     932         195 :   if (isPaused()) return Response::OK();
     933         195 :   if (m_breakReason.empty()) {
     934         190 :     m_debugger->setPauseOnNextStatement(true, m_session->contextGroupId());
     935             :   }
     936         585 :   pushBreakDetails(protocol::Debugger::Paused::ReasonEnum::Other, nullptr);
     937         195 :   return Response::OK();
     938             : }
     939             : 
     940        1625 : Response V8DebuggerAgentImpl::resume() {
     941        1670 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     942        4740 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
     943        3160 :   m_debugger->continueProgram(m_session->contextGroupId());
     944        1580 :   return Response::OK();
     945             : }
     946             : 
     947        7494 : Response V8DebuggerAgentImpl::stepOver() {
     948        7499 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     949       22467 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
     950       14978 :   m_debugger->stepOverStatement(m_session->contextGroupId());
     951        7489 :   return Response::OK();
     952             : }
     953             : 
     954       31737 : Response V8DebuggerAgentImpl::stepInto() {
     955       31742 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     956       95196 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
     957       63464 :   m_debugger->stepIntoStatement(m_session->contextGroupId());
     958       31732 :   return Response::OK();
     959             : }
     960             : 
     961         445 : Response V8DebuggerAgentImpl::stepOut() {
     962         450 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     963        1320 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
     964         880 :   m_debugger->stepOutOfFunction(m_session->contextGroupId());
     965         440 :   return Response::OK();
     966             : }
     967             : 
     968          75 : void V8DebuggerAgentImpl::scheduleStepIntoAsync(
     969             :     std::unique_ptr<ScheduleStepIntoAsyncCallback> callback) {
     970          75 :   if (!isPaused()) {
     971           0 :     callback->sendFailure(Response::Error(kDebuggerNotPaused));
     972          75 :     return;
     973             :   }
     974             :   m_debugger->scheduleStepIntoAsync(std::move(callback),
     975         225 :                                     m_session->contextGroupId());
     976             : }
     977             : 
     978        4619 : Response V8DebuggerAgentImpl::setPauseOnExceptions(
     979        4619 :     const String16& stringPauseState) {
     980        4619 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     981             :   v8::debug::ExceptionBreakState pauseState;
     982        9238 :   if (stringPauseState == "none") {
     983             :     pauseState = v8::debug::NoBreakOnException;
     984        7134 :   } else if (stringPauseState == "all") {
     985             :     pauseState = v8::debug::BreakOnAnyException;
     986        4582 :   } else if (stringPauseState == "uncaught") {
     987             :     pauseState = v8::debug::BreakOnUncaughtException;
     988             :   } else {
     989           0 :     return Response::Error("Unknown pause on exceptions mode: " +
     990           0 :                            stringPauseState);
     991             :   }
     992        4619 :   setPauseOnExceptionsImpl(pauseState);
     993        4619 :   return Response::OK();
     994             : }
     995             : 
     996        4629 : void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(int pauseState) {
     997             :   // TODO(dgozman): this changes the global state and forces all context groups
     998             :   // to pause. We should make this flag be per-context-group.
     999             :   m_debugger->setPauseOnExceptionsState(
    1000        4629 :       static_cast<v8::debug::ExceptionBreakState>(pauseState));
    1001        9258 :   m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, pauseState);
    1002        4629 : }
    1003             : 
    1004        9558 : Response V8DebuggerAgentImpl::evaluateOnCallFrame(
    1005             :     const String16& callFrameId, const String16& expression,
    1006             :     Maybe<String16> objectGroup, Maybe<bool> includeCommandLineAPI,
    1007             :     Maybe<bool> silent, Maybe<bool> returnByValue, Maybe<bool> generatePreview,
    1008             :     Maybe<bool> throwOnSideEffect, std::unique_ptr<RemoteObject>* result,
    1009             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
    1010        9563 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
    1011        9553 :   InjectedScript::CallFrameScope scope(m_session, callFrameId);
    1012        9553 :   Response response = scope.initialize();
    1013        9553 :   if (!response.isSuccess()) return response;
    1014        9553 :   if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
    1015        9553 :   if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
    1016             : 
    1017        9553 :   int frameOrdinal = static_cast<int>(scope.frameOrdinal());
    1018        9553 :   auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
    1019        9553 :   if (it->Done()) {
    1020           0 :     return Response::Error("Could not find call frame with given id");
    1021             :   }
    1022             :   v8::MaybeLocal<v8::Value> maybeResultValue = it->Evaluate(
    1023       19106 :       toV8String(m_isolate, expression), throwOnSideEffect.fromMaybe(false));
    1024             :   // Re-initialize after running client's code, as it could have destroyed
    1025             :   // context or session.
    1026       19106 :   response = scope.initialize();
    1027        9553 :   if (!response.isSuccess()) return response;
    1028             :   return scope.injectedScript()->wrapEvaluateResult(
    1029             :       maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""),
    1030             :       returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), result,
    1031       57318 :       exceptionDetails);
    1032             : }
    1033             : 
    1034         221 : Response V8DebuggerAgentImpl::setVariableValue(
    1035             :     int scopeNumber, const String16& variableName,
    1036             :     std::unique_ptr<protocol::Runtime::CallArgument> newValueArgument,
    1037         221 :     const String16& callFrameId) {
    1038         221 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
    1039         226 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
    1040         216 :   InjectedScript::CallFrameScope scope(m_session, callFrameId);
    1041         216 :   Response response = scope.initialize();
    1042         216 :   if (!response.isSuccess()) return response;
    1043             :   v8::Local<v8::Value> newValue;
    1044         432 :   response = scope.injectedScript()->resolveCallArgument(newValueArgument.get(),
    1045             :                                                          &newValue);
    1046         216 :   if (!response.isSuccess()) return response;
    1047             : 
    1048         216 :   int frameOrdinal = static_cast<int>(scope.frameOrdinal());
    1049         216 :   auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
    1050         216 :   if (it->Done()) {
    1051           0 :     return Response::Error("Could not find call frame with given id");
    1052             :   }
    1053         216 :   auto scopeIterator = it->GetScopeIterator();
    1054         567 :   while (!scopeIterator->Done() && scopeNumber > 0) {
    1055         135 :     --scopeNumber;
    1056         135 :     scopeIterator->Advance();
    1057             :   }
    1058         216 :   if (scopeNumber != 0) {
    1059           0 :     return Response::Error("Could not find scope with given number");
    1060             :   }
    1061         216 :   if (!scopeIterator->SetVariableValue(toV8String(m_isolate, variableName),
    1062         413 :                                        newValue) ||
    1063         197 :       scope.tryCatch().HasCaught()) {
    1064          19 :     return Response::InternalError();
    1065             :   }
    1066         413 :   return Response::OK();
    1067             : }
    1068             : 
    1069         220 : Response V8DebuggerAgentImpl::setAsyncCallStackDepth(int depth) {
    1070         220 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
    1071         440 :   m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth);
    1072         220 :   m_debugger->setAsyncCallStackDepth(this, depth);
    1073         220 :   return Response::OK();
    1074             : }
    1075             : 
    1076          57 : Response V8DebuggerAgentImpl::setBlackboxPatterns(
    1077             :     std::unique_ptr<protocol::Array<String16>> patterns) {
    1078          57 :   if (!patterns->length()) {
    1079             :     m_blackboxPattern = nullptr;
    1080             :     resetBlackboxedStateCache();
    1081           0 :     m_state->remove(DebuggerAgentState::blackboxPattern);
    1082           0 :     return Response::OK();
    1083             :   }
    1084             : 
    1085          57 :   String16Builder patternBuilder;
    1086          57 :   patternBuilder.append('(');
    1087         116 :   for (size_t i = 0; i < patterns->length() - 1; ++i) {
    1088           2 :     patternBuilder.append(patterns->get(i));
    1089           2 :     patternBuilder.append("|");
    1090             :   }
    1091         114 :   patternBuilder.append(patterns->get(patterns->length() - 1));
    1092          57 :   patternBuilder.append(')');
    1093          57 :   String16 pattern = patternBuilder.toString();
    1094          57 :   Response response = setBlackboxPattern(pattern);
    1095          57 :   if (!response.isSuccess()) return response;
    1096             :   resetBlackboxedStateCache();
    1097         112 :   m_state->setString(DebuggerAgentState::blackboxPattern, pattern);
    1098          56 :   return Response::OK();
    1099             : }
    1100             : 
    1101          57 : Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) {
    1102             :   std::unique_ptr<V8Regex> regex(new V8Regex(
    1103          57 :       m_inspector, pattern, true /** caseSensitive */, false /** multiline */));
    1104          57 :   if (!regex->isValid())
    1105           2 :     return Response::Error("Pattern parser error: " + regex->errorMessage());
    1106             :   m_blackboxPattern = std::move(regex);
    1107          56 :   return Response::OK();
    1108             : }
    1109             : 
    1110           0 : void V8DebuggerAgentImpl::resetBlackboxedStateCache() {
    1111       29381 :   for (const auto& it : m_scripts) {
    1112       26199 :     it.second->resetBlackboxedStateCache();
    1113             :   }
    1114           0 : }
    1115             : 
    1116          55 : Response V8DebuggerAgentImpl::setBlackboxedRanges(
    1117             :     const String16& scriptId,
    1118             :     std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>>
    1119             :         inPositions) {
    1120             :   auto it = m_scripts.find(scriptId);
    1121          55 :   if (it == m_scripts.end())
    1122           0 :     return Response::Error("No script with passed id.");
    1123             : 
    1124          55 :   if (!inPositions->length()) {
    1125             :     m_blackboxedPositions.erase(scriptId);
    1126           0 :     it->second->resetBlackboxedStateCache();
    1127           0 :     return Response::OK();
    1128             :   }
    1129             : 
    1130             :   std::vector<std::pair<int, int>> positions;
    1131          55 :   positions.reserve(inPositions->length());
    1132         290 :   for (size_t i = 0; i < inPositions->length(); ++i) {
    1133         190 :     protocol::Debugger::ScriptPosition* position = inPositions->get(i);
    1134          95 :     if (position->getLineNumber() < 0)
    1135           0 :       return Response::Error("Position missing 'line' or 'line' < 0.");
    1136          95 :     if (position->getColumnNumber() < 0)
    1137          10 :       return Response::Error("Position missing 'column' or 'column' < 0.");
    1138             :     positions.push_back(
    1139         180 :         std::make_pair(position->getLineNumber(), position->getColumnNumber()));
    1140             :   }
    1141             : 
    1142         110 :   for (size_t i = 1; i < positions.size(); ++i) {
    1143         120 :     if (positions[i - 1].first < positions[i].first) continue;
    1144          20 :     if (positions[i - 1].first == positions[i].first &&
    1145          10 :         positions[i - 1].second < positions[i].second)
    1146             :       continue;
    1147             :     return Response::Error(
    1148          20 :         "Input positions array is not sorted or contains duplicate values.");
    1149             :   }
    1150             : 
    1151          40 :   m_blackboxedPositions[scriptId] = positions;
    1152          40 :   it->second->resetBlackboxedStateCache();
    1153          40 :   return Response::OK();
    1154             : }
    1155             : 
    1156       49944 : Response V8DebuggerAgentImpl::currentCallFrames(
    1157             :     std::unique_ptr<Array<CallFrame>>* result) {
    1158       49944 :   if (!isPaused()) {
    1159             :     *result = Array<CallFrame>::create();
    1160           5 :     return Response::OK();
    1161             :   }
    1162       49939 :   v8::HandleScope handles(m_isolate);
    1163             :   *result = Array<CallFrame>::create();
    1164       49939 :   auto iterator = v8::debug::StackTraceIterator::Create(m_isolate);
    1165             :   int frameOrdinal = 0;
    1166      350034 :   for (; !iterator->Done(); iterator->Advance(), frameOrdinal++) {
    1167      125171 :     int contextId = iterator->GetContextId();
    1168      125171 :     InjectedScript* injectedScript = nullptr;
    1169      250228 :     if (contextId) m_session->findInjectedScript(contextId, injectedScript);
    1170             :     String16 callFrameId =
    1171      125171 :         RemoteCallFrameId::serialize(contextId, frameOrdinal);
    1172             : 
    1173      125171 :     v8::debug::Location loc = iterator->GetSourceLocation();
    1174             : 
    1175      125171 :     std::unique_ptr<Array<Scope>> scopes;
    1176      125171 :     auto scopeIterator = iterator->GetScopeIterator();
    1177      250342 :     Response res = buildScopes(scopeIterator.get(), injectedScript, &scopes);
    1178      125171 :     if (!res.isSuccess()) return res;
    1179             : 
    1180      125102 :     std::unique_ptr<RemoteObject> receiver;
    1181      125102 :     if (injectedScript) {
    1182      499952 :       res = injectedScript->wrapObject(iterator->GetReceiver(),
    1183             :                                        kBacktraceObjectGroup, false, false,
    1184             :                                        &receiver);
    1185      124988 :       if (!res.isSuccess()) return res;
    1186             :     } else {
    1187             :       receiver = RemoteObject::create()
    1188         342 :                      .setType(RemoteObject::TypeEnum::Undefined)
    1189             :                      .build();
    1190             :     }
    1191             : 
    1192      125078 :     v8::Local<v8::debug::Script> script = iterator->GetScript();
    1193             :     DCHECK(!script.IsEmpty());
    1194             :     std::unique_ptr<protocol::Debugger::Location> location =
    1195             :         protocol::Debugger::Location::create()
    1196      375234 :             .setScriptId(String16::fromInteger(script->Id()))
    1197      125078 :             .setLineNumber(loc.GetLineNumber())
    1198      125078 :             .setColumnNumber(loc.GetColumnNumber())
    1199             :             .build();
    1200      125078 :     TranslateLocation(location.get(), m_debugger->wasmTranslation());
    1201      125078 :     String16 scriptId = String16::fromInteger(script->Id());
    1202             :     ScriptsMap::iterator scriptIterator =
    1203      125078 :         m_scripts.find(location->getScriptId());
    1204      125078 :     String16 url;
    1205      125078 :     if (scriptIterator != m_scripts.end()) {
    1206      125074 :       url = scriptIterator->second->sourceURL();
    1207             :     }
    1208             : 
    1209             :     auto frame =
    1210             :         CallFrame::create()
    1211      125078 :             .setCallFrameId(callFrameId)
    1212      250156 :             .setFunctionName(toProtocolString(iterator->GetFunctionName()))
    1213             :             .setLocation(std::move(location))
    1214             :             .setUrl(url)
    1215             :             .setScopeChain(std::move(scopes))
    1216             :             .setThis(std::move(receiver))
    1217             :             .build();
    1218             : 
    1219      125078 :     v8::Local<v8::Function> func = iterator->GetFunction();
    1220      125078 :     if (!func.IsEmpty()) {
    1221             :       frame->setFunctionLocation(
    1222             :           protocol::Debugger::Location::create()
    1223      374046 :               .setScriptId(String16::fromInteger(func->ScriptId()))
    1224      124682 :               .setLineNumber(func->GetScriptLineNumber())
    1225      124682 :               .setColumnNumber(func->GetScriptColumnNumber())
    1226             :               .build());
    1227             :     }
    1228             : 
    1229      125078 :     v8::Local<v8::Value> returnValue = iterator->GetReturnValue();
    1230      125078 :     if (!returnValue.IsEmpty() && injectedScript) {
    1231        5499 :       std::unique_ptr<RemoteObject> value;
    1232       16497 :       res = injectedScript->wrapObject(returnValue, kBacktraceObjectGroup,
    1233             :                                        false, false, &value);
    1234        5499 :       if (!res.isSuccess()) return res;
    1235             :       frame->setReturnValue(std::move(value));
    1236             :     }
    1237      125078 :     (*result)->addItem(std::move(frame));
    1238             :   }
    1239       99785 :   return Response::OK();
    1240             : }
    1241             : 
    1242             : std::unique_ptr<protocol::Runtime::StackTrace>
    1243       49944 : V8DebuggerAgentImpl::currentAsyncStackTrace() {
    1244             :   std::shared_ptr<AsyncStackTrace> asyncParent =
    1245       50269 :       m_debugger->currentAsyncParent();
    1246       49944 :   if (!asyncParent) return nullptr;
    1247             :   return asyncParent->buildInspectorObject(
    1248             :       m_debugger->currentAsyncCreation().get(),
    1249         975 :       m_debugger->maxAsyncCallChainDepth() - 1);
    1250             : }
    1251             : 
    1252           0 : bool V8DebuggerAgentImpl::isPaused() const {
    1253      107870 :   return m_debugger->isPausedInContextGroup(m_session->contextGroupId());
    1254             : }
    1255             : 
    1256       25970 : void V8DebuggerAgentImpl::didParseSource(
    1257             :     std::unique_ptr<V8DebuggerScript> script, bool success) {
    1258       25970 :   v8::HandleScope handles(m_isolate);
    1259       25970 :   String16 scriptSource = script->source();
    1260       26234 :   if (!success) script->setSourceURL(findSourceURL(scriptSource, false));
    1261       25970 :   if (!success)
    1262         264 :     script->setSourceMappingURL(findSourceMapURL(scriptSource, false));
    1263             : 
    1264       25970 :   int contextId = script->executionContextId();
    1265       25970 :   int contextGroupId = m_inspector->contextGroupId(contextId);
    1266             :   InspectedContext* inspected =
    1267       25970 :       m_inspector->getContext(contextGroupId, contextId);
    1268             :   std::unique_ptr<protocol::DictionaryValue> executionContextAuxData;
    1269       25970 :   if (inspected) {
    1270             :     // Script reused between different groups/sessions can have a stale
    1271             :     // execution context id.
    1272       77895 :     executionContextAuxData = protocol::DictionaryValue::cast(
    1273             :         protocol::StringUtil::parseJSON(inspected->auxData()));
    1274             :   }
    1275       25970 :   bool isLiveEdit = script->isLiveEdit();
    1276       25970 :   bool hasSourceURL = script->hasSourceURL();
    1277       25970 :   bool isModule = script->isModule();
    1278       25970 :   String16 scriptId = script->scriptId();
    1279       25970 :   String16 scriptURL = script->sourceURL();
    1280             : 
    1281             :   m_scripts[scriptId] = std::move(script);
    1282             : 
    1283             :   ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
    1284             :   DCHECK(scriptIterator != m_scripts.end());
    1285       25970 :   V8DebuggerScript* scriptRef = scriptIterator->second.get();
    1286             :   // V8 could create functions for parsed scripts before reporting and asks
    1287             :   // inspector about blackboxed state, we should reset state each time when we
    1288             :   // make any change that change isFunctionBlackboxed output - adding parsed
    1289             :   // script is changing.
    1290       25970 :   scriptRef->resetBlackboxedStateCache();
    1291             : 
    1292       25970 :   Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL();
    1293             :   Maybe<protocol::DictionaryValue> executionContextAuxDataParam(
    1294             :       std::move(executionContextAuxData));
    1295       25970 :   const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr;
    1296       25970 :   const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr;
    1297       25970 :   const bool* isModuleParam = isModule ? &isModule : nullptr;
    1298             :   std::unique_ptr<V8StackTraceImpl> stack =
    1299       51940 :       V8StackTraceImpl::capture(m_inspector->debugger(), contextGroupId, 1);
    1300             :   std::unique_ptr<protocol::Runtime::StackTrace> stackTrace =
    1301       47764 :       stack && !stack->isEmpty() ? stack->buildInspectorObjectImpl() : nullptr;
    1302       25970 :   if (success) {
    1303             :     m_frontend.scriptParsed(
    1304             :         scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
    1305             :         scriptRef->endLine(), scriptRef->endColumn(), contextId,
    1306       25838 :         scriptRef->hash(), std::move(executionContextAuxDataParam),
    1307             :         isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam,
    1308             :         isModuleParam, static_cast<int>(scriptRef->source().length()),
    1309      206704 :         std::move(stackTrace));
    1310             :   } else {
    1311             :     m_frontend.scriptFailedToParse(
    1312             :         scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
    1313             :         scriptRef->endLine(), scriptRef->endColumn(), contextId,
    1314         132 :         scriptRef->hash(), std::move(executionContextAuxDataParam),
    1315             :         std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam,
    1316         924 :         static_cast<int>(scriptRef->source().length()), std::move(stackTrace));
    1317             :   }
    1318             : 
    1319       51940 :   if (!success) return;
    1320             : 
    1321             :   std::vector<protocol::DictionaryValue*> potentialBreakpoints;
    1322       25838 :   if (!scriptURL.isEmpty()) {
    1323             :     protocol::DictionaryValue* breakpointsByUrl =
    1324       17902 :         m_state->getObject(DebuggerAgentState::breakpointsByUrl);
    1325        8951 :     if (breakpointsByUrl) {
    1326         390 :       potentialBreakpoints.push_back(breakpointsByUrl->getObject(scriptURL));
    1327             :     }
    1328             :     potentialBreakpoints.push_back(
    1329       26853 :         m_state->getObject(DebuggerAgentState::breakpointsByRegex));
    1330             :   }
    1331             :   protocol::DictionaryValue* breakpointsByScriptHash =
    1332       51676 :       m_state->getObject(DebuggerAgentState::breakpointsByScriptHash);
    1333       25838 :   if (breakpointsByScriptHash) {
    1334             :     potentialBreakpoints.push_back(
    1335          50 :         breakpointsByScriptHash->getObject(scriptRef->hash()));
    1336             :   }
    1337             :   protocol::DictionaryValue* breakpointHints =
    1338       51676 :       m_state->getObject(DebuggerAgentState::breakpointHints);
    1339       60847 :   for (auto breakpoints : potentialBreakpoints) {
    1340        9171 :     if (!breakpoints) continue;
    1341         255 :     for (size_t i = 0; i < breakpoints->size(); ++i) {
    1342          85 :       auto breakpointWithCondition = breakpoints->at(i);
    1343          85 :       String16 breakpointId = breakpointWithCondition.first;
    1344             : 
    1345             :       BreakpointType type;
    1346          85 :       String16 selector;
    1347          85 :       int lineNumber = 0;
    1348          85 :       int columnNumber = 0;
    1349             :       parseBreakpointId(breakpointId, &type, &selector, &lineNumber,
    1350          85 :                         &columnNumber);
    1351             : 
    1352          85 :       if (!matches(m_inspector, *scriptRef, type, selector)) continue;
    1353          85 :       String16 condition;
    1354          85 :       breakpointWithCondition.second->asString(&condition);
    1355          85 :       String16 hint;
    1356             :       bool hasHint =
    1357          85 :           breakpointHints && breakpointHints->getString(breakpointId, &hint);
    1358          85 :       if (hasHint) {
    1359          40 :         adjustBreakpointLocation(*scriptRef, hint, &lineNumber, &columnNumber);
    1360             :       }
    1361             :       std::unique_ptr<protocol::Debugger::Location> location =
    1362             :           setBreakpointImpl(breakpointId, scriptId, condition, lineNumber,
    1363          85 :                             columnNumber);
    1364          85 :       if (location)
    1365          90 :         m_frontend.breakpointResolved(breakpointId, std::move(location));
    1366             :     }
    1367       25838 :   }
    1368             : }
    1369             : 
    1370       49820 : void V8DebuggerAgentImpl::didPause(
    1371             :     int contextId, v8::Local<v8::Value> exception,
    1372             :     const std::vector<v8::debug::BreakpointId>& hitBreakpoints,
    1373             :     bool isPromiseRejection, bool isUncaught, bool isOOMBreak, bool isAssert) {
    1374       49820 :   v8::HandleScope handles(m_isolate);
    1375             : 
    1376       49820 :   std::vector<BreakReason> hitReasons;
    1377             : 
    1378       49820 :   if (isOOMBreak) {
    1379             :     hitReasons.push_back(
    1380           5 :         std::make_pair(protocol::Debugger::Paused::ReasonEnum::OOM, nullptr));
    1381       49815 :   } else if (isAssert) {
    1382             :     hitReasons.push_back(std::make_pair(
    1383          60 :         protocol::Debugger::Paused::ReasonEnum::Assert, nullptr));
    1384       49755 :   } else if (!exception.IsEmpty()) {
    1385        1736 :     InjectedScript* injectedScript = nullptr;
    1386        3472 :     m_session->findInjectedScript(contextId, injectedScript);
    1387        1736 :     if (injectedScript) {
    1388             :       String16 breakReason =
    1389             :           isPromiseRejection
    1390             :               ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection
    1391        1736 :               : protocol::Debugger::Paused::ReasonEnum::Exception;
    1392        1736 :       std::unique_ptr<protocol::Runtime::RemoteObject> obj;
    1393             :       injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false,
    1394        5208 :                                  &obj);
    1395             :       std::unique_ptr<protocol::DictionaryValue> breakAuxData;
    1396        1736 :       if (obj) {
    1397        3472 :         breakAuxData = obj->toValue();
    1398        3472 :         breakAuxData->setBoolean("uncaught", isUncaught);
    1399             :       } else {
    1400             :         breakAuxData = nullptr;
    1401             :       }
    1402             :       hitReasons.push_back(
    1403        1736 :           std::make_pair(breakReason, std::move(breakAuxData)));
    1404             :     }
    1405             :   }
    1406             : 
    1407             :   std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create();
    1408             : 
    1409      102043 :   for (const auto& id : hitBreakpoints) {
    1410             :     auto breakpointIterator = m_debuggerBreakpointIdToBreakpointId.find(id);
    1411        2403 :     if (breakpointIterator == m_debuggerBreakpointIdToBreakpointId.end()) {
    1412        2373 :       continue;
    1413             :     }
    1414        2298 :     const String16& breakpointId = breakpointIterator->second;
    1415             :     hitBreakpointIds->addItem(breakpointId);
    1416             :     BreakpointType type;
    1417        2298 :     parseBreakpointId(breakpointId, &type);
    1418        2298 :     if (type != BreakpointType::kDebugCommand) continue;
    1419             :     hitReasons.push_back(std::make_pair(
    1420          30 :         protocol::Debugger::Paused::ReasonEnum::DebugCommand, nullptr));
    1421             :   }
    1422             : 
    1423       50490 :   for (size_t i = 0; i < m_breakReason.size(); ++i) {
    1424       50155 :     hitReasons.push_back(std::move(m_breakReason[i]));
    1425             :   }
    1426       49820 :   clearBreakDetails();
    1427             : 
    1428       49820 :   String16 breakReason = protocol::Debugger::Paused::ReasonEnum::Other;
    1429             :   std::unique_ptr<protocol::DictionaryValue> breakAuxData;
    1430       99640 :   if (hitReasons.size() == 1) {
    1431        2146 :     breakReason = hitReasons[0].first;
    1432        2146 :     breakAuxData = std::move(hitReasons[0].second);
    1433       47674 :   } else if (hitReasons.size() > 1) {
    1434          20 :     breakReason = protocol::Debugger::Paused::ReasonEnum::Ambiguous;
    1435             :     std::unique_ptr<protocol::ListValue> reasons =
    1436          10 :         protocol::ListValue::create();
    1437          60 :     for (size_t i = 0; i < hitReasons.size(); ++i) {
    1438             :       std::unique_ptr<protocol::DictionaryValue> reason =
    1439          20 :           protocol::DictionaryValue::create();
    1440          80 :       reason->setString("reason", hitReasons[i].first);
    1441          40 :       if (hitReasons[i].second)
    1442          20 :         reason->setObject("auxData", std::move(hitReasons[i].second));
    1443          40 :       reasons->pushValue(std::move(reason));
    1444             :     }
    1445          20 :     breakAuxData = protocol::DictionaryValue::create();
    1446          30 :     breakAuxData->setArray("reasons", std::move(reasons));
    1447             :   }
    1448             : 
    1449       49820 :   std::unique_ptr<Array<CallFrame>> protocolCallFrames;
    1450       49820 :   Response response = currentCallFrames(&protocolCallFrames);
    1451       49820 :   if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create();
    1452             :   m_frontend.paused(std::move(protocolCallFrames), breakReason,
    1453             :                     std::move(breakAuxData), std::move(hitBreakpointIds),
    1454      398560 :                     currentAsyncStackTrace());
    1455       49820 : }
    1456             : 
    1457       49679 : void V8DebuggerAgentImpl::didContinue() {
    1458       49679 :   clearBreakDetails();
    1459       49679 :   m_frontend.resumed();
    1460       49679 : }
    1461             : 
    1462          65 : void V8DebuggerAgentImpl::breakProgram(
    1463             :     const String16& breakReason,
    1464         120 :     std::unique_ptr<protocol::DictionaryValue> data) {
    1465          75 :   if (!enabled() || m_skipAllPauses || !m_debugger->canBreakProgram()) return;
    1466             :   std::vector<BreakReason> currentScheduledReason;
    1467             :   currentScheduledReason.swap(m_breakReason);
    1468         120 :   pushBreakDetails(breakReason, std::move(data));
    1469             : 
    1470          65 :   int contextGroupId = m_session->contextGroupId();
    1471             :   int sessionId = m_session->sessionId();
    1472          60 :   V8InspectorImpl* inspector = m_inspector;
    1473          60 :   m_debugger->breakProgram(contextGroupId);
    1474             :   // Check that session and |this| are still around.
    1475          65 :   if (!inspector->sessionById(contextGroupId, sessionId)) return;
    1476          55 :   if (!enabled()) return;
    1477             : 
    1478             :   popBreakDetails();
    1479             :   m_breakReason.swap(currentScheduledReason);
    1480          55 :   if (!m_breakReason.empty()) {
    1481          10 :     m_debugger->setPauseOnNextStatement(true, m_session->contextGroupId());
    1482          55 :   }
    1483             : }
    1484             : 
    1485          55 : void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId,
    1486             :                                           int lineNumber, int columnNumber,
    1487             :                                           BreakpointSource source,
    1488             :                                           const String16& condition) {
    1489             :   String16 breakpointId = generateBreakpointId(
    1490             :       source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand
    1491             :                                              : BreakpointType::kMonitorCommand,
    1492          55 :       scriptId, lineNumber, columnNumber);
    1493          55 :   if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
    1494             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
    1495          55 :     return;
    1496             :   }
    1497             :   setBreakpointImpl(breakpointId, scriptId, condition, lineNumber,
    1498         110 :                     columnNumber);
    1499             : }
    1500             : 
    1501          50 : void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId,
    1502             :                                              int lineNumber, int columnNumber,
    1503             :                                              BreakpointSource source) {
    1504             :   String16 breakpointId = generateBreakpointId(
    1505             :       source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand
    1506             :                                              : BreakpointType::kMonitorCommand,
    1507          50 :       scriptId, lineNumber, columnNumber);
    1508          50 :   removeBreakpointImpl(breakpointId);
    1509          50 : }
    1510             : 
    1511           0 : void V8DebuggerAgentImpl::reset() {
    1512           0 :   if (!enabled()) return;
    1513             :   m_blackboxedPositions.clear();
    1514             :   resetBlackboxedStateCache();
    1515             :   m_scripts.clear();
    1516             :   m_breakpointIdToDebuggerBreakpointIds.clear();
    1517             : }
    1518             : 
    1519             : }  // namespace v8_inspector

Generated by: LCOV version 1.10