Index: third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp |
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp |
index 84b43e853b96cbc499a4b754ccb86a05d12bbae5..2323038eadb2d212039a99991d22b0bf0988b325 100644 |
--- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp |
+++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp |
@@ -46,6 +46,8 @@ static const char pauseOnExceptionsState[] = "pauseOnExceptionsState"; |
static const char asyncCallStackDepth[] = "asyncCallStackDepth"; |
static const char promiseTrackerEnabled[] = "promiseTrackerEnabled"; |
static const char promiseTrackerCaptureStacks[] = "promiseTrackerCaptureStacks"; |
+static const char blackboxPatterns[] = "blackboxPatterns"; |
+static const char blackboxHashes[] = "blackboxHashes"; |
// Breakpoint properties. |
static const char url[] = "url"; |
@@ -55,6 +57,10 @@ static const char columnNumber[] = "columnNumber"; |
static const char condition[] = "condition"; |
static const char skipAllPauses[] = "skipAllPauses"; |
+// Blackbox hash object properties. |
+static const char hashValue[] = "hashValue"; |
+static const char hashPositions[] = "hashPositions"; |
+ |
} // namespace DebuggerAgentState; |
static const int maxSkipStepFrameCount = 128; |
@@ -101,6 +107,43 @@ static void appendUnsignedAsHex(unsigned number, String& destination) |
destination.append(result.data(), result.size()); |
} |
+static bool parseBlackboxPositions(ErrorString* error, protocol::Array<protocol::Debugger::ScriptPosition>* inPositions, Vector<std::pair<int, int>>* outPositions) |
+{ |
+ if (!inPositions) { |
+ Vector<std::pair<int, int>> blackboxed(1); |
+ outPositions->swap(blackboxed); |
+ return true; |
+ } |
+ Vector<std::pair<int, int>> positions(inPositions->length()); |
+ for (size_t i = 0; i < positions.size(); ++i) { |
+ protocol::Debugger::ScriptPosition* position = inPositions->get(i); |
+ if (position->getLine() < 0) { |
+ if (error) |
+ *error = "Position missing 'line' or 'line' < 0."; |
+ return false; |
+ } |
+ if (position->getColumn() < 0) { |
+ if (error) |
+ *error = "Position missing 'column' or 'column' < 0."; |
+ return false; |
+ } |
+ positions[i] = std::make_pair(position->getLine(), position->getColumn()); |
+ } |
+ |
+ 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; |
+ if (error) |
+ *error = "Input positions array is not sorted or contains duplicate values."; |
+ return false; |
+ } |
+ |
+ outPositions->swap(positions); |
+ return true; |
+} |
+ |
// Hash algorithm for substrings is described in "Über die Komplexität der Multiplikation in |
// eingeschränkten Branchingprogrammmodellen" by Woelfe. |
// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000 |
@@ -243,7 +286,11 @@ void V8DebuggerAgentImpl::disable(ErrorString*) |
m_pausedContext.Reset(); |
m_currentCallStack.Reset(); |
m_scripts.clear(); |
- m_blackboxedPositions.clear(); |
+ m_loadedScriptHashes.clear(); |
+ |
+ m_hashToBlackboxPositions.clear(); |
+ m_blackboxPattern = String(); |
+ |
m_breakpointIdToDebuggerBreakpointIds.clear(); |
internalSetAsyncCallStackDepth(0); |
m_promiseTracker->setEnabled(false, false); |
@@ -304,6 +351,39 @@ void V8DebuggerAgentImpl::restore() |
internalSetAsyncCallStackDepth(asyncCallStackDepth); |
m_promiseTracker->setEnabled(m_state->booleanProperty(DebuggerAgentState::promiseTrackerEnabled, false), m_state->booleanProperty(DebuggerAgentState::promiseTrackerCaptureStacks, false)); |
+ |
+ restoreBlackboxState(); |
+} |
+ |
+void V8DebuggerAgentImpl::restoreBlackboxState() |
+{ |
+ String error; |
+ protocol::ErrorSupport errors; |
+ |
+ protocol::ListValue* savedPatterns = m_state->getArray(DebuggerAgentState::blackboxPatterns); |
+ if (savedPatterns) { |
+ OwnPtr<protocol::Array<protocol::Debugger::BlackboxPattern>> patterns = protocol::Array<protocol::Debugger::BlackboxPattern>::parse(savedPatterns, &errors); |
+ ASSERT(!errors.hasErrors()); |
+ editBlackboxPatterns(&error, patterns.release()); |
+ ASSERT(!error.length()); |
+ } |
+ |
+ protocol::ListValue* savedHashes = m_state->getArray(DebuggerAgentState::blackboxHashes); |
+ if (!savedHashes) |
+ return; |
+ for (size_t i = 0; i < savedHashes->size(); ++i) { |
+ protocol::DictionaryValue* savedHash = protocol::DictionaryValue::cast(savedHashes->at(i)); |
+ |
+ String hash; |
+ OwnPtr<protocol::Array<protocol::Debugger::ScriptPosition>> positions; |
+ |
+ bool hadError = savedHash->getString(DebuggerAgentState::hashValue, &hash); |
+ ASSERT_UNUSED(hadError, !hadError); |
+ positions = protocol::Array<protocol::Debugger::ScriptPosition>::parse(savedHash->getArray(DebuggerAgentState::hashPositions), &errors); |
+ ASSERT(!errors.hasErrors()); |
+ addBlackboxRanges(&error, hash, positions.release()); |
+ ASSERT(!error.length()); |
+ } |
} |
void V8DebuggerAgentImpl::setBreakpointsActive(ErrorString* errorString, bool active) |
@@ -536,20 +616,35 @@ bool V8DebuggerAgentImpl::isCallFrameWithUnknownScriptOrBlackboxed(PassRefPtr<Ja |
RefPtr<JavaScriptCallFrame> frame = pFrame; |
if (!frame) |
return true; |
- ScriptsMap::iterator it = m_scripts.find(String::number(frame->sourceID())); |
+ String scriptId = String::number(frame->sourceID()); |
+ ScriptsMap::iterator it = m_scripts.find(scriptId); |
if (it == m_scripts.end()) { |
// Unknown scripts are blackboxed. |
return true; |
} |
- auto itBlackboxedPositions = m_blackboxedPositions.find(String::number(frame->sourceID())); |
- if (itBlackboxedPositions == m_blackboxedPositions.end()) |
+ |
+ Vector<std::pair<int, int>> emptyPositions; |
+ const Vector<std::pair<int, int>>* ranges = nullptr; |
+ |
+ V8DebuggerScript& script = it->value; |
+ auto itBlackboxHash = m_hashToBlackboxPositions.find(script.hash()); |
+ if (itBlackboxHash != m_hashToBlackboxPositions.end()) { |
+ ranges = &itBlackboxHash->value; |
+ } else { |
+ if (!m_blackboxPattern.isEmpty() && matches(m_debugger, script.sourceURL(), m_blackboxPattern, true)) { |
+ Vector<std::pair<int, int>> positions(1); |
+ positions[0].first = 0; |
+ positions[0].second = 0; |
+ m_hashToBlackboxPositions.set(script.hash(), positions); |
+ return true; |
+ } |
return false; |
+ } |
- const Vector<std::pair<int, int>>& ranges = itBlackboxedPositions->value; |
- auto itRange = std::lower_bound(ranges.begin(), ranges.end(), std::make_pair(frame->line(), frame->column()), positionComparator); |
+ 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; |
+ return std::distance(ranges->begin(), itRange) % 2; |
} |
V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::shouldSkipExceptionPause() |
@@ -1241,43 +1336,57 @@ void V8DebuggerAgentImpl::removeAsyncOperationBreakpoint(ErrorString* errorStrin |
m_asyncOperationBreakpoints.remove(operationId); |
} |
-void V8DebuggerAgentImpl::setBlackboxedRanges(ErrorString* error, const String& scriptId, PassOwnPtr<protocol::Array<protocol::Debugger::ScriptPosition>> inPositions) |
+void V8DebuggerAgentImpl::addBlackboxRanges(ErrorString* error, const String& hash, PassOwnPtr<protocol::Array<protocol::Debugger::ScriptPosition>> inPositions) |
{ |
- ScriptsMap::iterator it = m_scripts.find(scriptId); |
- if (it == m_scripts.end()) { |
- *error = "No script with passed id."; |
+ if (!m_loadedScriptHashes.contains(hash)) { |
+ *error = "No script with passed hash."; |
return; |
} |
if (!inPositions->length()) { |
- m_blackboxedPositions.remove(scriptId); |
+ m_hashToBlackboxPositions.remove(hash); |
return; |
} |
- Vector<std::pair<int, int>> positions(inPositions->length()); |
- for (size_t i = 0; i < positions.size(); ++i) { |
- protocol::Debugger::ScriptPosition* position = inPositions->get(i); |
- if (position->getLine() < 0) { |
- *error = "Position missing 'line' or 'line' < 0."; |
- return; |
- } |
- if (position->getColumn() < 0) { |
- *error = "Position missing 'column' or 'column' < 0."; |
+ Vector<std::pair<int, int>> positions; |
+ if (parseBlackboxPositions(error, inPositions.get(), &positions)) |
+ m_hashToBlackboxPositions.set(hash, positions); |
+ |
+ if (!m_state->getArray(DebuggerAgentState::blackboxHashes)) |
+ m_state->setArray(DebuggerAgentState::blackboxHashes, protocol::ListValue::create()); |
+ protocol::ListValue* hashes = m_state->getArray(DebuggerAgentState::blackboxHashes); |
+ OwnPtr<protocol::DictionaryValue> value = protocol::DictionaryValue::create(); |
+ value->setString(DebuggerAgentState::hashValue, hash); |
+ value->setArray(DebuggerAgentState::hashPositions, inPositions->serialize()); |
+ hashes->pushValue(value.release()); |
+} |
+ |
+void V8DebuggerAgentImpl::editBlackboxPatterns(ErrorString* error, PassOwnPtr<protocol::Array<protocol::Debugger::BlackboxPattern>> patterns) |
+{ |
+ HashSet<String> hashes; |
+ String blackboxPattern; |
+ |
+ for (size_t i = 0; i < patterns->length(); ++i) { |
+ protocol::Debugger::BlackboxPattern* pattern = patterns->get(i); |
+ |
+ String regex = pattern->getRegex(String()); |
+ String hash = pattern->getHash(String()); |
+ if ((!hash.isEmpty() && !regex.isEmpty()) || (hash.isEmpty() && regex.isEmpty())) { |
+ *error = "Blackbox pattern should contain regex or hash."; |
return; |
} |
- positions[i] = std::make_pair(position->getLine(), position->getColumn()); |
+ if (!regex.isEmpty()) |
+ blackboxPattern = blackboxPattern.isEmpty() ? regex : (blackboxPattern + "|" + regex); |
+ if (!hash.isEmpty()) |
+ hashes.add(hash); |
} |
- 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_state->setArray(DebuggerAgentState::blackboxPatterns, patterns->serialize()); |
- m_blackboxedPositions.set(scriptId, positions); |
+ Vector<std::pair<int, int>> positions(1); |
+ for (auto& hash : hashes) |
+ m_hashToBlackboxPositions.set(hash, positions); |
+ m_blackboxPattern = blackboxPattern; |
} |
void V8DebuggerAgentImpl::willExecuteScript(int scriptId) |
@@ -1401,6 +1510,7 @@ void V8DebuggerAgentImpl::didParseSource(const V8DebuggerParsedScript& parsedScr |
m_frontend->scriptFailedToParse(parsedScript.scriptId, scriptURL, script.startLine(), script.startColumn(), script.endLine(), script.endColumn(), executionContextId, script.hash(), isContentScriptParam, isInternalScriptParam, sourceMapURLParam, hasSourceURLParam, deprecatedCommentWasUsedParam); |
m_scripts.set(parsedScript.scriptId, script); |
+ m_loadedScriptHashes.add(script.hash()); |
if (scriptURL.isEmpty() || !parsedScript.success) |
return; |
@@ -1577,7 +1687,10 @@ void V8DebuggerAgentImpl::reset() |
{ |
m_scheduledDebuggerStep = NoStep; |
m_scripts.clear(); |
- m_blackboxedPositions.clear(); |
+ m_loadedScriptHashes.clear(); |
+ |
+ m_hashToBlackboxPositions.clear(); |
+ |
m_breakpointIdToDebuggerBreakpointIds.clear(); |
resetAsyncCallTracker(); |
m_promiseTracker->clear(); |