Chromium Code Reviews| 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(); |
| } |