Index: src/inspector/V8DebuggerAgentImpl.cpp |
diff --git a/src/inspector/V8DebuggerAgentImpl.cpp b/src/inspector/V8DebuggerAgentImpl.cpp |
deleted file mode 100644 |
index 58bcd610c3cdcf163be85753bffea2f7de8b9380..0000000000000000000000000000000000000000 |
--- a/src/inspector/V8DebuggerAgentImpl.cpp |
+++ /dev/null |
@@ -1,1250 +0,0 @@ |
-// Copyright 2015 the V8 project authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "src/inspector/V8DebuggerAgentImpl.h" |
- |
-#include "src/inspector/InjectedScript.h" |
-#include "src/inspector/InspectedContext.h" |
-#include "src/inspector/JavaScriptCallFrame.h" |
-#include "src/inspector/RemoteObjectId.h" |
-#include "src/inspector/ScriptBreakpoint.h" |
-#include "src/inspector/SearchUtil.h" |
-#include "src/inspector/StringUtil.h" |
-#include "src/inspector/V8Debugger.h" |
-#include "src/inspector/V8DebuggerScript.h" |
-#include "src/inspector/V8InspectorImpl.h" |
-#include "src/inspector/V8InspectorSessionImpl.h" |
-#include "src/inspector/V8Regex.h" |
-#include "src/inspector/V8RuntimeAgentImpl.h" |
-#include "src/inspector/V8StackTraceImpl.h" |
-#include "src/inspector/protocol/Protocol.h" |
- |
-#include "include/v8-inspector.h" |
- |
-#include <algorithm> |
- |
-namespace v8_inspector { |
- |
-using protocol::Array; |
-using protocol::Maybe; |
-using protocol::Debugger::BreakpointId; |
-using protocol::Debugger::CallFrame; |
-using protocol::Runtime::ExceptionDetails; |
-using protocol::Runtime::ScriptId; |
-using protocol::Runtime::StackTrace; |
-using protocol::Runtime::RemoteObject; |
- |
-namespace DebuggerAgentState { |
-static const char javaScriptBreakpoints[] = "javaScriptBreakopints"; |
-static const char pauseOnExceptionsState[] = "pauseOnExceptionsState"; |
-static const char asyncCallStackDepth[] = "asyncCallStackDepth"; |
-static const char blackboxPattern[] = "blackboxPattern"; |
-static const char debuggerEnabled[] = "debuggerEnabled"; |
- |
-// Breakpoint properties. |
-static const char url[] = "url"; |
-static const char isRegex[] = "isRegex"; |
-static const char lineNumber[] = "lineNumber"; |
-static const char columnNumber[] = "columnNumber"; |
-static const char condition[] = "condition"; |
-static const char skipAllPauses[] = "skipAllPauses"; |
- |
-} // namespace DebuggerAgentState; |
- |
-static const int maxSkipStepFrameCount = 128; |
-static const char backtraceObjectGroup[] = "backtrace"; |
- |
-static String16 breakpointIdSuffix( |
- V8DebuggerAgentImpl::BreakpointSource source) { |
- switch (source) { |
- case V8DebuggerAgentImpl::UserBreakpointSource: |
- break; |
- case V8DebuggerAgentImpl::DebugCommandBreakpointSource: |
- return ":debug"; |
- case V8DebuggerAgentImpl::MonitorCommandBreakpointSource: |
- return ":monitor"; |
- } |
- return String16(); |
-} |
- |
-static String16 generateBreakpointId( |
- const String16& scriptId, int lineNumber, int columnNumber, |
- V8DebuggerAgentImpl::BreakpointSource source) { |
- return scriptId + ":" + String16::fromInteger(lineNumber) + ":" + |
- String16::fromInteger(columnNumber) + breakpointIdSuffix(source); |
-} |
- |
-static bool positionComparator(const std::pair<int, int>& a, |
- const std::pair<int, int>& b) { |
- if (a.first != b.first) return a.first < b.first; |
- return a.second < b.second; |
-} |
- |
-static bool hasInternalError(ErrorString* errorString, bool hasError) { |
- if (hasError) *errorString = "Internal error"; |
- return hasError; |
-} |
- |
-static std::unique_ptr<protocol::Debugger::Location> buildProtocolLocation( |
- const String16& scriptId, int lineNumber, int columnNumber) { |
- return protocol::Debugger::Location::create() |
- .setScriptId(scriptId) |
- .setLineNumber(lineNumber) |
- .setColumnNumber(columnNumber) |
- .build(); |
-} |
- |
-V8DebuggerAgentImpl::V8DebuggerAgentImpl( |
- V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, |
- protocol::DictionaryValue* state) |
- : m_inspector(session->inspector()), |
- m_debugger(m_inspector->debugger()), |
- m_session(session), |
- m_enabled(false), |
- m_state(state), |
- m_frontend(frontendChannel), |
- 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(); |
-} |
- |
-V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {} |
- |
-bool V8DebuggerAgentImpl::checkEnabled(ErrorString* errorString) { |
- if (enabled()) return true; |
- *errorString = "Debugger agent is not enabled"; |
- return false; |
-} |
- |
-void V8DebuggerAgentImpl::enable() { |
- // m_inspector->addListener may result in reporting all parsed scripts to |
- // the agent so it should already be in enabled state by then. |
- m_enabled = true; |
- m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true); |
- m_debugger->enable(); |
- |
- std::vector<std::unique_ptr<V8DebuggerScript>> compiledScripts; |
- m_debugger->getCompiledScripts(m_session->contextGroupId(), compiledScripts); |
- for (size_t i = 0; i < compiledScripts.size(); i++) |
- didParseSource(std::move(compiledScripts[i]), true); |
- |
- // FIXME(WK44513): breakpoints activated flag should be synchronized between |
- // all front-ends |
- m_debugger->setBreakpointsActivated(true); |
-} |
- |
-bool V8DebuggerAgentImpl::enabled() { return m_enabled; } |
- |
-void V8DebuggerAgentImpl::enable(ErrorString* errorString) { |
- if (enabled()) return; |
- |
- if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId())) { |
- *errorString = "Script execution is prohibited"; |
- return; |
- } |
- |
- enable(); |
-} |
- |
-void V8DebuggerAgentImpl::disable(ErrorString*) { |
- if (!enabled()) return; |
- |
- m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, |
- protocol::DictionaryValue::create()); |
- m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, |
- V8Debugger::DontPauseOnExceptions); |
- m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0); |
- |
- if (!m_pausedContext.IsEmpty()) m_debugger->continueProgram(); |
- m_debugger->disable(); |
- m_pausedContext.Reset(); |
- JavaScriptCallFrames emptyCallFrames; |
- m_pausedCallFrames.swap(emptyCallFrames); |
- m_scripts.clear(); |
- m_blackboxedPositions.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); |
-} |
- |
-void V8DebuggerAgentImpl::restore() { |
- DCHECK(!m_enabled); |
- if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false)) |
- return; |
- if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId())) |
- return; |
- |
- enable(); |
- ErrorString error; |
- |
- int pauseState = V8Debugger::DontPauseOnExceptions; |
- m_state->getInteger(DebuggerAgentState::pauseOnExceptionsState, &pauseState); |
- setPauseOnExceptionsImpl(&error, pauseState); |
- DCHECK(error.isEmpty()); |
- |
- m_skipAllPauses = |
- m_state->booleanProperty(DebuggerAgentState::skipAllPauses, false); |
- |
- int asyncCallStackDepth = 0; |
- m_state->getInteger(DebuggerAgentState::asyncCallStackDepth, |
- &asyncCallStackDepth); |
- m_debugger->setAsyncCallStackDepth(this, asyncCallStackDepth); |
- |
- String16 blackboxPattern; |
- if (m_state->getString(DebuggerAgentState::blackboxPattern, |
- &blackboxPattern)) { |
- if (!setBlackboxPattern(&error, blackboxPattern)) UNREACHABLE(); |
- } |
-} |
- |
-void V8DebuggerAgentImpl::setBreakpointsActive(ErrorString* errorString, |
- bool active) { |
- if (!checkEnabled(errorString)) return; |
- m_debugger->setBreakpointsActivated(active); |
-} |
- |
-void V8DebuggerAgentImpl::setSkipAllPauses(ErrorString*, bool skip) { |
- m_skipAllPauses = skip; |
- m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses); |
-} |
- |
-static std::unique_ptr<protocol::DictionaryValue> |
-buildObjectForBreakpointCookie(const String16& url, int lineNumber, |
- int columnNumber, const String16& condition, |
- bool isRegex) { |
- std::unique_ptr<protocol::DictionaryValue> breakpointObject = |
- protocol::DictionaryValue::create(); |
- breakpointObject->setString(DebuggerAgentState::url, url); |
- breakpointObject->setInteger(DebuggerAgentState::lineNumber, lineNumber); |
- breakpointObject->setInteger(DebuggerAgentState::columnNumber, columnNumber); |
- breakpointObject->setString(DebuggerAgentState::condition, condition); |
- breakpointObject->setBoolean(DebuggerAgentState::isRegex, isRegex); |
- return breakpointObject; |
-} |
- |
-static bool matches(V8InspectorImpl* inspector, const String16& url, |
- const String16& pattern, bool isRegex) { |
- if (isRegex) { |
- V8Regex regex(inspector, pattern, true); |
- return regex.match(url) != -1; |
- } |
- return url == pattern; |
-} |
- |
-void V8DebuggerAgentImpl::setBreakpointByUrl( |
- ErrorString* errorString, int lineNumber, |
- const Maybe<String16>& optionalURL, const Maybe<String16>& optionalURLRegex, |
- const Maybe<int>& optionalColumnNumber, |
- const Maybe<String16>& optionalCondition, String16* outBreakpointId, |
- std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations) { |
- *locations = Array<protocol::Debugger::Location>::create(); |
- if (optionalURL.isJust() == optionalURLRegex.isJust()) { |
- *errorString = "Either url or urlRegex must be specified."; |
- return; |
- } |
- |
- String16 url = optionalURL.isJust() ? optionalURL.fromJust() |
- : optionalURLRegex.fromJust(); |
- int columnNumber = 0; |
- if (optionalColumnNumber.isJust()) { |
- columnNumber = optionalColumnNumber.fromJust(); |
- if (columnNumber < 0) { |
- *errorString = "Incorrect column number"; |
- return; |
- } |
- } |
- String16 condition = optionalCondition.fromMaybe(""); |
- bool isRegex = optionalURLRegex.isJust(); |
- |
- String16 breakpointId = (isRegex ? "/" + url + "/" : url) + ":" + |
- String16::fromInteger(lineNumber) + ":" + |
- String16::fromInteger(columnNumber); |
- protocol::DictionaryValue* breakpointsCookie = |
- m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); |
- if (!breakpointsCookie) { |
- std::unique_ptr<protocol::DictionaryValue> newValue = |
- protocol::DictionaryValue::create(); |
- breakpointsCookie = newValue.get(); |
- m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, |
- std::move(newValue)); |
- } |
- if (breakpointsCookie->get(breakpointId)) { |
- *errorString = "Breakpoint at specified location already exists."; |
- return; |
- } |
- |
- breakpointsCookie->setObject( |
- breakpointId, buildObjectForBreakpointCookie( |
- url, lineNumber, columnNumber, condition, isRegex)); |
- |
- ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); |
- for (const auto& script : m_scripts) { |
- if (!matches(m_inspector, script.second->sourceURL(), url, isRegex)) |
- continue; |
- std::unique_ptr<protocol::Debugger::Location> location = resolveBreakpoint( |
- breakpointId, script.first, breakpoint, UserBreakpointSource); |
- if (location) (*locations)->addItem(std::move(location)); |
- } |
- |
- *outBreakpointId = breakpointId; |
-} |
- |
-static bool parseLocation( |
- ErrorString* errorString, |
- std::unique_ptr<protocol::Debugger::Location> location, String16* scriptId, |
- int* lineNumber, int* columnNumber) { |
- *scriptId = location->getScriptId(); |
- *lineNumber = location->getLineNumber(); |
- *columnNumber = location->getColumnNumber(0); |
- return true; |
-} |
- |
-void V8DebuggerAgentImpl::setBreakpoint( |
- ErrorString* errorString, |
- std::unique_ptr<protocol::Debugger::Location> location, |
- const Maybe<String16>& optionalCondition, String16* outBreakpointId, |
- std::unique_ptr<protocol::Debugger::Location>* actualLocation) { |
- String16 scriptId; |
- int lineNumber; |
- int columnNumber; |
- |
- if (!parseLocation(errorString, std::move(location), &scriptId, &lineNumber, |
- &columnNumber)) |
- return; |
- |
- String16 condition = optionalCondition.fromMaybe(""); |
- |
- String16 breakpointId = generateBreakpointId( |
- scriptId, lineNumber, columnNumber, UserBreakpointSource); |
- if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) != |
- m_breakpointIdToDebuggerBreakpointIds.end()) { |
- *errorString = "Breakpoint at specified location already exists."; |
- return; |
- } |
- ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); |
- *actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint, |
- UserBreakpointSource); |
- if (*actualLocation) |
- *outBreakpointId = breakpointId; |
- else |
- *errorString = "Could not resolve breakpoint"; |
-} |
- |
-void V8DebuggerAgentImpl::removeBreakpoint(ErrorString* errorString, |
- const String16& breakpointId) { |
- if (!checkEnabled(errorString)) return; |
- protocol::DictionaryValue* breakpointsCookie = |
- m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); |
- if (breakpointsCookie) breakpointsCookie->remove(breakpointId); |
- removeBreakpoint(breakpointId); |
-} |
- |
-void V8DebuggerAgentImpl::removeBreakpoint(const String16& breakpointId) { |
- DCHECK(enabled()); |
- BreakpointIdToDebuggerBreakpointIdsMap::iterator |
- debuggerBreakpointIdsIterator = |
- m_breakpointIdToDebuggerBreakpointIds.find(breakpointId); |
- if (debuggerBreakpointIdsIterator == |
- m_breakpointIdToDebuggerBreakpointIds.end()) |
- return; |
- const std::vector<String16>& ids = debuggerBreakpointIdsIterator->second; |
- for (size_t i = 0; i < ids.size(); ++i) { |
- const String16& debuggerBreakpointId = ids[i]; |
- |
- m_debugger->removeBreakpoint(debuggerBreakpointId); |
- m_serverBreakpoints.erase(debuggerBreakpointId); |
- } |
- m_breakpointIdToDebuggerBreakpointIds.erase(breakpointId); |
-} |
- |
-void V8DebuggerAgentImpl::continueToLocation( |
- ErrorString* errorString, |
- std::unique_ptr<protocol::Debugger::Location> location) { |
- if (!checkEnabled(errorString)) return; |
- if (!m_continueToLocationBreakpointId.isEmpty()) { |
- m_debugger->removeBreakpoint(m_continueToLocationBreakpointId); |
- m_continueToLocationBreakpointId = ""; |
- } |
- |
- String16 scriptId; |
- int lineNumber; |
- int columnNumber; |
- |
- if (!parseLocation(errorString, std::move(location), &scriptId, &lineNumber, |
- &columnNumber)) |
- return; |
- |
- ScriptBreakpoint breakpoint(lineNumber, columnNumber, ""); |
- m_continueToLocationBreakpointId = m_debugger->setBreakpoint( |
- scriptId, breakpoint, &lineNumber, &columnNumber); |
- resume(errorString); |
-} |
- |
-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())); |
- if (it == m_scripts.end()) { |
- // Unknown scripts are blackboxed. |
- return true; |
- } |
- if (m_blackboxPattern) { |
- const String16& scriptSourceURL = it->second->sourceURL(); |
- if (!scriptSourceURL.isEmpty() && |
- m_blackboxPattern->match(scriptSourceURL) != -1) |
- return true; |
- } |
- auto itBlackboxedPositions = |
- m_blackboxedPositions.find(String16::fromInteger(frame->sourceID())); |
- if (itBlackboxedPositions == m_blackboxedPositions.end()) return false; |
- |
- const std::vector<std::pair<int, int>>& ranges = |
- itBlackboxedPositions->second; |
- auto itRange = std::lower_bound( |
- ranges.begin(), ranges.end(), |
- std::make_pair(frame->line(), frame->column()), 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 >= maxSkipStepFrameCount) return RequestStepOut; |
- |
- if (!m_skippedStepFrameCount) m_recursionLevelForStepFrame = 1; |
- |
- ++m_skippedStepFrameCount; |
- return RequestStepFrame; |
-} |
- |
-std::unique_ptr<protocol::Debugger::Location> |
-V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId, |
- const String16& scriptId, |
- const ScriptBreakpoint& breakpoint, |
- BreakpointSource source) { |
- DCHECK(enabled()); |
- // FIXME: remove these checks once crbug.com/520702 is resolved. |
- CHECK(!breakpointId.isEmpty()); |
- CHECK(!scriptId.isEmpty()); |
- ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId); |
- if (scriptIterator == m_scripts.end()) return nullptr; |
- if (breakpoint.lineNumber < scriptIterator->second->startLine() || |
- scriptIterator->second->endLine() < breakpoint.lineNumber) |
- return nullptr; |
- |
- int actualLineNumber; |
- int actualColumnNumber; |
- String16 debuggerBreakpointId = m_debugger->setBreakpoint( |
- scriptId, breakpoint, &actualLineNumber, &actualColumnNumber); |
- if (debuggerBreakpointId.isEmpty()) return nullptr; |
- |
- m_serverBreakpoints[debuggerBreakpointId] = |
- std::make_pair(breakpointId, source); |
- CHECK(!breakpointId.isEmpty()); |
- |
- m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back( |
- debuggerBreakpointId); |
- return buildProtocolLocation(scriptId, actualLineNumber, actualColumnNumber); |
-} |
- |
-void V8DebuggerAgentImpl::searchInContent( |
- ErrorString* error, const String16& scriptId, const String16& query, |
- const Maybe<bool>& optionalCaseSensitive, |
- const Maybe<bool>& optionalIsRegex, |
- std::unique_ptr<Array<protocol::Debugger::SearchMatch>>* results) { |
- v8::HandleScope handles(m_isolate); |
- ScriptsMap::iterator it = m_scripts.find(scriptId); |
- if (it == m_scripts.end()) { |
- *error = String16("No script for id: " + scriptId); |
- return; |
- } |
- |
- std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches = |
- searchInTextByLinesImpl(m_session, |
- toProtocolString(it->second->source(m_isolate)), |
- query, optionalCaseSensitive.fromMaybe(false), |
- optionalIsRegex.fromMaybe(false)); |
- *results = protocol::Array<protocol::Debugger::SearchMatch>::create(); |
- for (size_t i = 0; i < matches.size(); ++i) |
- (*results)->addItem(std::move(matches[i])); |
-} |
- |
-void V8DebuggerAgentImpl::setScriptSource( |
- ErrorString* errorString, const String16& scriptId, |
- const String16& newContent, const Maybe<bool>& dryRun, |
- Maybe<protocol::Array<protocol::Debugger::CallFrame>>* newCallFrames, |
- Maybe<bool>* stackChanged, Maybe<StackTrace>* asyncStackTrace, |
- Maybe<protocol::Runtime::ExceptionDetails>* optOutCompileError) { |
- if (!checkEnabled(errorString)) return; |
- |
- v8::HandleScope handles(m_isolate); |
- v8::Local<v8::String> newSource = toV8String(m_isolate, newContent); |
- if (!m_debugger->setScriptSource(scriptId, newSource, dryRun.fromMaybe(false), |
- errorString, optOutCompileError, |
- &m_pausedCallFrames, stackChanged)) |
- return; |
- |
- ScriptsMap::iterator it = m_scripts.find(scriptId); |
- if (it != m_scripts.end()) it->second->setSource(m_isolate, newSource); |
- |
- std::unique_ptr<Array<CallFrame>> callFrames = currentCallFrames(errorString); |
- if (!callFrames) return; |
- *newCallFrames = std::move(callFrames); |
- *asyncStackTrace = currentAsyncStackTrace(); |
-} |
- |
-void V8DebuggerAgentImpl::restartFrame( |
- ErrorString* errorString, const String16& callFrameId, |
- std::unique_ptr<Array<CallFrame>>* newCallFrames, |
- Maybe<StackTrace>* asyncStackTrace) { |
- if (!assertPaused(errorString)) return; |
- InjectedScript::CallFrameScope scope( |
- errorString, m_inspector, m_session->contextGroupId(), callFrameId); |
- if (!scope.initialize()) return; |
- if (scope.frameOrdinal() >= m_pausedCallFrames.size()) { |
- *errorString = "Could not find call frame with given id"; |
- return; |
- } |
- |
- v8::Local<v8::Value> resultValue; |
- v8::Local<v8::Boolean> result; |
- if (!m_pausedCallFrames[scope.frameOrdinal()]->restart().ToLocal( |
- &resultValue) || |
- scope.tryCatch().HasCaught() || |
- !resultValue->ToBoolean(scope.context()).ToLocal(&result) || |
- !result->Value()) { |
- *errorString = "Internal error"; |
- return; |
- } |
- JavaScriptCallFrames frames = m_debugger->currentCallFrames(); |
- m_pausedCallFrames.swap(frames); |
- |
- *newCallFrames = currentCallFrames(errorString); |
- if (!*newCallFrames) return; |
- *asyncStackTrace = currentAsyncStackTrace(); |
-} |
- |
-void V8DebuggerAgentImpl::getScriptSource(ErrorString* error, |
- const String16& scriptId, |
- String16* scriptSource) { |
- if (!checkEnabled(error)) return; |
- ScriptsMap::iterator it = m_scripts.find(scriptId); |
- if (it == m_scripts.end()) { |
- *error = "No script for id: " + scriptId; |
- return; |
- } |
- v8::HandleScope handles(m_isolate); |
- *scriptSource = toProtocolString(it->second->source(m_isolate)); |
-} |
- |
-void V8DebuggerAgentImpl::schedulePauseOnNextStatement( |
- const String16& breakReason, |
- std::unique_ptr<protocol::DictionaryValue> data) { |
- if (!enabled() || m_scheduledDebuggerStep == StepInto || |
- m_javaScriptPauseScheduled || m_debugger->isPaused() || |
- !m_debugger->breakpointsActivated()) |
- return; |
- m_breakReason = breakReason; |
- m_breakAuxData = std::move(data); |
- m_pausingOnNativeEvent = true; |
- m_skipNextDebuggerStepOut = false; |
- m_debugger->setPauseOnNextStatement(true); |
-} |
- |
-void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() { |
- DCHECK(enabled()); |
- if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || |
- 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); |
-} |
- |
-void V8DebuggerAgentImpl::pause(ErrorString* errorString) { |
- if (!checkEnabled(errorString)) return; |
- if (m_javaScriptPauseScheduled || m_debugger->isPaused()) return; |
- clearBreakDetails(); |
- m_javaScriptPauseScheduled = true; |
- m_scheduledDebuggerStep = NoStep; |
- m_skippedStepFrameCount = 0; |
- m_steppingFromFramework = false; |
- m_debugger->setPauseOnNextStatement(true); |
-} |
- |
-void V8DebuggerAgentImpl::resume(ErrorString* errorString) { |
- if (!assertPaused(errorString)) return; |
- m_scheduledDebuggerStep = NoStep; |
- m_steppingFromFramework = false; |
- m_session->releaseObjectGroup(backtraceObjectGroup); |
- m_debugger->continueProgram(); |
-} |
- |
-void V8DebuggerAgentImpl::stepOver(ErrorString* errorString) { |
- if (!assertPaused(errorString)) return; |
- // StepOver at function return point should fallback to StepInto. |
- JavaScriptCallFrame* frame = |
- !m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr; |
- if (frame && frame->isAtReturn()) { |
- stepInto(errorString); |
- return; |
- } |
- m_scheduledDebuggerStep = StepOver; |
- m_steppingFromFramework = isTopPausedCallFrameBlackboxed(); |
- m_session->releaseObjectGroup(backtraceObjectGroup); |
- m_debugger->stepOverStatement(); |
-} |
- |
-void V8DebuggerAgentImpl::stepInto(ErrorString* errorString) { |
- if (!assertPaused(errorString)) return; |
- m_scheduledDebuggerStep = StepInto; |
- m_steppingFromFramework = isTopPausedCallFrameBlackboxed(); |
- m_session->releaseObjectGroup(backtraceObjectGroup); |
- m_debugger->stepIntoStatement(); |
-} |
- |
-void V8DebuggerAgentImpl::stepOut(ErrorString* errorString) { |
- if (!assertPaused(errorString)) return; |
- m_scheduledDebuggerStep = StepOut; |
- m_skipNextDebuggerStepOut = false; |
- m_recursionLevelForStepOut = 1; |
- m_steppingFromFramework = isTopPausedCallFrameBlackboxed(); |
- m_session->releaseObjectGroup(backtraceObjectGroup); |
- m_debugger->stepOutOfFunction(); |
-} |
- |
-void V8DebuggerAgentImpl::setPauseOnExceptions( |
- ErrorString* errorString, const String16& stringPauseState) { |
- if (!checkEnabled(errorString)) return; |
- V8Debugger::PauseOnExceptionsState pauseState; |
- if (stringPauseState == "none") { |
- pauseState = V8Debugger::DontPauseOnExceptions; |
- } else if (stringPauseState == "all") { |
- pauseState = V8Debugger::PauseOnAllExceptions; |
- } else if (stringPauseState == "uncaught") { |
- pauseState = V8Debugger::PauseOnUncaughtExceptions; |
- } else { |
- *errorString = "Unknown pause on exceptions mode: " + stringPauseState; |
- return; |
- } |
- setPauseOnExceptionsImpl(errorString, pauseState); |
-} |
- |
-void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(ErrorString* errorString, |
- int pauseState) { |
- m_debugger->setPauseOnExceptionsState( |
- static_cast<V8Debugger::PauseOnExceptionsState>(pauseState)); |
- if (m_debugger->getPauseOnExceptionsState() != pauseState) |
- *errorString = "Internal error. Could not change pause on exceptions state"; |
- else |
- m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, pauseState); |
-} |
- |
-void V8DebuggerAgentImpl::evaluateOnCallFrame( |
- ErrorString* errorString, const String16& callFrameId, |
- const String16& expression, const Maybe<String16>& objectGroup, |
- const Maybe<bool>& includeCommandLineAPI, const Maybe<bool>& silent, |
- const Maybe<bool>& returnByValue, const Maybe<bool>& generatePreview, |
- std::unique_ptr<RemoteObject>* result, |
- Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) { |
- if (!assertPaused(errorString)) return; |
- InjectedScript::CallFrameScope scope( |
- errorString, m_inspector, m_session->contextGroupId(), callFrameId); |
- if (!scope.initialize()) return; |
- if (scope.frameOrdinal() >= m_pausedCallFrames.size()) { |
- *errorString = "Could not find call frame with given id"; |
- return; |
- } |
- |
- if (includeCommandLineAPI.fromMaybe(false) && !scope.installCommandLineAPI()) |
- return; |
- if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole(); |
- |
- v8::MaybeLocal<v8::Value> maybeResultValue = |
- m_pausedCallFrames[scope.frameOrdinal()]->evaluate( |
- toV8String(m_isolate, expression)); |
- |
- // Re-initialize after running client's code, as it could have destroyed |
- // context or session. |
- if (!scope.initialize()) return; |
- scope.injectedScript()->wrapEvaluateResult( |
- errorString, maybeResultValue, scope.tryCatch(), |
- objectGroup.fromMaybe(""), returnByValue.fromMaybe(false), |
- generatePreview.fromMaybe(false), result, exceptionDetails); |
-} |
- |
-void V8DebuggerAgentImpl::setVariableValue( |
- ErrorString* errorString, int scopeNumber, const String16& variableName, |
- std::unique_ptr<protocol::Runtime::CallArgument> newValueArgument, |
- const String16& callFrameId) { |
- if (!checkEnabled(errorString)) return; |
- if (!assertPaused(errorString)) return; |
- InjectedScript::CallFrameScope scope( |
- errorString, m_inspector, m_session->contextGroupId(), callFrameId); |
- if (!scope.initialize()) return; |
- |
- v8::Local<v8::Value> newValue; |
- if (!scope.injectedScript() |
- ->resolveCallArgument(errorString, newValueArgument.get()) |
- .ToLocal(&newValue)) |
- return; |
- |
- if (scope.frameOrdinal() >= m_pausedCallFrames.size()) { |
- *errorString = "Could not find call frame with given id"; |
- return; |
- } |
- v8::MaybeLocal<v8::Value> result = |
- m_pausedCallFrames[scope.frameOrdinal()]->setVariableValue( |
- scopeNumber, toV8String(m_isolate, variableName), newValue); |
- if (scope.tryCatch().HasCaught() || result.IsEmpty()) { |
- *errorString = "Internal error"; |
- return; |
- } |
-} |
- |
-void V8DebuggerAgentImpl::setAsyncCallStackDepth(ErrorString* errorString, |
- int depth) { |
- if (!checkEnabled(errorString)) return; |
- m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth); |
- m_debugger->setAsyncCallStackDepth(this, depth); |
-} |
- |
-void V8DebuggerAgentImpl::setBlackboxPatterns( |
- ErrorString* errorString, |
- std::unique_ptr<protocol::Array<String16>> patterns) { |
- if (!patterns->length()) { |
- m_blackboxPattern = nullptr; |
- m_state->remove(DebuggerAgentState::blackboxPattern); |
- return; |
- } |
- |
- String16Builder patternBuilder; |
- patternBuilder.append('('); |
- for (size_t i = 0; i < patterns->length() - 1; ++i) { |
- patternBuilder.append(patterns->get(i)); |
- patternBuilder.append("|"); |
- } |
- patternBuilder.append(patterns->get(patterns->length() - 1)); |
- patternBuilder.append(')'); |
- String16 pattern = patternBuilder.toString(); |
- if (!setBlackboxPattern(errorString, pattern)) return; |
- m_state->setString(DebuggerAgentState::blackboxPattern, pattern); |
-} |
- |
-bool V8DebuggerAgentImpl::setBlackboxPattern(ErrorString* errorString, |
- const String16& pattern) { |
- std::unique_ptr<V8Regex> regex(new V8Regex( |
- m_inspector, pattern, true /** caseSensitive */, false /** multiline */)); |
- if (!regex->isValid()) { |
- *errorString = "Pattern parser error: " + regex->errorMessage(); |
- return false; |
- } |
- m_blackboxPattern = std::move(regex); |
- return true; |
-} |
- |
-void V8DebuggerAgentImpl::setBlackboxedRanges( |
- ErrorString* error, const String16& scriptId, |
- std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>> |
- inPositions) { |
- if (m_scripts.find(scriptId) == m_scripts.end()) { |
- *error = "No script with passed id."; |
- return; |
- } |
- |
- if (!inPositions->length()) { |
- m_blackboxedPositions.erase(scriptId); |
- return; |
- } |
- |
- std::vector<std::pair<int, int>> positions; |
- positions.reserve(inPositions->length()); |
- for (size_t i = 0; i < inPositions->length(); ++i) { |
- protocol::Debugger::ScriptPosition* position = inPositions->get(i); |
- if (position->getLineNumber() < 0) { |
- *error = "Position missing 'line' or 'line' < 0."; |
- return; |
- } |
- if (position->getColumnNumber() < 0) { |
- *error = "Position missing 'column' or 'column' < 0."; |
- return; |
- } |
- positions.push_back( |
- std::make_pair(position->getLineNumber(), position->getColumnNumber())); |
- } |
- |
- for (size_t i = 1; i < positions.size(); ++i) { |
- if (positions[i - 1].first < positions[i].first) continue; |
- if (positions[i - 1].first == positions[i].first && |
- positions[i - 1].second < positions[i].second) |
- continue; |
- *error = |
- "Input positions array is not sorted or contains duplicate values."; |
- return; |
- } |
- |
- m_blackboxedPositions[scriptId] = positions; |
-} |
- |
-void V8DebuggerAgentImpl::willExecuteScript(int scriptId) { |
- changeJavaScriptRecursionLevel(+1); |
- // Fast return. |
- if (m_scheduledDebuggerStep != StepInto) return; |
- schedulePauseOnNextStatementIfSteppingInto(); |
-} |
- |
-void V8DebuggerAgentImpl::didExecuteScript() { |
- changeJavaScriptRecursionLevel(-1); |
-} |
- |
-void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) { |
- if (m_javaScriptPauseScheduled && !m_skipAllPauses && |
- !m_debugger->isPaused()) { |
- // Do not ever loose user's pause request until we have actually paused. |
- m_debugger->setPauseOnNextStatement(true); |
- } |
- if (m_scheduledDebuggerStep == StepOut) { |
- m_recursionLevelForStepOut += step; |
- if (!m_recursionLevelForStepOut) { |
- // When StepOut crosses a task boundary (i.e. js -> c++) from where it was |
- // requested, |
- // 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; |
- } |
- } |
-} |
- |
-std::unique_ptr<Array<CallFrame>> V8DebuggerAgentImpl::currentCallFrames( |
- ErrorString* errorString) { |
- if (m_pausedContext.IsEmpty() || !m_pausedCallFrames.size()) |
- return Array<CallFrame>::create(); |
- ErrorString ignored; |
- v8::HandleScope handles(m_isolate); |
- v8::Local<v8::Context> debuggerContext = |
- v8::Debug::GetDebugContext(m_isolate); |
- v8::Context::Scope contextScope(debuggerContext); |
- |
- v8::Local<v8::Array> objects = v8::Array::New(m_isolate); |
- |
- for (size_t frameOrdinal = 0; frameOrdinal < m_pausedCallFrames.size(); |
- ++frameOrdinal) { |
- const std::unique_ptr<JavaScriptCallFrame>& currentCallFrame = |
- m_pausedCallFrames[frameOrdinal]; |
- |
- v8::Local<v8::Object> details = currentCallFrame->details(); |
- if (hasInternalError(errorString, details.IsEmpty())) |
- return Array<CallFrame>::create(); |
- |
- int contextId = currentCallFrame->contextId(); |
- InjectedScript* injectedScript = |
- contextId ? m_session->findInjectedScript(&ignored, contextId) |
- : nullptr; |
- |
- String16 callFrameId = |
- RemoteCallFrameId::serialize(contextId, frameOrdinal); |
- if (hasInternalError( |
- errorString, |
- !details |
- ->Set(debuggerContext, |
- toV8StringInternalized(m_isolate, "callFrameId"), |
- toV8String(m_isolate, callFrameId)) |
- .FromMaybe(false))) |
- return Array<CallFrame>::create(); |
- |
- if (injectedScript) { |
- v8::Local<v8::Value> scopeChain; |
- if (hasInternalError( |
- errorString, |
- !details->Get(debuggerContext, |
- toV8StringInternalized(m_isolate, "scopeChain")) |
- .ToLocal(&scopeChain) || |
- !scopeChain->IsArray())) |
- return Array<CallFrame>::create(); |
- v8::Local<v8::Array> scopeChainArray = scopeChain.As<v8::Array>(); |
- if (!injectedScript->wrapPropertyInArray( |
- errorString, scopeChainArray, |
- toV8StringInternalized(m_isolate, "object"), |
- backtraceObjectGroup)) |
- return Array<CallFrame>::create(); |
- if (!injectedScript->wrapObjectProperty( |
- errorString, details, toV8StringInternalized(m_isolate, "this"), |
- backtraceObjectGroup)) |
- return Array<CallFrame>::create(); |
- if (details |
- ->Has(debuggerContext, |
- toV8StringInternalized(m_isolate, "returnValue")) |
- .FromMaybe(false)) { |
- if (!injectedScript->wrapObjectProperty( |
- errorString, details, |
- toV8StringInternalized(m_isolate, "returnValue"), |
- backtraceObjectGroup)) |
- return Array<CallFrame>::create(); |
- } |
- } else { |
- if (hasInternalError(errorString, !details |
- ->Set(debuggerContext, |
- toV8StringInternalized( |
- m_isolate, "scopeChain"), |
- v8::Array::New(m_isolate, 0)) |
- .FromMaybe(false))) |
- return Array<CallFrame>::create(); |
- v8::Local<v8::Object> remoteObject = v8::Object::New(m_isolate); |
- if (hasInternalError( |
- errorString, |
- !remoteObject |
- ->Set(debuggerContext, |
- toV8StringInternalized(m_isolate, "type"), |
- toV8StringInternalized(m_isolate, "undefined")) |
- .FromMaybe(false))) |
- return Array<CallFrame>::create(); |
- if (hasInternalError(errorString, |
- !details |
- ->Set(debuggerContext, |
- toV8StringInternalized(m_isolate, "this"), |
- remoteObject) |
- .FromMaybe(false))) |
- return Array<CallFrame>::create(); |
- if (hasInternalError( |
- errorString, |
- !details |
- ->Delete(debuggerContext, |
- toV8StringInternalized(m_isolate, "returnValue")) |
- .FromMaybe(false))) |
- return Array<CallFrame>::create(); |
- } |
- |
- if (hasInternalError(errorString, |
- !objects->Set(debuggerContext, frameOrdinal, details) |
- .FromMaybe(false))) |
- return Array<CallFrame>::create(); |
- } |
- |
- protocol::ErrorSupport errorSupport; |
- std::unique_ptr<Array<CallFrame>> callFrames = Array<CallFrame>::parse( |
- toProtocolValue(debuggerContext, objects).get(), &errorSupport); |
- if (hasInternalError(errorString, !callFrames)) |
- return Array<CallFrame>::create(); |
- return callFrames; |
-} |
- |
-std::unique_ptr<StackTrace> V8DebuggerAgentImpl::currentAsyncStackTrace() { |
- if (m_pausedContext.IsEmpty()) return nullptr; |
- V8StackTraceImpl* stackTrace = m_debugger->currentAsyncCallChain(); |
- return stackTrace ? stackTrace->buildInspectorObjectForTail(m_debugger) |
- : nullptr; |
-} |
- |
-void V8DebuggerAgentImpl::didParseSource( |
- std::unique_ptr<V8DebuggerScript> script, bool success) { |
- v8::HandleScope handles(m_isolate); |
- String16 scriptSource = toProtocolString(script->source(m_isolate)); |
- if (!success) script->setSourceURL(findSourceURL(scriptSource, false)); |
- if (!success) |
- script->setSourceMappingURL(findSourceMapURL(scriptSource, false)); |
- |
- std::unique_ptr<protocol::DictionaryValue> executionContextAuxData; |
- if (!script->executionContextAuxData().isEmpty()) |
- executionContextAuxData = protocol::DictionaryValue::cast( |
- protocol::parseJSON(script->executionContextAuxData())); |
- bool isLiveEdit = script->isLiveEdit(); |
- bool hasSourceURL = script->hasSourceURL(); |
- String16 scriptId = script->scriptId(); |
- String16 scriptURL = script->sourceURL(); |
- |
- const Maybe<String16>& sourceMapURLParam = script->sourceMappingURL(); |
- const Maybe<protocol::DictionaryValue>& executionContextAuxDataParam( |
- std::move(executionContextAuxData)); |
- const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr; |
- const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr; |
- if (success) |
- m_frontend.scriptParsed( |
- scriptId, scriptURL, script->startLine(), script->startColumn(), |
- script->endLine(), script->endColumn(), script->executionContextId(), |
- script->hash(), executionContextAuxDataParam, isLiveEditParam, |
- sourceMapURLParam, hasSourceURLParam); |
- else |
- m_frontend.scriptFailedToParse( |
- scriptId, scriptURL, script->startLine(), script->startColumn(), |
- script->endLine(), script->endColumn(), script->executionContextId(), |
- script->hash(), executionContextAuxDataParam, sourceMapURLParam, |
- hasSourceURLParam); |
- |
- m_scripts[scriptId] = std::move(script); |
- |
- if (scriptURL.isEmpty() || !success) return; |
- |
- protocol::DictionaryValue* breakpointsCookie = |
- m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); |
- if (!breakpointsCookie) return; |
- |
- for (size_t i = 0; i < breakpointsCookie->size(); ++i) { |
- auto cookie = breakpointsCookie->at(i); |
- protocol::DictionaryValue* breakpointObject = |
- protocol::DictionaryValue::cast(cookie.second); |
- bool isRegex; |
- breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex); |
- String16 url; |
- breakpointObject->getString(DebuggerAgentState::url, &url); |
- if (!matches(m_inspector, scriptURL, url, isRegex)) continue; |
- ScriptBreakpoint breakpoint; |
- breakpointObject->getInteger(DebuggerAgentState::lineNumber, |
- &breakpoint.lineNumber); |
- breakpointObject->getInteger(DebuggerAgentState::columnNumber, |
- &breakpoint.columnNumber); |
- breakpointObject->getString(DebuggerAgentState::condition, |
- &breakpoint.condition); |
- std::unique_ptr<protocol::Debugger::Location> location = resolveBreakpoint( |
- cookie.first, scriptId, breakpoint, UserBreakpointSource); |
- if (location) |
- m_frontend.breakpointResolved(cookie.first, std::move(location)); |
- } |
-} |
- |
-V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause( |
- v8::Local<v8::Context> context, v8::Local<v8::Value> exception, |
- const std::vector<String16>& hitBreakpoints, bool isPromiseRejection) { |
- JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(1); |
- JavaScriptCallFrame* topCallFrame = |
- !callFrames.empty() ? callFrames.begin()->get() : nullptr; |
- |
- V8DebuggerAgentImpl::SkipPauseRequest result; |
- 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; |
- |
- DCHECK(m_pausedContext.IsEmpty()); |
- JavaScriptCallFrames frames = m_debugger->currentCallFrames(); |
- m_pausedCallFrames.swap(frames); |
- m_pausedContext.Reset(m_isolate, context); |
- v8::HandleScope handles(m_isolate); |
- |
- if (!exception.IsEmpty()) { |
- ErrorString ignored; |
- InjectedScript* injectedScript = |
- m_session->findInjectedScript(&ignored, V8Debugger::contextId(context)); |
- if (injectedScript) { |
- m_breakReason = |
- isPromiseRejection |
- ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection |
- : protocol::Debugger::Paused::ReasonEnum::Exception; |
- ErrorString errorString; |
- auto obj = injectedScript->wrapObject(&errorString, exception, |
- backtraceObjectGroup); |
- m_breakAuxData = obj ? obj->serialize() : nullptr; |
- // m_breakAuxData might be null after this. |
- } |
- } |
- |
- std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create(); |
- |
- for (const auto& point : hitBreakpoints) { |
- DebugServerBreakpointToBreakpointIdAndSourceMap::iterator |
- breakpointIterator = m_serverBreakpoints.find(point); |
- if (breakpointIterator != m_serverBreakpoints.end()) { |
- const String16& localId = breakpointIterator->second.first; |
- 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; |
- } |
- } |
- |
- ErrorString errorString; |
- m_frontend.paused(currentCallFrames(&errorString), m_breakReason, |
- std::move(m_breakAuxData), std::move(hitBreakpointIds), |
- 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; |
-} |
- |
-void V8DebuggerAgentImpl::didContinue() { |
- m_pausedContext.Reset(); |
- JavaScriptCallFrames emptyCallFrames; |
- m_pausedCallFrames.swap(emptyCallFrames); |
- clearBreakDetails(); |
- m_frontend.resumed(); |
-} |
- |
-void V8DebuggerAgentImpl::breakProgram( |
- const String16& breakReason, |
- std::unique_ptr<protocol::DictionaryValue> data) { |
- if (!enabled() || m_skipAllPauses || !m_pausedContext.IsEmpty() || |
- isCurrentCallStackEmptyOrBlackboxed() || |
- !m_debugger->breakpointsActivated()) |
- return; |
- m_breakReason = breakReason; |
- m_breakAuxData = std::move(data); |
- m_scheduledDebuggerStep = NoStep; |
- m_steppingFromFramework = false; |
- m_pausingOnNativeEvent = false; |
- m_debugger->breakProgram(); |
-} |
- |
-void V8DebuggerAgentImpl::breakProgramOnException( |
- const String16& breakReason, |
- std::unique_ptr<protocol::DictionaryValue> data) { |
- if (!enabled() || |
- m_debugger->getPauseOnExceptionsState() == |
- V8Debugger::DontPauseOnExceptions) |
- return; |
- breakProgram(breakReason, std::move(data)); |
-} |
- |
-bool V8DebuggerAgentImpl::assertPaused(ErrorString* errorString) { |
- if (m_pausedContext.IsEmpty()) { |
- *errorString = "Can only perform operation while paused."; |
- return false; |
- } |
- return true; |
-} |
- |
-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, |
- const String16& condition) { |
- String16 breakpointId = |
- generateBreakpointId(scriptId, lineNumber, columnNumber, source); |
- ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); |
- resolveBreakpoint(breakpointId, scriptId, breakpoint, source); |
-} |
- |
-void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, |
- int lineNumber, int columnNumber, |
- BreakpointSource source) { |
- removeBreakpoint( |
- generateBreakpointId(scriptId, lineNumber, columnNumber, source)); |
-} |
- |
-void V8DebuggerAgentImpl::reset() { |
- if (!enabled()) return; |
- m_scheduledDebuggerStep = NoStep; |
- m_scripts.clear(); |
- m_blackboxedPositions.clear(); |
- m_breakpointIdToDebuggerBreakpointIds.clear(); |
-} |
- |
-} // namespace v8_inspector |