LCOV - code coverage report
Current view: top level - src/inspector - v8-debugger.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 514 549 93.6 %
Date: 2017-04-26 Functions: 63 69 91.3 %

          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/debugger-script.h"
       8             : #include "src/inspector/inspected-context.h"
       9             : #include "src/inspector/protocol/Protocol.h"
      10             : #include "src/inspector/script-breakpoint.h"
      11             : #include "src/inspector/string-util.h"
      12             : #include "src/inspector/v8-debugger-agent-impl.h"
      13             : #include "src/inspector/v8-inspector-impl.h"
      14             : #include "src/inspector/v8-internal-value-type.h"
      15             : #include "src/inspector/v8-stack-trace-impl.h"
      16             : #include "src/inspector/v8-value-copier.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             : 
      26             : inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) {
      27          18 :   return value ? v8::True(isolate) : v8::False(isolate);
      28             : }
      29             : 
      30       41548 : V8DebuggerAgentImpl* agentForScript(V8InspectorImpl* inspector,
      31             :                                     v8::Local<v8::debug::Script> script) {
      32             :   v8::Local<v8::Value> contextData;
      33       83096 :   if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) {
      34             :     return nullptr;
      35             :   }
      36       41484 :   int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value());
      37       41484 :   int contextGroupId = inspector->contextGroupId(contextId);
      38       41484 :   if (!contextGroupId) return nullptr;
      39       41484 :   return inspector->enabledDebuggerAgentForGroup(contextGroupId);
      40             : }
      41             : 
      42      106344 : v8::MaybeLocal<v8::Array> collectionsEntries(v8::Local<v8::Context> context,
      43             :                                              v8::Local<v8::Value> value) {
      44      106344 :   v8::Isolate* isolate = context->GetIsolate();
      45             :   v8::Local<v8::Array> entries;
      46      106344 :   bool isKeyValue = false;
      47      212688 :   if (!v8::debug::EntriesPreview(isolate, value, &isKeyValue).ToLocal(&entries))
      48      106090 :     return v8::MaybeLocal<v8::Array>();
      49             : 
      50         254 :   v8::Local<v8::Array> wrappedEntries = v8::Array::New(isolate);
      51         254 :   CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0);
      52         254 :   if (!wrappedEntries->SetPrototype(context, v8::Null(isolate))
      53         508 :            .FromMaybe(false))
      54           0 :     return v8::MaybeLocal<v8::Array>();
      55       12486 :   for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) {
      56             :     v8::Local<v8::Value> item;
      57       24972 :     if (!entries->Get(context, i).ToLocal(&item)) continue;
      58             :     v8::Local<v8::Value> value;
      59       18634 :     if (isKeyValue && !entries->Get(context, i + 1).ToLocal(&value)) continue;
      60       12486 :     v8::Local<v8::Object> wrapper = v8::Object::New(isolate);
      61       24972 :     if (!wrapper->SetPrototype(context, v8::Null(isolate)).FromMaybe(false))
      62             :       continue;
      63             :     createDataProperty(
      64             :         context, wrapper,
      65       24972 :         toV8StringInternalized(isolate, isKeyValue ? "key" : "value"), item);
      66       12486 :     if (isKeyValue) {
      67             :       createDataProperty(context, wrapper,
      68       12296 :                          toV8StringInternalized(isolate, "value"), value);
      69             :     }
      70       12486 :     createDataProperty(context, wrappedEntries, wrappedEntries->Length(),
      71       12486 :                        wrapper);
      72             :   }
      73         254 :   if (!markArrayEntriesAsInternal(context, wrappedEntries,
      74         254 :                                   V8InternalValueType::kEntry)) {
      75           0 :     return v8::MaybeLocal<v8::Array>();
      76             :   }
      77         254 :   return wrappedEntries;
      78             : }
      79             : 
      80          84 : v8::MaybeLocal<v8::Object> buildLocation(v8::Local<v8::Context> context,
      81             :                                          int scriptId, int lineNumber,
      82             :                                          int columnNumber) {
      83          84 :   if (scriptId == v8::UnboundScript::kNoScriptId)
      84           6 :     return v8::MaybeLocal<v8::Object>();
      85          78 :   if (lineNumber == v8::Function::kLineOffsetNotFound ||
      86             :       columnNumber == v8::Function::kLineOffsetNotFound) {
      87           0 :     return v8::MaybeLocal<v8::Object>();
      88             :   }
      89          78 :   v8::Isolate* isolate = context->GetIsolate();
      90          78 :   v8::Local<v8::Object> location = v8::Object::New(isolate);
      91         156 :   if (!location->SetPrototype(context, v8::Null(isolate)).FromMaybe(false)) {
      92           0 :     return v8::MaybeLocal<v8::Object>();
      93             :   }
      94          78 :   if (!createDataProperty(context, location,
      95             :                           toV8StringInternalized(isolate, "scriptId"),
      96         312 :                           toV8String(isolate, String16::fromInteger(scriptId)))
      97         156 :            .FromMaybe(false)) {
      98           0 :     return v8::MaybeLocal<v8::Object>();
      99             :   }
     100          78 :   if (!createDataProperty(context, location,
     101             :                           toV8StringInternalized(isolate, "lineNumber"),
     102         234 :                           v8::Integer::New(isolate, lineNumber))
     103         156 :            .FromMaybe(false)) {
     104           0 :     return v8::MaybeLocal<v8::Object>();
     105             :   }
     106          78 :   if (!createDataProperty(context, location,
     107             :                           toV8StringInternalized(isolate, "columnNumber"),
     108         234 :                           v8::Integer::New(isolate, columnNumber))
     109         156 :            .FromMaybe(false)) {
     110           0 :     return v8::MaybeLocal<v8::Object>();
     111             :   }
     112          78 :   if (!markAsInternal(context, location, V8InternalValueType::kLocation)) {
     113           0 :     return v8::MaybeLocal<v8::Object>();
     114             :   }
     115          78 :   return location;
     116             : }
     117             : 
     118          54 : v8::MaybeLocal<v8::Object> generatorObjectLocation(
     119             :     v8::Local<v8::Context> context, v8::Local<v8::Value> value) {
     120          54 :   if (!value->IsGeneratorObject()) return v8::MaybeLocal<v8::Object>();
     121             :   v8::Local<v8::debug::GeneratorObject> generatorObject =
     122          54 :       v8::debug::GeneratorObject::Cast(value);
     123          54 :   if (!generatorObject->IsSuspended()) {
     124          12 :     v8::Local<v8::Function> func = generatorObject->Function();
     125             :     return buildLocation(context, func->ScriptId(), func->GetScriptLineNumber(),
     126          12 :                          func->GetScriptColumnNumber());
     127             :   }
     128             :   v8::Local<v8::debug::Script> script;
     129          84 :   if (!generatorObject->Script().ToLocal(&script))
     130           0 :     return v8::MaybeLocal<v8::Object>();
     131          42 :   v8::debug::Location suspendedLocation = generatorObject->SuspendedLocation();
     132             :   return buildLocation(context, script->Id(), suspendedLocation.GetLineNumber(),
     133          42 :                        suspendedLocation.GetColumnNumber());
     134             : }
     135             : 
     136             : template <typename Map>
     137        1404 : void cleanupExpiredWeakPointers(Map& map) {
     138       14880 :   for (auto it = map.begin(); it != map.end();) {
     139       12072 :     if (it->second.expired()) {
     140             :       it = map.erase(it);
     141             :     } else {
     142             :       ++it;
     143             :     }
     144             :   }
     145        1404 : }
     146             : 
     147             : }  // namespace
     148             : 
     149             : static bool inLiveEditScope = false;
     150             : 
     151      151606 : v8::MaybeLocal<v8::Value> V8Debugger::callDebuggerMethod(
     152             :     const char* functionName, int argc, v8::Local<v8::Value> argv[],
     153             :     bool catchExceptions) {
     154             :   v8::MicrotasksScope microtasks(m_isolate,
     155      151606 :                                  v8::MicrotasksScope::kDoNotRunMicrotasks);
     156             :   DCHECK(m_isolate->InContext());
     157      151606 :   v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
     158      151606 :   v8::Local<v8::Object> debuggerScript = m_debuggerScript.Get(m_isolate);
     159             :   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
     160             :       debuggerScript
     161      303212 :           ->Get(context, toV8StringInternalized(m_isolate, functionName))
     162      151606 :           .ToLocalChecked());
     163      151606 :   if (catchExceptions) {
     164      151588 :     v8::TryCatch try_catch(m_isolate);
     165      151588 :     return function->Call(context, debuggerScript, argc, argv);
     166             :   }
     167          18 :   return function->Call(context, debuggerScript, argc, argv);
     168             : }
     169             : 
     170        4537 : V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector)
     171             :     : m_isolate(isolate),
     172             :       m_inspector(inspector),
     173             :       m_enableCount(0),
     174             :       m_breakpointsActivated(true),
     175             :       m_ignoreScriptParsedEventsCounter(0),
     176             :       m_maxAsyncCallStacks(kMaxAsyncTaskStacks),
     177             :       m_maxAsyncCallStackDepth(0),
     178             :       m_pauseOnExceptionsState(v8::debug::NoBreakOnException),
     179       36296 :       m_wasmTranslation(isolate) {}
     180             : 
     181       18148 : V8Debugger::~V8Debugger() {}
     182             : 
     183        4333 : void V8Debugger::enable() {
     184        4363 :   if (m_enableCount++) return;
     185             :   DCHECK(!enabled());
     186        4303 :   v8::HandleScope scope(m_isolate);
     187        4303 :   v8::debug::SetDebugDelegate(m_isolate, this);
     188             :   v8::debug::SetOutOfMemoryCallback(m_isolate, &V8Debugger::v8OOMCallback,
     189        4303 :                                     this);
     190        8606 :   m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate));
     191        4303 :   v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException);
     192        4303 :   m_pauseOnExceptionsState = v8::debug::NoBreakOnException;
     193        4303 :   compileDebuggerScript();
     194             : }
     195             : 
     196        4333 : void V8Debugger::disable() {
     197        8666 :   if (--m_enableCount) return;
     198             :   DCHECK(enabled());
     199        4303 :   clearBreakpoints();
     200             :   m_debuggerScript.Reset();
     201             :   m_debuggerContext.Reset();
     202        4303 :   allAsyncTasksCanceled();
     203        4303 :   m_taskWithScheduledBreak = nullptr;
     204        4303 :   m_wasmTranslation.Clear();
     205        4303 :   v8::debug::SetDebugDelegate(m_isolate, nullptr);
     206        4303 :   v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr);
     207        4303 :   m_isolate->RestoreOriginalHeapLimit();
     208             : }
     209             : 
     210      425016 : bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); }
     211             : 
     212        4333 : void V8Debugger::getCompiledScripts(
     213             :     int contextGroupId,
     214             :     std::vector<std::unique_ptr<V8DebuggerScript>>& result) {
     215        4333 :   v8::HandleScope scope(m_isolate);
     216        8666 :   v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate);
     217        4333 :   v8::debug::GetLoadedScripts(m_isolate, scripts);
     218       32842 :   for (size_t i = 0; i < scripts.Size(); ++i) {
     219       12088 :     v8::Local<v8::debug::Script> script = scripts.Get(i);
     220       12088 :     if (!script->WasCompiled()) continue;
     221             :     v8::Local<v8::Value> contextData;
     222       24128 :     if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32())
     223             :       continue;
     224       12058 :     int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value());
     225       12058 :     if (m_inspector->contextGroupId(contextId) != contextGroupId) continue;
     226       24008 :     result.push_back(V8DebuggerScript::Create(m_isolate, script, false));
     227        4333 :   }
     228        4333 : }
     229             : 
     230        2458 : String16 V8Debugger::setBreakpoint(const ScriptBreakpoint& breakpoint,
     231             :                                    int* actualLineNumber,
     232             :                                    int* actualColumnNumber) {
     233        2458 :   v8::HandleScope scope(m_isolate);
     234        2458 :   v8::Local<v8::Context> context = debuggerContext();
     235             :   v8::Context::Scope contextScope(context);
     236             : 
     237        2458 :   v8::Local<v8::Object> info = v8::Object::New(m_isolate);
     238             :   bool success = false;
     239             :   success = info->Set(context, toV8StringInternalized(m_isolate, "sourceID"),
     240        7374 :                       toV8String(m_isolate, breakpoint.script_id))
     241        2458 :                 .FromMaybe(false);
     242             :   DCHECK(success);
     243             :   success = info->Set(context, toV8StringInternalized(m_isolate, "lineNumber"),
     244        7374 :                       v8::Integer::New(m_isolate, breakpoint.line_number))
     245        2458 :                 .FromMaybe(false);
     246             :   DCHECK(success);
     247             :   success =
     248             :       info->Set(context, toV8StringInternalized(m_isolate, "columnNumber"),
     249        7374 :                 v8::Integer::New(m_isolate, breakpoint.column_number))
     250        2458 :           .FromMaybe(false);
     251             :   DCHECK(success);
     252             :   success = info->Set(context, toV8StringInternalized(m_isolate, "condition"),
     253        7374 :                       toV8String(m_isolate, breakpoint.condition))
     254        2458 :                 .FromMaybe(false);
     255             :   DCHECK(success);
     256             :   USE(success);
     257             : 
     258             :   v8::Local<v8::Function> setBreakpointFunction = v8::Local<v8::Function>::Cast(
     259        2458 :       m_debuggerScript.Get(m_isolate)
     260        4916 :           ->Get(context, toV8StringInternalized(m_isolate, "setBreakpoint"))
     261        4916 :           .ToLocalChecked());
     262             :   v8::Local<v8::Value> breakpointId =
     263        4916 :       v8::debug::Call(debuggerContext(), setBreakpointFunction, info)
     264        2458 :           .ToLocalChecked();
     265        2458 :   if (!breakpointId->IsString()) return "";
     266             :   *actualLineNumber =
     267        4916 :       info->Get(context, toV8StringInternalized(m_isolate, "lineNumber"))
     268        2458 :           .ToLocalChecked()
     269             :           ->Int32Value(context)
     270        4916 :           .FromJust();
     271             :   *actualColumnNumber =
     272        4916 :       info->Get(context, toV8StringInternalized(m_isolate, "columnNumber"))
     273        2458 :           .ToLocalChecked()
     274             :           ->Int32Value(context)
     275        4916 :           .FromJust();
     276        4916 :   return toProtocolString(breakpointId.As<v8::String>());
     277             : }
     278             : 
     279         822 : void V8Debugger::removeBreakpoint(const String16& breakpointId) {
     280         822 :   v8::HandleScope scope(m_isolate);
     281         822 :   v8::Local<v8::Context> context = debuggerContext();
     282             :   v8::Context::Scope contextScope(context);
     283             : 
     284         822 :   v8::Local<v8::Object> info = v8::Object::New(m_isolate);
     285             :   bool success = false;
     286             :   success =
     287             :       info->Set(context, toV8StringInternalized(m_isolate, "breakpointId"),
     288        2466 :                 toV8String(m_isolate, breakpointId))
     289         822 :           .FromMaybe(false);
     290             :   DCHECK(success);
     291             :   USE(success);
     292             : 
     293             :   v8::Local<v8::Function> removeBreakpointFunction =
     294             :       v8::Local<v8::Function>::Cast(
     295         822 :           m_debuggerScript.Get(m_isolate)
     296             :               ->Get(context,
     297        1644 :                     toV8StringInternalized(m_isolate, "removeBreakpoint"))
     298        1644 :               .ToLocalChecked());
     299        1644 :   v8::debug::Call(debuggerContext(), removeBreakpointFunction, info)
     300        1644 :       .ToLocalChecked();
     301         822 : }
     302             : 
     303        4303 : void V8Debugger::clearBreakpoints() {
     304        4303 :   v8::HandleScope scope(m_isolate);
     305        4303 :   v8::Local<v8::Context> context = debuggerContext();
     306             :   v8::Context::Scope contextScope(context);
     307             : 
     308             :   v8::Local<v8::Function> clearBreakpoints = v8::Local<v8::Function>::Cast(
     309        4303 :       m_debuggerScript.Get(m_isolate)
     310        8606 :           ->Get(context, toV8StringInternalized(m_isolate, "clearBreakpoints"))
     311        8606 :           .ToLocalChecked());
     312       12909 :   v8::debug::Call(debuggerContext(), clearBreakpoints).ToLocalChecked();
     313        4303 : }
     314             : 
     315        4513 : void V8Debugger::setBreakpointsActivated(bool activated) {
     316        4513 :   if (!enabled()) {
     317           0 :     UNREACHABLE();
     318             :     return;
     319             :   }
     320        4513 :   v8::debug::SetBreakPointsActive(m_isolate, activated);
     321        4513 :   m_breakpointsActivated = activated;
     322        4513 : }
     323             : 
     324      211932 : v8::debug::ExceptionBreakState V8Debugger::getPauseOnExceptionsState() {
     325             :   DCHECK(enabled());
     326      211932 :   return m_pauseOnExceptionsState;
     327             : }
     328             : 
     329        7532 : void V8Debugger::setPauseOnExceptionsState(
     330             :     v8::debug::ExceptionBreakState pauseOnExceptionsState) {
     331             :   DCHECK(enabled());
     332       15064 :   if (m_pauseOnExceptionsState == pauseOnExceptionsState) return;
     333        5960 :   v8::debug::ChangeBreakOnException(m_isolate, pauseOnExceptionsState);
     334        5960 :   m_pauseOnExceptionsState = pauseOnExceptionsState;
     335             : }
     336             : 
     337         282 : void V8Debugger::setPauseOnNextStatement(bool pause, int targetContextGroupId) {
     338         282 :   if (isPaused()) return;
     339             :   DCHECK(targetContextGroupId);
     340         282 :   if (!pause && m_targetContextGroupId &&
     341             :       m_targetContextGroupId != targetContextGroupId) {
     342             :     return;
     343             :   }
     344         282 :   m_targetContextGroupId = targetContextGroupId;
     345         282 :   m_breakRequested = pause;
     346         282 :   if (pause)
     347         261 :     v8::debug::DebugBreak(m_isolate);
     348             :   else
     349          21 :     v8::debug::CancelDebugBreak(m_isolate);
     350             : }
     351             : 
     352          78 : bool V8Debugger::canBreakProgram() {
     353         144 :   if (!m_breakpointsActivated) return false;
     354         144 :   return !v8::debug::AllFramesOnStackAreBlackboxed(m_isolate);
     355             : }
     356             : 
     357          66 : bool V8Debugger::breakProgram(int targetContextGroupId) {
     358             :   // Don't allow nested breaks.
     359          66 :   if (isPaused()) return true;
     360          66 :   if (!canBreakProgram()) return true;
     361             :   DCHECK(targetContextGroupId);
     362          66 :   m_targetContextGroupId = targetContextGroupId;
     363          66 :   v8::debug::BreakRightNow(m_isolate);
     364          66 :   return m_inspector->enabledDebuggerAgentForGroup(targetContextGroupId);
     365             : }
     366             : 
     367        1725 : void V8Debugger::continueProgram(int targetContextGroupId) {
     368       66268 :   if (m_pausedContextGroupId != targetContextGroupId) return;
     369       64531 :   if (isPaused()) m_inspector->client()->quitMessageLoopOnPause();
     370             :   m_pausedContext.Clear();
     371             :   m_executionState.Clear();
     372             : }
     373             : 
     374       50541 : void V8Debugger::stepIntoStatement(int targetContextGroupId) {
     375             :   DCHECK(isPaused());
     376             :   DCHECK(!m_executionState.IsEmpty());
     377             :   DCHECK(targetContextGroupId);
     378       50541 :   m_targetContextGroupId = targetContextGroupId;
     379       50541 :   v8::debug::PrepareStep(m_isolate, v8::debug::StepIn);
     380             :   continueProgram(targetContextGroupId);
     381       50541 : }
     382             : 
     383       11616 : void V8Debugger::stepOverStatement(int targetContextGroupId) {
     384             :   DCHECK(isPaused());
     385             :   DCHECK(!m_executionState.IsEmpty());
     386             :   DCHECK(targetContextGroupId);
     387       11616 :   m_targetContextGroupId = targetContextGroupId;
     388       11616 :   v8::debug::PrepareStep(m_isolate, v8::debug::StepNext);
     389             :   continueProgram(targetContextGroupId);
     390       11616 : }
     391             : 
     392         661 : void V8Debugger::stepOutOfFunction(int targetContextGroupId) {
     393             :   DCHECK(isPaused());
     394             :   DCHECK(!m_executionState.IsEmpty());
     395             :   DCHECK(targetContextGroupId);
     396         661 :   m_targetContextGroupId = targetContextGroupId;
     397         661 :   v8::debug::PrepareStep(m_isolate, v8::debug::StepOut);
     398             :   continueProgram(targetContextGroupId);
     399         661 : }
     400             : 
     401          90 : void V8Debugger::scheduleStepIntoAsync(
     402             :     std::unique_ptr<ScheduleStepIntoAsyncCallback> callback,
     403             :     int targetContextGroupId) {
     404             :   DCHECK(isPaused());
     405             :   DCHECK(!m_executionState.IsEmpty());
     406             :   DCHECK(targetContextGroupId);
     407          90 :   if (m_stepIntoAsyncCallback) {
     408             :     m_stepIntoAsyncCallback->sendFailure(Response::Error(
     409          18 :         "Current scheduled step into async was overriden with new one."));
     410             :   }
     411          90 :   m_targetContextGroupId = targetContextGroupId;
     412             :   m_stepIntoAsyncCallback = std::move(callback);
     413          90 : }
     414             : 
     415          18 : Response V8Debugger::setScriptSource(
     416             :     const String16& sourceID, v8::Local<v8::String> newSource, bool dryRun,
     417             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails,
     418             :     JavaScriptCallFrames* newCallFrames, Maybe<bool>* stackChanged,
     419          24 :     bool* compileError) {
     420             :   class EnableLiveEditScope {
     421             :    public:
     422             :     explicit EnableLiveEditScope(v8::Isolate* isolate) : m_isolate(isolate) {
     423          18 :       v8::debug::SetLiveEditEnabled(m_isolate, true);
     424          18 :       inLiveEditScope = true;
     425             :     }
     426             :     ~EnableLiveEditScope() {
     427          18 :       v8::debug::SetLiveEditEnabled(m_isolate, false);
     428          18 :       inLiveEditScope = false;
     429             :     }
     430             : 
     431             :    private:
     432             :     v8::Isolate* m_isolate;
     433             :   };
     434             : 
     435          18 :   *compileError = false;
     436             :   DCHECK(enabled());
     437          18 :   v8::HandleScope scope(m_isolate);
     438             : 
     439             :   std::unique_ptr<v8::Context::Scope> contextScope;
     440          18 :   if (!isPaused())
     441          36 :     contextScope.reset(new v8::Context::Scope(debuggerContext()));
     442             : 
     443             :   v8::Local<v8::Value> argv[] = {toV8String(m_isolate, sourceID), newSource,
     444          36 :                                  v8Boolean(dryRun, m_isolate)};
     445             : 
     446             :   v8::Local<v8::Value> v8result;
     447             :   {
     448             :     EnableLiveEditScope enableLiveEditScope(m_isolate);
     449          36 :     v8::TryCatch tryCatch(m_isolate);
     450          18 :     tryCatch.SetVerbose(false);
     451             :     v8::MaybeLocal<v8::Value> maybeResult =
     452          18 :         callDebuggerMethod("liveEditScriptSource", 3, argv, false);
     453          18 :     if (tryCatch.HasCaught()) {
     454           0 :       v8::Local<v8::Message> message = tryCatch.Message();
     455           0 :       if (!message.IsEmpty())
     456           0 :         return Response::Error(toProtocolStringWithTypeCheck(message->Get()));
     457             :       else
     458           0 :         return Response::InternalError();
     459             :     }
     460             :     v8result = maybeResult.ToLocalChecked();
     461             :   }
     462             :   DCHECK(!v8result.IsEmpty());
     463          18 :   v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
     464             :   v8::Local<v8::Object> resultTuple =
     465          18 :       v8result->ToObject(context).ToLocalChecked();
     466             :   int code = static_cast<int>(resultTuple->Get(context, 0)
     467          18 :                                   .ToLocalChecked()
     468             :                                   ->ToInteger(context)
     469          18 :                                   .ToLocalChecked()
     470          18 :                                   ->Value());
     471          18 :   switch (code) {
     472             :     case 0: {
     473             :       *stackChanged = resultTuple->Get(context, 1)
     474           6 :                           .ToLocalChecked()
     475             :                           ->BooleanValue(context)
     476          12 :                           .FromJust();
     477             :       // Call stack may have changed after if the edited function was on the
     478             :       // stack.
     479          12 :       if (!dryRun && isPaused()) {
     480           0 :         JavaScriptCallFrames frames = currentCallFrames();
     481           0 :         newCallFrames->swap(frames);
     482             :       }
     483           6 :       return Response::OK();
     484             :     }
     485             :     // Compile error.
     486             :     case 1: {
     487             :       *exceptionDetails =
     488             :           protocol::Runtime::ExceptionDetails::create()
     489          36 :               .setExceptionId(m_inspector->nextExceptionId())
     490             :               .setText(toProtocolStringWithTypeCheck(
     491          36 :                   resultTuple->Get(context, 2).ToLocalChecked()))
     492             :               .setLineNumber(static_cast<int>(resultTuple->Get(context, 3)
     493          12 :                                                   .ToLocalChecked()
     494             :                                                   ->ToInteger(context)
     495          12 :                                                   .ToLocalChecked()
     496          12 :                                                   ->Value()) -
     497          12 :                              1)
     498             :               .setColumnNumber(static_cast<int>(resultTuple->Get(context, 4)
     499          12 :                                                     .ToLocalChecked()
     500             :                                                     ->ToInteger(context)
     501          12 :                                                     .ToLocalChecked()
     502          12 :                                                     ->Value()) -
     503          12 :                                1)
     504             :               .build();
     505          12 :       *compileError = true;
     506          12 :       return Response::OK();
     507             :     }
     508             :   }
     509          18 :   return Response::InternalError();
     510             : }
     511             : 
     512       77166 : JavaScriptCallFrames V8Debugger::currentCallFrames(int limit) {
     513       77166 :   if (!isPaused()) return JavaScriptCallFrames();
     514             :   v8::Local<v8::Value> currentCallFramesV8;
     515             :   v8::Local<v8::Value> argv[] = {m_executionState,
     516       77166 :                                  v8::Integer::New(m_isolate, limit)};
     517       77166 :   if (!callDebuggerMethod("currentCallFrames", arraysize(argv), argv, true)
     518      154332 :            .ToLocal(&currentCallFramesV8)) {
     519             :     return JavaScriptCallFrames();
     520             :   }
     521       77160 :   if (!currentCallFramesV8->IsArray()) return JavaScriptCallFrames();
     522             :   v8::Local<v8::Array> callFramesArray = currentCallFramesV8.As<v8::Array>();
     523             :   JavaScriptCallFrames callFrames;
     524      268828 :   for (uint32_t i = 0; i < callFramesArray->Length(); ++i) {
     525             :     v8::Local<v8::Value> callFrameValue;
     526      383336 :     if (!callFramesArray->Get(debuggerContext(), i).ToLocal(&callFrameValue))
     527             :       return JavaScriptCallFrames();
     528      191668 :     if (!callFrameValue->IsObject()) return JavaScriptCallFrames();
     529             :     v8::Local<v8::Object> callFrameObject = callFrameValue.As<v8::Object>();
     530             :     callFrames.push_back(JavaScriptCallFrame::create(
     531      383336 :         debuggerContext(), v8::Local<v8::Object>::Cast(callFrameObject)));
     532             :   }
     533       77160 :   return callFrames;
     534             : }
     535             : 
     536       77036 : void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext,
     537             :                                     v8::Local<v8::Object> executionState,
     538             :                                     v8::Local<v8::Value> exception,
     539             :                                     v8::Local<v8::Array> hitBreakpointNumbers,
     540       77036 :                                     bool isPromiseRejection, bool isUncaught) {
     541             :   // Don't allow nested breaks.
     542       77060 :   if (isPaused()) return;
     543             : 
     544      154048 :   int contextGroupId = m_inspector->contextGroupId(pausedContext);
     545       77036 :   if (m_targetContextGroupId && contextGroupId != m_targetContextGroupId) {
     546          24 :     v8::debug::PrepareStep(m_isolate, v8::debug::StepOut);
     547          24 :     return;
     548             :   }
     549       77012 :   m_targetContextGroupId = 0;
     550       77012 :   if (m_stepIntoAsyncCallback) {
     551             :     m_stepIntoAsyncCallback->sendFailure(
     552          36 :         Response::Error("No async tasks were scheduled before pause."));
     553             :     m_stepIntoAsyncCallback.reset();
     554             :   }
     555       77012 :   m_breakRequested = false;
     556       77012 :   V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup(
     557       77012 :       m_inspector->contextGroupId(pausedContext));
     558      154024 :   if (!agent || (agent->skipAllPauses() && !m_scheduledOOMBreak)) return;
     559             : 
     560             :   std::vector<String16> breakpointIds;
     561       77012 :   if (!hitBreakpointNumbers.IsEmpty()) {
     562       74338 :     breakpointIds.reserve(hitBreakpointNumbers->Length());
     563       77181 :     for (uint32_t i = 0; i < hitBreakpointNumbers->Length(); i++) {
     564             :       v8::Local<v8::Value> hitBreakpointNumber =
     565        2843 :           hitBreakpointNumbers->Get(debuggerContext(), i).ToLocalChecked();
     566             :       DCHECK(hitBreakpointNumber->IsInt32());
     567             :       breakpointIds.push_back(String16::fromInteger(
     568        8529 :           hitBreakpointNumber->Int32Value(debuggerContext()).FromJust()));
     569             :     }
     570             :   }
     571             : 
     572       77012 :   m_pausedContext = pausedContext;
     573       77012 :   m_executionState = executionState;
     574       77012 :   m_pausedContextGroupId = contextGroupId;
     575             :   agent->didPause(InspectedContext::contextId(pausedContext), exception,
     576             :                   breakpointIds, isPromiseRejection, isUncaught,
     577       77012 :                   m_scheduledOOMBreak);
     578       77012 :   int groupId = m_inspector->contextGroupId(pausedContext);
     579             :   DCHECK(groupId);
     580             :   {
     581             :     v8::Context::Scope scope(pausedContext);
     582       77012 :     v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
     583      154024 :     CHECK(!context.IsEmpty() &&
     584             :           context != v8::debug::GetDebugContext(m_isolate));
     585      154024 :     m_inspector->client()->runMessageLoopOnPause(groupId);
     586       77012 :     m_pausedContextGroupId = 0;
     587             :   }
     588             :   // The agent may have been removed in the nested loop.
     589       77012 :   agent = m_inspector->enabledDebuggerAgentForGroup(groupId);
     590       77012 :   if (agent) agent->didContinue();
     591       77012 :   if (m_scheduledOOMBreak) m_isolate->RestoreOriginalHeapLimit();
     592       77012 :   m_scheduledOOMBreak = false;
     593             :   m_pausedContext.Clear();
     594       77012 :   m_executionState.Clear();
     595             : }
     596             : 
     597           6 : void V8Debugger::v8OOMCallback(void* data) {
     598             :   V8Debugger* thisPtr = static_cast<V8Debugger*>(data);
     599           6 :   thisPtr->m_isolate->IncreaseHeapLimitForDebugging();
     600           6 :   thisPtr->m_scheduledOOMBreak = true;
     601           6 :   v8::Local<v8::Context> context = thisPtr->m_isolate->GetEnteredContext();
     602             :   DCHECK(!context.IsEmpty());
     603             :   thisPtr->setPauseOnNextStatement(
     604           6 :       true, thisPtr->m_inspector->contextGroupId(context));
     605           6 : }
     606             : 
     607       24704 : void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script,
     608             :                                 bool has_compile_error) {
     609       24704 :   V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script);
     610       49408 :   if (!agent) return;
     611       24640 :   if (script->IsWasm()) {
     612          56 :     m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), agent);
     613       24584 :   } else if (m_ignoreScriptParsedEventsCounter == 0) {
     614             :     agent->didParseSource(
     615             :         V8DebuggerScript::Create(m_isolate, script, inLiveEditScope),
     616       49108 :         !has_compile_error);
     617             :   }
     618             : }
     619             : 
     620       74362 : void V8Debugger::BreakProgramRequested(v8::Local<v8::Context> pausedContext,
     621             :                                        v8::Local<v8::Object> execState,
     622             :                                        v8::Local<v8::Value> breakPointsHit) {
     623       74362 :   v8::Local<v8::Value> argv[] = {breakPointsHit};
     624             :   v8::Local<v8::Value> hitBreakpoints;
     625       74362 :   if (!callDebuggerMethod("getBreakpointNumbers", 1, argv, true)
     626      148724 :            .ToLocal(&hitBreakpoints)) {
     627           0 :     return;
     628             :   }
     629             :   DCHECK(hitBreakpoints->IsArray());
     630             :   handleProgramBreak(pausedContext, execState, v8::Local<v8::Value>(),
     631       74362 :                      hitBreakpoints.As<v8::Array>());
     632             : }
     633             : 
     634        2674 : void V8Debugger::ExceptionThrown(v8::Local<v8::Context> pausedContext,
     635             :                                  v8::Local<v8::Object> execState,
     636             :                                  v8::Local<v8::Value> exception,
     637             :                                  v8::Local<v8::Value> promise,
     638             :                                  bool isUncaught) {
     639        2674 :   bool isPromiseRejection = promise->IsPromise();
     640             :   handleProgramBreak(pausedContext, execState, exception,
     641        5348 :                      v8::Local<v8::Array>(), isPromiseRejection, isUncaught);
     642        2674 : }
     643             : 
     644       16844 : bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
     645             :                                       const v8::debug::Location& start,
     646             :                                       const v8::debug::Location& end) {
     647       16844 :   V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script);
     648       16844 :   if (!agent) return false;
     649             :   return agent->isFunctionBlackboxed(String16::fromInteger(script->Id()), start,
     650       33688 :                                      end);
     651             : }
     652             : 
     653      119578 : void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
     654             :                                       int id, int parentId,
     655             :                                       bool createdByUser) {
     656             :   // Async task events from Promises are given misaligned pointers to prevent
     657             :   // from overlapping with other Blink task identifiers.
     658      119578 :   void* task = reinterpret_cast<void*>(id * 2 + 1);
     659             :   void* parentTask =
     660      119578 :       parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr;
     661      119578 :   switch (type) {
     662             :     case v8::debug::kDebugPromiseCreated:
     663       36980 :       asyncTaskCreatedForStack(task, parentTask);
     664       36980 :       if (createdByUser && parentTask) asyncTaskCandidateForStepping(task);
     665             :       break;
     666             :     case v8::debug::kDebugEnqueueAsyncFunction:
     667       14648 :       asyncTaskScheduledForStack("async function", task, true);
     668        7324 :       break;
     669             :     case v8::debug::kDebugEnqueuePromiseResolve:
     670       60208 :       asyncTaskScheduledForStack("Promise.resolve", task, true);
     671       30104 :       break;
     672             :     case v8::debug::kDebugEnqueuePromiseReject:
     673       14428 :       asyncTaskScheduledForStack("Promise.reject", task, true);
     674        7214 :       break;
     675             :     case v8::debug::kDebugWillHandle:
     676       18978 :       asyncTaskStartedForStack(task);
     677             :       asyncTaskStartedForStepping(task);
     678             :       break;
     679             :     case v8::debug::kDebugDidHandle:
     680       18978 :       asyncTaskFinishedForStack(task);
     681             :       asyncTaskFinishedForStepping(task);
     682             :       break;
     683             :   }
     684      119578 : }
     685             : 
     686      133410 : std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncParent() {
     687      266820 :   return m_currentAsyncParent.empty() ? nullptr : m_currentAsyncParent.back();
     688             : }
     689             : 
     690       56616 : std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncCreation() {
     691             :   return m_currentAsyncCreation.empty() ? nullptr
     692      113232 :                                         : m_currentAsyncCreation.back();
     693             : }
     694             : 
     695        4303 : void V8Debugger::compileDebuggerScript() {
     696        4303 :   if (!m_debuggerScript.IsEmpty()) {
     697           0 :     UNREACHABLE();
     698             :     return;
     699             :   }
     700             : 
     701        4303 :   v8::HandleScope scope(m_isolate);
     702        4303 :   v8::Context::Scope contextScope(debuggerContext());
     703             : 
     704             :   v8::Local<v8::String> scriptValue =
     705             :       v8::String::NewFromUtf8(m_isolate, DebuggerScript_js,
     706             :                               v8::NewStringType::kInternalized,
     707        4303 :                               sizeof(DebuggerScript_js))
     708        8606 :           .ToLocalChecked();
     709             :   v8::Local<v8::Value> value;
     710        8606 :   if (!m_inspector->compileAndRunInternalScript(debuggerContext(), scriptValue)
     711        8606 :            .ToLocal(&value)) {
     712           0 :     UNREACHABLE();
     713             :     return;
     714             :   }
     715             :   DCHECK(value->IsObject());
     716        8606 :   m_debuggerScript.Reset(m_isolate, value.As<v8::Object>());
     717        4303 : }
     718             : 
     719      412872 : v8::Local<v8::Context> V8Debugger::debuggerContext() const {
     720             :   DCHECK(!m_debuggerContext.IsEmpty());
     721      825744 :   return m_debuggerContext.Get(m_isolate);
     722             : }
     723             : 
     724          60 : v8::MaybeLocal<v8::Value> V8Debugger::getTargetScopes(
     725             :     v8::Local<v8::Context> context, v8::Local<v8::Value> value,
     726             :     ScopeTargetKind kind) {
     727          60 :   if (!enabled()) {
     728           0 :     UNREACHABLE();
     729             :     return v8::Local<v8::Value>::New(m_isolate, v8::Undefined(m_isolate));
     730             :   }
     731          60 :   v8::Local<v8::Value> argv[] = {value};
     732             :   v8::Local<v8::Value> scopesValue;
     733             : 
     734             :   const char* debuggerMethod = nullptr;
     735          60 :   switch (kind) {
     736             :     case FUNCTION:
     737             :       debuggerMethod = "getFunctionScopes";
     738          24 :       break;
     739             :     case GENERATOR:
     740             :       debuggerMethod = "getGeneratorScopes";
     741          36 :       break;
     742             :   }
     743             : 
     744         120 :   if (!callDebuggerMethod(debuggerMethod, 1, argv, true).ToLocal(&scopesValue))
     745           0 :     return v8::MaybeLocal<v8::Value>();
     746             :   v8::Local<v8::Value> copied;
     747          60 :   if (!copyValueFromDebuggerContext(m_isolate, debuggerContext(), context,
     748          60 :                                     scopesValue)
     749         180 :            .ToLocal(&copied) ||
     750          60 :       !copied->IsArray())
     751           0 :     return v8::MaybeLocal<v8::Value>();
     752          60 :   if (!markAsInternal(context, v8::Local<v8::Array>::Cast(copied),
     753          60 :                       V8InternalValueType::kScopeList))
     754           0 :     return v8::MaybeLocal<v8::Value>();
     755          60 :   if (!markArrayEntriesAsInternal(context, v8::Local<v8::Array>::Cast(copied),
     756          60 :                                   V8InternalValueType::kScope))
     757           0 :     return v8::MaybeLocal<v8::Value>();
     758          60 :   return copied;
     759             : }
     760             : 
     761           0 : v8::MaybeLocal<v8::Value> V8Debugger::functionScopes(
     762             :     v8::Local<v8::Context> context, v8::Local<v8::Function> function) {
     763          24 :   return getTargetScopes(context, function, FUNCTION);
     764             : }
     765             : 
     766           0 : v8::MaybeLocal<v8::Value> V8Debugger::generatorScopes(
     767             :     v8::Local<v8::Context> context, v8::Local<v8::Value> generator) {
     768          36 :   return getTargetScopes(context, generator, GENERATOR);
     769             : }
     770             : 
     771      106344 : v8::MaybeLocal<v8::Array> V8Debugger::internalProperties(
     772             :     v8::Local<v8::Context> context, v8::Local<v8::Value> value) {
     773             :   v8::Local<v8::Array> properties;
     774      212688 :   if (!v8::debug::GetInternalProperties(m_isolate, value).ToLocal(&properties))
     775           0 :     return v8::MaybeLocal<v8::Array>();
     776      106344 :   if (value->IsFunction()) {
     777             :     v8::Local<v8::Function> function = value.As<v8::Function>();
     778             :     v8::Local<v8::Object> location;
     779          30 :     if (buildLocation(context, function->ScriptId(),
     780             :                       function->GetScriptLineNumber(),
     781          30 :                       function->GetScriptColumnNumber())
     782          60 :             .ToLocal(&location)) {
     783             :       createDataProperty(
     784          24 :           context, properties, properties->Length(),
     785          48 :           toV8StringInternalized(m_isolate, "[[FunctionLocation]]"));
     786          24 :       createDataProperty(context, properties, properties->Length(), location);
     787             :     }
     788          30 :     if (function->IsGeneratorFunction()) {
     789           6 :       createDataProperty(context, properties, properties->Length(),
     790          12 :                          toV8StringInternalized(m_isolate, "[[IsGenerator]]"));
     791           6 :       createDataProperty(context, properties, properties->Length(),
     792          12 :                          v8::True(m_isolate));
     793             :     }
     794             :   }
     795             :   v8::Local<v8::Array> entries;
     796      212688 :   if (collectionsEntries(context, value).ToLocal(&entries)) {
     797         254 :     createDataProperty(context, properties, properties->Length(),
     798         508 :                        toV8StringInternalized(m_isolate, "[[Entries]]"));
     799         254 :     createDataProperty(context, properties, properties->Length(), entries);
     800             :   }
     801      106344 :   if (value->IsGeneratorObject()) {
     802             :     v8::Local<v8::Object> location;
     803         108 :     if (generatorObjectLocation(context, value).ToLocal(&location)) {
     804             :       createDataProperty(
     805          54 :           context, properties, properties->Length(),
     806         108 :           toV8StringInternalized(m_isolate, "[[GeneratorLocation]]"));
     807          54 :       createDataProperty(context, properties, properties->Length(), location);
     808             :     }
     809          54 :     if (!enabled()) return properties;
     810             :     v8::Local<v8::Value> scopes;
     811          36 :     if (generatorScopes(context, value).ToLocal(&scopes)) {
     812          36 :       createDataProperty(context, properties, properties->Length(),
     813          72 :                          toV8StringInternalized(m_isolate, "[[Scopes]]"));
     814          36 :       createDataProperty(context, properties, properties->Length(), scopes);
     815             :     }
     816             :   }
     817      106326 :   if (!enabled()) return properties;
     818      106032 :   if (value->IsFunction()) {
     819             :     v8::Local<v8::Function> function = value.As<v8::Function>();
     820          24 :     v8::Local<v8::Value> boundFunction = function->GetBoundFunction();
     821             :     v8::Local<v8::Value> scopes;
     822          48 :     if (boundFunction->IsUndefined() &&
     823             :         functionScopes(context, function).ToLocal(&scopes)) {
     824          24 :       createDataProperty(context, properties, properties->Length(),
     825          48 :                          toV8StringInternalized(m_isolate, "[[Scopes]]"));
     826          24 :       createDataProperty(context, properties, properties->Length(), scopes);
     827             :     }
     828             :   }
     829      106032 :   return properties;
     830             : }
     831             : 
     832         120 : std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace(
     833             :     v8::Local<v8::StackTrace> v8StackTrace) {
     834             :   return V8StackTraceImpl::create(this, currentContextGroupId(), v8StackTrace,
     835         120 :                                   V8StackTraceImpl::maxCallStackSizeToCapture);
     836             : }
     837             : 
     838        4543 : void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) {
     839        4543 :   if (depth <= 0)
     840             :     m_maxAsyncCallStackDepthMap.erase(agent);
     841             :   else
     842         168 :     m_maxAsyncCallStackDepthMap[agent] = depth;
     843             : 
     844             :   int maxAsyncCallStackDepth = 0;
     845        9254 :   for (const auto& pair : m_maxAsyncCallStackDepthMap) {
     846         168 :     if (pair.second > maxAsyncCallStackDepth)
     847             :       maxAsyncCallStackDepth = pair.second;
     848             :   }
     849             : 
     850        9086 :   if (m_maxAsyncCallStackDepth == maxAsyncCallStackDepth) return;
     851         216 :   m_maxAsyncCallStackDepth = maxAsyncCallStackDepth;
     852         216 :   if (!maxAsyncCallStackDepth) allAsyncTasksCanceled();
     853             : }
     854             : 
     855       36980 : void V8Debugger::asyncTaskCreatedForStack(void* task, void* parentTask) {
     856       68488 :   if (!m_maxAsyncCallStackDepth) return;
     857        9264 :   if (parentTask) m_parentTask[task] = parentTask;
     858        5472 :   v8::HandleScope scope(m_isolate);
     859             :   std::shared_ptr<AsyncStackTrace> asyncCreation =
     860       10944 :       AsyncStackTrace::capture(this, currentContextGroupId(), String16(), 1);
     861             :   // Passing one as maxStackSize forces no async chain for the new stack.
     862        5472 :   if (asyncCreation && !asyncCreation->isEmpty()) {
     863             :     m_asyncTaskCreationStacks[task] = asyncCreation;
     864        3516 :     m_allAsyncStacks.push_back(std::move(asyncCreation));
     865        3516 :     ++m_asyncStacksCount;
     866        3516 :     collectOldAsyncStacksIfNeeded();
     867        5472 :   }
     868             : }
     869             : 
     870        1482 : void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task,
     871             :                                     bool recurring) {
     872        2964 :   asyncTaskScheduledForStack(toString16(taskName), task, recurring);
     873        1482 :   asyncTaskCandidateForStepping(task);
     874        1482 : }
     875             : 
     876           0 : void V8Debugger::asyncTaskCanceled(void* task) {
     877           0 :   asyncTaskCanceledForStack(task);
     878             :   asyncTaskCanceledForStepping(task);
     879           0 : }
     880             : 
     881        1482 : void V8Debugger::asyncTaskStarted(void* task) {
     882        1482 :   asyncTaskStartedForStack(task);
     883             :   asyncTaskStartedForStepping(task);
     884        1482 : }
     885             : 
     886        1482 : void V8Debugger::asyncTaskFinished(void* task) {
     887        1482 :   asyncTaskFinishedForStack(task);
     888             :   asyncTaskFinishedForStepping(task);
     889        1482 : }
     890             : 
     891       46124 : void V8Debugger::asyncTaskScheduledForStack(const String16& taskName,
     892             :                                             void* task, bool recurring) {
     893       85612 :   if (!m_maxAsyncCallStackDepth) return;
     894        6636 :   v8::HandleScope scope(m_isolate);
     895             :   std::shared_ptr<AsyncStackTrace> asyncStack =
     896             :       AsyncStackTrace::capture(this, currentContextGroupId(), taskName,
     897        6636 :                                V8StackTraceImpl::maxCallStackSizeToCapture);
     898        6636 :   if (asyncStack) {
     899             :     m_asyncTaskStacks[task] = asyncStack;
     900        6252 :     if (recurring) m_recurringTasks.insert(task);
     901        6252 :     m_allAsyncStacks.push_back(std::move(asyncStack));
     902        6252 :     ++m_asyncStacksCount;
     903        6252 :     collectOldAsyncStacksIfNeeded();
     904        6636 :   }
     905             : }
     906             : 
     907        2022 : void V8Debugger::asyncTaskCanceledForStack(void* task) {
     908        4044 :   if (!m_maxAsyncCallStackDepth) return;
     909             :   m_asyncTaskStacks.erase(task);
     910             :   m_recurringTasks.erase(task);
     911             :   m_parentTask.erase(task);
     912             :   m_asyncTaskCreationStacks.erase(task);
     913             : }
     914             : 
     915       20460 : void V8Debugger::asyncTaskStartedForStack(void* task) {
     916       36000 :   if (!m_maxAsyncCallStackDepth) return;
     917        4920 :   m_currentTasks.push_back(task);
     918             :   auto parentIt = m_parentTask.find(task);
     919             :   AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(
     920        4920 :       parentIt == m_parentTask.end() ? task : parentIt->second);
     921             :   // Needs to support following order of events:
     922             :   // - asyncTaskScheduled
     923             :   //   <-- attached here -->
     924             :   // - asyncTaskStarted
     925             :   // - asyncTaskCanceled <-- canceled before finished
     926             :   //   <-- async stack requested here -->
     927             :   // - asyncTaskFinished
     928        4920 :   std::weak_ptr<AsyncStackTrace> asyncParent;
     929        4920 :   if (stackIt != m_asyncTaskStacks.end()) asyncParent = stackIt->second;
     930             :   auto itCreation = m_asyncTaskCreationStacks.find(task);
     931        9840 :   if (asyncParent.lock() && itCreation != m_asyncTaskCreationStacks.end()) {
     932        4584 :     m_currentAsyncCreation.push_back(itCreation->second.lock());
     933             :   } else {
     934        2628 :     m_currentAsyncCreation.emplace_back();
     935             :   }
     936        9840 :   m_currentAsyncParent.push_back(asyncParent.lock());
     937             : }
     938             : 
     939       20460 : void V8Debugger::asyncTaskFinishedForStack(void* task) {
     940       20460 :   if (!m_maxAsyncCallStackDepth) return;
     941             :   // We could start instrumenting half way and the stack is empty.
     942        9864 :   if (!m_currentTasks.size()) return;
     943             :   DCHECK(m_currentTasks.back() == task);
     944             :   m_currentTasks.pop_back();
     945             : 
     946             :   DCHECK(m_currentAsyncParent.size() == m_currentAsyncCreation.size());
     947             :   m_currentAsyncParent.pop_back();
     948             :   m_currentAsyncCreation.pop_back();
     949             : 
     950        4920 :   if (m_recurringTasks.find(task) == m_recurringTasks.end()) {
     951        2022 :     asyncTaskCanceledForStack(task);
     952             :   }
     953             : }
     954             : 
     955       15458 : void V8Debugger::asyncTaskCandidateForStepping(void* task) {
     956       15458 :   if (!m_stepIntoAsyncCallback) return;
     957             :   DCHECK(m_targetContextGroupId);
     958          72 :   if (currentContextGroupId() != m_targetContextGroupId) return;
     959          72 :   m_taskWithScheduledBreak = task;
     960          72 :   v8::debug::ClearStepping(m_isolate);
     961          72 :   m_stepIntoAsyncCallback->sendSuccess();
     962             :   m_stepIntoAsyncCallback.reset();
     963             : }
     964             : 
     965           0 : void V8Debugger::asyncTaskStartedForStepping(void* task) {
     966       20460 :   if (m_breakRequested) return;
     967       20460 :   if (task != m_taskWithScheduledBreak) return;
     968          66 :   v8::debug::DebugBreak(m_isolate);
     969             : }
     970             : 
     971           0 : void V8Debugger::asyncTaskFinishedForStepping(void* task) {
     972       20460 :   if (task != m_taskWithScheduledBreak) return;
     973          66 :   m_taskWithScheduledBreak = nullptr;
     974          66 :   if (m_breakRequested) return;
     975          66 :   v8::debug::CancelDebugBreak(m_isolate);
     976             : }
     977             : 
     978           0 : void V8Debugger::asyncTaskCanceledForStepping(void* task) {
     979           0 :   if (task != m_taskWithScheduledBreak) return;
     980           0 :   m_taskWithScheduledBreak = nullptr;
     981             : }
     982             : 
     983        4399 : void V8Debugger::allAsyncTasksCanceled() {
     984             :   m_asyncTaskStacks.clear();
     985             :   m_recurringTasks.clear();
     986             :   m_currentAsyncParent.clear();
     987             :   m_currentAsyncCreation.clear();
     988             :   m_currentTasks.clear();
     989             :   m_parentTask.clear();
     990             :   m_asyncTaskCreationStacks.clear();
     991             : 
     992             :   m_framesCache.clear();
     993             :   m_allAsyncStacks.clear();
     994        4399 :   m_asyncStacksCount = 0;
     995        4399 : }
     996             : 
     997          30 : void V8Debugger::muteScriptParsedEvents() {
     998          30 :   ++m_ignoreScriptParsedEventsCounter;
     999          30 : }
    1000             : 
    1001          30 : void V8Debugger::unmuteScriptParsedEvents() {
    1002          30 :   --m_ignoreScriptParsedEventsCounter;
    1003             :   DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0);
    1004          30 : }
    1005             : 
    1006        7334 : std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace(
    1007             :     bool fullStack) {
    1008        7334 :   if (!m_isolate->InContext()) return nullptr;
    1009             : 
    1010        7334 :   v8::HandleScope handles(m_isolate);
    1011        7334 :   int contextGroupId = currentContextGroupId();
    1012        7334 :   if (!contextGroupId) return nullptr;
    1013             : 
    1014             :   int stackSize = 1;
    1015        7334 :   if (fullStack || m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) {
    1016             :     stackSize = V8StackTraceImpl::maxCallStackSizeToCapture;
    1017             :   }
    1018        7334 :   return V8StackTraceImpl::capture(this, contextGroupId, stackSize);
    1019             : }
    1020             : 
    1021       19634 : int V8Debugger::currentContextGroupId() {
    1022       19634 :   if (!m_isolate->InContext()) return 0;
    1023       19634 :   return m_inspector->contextGroupId(m_isolate->GetCurrentContext());
    1024             : }
    1025             : 
    1026       10092 : void V8Debugger::collectOldAsyncStacksIfNeeded() {
    1027       20184 :   if (m_asyncStacksCount <= m_maxAsyncCallStacks) return;
    1028             :   int halfOfLimitRoundedUp =
    1029         468 :       m_maxAsyncCallStacks / 2 + m_maxAsyncCallStacks % 2;
    1030        2028 :   while (m_asyncStacksCount > halfOfLimitRoundedUp) {
    1031             :     m_allAsyncStacks.pop_front();
    1032        1092 :     --m_asyncStacksCount;
    1033             :   }
    1034         468 :   cleanupExpiredWeakPointers(m_asyncTaskStacks);
    1035         468 :   cleanupExpiredWeakPointers(m_asyncTaskCreationStacks);
    1036        1362 :   for (auto it = m_recurringTasks.begin(); it != m_recurringTasks.end();) {
    1037         852 :     if (m_asyncTaskStacks.find(*it) == m_asyncTaskStacks.end()) {
    1038             :       it = m_recurringTasks.erase(it);
    1039             :     } else {
    1040             :       ++it;
    1041             :     }
    1042             :   }
    1043        1260 :   for (auto it = m_parentTask.begin(); it != m_parentTask.end();) {
    1044         648 :     if (m_asyncTaskCreationStacks.find(it->second) ==
    1045             :         m_asyncTaskCreationStacks.end()) {
    1046             :       it = m_parentTask.erase(it);
    1047             :     } else {
    1048             :       ++it;
    1049             :     }
    1050             :   }
    1051         468 :   cleanupExpiredWeakPointers(m_framesCache);
    1052             : }
    1053             : 
    1054       46529 : std::shared_ptr<StackFrame> V8Debugger::symbolize(
    1055             :     v8::Local<v8::StackFrame> v8Frame) {
    1056             :   auto it = m_framesCache.end();
    1057       46529 :   int frameId = 0;
    1058       46529 :   if (m_maxAsyncCallStackDepth) {
    1059        6378 :     frameId = v8::debug::GetStackFrameId(v8Frame);
    1060             :     it = m_framesCache.find(frameId);
    1061             :   }
    1062       47927 :   if (it != m_framesCache.end() && it->second.lock()) return it->second.lock();
    1063       90262 :   std::shared_ptr<StackFrame> frame(new StackFrame(v8Frame));
    1064             :   // TODO(clemensh): Figure out a way to do this translation only right before
    1065             :   // sending the stack trace over wire.
    1066       45131 :   if (v8Frame->IsWasm()) frame->translate(&m_wasmTranslation);
    1067       45131 :   if (m_maxAsyncCallStackDepth) {
    1068        4980 :     m_framesCache[frameId] = frame;
    1069             :   }
    1070             :   return frame;
    1071             : }
    1072             : 
    1073         324 : void V8Debugger::setMaxAsyncTaskStacksForTest(int limit) {
    1074         324 :   m_maxAsyncCallStacks = 0;
    1075         324 :   collectOldAsyncStacksIfNeeded();
    1076         324 :   m_maxAsyncCallStacks = limit;
    1077         324 : }
    1078             : 
    1079          36 : void V8Debugger::dumpAsyncTaskStacksStateForTest() {
    1080          36 :   fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount);
    1081          36 :   fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size());
    1082             :   fprintf(stdout, "Created async tasks: %zu\n",
    1083          36 :           m_asyncTaskCreationStacks.size());
    1084          36 :   fprintf(stdout, "Async tasks with parent: %zu\n", m_parentTask.size());
    1085          36 :   fprintf(stdout, "Recurring async tasks: %zu\n", m_recurringTasks.size());
    1086          36 :   fprintf(stdout, "\n");
    1087          36 : }
    1088             : 
    1089             : }  // namespace v8_inspector

Generated by: LCOV version 1.10