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 5ae6ce42f24f9f034be08295857845781a58c57f..db4a83c3928319ffc4c480136422a19b3d03a701 100644 |
--- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp |
+++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp |
@@ -45,6 +45,11 @@ namespace DebuggerAgentState { |
static const char javaScriptBreakpoints[] = "javaScriptBreakopints"; |
static const char pauseOnExceptionsState[] = "pauseOnExceptionsState"; |
static const char asyncCallStackDepth[] = "asyncCallStackDepth"; |
+static const char blackboxPatterns[] = "blackboxPatterns"; |
+static const char blackboxRangesByURL[] = "blackboxRangesByURL"; |
+static const char blackboxRangesByHash[] = "blackboxRangesByHash"; |
+static const char blackboxScriptsByURL[] = "blackboxScriptsByURL"; |
+static const char blackboxScriptsByHash[] = "blackboxScriptsByHash"; |
// Breakpoint properties. |
static const char url[] = "url"; |
@@ -236,7 +241,6 @@ void V8DebuggerAgentImpl::disable(ErrorString*) |
JavaScriptCallFrames emptyCallFrames; |
m_pausedCallFrames.swap(emptyCallFrames); |
m_scripts.clear(); |
- m_blackboxedPositions.clear(); |
m_breakpointIdToDebuggerBreakpointIds.clear(); |
internalSetAsyncCallStackDepth(0); |
m_continueToLocationBreakpointId = String16(); |
@@ -250,6 +254,10 @@ void V8DebuggerAgentImpl::disable(ErrorString*) |
m_recursionLevelForStepFrame = 0; |
m_skipAllPauses = false; |
m_enabled = false; |
+ |
+ m_blackboxPattern = nullptr; |
+ m_blackboxRangesByHash.clear(); |
+ m_blackboxRangesByURL.clear(); |
} |
void V8DebuggerAgentImpl::internalSetAsyncCallStackDepth(int depth) |
@@ -284,12 +292,63 @@ void V8DebuggerAgentImpl::restore() |
int pauseState = V8DebuggerImpl::DontPauseOnExceptions; |
m_state->getNumber(DebuggerAgentState::pauseOnExceptionsState, &pauseState); |
setPauseOnExceptionsImpl(&error, pauseState); |
+ ASSERT(error.isEmpty()); |
m_skipAllPauses = m_state->booleanProperty(DebuggerAgentState::skipAllPauses, false); |
int asyncCallStackDepth = 0; |
m_state->getNumber(DebuggerAgentState::asyncCallStackDepth, &asyncCallStackDepth); |
internalSetAsyncCallStackDepth(asyncCallStackDepth); |
+ |
+ protocol::ListValue* blackboxPatternsValue = m_state->getArray(DebuggerAgentState::blackboxPatterns); |
+ if (blackboxPatternsValue) { |
+ protocol::ErrorSupport errors; |
+ OwnPtr<protocol::Array<String16>> blackboxPatterns = protocol::Array<String16>::parse(blackboxPatternsValue, &errors); |
+ if (blackboxPatterns) |
+ setBlackboxPatterns(&error, blackboxPatterns.release()); |
+ ASSERT(!errors.hasErrors() && error.isEmpty()); |
+ } |
+ restoreBlackboxScripts(DebuggerAgentState::blackboxScriptsByHash, m_blackboxRangesByHash); |
dgozman
2016/04/20 02:06:40
Can we use empty ranges as a meaning for "fully bl
|
+ restoreBlackboxScripts(DebuggerAgentState::blackboxScriptsByURL, m_blackboxRangesByURL); |
+ restoreBlackboxRanges(DebuggerAgentState::blackboxRangesByHash, m_blackboxRangesByHash); |
+ restoreBlackboxRanges(DebuggerAgentState::blackboxRangesByURL, m_blackboxRangesByURL); |
+} |
+ |
+void V8DebuggerAgentImpl::restoreBlackboxScripts(const String16& key, BlackboxRangesByString& map) |
+{ |
+ protocol::ListValue* list = m_state->getArray(key); |
+ if (!list) |
+ return; |
+ Vector<std::pair<int, int>> blackboxedRanges(1); |
+ for (size_t i = 0; i < list->size(); ++i) { |
+ protocol::Value* val = list->at(i); |
+ String16 id; |
+ bool success = val->asString(&id); |
+ ASSERT_UNUSED(success, success); |
+ map.set(id, blackboxedRanges); |
+ } |
+} |
+ |
+void V8DebuggerAgentImpl::restoreBlackboxRanges(const String16& key, BlackboxRangesByString& map) |
+{ |
+ using protocol::Runtime::SourceRange; |
+ |
+ protocol::DictionaryValue* storedMap = m_state->getObject(key); |
+ if (!storedMap) |
+ return; |
+ protocol::ErrorSupport errorSupport; |
+ for (size_t i = 0; i < storedMap->size(); ++i) { |
+ auto value = storedMap->at(i); |
+ OwnPtr<protocol::Array<SourceRange>> ranges = protocol::Array<SourceRange>::parse(value.second, &errorSupport); |
+ ASSERT(!errorSupport.hasErrors()); |
+ Vector<std::pair<int, int>> blackboxedRanges(ranges->length() * 2); |
+ for (size_t i = 0; i < ranges->length(); ++i) { |
+ SourceRange* range = ranges->get(i); |
+ blackboxedRanges[i * 2] = std::make_pair(range->getStartLine(), range->getStartColumn()); |
+ blackboxedRanges[i * 2 + 1] = std::make_pair(range->getEndLine(), range->getEndColumn()); |
+ } |
+ map.set(value.first, blackboxedRanges); |
+ } |
} |
void V8DebuggerAgentImpl::setBreakpointsActive(ErrorString* errorString, bool active) |
@@ -505,11 +564,23 @@ bool V8DebuggerAgentImpl::isCallFrameWithUnknownScriptOrBlackboxed(JavaScriptCal |
// Unknown scripts are blackboxed. |
return true; |
} |
- auto itBlackboxedPositions = m_blackboxedPositions.find(String16::number(frame->sourceID())); |
- if (itBlackboxedPositions == m_blackboxedPositions.end()) |
+ V8DebuggerScript* script = it->second; |
+ if (m_blackboxPattern) { |
+ String16 scriptSourceURL = script->sourceURL(); |
+ if (!scriptSourceURL.isEmpty() && m_blackboxPattern->match(scriptSourceURL) != -1) |
+ return true; |
+ } |
+ auto itBlackboxedRangesByHash = m_blackboxRangesByHash.find(script->hash()); |
+ const Vector<std::pair<int, int>>* ranges = nullptr; |
+ if (itBlackboxedRangesByHash != m_blackboxRangesByHash.end()) { |
+ ranges = itBlackboxedRangesByHash->second; |
+ } else { |
+ auto itBlackboxedRangesByURL = m_blackboxRangesByURL.find(script->sourceURL()); |
+ if (itBlackboxedRangesByURL != m_blackboxRangesByURL.end()) |
+ ranges = itBlackboxedRangesByURL->second; |
+ } |
+ if (!ranges) |
return false; |
- |
- protocol::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... |
@@ -1050,42 +1121,92 @@ void V8DebuggerAgentImpl::allAsyncTasksCanceled() |
#endif |
} |
-void V8DebuggerAgentImpl::setBlackboxedRanges(ErrorString* error, const String16& scriptId, PassOwnPtr<protocol::Array<protocol::Debugger::ScriptPosition>> inPositions) |
+void V8DebuggerAgentImpl::setBlackboxPatterns(ErrorString* errorString, PassOwnPtr<protocol::Array<String16>> patterns) |
{ |
- if (!m_scripts.contains(scriptId)) { |
- *error = "No script with passed id."; |
+ if (!patterns->length()) { |
+ m_blackboxPattern = nullptr; |
+ m_state->setArray(DebuggerAgentState::blackboxPatterns, patterns->serialize()); |
return; |
} |
- if (!inPositions->length()) { |
- m_blackboxedPositions.remove(scriptId); |
+ String16 pattern; |
+ for (size_t i = 0; i < patterns->length() - 1; ++i) |
+ pattern = pattern + patterns->get(i) + "|"; |
+ pattern = "(" + pattern + patterns->get(patterns->length() - 1) + ")"; |
+ |
+ OwnPtr<V8Regex> regex = adoptPtr(new V8Regex(m_debugger, pattern, true /** caseSensitive */, false /** multiline */)); |
+ if (!regex->isValid()) { |
+ *errorString = "Pattern parser error: " + regex->errorMessage(); |
return; |
} |
- protocol::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."; |
- return; |
+ m_blackboxPattern = regex.release(); |
+ m_state->setArray(DebuggerAgentState::blackboxPatterns, patterns->serialize()); |
+} |
+ |
+void V8DebuggerAgentImpl::setScriptBlackboxed(ErrorString* errorString, const Maybe<String16>& hash, const Maybe<String16>& url, const Maybe<protocol::Array<protocol::Runtime::SourceRange>>& optRanges) |
+{ |
+ using protocol::Runtime::SourceRange; |
+ |
+ if (!hash.isJust() && !url.isJust()) { |
+ *errorString = "Hash or URL should be set"; |
+ return; |
+ } |
+ BlackboxRangesByString& idToBlackboxRanges = hash.isJust() ? m_blackboxRangesByHash : m_blackboxRangesByURL; |
+ String16 id = hash.isJust() ? hash.fromJust() : url.fromJust(); |
+ |
+ if (!optRanges.isJust()) { |
+ const String16& stateKey = hash.isJust() ? DebuggerAgentState::blackboxScriptsByHash : DebuggerAgentState::blackboxScriptsByURL; |
+ protocol::ListValue* stateBlackboxedScripts = m_state->getArray(stateKey); |
+ if (!stateBlackboxedScripts) { |
+ m_state->setArray(stateKey, protocol::ListValue::create()); |
+ stateBlackboxedScripts = m_state->getArray(stateKey); |
} |
- positions[i] = std::make_pair(position->getLine(), position->getColumn()); |
+ |
+ Vector<std::pair<int, int>> blackboxedRanges(1); |
+ idToBlackboxRanges.set(id, blackboxedRanges); |
+ stateBlackboxedScripts->pushValue(protocol::StringValue::create(id)); |
+ return; |
} |
- 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."; |
+ const String16& stateKey = hash.isJust() ? DebuggerAgentState::blackboxRangesByHash : DebuggerAgentState::blackboxRangesByURL; |
+ protocol::DictionaryValue* stateMap = m_state->getObject(stateKey); |
+ if (!stateMap) { |
+ m_state->setObject(stateKey, protocol::DictionaryValue::create()); |
+ stateMap = m_state->getObject(stateKey); |
+ } |
+ protocol::Array<SourceRange>* ranges = optRanges.fromJust(); |
+ if (!ranges->length()) { |
+ idToBlackboxRanges.remove(id); |
+ stateMap->remove(id); |
return; |
} |
- m_blackboxedPositions.set(scriptId, positions); |
+ String16 errors; |
dgozman
2016/04/20 02:06:40
Let's extract validation into a helper function.
|
+ for (size_t i = 0; i < ranges->length(); ++i) { |
+ SourceRange* range = ranges->get(i); |
+ if (range->getStartLine() > range->getEndLine()) |
+ errors = errors + " 'startLine' should be not more then 'endLine' in (" + String16::number(i + 1) + ")."; |
+ if (range->getStartLine() == range->getEndLine() && range->getStartColumn() >= range->getEndColumn()) |
+ errors = errors + " 'startColumn' should be less then 'endColumn' if 'startLine' == 'endLine' in (" + String16::number(i + 1) + ")."; |
+ if (i > 0) { |
+ SourceRange* prevRange = ranges->get(i - 1); |
+ if (prevRange->getEndLine() > range->getStartLine() || (prevRange->getEndLine() == range->getStartLine() && prevRange->getEndColumn() > range->getStartColumn())) |
+ errors = errors + " Records in ranges array should be sorted and disjoint."; |
+ } |
+ } |
+ if (!errors.isEmpty()) { |
+ *errorString = errors; |
+ return; |
+ } |
+ Vector<std::pair<int, int>> blackboxedRanges(ranges->length() * 2); |
+ for (size_t i = 0; i < ranges->length(); ++i) { |
+ SourceRange* range = ranges->get(i); |
+ blackboxedRanges[i * 2] = std::make_pair(range->getStartLine(), range->getStartColumn()); |
+ blackboxedRanges[i * 2 + 1] = std::make_pair(range->getEndLine(), range->getEndColumn()); |
+ } |
+ idToBlackboxRanges.set(id, blackboxedRanges); |
+ stateMap->setArray(id, ranges->serialize()); |
} |
void V8DebuggerAgentImpl::willExecuteScript(int scriptId) |
@@ -1415,7 +1536,6 @@ void V8DebuggerAgentImpl::reset() |
return; |
m_scheduledDebuggerStep = NoStep; |
m_scripts.clear(); |
- m_blackboxedPositions.clear(); |
m_breakpointIdToDebuggerBreakpointIds.clear(); |
allAsyncTasksCanceled(); |
} |