| 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 09c7b5842be7cc5b9ce57929f8603e6f46c30f3e..8cb5764968fea2bbc24e8f253ffe298853fcc0b6 100644
|
| --- a/src/inspector/v8-debugger-agent-impl.cc
|
| +++ b/src/inspector/v8-debugger-agent-impl.cc
|
| @@ -54,7 +54,6 @@ static const char skipAllPauses[] = "skipAllPauses";
|
|
|
| } // namespace DebuggerAgentState
|
|
|
| -static const int kMaxSkipStepFrameCount = 128;
|
| static const char kBacktraceObjectGroup[] = "backtrace";
|
| static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled";
|
| static const char kDebuggerNotPaused[] =
|
| @@ -134,13 +133,8 @@ V8DebuggerAgentImpl::V8DebuggerAgentImpl(
|
| m_isolate(m_inspector->isolate()),
|
| m_breakReason(protocol::Debugger::Paused::ReasonEnum::Other),
|
| m_scheduledDebuggerStep(NoStep),
|
| - m_skipNextDebuggerStepOut(false),
|
| m_javaScriptPauseScheduled(false),
|
| - m_steppingFromFramework(false),
|
| - m_pausingOnNativeEvent(false),
|
| - m_skippedStepFrameCount(0),
|
| m_recursionLevelForStepOut(0),
|
| - m_recursionLevelForStepFrame(0),
|
| m_skipAllPauses(false) {
|
| clearBreakDetails();
|
| }
|
| @@ -190,21 +184,17 @@ Response V8DebuggerAgentImpl::disable() {
|
| m_pausedContext.Reset();
|
| JavaScriptCallFrames emptyCallFrames;
|
| m_pausedCallFrames.swap(emptyCallFrames);
|
| - m_scripts.clear();
|
| m_blackboxedPositions.clear();
|
| + m_blackboxPattern.reset();
|
| + resetBlackboxedStateCache();
|
| + m_scripts.clear();
|
| m_breakpointIdToDebuggerBreakpointIds.clear();
|
| m_debugger->setAsyncCallStackDepth(this, 0);
|
| m_continueToLocationBreakpointId = String16();
|
| clearBreakDetails();
|
| m_scheduledDebuggerStep = NoStep;
|
| - m_skipNextDebuggerStepOut = false;
|
| m_javaScriptPauseScheduled = false;
|
| - m_steppingFromFramework = false;
|
| - m_pausingOnNativeEvent = false;
|
| - m_skippedStepFrameCount = 0;
|
| - m_recursionLevelForStepFrame = 0;
|
| m_skipAllPauses = false;
|
| - m_blackboxPattern = nullptr;
|
| m_state->remove(DebuggerAgentState::blackboxPattern);
|
| m_enabled = false;
|
| m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
|
| @@ -434,28 +424,10 @@ Response V8DebuggerAgentImpl::continueToLocation(
|
| return resume();
|
| }
|
|
|
| -bool V8DebuggerAgentImpl::isCurrentCallStackEmptyOrBlackboxed() {
|
| - DCHECK(enabled());
|
| - JavaScriptCallFrames callFrames = m_debugger->currentCallFrames();
|
| - for (size_t index = 0; index < callFrames.size(); ++index) {
|
| - if (!isCallFrameWithUnknownScriptOrBlackboxed(callFrames[index].get()))
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool V8DebuggerAgentImpl::isTopPausedCallFrameBlackboxed() {
|
| - DCHECK(enabled());
|
| - JavaScriptCallFrame* frame =
|
| - m_pausedCallFrames.size() ? m_pausedCallFrames[0].get() : nullptr;
|
| - return isCallFrameWithUnknownScriptOrBlackboxed(frame);
|
| -}
|
| -
|
| -bool V8DebuggerAgentImpl::isCallFrameWithUnknownScriptOrBlackboxed(
|
| - JavaScriptCallFrame* frame) {
|
| - if (!frame) return true;
|
| - ScriptsMap::iterator it =
|
| - m_scripts.find(String16::fromInteger(frame->sourceID()));
|
| +bool V8DebuggerAgentImpl::isFunctionBlackboxed(const String16& scriptId,
|
| + const v8::debug::Location& start,
|
| + const v8::debug::Location& end) {
|
| + ScriptsMap::iterator it = m_scripts.find(scriptId);
|
| if (it == m_scripts.end()) {
|
| // Unknown scripts are blackboxed.
|
| return true;
|
| @@ -466,48 +438,24 @@ bool V8DebuggerAgentImpl::isCallFrameWithUnknownScriptOrBlackboxed(
|
| m_blackboxPattern->match(scriptSourceURL) != -1)
|
| return true;
|
| }
|
| - auto itBlackboxedPositions =
|
| - m_blackboxedPositions.find(String16::fromInteger(frame->sourceID()));
|
| + auto itBlackboxedPositions = m_blackboxedPositions.find(scriptId);
|
| if (itBlackboxedPositions == m_blackboxedPositions.end()) return false;
|
|
|
| const std::vector<std::pair<int, int>>& ranges =
|
| itBlackboxedPositions->second;
|
| - auto itRange = std::lower_bound(
|
| + auto itStartRange = std::lower_bound(
|
| ranges.begin(), ranges.end(),
|
| - std::make_pair(frame->line(), frame->column()), positionComparator);
|
| + std::make_pair(start.GetLineNumber(), start.GetColumnNumber()),
|
| + positionComparator);
|
| + auto itEndRange = std::lower_bound(
|
| + itStartRange, ranges.end(),
|
| + std::make_pair(end.GetLineNumber(), end.GetColumnNumber()),
|
| + positionComparator);
|
| // Ranges array contains positions in script where blackbox state is changed.
|
| // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is
|
| // blackboxed...
|
| - return std::distance(ranges.begin(), itRange) % 2;
|
| -}
|
| -
|
| -V8DebuggerAgentImpl::SkipPauseRequest
|
| -V8DebuggerAgentImpl::shouldSkipExceptionPause(
|
| - JavaScriptCallFrame* topCallFrame) {
|
| - if (m_steppingFromFramework) return RequestNoSkip;
|
| - if (isCallFrameWithUnknownScriptOrBlackboxed(topCallFrame))
|
| - return RequestContinue;
|
| - return RequestNoSkip;
|
| -}
|
| -
|
| -V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::shouldSkipStepPause(
|
| - JavaScriptCallFrame* topCallFrame) {
|
| - if (m_steppingFromFramework) return RequestNoSkip;
|
| -
|
| - if (m_skipNextDebuggerStepOut) {
|
| - m_skipNextDebuggerStepOut = false;
|
| - if (m_scheduledDebuggerStep == StepOut) return RequestStepOut;
|
| - }
|
| -
|
| - if (!isCallFrameWithUnknownScriptOrBlackboxed(topCallFrame))
|
| - return RequestNoSkip;
|
| -
|
| - if (m_skippedStepFrameCount >= kMaxSkipStepFrameCount) return RequestStepOut;
|
| -
|
| - if (!m_skippedStepFrameCount) m_recursionLevelForStepFrame = 1;
|
| -
|
| - ++m_skippedStepFrameCount;
|
| - return RequestStepFrame;
|
| + return itStartRange == itEndRange &&
|
| + std::distance(ranges.begin(), itStartRange) % 2;
|
| }
|
|
|
| std::unique_ptr<protocol::Debugger::Location>
|
| @@ -641,8 +589,6 @@ void V8DebuggerAgentImpl::schedulePauseOnNextStatement(
|
| return;
|
| m_breakReason = breakReason;
|
| m_breakAuxData = std::move(data);
|
| - m_pausingOnNativeEvent = true;
|
| - m_skipNextDebuggerStepOut = false;
|
| m_debugger->setPauseOnNextStatement(true);
|
| }
|
|
|
| @@ -652,16 +598,12 @@ void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() {
|
| m_debugger->isPaused())
|
| return;
|
| clearBreakDetails();
|
| - m_pausingOnNativeEvent = false;
|
| - m_skippedStepFrameCount = 0;
|
| - m_recursionLevelForStepFrame = 0;
|
| m_debugger->setPauseOnNextStatement(true);
|
| }
|
|
|
| void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
|
| if (m_javaScriptPauseScheduled || m_debugger->isPaused()) return;
|
| clearBreakDetails();
|
| - m_pausingOnNativeEvent = false;
|
| m_debugger->setPauseOnNextStatement(false);
|
| }
|
|
|
| @@ -672,8 +614,6 @@ Response V8DebuggerAgentImpl::pause() {
|
| clearBreakDetails();
|
| m_javaScriptPauseScheduled = true;
|
| m_scheduledDebuggerStep = NoStep;
|
| - m_skippedStepFrameCount = 0;
|
| - m_steppingFromFramework = false;
|
| m_debugger->setPauseOnNextStatement(true);
|
| return Response::OK();
|
| }
|
| @@ -681,7 +621,6 @@ Response V8DebuggerAgentImpl::pause() {
|
| Response V8DebuggerAgentImpl::resume() {
|
| if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
|
| m_scheduledDebuggerStep = NoStep;
|
| - m_steppingFromFramework = false;
|
| m_session->releaseObjectGroup(kBacktraceObjectGroup);
|
| m_debugger->continueProgram();
|
| return Response::OK();
|
| @@ -694,7 +633,6 @@ Response V8DebuggerAgentImpl::stepOver() {
|
| !m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr;
|
| if (frame && frame->isAtReturn()) return stepInto();
|
| m_scheduledDebuggerStep = StepOver;
|
| - m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
|
| m_session->releaseObjectGroup(kBacktraceObjectGroup);
|
| m_debugger->stepOverStatement();
|
| return Response::OK();
|
| @@ -703,7 +641,6 @@ Response V8DebuggerAgentImpl::stepOver() {
|
| Response V8DebuggerAgentImpl::stepInto() {
|
| if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
|
| m_scheduledDebuggerStep = StepInto;
|
| - m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
|
| m_session->releaseObjectGroup(kBacktraceObjectGroup);
|
| m_debugger->stepIntoStatement();
|
| return Response::OK();
|
| @@ -712,9 +649,7 @@ Response V8DebuggerAgentImpl::stepInto() {
|
| Response V8DebuggerAgentImpl::stepOut() {
|
| if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
|
| m_scheduledDebuggerStep = StepOut;
|
| - m_skipNextDebuggerStepOut = false;
|
| m_recursionLevelForStepOut = 1;
|
| - m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
|
| m_session->releaseObjectGroup(kBacktraceObjectGroup);
|
| m_debugger->stepOutOfFunction();
|
| return Response::OK();
|
| @@ -811,6 +746,7 @@ Response V8DebuggerAgentImpl::setBlackboxPatterns(
|
| std::unique_ptr<protocol::Array<String16>> patterns) {
|
| if (!patterns->length()) {
|
| m_blackboxPattern = nullptr;
|
| + resetBlackboxedStateCache();
|
| m_state->remove(DebuggerAgentState::blackboxPattern);
|
| return Response::OK();
|
| }
|
| @@ -826,6 +762,7 @@ Response V8DebuggerAgentImpl::setBlackboxPatterns(
|
| String16 pattern = patternBuilder.toString();
|
| Response response = setBlackboxPattern(pattern);
|
| if (!response.isSuccess()) return response;
|
| + resetBlackboxedStateCache();
|
| m_state->setString(DebuggerAgentState::blackboxPattern, pattern);
|
| return Response::OK();
|
| }
|
| @@ -839,15 +776,23 @@ Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) {
|
| return Response::OK();
|
| }
|
|
|
| +void V8DebuggerAgentImpl::resetBlackboxedStateCache() {
|
| + for (const auto& it : m_scripts) {
|
| + it.second->resetBlackboxedStateCache();
|
| + }
|
| +}
|
| +
|
| Response V8DebuggerAgentImpl::setBlackboxedRanges(
|
| const String16& scriptId,
|
| std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>>
|
| inPositions) {
|
| - if (m_scripts.find(scriptId) == m_scripts.end())
|
| + auto it = m_scripts.find(scriptId);
|
| + if (it == m_scripts.end())
|
| return Response::Error("No script with passed id.");
|
|
|
| if (!inPositions->length()) {
|
| m_blackboxedPositions.erase(scriptId);
|
| + it->second->resetBlackboxedStateCache();
|
| return Response::OK();
|
| }
|
|
|
| @@ -873,6 +818,7 @@ Response V8DebuggerAgentImpl::setBlackboxedRanges(
|
| }
|
|
|
| m_blackboxedPositions[scriptId] = positions;
|
| + it->second->resetBlackboxedStateCache();
|
| return Response::OK();
|
| }
|
|
|
| @@ -901,27 +847,6 @@ void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) {
|
| // switch stepping to step into a next JS task, as if we exited to a
|
| // blackboxed framework.
|
| m_scheduledDebuggerStep = StepInto;
|
| - m_skipNextDebuggerStepOut = false;
|
| - }
|
| - }
|
| - if (m_recursionLevelForStepFrame) {
|
| - m_recursionLevelForStepFrame += step;
|
| - if (!m_recursionLevelForStepFrame) {
|
| - // We have walked through a blackboxed framework and got back to where we
|
| - // started.
|
| - // If there was no stepping scheduled, we should cancel the stepping
|
| - // explicitly,
|
| - // since there may be a scheduled StepFrame left.
|
| - // Otherwise, if we were stepping in/over, the StepFrame will stop at the
|
| - // right location,
|
| - // whereas if we were stepping out, we should continue doing so after
|
| - // debugger pauses
|
| - // from the old StepFrame.
|
| - m_skippedStepFrameCount = 0;
|
| - if (m_scheduledDebuggerStep == NoStep)
|
| - m_debugger->clearStepping();
|
| - else if (m_scheduledDebuggerStep == StepOut)
|
| - m_skipNextDebuggerStepOut = true;
|
| }
|
| }
|
| }
|
| @@ -1072,6 +997,11 @@ void V8DebuggerAgentImpl::didParseSource(
|
| ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
|
| DCHECK(scriptIterator != m_scripts.end());
|
| V8DebuggerScript* scriptRef = scriptIterator->second.get();
|
| + // V8 could create functions for parsed scripts before reporting and asks
|
| + // inspector about blackboxed state, we should reset state each time when we
|
| + // make any change that change isFunctionBlackboxed output - adding parsed
|
| + // script is changing.
|
| + scriptRef->resetBlackboxedStateCache();
|
|
|
| Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL();
|
| Maybe<protocol::DictionaryValue> executionContextAuxDataParam(
|
| @@ -1121,35 +1051,19 @@ void V8DebuggerAgentImpl::didParseSource(
|
| }
|
| }
|
|
|
| -V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(
|
| - v8::Local<v8::Context> context, v8::Local<v8::Value> exception,
|
| - const std::vector<String16>& hitBreakpoints, bool isPromiseRejection,
|
| - bool isUncaught, bool isOOMBreak) {
|
| - JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(1);
|
| - JavaScriptCallFrame* topCallFrame =
|
| - !callFrames.empty() ? callFrames.begin()->get() : nullptr;
|
| -
|
| - V8DebuggerAgentImpl::SkipPauseRequest result;
|
| - if (isOOMBreak)
|
| - result = RequestNoSkip;
|
| - else if (m_skipAllPauses)
|
| - result = RequestContinue;
|
| - else if (!hitBreakpoints.empty())
|
| - result = RequestNoSkip; // Don't skip explicit breakpoints even if set in
|
| - // frameworks.
|
| - else if (!exception.IsEmpty())
|
| - result = shouldSkipExceptionPause(topCallFrame);
|
| - else if (m_scheduledDebuggerStep != NoStep || m_javaScriptPauseScheduled ||
|
| - m_pausingOnNativeEvent)
|
| - result = shouldSkipStepPause(topCallFrame);
|
| - else
|
| - result = RequestNoSkip;
|
| -
|
| - m_skipNextDebuggerStepOut = false;
|
| - if (result != RequestNoSkip) return result;
|
| - // Skip pauses inside V8 internal scripts and on syntax errors.
|
| - if (!topCallFrame) return RequestContinue;
|
| -
|
| +bool V8DebuggerAgentImpl::didPause(v8::Local<v8::Context> context,
|
| + v8::Local<v8::Value> exception,
|
| + const std::vector<String16>& hitBreakpoints,
|
| + bool isPromiseRejection, bool isUncaught,
|
| + bool isOOMBreak) {
|
| + if (!isOOMBreak) {
|
| + if (m_skipAllPauses) return false;
|
| + JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(1);
|
| + JavaScriptCallFrame* topCallFrame =
|
| + !callFrames.empty() ? callFrames.begin()->get() : nullptr;
|
| + // Skip pauses inside V8 internal scripts and on syntax errors.
|
| + if (!topCallFrame) return false;
|
| + }
|
| DCHECK(m_pausedContext.IsEmpty());
|
| JavaScriptCallFrames frames = m_debugger->currentCallFrames();
|
| m_pausedCallFrames.swap(frames);
|
| @@ -1205,16 +1119,12 @@ V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(
|
| currentAsyncStackTrace());
|
| m_scheduledDebuggerStep = NoStep;
|
| m_javaScriptPauseScheduled = false;
|
| - m_steppingFromFramework = false;
|
| - m_pausingOnNativeEvent = false;
|
| - m_skippedStepFrameCount = 0;
|
| - m_recursionLevelForStepFrame = 0;
|
|
|
| if (!m_continueToLocationBreakpointId.isEmpty()) {
|
| m_debugger->removeBreakpoint(m_continueToLocationBreakpointId);
|
| m_continueToLocationBreakpointId = "";
|
| }
|
| - return result;
|
| + return true;
|
| }
|
|
|
| void V8DebuggerAgentImpl::didContinue() {
|
| @@ -1229,14 +1139,11 @@ void V8DebuggerAgentImpl::breakProgram(
|
| const String16& breakReason,
|
| std::unique_ptr<protocol::DictionaryValue> data) {
|
| if (!enabled() || m_skipAllPauses || !m_pausedContext.IsEmpty() ||
|
| - isCurrentCallStackEmptyOrBlackboxed() ||
|
| - !m_debugger->breakpointsActivated())
|
| + !m_debugger->canBreakProgram())
|
| return;
|
| m_breakReason = breakReason;
|
| m_breakAuxData = std::move(data);
|
| m_scheduledDebuggerStep = NoStep;
|
| - m_steppingFromFramework = false;
|
| - m_pausingOnNativeEvent = false;
|
| m_debugger->breakProgram();
|
| }
|
|
|
| @@ -1274,8 +1181,9 @@ void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId,
|
| void V8DebuggerAgentImpl::reset() {
|
| if (!enabled()) return;
|
| m_scheduledDebuggerStep = NoStep;
|
| - m_scripts.clear();
|
| m_blackboxedPositions.clear();
|
| + resetBlackboxedStateCache();
|
| + m_scripts.clear();
|
| m_breakpointIdToDebuggerBreakpointIds.clear();
|
| }
|
|
|
|
|