| 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 7fc081cc11bd612915d5eca7210ff148cb85dda1..6a24e8834262ca193ed7ccebf2bfd0cf1b64548f 100644
|
| --- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp
|
| +++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp
|
| @@ -49,6 +49,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";
|
| @@ -58,6 +60,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;
|
| @@ -113,6 +119,43 @@ static bool positionComparator(const std::pair<int, int>& a, const std::pair<int
|
| return a.second < b.second;
|
| }
|
|
|
| +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
|
| @@ -255,7 +298,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);
|
| @@ -316,6 +363,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());
|
| + setBlackboxPatterns(&error, patterns.release());
|
| + ASSERT(!error.length());
|
| + }
|
| +
|
| + protocol::ListValue* savedHashes = m_state->getArray(DebuggerAgentState::blackboxHashes);
|
| + if (!savedHashes)
|
| + return;
|
| + for (size_t i = 0; i < savedHashes->length(); ++i) {
|
| + protocol::DictionaryValue* savedHash = protocol::DictionaryValue::cast(savedHashes->get(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());
|
| + setBlackboxRanges(&error, hash, positions.release());
|
| + ASSERT(!error.length());
|
| + }
|
| }
|
|
|
| void V8DebuggerAgentImpl::setBreakpointsActive(ErrorString* errorString, bool active)
|
| @@ -548,20 +628,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()
|
| @@ -1279,43 +1374,55 @@ 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::setBlackboxRanges(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::setBlackboxPatterns(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 type = pattern->getType();
|
| + if (type == protocol::Debugger::BlackboxPatternTypeEnum::RegExp) {
|
| + blackboxPattern = blackboxPattern.isEmpty() ? pattern->getValue() : (blackboxPattern + "|" + pattern->getValue());
|
| + } else if (type== protocol::Debugger::BlackboxPatternTypeEnum::Hash) {
|
| + hashes.add(pattern->getValue());
|
| + } else {
|
| + *error = "Unknown blackbox pattern type.";
|
| return;
|
| }
|
| - 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;
|
| - *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)
|
| @@ -1475,6 +1582,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;
|
| @@ -1650,7 +1758,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();
|
|
|