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

Generated by: LCOV version 1.10