Skip to content
Permalink
Browse files
Web Inspector: Pause Reason Improvements (Breakpoint, Debugger Statem…
…ent, Pause on Next Statement)

https://bugs.webkit.org/show_bug.cgi?id=138991

Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

* debugger/Debugger.cpp:
(JSC::Debugger::Debugger):
(JSC::Debugger::pauseIfNeeded):
(JSC::Debugger::didReachBreakpoint):
When actually pausing, if we hit a breakpoint ensure the reason
is PausedForBreakpoint, otherwise use the current reason.

* debugger/Debugger.h:
Make pause reason and pausing breakpoint ID public.

* inspector/agents/InspectorDebuggerAgent.h:
* inspector/agents/InspectorDebuggerAgent.cpp:
(Inspector::buildAssertPauseReason):
(Inspector::buildCSPViolationPauseReason):
(Inspector::InspectorDebuggerAgent::buildBreakpointPauseReason):
(Inspector::InspectorDebuggerAgent::buildExceptionPauseReason):
(Inspector::InspectorDebuggerAgent::handleConsoleAssert):
(Inspector::buildObjectForBreakpointCookie):
(Inspector::InspectorDebuggerAgent::setBreakpointByUrl):
(Inspector::InspectorDebuggerAgent::removeBreakpoint):
(Inspector::InspectorDebuggerAgent::resolveBreakpoint):
(Inspector::InspectorDebuggerAgent::pause):
(Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP):
(Inspector::InspectorDebuggerAgent::currentCallFrames):
(Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState):
Clean up creation of pause reason objects and other cleanup
of PassRefPtr use and InjectedScript use.

(Inspector::InspectorDebuggerAgent::didPause):
Clean up so that we first check for an Exception, and then fall
back to including a Pause Reason derived from the Debugger.

* inspector/protocol/Debugger.json:
Add new DebuggerStatement, Breakpoint, and PauseOnNextStatement reasons.

Source/WebInspectorUI:

* Localizations/en.lproj/localizedStrings.js:
New UI strings for Pause Reasons.

* UserInterface/Controllers/DebuggerManager.js:
(WebInspector.DebuggerManager.prototype.breakpointForIdentifier):
Provide a way to get the breakpoint with an identifier.

* UserInterface/Images/PausedBreakpoint.svg: Added.
* UserInterface/Images/gtk/PausedBreakpoint.svg: Added.
Copy PseudoElement.svg icon and give it a new name.

* UserInterface/Views/BreakpointTreeElement.css:
(.breakpoint-paused-icon .icon):
New icon for a breakpoint causing a pause.

* UserInterface/Views/BreakpointTreeElement.js:
(WebInspector.BreakpointTreeElement.prototype.removeStatusImage):
(WebInspector.BreakpointTreeElement.prototype._updateStatus):
Give API to remove the breakpoint status icon from a BreakpointTreeElement.

* UserInterface/Views/DebuggerSidebarPanel.js:
(WebInspector.DebuggerSidebarPanel):
(WebInspector.DebuggerSidebarPanel.prototype.get hasSelectedElement):
(WebInspector.DebuggerSidebarPanel.prototype.deselectBreakpointContentTreeElements):
(WebInspector.DebuggerSidebarPanel.prototype.deselectPauseReasonContentTreeElements):
(WebInspector.DebuggerSidebarPanel.prototype._treeElementSelected):
Give DebuggerSidebarPanel an optional pause reason tree outline. When available
include it in the pattern of ensuring a single exclusive selection.

(WebInspector.DebuggerSidebarPanel.prototype._breakpointRemoved):
When a breakpoint is removed, check if we should update the pause reason tree outline.

(WebInspector.DebuggerSidebarPanel.prototype._updatePauseReason):
(WebInspector.DebuggerSidebarPanel.prototype._updatePauseReasonSection):
Update Pause Reason section contents depending on the reason.

(WebInspector.DebuggerSidebarPanel.prototype._updatePauseReasonGotoArrow):
Always try to include a goto arrow to jump to the original pause location
if it is available at the time of pausing.

LayoutTests:

Test that the frontend receives expected pause reasons for different kinds of pauses.

* inspector/debugger/pause-reason-expected.txt: Added.
* inspector/debugger/pause-reason.html: Added.
* inspector/debugger/resources/pause-reasons.js: Added.
(triggerBreakpoint):
(triggerException):
(triggerDebuggerStatement):
(triggerAssert):

Canonical link: https://commits.webkit.org/158231@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@178137 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
JosephPecoraro committed Jan 8, 2015
1 parent 76c6f59 commit 6aaa86b716bbfbf45800926c2448c873c3cb8efa
@@ -1,3 +1,20 @@
2015-01-08 Joseph Pecoraro <pecoraro@apple.com>

Web Inspector: Pause Reason Improvements (Breakpoint, Debugger Statement, Pause on Next Statement)
https://bugs.webkit.org/show_bug.cgi?id=138991

Reviewed by Timothy Hatcher.

Test that the frontend receives expected pause reasons for different kinds of pauses.

* inspector/debugger/pause-reason-expected.txt: Added.
* inspector/debugger/pause-reason.html: Added.
* inspector/debugger/resources/pause-reasons.js: Added.
(triggerBreakpoint):
(triggerException):
(triggerDebuggerStatement):
(triggerAssert):

2015-01-08 Darin Adler <darin@apple.com>

ASSERTION FAILED: character != kEndOfFileMarker in WebCore::HTMLTokenizer::bufferCharacter
@@ -0,0 +1,30 @@
CONSOLE MESSAGE: line 8: TypeError: undefined is not an object (evaluating '[].x.x')
CONSOLE MESSAGE: line 18: Assertion message
Test that pausing in different ways triggers different pause reasons.

PAUSE #1
REASON: exception
DATA: {"description":"TypeError: undefined is not an object (evaluating '[].x.x')"}
RESUMED

PAUSE #2
REASON: debugger-statement
NO DATA
RESUMED

PAUSE #3
REASON: assertion
DATA: {"message":"Assertion message"}
RESUMED

PAUSE #4
REASON: breakpoint
DATA: {"breakpointId":"pause-reasons.js:3:0"}
RESUMED

PAUSE #5
REASON: pause-on-next-statement
NO DATA
RESUMED


@@ -0,0 +1,88 @@
<!doctype html>
<html>
<head>
<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
<script type="text/javascript" src="./resources/pause-reasons.js"></script>
<script>
// We expect uncaught exceptions, so avoid logs for them.
window.onerror = function(){};

function test()
{
var pauses = 0;
var index = 0;
var testCases = [
{ expression: "setTimeout(triggerException, 0)" },
{ expression: "setTimeout(triggerDebuggerStatement, 0)" },
{ expression: "setTimeout(triggerAssert, 0)" },
{ expression: "setTimeout(triggerBreakpoint, 0)" },
{ expression: "setTimeout(function() { 1+1 }, 0)", setup: function() { WebInspector.debuggerManager.pause(); } },
];

function nextTestCase()
{
var test = testCases[index++];
if (!test) {
InspectorTest.completeTest();
return;
}

if (test.setup)
test.setup();

InspectorTest.evaluateInPage(test.expression);
}

function sanitizePauseData(data)
{
// Sanitize RemoteObjects to just output the description.
if (data.description)
return {description: data.description};

// Sanitize BreakpointIdentifier path.
if (data.breakpointId)
return {breakpointId: data.breakpointId.substring(data.breakpointId.indexOf("pause-reasons.js"))};

return data;
}

WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;

WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
var scriptObject = event.data.script;
if (!/pause-reasons\.js$/.test(scriptObject.url))
return;

var sourceCodeLocation = scriptObject.createSourceCodeLocation(3, 0);
var breakpoint = new WebInspector.Breakpoint(sourceCodeLocation);
WebInspector.debuggerManager.addBreakpoint(breakpoint);

nextTestCase();
});

WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Paused, function(event) {
InspectorTest.log("PAUSE #" + (++pauses));
InspectorTest.log(" REASON: " + WebInspector.debuggerManager.pauseReason);
if (WebInspector.debuggerManager.pauseData)
InspectorTest.log(" DATA: " + JSON.stringify(sanitizePauseData(WebInspector.debuggerManager.pauseData)));
else
InspectorTest.log(" NO DATA");

WebInspector.debuggerManager.resume();
});

WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Resumed, function(event) {
InspectorTest.log("RESUMED");
InspectorTest.log("");

nextTestCase();
});

InspectorTest.reloadPage();
}
</script>
</head>
<body onload="runTest()">
<p>Test that pausing in different ways triggers different pause reasons.</p>
</body>
</html>
@@ -0,0 +1,19 @@
function triggerBreakpoint()
{
1+1; // BREAKPOINT
}

function triggerException()
{
[].x.x;
}

function triggerDebuggerStatement()
{
debugger;
}

function triggerAssert()
{
console.assert(false, "Assertion message");
}
@@ -1,3 +1,45 @@
2015-01-08 Joseph Pecoraro <pecoraro@apple.com>

Web Inspector: Pause Reason Improvements (Breakpoint, Debugger Statement, Pause on Next Statement)
https://bugs.webkit.org/show_bug.cgi?id=138991

Reviewed by Timothy Hatcher.

* debugger/Debugger.cpp:
(JSC::Debugger::Debugger):
(JSC::Debugger::pauseIfNeeded):
(JSC::Debugger::didReachBreakpoint):
When actually pausing, if we hit a breakpoint ensure the reason
is PausedForBreakpoint, otherwise use the current reason.

* debugger/Debugger.h:
Make pause reason and pausing breakpoint ID public.

* inspector/agents/InspectorDebuggerAgent.h:
* inspector/agents/InspectorDebuggerAgent.cpp:
(Inspector::buildAssertPauseReason):
(Inspector::buildCSPViolationPauseReason):
(Inspector::InspectorDebuggerAgent::buildBreakpointPauseReason):
(Inspector::InspectorDebuggerAgent::buildExceptionPauseReason):
(Inspector::InspectorDebuggerAgent::handleConsoleAssert):
(Inspector::buildObjectForBreakpointCookie):
(Inspector::InspectorDebuggerAgent::setBreakpointByUrl):
(Inspector::InspectorDebuggerAgent::removeBreakpoint):
(Inspector::InspectorDebuggerAgent::resolveBreakpoint):
(Inspector::InspectorDebuggerAgent::pause):
(Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP):
(Inspector::InspectorDebuggerAgent::currentCallFrames):
(Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState):
Clean up creation of pause reason objects and other cleanup
of PassRefPtr use and InjectedScript use.

(Inspector::InspectorDebuggerAgent::didPause):
Clean up so that we first check for an Exception, and then fall
back to including a Pause Reason derived from the Debugger.

* inspector/protocol/Debugger.json:
Add new DebuggerStatement, Breakpoint, and PauseOnNextStatement reasons.

2015-01-08 Joseph Pecoraro <pecoraro@apple.com>

Web Inspector: Type check NSArray's in ObjC Interfaces have the right object types
@@ -160,6 +160,7 @@ Debugger::Debugger(bool isInWorkerThread)
, m_lastExecutedLine(UINT_MAX)
, m_lastExecutedSourceID(noSourceID)
, m_topBreakpointID(noBreakpointID)
, m_pausingBreakpointID(noBreakpointID)
{
}

@@ -670,9 +671,15 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame)
// we still have a current call frame when we get back.
if (breakpoint.autoContinue || !m_currentCallFrame)
return;
m_pausingBreakpointID = breakpoint.id;
}

handlePause(vmEntryGlobalObject, m_reasonForPause);
{
PauseReasonDeclaration reason(*this, didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause);
handlePause(vmEntryGlobalObject, m_reasonForPause);
}

m_pausingBreakpointID = noBreakpointID;

if (!m_pauseOnNextStatement && !m_pauseOnCallFrame) {
setSteppingMode(SteppingModeDisabled);
@@ -779,7 +786,7 @@ void Debugger::didReachBreakpoint(CallFrame* callFrame)
if (m_isPaused)
return;

PauseReasonDeclaration reason(*this, PausedForBreakpoint);
PauseReasonDeclaration reason(*this, PausedForDebuggerStatement);
m_pauseOnNextStatement = true;
setSteppingMode(SteppingModeEnabled);
updateCallFrameAndPauseIfNeeded(callFrame);
@@ -83,6 +83,20 @@ class JS_EXPORT_PRIVATE Debugger {
PauseOnExceptionsState pauseOnExceptionsState() const { return m_pauseOnExceptionsState; }
void setPauseOnExceptionsState(PauseOnExceptionsState);

enum ReasonForPause {
NotPaused,
PausedForException,
PausedAtStatement,
PausedAfterCall,
PausedBeforeReturn,
PausedAtStartOfProgram,
PausedAtEndOfProgram,
PausedForBreakpoint,
PausedForDebuggerStatement,
};
ReasonForPause reasonForPause() const { return m_reasonForPause; }
BreakpointID pausingBreakpointID() const { return m_pausingBreakpointID; }

void setPauseOnNextStatement(bool);
void breakProgram();
void continueProgram();
@@ -111,20 +125,6 @@ class JS_EXPORT_PRIVATE Debugger {
virtual bool needPauseHandling(JSGlobalObject*) { return false; }
virtual void handleBreakpointHit(JSGlobalObject*, const Breakpoint&) { }
virtual void handleExceptionInBreakpointCondition(ExecState*, JSValue exception) const { UNUSED_PARAM(exception); }

enum ReasonForPause {
NotPaused,
PausedForException,
PausedAtStatement,
PausedAfterCall,
PausedBeforeReturn,
PausedAtStartOfProgram,
PausedAtEndOfProgram,
PausedForBreakpoint
};

ReasonForPause reasonForPause() const { return m_reasonForPause; }

virtual void handlePause(JSGlobalObject*, ReasonForPause) { }
virtual void notifyDoneProcessingDebuggerEvents() { }

@@ -205,6 +205,7 @@ class JS_EXPORT_PRIVATE Debugger {
SourceID m_lastExecutedSourceID;

BreakpointID m_topBreakpointID;
BreakpointID m_pausingBreakpointID;
BreakpointIDToBreakpointMap m_breakpointIDToBreakpoint;
SourceIDToBreakpointsMap m_sourceIDToBreakpoints;

0 comments on commit 6aaa86b

Please sign in to comment.