Index: src/inspector/v8-debugger-agent-impl.cc |
diff --git a/src/inspector/v8-debugger-agent-impl.cc b/src/inspector/v8-debugger-agent-impl.cc |
index 664c2ed095a0545d2ee655c3b15178e21e056f3f..1ad7389da62ffe74e35a8accd28052f2a17db435 100644 |
--- a/src/inspector/v8-debugger-agent-impl.cc |
+++ b/src/inspector/v8-debugger-agent-impl.cc |
@@ -131,11 +131,9 @@ V8DebuggerAgentImpl::V8DebuggerAgentImpl( |
m_state(state), |
m_frontend(frontendChannel), |
m_isolate(m_inspector->isolate()), |
- m_breakReason(protocol::Debugger::Paused::ReasonEnum::Other), |
m_scheduledDebuggerStep(NoStep), |
m_javaScriptPauseScheduled(false), |
m_recursionLevelForStepOut(0) { |
- clearBreakDetails(); |
} |
V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {} |
@@ -589,6 +587,22 @@ Response V8DebuggerAgentImpl::getScriptSource(const String16& scriptId, |
return Response::OK(); |
} |
+void V8DebuggerAgentImpl::pushBreakDetails( |
+ const String16& breakReason, |
+ std::unique_ptr<protocol::DictionaryValue> breakAuxData) { |
+ m_breakReason.push_back(std::make_pair(breakReason, std::move(breakAuxData))); |
+} |
+ |
+void V8DebuggerAgentImpl::popBreakDetails() { |
+ if (m_breakReason.empty()) return; |
+ m_breakReason.pop_back(); |
+} |
+ |
+void V8DebuggerAgentImpl::clearBreakDetails() { |
+ std::vector<BreakReason> emptyBreakReason; |
+ m_breakReason.swap(emptyBreakReason); |
+} |
+ |
void V8DebuggerAgentImpl::schedulePauseOnNextStatement( |
const String16& breakReason, |
std::unique_ptr<protocol::DictionaryValue> data) { |
@@ -596,9 +610,8 @@ void V8DebuggerAgentImpl::schedulePauseOnNextStatement( |
m_javaScriptPauseScheduled || isPaused() || |
!m_debugger->breakpointsActivated()) |
return; |
- m_breakReason = breakReason; |
- m_breakAuxData = std::move(data); |
- m_debugger->setPauseOnNextStatement(true); |
+ if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(true); |
+ pushBreakDetails(breakReason, std::move(data)); |
} |
void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() { |
@@ -606,14 +619,13 @@ void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() { |
if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || |
isPaused()) |
return; |
- clearBreakDetails(); |
m_debugger->setPauseOnNextStatement(true); |
} |
void V8DebuggerAgentImpl::cancelPauseOnNextStatement() { |
if (m_javaScriptPauseScheduled || isPaused()) return; |
- clearBreakDetails(); |
- m_debugger->setPauseOnNextStatement(false); |
+ popBreakDetails(); |
+ if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(false); |
} |
Response V8DebuggerAgentImpl::pause() { |
@@ -1071,32 +1083,37 @@ void V8DebuggerAgentImpl::didPause(int contextId, |
m_pausedCallFrames.swap(frames); |
v8::HandleScope handles(m_isolate); |
+ std::vector<BreakReason> hitReasons; |
+ |
if (isOOMBreak) { |
- m_breakReason = protocol::Debugger::Paused::ReasonEnum::OOM; |
- m_breakAuxData = nullptr; |
+ hitReasons.push_back( |
+ std::make_pair(protocol::Debugger::Paused::ReasonEnum::OOM, nullptr)); |
} else if (!exception.IsEmpty()) { |
InjectedScript* injectedScript = nullptr; |
m_session->findInjectedScript(contextId, injectedScript); |
if (injectedScript) { |
- m_breakReason = |
+ String16 breakReason = |
isPromiseRejection |
? protocol::Debugger::Paused::ReasonEnum::PromiseRejection |
: protocol::Debugger::Paused::ReasonEnum::Exception; |
std::unique_ptr<protocol::Runtime::RemoteObject> obj; |
injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false, |
&obj); |
+ std::unique_ptr<protocol::DictionaryValue> breakAuxData; |
if (obj) { |
- m_breakAuxData = obj->toValue(); |
- m_breakAuxData->setBoolean("uncaught", isUncaught); |
+ breakAuxData = obj->toValue(); |
+ breakAuxData->setBoolean("uncaught", isUncaught); |
} else { |
- m_breakAuxData = nullptr; |
+ breakAuxData = nullptr; |
} |
- // m_breakAuxData might be null after this. |
+ hitReasons.push_back( |
+ std::make_pair(breakReason, std::move(breakAuxData))); |
} |
} |
std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create(); |
+ bool hasDebugCommandBreakpointReason = false; |
for (const auto& point : hitBreakpoints) { |
DebugServerBreakpointToBreakpointIdAndSourceMap::iterator |
breakpointIterator = m_serverBreakpoints.find(point); |
@@ -1105,17 +1122,46 @@ void V8DebuggerAgentImpl::didPause(int contextId, |
hitBreakpointIds->addItem(localId); |
BreakpointSource source = breakpointIterator->second.second; |
- if (m_breakReason == protocol::Debugger::Paused::ReasonEnum::Other && |
- source == DebugCommandBreakpointSource) |
- m_breakReason = protocol::Debugger::Paused::ReasonEnum::DebugCommand; |
+ if (!hasDebugCommandBreakpointReason && |
+ source == DebugCommandBreakpointSource) { |
+ hasDebugCommandBreakpointReason = true; |
+ hitReasons.push_back(std::make_pair( |
+ protocol::Debugger::Paused::ReasonEnum::DebugCommand, nullptr)); |
+ } |
} |
} |
+ for (size_t i = 0; i < m_breakReason.size(); ++i) { |
+ hitReasons.push_back(std::move(m_breakReason[i])); |
+ } |
+ clearBreakDetails(); |
+ |
+ String16 breakReason = protocol::Debugger::Paused::ReasonEnum::Other; |
+ std::unique_ptr<protocol::DictionaryValue> breakAuxData; |
+ if (hitReasons.size() == 1) { |
+ breakReason = hitReasons[0].first; |
+ breakAuxData = std::move(hitReasons[0].second); |
+ } else if (hitReasons.size() > 1) { |
+ breakReason = protocol::Debugger::Paused::ReasonEnum::Ambiguous; |
+ std::unique_ptr<protocol::ListValue> reasons = |
+ protocol::ListValue::create(); |
+ for (size_t i = 0; i < hitReasons.size(); ++i) { |
+ std::unique_ptr<protocol::DictionaryValue> reason = |
+ protocol::DictionaryValue::create(); |
+ reason->setString("reason", hitReasons[i].first); |
+ if (hitReasons[i].second) |
+ reason->setObject("auxData", std::move(hitReasons[i].second)); |
+ reasons->pushValue(std::move(reason)); |
+ } |
+ breakAuxData = protocol::DictionaryValue::create(); |
+ breakAuxData->setArray("reasons", std::move(reasons)); |
+ } |
+ |
std::unique_ptr<Array<CallFrame>> protocolCallFrames; |
Response response = currentCallFrames(&protocolCallFrames); |
if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create(); |
- m_frontend.paused(std::move(protocolCallFrames), m_breakReason, |
- std::move(m_breakAuxData), std::move(hitBreakpointIds), |
+ m_frontend.paused(std::move(protocolCallFrames), breakReason, |
+ std::move(breakAuxData), std::move(hitBreakpointIds), |
currentAsyncStackTrace()); |
m_scheduledDebuggerStep = NoStep; |
m_javaScriptPauseScheduled = false; |
@@ -1137,10 +1183,13 @@ void V8DebuggerAgentImpl::breakProgram( |
const String16& breakReason, |
std::unique_ptr<protocol::DictionaryValue> data) { |
if (!enabled() || !m_debugger->canBreakProgram() || m_skipAllPauses) return; |
- m_breakReason = breakReason; |
- m_breakAuxData = std::move(data); |
+ std::vector<BreakReason> currentScheduledReason; |
+ currentScheduledReason.swap(m_breakReason); |
+ pushBreakDetails(breakReason, std::move(data)); |
m_scheduledDebuggerStep = NoStep; |
m_debugger->breakProgram(); |
+ popBreakDetails(); |
+ m_breakReason.swap(currentScheduledReason); |
} |
void V8DebuggerAgentImpl::breakProgramOnException( |
@@ -1152,11 +1201,6 @@ void V8DebuggerAgentImpl::breakProgramOnException( |
breakProgram(breakReason, std::move(data)); |
} |
-void V8DebuggerAgentImpl::clearBreakDetails() { |
- m_breakReason = protocol::Debugger::Paused::ReasonEnum::Other; |
- m_breakAuxData = nullptr; |
-} |
- |
void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId, |
int lineNumber, int columnNumber, |
BreakpointSource source, |