LCOV - code coverage report
Current view: top level - src/inspector - v8-debugger.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 473 498 95.0 %
Date: 2017-10-20 Functions: 66 74 89.2 %

          Line data    Source code
       1             : // Copyright 2016 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/inspector/v8-debugger.h"
       6             : 
       7             : #include "src/inspector/inspected-context.h"
       8             : #include "src/inspector/protocol/Protocol.h"
       9             : #include "src/inspector/string-util.h"
      10             : #include "src/inspector/v8-debugger-agent-impl.h"
      11             : #include "src/inspector/v8-inspector-impl.h"
      12             : #include "src/inspector/v8-inspector-session-impl.h"
      13             : #include "src/inspector/v8-internal-value-type.h"
      14             : #include "src/inspector/v8-runtime-agent-impl.h"
      15             : #include "src/inspector/v8-stack-trace-impl.h"
      16             : #include "src/inspector/v8-value-utils.h"
      17             : 
      18             : #include "include/v8-util.h"
      19             : 
      20             : namespace v8_inspector {
      21             : 
      22             : namespace {
      23             : 
      24             : static const int kMaxAsyncTaskStacks = 128 * 1024;
      25             : static const int kNoBreakpointId = 0;
      26             : 
      27       67176 : v8::MaybeLocal<v8::Array> collectionsEntries(v8::Local<v8::Context> context,
      28             :                                              v8::Local<v8::Value> value) {
      29       67176 :   v8::Isolate* isolate = context->GetIsolate();
      30             :   v8::Local<v8::Array> entries;
      31       67176 :   bool isKeyValue = false;
      32      134352 :   if (!v8::debug::EntriesPreview(isolate, value, &isKeyValue).ToLocal(&entries))
      33       66975 :     return v8::MaybeLocal<v8::Array>();
      34             : 
      35         201 :   v8::Local<v8::Array> wrappedEntries = v8::Array::New(isolate);
      36         201 :   CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0);
      37         201 :   if (!wrappedEntries->SetPrototype(context, v8::Null(isolate))
      38         402 :            .FromMaybe(false))
      39           0 :     return v8::MaybeLocal<v8::Array>();
      40       10389 :   for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) {
      41             :     v8::Local<v8::Value> item;
      42       20778 :     if (!entries->Get(context, i).ToLocal(&item)) continue;
      43             :     v8::Local<v8::Value> value;
      44       15507 :     if (isKeyValue && !entries->Get(context, i + 1).ToLocal(&value)) continue;
      45       10389 :     v8::Local<v8::Object> wrapper = v8::Object::New(isolate);
      46       20778 :     if (!wrapper->SetPrototype(context, v8::Null(isolate)).FromMaybe(false))
      47             :       continue;
      48             :     createDataProperty(
      49             :         context, wrapper,
      50       20778 :         toV8StringInternalized(isolate, isKeyValue ? "key" : "value"), item);
      51       10389 :     if (isKeyValue) {
      52             :       createDataProperty(context, wrapper,
      53       10236 :                          toV8StringInternalized(isolate, "value"), value);
      54             :     }
      55       10389 :     createDataProperty(context, wrappedEntries, wrappedEntries->Length(),
      56       10389 :                        wrapper);
      57             :   }
      58         201 :   if (!markArrayEntriesAsInternal(context, wrappedEntries,
      59         201 :                                   V8InternalValueType::kEntry)) {
      60           0 :     return v8::MaybeLocal<v8::Array>();
      61             :   }
      62         201 :   return wrappedEntries;
      63             : }
      64             : 
      65          75 : v8::MaybeLocal<v8::Object> buildLocation(v8::Local<v8::Context> context,
      66             :                                          int scriptId, int lineNumber,
      67             :                                          int columnNumber) {
      68          75 :   if (scriptId == v8::UnboundScript::kNoScriptId)
      69           5 :     return v8::MaybeLocal<v8::Object>();
      70          70 :   if (lineNumber == v8::Function::kLineOffsetNotFound ||
      71             :       columnNumber == v8::Function::kLineOffsetNotFound) {
      72           0 :     return v8::MaybeLocal<v8::Object>();
      73             :   }
      74          70 :   v8::Isolate* isolate = context->GetIsolate();
      75          70 :   v8::Local<v8::Object> location = v8::Object::New(isolate);
      76         140 :   if (!location->SetPrototype(context, v8::Null(isolate)).FromMaybe(false)) {
      77           0 :     return v8::MaybeLocal<v8::Object>();
      78             :   }
      79          70 :   if (!createDataProperty(context, location,
      80             :                           toV8StringInternalized(isolate, "scriptId"),
      81         280 :                           toV8String(isolate, String16::fromInteger(scriptId)))
      82         140 :            .FromMaybe(false)) {
      83           0 :     return v8::MaybeLocal<v8::Object>();
      84             :   }
      85          70 :   if (!createDataProperty(context, location,
      86             :                           toV8StringInternalized(isolate, "lineNumber"),
      87         210 :                           v8::Integer::New(isolate, lineNumber))
      88         140 :            .FromMaybe(false)) {
      89           0 :     return v8::MaybeLocal<v8::Object>();
      90             :   }
      91          70 :   if (!createDataProperty(context, location,
      92             :                           toV8StringInternalized(isolate, "columnNumber"),
      93         210 :                           v8::Integer::New(isolate, columnNumber))
      94         140 :            .FromMaybe(false)) {
      95           0 :     return v8::MaybeLocal<v8::Object>();
      96             :   }
      97          70 :   if (!markAsInternal(context, location, V8InternalValueType::kLocation)) {
      98           0 :     return v8::MaybeLocal<v8::Object>();
      99             :   }
     100          70 :   return location;
     101             : }
     102             : 
     103          45 : v8::MaybeLocal<v8::Object> generatorObjectLocation(
     104             :     v8::Local<v8::Context> context, v8::Local<v8::Value> value) {
     105          45 :   if (!value->IsGeneratorObject()) return v8::MaybeLocal<v8::Object>();
     106             :   v8::Local<v8::debug::GeneratorObject> generatorObject =
     107          45 :       v8::debug::GeneratorObject::Cast(value);
     108          45 :   if (!generatorObject->IsSuspended()) {
     109          10 :     v8::Local<v8::Function> func = generatorObject->Function();
     110             :     return buildLocation(context, func->ScriptId(), func->GetScriptLineNumber(),
     111          10 :                          func->GetScriptColumnNumber());
     112             :   }
     113             :   v8::Local<v8::debug::Script> script;
     114          70 :   if (!generatorObject->Script().ToLocal(&script))
     115           0 :     return v8::MaybeLocal<v8::Object>();
     116          35 :   v8::debug::Location suspendedLocation = generatorObject->SuspendedLocation();
     117             :   return buildLocation(context, script->Id(), suspendedLocation.GetLineNumber(),
     118          35 :                        suspendedLocation.GetColumnNumber());
     119             : }
     120             : 
     121             : template <typename Map>
     122        1410 : void cleanupExpiredWeakPointers(Map& map) {
     123       14120 :   for (auto it = map.begin(); it != map.end();) {
     124       11300 :     if (it->second.expired()) {
     125             :       it = map.erase(it);
     126             :     } else {
     127             :       ++it;
     128             :     }
     129             :   }
     130        1410 : }
     131             : 
     132          65 : class MatchPrototypePredicate : public v8::debug::QueryObjectPredicate {
     133             :  public:
     134             :   MatchPrototypePredicate(V8InspectorImpl* inspector,
     135             :                           v8::Local<v8::Context> context,
     136             :                           v8::Local<v8::Object> prototype)
     137          65 :       : m_inspector(inspector), m_context(context), m_prototype(prototype) {}
     138             : 
     139      221575 :   bool Filter(v8::Local<v8::Object> object) override {
     140      221575 :     v8::Local<v8::Context> objectContext = object->CreationContext();
     141      221575 :     if (objectContext != m_context) return false;
     142       61615 :     if (!m_inspector->client()->isInspectableHeapObject(object)) return false;
     143             :     // Get prototype chain for current object until first visited prototype.
     144      179035 :     for (v8::Local<v8::Value> prototype = object->GetPrototype();
     145             :          prototype->IsObject();
     146             :          prototype = prototype.As<v8::Object>()->GetPrototype()) {
     147      117510 :       if (m_prototype == prototype) return true;
     148             :     }
     149             :     return false;
     150             :   }
     151             : 
     152             :  private:
     153             :   V8InspectorImpl* m_inspector;
     154             :   v8::Local<v8::Context> m_context;
     155             :   v8::Local<v8::Value> m_prototype;
     156             : };
     157             : 
     158             : }  // namespace
     159             : 
     160        3261 : V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector)
     161             :     : m_isolate(isolate),
     162             :       m_inspector(inspector),
     163             :       m_enableCount(0),
     164             :       m_ignoreScriptParsedEventsCounter(0),
     165             :       m_continueToLocationBreakpointId(kNoBreakpointId),
     166             :       m_maxAsyncCallStacks(kMaxAsyncTaskStacks),
     167             :       m_maxAsyncCallStackDepth(0),
     168             :       m_pauseOnExceptionsState(v8::debug::NoBreakOnException),
     169       22827 :       m_wasmTranslation(isolate) {}
     170             : 
     171       13044 : V8Debugger::~V8Debugger() {}
     172             : 
     173        3126 : void V8Debugger::enable() {
     174        3176 :   if (m_enableCount++) return;
     175        3076 :   v8::HandleScope scope(m_isolate);
     176        3076 :   v8::debug::SetDebugDelegate(m_isolate, this);
     177             :   v8::debug::SetOutOfMemoryCallback(m_isolate, &V8Debugger::v8OOMCallback,
     178        3076 :                                     this);
     179        3076 :   v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException);
     180        3076 :   m_pauseOnExceptionsState = v8::debug::NoBreakOnException;
     181             : }
     182             : 
     183        3126 : void V8Debugger::disable() {
     184        6252 :   if (--m_enableCount) return;
     185        3076 :   clearContinueToLocation();
     186        3076 :   allAsyncTasksCanceled();
     187        3076 :   m_taskWithScheduledBreak = nullptr;
     188        3076 :   m_wasmTranslation.Clear();
     189        3076 :   v8::debug::SetDebugDelegate(m_isolate, nullptr);
     190        3076 :   v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr);
     191        3076 :   m_isolate->RestoreOriginalHeapLimit();
     192             : }
     193             : 
     194      107870 : bool V8Debugger::isPausedInContextGroup(int contextGroupId) const {
     195      107870 :   return isPaused() && m_pausedContextGroupId == contextGroupId;
     196             : }
     197             : 
     198      140636 : bool V8Debugger::enabled() const { return m_enableCount > 0; }
     199             : 
     200        3126 : void V8Debugger::getCompiledScripts(
     201             :     int contextGroupId,
     202             :     std::vector<std::unique_ptr<V8DebuggerScript>>& result) {
     203        3126 :   v8::HandleScope scope(m_isolate);
     204        6252 :   v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate);
     205        3126 :   v8::debug::GetLoadedScripts(m_isolate, scripts);
     206       22590 :   for (size_t i = 0; i < scripts.Size(); ++i) {
     207        8169 :     v8::Local<v8::debug::Script> script = scripts.Get(i);
     208        8169 :     if (!script->WasCompiled()) continue;
     209        8149 :     if (script->IsEmbedded()) {
     210          10 :       result.push_back(V8DebuggerScript::Create(m_isolate, script, false));
     211           5 :       continue;
     212             :     }
     213             :     int contextId;
     214       16288 :     if (!script->ContextId().To(&contextId)) continue;
     215        8144 :     if (m_inspector->contextGroupId(contextId) != contextGroupId) continue;
     216       16038 :     result.push_back(V8DebuggerScript::Create(m_isolate, script, false));
     217        3126 :   }
     218        3126 : }
     219             : 
     220        6354 : void V8Debugger::setBreakpointsActive(bool active) {
     221        6354 :   if (!enabled()) {
     222           0 :     UNREACHABLE();
     223             :     return;
     224             :   }
     225        6354 :   m_breakpointsActiveCount += active ? 1 : -1;
     226        6354 :   v8::debug::SetBreakPointsActive(m_isolate, m_breakpointsActiveCount);
     227        6354 : }
     228             : 
     229      133562 : v8::debug::ExceptionBreakState V8Debugger::getPauseOnExceptionsState() {
     230             :   DCHECK(enabled());
     231      133562 :   return m_pauseOnExceptionsState;
     232             : }
     233             : 
     234        4909 : void V8Debugger::setPauseOnExceptionsState(
     235             :     v8::debug::ExceptionBreakState pauseOnExceptionsState) {
     236             :   DCHECK(enabled());
     237        9818 :   if (m_pauseOnExceptionsState == pauseOnExceptionsState) return;
     238        3885 :   v8::debug::ChangeBreakOnException(m_isolate, pauseOnExceptionsState);
     239        3885 :   m_pauseOnExceptionsState = pauseOnExceptionsState;
     240             : }
     241             : 
     242         315 : void V8Debugger::setPauseOnNextStatement(bool pause, int targetContextGroupId) {
     243         315 :   if (isPaused()) return;
     244             :   DCHECK(targetContextGroupId);
     245         315 :   if (!pause && m_targetContextGroupId &&
     246             :       m_targetContextGroupId != targetContextGroupId) {
     247             :     return;
     248             :   }
     249         315 :   m_targetContextGroupId = targetContextGroupId;
     250         315 :   m_breakRequested = pause;
     251         315 :   if (pause)
     252         295 :     v8::debug::DebugBreak(m_isolate);
     253             :   else
     254          20 :     v8::debug::CancelDebugBreak(m_isolate);
     255             : }
     256             : 
     257          65 : bool V8Debugger::canBreakProgram() {
     258         105 :   return !v8::debug::AllFramesOnStackAreBlackboxed(m_isolate);
     259             : }
     260             : 
     261          60 : void V8Debugger::breakProgram(int targetContextGroupId) {
     262             :   DCHECK(canBreakProgram());
     263             :   // Don't allow nested breaks.
     264         120 :   if (isPaused()) return;
     265             :   DCHECK(targetContextGroupId);
     266          60 :   m_targetContextGroupId = targetContextGroupId;
     267          60 :   v8::debug::BreakRightNow(m_isolate);
     268             : }
     269             : 
     270        1726 : void V8Debugger::continueProgram(int targetContextGroupId) {
     271       43173 :   if (m_pausedContextGroupId != targetContextGroupId) return;
     272       41447 :   if (isPaused()) m_inspector->client()->quitMessageLoopOnPause();
     273             : }
     274             : 
     275         120 : void V8Debugger::breakProgramOnAssert(int targetContextGroupId) {
     276          80 :   if (!enabled()) return;
     277          60 :   if (m_pauseOnExceptionsState == v8::debug::NoBreakOnException) return;
     278             :   // Don't allow nested breaks.
     279          40 :   if (isPaused()) return;
     280          40 :   if (!canBreakProgram()) return;
     281             :   DCHECK(targetContextGroupId);
     282          35 :   m_targetContextGroupId = targetContextGroupId;
     283          35 :   m_scheduledAssertBreak = true;
     284          35 :   v8::debug::BreakRightNow(m_isolate);
     285             : }
     286             : 
     287       31732 : void V8Debugger::stepIntoStatement(int targetContextGroupId) {
     288             :   DCHECK(isPaused());
     289             :   DCHECK(targetContextGroupId);
     290       31732 :   m_targetContextGroupId = targetContextGroupId;
     291       31732 :   v8::debug::PrepareStep(m_isolate, v8::debug::StepIn);
     292             :   continueProgram(targetContextGroupId);
     293       31732 : }
     294             : 
     295        7489 : void V8Debugger::stepOverStatement(int targetContextGroupId) {
     296             :   DCHECK(isPaused());
     297             :   DCHECK(targetContextGroupId);
     298        7489 :   m_targetContextGroupId = targetContextGroupId;
     299        7489 :   v8::debug::PrepareStep(m_isolate, v8::debug::StepNext);
     300             :   continueProgram(targetContextGroupId);
     301        7489 : }
     302             : 
     303         440 : void V8Debugger::stepOutOfFunction(int targetContextGroupId) {
     304             :   DCHECK(isPaused());
     305             :   DCHECK(targetContextGroupId);
     306         440 :   m_targetContextGroupId = targetContextGroupId;
     307         440 :   v8::debug::PrepareStep(m_isolate, v8::debug::StepOut);
     308             :   continueProgram(targetContextGroupId);
     309         440 : }
     310             : 
     311          75 : void V8Debugger::scheduleStepIntoAsync(
     312             :     std::unique_ptr<ScheduleStepIntoAsyncCallback> callback,
     313             :     int targetContextGroupId) {
     314             :   DCHECK(isPaused());
     315             :   DCHECK(targetContextGroupId);
     316          75 :   if (m_stepIntoAsyncCallback) {
     317             :     m_stepIntoAsyncCallback->sendFailure(Response::Error(
     318          15 :         "Current scheduled step into async was overriden with new one."));
     319             :   }
     320          75 :   m_targetContextGroupId = targetContextGroupId;
     321             :   m_stepIntoAsyncCallback = std::move(callback);
     322          75 : }
     323             : 
     324          60 : Response V8Debugger::continueToLocation(
     325             :     int targetContextGroupId, V8DebuggerScript* script,
     326             :     std::unique_ptr<protocol::Debugger::Location> location,
     327             :     const String16& targetCallFrames) {
     328             :   DCHECK(isPaused());
     329             :   DCHECK(targetContextGroupId);
     330          60 :   m_targetContextGroupId = targetContextGroupId;
     331             :   v8::debug::Location v8Location(location->getLineNumber(),
     332          60 :                                  location->getColumnNumber(0));
     333         120 :   if (script->setBreakpoint(String16(), &v8Location,
     334         120 :                             &m_continueToLocationBreakpointId)) {
     335          60 :     m_continueToLocationTargetCallFrames = targetCallFrames;
     336         120 :     if (m_continueToLocationTargetCallFrames !=
     337             :         protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any) {
     338          30 :       m_continueToLocationStack = captureStackTrace(true);
     339             :       DCHECK(m_continueToLocationStack);
     340             :     }
     341             :     continueProgram(targetContextGroupId);
     342             :     // TODO(kozyatinskiy): Return actual line and column number.
     343          60 :     return Response::OK();
     344             :   } else {
     345           0 :     return Response::Error("Cannot continue to specified location");
     346             :   }
     347             : }
     348             : 
     349          90 : bool V8Debugger::shouldContinueToCurrentLocation() {
     350         180 :   if (m_continueToLocationTargetCallFrames ==
     351             :       protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any) {
     352             :     return true;
     353             :   }
     354          45 :   std::unique_ptr<V8StackTraceImpl> currentStack = captureStackTrace(true);
     355          90 :   if (m_continueToLocationTargetCallFrames ==
     356             :       protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Current) {
     357             :     return m_continueToLocationStack->isEqualIgnoringTopFrame(
     358          45 :         currentStack.get());
     359             :   }
     360             :   return true;
     361             : }
     362             : 
     363       52796 : void V8Debugger::clearContinueToLocation() {
     364      105592 :   if (m_continueToLocationBreakpointId == kNoBreakpointId) return;
     365          60 :   v8::debug::RemoveBreakpoint(m_isolate, m_continueToLocationBreakpointId);
     366          60 :   m_continueToLocationBreakpointId = kNoBreakpointId;
     367         120 :   m_continueToLocationTargetCallFrames = String16();
     368             :   m_continueToLocationStack.reset();
     369             : }
     370             : 
     371       49780 : void V8Debugger::handleProgramBreak(
     372             :     v8::Local<v8::Context> pausedContext, v8::Local<v8::Value> exception,
     373       49750 :     const std::vector<v8::debug::BreakpointId>& breakpointIds,
     374       49780 :     bool isPromiseRejection, bool isUncaught) {
     375             :   // Don't allow nested breaks.
     376       49840 :   if (isPaused()) return;
     377             : 
     378       99500 :   int contextGroupId = m_inspector->contextGroupId(pausedContext);
     379       49780 :   if (m_targetContextGroupId && contextGroupId != m_targetContextGroupId) {
     380          20 :     v8::debug::PrepareStep(m_isolate, v8::debug::StepOut);
     381          20 :     return;
     382             :   }
     383       49760 :   m_targetContextGroupId = 0;
     384       49760 :   if (m_stepIntoAsyncCallback) {
     385             :     m_stepIntoAsyncCallback->sendFailure(
     386          30 :         Response::Error("No async tasks were scheduled before pause."));
     387             :     m_stepIntoAsyncCallback.reset();
     388             :   }
     389       49760 :   m_breakRequested = false;
     390             : 
     391       49760 :   bool scheduledOOMBreak = m_scheduledOOMBreak;
     392       49760 :   bool scheduledAssertBreak = m_scheduledAssertBreak;
     393       49760 :   bool hasAgents = false;
     394             :   m_inspector->forEachSession(
     395             :       contextGroupId,
     396       49870 :       [&scheduledOOMBreak, &hasAgents](V8InspectorSessionImpl* session) {
     397       99740 :         if (session->debuggerAgent()->acceptsPause(scheduledOOMBreak))
     398       49845 :           hasAgents = true;
     399      149390 :       });
     400       49760 :   if (!hasAgents) return;
     401             : 
     402       52028 :   if (breakpointIds.size() == 1 &&
     403        2278 :       breakpointIds[0] == m_continueToLocationBreakpointId) {
     404             :     v8::Context::Scope contextScope(pausedContext);
     405          90 :     if (!shouldContinueToCurrentLocation()) return;
     406             :   }
     407       49720 :   clearContinueToLocation();
     408             : 
     409             :   DCHECK(contextGroupId);
     410       49720 :   m_pausedContextGroupId = contextGroupId;
     411             : 
     412             :   m_inspector->forEachSession(
     413             :       contextGroupId, [&pausedContext, &exception, &breakpointIds,
     414             :                        &isPromiseRejection, &isUncaught, &scheduledOOMBreak,
     415       49825 :                        &scheduledAssertBreak](V8InspectorSessionImpl* session) {
     416       99650 :         if (session->debuggerAgent()->acceptsPause(scheduledOOMBreak)) {
     417             :           session->debuggerAgent()->didPause(
     418             :               InspectedContext::contextId(pausedContext), exception,
     419             :               breakpointIds, isPromiseRejection, isUncaught, scheduledOOMBreak,
     420       99630 :               scheduledAssertBreak);
     421             :         }
     422      149265 :       });
     423             :   {
     424             :     v8::Context::Scope scope(pausedContext);
     425       49720 :     v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
     426       99440 :     CHECK(!context.IsEmpty() &&
     427             :           context != v8::debug::GetDebugContext(m_isolate));
     428       99440 :     m_inspector->client()->runMessageLoopOnPause(contextGroupId);
     429       49720 :     m_pausedContextGroupId = 0;
     430             :   }
     431             :   m_inspector->forEachSession(contextGroupId,
     432             :                               [](V8InspectorSessionImpl* session) {
     433       49825 :                                 if (session->debuggerAgent()->enabled())
     434       49679 :                                   session->debuggerAgent()->didContinue();
     435       99440 :                               });
     436             : 
     437       49720 :   if (m_scheduledOOMBreak) m_isolate->RestoreOriginalHeapLimit();
     438       49720 :   m_scheduledOOMBreak = false;
     439       49720 :   m_scheduledAssertBreak = false;
     440             : }
     441             : 
     442           5 : void V8Debugger::v8OOMCallback(void* data) {
     443             :   V8Debugger* thisPtr = static_cast<V8Debugger*>(data);
     444           5 :   thisPtr->m_isolate->IncreaseHeapLimitForDebugging();
     445           5 :   thisPtr->m_scheduledOOMBreak = true;
     446           5 :   v8::Local<v8::Context> context = thisPtr->m_isolate->GetEnteredContext();
     447             :   DCHECK(!context.IsEmpty());
     448             :   thisPtr->setPauseOnNextStatement(
     449           5 :       true, thisPtr->m_inspector->contextGroupId(context));
     450           5 : }
     451             : 
     452       17872 : void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script,
     453             :                                 bool is_live_edited, bool has_compile_error) {
     454             :   int contextId;
     455       53616 :   if (!script->ContextId().To(&contextId)) return;
     456       17827 :   if (script->IsWasm()) {
     457          49 :     WasmTranslation* wasmTranslation = &m_wasmTranslation;
     458             :     m_inspector->forEachSession(
     459             :         m_inspector->contextGroupId(contextId),
     460          49 :         [&script, &wasmTranslation](V8InspectorSessionImpl* session) {
     461          98 :           if (!session->debuggerAgent()->enabled()) return;
     462             :           wasmTranslation->AddScript(script.As<v8::debug::WasmScript>(),
     463          98 :                                      session->debuggerAgent());
     464          98 :         });
     465       17778 :   } else if (m_ignoreScriptParsedEventsCounter == 0) {
     466       17753 :     v8::Isolate* isolate = m_isolate;
     467             :     m_inspector->forEachSession(
     468             :         m_inspector->contextGroupId(contextId),
     469             :         [&isolate, &script, &has_compile_error,
     470       17868 :          &is_live_edited](V8InspectorSessionImpl* session) {
     471       35736 :           if (!session->debuggerAgent()->enabled()) return;
     472             :           session->debuggerAgent()->didParseSource(
     473             :               V8DebuggerScript::Create(isolate, script, is_live_edited),
     474       53589 :               !has_compile_error);
     475       35506 :         });
     476             :   }
     477             : }
     478             : 
     479       48044 : void V8Debugger::BreakProgramRequested(
     480             :     v8::Local<v8::Context> pausedContext, v8::Local<v8::Object>,
     481             :     v8::Local<v8::Value>,
     482             :     const std::vector<v8::debug::BreakpointId>& break_points_hit) {
     483       48044 :   handleProgramBreak(pausedContext, v8::Local<v8::Value>(), break_points_hit);
     484       48044 : }
     485             : 
     486        1736 : void V8Debugger::ExceptionThrown(v8::Local<v8::Context> pausedContext,
     487             :                                  v8::Local<v8::Object>,
     488             :                                  v8::Local<v8::Value> exception,
     489             :                                  v8::Local<v8::Value> promise,
     490             :                                  bool isUncaught) {
     491        1736 :   bool isPromiseRejection = promise->IsPromise();
     492             :   std::vector<v8::debug::BreakpointId> break_points_hit;
     493             :   handleProgramBreak(pausedContext, exception, break_points_hit,
     494        1736 :                      isPromiseRejection, isUncaught);
     495        1736 : }
     496             : 
     497       11626 : bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
     498             :                                       const v8::debug::Location& start,
     499             :                                       const v8::debug::Location& end) {
     500             :   int contextId;
     501       23252 :   if (!script->ContextId().To(&contextId)) return false;
     502       11621 :   bool hasAgents = false;
     503       11621 :   bool allBlackboxed = true;
     504       11621 :   String16 scriptId = String16::fromInteger(script->Id());
     505             :   m_inspector->forEachSession(
     506             :       m_inspector->contextGroupId(contextId),
     507             :       [&hasAgents, &allBlackboxed, &scriptId, &start,
     508       11686 :        &end](V8InspectorSessionImpl* session) {
     509       11686 :         V8DebuggerAgentImpl* agent = session->debuggerAgent();
     510       23372 :         if (!agent->enabled()) return;
     511       11681 :         hasAgents = true;
     512       11681 :         allBlackboxed &= agent->isFunctionBlackboxed(scriptId, start, end);
     513       23242 :       });
     514       11621 :   return hasAgents && allBlackboxed;
     515             : }
     516             : 
     517      116959 : void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
     518             :                                       int id, int parentId,
     519             :                                       bool createdByUser) {
     520             :   // Async task events from Promises are given misaligned pointers to prevent
     521             :   // from overlapping with other Blink task identifiers.
     522      116959 :   void* task = reinterpret_cast<void*>(id * 2 + 1);
     523             :   void* parentTask =
     524      116959 :       parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr;
     525      116959 :   switch (type) {
     526             :     case v8::debug::kDebugPromiseCreated:
     527       42579 :       asyncTaskCreatedForStack(task, parentTask);
     528       42579 :       if (createdByUser && parentTask) asyncTaskCandidateForStepping(task);
     529             :       break;
     530             :     case v8::debug::kDebugEnqueueAsyncFunction:
     531        9162 :       asyncTaskScheduledForStack("async function", task, true);
     532        4581 :       break;
     533             :     case v8::debug::kDebugEnqueuePromiseResolve:
     534       76334 :       asyncTaskScheduledForStack("Promise.resolve", task, true);
     535       38167 :       break;
     536             :     case v8::debug::kDebugEnqueuePromiseReject:
     537        9302 :       asyncTaskScheduledForStack("Promise.reject", task, true);
     538        4651 :       break;
     539             :     case v8::debug::kDebugWillHandle:
     540       13493 :       asyncTaskStartedForStack(task);
     541             :       asyncTaskStartedForStepping(task);
     542             :       break;
     543             :     case v8::debug::kDebugDidHandle:
     544       13488 :       asyncTaskFinishedForStack(task);
     545             :       asyncTaskFinishedForStepping(task);
     546             :       break;
     547             :   }
     548      116959 : }
     549             : 
     550      128194 : std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncParent() {
     551             :   // TODO(kozyatinskiy): implement creation chain as parent without hack.
     552      128194 :   if (!m_currentAsyncCreation.empty() && m_currentAsyncCreation.back()) {
     553             :     return m_currentAsyncCreation.back();
     554             :   }
     555      124499 :   return m_currentAsyncParent.empty() ? nullptr : m_currentAsyncParent.back();
     556             : }
     557             : 
     558       78575 : std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncCreation() {
     559       78575 :   return nullptr;
     560             : }
     561             : 
     562          70 : v8::MaybeLocal<v8::Value> V8Debugger::getTargetScopes(
     563             :     v8::Local<v8::Context> context, v8::Local<v8::Value> value,
     564             :     ScopeTargetKind kind) {
     565             :   v8::Local<v8::Value> scopesValue;
     566             :   std::unique_ptr<v8::debug::ScopeIterator> iterator;
     567          70 :   switch (kind) {
     568             :     case FUNCTION:
     569          50 :       iterator = v8::debug::ScopeIterator::CreateForFunction(
     570             :           m_isolate, v8::Local<v8::Function>::Cast(value));
     571          85 :       break;
     572             :     case GENERATOR:
     573             :       v8::Local<v8::debug::GeneratorObject> generatorObject =
     574          45 :           v8::debug::GeneratorObject::Cast(value);
     575          45 :       if (!generatorObject->IsSuspended()) return v8::MaybeLocal<v8::Value>();
     576             : 
     577          70 :       iterator = v8::debug::ScopeIterator::CreateForGeneratorObject(
     578             :           m_isolate, v8::Local<v8::Object>::Cast(value));
     579          35 :       break;
     580             :   }
     581          60 :   if (!iterator) return v8::MaybeLocal<v8::Value>();
     582          60 :   v8::Local<v8::Array> result = v8::Array::New(m_isolate);
     583         180 :   if (!result->SetPrototype(context, v8::Null(m_isolate)).FromMaybe(false)) {
     584           0 :     return v8::MaybeLocal<v8::Value>();
     585             :   }
     586             : 
     587         110 :   for (; !iterator->Done(); iterator->Advance()) {
     588         110 :     v8::Local<v8::Object> scope = v8::Object::New(m_isolate);
     589         110 :     if (!markAsInternal(context, scope, V8InternalValueType::kScope)) {
     590           0 :       return v8::MaybeLocal<v8::Value>();
     591             :     }
     592         110 :     String16 type = v8_inspector::scopeType(iterator->GetType());
     593         110 :     String16 name;
     594         110 :     v8::Local<v8::Function> closure = iterator->GetFunction();
     595         110 :     if (!closure.IsEmpty()) {
     596         100 :       name = toProtocolStringWithTypeCheck(closure->GetDebugName());
     597             :     }
     598         110 :     v8::Local<v8::Object> object = iterator->GetObject();
     599             :     createDataProperty(context, scope,
     600             :                        toV8StringInternalized(m_isolate, "type"),
     601         330 :                        toV8String(m_isolate, type));
     602             :     createDataProperty(context, scope,
     603             :                        toV8StringInternalized(m_isolate, "name"),
     604         330 :                        toV8String(m_isolate, name));
     605             :     createDataProperty(context, scope,
     606         220 :                        toV8StringInternalized(m_isolate, "object"), object);
     607         110 :     createDataProperty(context, result, result->Length(), scope);
     608             :   }
     609          60 :   if (!markAsInternal(context, v8::Local<v8::Array>::Cast(result),
     610          60 :                       V8InternalValueType::kScopeList))
     611           0 :     return v8::MaybeLocal<v8::Value>();
     612          60 :   return result;
     613             : }
     614             : 
     615           0 : v8::MaybeLocal<v8::Value> V8Debugger::functionScopes(
     616             :     v8::Local<v8::Context> context, v8::Local<v8::Function> function) {
     617          25 :   return getTargetScopes(context, function, FUNCTION);
     618             : }
     619             : 
     620           0 : v8::MaybeLocal<v8::Value> V8Debugger::generatorScopes(
     621             :     v8::Local<v8::Context> context, v8::Local<v8::Value> generator) {
     622          45 :   return getTargetScopes(context, generator, GENERATOR);
     623             : }
     624             : 
     625       67176 : v8::MaybeLocal<v8::Array> V8Debugger::internalProperties(
     626             :     v8::Local<v8::Context> context, v8::Local<v8::Value> value) {
     627             :   v8::Local<v8::Array> properties;
     628      134352 :   if (!v8::debug::GetInternalProperties(m_isolate, value).ToLocal(&properties))
     629           0 :     return v8::MaybeLocal<v8::Array>();
     630       67176 :   if (value->IsFunction()) {
     631             :     v8::Local<v8::Function> function = value.As<v8::Function>();
     632             :     v8::Local<v8::Object> location;
     633          30 :     if (buildLocation(context, function->ScriptId(),
     634             :                       function->GetScriptLineNumber(),
     635          30 :                       function->GetScriptColumnNumber())
     636          30 :             .ToLocal(&location)) {
     637             :       createDataProperty(
     638          25 :           context, properties, properties->Length(),
     639          50 :           toV8StringInternalized(m_isolate, "[[FunctionLocation]]"));
     640          25 :       createDataProperty(context, properties, properties->Length(), location);
     641             :     }
     642          30 :     if (function->IsGeneratorFunction()) {
     643           5 :       createDataProperty(context, properties, properties->Length(),
     644          10 :                          toV8StringInternalized(m_isolate, "[[IsGenerator]]"));
     645           5 :       createDataProperty(context, properties, properties->Length(),
     646          10 :                          v8::True(m_isolate));
     647             :     }
     648             :   }
     649             :   v8::Local<v8::Array> entries;
     650      134352 :   if (collectionsEntries(context, value).ToLocal(&entries)) {
     651         201 :     createDataProperty(context, properties, properties->Length(),
     652         402 :                        toV8StringInternalized(m_isolate, "[[Entries]]"));
     653         201 :     createDataProperty(context, properties, properties->Length(), entries);
     654             :   }
     655       67176 :   if (value->IsGeneratorObject()) {
     656             :     v8::Local<v8::Object> location;
     657          90 :     if (generatorObjectLocation(context, value).ToLocal(&location)) {
     658             :       createDataProperty(
     659          45 :           context, properties, properties->Length(),
     660          90 :           toV8StringInternalized(m_isolate, "[[GeneratorLocation]]"));
     661          45 :       createDataProperty(context, properties, properties->Length(), location);
     662             :     }
     663             :     v8::Local<v8::Value> scopes;
     664          45 :     if (generatorScopes(context, value).ToLocal(&scopes)) {
     665          35 :       createDataProperty(context, properties, properties->Length(),
     666          70 :                          toV8StringInternalized(m_isolate, "[[Scopes]]"));
     667          35 :       createDataProperty(context, properties, properties->Length(), scopes);
     668             :     }
     669             :   }
     670       67176 :   if (value->IsFunction()) {
     671             :     v8::Local<v8::Function> function = value.As<v8::Function>();
     672          30 :     v8::Local<v8::Value> boundFunction = function->GetBoundFunction();
     673             :     v8::Local<v8::Value> scopes;
     674          55 :     if (boundFunction->IsUndefined() &&
     675             :         functionScopes(context, function).ToLocal(&scopes)) {
     676          25 :       createDataProperty(context, properties, properties->Length(),
     677          50 :                          toV8StringInternalized(m_isolate, "[[Scopes]]"));
     678          25 :       createDataProperty(context, properties, properties->Length(), scopes);
     679             :     }
     680             :   }
     681       67176 :   return properties;
     682             : }
     683             : 
     684          65 : v8::Local<v8::Array> V8Debugger::queryObjects(v8::Local<v8::Context> context,
     685             :                                               v8::Local<v8::Object> prototype) {
     686          65 :   v8::Isolate* isolate = context->GetIsolate();
     687             :   v8::PersistentValueVector<v8::Object> v8Objects(isolate);
     688         130 :   MatchPrototypePredicate predicate(m_inspector, context, prototype);
     689          65 :   v8::debug::QueryObjects(context, &predicate, &v8Objects);
     690             : 
     691             :   v8::MicrotasksScope microtasksScope(isolate,
     692         130 :                                       v8::MicrotasksScope::kDoNotRunMicrotasks);
     693             :   v8::Local<v8::Array> resultArray = v8::Array::New(
     694         130 :       m_inspector->isolate(), static_cast<int>(v8Objects.Size()));
     695         300 :   for (size_t i = 0; i < v8Objects.Size(); ++i) {
     696             :     createDataProperty(context, resultArray, static_cast<int>(i),
     697         170 :                        v8Objects.Get(i));
     698             :   }
     699         130 :   return resultArray;
     700             : }
     701             : 
     702         275 : std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace(
     703             :     v8::Local<v8::StackTrace> v8StackTrace) {
     704             :   return V8StackTraceImpl::create(this, currentContextGroupId(), v8StackTrace,
     705         275 :                                   V8StackTraceImpl::maxCallStackSizeToCapture);
     706             : }
     707             : 
     708        3356 : void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) {
     709        3356 :   if (depth <= 0)
     710             :     m_maxAsyncCallStackDepthMap.erase(agent);
     711             :   else
     712         190 :     m_maxAsyncCallStackDepthMap[agent] = depth;
     713             : 
     714             :   int maxAsyncCallStackDepth = 0;
     715        6902 :   for (const auto& pair : m_maxAsyncCallStackDepthMap) {
     716         190 :     if (pair.second > maxAsyncCallStackDepth)
     717             :       maxAsyncCallStackDepth = pair.second;
     718             :   }
     719             : 
     720        6712 :   if (m_maxAsyncCallStackDepth == maxAsyncCallStackDepth) return;
     721             :   // TODO(dgozman): ideally, this should be per context group.
     722         280 :   m_maxAsyncCallStackDepth = maxAsyncCallStackDepth;
     723         280 :   m_inspector->client()->maxAsyncCallStackDepthChanged(
     724         280 :       m_maxAsyncCallStackDepth);
     725         280 :   if (!maxAsyncCallStackDepth) allAsyncTasksCanceled();
     726             : }
     727             : 
     728       42579 : void V8Debugger::asyncTaskCreatedForStack(void* task, void* parentTask) {
     729       62902 :   if (!m_maxAsyncCallStackDepth) return;
     730       25966 :   if (parentTask) m_parentTask[task] = parentTask;
     731       22256 :   v8::HandleScope scope(m_isolate);
     732             :   std::shared_ptr<AsyncStackTrace> asyncCreation =
     733             :       AsyncStackTrace::capture(this, currentContextGroupId(), String16(),
     734       44512 :                                V8StackTraceImpl::maxCallStackSizeToCapture);
     735             :   // Passing one as maxStackSize forces no async chain for the new stack.
     736       22256 :   if (asyncCreation && !asyncCreation->isEmpty()) {
     737             :     m_asyncTaskCreationStacks[task] = asyncCreation;
     738       20106 :     m_allAsyncStacks.push_back(std::move(asyncCreation));
     739       20106 :     ++m_asyncStacksCount;
     740       20106 :     collectOldAsyncStacksIfNeeded();
     741       22256 :   }
     742             : }
     743             : 
     744        1385 : void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task,
     745             :                                     bool recurring) {
     746        2770 :   asyncTaskScheduledForStack(toString16(taskName), task, recurring);
     747        1385 :   asyncTaskCandidateForStepping(task);
     748        1385 : }
     749             : 
     750           0 : void V8Debugger::asyncTaskCanceled(void* task) {
     751           0 :   asyncTaskCanceledForStack(task);
     752             :   asyncTaskCanceledForStepping(task);
     753           0 : }
     754             : 
     755        1385 : void V8Debugger::asyncTaskStarted(void* task) {
     756        1385 :   asyncTaskStartedForStack(task);
     757             :   asyncTaskStartedForStepping(task);
     758        1385 : }
     759             : 
     760        1385 : void V8Debugger::asyncTaskFinished(void* task) {
     761        1385 :   asyncTaskFinishedForStack(task);
     762             :   asyncTaskFinishedForStepping(task);
     763        1385 : }
     764             : 
     765       48784 : void V8Debugger::asyncTaskScheduledForStack(const String16& taskName,
     766             :                                             void* task, bool recurring) {
     767       74372 :   if (!m_maxAsyncCallStackDepth) return;
     768       23196 :   v8::HandleScope scope(m_isolate);
     769             :   std::shared_ptr<AsyncStackTrace> asyncStack =
     770             :       AsyncStackTrace::capture(this, currentContextGroupId(), taskName,
     771       23196 :                                V8StackTraceImpl::maxCallStackSizeToCapture);
     772       23196 :   if (asyncStack) {
     773             :     m_asyncTaskStacks[task] = asyncStack;
     774       23081 :     if (recurring) m_recurringTasks.insert(task);
     775       23081 :     m_allAsyncStacks.push_back(std::move(asyncStack));
     776       23081 :     ++m_asyncStacksCount;
     777       23081 :     collectOldAsyncStacksIfNeeded();
     778       23196 :   }
     779             : }
     780             : 
     781        1530 : void V8Debugger::asyncTaskCanceledForStack(void* task) {
     782        3060 :   if (!m_maxAsyncCallStackDepth) return;
     783             :   m_asyncTaskStacks.erase(task);
     784             :   m_recurringTasks.erase(task);
     785             :   m_parentTask.erase(task);
     786             :   m_asyncTaskCreationStacks.erase(task);
     787             : }
     788             : 
     789       14878 : void V8Debugger::asyncTaskStartedForStack(void* task) {
     790       29756 :   if (!m_maxAsyncCallStackDepth) return;
     791             :   // Needs to support following order of events:
     792             :   // - asyncTaskScheduled
     793             :   //   <-- attached here -->
     794             :   // - asyncTaskStarted
     795             :   // - asyncTaskCanceled <-- canceled before finished
     796             :   //   <-- async stack requested here -->
     797             :   // - asyncTaskFinished
     798        4480 :   m_currentTasks.push_back(task);
     799             :   auto parentIt = m_parentTask.find(task);
     800             :   AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(
     801        4480 :       parentIt == m_parentTask.end() ? task : parentIt->second);
     802        4480 :   if (stackIt != m_asyncTaskStacks.end()) {
     803        8520 :     m_currentAsyncParent.push_back(stackIt->second.lock());
     804             :   } else {
     805         220 :     m_currentAsyncParent.emplace_back();
     806             :   }
     807             :   auto itCreation = m_asyncTaskCreationStacks.find(task);
     808        4480 :   if (itCreation != m_asyncTaskCreationStacks.end()) {
     809        4260 :     m_currentAsyncCreation.push_back(itCreation->second.lock());
     810             :     // TODO(kozyatinskiy): implement it without hack.
     811        2130 :     if (m_currentAsyncParent.back()) {
     812             :       m_currentAsyncCreation.back()->setDescription(
     813        4020 :           m_currentAsyncParent.back()->description());
     814             :       m_currentAsyncParent.back().reset();
     815             :     }
     816             :   } else {
     817        2350 :     m_currentAsyncCreation.emplace_back();
     818             :   }
     819             : }
     820             : 
     821       14873 : void V8Debugger::asyncTaskFinishedForStack(void* task) {
     822       14873 :   if (!m_maxAsyncCallStackDepth) return;
     823             :   // We could start instrumenting half way and the stack is empty.
     824        8970 :   if (!m_currentTasks.size()) return;
     825             :   DCHECK(m_currentTasks.back() == task);
     826             :   m_currentTasks.pop_back();
     827             : 
     828             :   DCHECK(m_currentAsyncParent.size() == m_currentAsyncCreation.size());
     829             :   m_currentAsyncParent.pop_back();
     830             :   m_currentAsyncCreation.pop_back();
     831             : 
     832        4475 :   if (m_recurringTasks.find(task) == m_recurringTasks.end()) {
     833        1530 :     asyncTaskCanceledForStack(task);
     834             :   }
     835             : }
     836             : 
     837       15111 : void V8Debugger::asyncTaskCandidateForStepping(void* task) {
     838       15111 :   if (!m_stepIntoAsyncCallback) return;
     839             :   DCHECK(m_targetContextGroupId);
     840          60 :   if (currentContextGroupId() != m_targetContextGroupId) return;
     841          60 :   m_taskWithScheduledBreak = task;
     842          60 :   v8::debug::ClearStepping(m_isolate);
     843          60 :   m_stepIntoAsyncCallback->sendSuccess();
     844             :   m_stepIntoAsyncCallback.reset();
     845             : }
     846             : 
     847           0 : void V8Debugger::asyncTaskStartedForStepping(void* task) {
     848       14878 :   if (m_breakRequested) return;
     849       14878 :   if (task != m_taskWithScheduledBreak) return;
     850          55 :   v8::debug::DebugBreak(m_isolate);
     851             : }
     852             : 
     853           0 : void V8Debugger::asyncTaskFinishedForStepping(void* task) {
     854       14873 :   if (task != m_taskWithScheduledBreak) return;
     855          55 :   m_taskWithScheduledBreak = nullptr;
     856          55 :   if (m_breakRequested) return;
     857          55 :   v8::debug::CancelDebugBreak(m_isolate);
     858             : }
     859             : 
     860           0 : void V8Debugger::asyncTaskCanceledForStepping(void* task) {
     861           0 :   if (task != m_taskWithScheduledBreak) return;
     862           0 :   m_taskWithScheduledBreak = nullptr;
     863             : }
     864             : 
     865        3206 : void V8Debugger::allAsyncTasksCanceled() {
     866             :   m_asyncTaskStacks.clear();
     867             :   m_recurringTasks.clear();
     868             :   m_currentAsyncParent.clear();
     869             :   m_currentAsyncCreation.clear();
     870             :   m_currentTasks.clear();
     871             :   m_parentTask.clear();
     872             :   m_asyncTaskCreationStacks.clear();
     873             : 
     874             :   m_framesCache.clear();
     875             :   m_allAsyncStacks.clear();
     876        3206 :   m_asyncStacksCount = 0;
     877        3206 : }
     878             : 
     879          25 : void V8Debugger::muteScriptParsedEvents() {
     880          25 :   ++m_ignoreScriptParsedEventsCounter;
     881          25 : }
     882             : 
     883          25 : void V8Debugger::unmuteScriptParsedEvents() {
     884          25 :   --m_ignoreScriptParsedEventsCounter;
     885             :   DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0);
     886          25 : }
     887             : 
     888        6533 : std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace(
     889             :     bool fullStack) {
     890        6533 :   if (!m_isolate->InContext()) return nullptr;
     891             : 
     892        6533 :   v8::HandleScope handles(m_isolate);
     893        6533 :   int contextGroupId = currentContextGroupId();
     894        6533 :   if (!contextGroupId) return nullptr;
     895             : 
     896        6533 :   int stackSize = 1;
     897        6533 :   if (fullStack) {
     898          90 :     stackSize = V8StackTraceImpl::maxCallStackSizeToCapture;
     899             :   } else {
     900             :     m_inspector->forEachSession(
     901             :         contextGroupId, [&stackSize](V8InspectorSessionImpl* session) {
     902        6498 :           if (session->runtimeAgent()->enabled())
     903        1150 :             stackSize = V8StackTraceImpl::maxCallStackSizeToCapture;
     904       12886 :         });
     905             :   }
     906        6533 :   return V8StackTraceImpl::capture(this, contextGroupId, stackSize);
     907             : }
     908             : 
     909       52320 : int V8Debugger::currentContextGroupId() {
     910       52320 :   if (!m_isolate->InContext()) return 0;
     911       52320 :   return m_inspector->contextGroupId(m_isolate->GetCurrentContext());
     912             : }
     913             : 
     914       43487 : void V8Debugger::collectOldAsyncStacksIfNeeded() {
     915       86974 :   if (m_asyncStacksCount <= m_maxAsyncCallStacks) return;
     916             :   int halfOfLimitRoundedUp =
     917         470 :       m_maxAsyncCallStacks / 2 + m_maxAsyncCallStacks % 2;
     918        2095 :   while (m_asyncStacksCount > halfOfLimitRoundedUp) {
     919             :     m_allAsyncStacks.pop_front();
     920        1155 :     --m_asyncStacksCount;
     921             :   }
     922         470 :   cleanupExpiredWeakPointers(m_asyncTaskStacks);
     923         470 :   cleanupExpiredWeakPointers(m_asyncTaskCreationStacks);
     924        1490 :   for (auto it = m_recurringTasks.begin(); it != m_recurringTasks.end();) {
     925        1100 :     if (m_asyncTaskStacks.find(*it) == m_asyncTaskStacks.end()) {
     926             :       it = m_recurringTasks.erase(it);
     927             :     } else {
     928             :       ++it;
     929             :     }
     930             :   }
     931        1375 :   for (auto it = m_parentTask.begin(); it != m_parentTask.end();) {
     932         870 :     if (m_asyncTaskCreationStacks.find(it->second) ==
     933         760 :             m_asyncTaskCreationStacks.end() &&
     934             :         m_asyncTaskStacks.find(it->second) == m_asyncTaskStacks.end()) {
     935             :       it = m_parentTask.erase(it);
     936             :     } else {
     937             :       ++it;
     938             :     }
     939             :   }
     940         470 :   cleanupExpiredWeakPointers(m_framesCache);
     941             : }
     942             : 
     943       69884 : std::shared_ptr<StackFrame> V8Debugger::symbolize(
     944             :     v8::Local<v8::StackFrame> v8Frame) {
     945             :   auto it = m_framesCache.end();
     946       69884 :   int frameId = 0;
     947       69884 :   if (m_maxAsyncCallStackDepth) {
     948       41577 :     frameId = v8::debug::GetStackFrameId(v8Frame);
     949             :     it = m_framesCache.find(frameId);
     950             :   }
     951      106996 :   if (it != m_framesCache.end() && it->second.lock()) return it->second.lock();
     952       65634 :   std::shared_ptr<StackFrame> frame(new StackFrame(v8Frame));
     953             :   // TODO(clemensh): Figure out a way to do this translation only right before
     954             :   // sending the stack trace over wire.
     955       32817 :   if (v8Frame->IsWasm()) frame->translate(&m_wasmTranslation);
     956       32817 :   if (m_maxAsyncCallStackDepth) {
     957        4510 :     m_framesCache[frameId] = frame;
     958             :   }
     959             :   return frame;
     960             : }
     961             : 
     962         300 : void V8Debugger::setMaxAsyncTaskStacksForTest(int limit) {
     963         300 :   m_maxAsyncCallStacks = 0;
     964         300 :   collectOldAsyncStacksIfNeeded();
     965         300 :   m_maxAsyncCallStacks = limit;
     966         300 : }
     967             : 
     968          30 : void V8Debugger::dumpAsyncTaskStacksStateForTest() {
     969          30 :   fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount);
     970          30 :   fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size());
     971             :   fprintf(stdout, "Created async tasks: %zu\n",
     972          30 :           m_asyncTaskCreationStacks.size());
     973          30 :   fprintf(stdout, "Async tasks with parent: %zu\n", m_parentTask.size());
     974          30 :   fprintf(stdout, "Recurring async tasks: %zu\n", m_recurringTasks.size());
     975          30 :   fprintf(stdout, "\n");
     976          30 : }
     977             : 
     978             : }  // namespace v8_inspector

Generated by: LCOV version 1.10