WebKit Bugzilla
Attachment 372168 Details for
Bug 17240
: Web Inspector: implement blackboxing of script resources
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-17240-20190614193450.patch (text/plain), 67.65 KB, created by
Devin Rousso
on 2019-06-14 19:34:51 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Devin Rousso
Created:
2019-06-14 19:34:51 PDT
Size:
67.65 KB
patch
obsolete
>diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index b69160bbd2a5852e0875ad425ad3eb33c3e06244..17bcf43803bc09686b5b537cca1e7439acdc5925 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,46 @@ >+2019-06-14 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: implement blackboxing of script resources >+ https://bugs.webkit.org/show_bug.cgi?id=17240 >+ <rdar://problem/5732847> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ When a script is blackboxed and the debugger attempts to pause in that script, the pause >+ reason/data will be saved and execution will continue until it has left the blackboxed >+ script. Once outside, execution is paused with the saved reason/data. >+ >+ This is especially useful when debugging issues using libraries/frameworks, as it allows the >+ developer to "skip" the internal logic of the library/framework and instead focus only on >+ how they're using it. >+ >+ * inspector/protocol/Debugger.json: >+ Add `setShouldBlackboxURL` command. >+ >+ * inspector/agents/InspectorDebuggerAgent.h: >+ * inspector/agents/InspectorDebuggerAgent.cpp: >+ (Inspector::isWebKitInjectedScript): >+ (Inspector::InspectorDebuggerAgent::enable): >+ (Inspector::InspectorDebuggerAgent::updateBreakReasonAndData): >+ (Inspector::InspectorDebuggerAgent::schedulePauseOnNextStatement): >+ (Inspector::InspectorDebuggerAgent::setShouldBlackboxURL): Added. >+ (Inspector::InspectorDebuggerAgent::setPauseForInternalScripts): >+ (Inspector::InspectorDebuggerAgent::didParseSource): >+ (Inspector::InspectorDebuggerAgent::toggleBlackboxForScriptsMatchingPredicate): Added. >+ (Inspector::InspectorDebuggerAgent::didPause): >+ (Inspector::InspectorDebuggerAgent::breakProgram): >+ (Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState): >+ (Inspector::InspectorDebuggerAgent::clearBreakDetails): >+ >+ * debugger/Debugger.h: >+ * debugger/Debugger.cpp: >+ (JSC::Debugger::pauseIfNeeded): >+ (JSC::Debugger::isBlackboxed const): Added. >+ (JSC::Debugger::setShouldBlackbox): Added. >+ (JSC::Debugger::isBlacklisted const): Deleted. >+ (JSC::Debugger::addToBlacklist): Deleted. >+ (JSC::Debugger::clearBlacklist): Deleted. >+ > 2019-06-14 Keith Miller <keith_miller@apple.com> > > Restore PAC based cage. >diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index 926b90cc67776b20e5fc5f9541c3d14024093263..9fab35bb978df617da59c431169604ca14102792 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,79 @@ >+2019-06-14 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: implement blackboxing of script resources >+ https://bugs.webkit.org/show_bug.cgi?id=17240 >+ <rdar://problem/5732847> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ When a script is blackboxed and the debugger attempts to pause in that script, the pause >+ reason/data will be saved and execution will continue until it has left the blackboxed >+ script. Once outside, execution is paused with the saved reason/data. >+ >+ This is especially useful when debugging issues using libraries/frameworks, as it allows the >+ developer to "skip" the internal logic of the library/framework and instead focus only on >+ how they're using it. >+ >+ * UserInterface/Controllers/DebuggerManager.js: >+ (WI.DebuggerManager): >+ (WI.DebuggerManager.prototype.initializeTarget): >+ (WI.DebuggerManager.supportsBlackboxingScripts): Added. >+ (WI.DebuggerManager.pauseReasonFromPayload): Added. >+ (WI.DebuggerManager.prototype.isScriptBlackboxed): Added. >+ (WI.DebuggerManager.prototype.setShouldBlackboxScript): Added. >+ (WI.DebuggerManager.prototype._pauseReasonFromPayload): >+ (WI.DebuggerManager.prototype._pauseReasonFromPayload): Deleted. >+ >+ * UserInterface/Models/SourceCode.js: >+ (WI.SourceCode.prototype.get isScript): Added. >+ * UserInterface/Models/Script.js: >+ (WI.Script.prototype.get isScript): Added. >+ * UserInterface/Models/Resource.js: >+ (WI.Resource.prototype.get isScript): Added. >+ Provide a more straightforward way of determining if a `WI.SourceCode` is a script. >+ >+ * UserInterface/Views/DebuggerSidebarPanel.js: >+ (WI.DebuggerSidebarPanel.prototype._updatePauseReason): >+ (WI.DebuggerSidebarPanel.prototype._updatePauseReasonSection): >+ * UserInterface/Views/SourcesNavigationSidebarPanel.js: >+ (WI.SourcesNavigationSidebarPanel.prototype._updatePauseReason): >+ (WI.SourcesNavigationSidebarPanel.prototype._updatePauseReasonSection): >+ Display the original pause reason and breakpoint (if applicable) when pausing after leaving >+ a blackboxed script. >+ >+ * UserInterface/Views/SourceCodeTreeElement.js: >+ (WI.SourceCodeTreeElement.prototype.canSelectOnMouseDown): >+ (WI.SourceCodeTreeElement.prototype.updateStatus): >+ (WI.SourceCodeTreeElement.prototype._updateSourceCode): >+ (WI.SourceCodeTreeElement.prototype._updateToggleBlackboxImageElementState): >+ (WI.SourceCodeTreeElement.prototype._handleToggleBlackboxedImageElementClicked): >+ * UserInterface/Views/SourceCodeTreeElement.css: Added. >+ (.tree-outline .item .status > .toggle-script-blackboxed): >+ (.tree-outline:not(.navigation-sidebar-panel-content-tree-outline) .item .status > .toggle-script-blackboxed,): >+ (.tree-outline:focus .item.selected .status > .toggle-script-blackboxed): >+ (.tree-outline .item .status > .toggle-script-blackboxed.blackboxed): >+ (@media (prefers-color-scheme: dark) .tree-outline .item .status > .toggle-script-blackboxed): >+ >+ * UserInterface/Views/ResourceTreeElement.js: >+ (WI.ResourceTreeElement.prototype._updateResource): >+ (WI.ResourceTreeElement.prototype.updateStatus): Added. >+ (WI.ResourceTreeElement.prototype._updateStatus): Deleted. >+ Make sure that the loading indicator doesn't override the blackbox toggle. >+ >+ * UserInterface/Base/Setting.js: >+ (WI.Setting.prototype.set value): >+ (WI.Setting.prototype.save): Added. >+ When modifying an array value, that doesn't go through `WI.Setting.prototype.set value`, so >+ we need a more "manual" way of saving the new value. >+ >+ * UserInterface/Main.html: >+ * Localizations/en.lproj/localizedStrings.js: >+ >+ * UserInterface/Test/TestHarness.js: >+ (TestHarness.prototype.newline): Added. >+ (TestHarness.prototype.expectException): >+ Add a special case for logging error message objects when running protocol tests. >+ > 2019-06-13 Devin Rousso <drousso@apple.com> > > Web Inspector: REGRESSION(r246178): extra spaces added in at-rules when formatting CSS >diff --git a/Source/JavaScriptCore/debugger/Debugger.cpp b/Source/JavaScriptCore/debugger/Debugger.cpp >index 09a6ded96e077e34c44d07ad93efa16a70c8609e..296007b21fab58d380eda8a8eec76231d4a1888d 100644 >--- a/Source/JavaScriptCore/debugger/Debugger.cpp >+++ b/Source/JavaScriptCore/debugger/Debugger.cpp >@@ -694,10 +694,6 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame) > if (m_suppressAllPauses) > return; > >- intptr_t sourceID = DebuggerCallFrame::sourceIDForCallFrame(m_currentCallFrame); >- if (isBlacklisted(sourceID)) >- return; >- > DebuggerPausedScope debuggerPausedScope(*this); > > bool pauseNow = m_pauseAtNextOpportunity; >@@ -706,13 +702,15 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame) > bool didPauseForStep = pauseNow; > > Breakpoint breakpoint; >- TextPosition position = DebuggerCallFrame::positionForCallFrame(vm, m_currentCallFrame); >+ auto sourceID = DebuggerCallFrame::sourceIDForCallFrame(m_currentCallFrame); >+ auto position = DebuggerCallFrame::positionForCallFrame(vm, m_currentCallFrame); > bool didHitBreakpoint = hasBreakpoint(sourceID, position, &breakpoint); > pauseNow |= didHitBreakpoint; > m_lastExecutedLine = position.m_line.zeroBasedInt(); > if (!pauseNow) > return; > >+ bool afterBlackboxedScript = m_afterBlackboxedScript; > clearNextPauseState(); > > // Make sure we are not going to pause again on breakpoint actions by >@@ -736,8 +734,14 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame) > m_pausingBreakpointID = breakpoint.id; > } > >+ if (isBlackboxed(sourceID)) { >+ m_afterBlackboxedScript = true; >+ setPauseOnNextStatement(true); >+ return; >+ } >+ > { >- PauseReasonDeclaration reason(*this, didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause); >+ PauseReasonDeclaration reason(*this, afterBlackboxedScript ? PausedAfterBlackboxedScript : (didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause)); > handlePause(vmEntryGlobalObject, m_reasonForPause); > scope.releaseAssertNoException(); > } >@@ -908,6 +912,7 @@ void Debugger::clearNextPauseState() > m_pauseOnCallFrame = nullptr; > m_pauseAtNextOpportunity = false; > m_pauseOnStepOut = false; >+ m_afterBlackboxedScript = false; > } > > void Debugger::didReachBreakpoint(CallFrame* callFrame) >@@ -928,19 +933,17 @@ DebuggerCallFrame& Debugger::currentDebuggerCallFrame() > return *m_currentDebuggerCallFrame; > } > >-bool Debugger::isBlacklisted(SourceID sourceID) const >+bool Debugger::isBlackboxed(SourceID sourceID) const > { >- return m_blacklistedScripts.contains(sourceID); >+ return m_blackboxedScripts.contains(sourceID); > } > >-void Debugger::addToBlacklist(SourceID sourceID) >+void Debugger::setShouldBlackbox(SourceID sourceID, bool shouldBlackbox) > { >- m_blacklistedScripts.add(sourceID); >-} >- >-void Debugger::clearBlacklist() >-{ >- m_blacklistedScripts.clear(); >+ if (shouldBlackbox) >+ m_blackboxedScripts.add(sourceID); >+ else >+ m_blackboxedScripts.remove(sourceID); > } > > } // namespace JSC >diff --git a/Source/JavaScriptCore/debugger/Debugger.h b/Source/JavaScriptCore/debugger/Debugger.h >index bcd72ea09f5f717a65f65d7d2efc175e023e6990..289ecd579f40440c833009ac46ef005023b09fc7 100644 >--- a/Source/JavaScriptCore/debugger/Debugger.h >+++ b/Source/JavaScriptCore/debugger/Debugger.h >@@ -99,6 +99,7 @@ public: > PausedAtEndOfProgram, > PausedForBreakpoint, > PausedForDebuggerStatement, >+ PausedAfterBlackboxedScript, > }; > ReasonForPause reasonForPause() const { return m_reasonForPause; } > BreakpointID pausingBreakpointID() const { return m_pausingBreakpointID; } >@@ -110,9 +111,8 @@ public: > void stepOverStatement(); > void stepOutOfFunction(); > >- bool isBlacklisted(SourceID) const; >- void addToBlacklist(SourceID); >- void clearBlacklist(); >+ bool isBlackboxed(SourceID) const; >+ void setShouldBlackbox(SourceID, bool shouldBlackbox); > > bool isPaused() const { return m_isPaused; } > bool isStepping() const { return m_steppingMode == SteppingModeEnabled; } >@@ -221,7 +221,7 @@ private: > VM& m_vm; > HashSet<JSGlobalObject*> m_globalObjects; > HashMap<SourceID, DebuggerParseData, WTF::IntHash<SourceID>, WTF::UnsignedWithZeroKeyHashTraits<SourceID>> m_parseDataMap; >- HashSet<SourceID, WTF::IntHash<SourceID>, WTF::UnsignedWithZeroKeyHashTraits<SourceID>> m_blacklistedScripts; >+ HashSet<SourceID, WTF::IntHash<SourceID>, WTF::UnsignedWithZeroKeyHashTraits<SourceID>> m_blackboxedScripts; > > PauseOnExceptionsState m_pauseOnExceptionsState; > bool m_pauseAtNextOpportunity : 1; >@@ -239,6 +239,7 @@ private: > CallFrame* m_currentCallFrame { nullptr }; > unsigned m_lastExecutedLine; > SourceID m_lastExecutedSourceID; >+ bool m_afterBlackboxedScript { false }; > > BreakpointID m_topBreakpointID; > BreakpointID m_pausingBreakpointID; >diff --git a/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp >index 7e3dc65e645cd8f1e898c46af55518c9c34ff40d..6f635b66bc094312f810cab4c0083a2a0955db91 100644 >--- a/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp >+++ b/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp >@@ -41,6 +41,7 @@ > #include "ScriptCallStackFactory.h" > #include "ScriptDebugServer.h" > #include "ScriptObject.h" >+#include <wtf/Function.h> > #include <wtf/JSONValues.h> > #include <wtf/NeverDestroyed.h> > #include <wtf/Stopwatch.h> >@@ -60,6 +61,11 @@ static String objectGroupForBreakpointAction(const ScriptBreakpointAction& actio > return makeString("breakpoint-action-", action.identifier); > } > >+static bool isWebKitInjectedScript(const String& sourceURL) >+{ >+ return sourceURL.startsWith("__InjectedScript_") && sourceURL.endsWith(".js"); >+} >+ > InspectorDebuggerAgent::InspectorDebuggerAgent(AgentContext& context) > : InspectorAgentBase("Debugger"_s) > , m_frontendDispatcher(std::make_unique<DebuggerFrontendDispatcher>(context.frontendRouter)) >@@ -96,6 +102,20 @@ void InspectorDebuggerAgent::enable() > > for (auto* listener : copyToVector(m_listeners)) > listener->debuggerWasEnabled(); >+ >+ toggleBlackboxForScriptsMatchingPredicate(true, [&] (const Script& script) { >+ if (!script.sourceURL.isEmpty()) { >+ if (m_pauseForInternalScripts && isWebKitInjectedScript(script.sourceURL)) >+ return true; >+ if (m_blackboxedURLs.contains(script.sourceURL)) >+ return true; >+ } >+ if (!script.url.isEmpty()) { >+ if (m_blackboxedURLs.contains(script.url)) >+ return true; >+ } >+ return false; >+ }); > } > > void InspectorDebuggerAgent::disable(bool isBeingDestroyed) >@@ -171,6 +191,17 @@ void InspectorDebuggerAgent::setSuppressAllPauses(bool suppress) > m_scriptDebugServer.setSuppressAllPauses(suppress); > } > >+void InspectorDebuggerAgent::updateBreakReasonAndData(DebuggerFrontendDispatcher::Reason reason, RefPtr<JSON::Object>&& data) >+{ >+ if (m_breakReason != DebuggerFrontendDispatcher::Reason::BlackboxedScript) { >+ m_lastBreakReason = m_breakReason; >+ m_lastBreakData = WTFMove(m_breakData); >+ } >+ >+ m_breakReason = reason; >+ m_breakData = WTFMove(data); >+} >+ > static RefPtr<JSON::Object> buildAssertPauseReason(const String& message) > { > auto reason = Protocol::Debugger::AssertPauseReason::create().release(); >@@ -701,8 +732,7 @@ void InspectorDebuggerAgent::schedulePauseOnNextStatement(DebuggerFrontendDispat > > m_javaScriptPauseScheduled = true; > >- m_breakReason = breakReason; >- m_breakData = WTFMove(data); >+ updateBreakReasonAndData(breakReason, WTFMove(data)); > > JSC::JSLockHolder locker(m_scriptDebugServer.vm()); > m_scriptDebugServer.setPauseOnNextStatement(true); >@@ -857,6 +887,28 @@ void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString& errorString, const > } > } > >+void InspectorDebuggerAgent::setShouldBlackboxURL(ErrorString& errorString, const String& url, bool shouldBlackbox) >+{ >+ if (url.isEmpty()) { >+ errorString = "URL must not be empty"_s; >+ return; >+ } >+ >+ if (isWebKitInjectedScript(url)) { >+ errorString = "Blackboxing of internal scripts is controlled by 'setPauseForInternalScripts'"; >+ return; >+ } >+ >+ if (shouldBlackbox) >+ m_blackboxedURLs.add(url); >+ else >+ m_blackboxedURLs.remove(url); >+ >+ toggleBlackboxForScriptsMatchingPredicate(shouldBlackbox, [&] (const Script& script) { >+ return script.sourceURL == url || script.url == url; >+ }); >+} >+ > void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText) > { > if (m_scriptDebugServer.pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions) >@@ -884,13 +936,9 @@ void InspectorDebuggerAgent::setPauseForInternalScripts(ErrorString&, bool shoul > > m_pauseForInternalScripts = shouldPause; > >- if (m_pauseForInternalScripts) >- m_scriptDebugServer.clearBlacklist(); >-} >- >-static bool isWebKitInjectedScript(const String& sourceURL) >-{ >- return sourceURL.startsWith("__InjectedScript_") && sourceURL.endsWith(".js"); >+ toggleBlackboxForScriptsMatchingPredicate(!m_pauseForInternalScripts, [&] (const Script& script) { >+ return isWebKitInjectedScript(script.sourceURL); >+ }); > } > > void InspectorDebuggerAgent::didParseSource(JSC::SourceID sourceID, const Script& script) >@@ -910,7 +958,10 @@ void InspectorDebuggerAgent::didParseSource(JSC::SourceID sourceID, const Script > m_scripts.set(sourceID, script); > > if (hasSourceURL && isWebKitInjectedScript(sourceURL) && !m_pauseForInternalScripts) >- m_scriptDebugServer.addToBlacklist(sourceID); >+ m_scriptDebugServer.setShouldBlackbox(sourceID, true); >+ >+ if ((hasSourceURL && m_blackboxedURLs.contains(sourceURL)) || (!script.url.isEmpty() && m_blackboxedURLs.contains(script.url))) >+ m_scriptDebugServer.setShouldBlackbox(sourceID, true); > > String scriptURLForBreakpoints = hasSourceURL ? script.sourceURL : script.url; > if (scriptURLForBreakpoints.isEmpty()) >@@ -962,6 +1013,14 @@ void InspectorDebuggerAgent::failedToParseSource(const String& url, const String > m_frontendDispatcher->scriptFailedToParse(url, data, firstLine, errorLine, errorMessage); > } > >+void InspectorDebuggerAgent::toggleBlackboxForScriptsMatchingPredicate(bool shouldBlackbox, WTF::Function<bool(const Script&)> predicate) >+{ >+ for (auto& entry : m_scripts) { >+ if (predicate(entry.value)) >+ m_scriptDebugServer.setShouldBlackbox(entry.key, shouldBlackbox); >+ } >+} >+ > void InspectorDebuggerAgent::didPause(JSC::ExecState& scriptState, JSC::JSValue callFrames, JSC::JSValue exceptionOrCaughtValue) > { > ASSERT(!m_pausedScriptState); >@@ -974,21 +1033,27 @@ void InspectorDebuggerAgent::didPause(JSC::ExecState& scriptState, JSC::JSValue > if (m_breakReason == DebuggerFrontendDispatcher::Reason::Other) { > switch (m_scriptDebugServer.reasonForPause()) { > case JSC::Debugger::PausedForBreakpoint: { >- JSC::BreakpointID debuggerBreakpointId = m_scriptDebugServer.pausingBreakpointID(); >- if (debuggerBreakpointId != m_continueToLocationBreakpointID) { >- m_breakReason = DebuggerFrontendDispatcher::Reason::Breakpoint; >- m_breakData = buildBreakpointPauseReason(debuggerBreakpointId); >- } >+ auto debuggerBreakpointId = m_scriptDebugServer.pausingBreakpointID(); >+ if (debuggerBreakpointId != m_continueToLocationBreakpointID) >+ updateBreakReasonAndData(DebuggerFrontendDispatcher::Reason::Breakpoint, buildBreakpointPauseReason(debuggerBreakpointId)); > break; > } > case JSC::Debugger::PausedForDebuggerStatement: >- m_breakReason = DebuggerFrontendDispatcher::Reason::DebuggerStatement; >- m_breakData = nullptr; >+ updateBreakReasonAndData(DebuggerFrontendDispatcher::Reason::DebuggerStatement, nullptr); > break; > case JSC::Debugger::PausedForException: >- m_breakReason = DebuggerFrontendDispatcher::Reason::Exception; >- m_breakData = buildExceptionPauseReason(exceptionOrCaughtValue, injectedScript); >+ updateBreakReasonAndData(DebuggerFrontendDispatcher::Reason::Exception, buildExceptionPauseReason(exceptionOrCaughtValue, injectedScript)); > break; >+ case JSC::Debugger::PausedAfterBlackboxedScript: { >+ // There should be no break data, as we would've already continued past the breakpoint. >+ ASSERT(!m_breakData); >+ >+ // Don't call `updateBreakReasonAndData` so as to not override `m_lastBreakData`. >+ if (m_breakReason != DebuggerFrontendDispatcher::Reason::BlackboxedScript) >+ m_lastBreakReason = m_breakReason; >+ m_breakReason = DebuggerFrontendDispatcher::Reason::BlackboxedScript; >+ break; >+ } > case JSC::Debugger::PausedAtStatement: > case JSC::Debugger::PausedAtExpression: > case JSC::Debugger::PausedBeforeReturn: >@@ -1001,6 +1066,24 @@ void InspectorDebuggerAgent::didPause(JSC::ExecState& scriptState, JSC::JSValue > } > } > >+ if (m_scriptDebugServer.reasonForPause() == JSC::Debugger::PausedAfterBlackboxedScript) { >+ // Ensure that `m_lastBreakReason` is populated with the most recent data. >+ updateBreakReasonAndData(m_breakReason, nullptr); >+ >+ RefPtr<JSON::Object> data = nullptr; >+ if (auto debuggerBreakpointId = m_scriptDebugServer.pausingBreakpointID()) { >+ ASSERT(debuggerBreakpointId != m_continueToLocationBreakpointID); >+ data = JSON::Object::create(); >+ data->setString("originalReason", Protocol::InspectorHelpers::getEnumConstantValue(DebuggerFrontendDispatcher::Reason::Breakpoint)); >+ data->setValue("originalData", buildBreakpointPauseReason(debuggerBreakpointId)); >+ } else if (m_lastBreakData) { >+ data = JSON::Object::create(); >+ data->setString("originalReason", Protocol::InspectorHelpers::getEnumConstantValue(m_lastBreakReason)); >+ data->setValue("originalData", m_lastBreakData); >+ } >+ updateBreakReasonAndData(DebuggerFrontendDispatcher::Reason::BlackboxedScript, WTFMove(data)); >+ } >+ > // Set $exception to the exception or caught value. > if (exceptionOrCaughtValue && !injectedScript.hasNoValue()) { > injectedScript.setExceptionValue(exceptionOrCaughtValue); >@@ -1071,8 +1154,8 @@ void InspectorDebuggerAgent::didContinue() > > void InspectorDebuggerAgent::breakProgram(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<JSON::Object>&& data) > { >- m_breakReason = breakReason; >- m_breakData = WTFMove(data); >+ updateBreakReasonAndData(breakReason, WTFMove(data)); >+ > m_scriptDebugServer.breakProgram(); > } > >@@ -1093,7 +1176,7 @@ void InspectorDebuggerAgent::clearDebuggerBreakpointState() > JSC::JSLockHolder holder(m_scriptDebugServer.vm()); > m_scriptDebugServer.clearBreakpointActions(); > m_scriptDebugServer.clearBreakpoints(); >- m_scriptDebugServer.clearBlacklist(); >+ toggleBlackboxForScriptsMatchingPredicate(false, [] (const Script&) { return true; }); > } > > m_pausedScriptState = nullptr; >@@ -1135,8 +1218,7 @@ bool InspectorDebuggerAgent::assertPaused(ErrorString& errorString) > > void InspectorDebuggerAgent::clearBreakDetails() > { >- m_breakReason = DebuggerFrontendDispatcher::Reason::Other; >- m_breakData = nullptr; >+ updateBreakReasonAndData(DebuggerFrontendDispatcher::Reason::Other, nullptr); > } > > void InspectorDebuggerAgent::clearExceptionValue() >diff --git a/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h >index 1311c4f162c6f00e1c577bb2ea1a79eafb8efc5c..83e7a55e6601129353ebc81544445efc32dd17f7 100644 >--- a/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h >+++ b/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h >@@ -81,6 +81,7 @@ public: > void setPauseOnExceptions(ErrorString&, const String& pauseState) final; > void setPauseOnAssertions(ErrorString&, bool enabled) final; > void evaluateOnCallFrame(ErrorString&, const String& callFrameId, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, Optional<bool>& wasThrown, Optional<int>& savedResultIndex) final; >+ void setShouldBlackboxURL(ErrorString&, const String& url, bool shouldBlackbox) final; > > bool isPaused() const; > bool breakpointsActive() const; >@@ -144,6 +145,8 @@ private: > void didParseSource(JSC::SourceID, const Script&) final; > void failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage) final; > >+ void toggleBlackboxForScriptsMatchingPredicate(bool shouldBlackbox, WTF::Function<bool(const Script&)>); >+ > void breakpointActionSound(int breakpointActionIdentifier) final; > void breakpointActionProbe(JSC::ExecState&, const ScriptBreakpointAction&, unsigned batchId, unsigned sampleId, JSC::JSValue sample) final; > >@@ -163,6 +166,8 @@ private: > void willStepAndMayBecomeIdle(); > void didBecomeIdle(); > >+ void updateBreakReasonAndData(DebuggerFrontendDispatcher::Reason, RefPtr<JSON::Object>&& data); >+ > RefPtr<JSON::Object> buildBreakpointPauseReason(JSC::BreakpointID); > RefPtr<JSON::Object> buildExceptionPauseReason(JSC::JSValue exception, const InjectedScript&); > >@@ -177,6 +182,7 @@ private: > ScriptDebugServer& m_scriptDebugServer; > InjectedScriptManager& m_injectedScriptManager; > HashMap<JSC::SourceID, Script> m_scripts; >+ HashSet<String> m_blackboxedURLs; > > HashSet<Listener*> m_listeners; > >@@ -191,6 +197,9 @@ private: > RefPtr<JSON::Object> m_breakData; > ShouldDispatchResumed m_conditionToDispatchResumed { ShouldDispatchResumed::No }; > >+ DebuggerFrontendDispatcher::Reason m_lastBreakReason; >+ RefPtr<JSON::Object> m_lastBreakData; >+ > HashMap<AsyncCallIdentifier, RefPtr<AsyncStackTrace>> m_pendingAsyncCalls; > Optional<AsyncCallIdentifier> m_currentAsyncCallIdentifier; > int m_asyncStackTraceDepth { 0 }; >diff --git a/Source/JavaScriptCore/inspector/protocol/Debugger.json b/Source/JavaScriptCore/inspector/protocol/Debugger.json >index a5495ca1103a870728013cfdf4063bff98341189..9757588a05e20126e92714df03491797a2a173ee 100644 >--- a/Source/JavaScriptCore/inspector/protocol/Debugger.json >+++ b/Source/JavaScriptCore/inspector/protocol/Debugger.json >@@ -286,6 +286,14 @@ > { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, > { "name": "savedResultIndex", "type": "integer", "optional": true, "description": "If the result was saved, this is the $n index that can be used to access the value." } > ] >+ }, >+ { >+ "name": "setShouldBlackboxURL", >+ "description": "Sets whether the given URL should be in the list of blackboxed scripts, which are ignored when pausing/stepping/debugging.", >+ "parameters": [ >+ { "name": "url", "type": "string" }, >+ { "name": "shouldBlackbox", "type": "boolean" } >+ ] > } > ], > "events": [ >@@ -333,7 +341,7 @@ > "description": "Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria.", > "parameters": [ > { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, >- { "name": "reason", "type": "string", "enum": ["XHR", "Fetch", "DOM", "AnimationFrame", "EventListener", "Timer", "exception", "assert", "CSPViolation", "DebuggerStatement", "Breakpoint", "PauseOnNextStatement", "other"], "description": "Pause reason." }, >+ { "name": "reason", "type": "string", "enum": ["XHR", "Fetch", "DOM", "AnimationFrame", "EventListener", "Timer", "exception", "assert", "CSPViolation", "DebuggerStatement", "Breakpoint", "PauseOnNextStatement", "BlackboxedScript", "other"], "description": "Pause reason." }, > { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." }, > { "name": "asyncStackTrace", "$ref": "Console.StackTrace", "optional": true, "description": "Linked list of asynchronous StackTraces." } > ] >diff --git a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >index 9a3c9ea4c4a35e98c0aa6440aee3fc91aae16296..5702284ea0bc37313399366a811c1c5c6ebcbf8c 100644 >--- a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >+++ b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >@@ -321,6 +321,7 @@ localizedStrings["Debugger:"] = "Debugger:"; > localizedStrings["Debugs"] = "Debugs"; > localizedStrings["Decoded"] = "Decoded"; > localizedStrings["Default"] = "Default"; >+localizedStrings["Deferred pause from blackboxed script"] = "Deferred pause from blackboxed script"; > localizedStrings["Delete"] = "Delete"; > localizedStrings["Delete Breakpoint"] = "Delete Breakpoint"; > localizedStrings["Delete Breakpoints"] = "Delete Breakpoints"; >@@ -565,6 +566,7 @@ localizedStrings["IP Address"] = "IP Address"; > localizedStrings["Identity"] = "Identity"; > localizedStrings["Idle"] = "Idle"; > localizedStrings["Ignore"] = "Ignore"; >+localizedStrings["Ignore script when debugging"] = "Ignore script when debugging"; > localizedStrings["Ignore the resource cache when loading resources"] = "Ignore the resource cache when loading resources"; > localizedStrings["Ignored"] = "Ignored"; > localizedStrings["Image"] = "Image"; >@@ -575,6 +577,7 @@ localizedStrings["Import"] = "Import"; > localizedStrings["Imported"] = "Imported"; > localizedStrings["Imported - %s"] = "Imported - %s"; > localizedStrings["Imported \u2014 %s"] = "Imported \u2014 %s"; >+localizedStrings["Include script when debugging"] = "Include script when debugging"; > localizedStrings["Incomplete"] = "Incomplete"; > localizedStrings["Indent width:"] = "Indent width:"; > localizedStrings["Index"] = "Index"; >diff --git a/Source/WebInspectorUI/UserInterface/Base/Setting.js b/Source/WebInspectorUI/UserInterface/Base/Setting.js >index bfa983806359e22083863b7fe6dc0e6fde2a50d3..c8eb793d657bf805168b9e464dbcfa60086e636a 100644 >--- a/Source/WebInspectorUI/UserInterface/Base/Setting.js >+++ b/Source/WebInspectorUI/UserInterface/Base/Setting.js >@@ -113,9 +113,13 @@ WI.Setting = class Setting extends WI.Object > > this._value = value; > >+ this.save(); >+ } >+ >+ save() >+ { > if (!window.InspectorTest && window.localStorage) { > try { >- // Use Object.shallowEqual to properly compare objects. > if (Object.shallowEqual(this._value, this._defaultValue)) > delete window.localStorage[this._localStorageKey]; > else >diff --git a/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js b/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js >index 7aaeeb86849c9a3642363d9b208db9414b618567..fd44e90f7b88c2c72efa65d03edf8510d1315b0e 100644 >--- a/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js >+++ b/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js >@@ -72,6 +72,8 @@ WI.DebuggerManager = class DebuggerManager extends WI.Object > }); > this._assertionFailuresBreakpoint.resolved = true; > >+ this._blackboxURLsSetting = new WI.Setting("debugger-blackbox-urls", []); >+ > this._breakpoints = []; > this._breakpointContentIdentifierMap = new Multimap; > this._breakpointScriptIdentifierMap = new Multimap; >@@ -150,6 +152,11 @@ WI.DebuggerManager = class DebuggerManager extends WI.Object > if (target.DebuggerAgent.setPauseForInternalScripts) > target.DebuggerAgent.setPauseForInternalScripts(WI.settings.pauseForInternalScripts.value); > >+ if (target.DebuggerAgent.setShouldBlackboxURL) { >+ for (let url of this._blackboxURLsSetting.value) >+ target.DebuggerAgent.setShouldBlackboxURL(url, true); >+ } >+ > if (this.paused) > targetData.pauseIfNeeded(); > >@@ -165,6 +172,48 @@ WI.DebuggerManager = class DebuggerManager extends WI.Object > this._restoringBreakpoints = false; > } > >+ // Static >+ >+ static supportsBlackboxingScripts() >+ { >+ return InspectorBackend.domains.Debugger.setShouldBlackboxURL; >+ } >+ >+ static pauseReasonFromPayload(payload) >+ { >+ // FIXME: Handle other backend pause reasons. >+ switch (payload) { >+ case DebuggerAgent.PausedReason.AnimationFrame: >+ return WI.DebuggerManager.PauseReason.AnimationFrame; >+ case DebuggerAgent.PausedReason.Assert: >+ return WI.DebuggerManager.PauseReason.Assertion; >+ case DebuggerAgent.PausedReason.BlackboxedScript: >+ return WI.DebuggerManager.PauseReason.BlackboxedScript; >+ case DebuggerAgent.PausedReason.Breakpoint: >+ return WI.DebuggerManager.PauseReason.Breakpoint; >+ case DebuggerAgent.PausedReason.CSPViolation: >+ return WI.DebuggerManager.PauseReason.CSPViolation; >+ case DebuggerAgent.PausedReason.DOM: >+ return WI.DebuggerManager.PauseReason.DOM; >+ case DebuggerAgent.PausedReason.DebuggerStatement: >+ return WI.DebuggerManager.PauseReason.DebuggerStatement; >+ case DebuggerAgent.PausedReason.EventListener: >+ return WI.DebuggerManager.PauseReason.EventListener; >+ case DebuggerAgent.PausedReason.Exception: >+ return WI.DebuggerManager.PauseReason.Exception; >+ case DebuggerAgent.PausedReason.Fetch: >+ return WI.DebuggerManager.PauseReason.Fetch; >+ case DebuggerAgent.PausedReason.PauseOnNextStatement: >+ return WI.DebuggerManager.PauseReason.PauseOnNextStatement; >+ case DebuggerAgent.PausedReason.Timer: >+ return WI.DebuggerManager.PauseReason.Timer; >+ case DebuggerAgent.PausedReason.XHR: >+ return WI.DebuggerManager.PauseReason.XHR; >+ default: >+ return WI.DebuggerManager.PauseReason.Other; >+ } >+ } >+ > // Public > > get paused() >@@ -334,6 +383,27 @@ WI.DebuggerManager = class DebuggerManager extends WI.Object > return knownScripts; > } > >+ isScriptBlackboxed(sourceCode) >+ { >+ return this._blackboxURLsSetting.value.includes(sourceCode.contentIdentifier); >+ } >+ >+ setShouldBlackboxScript(sourceCode, shouldBlackbox) >+ { >+ console.assert(DebuggerManager.supportsBlackboxingScripts()); >+ console.assert(sourceCode instanceof WI.SourceCode); >+ console.assert(sourceCode.contentIdentifier); >+ console.assert(!isWebKitInjectedScript(sourceCode.contentIdentifier)); >+ >+ this._blackboxURLsSetting.value.toggleIncludes(sourceCode.contentIdentifier, shouldBlackbox); >+ this._blackboxURLsSetting.save(); >+ >+ this.dispatchEventToListeners(DebuggerManager.Event.BlackboxedURLsChanged); >+ >+ for (let target of WI.targets) >+ target.DebuggerAgent.setShouldBlackboxURL(sourceCode.contentIdentifier, !!shouldBlackbox); >+ } >+ > get asyncStackTraceDepth() > { > return this._asyncStackTraceDepthSetting.value; >@@ -613,7 +683,7 @@ WI.DebuggerManager = class DebuggerManager extends WI.Object > let targetData = this._targetDebuggerDataMap.get(target); > > let callFrames = []; >- let pauseReason = this._pauseReasonFromPayload(reason); >+ let pauseReason = DebuggerManager.pauseReasonFromPayload(reason); > let pauseData = data || null; > > for (var i = 0; i < callFramesPayload.length; ++i) { >@@ -846,39 +916,6 @@ WI.DebuggerManager = class DebuggerManager extends WI.Object > return new WI.ScopeChainNode(type, [object], payload.name, payload.location, payload.empty); > } > >- _pauseReasonFromPayload(payload) >- { >- // FIXME: Handle other backend pause reasons. >- switch (payload) { >- case DebuggerAgent.PausedReason.AnimationFrame: >- return WI.DebuggerManager.PauseReason.AnimationFrame; >- case DebuggerAgent.PausedReason.Assert: >- return WI.DebuggerManager.PauseReason.Assertion; >- case DebuggerAgent.PausedReason.Breakpoint: >- return WI.DebuggerManager.PauseReason.Breakpoint; >- case DebuggerAgent.PausedReason.CSPViolation: >- return WI.DebuggerManager.PauseReason.CSPViolation; >- case DebuggerAgent.PausedReason.DOM: >- return WI.DebuggerManager.PauseReason.DOM; >- case DebuggerAgent.PausedReason.DebuggerStatement: >- return WI.DebuggerManager.PauseReason.DebuggerStatement; >- case DebuggerAgent.PausedReason.EventListener: >- return WI.DebuggerManager.PauseReason.EventListener; >- case DebuggerAgent.PausedReason.Exception: >- return WI.DebuggerManager.PauseReason.Exception; >- case DebuggerAgent.PausedReason.Fetch: >- return WI.DebuggerManager.PauseReason.Fetch; >- case DebuggerAgent.PausedReason.PauseOnNextStatement: >- return WI.DebuggerManager.PauseReason.PauseOnNextStatement; >- case DebuggerAgent.PausedReason.Timer: >- return WI.DebuggerManager.PauseReason.Timer; >- case DebuggerAgent.PausedReason.XHR: >- return WI.DebuggerManager.PauseReason.XHR; >- default: >- return WI.DebuggerManager.PauseReason.Other; >- } >- } >- > _debuggerBreakpointActionType(type) > { > switch (type) { >@@ -1380,11 +1417,13 @@ WI.DebuggerManager.Event = { > BreakpointsEnabledDidChange: "debugger-manager-breakpoints-enabled-did-change", > ProbeSetAdded: "debugger-manager-probe-set-added", > ProbeSetRemoved: "debugger-manager-probe-set-removed", >+ BlackboxedURLsChanged: "blackboxed-urls-changed", > }; > > WI.DebuggerManager.PauseReason = { > AnimationFrame: "animation-frame", > Assertion: "assertion", >+ BlackboxedScript: "blackboxed-script", > Breakpoint: "breakpoint", > CSPViolation: "CSP-violation", > DebuggerStatement: "debugger-statement", >diff --git a/Source/WebInspectorUI/UserInterface/Main.html b/Source/WebInspectorUI/UserInterface/Main.html >index 6b4d613704ff5ba6123df03cac09cf917ac413ee..53be532b4189196ef2df230f4bedcf3c167d3d72 100644 >--- a/Source/WebInspectorUI/UserInterface/Main.html >+++ b/Source/WebInspectorUI/UserInterface/Main.html >@@ -197,6 +197,7 @@ > <link rel="stylesheet" href="Views/Slider.css"> > <link rel="stylesheet" href="Views/SoftContextMenu.css"> > <link rel="stylesheet" href="Views/SourceCodeTextEditor.css"> >+ <link rel="stylesheet" href="Views/SourceCodeTreeElement.css"> > <link rel="stylesheet" href="Views/SourcesNavigationSidebarPanel.css"> > <link rel="stylesheet" href="Views/SpreadsheetCSSStyleDeclarationEditor.css"> > <link rel="stylesheet" href="Views/SpreadsheetCSSStyleDeclarationSection.css"> >diff --git a/Source/WebInspectorUI/UserInterface/Models/Resource.js b/Source/WebInspectorUI/UserInterface/Models/Resource.js >index e931c127481310c21fc941e945c8dd3cb55f3d3f..304019a0cc27610bc71dfca722b9d7a2aa865321 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/Resource.js >+++ b/Source/WebInspectorUI/UserInterface/Models/Resource.js >@@ -352,6 +352,11 @@ WI.Resource = class Resource extends WI.SourceCode > return true; > } > >+ get isScript() >+ { >+ return this._type === Resource.Type.Script; >+ } >+ > get displayName() > { > return WI.displayNameForURL(this._url, this.urlComponents); >diff --git a/Source/WebInspectorUI/UserInterface/Models/Script.js b/Source/WebInspectorUI/UserInterface/Models/Script.js >index 82a2151e284d9474f1c2ec0c2a94e686b6bcf5f4..309ae138b05ceebeb203dbb7cc83d2e967b99b9e 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/Script.js >+++ b/Source/WebInspectorUI/UserInterface/Models/Script.js >@@ -120,6 +120,11 @@ WI.Script = class Script extends WI.SourceCode > return this._resource.mimeType; > } > >+ get isScript() >+ { >+ return true; >+ } >+ > get displayName() > { > if (this._url && !this._dynamicallyAddedScriptElement) >diff --git a/Source/WebInspectorUI/UserInterface/Models/SourceCode.js b/Source/WebInspectorUI/UserInterface/Models/SourceCode.js >index 834333641ac814936f8aedbbc4d9223fa9fafb87..0c339e86d6f173a346dc76e4807f8701ea9d2640 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/SourceCode.js >+++ b/Source/WebInspectorUI/UserInterface/Models/SourceCode.js >@@ -46,6 +46,12 @@ WI.SourceCode = class SourceCode extends WI.Object > return ""; > } > >+ get isScript() >+ { >+ // Implemented by subclasses if needed. >+ return false; >+ } >+ > get originalRevision() > { > return this._originalRevision; >diff --git a/Source/WebInspectorUI/UserInterface/Test/TestHarness.js b/Source/WebInspectorUI/UserInterface/Test/TestHarness.js >index 64534d621bb3f3a0f6c04c43a3afbf25008043fe..6929417868ed4b7ac38ccac3bfc45fcd8753bb32 100644 >--- a/Source/WebInspectorUI/UserInterface/Test/TestHarness.js >+++ b/Source/WebInspectorUI/UserInterface/Test/TestHarness.js >@@ -97,6 +97,11 @@ TestHarness = class TestHarness extends WI.Object > this.addResult(message); > } > >+ newline() >+ { >+ this.log(""); >+ } >+ > json(object, filter) > { > this.log(JSON.stringify(object, filter || null, 2)); >@@ -207,7 +212,15 @@ TestHarness = class TestHarness extends WI.Object > let expectAndDumpError = (e) => { > this.expectNotNull(e, "Should produce an exception."); > if (e) >- this.log(e.toString()); >+ if (e instanceof Error || !(e instanceof Object)) >+ this.log(e.toString()); >+ else { >+ try { >+ this.json(e); >+ } catch { >+ this.log(e.constructor.name); >+ } >+ } > } > > let error = null; >diff --git a/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js b/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js >index 9bb6a68485e8fbcddd5e560742e5d761075d0ede..1cdc5cc4abc7555d898009a67f0960aa098404ac 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js >+++ b/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js >@@ -1113,15 +1113,13 @@ WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba > this._pauseReasonTreeOutline = null; > > this._updatePauseReasonGotoArrow(); >- return this._updatePauseReasonSection(); >- } >- >- _updatePauseReasonSection() >- { > let target = WI.debuggerManager.activeCallFrame.target; > let targetData = WI.debuggerManager.dataForTarget(target); >- let {pauseReason, pauseData} = targetData; >+ return this._updatePauseReasonSection(target, targetData.pauseReason, targetData.pauseData); >+ } > >+ _updatePauseReasonSection(target, pauseReason, pauseData) >+ { > switch (pauseReason) { > case WI.DebuggerManager.PauseReason.AnimationFrame: > console.assert(pauseData, "Expected data with an animation frame, but found none."); >@@ -1159,6 +1157,20 @@ WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba > this._pauseReasonGroup.rows = [this._pauseReasonTextRow]; > return true; > >+ case WI.DebuggerManager.PauseReason.BlackboxedScript: { >+ console.assert(pauseData); >+ if (pauseData) >+ this._updatePauseReasonSection(target, WI.DebuggerManager.pauseReasonFromPayload(pauseData.originalReason), pauseData.originalData); >+ >+ // Don't use `_pauseReasonTextRow` as it may have already been set. >+ let blackboxReasonTextRow = new WI.DetailsSectionTextRow(WI.UIString("Deferred pause from blackboxed script")); >+ blackboxReasonTextRow.__blackboxReason = true; >+ >+ let existingRows = this._pauseReasonGroup.rows.filter((row) => !row.__blackboxReason); >+ this._pauseReasonGroup.rows = [blackboxReasonTextRow, ...existingRows]; >+ return true; >+ } >+ > case WI.DebuggerManager.PauseReason.Breakpoint: > console.assert(pauseData, "Expected breakpoint identifier, but found none."); > if (pauseData && pauseData.breakpointId) { >diff --git a/Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js >index 278c005ebf98fd05c78c6ed3e8c4dcdba0b37b85..85a90de30075a4ea6a3761212d2390f8e9c9239f 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js >+++ b/Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js >@@ -118,8 +118,8 @@ WI.ResourceTreeElement = class ResourceTreeElement extends WI.SourceCodeTreeElem > if (this._resource) { > this._resource.removeEventListener(WI.Resource.Event.URLDidChange, this._urlDidChange, this); > this._resource.removeEventListener(WI.Resource.Event.TypeDidChange, this._typeDidChange, this); >- this._resource.removeEventListener(WI.Resource.Event.LoadingDidFinish, this._updateStatus, this); >- this._resource.removeEventListener(WI.Resource.Event.LoadingDidFail, this._updateStatus, this); >+ this._resource.removeEventListener(WI.Resource.Event.LoadingDidFinish, this.updateStatus, this); >+ this._resource.removeEventListener(WI.Resource.Event.LoadingDidFail, this.updateStatus, this); > } > > this._updateSourceCode(resource); >@@ -128,11 +128,11 @@ WI.ResourceTreeElement = class ResourceTreeElement extends WI.SourceCodeTreeElem > > resource.addEventListener(WI.Resource.Event.URLDidChange, this._urlDidChange, this); > resource.addEventListener(WI.Resource.Event.TypeDidChange, this._typeDidChange, this); >- resource.addEventListener(WI.Resource.Event.LoadingDidFinish, this._updateStatus, this); >- resource.addEventListener(WI.Resource.Event.LoadingDidFail, this._updateStatus, this); >+ resource.addEventListener(WI.Resource.Event.LoadingDidFinish, this.updateStatus, this); >+ resource.addEventListener(WI.Resource.Event.LoadingDidFail, this.updateStatus, this); > > this._updateTitles(); >- this._updateStatus(); >+ this.updateStatus(); > this._updateToolTip(); > } > >@@ -175,17 +175,13 @@ WI.ResourceTreeElement = class ResourceTreeElement extends WI.SourceCodeTreeElem > this.callFirstAncestorFunction("descendantResourceTreeElementMainTitleDidChange", [this, oldMainTitle]); > } > >- populateContextMenu(contextMenu, event) >+ updateStatus() > { >- WI.appendContextMenuItemsForSourceCode(contextMenu, this._resource); >+ super.updateStatus(); > >- super.populateContextMenu(contextMenu, event); >- } >+ if (!this._resource) >+ return; > >- // Private >- >- _updateStatus() >- { > if (this._resource.hadLoadingError()) > this.addClassName(WI.ResourceTreeElement.FailedStyleClassName); > else >@@ -194,15 +190,33 @@ WI.ResourceTreeElement = class ResourceTreeElement extends WI.SourceCodeTreeElem > if (this._resource.isLoading()) { > if (!this.status || !this.status[WI.ResourceTreeElement.SpinnerSymbol]) { > let spinner = new WI.IndeterminateProgressSpinner; >- this.status = spinner.element; >- this.status[WI.ResourceTreeElement.SpinnerSymbol] = true; >+ if (this.status) >+ this.statusElement.insertAdjacentElement("afterbegin", spinner.element); >+ else >+ this.status = spinner.element; >+ this.status[WI.ResourceTreeElement.SpinnerSymbol] = spinner.element; > } > } else { >- if (this.status && this.status[WI.ResourceTreeElement.SpinnerSymbol]) >- this.status = ""; >+ if (this.status && this.status[WI.ResourceTreeElement.SpinnerSymbol]) { >+ if (this.status === this.status[WI.ResourceTreeElement.SpinnerSymbol]) >+ this.status = null; >+ else { >+ this.status[WI.ResourceTreeElement.SpinnerSymbol].remove(); >+ this.status[WI.ResourceTreeElement.SpinnerSymbol] = null; >+ } >+ } > } > } > >+ populateContextMenu(contextMenu, event) >+ { >+ WI.appendContextMenuItemsForSourceCode(contextMenu, this._resource); >+ >+ super.populateContextMenu(contextMenu, event); >+ } >+ >+ // Private >+ > _updateToolTip() > { > this.tooltip = this._resource.displayURL; >diff --git a/Source/WebInspectorUI/UserInterface/Views/SourceCodeTreeElement.css b/Source/WebInspectorUI/UserInterface/Views/SourceCodeTreeElement.css >new file mode 100644 >index 0000000000000000000000000000000000000000..dc35f412406ba1498797319e7d120a26e6ae8b06 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/SourceCodeTreeElement.css >@@ -0,0 +1,49 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+.tree-outline .item .status > .toggle-script-blackboxed { >+ width: 18px; >+ margin-top: 2px; >+ content: url(../Images/Eye.svg); >+} >+ >+.tree-outline:not(.navigation-sidebar-panel-content-tree-outline) .item .status > .toggle-script-blackboxed, >+.tree-outline .item:not(:hover, .selected) .status > .toggle-script-blackboxed:not(.blackboxed) { >+ display: none; >+} >+ >+.tree-outline:focus .item.selected .status > .toggle-script-blackboxed { >+ filter: invert(); >+} >+ >+.tree-outline .item .status > .toggle-script-blackboxed.blackboxed { >+ opacity: 0.5; >+} >+ >+@media (prefers-color-scheme: dark) { >+ .tree-outline .item .status > .toggle-script-blackboxed { >+ filter: invert(); >+ } >+} >diff --git a/Source/WebInspectorUI/UserInterface/Views/SourceCodeTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/SourceCodeTreeElement.js >index 87de40d599981984b2de9be9e1e66e9fe6bedb68..970f808bd72506af12f7aeb2b6e38708b620a243 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/SourceCodeTreeElement.js >+++ b/Source/WebInspectorUI/UserInterface/Views/SourceCodeTreeElement.js >@@ -128,6 +128,13 @@ WI.SourceCodeTreeElement = class SourceCodeTreeElement extends WI.FolderizedTree > findAndCombineFolderChains(this.children[i], null); > } > >+ canSelectOnMouseDown(event) >+ { >+ if (this._toggleBlackboxedImageElement && this._toggleBlackboxedImageElement.contains(event.target)) >+ return false; >+ return super.canSelectOnMouseDown(event); >+ } >+ > // Protected > > descendantResourceTreeElementTypeDidChange(childTreeElement, oldType) >@@ -150,6 +157,19 @@ WI.SourceCodeTreeElement = class SourceCodeTreeElement extends WI.FolderizedTree > childTreeElement.revealAndSelect(true, false, true); > } > >+ updateStatus() >+ { >+ if (WI.DebuggerManager.supportsBlackboxingScripts() && this._sourceCode.isScript && this._sourceCode.contentIdentifier && !isWebKitInjectedScript(this._sourceCode.contentIdentifier)) { >+ this._toggleBlackboxedImageElement = document.createElement("img"); >+ this._toggleBlackboxedImageElement.classList.add("toggle-script-blackboxed"); >+ this._toggleBlackboxedImageElement.addEventListener("click", this._handleToggleBlackboxedImageElementClicked.bind(this)); >+ this.status = this._toggleBlackboxedImageElement; >+ >+ WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BlackboxedURLsChanged, this._updateToggleBlackboxImageElementState, this); >+ this._updateToggleBlackboxImageElementState(); >+ } >+ } >+ > // Protected (ResourceTreeElement calls this when its Resource changes dynamically for Frames) > > _updateSourceCode(sourceCode) >@@ -166,5 +186,24 @@ WI.SourceCodeTreeElement = class SourceCodeTreeElement extends WI.FolderizedTree > this._sourceCode.addEventListener(WI.SourceCode.Event.SourceMapAdded, this.updateSourceMapResources, this); > > this.updateSourceMapResources(); >+ >+ this.updateStatus(); >+ } >+ >+ // Private >+ >+ _updateToggleBlackboxImageElementState() >+ { >+ let isBlackboxed = WI.debuggerManager.isScriptBlackboxed(this._sourceCode); >+ this._toggleBlackboxedImageElement.classList.toggle("blackboxed", isBlackboxed); >+ this._toggleBlackboxedImageElement.title = isBlackboxed ? WI.UIString("Include script when debugging") : WI.UIString("Ignore script when debugging"); >+ } >+ >+ _handleToggleBlackboxedImageElementClicked(event) >+ { >+ let isBlackboxed = WI.debuggerManager.isScriptBlackboxed(this._sourceCode); >+ WI.debuggerManager.setShouldBlackboxScript(this._sourceCode, !isBlackboxed); >+ >+ this._updateToggleBlackboxImageElementState(); > } > }; >diff --git a/Source/WebInspectorUI/UserInterface/Views/SourcesNavigationSidebarPanel.js b/Source/WebInspectorUI/UserInterface/Views/SourcesNavigationSidebarPanel.js >index 8e9dd14bf1cc53fd8e2a2204a140e4dca7a0c766..a740940647f1cf0271e5f1fb008216c7c427ebd1 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/SourcesNavigationSidebarPanel.js >+++ b/Source/WebInspectorUI/UserInterface/Views/SourcesNavigationSidebarPanel.js >@@ -1102,7 +1102,10 @@ WI.SourcesNavigationSidebarPanel = class SourcesNavigationSidebarPanel extends W > this._pauseReasonTreeOutline = null; > > this._updatePauseReasonGotoArrow(); >- return this._updatePauseReasonSection(); >+ >+ let target = WI.debuggerManager.activeCallFrame.target; >+ let targetData = WI.debuggerManager.dataForTarget(target); >+ return this._updatePauseReasonSection(target, targetData.pauseReason, targetData.pauseData); > } > > _updatePauseReasonGotoArrow() >@@ -1124,12 +1127,8 @@ WI.SourcesNavigationSidebarPanel = class SourcesNavigationSidebarPanel extends W > this._pauseReasonLinkContainerElement.appendChild(linkElement); > } > >- _updatePauseReasonSection() >+ _updatePauseReasonSection(target, pauseReason, pauseData) > { >- let target = WI.debuggerManager.activeCallFrame.target; >- let targetData = WI.debuggerManager.dataForTarget(target); >- let {pauseReason, pauseData} = targetData; >- > switch (pauseReason) { > case WI.DebuggerManager.PauseReason.AnimationFrame: { > console.assert(pauseData, "Expected data with an animation frame, but found none."); >@@ -1166,6 +1165,20 @@ WI.SourcesNavigationSidebarPanel = class SourcesNavigationSidebarPanel extends W > this._pauseReasonGroup.rows = [this._pauseReasonTextRow]; > return true; > >+ case WI.DebuggerManager.PauseReason.BlackboxedScript: { >+ console.assert(pauseData); >+ if (pauseData) >+ this._updatePauseReasonSection(target, WI.DebuggerManager.pauseReasonFromPayload(pauseData.originalReason), pauseData.originalData); >+ >+ // Don't use `_pauseReasonTextRow` as it may have already been set. >+ let blackboxReasonTextRow = new WI.DetailsSectionTextRow(WI.UIString("Deferred pause from blackboxed script")); >+ blackboxReasonTextRow.__blackboxReason = true; >+ >+ let existingRows = this._pauseReasonGroup.rows.filter((row) => !row.__blackboxReason); >+ this._pauseReasonGroup.rows = [blackboxReasonTextRow, ...existingRows]; >+ return true; >+ } >+ > case WI.DebuggerManager.PauseReason.Breakpoint: { > console.assert(pauseData, "Expected breakpoint identifier, but found none."); > if (!pauseData || !pauseData.breakpointId) >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index a50c79d47504e98fc5dfe8fbd6767d6239c77cae..7d8e06bcd438011fd7094dbfccf8952fbbe3af6c 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,14 @@ >+2019-06-14 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: implement blackboxing of script resources >+ https://bugs.webkit.org/show_bug.cgi?id=17240 >+ <rdar://problem/5732847> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * inspector/debugger/setShouldBlackboxURL.html: Added. >+ * inspector/debugger/setShouldBlackboxURL-expected.txt: Added. >+ > 2019-06-14 Daniel Bates <dabates@apple.com> > > [iOS] Split up fast/events/ios/key-events-meta-alt-combinations.html and add more tests >diff --git a/LayoutTests/inspector/debugger/setShouldBlackboxURL-expected.txt b/LayoutTests/inspector/debugger/setShouldBlackboxURL-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..8aedadeed6aa475d74722cb72fd39416f911949b >--- /dev/null >+++ b/LayoutTests/inspector/debugger/setShouldBlackboxURL-expected.txt >@@ -0,0 +1,105 @@ >+Tests Debugger.setShouldBlackboxURL >+ >+ >+== Running test suite: Debugger.setShouldBlackboxURL >+-- Running test case: Debugger.setShouldBlackboxURL.stepOver >+Evaluating 'createScripts("stepOver")'... >+Blackboxing 'stepOverMiddle.js'... >+Setting breakpoint in 'stepOverInner.js'... >+Evaluating 'stepOverOuter(10)'... >+ >+Paused in 'stepOverInner:3:1'. >+Reason: 'Breakpoint' >+{ >+ "breakpointId": "stepOverInner.js:3:0" >+} >+Stepping over... >+ >+Paused in 'stepOverOuter:3:1'. >+Reason: 'BlackboxedScript' >+{ >+ "originalReason": "other", >+ "originalData": { >+ "breakpointId": "stepOverInner.js:3:0" >+ } >+} >+Stepping over... >+ >+Resuming... >+PASS: Resumed. >+PASS: Should not pause in 'stepOverMiddle'. >+ >+-- Running test case: Debugger.setShouldBlackboxURL.PauseInCaller >+Evaluating 'createScripts("pauseInCaller")'... >+Blackboxing 'pauseInCallerInner.js'... >+Setting breakpoint in 'pauseInCallerInner.js'... >+Evaluating 'pauseInCallerOuter(10)'... >+ >+Paused in 'pauseInCallerMiddle:3:1'. >+Reason: 'BlackboxedScript' >+{ >+ "originalReason": "Breakpoint", >+ "originalData": { >+ "breakpointId": "pauseInCallerInner.js:2:0" >+ } >+} >+Stepping over... >+ >+Paused in 'pauseInCallerOuter:3:1'. >+Reason: 'other' >+Stepping over... >+ >+Resuming... >+PASS: Resumed. >+PASS: Should not pause in 'pauseInCallerInner'. >+ >+-- Running test case: Debugger.setShouldBlackboxURL.PauseInCallee >+Evaluating 'createScripts("pauseInCallee")'... >+Blackboxing 'pauseInCalleeOuter.js'... >+Setting breakpoint in 'pauseInCalleeOuter.js'... >+Evaluating 'pauseInCalleeOuter(10)'... >+ >+Paused in 'pauseInCalleeMiddle:2:4'. >+Reason: 'BlackboxedScript' >+{ >+ "originalReason": "Breakpoint", >+ "originalData": { >+ "breakpointId": "pauseInCalleeOuter.js:2:0" >+ } >+} >+Stepping over... >+ >+Paused in 'pauseInCalleeMiddle:3:1'. >+Reason: 'other' >+Stepping over... >+ >+Resuming... >+PASS: Resumed. >+PASS: Should not pause in 'pauseInCalleeOuter'. >+ >+-- Running test case: Debugger.setShouldBlackboxURL.Invalid.emptyURL >+PASS: Should produce an exception. >+{ >+ "code": -32000, >+ "message": "URL must not be empty", >+ "data": [ >+ { >+ "code": -32000, >+ "message": "URL must not be empty" >+ } >+ ] >+} >+ >+-- Running test case: Debugger.setShouldBlackboxURL.Invalid.injectedScript >+PASS: Should produce an exception. >+{ >+ "code": -32000, >+ "message": "Blackboxing of internal scripts is controlled by 'setPauseForInternalScripts'", >+ "data": [ >+ { >+ "code": -32000, >+ "message": "Blackboxing of internal scripts is controlled by 'setPauseForInternalScripts'" >+ } >+ ] >+} >+ >diff --git a/LayoutTests/inspector/debugger/setShouldBlackboxURL.html b/LayoutTests/inspector/debugger/setShouldBlackboxURL.html >new file mode 100644 >index 0000000000000000000000000000000000000000..fd70bc12c770b25cce1b12fd09128404cc36b633 >--- /dev/null >+++ b/LayoutTests/inspector/debugger/setShouldBlackboxURL.html >@@ -0,0 +1,233 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../http/tests/inspector/resources/protocol-test.js"></script> >+<script> >+ >+function createScripts(id) { >+ eval( >+` >+window.${id}Inner = function ${id}Inner(x) { >+ return x + 42; >+}; >+//# sourceURL=${id}Inner.js >+` >+ ); >+ >+ eval( >+` >+window.${id}Middle = function ${id}Middle(x) { >+ return ${id}Inner(x); >+}; >+//# sourceURL=${id}Middle.js >+` >+ ); >+ >+ eval( >+` >+window.${id}Outer = function ${id}Outer(x) { >+ return ${id}Middle(x); >+}; >+//# sourceURL=${id}Outer.js >+` >+ ); >+} >+ >+function test() >+{ >+ let suite = ProtocolTest.createAsyncSuite("Debugger.setShouldBlackboxURL"); >+ >+ let sourceURLRegExpQueries = new Map; >+ let pausedFunctionNames = []; >+ let resumeCallback = null; >+ >+ InspectorProtocol.sendCommand("Debugger.enable", {}); >+ InspectorProtocol.sendCommand("Debugger.setBreakpointsActive", {active: true}); >+ >+ InspectorProtocol.eventHandler["Debugger.scriptParsed"] = function(message) { >+ let sourceURL = message.params.sourceURL; >+ for (let [regExp, callback] of sourceURLRegExpQueries) { >+ if (regExp.test(sourceURL)) { >+ sourceURLRegExpQueries.delete(regExp); >+ callback(sourceURL); >+ } >+ }; >+ }; >+ >+ InspectorProtocol.eventHandler["Debugger.paused"] = function(message) { >+ let topCallFrame = message.params.callFrames[0]; >+ let functionName = topCallFrame.functionName; >+ if (functionName === "global code") { >+ ProtocolTest.log("Resuming..."); >+ InspectorProtocol.sendCommand(`Debugger.resume`, {}, function(response) { >+ InspectorProtocol.checkForError(response); >+ }); >+ return; >+ } >+ >+ ProtocolTest.log(`Paused in '${functionName}:${topCallFrame.location.lineNumber}:${topCallFrame.location.columnNumber}'.`); >+ ProtocolTest.log(`Reason: '${message.params.reason}'`); >+ if (message.params.data) >+ ProtocolTest.json(message.params.data); >+ pausedFunctionNames.push(functionName); >+ >+ ProtocolTest.log("Stepping over..."); >+ ProtocolTest.newline(); >+ InspectorProtocol.sendCommand(`Debugger.stepOver`, {}, function(response) { >+ InspectorProtocol.checkForError(response); >+ }); >+ }; >+ >+ InspectorProtocol.eventHandler["Debugger.resumed"] = function(message) { >+ ProtocolTest.pass("Resumed."); >+ resumeCallback(); >+ }; >+ >+ async function setBlackbox(url) { >+ ProtocolTest.log(`Blackboxing '${url}'...`); >+ await InspectorProtocol.awaitCommand({ >+ method: "Debugger.setShouldBlackboxURL", >+ params: {url, shouldBlackbox: true}, >+ }); >+ } >+ >+ async function setBreakpoint(url, lineNumber) { >+ ProtocolTest.log(`Setting breakpoint in '${url}'...`); >+ await InspectorProtocol.awaitCommand({ >+ method: "Debugger.setBreakpointByUrl", >+ params: {url, lineNumber}, >+ }); >+ } >+ >+ async function listenForSourceParsed(sourceURLRegExp) { >+ return new Promise((resolve, reject) => { >+ sourceURLRegExpQueries.set(sourceURLRegExp, resolve); >+ }); >+ } >+ >+ async function evaluate(expression) { >+ ProtocolTest.log(`Evaluating '${expression}'...`); >+ return InspectorProtocol.awaitCommand({ >+ method: "Runtime.evaluate", >+ params: {expression}, >+ }); >+ } >+ >+ suite.addTestCase({ >+ name: "Debugger.setShouldBlackboxURL.stepOver", >+ description: "Check that stepping through a blackboxed script doesn't pause.", >+ async test() { >+ let resumePromise = new Promise((resolve, reject) => { >+ resumeCallback = function() { >+ ProtocolTest.expectThat(!pausedFunctionNames.includes("stepOverMiddle"), "Should not pause in 'stepOverMiddle'."); >+ resolve(); >+ }; >+ }); >+ >+ let [stepOverInnerSourceURL, stepOverMiddleSourceURL] = await Promise.all([ >+ listenForSourceParsed(/stepOverInner\.js$/), >+ listenForSourceParsed(/stepOverMiddle\.js$/), >+ listenForSourceParsed(/stepOverOuter\.js$/), >+ evaluate(`createScripts("stepOver")`), >+ ]); >+ >+ await setBlackbox(stepOverMiddleSourceURL); >+ await setBreakpoint(stepOverInnerSourceURL, 3); // last line of function, so it only pauses once >+ evaluate(`stepOverOuter(10)`); >+ >+ ProtocolTest.newline(); >+ >+ await resumePromise; >+ }, >+ }); >+ >+ suite.addTestCase({ >+ name: "Debugger.setShouldBlackboxURL.PauseInCaller", >+ description: "Check that the debugger will pause in the caller if a breakpoint is set in a blackboxed script.", >+ async test() { >+ let resumePromise = new Promise((resolve, reject) => { >+ resumeCallback = function() { >+ ProtocolTest.expectThat(!pausedFunctionNames.includes("pauseInCallerInner"), "Should not pause in 'pauseInCallerInner'."); >+ resolve(); >+ }; >+ }); >+ >+ let [pauseInCallerInnerSourceURL] = await Promise.all([ >+ listenForSourceParsed(/pauseInCallerInner\.js$/), >+ listenForSourceParsed(/pauseInCallerMiddle\.js$/), >+ listenForSourceParsed(/pauseInCallerOuter\.js$/), >+ evaluate(`createScripts("pauseInCaller")`), >+ ]); >+ >+ await setBlackbox(pauseInCallerInnerSourceURL); >+ await setBreakpoint(pauseInCallerInnerSourceURL, 2); >+ evaluate(`pauseInCallerOuter(10)`); >+ >+ ProtocolTest.newline(); >+ >+ await resumePromise; >+ }, >+ }); >+ >+ suite.addTestCase({ >+ name: "Debugger.setShouldBlackboxURL.PauseInCallee", >+ description: "Check that the debugger will pause in the callee if a breakpoint is set in a blackboxed script.", >+ async test() { >+ let resumePromise = new Promise((resolve, reject) => { >+ resumeCallback = function() { >+ ProtocolTest.expectThat(!pausedFunctionNames.includes("pauseInCalleeOuter"), "Should not pause in 'pauseInCalleeOuter'."); >+ resolve(); >+ }; >+ }); >+ >+ let [pauseInCalleeInnerSourceURL, pauseInCalleeMiddleSourceURL, pauseInCalleeOuterSourceURL] = await Promise.all([ >+ listenForSourceParsed(/pauseInCalleeInner\.js$/), >+ listenForSourceParsed(/pauseInCalleeMiddle\.js$/), >+ listenForSourceParsed(/pauseInCalleeOuter\.js$/), >+ evaluate(`createScripts("pauseInCallee")`), >+ ]); >+ >+ await setBlackbox(pauseInCalleeOuterSourceURL); >+ await setBreakpoint(pauseInCalleeOuterSourceURL, 2); >+ evaluate(`pauseInCalleeOuter(10)`); >+ >+ ProtocolTest.newline(); >+ >+ await resumePromise; >+ }, >+ }); >+ >+ suite.addTestCase({ >+ name: "Debugger.setShouldBlackboxURL.Invalid.emptyURL", >+ description: "Check that an error is thrown if the given url is empty.", >+ async test() { >+ await ProtocolTest.expectException(async () => { >+ await InspectorProtocol.awaitCommand({ >+ method: "Debugger.setShouldBlackboxURL", >+ params: {url: "", shouldBlackbox: true}, >+ }); >+ }); >+ }, >+ }); >+ >+ suite.addTestCase({ >+ name: "Debugger.setShouldBlackboxURL.Invalid.injectedScript", >+ description: "Check that an error is thrown if the given url matches an injected script url.", >+ async test() { >+ await ProtocolTest.expectException(async () => { >+ await InspectorProtocol.awaitCommand({ >+ method: "Debugger.setShouldBlackboxURL", >+ params: {url: "__InjectedScript__test.js", shouldBlackbox: true}, >+ }); >+ }); >+ }, >+ }); >+ >+ suite.runTestCasesAndFinish(); >+} >+</script> >+</head> >+<body onload="runTest()"> >+ <p>Tests Debugger.setShouldBlackboxURL</p> >+</body> >+</html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 17240
:
372117
|
372119
|
372120
|
372123
|
372154
|
372162
|
372163
|
372166
|
372168
|
372172
|
372176
|
372189
|
375517
|
375853
|
375869
|
375870
|
377655
|
377656
|
377935