<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[163477] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/163477">163477</a></dd>
<dt>Author</dt> <dd>bburg@apple.com</dd>
<dt>Date</dt> <dd>2014-02-05 14:21:40 -0800 (Wed, 05 Feb 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: add probe manager and model objects to the frontend
https://bugs.webkit.org/show_bug.cgi?id=127117

Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

The inspector frontend now assigns breakpoint action identifiers,
rather than the backend. Remove return values containing breakpoint
identifiers, and remove tracking and assignment of action identifiers.

* inspector/ScriptDebugListener.h:
* inspector/ScriptDebugServer.cpp:
(Inspector::ScriptDebugServer::evaluateBreakpointAction):
(Inspector::ScriptDebugServer::dispatchBreakpointActionProbe):
Pass BreakpointAction by reference rather than just the action identifier.

* inspector/ScriptDebugServer.h:
* inspector/agents/InspectorDebuggerAgent.cpp:
(Inspector::objectGroupForBreakpointAction):
(Inspector::InspectorDebuggerAgent::InspectorDebuggerAgent):
(Inspector::InspectorDebuggerAgent::breakpointActionsFromProtocol):
(Inspector::InspectorDebuggerAgent::setBreakpointByUrl):
(Inspector::InspectorDebuggerAgent::setBreakpoint):
(Inspector::InspectorDebuggerAgent::removeBreakpoint):
(Inspector::InspectorDebuggerAgent::breakpointActionProbe):
* inspector/agents/InspectorDebuggerAgent.h:
* inspector/protocol/Debugger.json: Revert change to setBreakpoint return values. Add optional identifier to breakpoint actions.

Source/WebInspectorUI:

Add the probe manager, and the following model objects:

- ProbeObject corresponds to a single probe breakpoint action.
- ProbeSetObject contains all ProbeObjects for one Breakpoint.
- ProbeSetDataFrame holds probe samples from multiple
probes fired from the same breakpoint hit/debugger pause.
- ProbeSetDataTable keeps track of multiple such data frames
and manages probe sample lifetimes across page navigations.

The probe manager updates probe model objects whenever breakpoints
are added, removed, or modified.

The inspector frontend now assigns breakpoint action identifiers,
rather than the backend. This lets ProbeObjects keep stable
identifiers that match the probe's samples, even when the underlying
breakpoint is re-added with a different identifier (such as when
editing probe expressions).

* UserInterface/Breakpoint.js:
(WebInspector.Breakpoint.prototype.get probeActions): Added.
(WebInspector.Breakpoint.prototype.createAction):
(WebInspector.Breakpoint.prototype.removeAction):
(WebInspector.Breakpoint.prototype.clearActions): Added.
* UserInterface/BreakpointAction.js:
(WebInspector.BreakpointAction):
(WebInspector.BreakpointAction.prototype.get id):
(WebInspector.BreakpointAction.prototype.get info):
* UserInterface/DebuggerManager.js:
(WebInspector.DebuggerManager.restoreBreakpointsSoon):
(WebInspector.DebuggerManager): Restore saved breakpoints
from cookies on the second run loop, so that all managers will
be able to received breakpoint added events.
(WebInspector.DebuggerManager.prototype.addBreakpoint):
(WebInspector.DebuggerManager.prototype.removeBreakpoint):
(WebInspector.DebuggerManager.prototype.get nextBreakpointActionIdentifier):
The debugger manager assigns unique breakpoint action identifiers with this getter.

(WebInspector.DebuggerManager.prototype._debuggerBreakpointActionType):
(WebInspector.DebuggerManager.prototype.didSetBreakpoint):
(WebInspector.DebuggerManager.prototype._setBreakpoint):
(WebInspector.DebuggerManager.prototype.didRemoveBreakpoint):
(WebInspector.DebuggerManager.prototype._removeBreakpoint):
* UserInterface/DebuggerObserver.js:
(WebInspector.DebuggerObserver.prototype.didSampleProbe):
* UserInterface/InspectorJSBackendCommands.js:
* UserInterface/Main.html:
* UserInterface/Main.js:
(WebInspector.loaded):
* UserInterface/Probe.js: Added.
(WebInspector.ProbeSample):
(WebInspector.Probe):
(WebInspector.Probe.prototype.get id):
(WebInspector.Probe.prototype.get breakpoint):
(WebInspector.Probe.prototype.get expression):
(WebInspector.Probe.prototype.set expression):
(WebInspector.Probe.prototype.get samples):
(WebInspector.Probe.prototype.clearSamples):
(WebInspector.Probe.prototype.addSample):
* UserInterface/ProbeManager.js: Added.
(WebInspector.ProbeManager):
(WebInspector.ProbeManager.prototype.probeSetForBreakpoint):
(WebInspector.ProbeManager.prototype._breakpointRemoved):
(WebInspector.ProbeManager.prototype._breakpointActionsChanged.get var):
(WebInspector.ProbeManager.prototype._breakpointActionsChanged.set get knownProbeIdentifiers):
(WebInspector.ProbeManager.prototype._breakpointActionsChanged):
* UserInterface/ProbeSet.js: Added.
(WebInspector.ProbeSet):
(WebInspector.ProbeSet.prototype.get breakpoint):
(WebInspector.ProbeSet.prototype.get probes):
(WebInspector.ProbeSet.prototype.get dataTable):
(WebInspector.ProbeSet.prototype.clear):
(WebInspector.ProbeSet.prototype.clearSamples):
(WebInspector.ProbeSet.prototype.createProbe):
(WebInspector.ProbeSet.prototype.removeProbe):
(WebInspector.ProbeSet.prototype.willRemove):
(WebInspector.ProbeSet.prototype._mainResourceChanged):
(WebInspector.ProbeSet.prototype._createDataTable):
(WebInspector.ProbeSet.prototype._sampleCollected):
(WebInspector.ProbeSet.prototype._breakpointResolvedStateDidChange):
* UserInterface/ProbeSetDataFrame.js: Added.
(WebInspector.ProbeSetDataFrame):
(WebInspector.ProbeSetDataFrame.compare):
(WebInspector.ProbeSetDataFrame.prototype.get key):
(WebInspector.ProbeSetDataFrame.prototype.get count):
(WebInspector.ProbeSetDataFrame.prototype.get index):
(WebInspector.ProbeSetDataFrame.prototype.get isSeparator):
(WebInspector.ProbeSetDataFrame.prototype.set isSeparator):
(WebInspector.ProbeSetDataFrame.prototype.addSampleForProbe):
(WebInspector.ProbeSetDataFrame.prototype.missingKeys):
(WebInspector.ProbeSetDataFrame.prototype.isComplete):
(WebInspector.ProbeSetDataFrame.prototype.fillMissingValues):
* UserInterface/ProbeSetDataTable.js: Added.
(WebInspector.ProbeSetDataTable):
(WebInspector.ProbeSetDataTable.prototype.get frames):
(WebInspector.ProbeSetDataTable.prototype.get separators):
(WebInspector.ProbeSetDataTable.prototype.willRemove):
(WebInspector.ProbeSetDataTable.prototype.mainResourceChanged):
(WebInspector.ProbeSetDataTable.prototype.addSampleForProbe):
(WebInspector.ProbeSetDataTable.prototype.addProbe):
(WebInspector.ProbeSetDataTable.prototype.removeProbe):
(WebInspector.ProbeSetDataTable.prototype.createFrame):
(WebInspector.ProbeSetDataTable.prototype.addFrame):
(WebInspector.ProbeSetDataTable.prototype.addSeparator):

LayoutTests:

Set up the debugger and probe managers when testing models.

Add a workalike for InspectorBackend.dumpInspectorProtocolMessages to
InspectorTest.

Add listeners for breakpoints and probes that produce
useful, deterministic trace output. Use the tracing in a new test.

* http/tests/inspector-protocol/resources/InspectorTest.js:
(InspectorTest.sendCommand):
(InspectorTest.initializeInspectorModels.console.assert):
(InspectorTest.initializeInspectorModels):
* inspector-protocol/debugger/didSampleProbe-multiple-probes-expected.txt:
* inspector-protocol/debugger/didSampleProbe-multiple-probes.html:
* inspector-protocol/model/probe-manager-add-remove-actions-expected.txt: Added.
* inspector-protocol/model/probe-manager-add-remove-actions.html: Added.
* inspector-protocol/resources/probe-helper.js:
(ProbeHelper.stringifyProbeSample):
(ProbeHelper.installTracingListeners.WebInspector):
(ProbeHelper.installTracingListeners):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestshttptestsinspectorprotocolresourcesInspectorTestjs">trunk/LayoutTests/http/tests/inspector-protocol/resources/InspectorTest.js</a></li>
<li><a href="#trunkLayoutTestsinspectorprotocoldebuggerdidSampleProbemultipleprobesexpectedtxt">trunk/LayoutTests/inspector-protocol/debugger/didSampleProbe-multiple-probes-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectorprotocoldebuggerdidSampleProbemultipleprobeshtml">trunk/LayoutTests/inspector-protocol/debugger/didSampleProbe-multiple-probes.html</a></li>
<li><a href="#trunkLayoutTestsinspectorprotocolresourcesprobehelperjs">trunk/LayoutTests/inspector-protocol/resources/probe-helper.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectorScriptDebugListenerh">trunk/Source/JavaScriptCore/inspector/ScriptDebugListener.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectorScriptDebugServercpp">trunk/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectorScriptDebugServerh">trunk/Source/JavaScriptCore/inspector/ScriptDebugServer.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectoragentsInspectorDebuggerAgentcpp">trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectoragentsInspectorDebuggerAgenth">trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectorprotocolDebuggerjson">trunk/Source/JavaScriptCore/inspector/protocol/Debugger.json</a></li>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceBreakpointjs">trunk/Source/WebInspectorUI/UserInterface/Breakpoint.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceBreakpointActionjs">trunk/Source/WebInspectorUI/UserInterface/BreakpointAction.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceDebuggerManagerjs">trunk/Source/WebInspectorUI/UserInterface/DebuggerManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceDebuggerObserverjs">trunk/Source/WebInspectorUI/UserInterface/DebuggerObserver.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceInspectorJSBackendCommandsjs">trunk/Source/WebInspectorUI/UserInterface/InspectorJSBackendCommands.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceMainhtml">trunk/Source/WebInspectorUI/UserInterface/Main.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceMainjs">trunk/Source/WebInspectorUI/UserInterface/Main.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsinspectorprotocolmodelprobemanageraddremoveactionsexpectedtxt">trunk/LayoutTests/inspector-protocol/model/probe-manager-add-remove-actions-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectorprotocolmodelprobemanageraddremoveactionshtml">trunk/LayoutTests/inspector-protocol/model/probe-manager-add-remove-actions.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProbejs">trunk/Source/WebInspectorUI/UserInterface/Probe.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProbeManagerjs">trunk/Source/WebInspectorUI/UserInterface/ProbeManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProbeSetjs">trunk/Source/WebInspectorUI/UserInterface/ProbeSet.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProbeSetDataFramejs">trunk/Source/WebInspectorUI/UserInterface/ProbeSetDataFrame.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProbeSetDataTablejs">trunk/Source/WebInspectorUI/UserInterface/ProbeSetDataTable.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/LayoutTests/ChangeLog        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2014-02-05  Brian Burg  &lt;bburg@apple.com&gt;
+
+        Web Inspector: add probe manager and model objects to the frontend
+        https://bugs.webkit.org/show_bug.cgi?id=127117
+
+        Reviewed by Timothy Hatcher.
+
+        Set up the debugger and probe managers when testing models.
+
+        Add a workalike for InspectorBackend.dumpInspectorProtocolMessages to
+        InspectorTest.
+
+        Add listeners for breakpoints and probes that produce
+        useful, deterministic trace output. Use the tracing in a new test.
+
+        * http/tests/inspector-protocol/resources/InspectorTest.js:
+        (InspectorTest.sendCommand):
+        (InspectorTest.initializeInspectorModels.console.assert):
+        (InspectorTest.initializeInspectorModels):
+        * inspector-protocol/debugger/didSampleProbe-multiple-probes-expected.txt:
+        * inspector-protocol/debugger/didSampleProbe-multiple-probes.html:
+        * inspector-protocol/model/probe-manager-add-remove-actions-expected.txt: Added.
+        * inspector-protocol/model/probe-manager-add-remove-actions.html: Added.
+        * inspector-protocol/resources/probe-helper.js:
+        (ProbeHelper.stringifyProbeSample):
+        (ProbeHelper.installTracingListeners.WebInspector):
+        (ProbeHelper.installTracingListeners):
+
</ins><span class="cx"> 2014-02-05  Antti Koivisto  &lt;antti@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         ElementRuleCollector should not use StyleResolver::State
</span></span></pre></div>
<a id="trunkLayoutTestshttptestsinspectorprotocolresourcesInspectorTestjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/inspector-protocol/resources/InspectorTest.js (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/inspector-protocol/resources/InspectorTest.js        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/LayoutTests/http/tests/inspector-protocol/resources/InspectorTest.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> InspectorFrontendAPI = {};
</span><span class="cx"> 
</span><span class="cx"> InspectorTest = {};
</span><ins>+InspectorTest.dumpInspectorProtocolMessages = false;
</ins><span class="cx"> InspectorTest._dispatchTable = [];
</span><span class="cx"> InspectorTest._requestId = -1;
</span><span class="cx"> InspectorTest.eventHandler = {};
</span><span class="lines">@@ -43,6 +44,11 @@
</span><span class="cx">                           &quot;params&quot;: params,
</span><span class="cx">                           &quot;id&quot;: this._requestId };
</span><span class="cx"> 
</span><ins>+    // This matches the debug dumping in InspectorBackend, which is bypassed
+    // by InspectorTest. Return messages should be dumped by InspectorBackend.
+    if (this.dumpInspectorProtocolMessages)
+        console.log(&quot;frontend: &quot; + JSON.stringify(messageObject));
+
</ins><span class="cx">     InspectorFrontendHost.sendMessageToBackend(JSON.stringify(messageObject));
</span><span class="cx"> 
</span><span class="cx">     return this._requestId;
</span><span class="lines">@@ -165,8 +171,9 @@
</span><span class="cx">     {
</span><span class="cx">         if (assertion)
</span><span class="cx">             return;
</span><ins>+
+        InspectorTest.log(&quot;ASSERT:&quot; + message);
</ins><span class="cx">         InspectorTest.completeTest();
</span><del>-        InspectorTest.log(&quot;ASSERT:&quot; + message);
</del><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     // Note: This function overwrites the InspectorFrontendAPI, so there's currently no
</span><span class="lines">@@ -194,8 +201,12 @@
</span><span class="cx">         &quot;Revision&quot;,
</span><span class="cx">         &quot;SourceCodeRevision&quot;,
</span><span class="cx">         &quot;SourceCode&quot;,
</span><ins>+        &quot;SourceCodeLocation&quot;,
+        &quot;Script&quot;,
+        &quot;TextRange&quot;,
</ins><span class="cx">         &quot;Resource&quot;,
</span><span class="cx">         &quot;ResourceCollection&quot;,
</span><ins>+        &quot;SourceMapResource&quot;,
</ins><span class="cx">         &quot;DOMTreeManager&quot;,
</span><span class="cx">         &quot;DOMNode&quot;,
</span><span class="cx">         &quot;ContentFlow&quot;,
</span><span class="lines">@@ -206,7 +217,17 @@
</span><span class="cx">         &quot;CSSStyleManager&quot;,
</span><span class="cx">         &quot;Color&quot;,
</span><span class="cx">         &quot;RuntimeObserver&quot;,
</span><del>-        &quot;RuntimeManager&quot;
</del><ins>+        &quot;RuntimeManager&quot;,
+        &quot;DebuggerObserver&quot;,
+        &quot;DebuggerManager&quot;,
+        &quot;BreakpointAction&quot;,
+        &quot;Breakpoint&quot;,
+        &quot;Probe&quot;,
+        &quot;ProbeSet&quot;,
+        &quot;ProbeManager&quot;,
+        &quot;ProbeSetDataFrame&quot;,
+        &quot;ProbeSetDataTable&quot;,
+        &quot;RemoteObject&quot;
</ins><span class="cx">     ];
</span><span class="cx"> 
</span><span class="cx">     // This corresponds to loading the scripts in Main.hml.
</span><span class="lines">@@ -225,6 +246,7 @@
</span><span class="cx">     InspectorBackend.registerInspectorDispatcher(new WebInspector.InspectorObserver);
</span><span class="cx">     InspectorBackend.registerPageDispatcher(new WebInspector.PageObserver);
</span><span class="cx">     InspectorBackend.registerDOMDispatcher(new WebInspector.DOMObserver);
</span><ins>+    InspectorBackend.registerDebuggerDispatcher(new WebInspector.DebuggerObserver);
</ins><span class="cx">     InspectorBackend.registerCSSDispatcher(new WebInspector.CSSObserver);
</span><span class="cx">     if (InspectorBackend.registerRuntimeDispatcher)
</span><span class="cx">         InspectorBackend.registerRuntimeDispatcher(new WebInspector.RuntimeObserver);
</span><span class="lines">@@ -232,7 +254,9 @@
</span><span class="cx">     WebInspector.frameResourceManager = new WebInspector.FrameResourceManager;
</span><span class="cx">     WebInspector.domTreeManager = new WebInspector.DOMTreeManager;
</span><span class="cx">     WebInspector.cssStyleManager = new WebInspector.CSSStyleManager;
</span><ins>+    WebInspector.debuggerManager = new WebInspector.DebuggerManager;
</ins><span class="cx">     WebInspector.runtimeManager = new WebInspector.RuntimeManager;
</span><ins>+    WebInspector.probeManager = new WebInspector.ProbeManager;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsinspectorprotocoldebuggerdidSampleProbemultipleprobesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/inspector-protocol/debugger/didSampleProbe-multiple-probes-expected.txt (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector-protocol/debugger/didSampleProbe-multiple-probes-expected.txt        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/LayoutTests/inspector-protocol/debugger/didSampleProbe-multiple-probes-expected.txt        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -1,11 +1,10 @@
</span><span class="cx"> Debugger.setBreakpoint with multiple probe actions at the same breakpoint. Test Debugger.didSampleProbe events for the probe samples.
</span><span class="cx"> 
</span><span class="cx"> Found breakpoint.js
</span><del>-PASS: Should receive two breakpoint action identifiers on Debugger.setBreakpoint callback.
</del><span class="cx"> Running breakpointActions to trigger probe samples.
</span><span class="cx"> inside breakpointActions a:(12) b:([object Object])
</span><span class="cx"> Received probe sample payload: {&quot;type&quot;:&quot;number&quot;,&quot;value&quot;:12,&quot;description&quot;:&quot;12&quot;}
</span><span class="cx"> Received probe sample payload: {&quot;type&quot;:&quot;number&quot;,&quot;value&quot;:12,&quot;description&quot;:&quot;12&quot;}
</span><del>-PASS: Samples from probe actions on the same breakpoint should have unique action identifiers.
</del><ins>+PASS: Samples from different probe actions should have unique action identifiers.
</ins><span class="cx"> PASS: Samples from probe actions on the same breakpoint should have the same batch identifiers.
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsinspectorprotocoldebuggerdidSampleProbemultipleprobeshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/inspector-protocol/debugger/didSampleProbe-multiple-probes.html (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector-protocol/debugger/didSampleProbe-multiple-probes.html        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/LayoutTests/inspector-protocol/debugger/didSampleProbe-multiple-probes.html        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -24,7 +24,7 @@
</span><span class="cx"> 
</span><span class="cx">     var tests = [
</span><span class="cx">         {
</span><del>-            message: &quot;Samples from probe actions on the same breakpoint should have unique action identifiers.&quot;,
</del><ins>+            message: &quot;Samples from different probe actions should have unique action identifiers.&quot;,
</ins><span class="cx">             predicate: function samplesHaveUniqueActionIds() {
</span><span class="cx">                 return samples[0].probeId !== samples[1].probeId;
</span><span class="cx">             },
</span><span class="lines">@@ -48,22 +48,14 @@
</span><span class="cx">             var options = {
</span><span class="cx">                 autoContinue: true,
</span><span class="cx">                 actions: [
</span><del>-                    {&quot;type&quot;: &quot;probe&quot;, &quot;data&quot;: &quot;a&quot;},
-                    {&quot;type&quot;: &quot;probe&quot;, &quot;data&quot;: &quot;a&quot;}
</del><ins>+                    {&quot;type&quot;: &quot;probe&quot;, &quot;data&quot;: &quot;a&quot;, &quot;id&quot;: 1},
+                    {&quot;type&quot;: &quot;probe&quot;, &quot;data&quot;: &quot;a&quot;, &quot;id&quot;: 2}
</ins><span class="cx">                 ]
</span><span class="cx">             };
</span><span class="cx"> 
</span><span class="cx">             InspectorTest.sendCommand(&quot;Debugger.setBreakpoint&quot;, {location: location, options: options}, function(responseObject) {
</span><span class="cx">                 InspectorTest.checkForError(responseObject);
</span><del>-                var actionIdentifiers = responseObject.result.breakpointActionIdentifiers;
-                InspectorTest.assert(actionIdentifiers instanceof Array &amp;&amp; actionIdentifiers.length === 2,
-                                     &quot;Should receive two breakpoint action identifiers on Debugger.setBreakpoint callback.&quot;);
</del><span class="cx"> 
</span><del>-                // FIXME: should we use the Breakpoint/BreakpointAction model objects to manage this?
-                if (actionIdentifiers.length === 2) {
-                    options.actions[0].identifier = actionIdentifiers[0];
-                    options.actions[1].identifier = actionIdentifiers[1];
-                }
</del><span class="cx">                 InspectorTest.log(&quot;Running breakpointActions to trigger probe samples.&quot;);
</span><span class="cx">                 InspectorTest.sendCommand(&quot;Runtime.evaluate&quot;, {expression: &quot;breakpointActions(12, {x:1,y:2})&quot;});
</span><span class="cx">             });
</span></span></pre></div>
<a id="trunkLayoutTestsinspectorprotocolmodelprobemanageraddremoveactionsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector-protocol/model/probe-manager-add-remove-actions-expected.txt (0 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector-protocol/model/probe-manager-add-remove-actions-expected.txt                                (rev 0)
+++ trunk/LayoutTests/inspector-protocol/model/probe-manager-add-remove-actions-expected.txt        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+Testing that the probe manager properly handles addition and removal of related probes.
+
+Breakpoint autocontinue state changed: true
+Probe set was added. New count: 1
+Probe with identifier 1 was added to probe set.
+Probe set's probe count: 1
+Breakpoint actions changed. New count: 1
+Probe with identifier 2 was added to probe set.
+Probe set's probe count: 2
+Breakpoint actions changed. New count: 2
+Breakpoint was added.
+PASS: Breakpoint should be resolved.
+inside breakpointActions a:(12) b:([object Object])
+Breakpoint resolved state changed: true
+Hit test checkpoint event #0 with type: probe-object-sample-added
+Probe with identifier 1 added sample: [object Object]
+Hit test checkpoint event #1 with type: probe-object-sample-added
+
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectorprotocolmodelprobemanageraddremoveactionshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector-protocol/model/probe-manager-add-remove-actions.html (0 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector-protocol/model/probe-manager-add-remove-actions.html                                (rev 0)
+++ trunk/LayoutTests/inspector-protocol/model/probe-manager-add-remove-actions.html        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -0,0 +1,54 @@
</span><ins>+&lt;!doctype html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script type=&quot;text/javascript&quot; src=&quot;../../http/tests/inspector-protocol/resources/protocol-test.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../debugger/resources/breakpoint.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+function test()
+{
+    InspectorTest.importScript(&quot;../../../../inspector-protocol/resources/probe-helper.js&quot;);
+    InspectorTest.initializeInspectorModels();
+
+    var currentTicks = 0;
+    const expectedTicks = 2;
+
+    function incrementTick(event)
+    {
+        InspectorTest.log(&quot;Hit test checkpoint event #&quot; + currentTicks + &quot; with type: &quot; + event.type);
+        if (++currentTicks === expectedTicks)
+            InspectorTest.completeTest();
+    }
+
+    WebInspector.Probe.addEventListener(WebInspector.Probe.Event.SampleAdded, incrementTick);
+
+    ProbeHelper.installTracingListeners();
+
+    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+
+        var scriptObject = event.data.script;
+
+        if (!/resources\/breakpoint\.js$/.test(scriptObject.url))
+            return;
+
+        var location = scriptObject.createSourceCodeLocation(18, 0);
+        // For this test, first create the breakpoint and its actions before sending anything to the backend.
+        var breakpoint = new WebInspector.Breakpoint(location);
+        breakpoint.autoContinue = true;
+        // Create two related actions.
+        for (var i of [0, 1])
+            var action = breakpoint.createAction(WebInspector.BreakpointAction.Type.Probe, null, &quot;a&quot;);
+
+        WebInspector.debuggerManager.addBreakpoint(breakpoint);
+
+        breakpoint.addEventListener(WebInspector.Breakpoint.Event.ResolvedStateDidChange, function() {
+            InspectorTest.assert(breakpoint.resolved, &quot;Breakpoint should be resolved.&quot;);
+            InspectorTest.sendCommand(&quot;Runtime.evaluate&quot;, {expression: &quot;breakpointActions(12, {x:1,y:2})&quot;});
+        });
+    });
+}
+&lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=&quot;runTest()&quot;&gt;
+    &lt;p&gt;Testing that the probe manager properly handles addition and removal of related probes.&lt;/p&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectorprotocolresourcesprobehelperjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/inspector-protocol/resources/probe-helper.js (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector-protocol/resources/probe-helper.js        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/LayoutTests/inspector-protocol/resources/probe-helper.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -10,3 +10,118 @@
</span><span class="cx">         payload: data.payload
</span><span class="cx">     };
</span><span class="cx"> }
</span><ins>+
+ProbeHelper.stringifyProbeSample = function(ProbeSample)
+{
+    console.assert(ProbeSample instanceof WebInspector.ProbeSample, &quot;Unexpected object type!&quot;);
+    return JSON.stringify({
+        &quot;sampleId&quot;: ProbeSample.sampleId,
+        &quot;batchId&quot;: ProbeSample.batchId,
+    });
+}
+
+ProbeHelper.installTracingListeners = function()
+{
+    if (!WebInspector.debuggerManager || !WebInspector.probeManager)
+        return;
+
+    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointAdded, function(event) {
+        InspectorTest.log(&quot;Breakpoint was added.&quot;);
+    });
+
+    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointRemoved, function(event) {
+        InspectorTest.log(&quot;Breakpoint was removed.&quot;);
+    });
+
+    WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.DisabledStateDidChange, function(event) {
+        var breakpoint = event.target;
+        console.assert(breakpoint instanceof WebInspector.Breakpoint, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Breakpoint disabled state changed: &quot; + breakpoint.disabled);
+    });
+
+    WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.ResolvedStateDidChange, function(event) {
+        var breakpoint = event.target;
+        console.assert(breakpoint instanceof WebInspector.Breakpoint, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Breakpoint resolved state changed: &quot; + breakpoint.resolved);
+    });
+
+    WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.AutoContinueDidChange, function(event) {
+        var breakpoint = event.target;
+        console.assert(breakpoint instanceof WebInspector.Breakpoint, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Breakpoint autocontinue state changed: &quot; + breakpoint.autoContinue);
+    });
+
+    WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.ConditionDidChange, function(event) {
+        var breakpoint = event.target;
+        console.assert(breakpoint instanceof WebInspector.Breakpoint, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Breakpoint condition changed: &quot; + breakpoint.condition);
+    });
+
+    WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.ActionsDidChange, function(event) {
+        var breakpoint = event.target;
+        console.assert(breakpoint instanceof WebInspector.Breakpoint, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Breakpoint actions changed. New count: &quot; + breakpoint.actions.length);
+    });
+
+    WebInspector.probeManager.addEventListener(WebInspector.ProbeManager.Event.ProbeSetAdded, function(event) {
+        var probeSet = event.data;
+        console.assert(probeSet instanceof WebInspector.ProbeSet, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Probe set was added. New count: &quot; + WebInspector.probeManager.probeSets.length);
+    });
+
+    WebInspector.probeManager.addEventListener(WebInspector.ProbeManager.Event.ProbeSetRemoved, function(event) {
+        var probeSet = event.data;
+        console.assert(probeSet instanceof WebInspector.ProbeSet, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Probe set was removed. New count: &quot; + WebInspector.probeManager.probeSets.length);
+    });
+
+    WebInspector.Probe.addEventListener(WebInspector.Probe.Event.ExpressionChanged, function(event) {
+        var probe = event.target;
+        console.assert(probe instanceof WebInspector.Probe, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Probe with identifier &quot; + probe.id + &quot; changed expression: &quot; + probe.expression);
+    });
+
+    WebInspector.Probe.addEventListener(WebInspector.Probe.Event.SampleAdded, function(event) {
+        var probe = event.target;
+        var sample = event.data;
+        console.assert(probe instanceof WebInspector.Probe, &quot;Unexpected object type!&quot;);
+        console.assert(sample instanceof WebInspector.ProbeSample, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Probe with identifier &quot; + probe.id + &quot; added sample: &quot; + sample);
+    });
+
+    WebInspector.Probe.addEventListener(WebInspector.Probe.Event.SamplesCleared, function(event) {
+        var probe = event.target;
+        console.assert(probe instanceof WebInspector.Probe, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Probe with identifier &quot; + probe.id + &quot; cleared all samples.&quot;);
+    });
+
+    WebInspector.ProbeSet.addEventListener(WebInspector.ProbeSet.Event.ProbeAdded, function(event) {
+        var probe = event.data;
+        var probeSet = event.target;
+        console.assert(probe instanceof WebInspector.Probe, &quot;Unexpected object type!&quot;);
+        console.assert(probeSet instanceof WebInspector.ProbeSet, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Probe with identifier &quot; + probe.id + &quot; was added to probe set.&quot;);
+        InspectorTest.log(&quot;Probe set's probe count: &quot; + probeSet.probes.length);
+    });
+
+    WebInspector.ProbeSet.addEventListener(WebInspector.ProbeSet.Event.ProbeRemoved, function(event) {
+        var probe = event.data;
+        var probeSet = event.target;
+        console.assert(probe instanceof WebInspector.Probe, &quot;Unexpected object type!&quot;);
+        console.assert(probeSet instanceof WebInspector.ProbeSet, &quot;Unexpected object type!&quot;);
+
+        InspectorTest.log(&quot;Probe with identifier &quot; + probe.id + &quot; was removed from probe set.&quot;);
+        InspectorTest.log(&quot;Probe set's probe count: &quot; + probeSet.probes.length);
+    });
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -1,3 +1,32 @@
</span><ins>+2014-02-05  Brian Burg  &lt;bburg@apple.com&gt;
+
+        Web Inspector: add probe manager and model objects to the frontend
+        https://bugs.webkit.org/show_bug.cgi?id=127117
+
+        Reviewed by Timothy Hatcher.
+
+        The inspector frontend now assigns breakpoint action identifiers,
+        rather than the backend. Remove return values containing breakpoint
+        identifiers, and remove tracking and assignment of action identifiers.
+
+        * inspector/ScriptDebugListener.h:
+        * inspector/ScriptDebugServer.cpp:
+        (Inspector::ScriptDebugServer::evaluateBreakpointAction):
+        (Inspector::ScriptDebugServer::dispatchBreakpointActionProbe):
+        Pass BreakpointAction by reference rather than just the action identifier.
+
+        * inspector/ScriptDebugServer.h:
+        * inspector/agents/InspectorDebuggerAgent.cpp:
+        (Inspector::objectGroupForBreakpointAction):
+        (Inspector::InspectorDebuggerAgent::InspectorDebuggerAgent):
+        (Inspector::InspectorDebuggerAgent::breakpointActionsFromProtocol):
+        (Inspector::InspectorDebuggerAgent::setBreakpointByUrl):
+        (Inspector::InspectorDebuggerAgent::setBreakpoint):
+        (Inspector::InspectorDebuggerAgent::removeBreakpoint):
+        (Inspector::InspectorDebuggerAgent::breakpointActionProbe):
+        * inspector/agents/InspectorDebuggerAgent.h:
+        * inspector/protocol/Debugger.json: Revert change to setBreakpoint return values. Add optional identifier to breakpoint actions.
+
</ins><span class="cx"> 2014-02-05  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         JSC on Mac should pull LLVM from prefix=/usr/local/LLVMForJavaScriptCore and not /usr/local
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectorScriptDebugListenerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/ScriptDebugListener.h (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/ScriptDebugListener.h        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/JavaScriptCore/inspector/ScriptDebugListener.h        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -69,11 +69,11 @@
</span><span class="cx">     virtual void didParseSource(JSC::SourceID, const Script&amp;) = 0;
</span><span class="cx">     virtual void failedToParseSource(const String&amp; url, const String&amp; data, int firstLine, int errorLine, const String&amp; errorMessage) = 0;
</span><span class="cx">     virtual void didPause(JSC::ExecState*, const Deprecated::ScriptValue&amp; callFrames, const Deprecated::ScriptValue&amp; exception) = 0;
</span><del>-    virtual void didSampleProbe(JSC::ExecState*, int probeIdentifier, int hitCount, const Deprecated::ScriptValue&amp; result) = 0;
</del><span class="cx">     virtual void didContinue() = 0;
</span><span class="cx"> 
</span><span class="cx">     virtual void breakpointActionLog(JSC::ExecState*, const String&amp;) = 0;
</span><span class="cx">     virtual void breakpointActionSound(int breakpointActionIdentifier) = 0;
</span><ins>+    virtual void breakpointActionProbe(JSC::ExecState*, const ScriptBreakpointAction&amp;, int hitCount, const Deprecated::ScriptValue&amp; result) = 0;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace Inspector
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectorScriptDebugServercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -113,7 +113,7 @@
</span><span class="cx">         
</span><span class="cx">         JSC::ExecState* state = debuggerCallFrame-&gt;scope()-&gt;globalObject()-&gt;globalExec();
</span><span class="cx">         Deprecated::ScriptValue wrappedResult = Deprecated::ScriptValue(state-&gt;vm(), exception ? exception : result);
</span><del>-        dispatchDidSampleProbe(state, breakpointAction.identifier, wrappedResult);
</del><ins>+        dispatchBreakpointActionProbe(state, breakpointAction, wrappedResult);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     default:
</span><span class="lines">@@ -176,7 +176,7 @@
</span><span class="cx">         listener-&gt;breakpointActionSound(breakpointActionIdentifier);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ScriptDebugServer::dispatchDidSampleProbe(ExecState* exec, int identifier, const Deprecated::ScriptValue&amp; sample)
</del><ins>+void ScriptDebugServer::dispatchBreakpointActionProbe(ExecState* exec, const ScriptBreakpointAction&amp; action, const Deprecated::ScriptValue&amp; sample)
</ins><span class="cx"> {
</span><span class="cx">     if (m_callingListeners)
</span><span class="cx">         return;
</span><span class="lines">@@ -191,7 +191,7 @@
</span><span class="cx">     Vector&lt;ScriptDebugListener*&gt; listenersCopy;
</span><span class="cx">     copyToVector(*listeners, listenersCopy);
</span><span class="cx">     for (auto listener : listenersCopy)
</span><del>-        listener-&gt;didSampleProbe(exec, identifier, m_hitCount, sample);
</del><ins>+        listener-&gt;breakpointActionProbe(exec, action, m_hitCount, sample);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ScriptDebugServer::dispatchDidContinue(ScriptDebugListener* listener)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectorScriptDebugServerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/ScriptDebugServer.h (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/ScriptDebugServer.h        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/JavaScriptCore/inspector/ScriptDebugServer.h        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -91,7 +91,7 @@
</span><span class="cx">     void dispatchFailedToParseSource(const ListenerSet&amp; listeners, JSC::SourceProvider*, int errorLine, const String&amp; errorMessage);
</span><span class="cx">     void dispatchBreakpointActionLog(JSC::ExecState*, const String&amp;);
</span><span class="cx">     void dispatchBreakpointActionSound(JSC::ExecState*, int breakpointActionIdentifier);
</span><del>-    void dispatchDidSampleProbe(JSC::ExecState*, int probeIdentifier, const Deprecated::ScriptValue&amp; sample);
</del><ins>+    void dispatchBreakpointActionProbe(JSC::ExecState*, const ScriptBreakpointAction&amp;, const Deprecated::ScriptValue&amp; sample);
</ins><span class="cx"> 
</span><span class="cx">     bool m_doneProcessingDebuggerEvents;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectoragentsInspectorDebuggerAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -46,10 +46,14 @@
</span><span class="cx"> 
</span><span class="cx"> const char* InspectorDebuggerAgent::backtraceObjectGroup = &quot;backtrace&quot;;
</span><span class="cx"> 
</span><del>-static String objectGroupForBreakpointAction(int identifier)
</del><ins>+// Objects created and retained by evaluating breakpoint actions are put into object groups
+// according to the breakpoint action identifier assigned by the frontend. A breakpoint may
+// have several object groups, and objects from several backend breakpoint action instances may
+// create objects in the same group.
+static String objectGroupForBreakpointAction(const ScriptBreakpointAction&amp; action)
</ins><span class="cx"> {
</span><span class="cx">     DEFINE_STATIC_LOCAL(const AtomicString, objectGroup, (&quot;breakpoint-action-&quot;, AtomicString::ConstructFromLiteral));
</span><del>-    return makeString(objectGroup, String::number(identifier));
</del><ins>+    return makeString(objectGroup, String::number(action.identifier));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> InspectorDebuggerAgent::InspectorDebuggerAgent(InjectedScriptManager* injectedScriptManager)
</span><span class="lines">@@ -61,7 +65,6 @@
</span><span class="cx">     , m_enabled(false)
</span><span class="cx">     , m_javaScriptPauseScheduled(false)
</span><span class="cx">     , m_nextProbeSampleId(1)
</span><del>-    , m_nextBreakpointActionIdentifier(1)
</del><span class="cx"> {
</span><span class="cx">     // FIXME: make breakReason optional so that there was no need to init it with &quot;other&quot;.
</span><span class="cx">     clearBreakDetails();
</span><span class="lines">@@ -222,16 +225,21 @@
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        // Specifying an identifier is optional. They are used to correlate probe samples
+        // in the frontend across multiple backend probe actions and segregate object groups.
+        int identifier = 0;
+        object-&gt;getNumber(ASCIILiteral(&quot;id&quot;), &amp;identifier);
+
</ins><span class="cx">         String data;
</span><span class="cx">         object-&gt;getString(ASCIILiteral(&quot;data&quot;), &amp;data);
</span><span class="cx"> 
</span><del>-        result-&gt;append(ScriptBreakpointAction(type, m_nextBreakpointActionIdentifier++, data));
</del><ins>+        result-&gt;append(ScriptBreakpointAction(type, identifier, data));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int lineNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const RefPtr&lt;InspectorObject&gt;* options, Inspector::TypeBuilder::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr&lt;Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::Location&gt;&gt;&amp; locations, RefPtr&lt;Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::BreakpointActionIdentifier&gt;&gt;&amp; breakpointActionIdentifiers)
</del><ins>+void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int lineNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const RefPtr&lt;InspectorObject&gt;* options, Inspector::TypeBuilder::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr&lt;Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::Location&gt;&gt;&amp; locations)
</ins><span class="cx"> {
</span><span class="cx">     locations = Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::Location&gt;::create();
</span><span class="cx">     if (!optionalURL == !optionalURLRegex) {
</span><span class="lines">@@ -262,10 +270,6 @@
</span><span class="cx">     if (!breakpointActionsFromProtocol(errorString, actions, &amp;breakpointActions))
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    breakpointActionIdentifiers = Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::BreakpointActionIdentifier&gt;::create();
-    for (ScriptBreakpointAction&amp; action : breakpointActions)
-        breakpointActionIdentifiers-&gt;addItem(action.identifier);
-
</del><span class="cx">     m_javaScriptBreakpoints.set(breakpointIdentifier, buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition, actions, isRegex, autoContinue));
</span><span class="cx"> 
</span><span class="cx">     ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition, breakpointActions, autoContinue);
</span><span class="lines">@@ -296,7 +300,7 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, const RefPtr&lt;InspectorObject&gt;&amp; location, const RefPtr&lt;InspectorObject&gt;* options, Inspector::TypeBuilder::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr&lt;Inspector::TypeBuilder::Debugger::Location&gt;&amp; actualLocation, RefPtr&lt;Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::BreakpointActionIdentifier&gt;&gt;&amp; breakpointActionIdentifiers)
</del><ins>+void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, const RefPtr&lt;InspectorObject&gt;&amp; location, const RefPtr&lt;InspectorObject&gt;* options, Inspector::TypeBuilder::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr&lt;Inspector::TypeBuilder::Debugger::Location&gt;&amp; actualLocation)
</ins><span class="cx"> {
</span><span class="cx">     JSC::SourceID sourceID;
</span><span class="cx">     unsigned lineNumber;
</span><span class="lines">@@ -317,10 +321,6 @@
</span><span class="cx">     if (!breakpointActionsFromProtocol(errorString, actions, &amp;breakpointActions))
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    breakpointActionIdentifiers = Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::BreakpointActionIdentifier&gt;::create();
-    for (ScriptBreakpointAction&amp; action : breakpointActions)
-        breakpointActionIdentifiers-&gt;addItem(action.identifier);
-
</del><span class="cx">     String breakpointIdentifier = String::number(sourceID) + ':' + String::number(lineNumber) + ':' + String::number(columnNumber);
</span><span class="cx">     if (m_breakpointIdentifierToDebugServerBreakpointIDs.find(breakpointIdentifier) != m_breakpointIdentifierToDebugServerBreakpointIDs.end()) {
</span><span class="cx">         *errorString = ASCIILiteral(&quot;Breakpoint at specified location already exists.&quot;);
</span><span class="lines">@@ -345,7 +345,7 @@
</span><span class="cx">     for (auto breakpointID : breakpointIDs) {
</span><span class="cx">         const Vector&lt;ScriptBreakpointAction&gt;&amp; breakpointActions = scriptDebugServer().getActionsForBreakpoint(breakpointID);
</span><span class="cx">         for (auto&amp; action : breakpointActions)
</span><del>-            m_injectedScriptManager-&gt;releaseObjectGroup(objectGroupForBreakpointAction(action.identifier));
</del><ins>+            m_injectedScriptManager-&gt;releaseObjectGroup(objectGroupForBreakpointAction(action));
</ins><span class="cx"> 
</span><span class="cx">         scriptDebugServer().removeBreakpoint(breakpointID);
</span><span class="cx">     }
</span><span class="lines">@@ -649,14 +649,19 @@
</span><span class="cx">         m_listener-&gt;didPause();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void InspectorDebuggerAgent::didSampleProbe(JSC::ExecState* scriptState, int probeIdentifier, int hitCount, const Deprecated::ScriptValue&amp; sample)
</del><ins>+void InspectorDebuggerAgent::breakpointActionSound(int breakpointActionIdentifier)
</ins><span class="cx"> {
</span><ins>+    m_frontendDispatcher-&gt;playBreakpointActionSound(breakpointActionIdentifier);
+}
+
+void InspectorDebuggerAgent::breakpointActionProbe(JSC::ExecState* scriptState, const ScriptBreakpointAction&amp; action, int hitCount, const Deprecated::ScriptValue&amp; sample)
+{
</ins><span class="cx">     int sampleId = m_nextProbeSampleId++;
</span><span class="cx"> 
</span><span class="cx">     InjectedScript injectedScript = m_injectedScriptManager-&gt;injectedScriptFor(scriptState);
</span><del>-    RefPtr&lt;TypeBuilder::Runtime::RemoteObject&gt; payload = injectedScript.wrapObject(sample, objectGroupForBreakpointAction(probeIdentifier));
</del><ins>+    RefPtr&lt;TypeBuilder::Runtime::RemoteObject&gt; payload = injectedScript.wrapObject(sample, objectGroupForBreakpointAction(action));
</ins><span class="cx">     RefPtr&lt;TypeBuilder::Debugger::ProbeSample&gt; result = TypeBuilder::Debugger::ProbeSample::create()
</span><del>-        .setProbeId(probeIdentifier)
</del><ins>+        .setProbeId(action.identifier)
</ins><span class="cx">         .setSampleId(sampleId)
</span><span class="cx">         .setBatchId(hitCount)
</span><span class="cx">         .setTimestamp(monotonicallyIncreasingTime())
</span><span class="lines">@@ -665,11 +670,6 @@
</span><span class="cx">     m_frontendDispatcher-&gt;didSampleProbe(result.release());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void InspectorDebuggerAgent::breakpointActionSound(int breakpointActionIdentifier)
-{
-    m_frontendDispatcher-&gt;playBreakpointActionSound(breakpointActionIdentifier);
-}
-
</del><span class="cx"> void InspectorDebuggerAgent::didContinue()
</span><span class="cx"> {
</span><span class="cx">     m_pausedScriptState = nullptr;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectoragentsInspectorDebuggerAgenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -71,8 +71,8 @@
</span><span class="cx">     virtual void enable(ErrorString*) override;
</span><span class="cx">     virtual void disable(ErrorString*) override;
</span><span class="cx">     virtual void setBreakpointsActive(ErrorString*, bool active) override;
</span><del>-    virtual void setBreakpointByUrl(ErrorString*, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const RefPtr&lt;Inspector::InspectorObject&gt;* options, Inspector::TypeBuilder::Debugger::BreakpointId*, RefPtr&lt;Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::Location&gt;&gt;&amp; locations, RefPtr&lt;Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::BreakpointActionIdentifier&gt;&gt;&amp; breakpointActionIdentifiers) override;
-    virtual void setBreakpoint(ErrorString*, const RefPtr&lt;Inspector::InspectorObject&gt;&amp; location, const RefPtr&lt;Inspector::InspectorObject&gt;* options, Inspector::TypeBuilder::Debugger::BreakpointId*, RefPtr&lt;Inspector::TypeBuilder::Debugger::Location&gt;&amp; actualLocation, RefPtr&lt;Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::BreakpointActionIdentifier&gt;&gt;&amp; breakpointActionIdentifiers) override;
</del><ins>+    virtual void setBreakpointByUrl(ErrorString*, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const RefPtr&lt;Inspector::InspectorObject&gt;* options, Inspector::TypeBuilder::Debugger::BreakpointId*, RefPtr&lt;Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::Debugger::Location&gt;&gt;&amp; locations) override;
+    virtual void setBreakpoint(ErrorString*, const RefPtr&lt;Inspector::InspectorObject&gt;&amp; location, const RefPtr&lt;Inspector::InspectorObject&gt;* options, Inspector::TypeBuilder::Debugger::BreakpointId*, RefPtr&lt;Inspector::TypeBuilder::Debugger::Location&gt;&amp; actualLocation) override;
</ins><span class="cx">     virtual void removeBreakpoint(ErrorString*, const String&amp; breakpointIdentifier) override;
</span><span class="cx">     virtual void continueToLocation(ErrorString*, const RefPtr&lt;InspectorObject&gt;&amp; location) override;
</span><span class="cx">     virtual void searchInContent(ErrorString*, const String&amp; scriptID, const String&amp; query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, RefPtr&lt;Inspector::TypeBuilder::Array&lt;Inspector::TypeBuilder::GenericTypes::SearchMatch&gt;&gt;&amp;) override;
</span><span class="lines">@@ -133,9 +133,9 @@
</span><span class="cx"> 
</span><span class="cx">     virtual void didParseSource(JSC::SourceID, const Script&amp;) override final;
</span><span class="cx">     virtual void failedToParseSource(const String&amp; url, const String&amp; data, int firstLine, int errorLine, const String&amp; errorMessage) override final;
</span><del>-    virtual void didSampleProbe(JSC::ExecState*, int probeIdentifier, int hitCount, const Deprecated::ScriptValue&amp; sample) override final;
</del><span class="cx"> 
</span><span class="cx">     virtual void breakpointActionSound(int breakpointActionIdentifier) override;
</span><ins>+    virtual void breakpointActionProbe(JSC::ExecState*, const ScriptBreakpointAction&amp;, int hitCount, const Deprecated::ScriptValue&amp; sample) override final;
</ins><span class="cx"> 
</span><span class="cx">     PassRefPtr&lt;Inspector::TypeBuilder::Debugger::Location&gt; resolveBreakpoint(const String&amp; breakpointIdentifier, JSC::SourceID, const ScriptBreakpoint&amp;);
</span><span class="cx">     bool assertPaused(ErrorString*);
</span><span class="lines">@@ -163,7 +163,6 @@
</span><span class="cx">     bool m_enabled;
</span><span class="cx">     bool m_javaScriptPauseScheduled;
</span><span class="cx">     int m_nextProbeSampleId;
</span><del>-    int m_nextBreakpointActionIdentifier;
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace Inspector
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectorprotocolDebuggerjson"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/protocol/Debugger.json (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/protocol/Debugger.json        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/JavaScriptCore/inspector/protocol/Debugger.json        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -37,7 +37,8 @@
</span><span class="cx">             &quot;type&quot;: &quot;object&quot;,
</span><span class="cx">             &quot;properties&quot;: [
</span><span class="cx">                 { &quot;name&quot;: &quot;type&quot;, &quot;type&quot;: &quot;string&quot;, &quot;enum&quot;: [&quot;log&quot;, &quot;evaluate&quot;, &quot;sound&quot;, &quot;probe&quot;], &quot;description&quot;: &quot;Different kinds of breakpoint actions.&quot; },
</span><del>-                { &quot;name&quot;: &quot;data&quot;, &quot;type&quot;: &quot;string&quot;, &quot;optional&quot;: true, &quot;description&quot;: &quot;Data associated with this breakpoint type (e.g. for type \&quot;eval\&quot; this is the JavaScript string to evalulate).&quot; }
</del><ins>+                { &quot;name&quot;: &quot;data&quot;, &quot;type&quot;: &quot;string&quot;, &quot;optional&quot;: true, &quot;description&quot;: &quot;Data associated with this breakpoint type (e.g. for type \&quot;eval\&quot; this is the JavaScript string to evalulate).&quot; },
+                { &quot;name&quot;: &quot;id&quot;, &quot;$ref&quot;: &quot;BreakpointActionIdentifier&quot;, &quot;optional&quot;: true, &quot;description&quot;: &quot;A frontend-assigned identifier for this breakpoint action.&quot; }
</ins><span class="cx">             ],
</span><span class="cx">             &quot;description&quot;: &quot;Action to perform when a breakpoint is triggered.&quot;
</span><span class="cx">         },
</span><span class="lines">@@ -124,8 +125,7 @@
</span><span class="cx">             ],
</span><span class="cx">             &quot;returns&quot;: [
</span><span class="cx">                 { &quot;name&quot;: &quot;breakpointId&quot;, &quot;$ref&quot;: &quot;BreakpointId&quot;, &quot;description&quot;: &quot;Id of the created breakpoint for further reference.&quot; },
</span><del>-                { &quot;name&quot;: &quot;locations&quot;, &quot;type&quot;: &quot;array&quot;, &quot;items&quot;: { &quot;$ref&quot;: &quot;Location&quot;}, &quot;description&quot;: &quot;List of the locations this breakpoint resolved into upon addition.&quot; },
-                { &quot;name&quot;: &quot;breakpointActionIdentifiers&quot;, &quot;type&quot;: &quot;array&quot;, &quot;items&quot;: { &quot;$ref&quot;: &quot;BreakpointActionIdentifier&quot; }, &quot;description&quot;: &quot;Assigned breakpoint action identifiers.&quot; }
</del><ins>+                { &quot;name&quot;: &quot;locations&quot;, &quot;type&quot;: &quot;array&quot;, &quot;items&quot;: { &quot;$ref&quot;: &quot;Location&quot;}, &quot;description&quot;: &quot;List of the locations this breakpoint resolved into upon addition.&quot; }
</ins><span class="cx">             ],
</span><span class="cx">             &quot;description&quot;: &quot;Sets JavaScript breakpoint at given location specified either by URL or URL regex. Once this command is issued, all existing parsed scripts will have breakpoints resolved and returned in &lt;code&gt;locations&lt;/code&gt; property. Further matching script parsing will result in subsequent &lt;code&gt;breakpointResolved&lt;/code&gt; events issued. This logical breakpoint will survive page reloads.&quot;
</span><span class="cx">         },
</span><span class="lines">@@ -137,8 +137,7 @@
</span><span class="cx">             ],
</span><span class="cx">             &quot;returns&quot;: [
</span><span class="cx">                 { &quot;name&quot;: &quot;breakpointId&quot;, &quot;$ref&quot;: &quot;BreakpointId&quot;, &quot;description&quot;: &quot;Id of the created breakpoint for further reference.&quot; },
</span><del>-                { &quot;name&quot;: &quot;actualLocation&quot;, &quot;$ref&quot;: &quot;Location&quot;, &quot;description&quot;: &quot;Location this breakpoint resolved into.&quot; },
-                { &quot;name&quot;: &quot;breakpointActionIdentifiers&quot;, &quot;type&quot;: &quot;array&quot;, &quot;items&quot;: { &quot;$ref&quot;: &quot;BreakpointActionIdentifier&quot; }, &quot;description&quot;: &quot;Assigned breakpoint action identifiers.&quot; }
</del><ins>+                { &quot;name&quot;: &quot;actualLocation&quot;, &quot;$ref&quot;: &quot;Location&quot;, &quot;description&quot;: &quot;Location this breakpoint resolved into.&quot; }
</ins><span class="cx">             ],
</span><span class="cx">             &quot;description&quot;: &quot;Sets JavaScript breakpoint at a given location.&quot;
</span><span class="cx">         },
</span><span class="lines">@@ -295,7 +294,7 @@
</span><span class="cx">         },
</span><span class="cx">         {
</span><span class="cx">             &quot;name&quot;: &quot;didSampleProbe&quot;,
</span><del>-            &quot;description&quot;: &quot;Fires when a new proben sample is collected.&quot;,
</del><ins>+            &quot;description&quot;: &quot;Fires when a new probe sample is collected.&quot;,
</ins><span class="cx">             &quot;parameters&quot;: [
</span><span class="cx">                 { &quot;name&quot;: &quot;sample&quot;, &quot;$ref&quot;: &quot;ProbeSample&quot;, &quot;description&quot;: &quot;A collected probe sample.&quot; }
</span><span class="cx">             ]
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/WebInspectorUI/ChangeLog        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -1,3 +1,114 @@
</span><ins>+2014-02-05  Brian Burg  &lt;bburg@apple.com&gt;
+
+        Web Inspector: add probe manager and model objects to the frontend
+        https://bugs.webkit.org/show_bug.cgi?id=127117
+
+        Reviewed by Timothy Hatcher.
+
+        Add the probe manager, and the following model objects:
+
+        - ProbeObject corresponds to a single probe breakpoint action.
+        - ProbeSetObject contains all ProbeObjects for one Breakpoint.
+        - ProbeSetDataFrame holds probe samples from multiple
+        probes fired from the same breakpoint hit/debugger pause.
+        - ProbeSetDataTable keeps track of multiple such data frames
+        and manages probe sample lifetimes across page navigations.
+
+        The probe manager updates probe model objects whenever breakpoints
+        are added, removed, or modified.
+
+        The inspector frontend now assigns breakpoint action identifiers,
+        rather than the backend. This lets ProbeObjects keep stable
+        identifiers that match the probe's samples, even when the underlying
+        breakpoint is re-added with a different identifier (such as when
+        editing probe expressions).
+
+        * UserInterface/Breakpoint.js:
+        (WebInspector.Breakpoint.prototype.get probeActions): Added.
+        (WebInspector.Breakpoint.prototype.createAction):
+        (WebInspector.Breakpoint.prototype.removeAction):
+        (WebInspector.Breakpoint.prototype.clearActions): Added.
+        * UserInterface/BreakpointAction.js:
+        (WebInspector.BreakpointAction):
+        (WebInspector.BreakpointAction.prototype.get id):
+        (WebInspector.BreakpointAction.prototype.get info):
+        * UserInterface/DebuggerManager.js:
+        (WebInspector.DebuggerManager.restoreBreakpointsSoon):
+        (WebInspector.DebuggerManager): Restore saved breakpoints
+        from cookies on the second run loop, so that all managers will
+        be able to received breakpoint added events.
+        (WebInspector.DebuggerManager.prototype.addBreakpoint):
+        (WebInspector.DebuggerManager.prototype.removeBreakpoint):
+        (WebInspector.DebuggerManager.prototype.get nextBreakpointActionIdentifier):
+        The debugger manager assigns unique breakpoint action identifiers with this getter.
+
+        (WebInspector.DebuggerManager.prototype._debuggerBreakpointActionType):
+        (WebInspector.DebuggerManager.prototype.didSetBreakpoint):
+        (WebInspector.DebuggerManager.prototype._setBreakpoint):
+        (WebInspector.DebuggerManager.prototype.didRemoveBreakpoint):
+        (WebInspector.DebuggerManager.prototype._removeBreakpoint):
+        * UserInterface/DebuggerObserver.js:
+        (WebInspector.DebuggerObserver.prototype.didSampleProbe):
+        * UserInterface/InspectorJSBackendCommands.js:
+        * UserInterface/Main.html:
+        * UserInterface/Main.js:
+        (WebInspector.loaded):
+        * UserInterface/Probe.js: Added.
+        (WebInspector.ProbeSample):
+        (WebInspector.Probe):
+        (WebInspector.Probe.prototype.get id):
+        (WebInspector.Probe.prototype.get breakpoint):
+        (WebInspector.Probe.prototype.get expression):
+        (WebInspector.Probe.prototype.set expression):
+        (WebInspector.Probe.prototype.get samples):
+        (WebInspector.Probe.prototype.clearSamples):
+        (WebInspector.Probe.prototype.addSample):
+        * UserInterface/ProbeManager.js: Added.
+        (WebInspector.ProbeManager):
+        (WebInspector.ProbeManager.prototype.probeSetForBreakpoint):
+        (WebInspector.ProbeManager.prototype._breakpointRemoved):
+        (WebInspector.ProbeManager.prototype._breakpointActionsChanged.get var):
+        (WebInspector.ProbeManager.prototype._breakpointActionsChanged.set get knownProbeIdentifiers):
+        (WebInspector.ProbeManager.prototype._breakpointActionsChanged):
+        * UserInterface/ProbeSet.js: Added.
+        (WebInspector.ProbeSet):
+        (WebInspector.ProbeSet.prototype.get breakpoint):
+        (WebInspector.ProbeSet.prototype.get probes):
+        (WebInspector.ProbeSet.prototype.get dataTable):
+        (WebInspector.ProbeSet.prototype.clear):
+        (WebInspector.ProbeSet.prototype.clearSamples):
+        (WebInspector.ProbeSet.prototype.createProbe):
+        (WebInspector.ProbeSet.prototype.removeProbe):
+        (WebInspector.ProbeSet.prototype.willRemove):
+        (WebInspector.ProbeSet.prototype._mainResourceChanged):
+        (WebInspector.ProbeSet.prototype._createDataTable):
+        (WebInspector.ProbeSet.prototype._sampleCollected):
+        (WebInspector.ProbeSet.prototype._breakpointResolvedStateDidChange):
+        * UserInterface/ProbeSetDataFrame.js: Added.
+        (WebInspector.ProbeSetDataFrame):
+        (WebInspector.ProbeSetDataFrame.compare):
+        (WebInspector.ProbeSetDataFrame.prototype.get key):
+        (WebInspector.ProbeSetDataFrame.prototype.get count):
+        (WebInspector.ProbeSetDataFrame.prototype.get index):
+        (WebInspector.ProbeSetDataFrame.prototype.get isSeparator):
+        (WebInspector.ProbeSetDataFrame.prototype.set isSeparator):
+        (WebInspector.ProbeSetDataFrame.prototype.addSampleForProbe):
+        (WebInspector.ProbeSetDataFrame.prototype.missingKeys):
+        (WebInspector.ProbeSetDataFrame.prototype.isComplete):
+        (WebInspector.ProbeSetDataFrame.prototype.fillMissingValues):
+        * UserInterface/ProbeSetDataTable.js: Added.
+        (WebInspector.ProbeSetDataTable):
+        (WebInspector.ProbeSetDataTable.prototype.get frames):
+        (WebInspector.ProbeSetDataTable.prototype.get separators):
+        (WebInspector.ProbeSetDataTable.prototype.willRemove):
+        (WebInspector.ProbeSetDataTable.prototype.mainResourceChanged):
+        (WebInspector.ProbeSetDataTable.prototype.addSampleForProbe):
+        (WebInspector.ProbeSetDataTable.prototype.addProbe):
+        (WebInspector.ProbeSetDataTable.prototype.removeProbe):
+        (WebInspector.ProbeSetDataTable.prototype.createFrame):
+        (WebInspector.ProbeSetDataTable.prototype.addFrame):
+        (WebInspector.ProbeSetDataTable.prototype.addSeparator):
+
</ins><span class="cx"> 2014-02-05  Zan Dobersek  &lt;zdobersek@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] Avoid no-op regenerations of GResourceBundle.xml, GResourceBundle.c
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceBreakpointjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Breakpoint.js (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Breakpoint.js        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/WebInspectorUI/UserInterface/Breakpoint.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -203,6 +203,13 @@
</span><span class="cx">         };
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    get probeActions()
+    {
+        return this._actions.filter(function(action) {
+            return action.type === WebInspector.BreakpointAction.Type.Probe;
+        });
+    },
+
</ins><span class="cx">     cycleToNextMode: function()
</span><span class="cx">     {
</span><span class="cx">         if (this.disabled) {
</span><span class="lines">@@ -281,9 +288,9 @@
</span><span class="cx">         }
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    createAction: function(type, precedingAction)
</del><ins>+    createAction: function(type, precedingAction, data)
</ins><span class="cx">     {
</span><del>-        var newAction = new WebInspector.BreakpointAction(this, type, null);
</del><ins>+        var newAction = new WebInspector.BreakpointAction(this, type, data || null);
</ins><span class="cx"> 
</span><span class="cx">         if (!precedingAction)
</span><span class="cx">             this._actions.push(newAction);
</span><span class="lines">@@ -332,6 +339,16 @@
</span><span class="cx">         this.dispatchEventToListeners(WebInspector.Breakpoint.Event.ActionsDidChange);
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    clearActions: function(type)
+    {
+        if (!type)
+            this._actions = [];
+        else
+            this._actions = this._actions.filter(function(action) { action.type != type; });
+
+        this.dispatchEventToListeners(WebInspector.Breakpoint.Event.ActionsDidChange);
+    },
+
</ins><span class="cx">     saveIdentityToCookie: function(cookie)
</span><span class="cx">     {
</span><span class="cx">         cookie[WebInspector.Breakpoint.URLCookieKey] = this.url;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceBreakpointActionjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/BreakpointAction.js (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/BreakpointAction.js        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/WebInspectorUI/UserInterface/BreakpointAction.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx">         console.error(&quot;Unexpected type passed to WebInspector.BreakpointAction&quot;);
</span><span class="cx"> 
</span><span class="cx">     console.assert(typeof this._type === &quot;string&quot;);
</span><ins>+    this._id = WebInspector.debuggerManager.nextBreakpointActionIdentifier;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WebInspector.BreakpointAction.Type = {
</span><span class="lines">@@ -53,6 +54,7 @@
</span><span class="cx"> 
</span><span class="cx"> WebInspector.BreakpointAction.prototype = {
</span><span class="cx">     constructor: WebInspector.BreakpointAction,
</span><ins>+    __proto__: WebInspector.Object.prototype,
</ins><span class="cx"> 
</span><span class="cx">     // Public
</span><span class="cx"> 
</span><span class="lines">@@ -61,6 +63,11 @@
</span><span class="cx">         return this._breakpoint;
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    get id()
+    {
+        return this._id;
+    },
+
</ins><span class="cx">     get type()
</span><span class="cx">     {
</span><span class="cx">         return this._type;
</span><span class="lines">@@ -83,11 +90,9 @@
</span><span class="cx"> 
</span><span class="cx">     get info()
</span><span class="cx">     {
</span><del>-        var obj = {type: this._type};
</del><ins>+        var obj = {type: this._type, id: this._id};
</ins><span class="cx">         if (this._data)
</span><span class="cx">             obj.data = this._data;
</span><span class="cx">         return obj;
</span><span class="cx">     }
</span><span class="cx"> };
</span><del>-
-WebInspector.BreakpointAction.prototype.__proto__ = WebInspector.Object.prototype;
</del></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceDebuggerManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/DebuggerManager.js (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/DebuggerManager.js        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/WebInspectorUI/UserInterface/DebuggerManager.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -53,6 +53,8 @@
</span><span class="cx">     this._breakpointScriptIdentifierMap = {};
</span><span class="cx">     this._breakpointIdMap = {};
</span><span class="cx"> 
</span><ins>+    this._nextBreakpointActionIdentifier = 1;
+
</ins><span class="cx">     this._scriptIdMap = {};
</span><span class="cx">     this._scriptURLMap = {};
</span><span class="cx"> 
</span><span class="lines">@@ -64,11 +66,14 @@
</span><span class="cx"> 
</span><span class="cx">     this._updateBreakOnExceptionsState();
</span><span class="cx"> 
</span><del>-    var savedBreakpoints = this._breakpointsSetting.value;
-    for (var i = 0; i &lt; savedBreakpoints.length; ++i) {
-        var breakpoint = new WebInspector.Breakpoint(savedBreakpoints[i]);
-        this.addBreakpoint(breakpoint, true);
</del><ins>+    function restoreBreakpointsSoon() {
+        for (cookie of this._breakpointsSetting.value)
+            this.addBreakpoint(new WebInspector.Breakpoint(cookie));
</ins><span class="cx">     }
</span><ins>+
+    // Ensure that all managers learn about restored breakpoints,
+    // regardless of their initialization order.
+    setTimeout(restoreBreakpointsSoon.bind(this), 0);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WebInspector.DebuggerManager.Event = {
</span><span class="lines">@@ -221,7 +226,7 @@
</span><span class="cx"> 
</span><span class="cx">     addBreakpoint: function(breakpoint, skipEventDispatch)
</span><span class="cx">     {
</span><del>-        console.assert(breakpoint);
</del><ins>+        console.assert(breakpoint instanceof WebInspector.Breakpoint, &quot;Bad argument to DebuggerManger.addBreakpoint: &quot;, breakpoint);
</ins><span class="cx">         if (!breakpoint)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="lines">@@ -260,7 +265,7 @@
</span><span class="cx"> 
</span><span class="cx">         this._breakpoints.remove(breakpoint);
</span><span class="cx"> 
</span><del>-        if (breakpoint.id)
</del><ins>+        if (breakpoint.identifier)
</ins><span class="cx">             this._removeBreakpoint(breakpoint);
</span><span class="cx"> 
</span><span class="cx">         if (breakpoint.url) {
</span><span class="lines">@@ -281,6 +286,10 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        // Disable the breakpoint first, so removing actions doesn't re-add the breakpoint.
+        breakpoint.disabled = true;
+        breakpoint.clearActions();
+
</ins><span class="cx">         this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.BreakpointRemoved, {breakpoint: breakpoint});
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="lines">@@ -431,6 +440,11 @@
</span><span class="cx">         return this.isBreakpointRemovable(breakpoint);
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    get nextBreakpointActionIdentifier()
+    {
+        return this._nextBreakpointActionIdentifier++;
+    },
+
</ins><span class="cx">     // Private
</span><span class="cx"> 
</span><span class="cx">     _sourceCodeLocationFromPayload: function(payload)
</span><span class="lines">@@ -487,6 +501,8 @@
</span><span class="cx">             return DebuggerAgent.BreakpointActionType.Evaluate;
</span><span class="cx">         case WebInspector.BreakpointAction.Type.Sound:
</span><span class="cx">             return DebuggerAgent.BreakpointActionType.Sound;
</span><ins>+        case WebInspector.BreakpointAction.Type.Probe:
+            return DebuggerAgent.BreakpointActionType.Probe;
</ins><span class="cx">         default:
</span><span class="cx">             console.assert(false);
</span><span class="cx">             return DebuggerAgent.BreakpointActionType.Log;
</span><span class="lines">@@ -495,10 +511,10 @@
</span><span class="cx"> 
</span><span class="cx">     _setBreakpoint: function(breakpoint, callback)
</span><span class="cx">     {
</span><del>-        console.assert(!breakpoint.id);
</del><ins>+        console.assert(!breakpoint.identifier);
</ins><span class="cx">         console.assert(!breakpoint.disabled);
</span><span class="cx"> 
</span><del>-        if (breakpoint.id || breakpoint.disabled)
</del><ins>+        if (breakpoint.identifier || breakpoint.disabled)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         function didSetBreakpoint(error, breakpointIdentifier)
</span><span class="lines">@@ -508,7 +524,7 @@
</span><span class="cx"> 
</span><span class="cx">             this._breakpointIdMap[breakpointIdentifier] = breakpoint;
</span><span class="cx"> 
</span><del>-            breakpoint.id = breakpointIdentifier;
</del><ins>+            breakpoint.identifier = breakpointIdentifier;
</ins><span class="cx">             breakpoint.resolved = true;
</span><span class="cx"> 
</span><span class="cx">             if (typeof callback === &quot;function&quot;)
</span><span class="lines">@@ -552,9 +568,7 @@
</span><span class="cx"> 
</span><span class="cx">     _removeBreakpoint: function(breakpoint, callback)
</span><span class="cx">     {
</span><del>-        console.assert(breakpoint.id);
-
-        if (!breakpoint.id)
</del><ins>+        if (!breakpoint.identifier)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         function didRemoveBreakpoint(error)
</span><span class="lines">@@ -562,9 +576,9 @@
</span><span class="cx">             if (error)
</span><span class="cx">                 console.error(error);
</span><span class="cx"> 
</span><del>-            delete this._breakpointIdMap[breakpoint.id];
</del><ins>+            delete this._breakpointIdMap[breakpoint.identifier];
</ins><span class="cx"> 
</span><del>-            breakpoint.id = null;
</del><ins>+            breakpoint.identifier = null;
</ins><span class="cx"> 
</span><span class="cx">             // Don't reset resolved here since we want to keep disabled breakpoints looking like they
</span><span class="cx">             // are resolved in the user interface. They will get marked as unresolved in reset.
</span><span class="lines">@@ -573,7 +587,7 @@
</span><span class="cx">                 callback();
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        DebuggerAgent.removeBreakpoint(breakpoint.id, didRemoveBreakpoint.bind(this));
</del><ins>+        DebuggerAgent.removeBreakpoint(breakpoint.identifier, didRemoveBreakpoint.bind(this));
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _breakpointDisplayLocationDidChange: function(event)
</span><span class="lines">@@ -582,7 +596,7 @@
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         var breakpoint = event.target;
</span><del>-        if (!breakpoint.id || breakpoint.disabled)
</del><ins>+        if (!breakpoint.identifier || breakpoint.disabled)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         // Remove the breakpoint with its old id.
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceDebuggerObserverjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/DebuggerObserver.js (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/DebuggerObserver.js        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/WebInspectorUI/UserInterface/DebuggerObserver.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -67,6 +67,11 @@
</span><span class="cx">     {
</span><span class="cx">         WebInspector.debuggerManager.playBreakpointActionSound(breakpointActionIdentifier);
</span><span class="cx">     },
</span><ins>+
+    didSampleProbe: function(sample)
+    {
+        WebInspector.probeManager.didSampleProbe(sample);
+    }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WebInspector.DebuggerObserver.prototype.__proto__ = WebInspector.Object.prototype;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceInspectorJSBackendCommandsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/InspectorJSBackendCommands.js (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/InspectorJSBackendCommands.js        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/WebInspectorUI/UserInterface/InspectorJSBackendCommands.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -21,8 +21,8 @@
</span><span class="cx"> InspectorBackend.registerCommand(&quot;Debugger.enable&quot;, [], []);
</span><span class="cx"> InspectorBackend.registerCommand(&quot;Debugger.disable&quot;, [], []);
</span><span class="cx"> InspectorBackend.registerCommand(&quot;Debugger.setBreakpointsActive&quot;, [{&quot;name&quot;: &quot;active&quot;, &quot;type&quot;: &quot;boolean&quot;, &quot;optional&quot;: false}], []);
</span><del>-InspectorBackend.registerCommand(&quot;Debugger.setBreakpointByUrl&quot;, [{&quot;name&quot;: &quot;lineNumber&quot;, &quot;type&quot;: &quot;number&quot;, &quot;optional&quot;: false}, {&quot;name&quot;: &quot;url&quot;, &quot;type&quot;: &quot;string&quot;, &quot;optional&quot;: true}, {&quot;name&quot;: &quot;urlRegex&quot;, &quot;type&quot;: &quot;string&quot;, &quot;optional&quot;: true}, {&quot;name&quot;: &quot;columnNumber&quot;, &quot;type&quot;: &quot;number&quot;, &quot;optional&quot;: true}, {&quot;name&quot;: &quot;options&quot;, &quot;type&quot;: &quot;object&quot;, &quot;optional&quot;: true}], [&quot;breakpointId&quot;, &quot;locations&quot;, &quot;breakpointActionIdentifiers&quot;]);
-InspectorBackend.registerCommand(&quot;Debugger.setBreakpoint&quot;, [{&quot;name&quot;: &quot;location&quot;, &quot;type&quot;: &quot;object&quot;, &quot;optional&quot;: false}, {&quot;name&quot;: &quot;options&quot;, &quot;type&quot;: &quot;object&quot;, &quot;optional&quot;: true}], [&quot;breakpointId&quot;, &quot;actualLocation&quot;, &quot;breakpointActionIdentifiers&quot;]);
</del><ins>+InspectorBackend.registerCommand(&quot;Debugger.setBreakpointByUrl&quot;, [{&quot;name&quot;: &quot;lineNumber&quot;, &quot;type&quot;: &quot;number&quot;, &quot;optional&quot;: false}, {&quot;name&quot;: &quot;url&quot;, &quot;type&quot;: &quot;string&quot;, &quot;optional&quot;: true}, {&quot;name&quot;: &quot;urlRegex&quot;, &quot;type&quot;: &quot;string&quot;, &quot;optional&quot;: true}, {&quot;name&quot;: &quot;columnNumber&quot;, &quot;type&quot;: &quot;number&quot;, &quot;optional&quot;: true}, {&quot;name&quot;: &quot;options&quot;, &quot;type&quot;: &quot;object&quot;, &quot;optional&quot;: true}], [&quot;breakpointId&quot;, &quot;locations&quot;]);
+InspectorBackend.registerCommand(&quot;Debugger.setBreakpoint&quot;, [{&quot;name&quot;: &quot;location&quot;, &quot;type&quot;: &quot;object&quot;, &quot;optional&quot;: false}, {&quot;name&quot;: &quot;options&quot;, &quot;type&quot;: &quot;object&quot;, &quot;optional&quot;: true}], [&quot;breakpointId&quot;, &quot;actualLocation&quot;]);
</ins><span class="cx"> InspectorBackend.registerCommand(&quot;Debugger.removeBreakpoint&quot;, [{&quot;name&quot;: &quot;breakpointId&quot;, &quot;type&quot;: &quot;string&quot;, &quot;optional&quot;: false}], []);
</span><span class="cx"> InspectorBackend.registerCommand(&quot;Debugger.continueToLocation&quot;, [{&quot;name&quot;: &quot;location&quot;, &quot;type&quot;: &quot;object&quot;, &quot;optional&quot;: false}], []);
</span><span class="cx"> InspectorBackend.registerCommand(&quot;Debugger.stepOver&quot;, [], []);
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceMainhtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Main.html        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -390,6 +390,11 @@
</span><span class="cx">     &lt;script src=&quot;BreakpointActionView.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Breakpoint.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;DebuggerManager.js&quot;&gt;&lt;/script&gt;
</span><ins>+    &lt;script src=&quot;ProbeManager.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;Probe.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;ProbeSet.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;ProbeSetDataFrame.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;ProbeSetDataTable.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx">     &lt;script src=&quot;SourceMapManager.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Script.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;SourceMap.js&quot;&gt;&lt;/script&gt;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceMainjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Main.js (163476 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Main.js        2014-02-05 21:54:49 UTC (rev 163476)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -114,6 +114,7 @@
</span><span class="cx">     this.sourceMapManager = new WebInspector.SourceMapManager;
</span><span class="cx">     this.layerTreeManager = new WebInspector.LayerTreeManager;
</span><span class="cx">     this.dashboardManager = new WebInspector.DashboardManager;
</span><ins>+    this.probeManager = new WebInspector.ProbeManager;
</ins><span class="cx"> 
</span><span class="cx">     // Enable the Console Agent after creating the singleton managers.
</span><span class="cx">     if (window.ConsoleAgent)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProbejs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Probe.js (0 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Probe.js                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Probe.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -0,0 +1,105 @@
</span><ins>+/*
+ * Copyright (C) 2013 University of Washington. All rights reserved.
+ * Copyright (C) 2014 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS
+ * IS&quot; 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 THE COPYRIGHT
+ * HOLDER OR 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.
+ */
+
+WebInspector.ProbeSample = function(sampleId, batchId, timestamp, payload)
+{
+    this.sampleId = sampleId;
+    this.batchId = batchId;
+    this.timestamp = timestamp;
+    this.object = WebInspector.RemoteObject.fromPayload(payload);
+};
+
+WebInspector.Probe = function(id, breakpoint, expression)
+{
+    WebInspector.Object.call(this);
+
+    console.assert(id);
+    console.assert(breakpoint instanceof WebInspector.Breakpoint);
+
+    this._id = id;
+    this._breakpoint = breakpoint;
+    this._expression = expression;
+    this._samples = [];
+};
+
+WebInspector.Object.addConstructorFunctions(WebInspector.Probe);
+
+WebInspector.Probe.Event = {
+    ExpressionChanged: &quot;probe-object-expression-changed&quot;,
+    SampleAdded: &quot;probe-object-sample-added&quot;,
+    SamplesCleared: &quot;probe-object-samples-cleared&quot;
+};
+
+WebInspector.Probe.prototype = {
+    constructor: WebInspector.Probe,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+    get id()
+    {
+        return this._id;
+    },
+
+    get breakpoint()
+    {
+        return this._breakpoint;
+    },
+
+    get expression()
+    {
+        return this._expression;
+    },
+
+    set expression(value)
+    {
+        if (this._expression === value)
+            return;
+
+        var data = {oldValue: this._expression, newValue: value};
+        this._expression = value;
+        this.clearSamples();
+        this.dispatchEventToListeners(WebInspector.Probe.Event.ExpressionChanged, data);
+    },
+
+    get samples()
+    {
+        return this._samples.slice();
+    },
+
+    clearSamples: function()
+    {
+        this._samples = [];
+        this.dispatchEventToListeners(WebInspector.Probe.Event.SamplesCleared);
+    },
+
+    addSample: function(sample)
+    {
+        console.assert(sample instanceof WebInspector.ProbeSample, &quot;Wrong object type passed as probe sample: &quot;, sample);
+        this._samples.push(sample);
+        this.dispatchEventToListeners(WebInspector.Probe.Event.SampleAdded, sample);
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProbeManagerjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/ProbeManager.js (0 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/ProbeManager.js                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/ProbeManager.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -0,0 +1,181 @@
</span><ins>+/*
+ * Copyright (C) 2013 University of Washington. All rights reserved.
+ * Copyright (C) 2014 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS
+ * IS&quot; 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 THE COPYRIGHT
+ * HOLDER OR 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.
+ */
+
+WebInspector.ProbeManager = function()
+{
+    WebInspector.Object.call(this);
+
+    // Used to detect deleted probe actions.
+    this._knownProbeIdentifiersForBreakpoint = new Map;
+
+    // Main lookup tables for probes and probe sets.
+    this._probesByIdentifier = new Map;
+    this._probeSetsByBreakpoint = new Map;
+
+    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointAdded, this._breakpointAdded, this);
+    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointRemoved, this._breakpointRemoved, this);
+    WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.ActionsDidChange, this._breakpointActionsChanged, this);
+
+    // Saved breakpoints should not be restored on the first event loop turn, because it
+    // makes manager initialization order very fragile. No breakpoints should be available.
+    console.assert(!WebInspector.debuggerManager.breakpoints.length, &quot;No breakpoints should exist before all the managers are constructed.&quot;);
+}
+
+WebInspector.ProbeManager.Event = {
+    ProbeSetAdded: &quot;probe-manager-probe-set-added&quot;,
+    ProbeSetRemoved: &quot;probe-manager-probe-set-removed&quot;,
+};
+
+WebInspector.ProbeManager.prototype = {
+    constructor: WebInspector.ProbeManager,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+    get probeSets()
+    {
+        var sets = [];
+        for (var set of this._probeSetsByBreakpoint.values())
+            sets.push(set);
+
+        return sets;
+    },
+
+    probeSetForBreakpoint: function(breakpoint)
+    {
+        return this._probeSetsByBreakpoint.get(breakpoint);
+    },
+
+    // Protected (called by WebInspector.DebuggerObserver)
+
+    didSampleProbe: function(sample)
+    {
+        console.assert(this._probesByIdentifier.has(sample.probeId), &quot;Unknown probe identifier specified for sample: &quot;, sample);
+        var probe = this._probesByIdentifier.get(sample.probeId);
+        probe.addSample(new WebInspector.ProbeSample(sample.sampleId, sample.batchId, sample.timestamp, sample.payload));
+    },
+
+    // Private
+
+    _breakpointAdded: function(breakpointOrEvent)
+    {
+        var breakpoint;
+        if (breakpointOrEvent instanceof WebInspector.Breakpoint)
+            breakpoint = breakpointOrEvent;
+        else
+            breakpoint = breakpointOrEvent.data.breakpoint;
+
+        console.assert(breakpoint instanceof WebInspector.Breakpoint, &quot;Unknown object passed as breakpoint: &quot;, breakpoint);
+
+        if (this._knownProbeIdentifiersForBreakpoint.has(breakpoint))
+            return;
+
+        this._knownProbeIdentifiersForBreakpoint.set(breakpoint, new Set);
+
+        this._breakpointActionsChanged(breakpoint);
+    },
+
+    _breakpointRemoved: function(event)
+    {
+        var breakpoint = event.data.breakpoint;
+        console.assert(this._knownProbeIdentifiersForBreakpoint.has(breakpoint));
+
+        this._breakpointActionsChanged(breakpoint);
+        this._knownProbeIdentifiersForBreakpoint.delete(breakpoint);
+    },
+
+    _breakpointActionsChanged: function(breakpointOrEvent)
+    {
+        var breakpoint;
+        if (breakpointOrEvent instanceof WebInspector.Breakpoint)
+            breakpoint = breakpointOrEvent;
+        else
+            breakpoint = breakpointOrEvent.target;
+
+        console.assert(breakpoint instanceof WebInspector.Breakpoint, &quot;Unknown object passed as breakpoint: &quot;, breakpoint);
+
+        // Sometimes actions change before the added breakpoint is fully dispatched.
+        if (!this._knownProbeIdentifiersForBreakpoint.has(breakpoint)) {
+            this._breakpointAdded(breakpoint);
+            return;
+        }
+
+        var knownProbeIdentifiers = this._knownProbeIdentifiersForBreakpoint.get(breakpoint);
+        var seenProbeIdentifiers = new Set;
+
+        breakpoint.probeActions.forEach(function(probeAction) {
+            var probeIdentifier = probeAction.id;
+            console.assert(probeIdentifier, &quot;Probe added without breakpoint action identifier: &quot;, breakpoint);
+
+            seenProbeIdentifiers.add(probeIdentifier);
+            if (!knownProbeIdentifiers.has(probeIdentifier)) {
+                // New probe; find or create relevant probe set.
+                knownProbeIdentifiers.add(probeIdentifier);
+                var probeSet = this._probeSetForBreakpoint(breakpoint);
+                var newProbe = new WebInspector.Probe(probeIdentifier, breakpoint, probeAction.data);
+                this._probesByIdentifier.set(probeIdentifier, newProbe);
+                probeSet.addProbe(newProbe);
+                return;
+            }
+
+            var probe = this._probesByIdentifier.get(probeIdentifier);
+            console.assert(probe, &quot;Probe known but couldn't be found by identifier: &quot;, probeIdentifier);
+            // Update probe expression; if it differed, change events will fire.
+            probe.expression = probeAction.data;
+        }, this);
+
+        // Look for missing probes based on what we saw last.
+        knownProbeIdentifiers.forEach(function(probeIdentifier) {
+            if (seenProbeIdentifiers.has(probeIdentifier))
+                return;
+
+            // The probe has gone missing, remove it.
+            var probeSet = this._probeSetForBreakpoint(breakpoint);
+            var probe = this._probesByIdentifier.get(probeIdentifier);
+            this._probesByIdentifier.delete(probeIdentifier);
+            knownProbeIdentifiers.delete(probeIdentifier);
+            probeSet.removeProbe(probe);
+
+            // Remove the probe set if it has become empty.
+            if (!probeSet.probes.length) {
+                this._probeSetsByBreakpoint.delete(probeSet.breakpoint);
+                probeSet.willRemove();
+                this.dispatchEventToListeners(WebInspector.ProbeManager.Event.ProbeSetRemoved, probeSet);
+            }
+        }, this);
+    },
+
+    _probeSetForBreakpoint: function(breakpoint)
+    {
+        if (this._probeSetsByBreakpoint.has(breakpoint))
+            return this._probeSetsByBreakpoint.get(breakpoint);
+
+        var newProbeSet = new WebInspector.ProbeSet(breakpoint);
+        this._probeSetsByBreakpoint.set(breakpoint, newProbeSet);
+        this.dispatchEventToListeners(WebInspector.ProbeManager.Event.ProbeSetAdded, newProbeSet);
+        return newProbeSet;
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProbeSetjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/ProbeSet.js (0 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/ProbeSet.js                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/ProbeSet.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -0,0 +1,161 @@
</span><ins>+/*
+ * Copyright (C) 2013 University of Washington. All rights reserved.
+ * Copyright (C) 2014 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS
+ * IS&quot; 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 THE COPYRIGHT
+ * HOLDER OR 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.
+ */
+
+// A ProbeSet clusters Probes from the same Breakpoint and their samples.
+
+WebInspector.ProbeSet = function(breakpoint)
+{
+    console.assert(breakpoint instanceof WebInspector.Breakpoint, &quot;Unknown breakpoint argument: &quot;, breakpoint);
+
+    WebInspector.Object.call(this);
+    this._breakpoint = breakpoint;
+    this._probes = [];
+    this._probesByIdentifier = new Map;
+
+    this._createDataTable();
+
+    WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceChanged, this);
+    WebInspector.Probe.addEventListener(WebInspector.Probe.Event.SampleAdded, this._sampleCollected, this);
+    WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.ResolvedStateDidChange, this._breakpointResolvedStateDidChange, this);
+}
+
+WebInspector.Object.addConstructorFunctions(WebInspector.ProbeSet);
+
+WebInspector.ProbeSet.Event = {
+    ProbeAdded: &quot;probe-set-probe-added&quot;,
+    ProbeRemoved: &quot;probe-set-probe-removed&quot;,
+    ResolvedStateDidChange: &quot;probe-set-resolved-state-did-change&quot;,
+    SamplesCleared: &quot;probe-set-samples-cleared&quot;,
+};
+
+WebInspector.ProbeSet.SampleObjectTitle = &quot;Object&quot;;
+
+WebInspector.ProbeSet.prototype = {
+    constructor: WebInspector.ProbeSet,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+   get breakpoint()
+   {
+        return this._breakpoint;
+   },
+
+    get probes()
+    {
+        return this._probes.slice();
+    },
+
+    get dataTable()
+    {
+        return this._dataTable;
+    },
+
+    clear: function()
+    {
+        this._breakpoint.clearActions(WebInspector.BreakpointAction.Type.Probe);
+    },
+
+    clearSamples: function()
+    {
+        for (var probe of this._probes)
+            probe.clearSamples();
+
+        this._createDataTable();
+        this.dispatchEventToListeners(WebInspector.ProbeSet.Event.SamplesCleared, this);
+    },
+
+    createProbe: function(expression)
+    {
+        this.breakpoint.createAction(WebInspector.BreakpointAction.Type.Probe, null, expression);
+    },
+
+    addProbe: function(probe)
+    {
+        console.assert(probe instanceof WebInspector.Probe, &quot;Tried to add non-probe &quot;, probe, &quot; to probe group&quot;, this);
+        console.assert(probe.breakpoint === this.breakpoint, &quot;Probe and ProbeSet must have same breakpoint.&quot;, probe, this);
+
+        this._probes.push(probe);
+        this._probesByIdentifier.set(probe.identifier, probe);
+
+        this.dataTable.addProbe(probe);
+        this.dispatchEventToListeners(WebInspector.ProbeSet.Event.ProbeAdded, probe);
+    },
+
+    removeProbe: function(probe)
+    {
+        console.assert(probe instanceof WebInspector.Probe, &quot;Tried to remove non-probe &quot;, probe, &quot; to probe group&quot;, this);
+        console.assert(this._probes.indexOf(probe) != -1, &quot;Tried to remove probe&quot;, probe, &quot; not in group &quot;, this);
+        console.assert(this._probesByIdentifier.has(probe.identifier), &quot;Tried to remove probe&quot;, probe, &quot; not in group &quot;, this);
+
+        this._probes.splice(this._probes.indexOf(probe), 1);
+        this._probesByIdentifier.delete(probe.identifier);
+        this.dataTable.removeProbe(probe);
+        this.dispatchEventToListeners(WebInspector.ProbeSet.Event.ProbeRemoved, probe);
+    },
+
+    willRemove: function()
+    {
+        console.assert(!this._probes.length, &quot;ProbeSet.willRemove called, but probes still associated with group: &quot;, this._probes);
+
+        WebInspector.Frame.removeEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceChanged, this);
+        WebInspector.Probe.removeEventListener(WebInspector.Probe.Event.SampleAdded, this._sampleCollected, this);
+        WebInspector.Breakpoint.removeEventListener(WebInspector.Breakpoint.Event.ResolvedStateDidChange, this._breakpointResolvedStateDidChange, this);
+    },
+
+    // Private
+
+    _mainResourceChanged: function()
+    {
+        this.dataTable.mainResourceChanged();
+    },
+
+    _createDataTable: function()
+    {
+        if (this.dataTable)
+            this.dataTable.willRemove();
+
+        this._dataTable = new WebInspector.ProbeSetDataTable(this);
+    },
+
+    _sampleCollected: function(event)
+    {
+        var sample = event.data;
+        console.assert(sample instanceof WebInspector.ProbeSample, &quot;Tried to add non-sample to probe group: &quot;, sample);
+
+        var probe = event.target;
+        if (!this._probesByIdentifier.has(probe.identifier))
+            return;
+
+        console.assert(this.dataTable);
+        this.dataTable.addSampleForProbe(probe, sample);
+    },
+
+    _breakpointResolvedStateDidChange: function(event)
+    {
+        this.dispatchEventToListeners(WebInspector.ProbeSet.Event.ResolvedStateDidChange);
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProbeSetDataFramejs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/ProbeSetDataFrame.js (0 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/ProbeSetDataFrame.js                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/ProbeSetDataFrame.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -0,0 +1,97 @@
</span><ins>+/*
+ * Copyright (C) 2013 University of Washington. All rights reserved.
+ * Copyright (C) 2014 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS
+ * IS&quot; 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 THE COPYRIGHT
+ * HOLDER OR 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.
+ */
+
+WebInspector.ProbeSetDataFrame = function(index)
+{
+    this._count = 0;
+    this._index = index;
+    this._separator = false;
+};
+
+WebInspector.ProbeSetDataFrame.compare = function(a, b) {
+    console.assert(a instanceof WebInspector.ProbeSetDataFrame, a);
+    console.assert(b instanceof WebInspector.ProbeSetDataFrame, b);
+
+    return a.index - b.index;
+}
+
+WebInspector.ProbeSetDataFrame.MissingValue = &quot;?&quot;;
+
+WebInspector.ProbeSetDataFrame.prototype = {
+    constructor: WebInspector.ProbeSetDataFrame,
+
+    // Public
+
+    get key()
+    {
+        return String(this._index);
+    },
+
+    get count()
+    {
+        return this._count;
+    },
+
+    get index()
+    {
+        return this._index;
+    },
+
+    get isSeparator()
+    {
+        return this._separator;
+    },
+
+    // The last data frame before a main frame navigation is marked as a &quot;separator&quot; frame.
+    set isSeparator(value)
+    {
+        this._separator = !!value;
+    },
+
+    addSampleForProbe: function(probe, sample)
+    {
+        this[probe.id] = sample;
+        this._count++;
+    },
+
+    missingKeys: function(probeSet)
+    {
+        return probeSet.probes.filter(function(probe) {
+            return !this.hasOwnProperty(probe.id);
+        }, this);
+    },
+
+    isComplete: function(probeSet)
+    {
+        return !this.missingKeys(probeSet).length;
+    },
+
+    fillMissingValues: function(probeSet)
+    {
+        for (var key of this.missingKeys(probeSet))
+            this[key] = WebInspector.ProbeSetDataFrame.MissingValue;
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProbeSetDataTablejs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/ProbeSetDataTable.js (0 => 163477)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/ProbeSetDataTable.js                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/ProbeSetDataTable.js        2014-02-05 22:21:40 UTC (rev 163477)
</span><span class="lines">@@ -0,0 +1,134 @@
</span><ins>+/*
+ * Copyright (C) 2013 University of Washington. All rights reserved.
+ * Copyright (C) 2014 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS
+ * IS&quot; 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 THE COPYRIGHT
+ * HOLDER OR 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.
+ */
+
+WebInspector.ProbeSetDataTable = function(probeSet)
+{
+    WebInspector.Object.call(this);
+
+    this._probeSet = probeSet;
+    this._frames = [];
+    this._previousBatchIdentifier = WebInspector.ProbeSetDataTable.SentinelValue;
+};
+
+WebInspector.ProbeSetDataTable.Event = {
+    FrameInserted: &quot;probe-set-data-table-frame-inserted&quot;,
+    SeparatorInserted: &quot;probe-set-data-table-separator-inserted&quot;,
+    WillRemove: &quot;probe-set-data-table-will-remove&quot;
+};
+
+WebInspector.ProbeSetDataTable.SentinelValue = -1;
+WebInspector.ProbeSetDataTable.UnknownValue = &quot;?&quot;;
+
+WebInspector.ProbeSetDataTable.prototype = {
+    constructor: WebInspector.ProbeSetDataTable,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+    get frames()
+    {
+        return this._frames.slice();
+    },
+
+    get separators()
+    {
+        return this._frames.filter(function(frame) { return frame.isSeparator; });
+    },
+
+    willRemove: function()
+    {
+        this.dispatchEventToListeners(WebInspector.ProbeSetDataTable.Event.WillRemove);
+        this._frames = [];
+        delete this._probeSet;
+    },
+
+    mainResourceChanged: function()
+    {
+        this.addSeparator();
+    },
+
+    addSampleForProbe: function(probe, sample)
+    {
+        // Eagerly save the frame if the batch identifier differs, or we know the frame is full.
+        // Create a new frame when the batch identifier differs.
+        if (sample.batchId != this._previousBatchIdentifier) {
+            if (this._openFrame) {
+                this._openFrame.fillMissingValues(this._probeSet);
+                this.addFrame(this._openFrame);
+            }
+            this._openFrame = this.createFrame();
+            this._previousBatchIdentifier = sample.batchId;
+        }
+
+        console.assert(this._openFrame, &quot;Should always have an open frame before adding sample.&quot;, this, probe, sample);
+        this._openFrame.addSampleForProbe(probe, sample);
+        if (this._openFrame.count == this._probeSet.probes.length) {
+            this.addFrame(this._openFrame);
+            this._openFrame = null;
+        }
+    },
+
+    addProbe: function(probe)
+    {
+        for (var frame of this.frames)
+            if (!frame[probe.id])
+                frame[probe.id] = WebInspector.ProbeSetDataTable.UnknownValue;
+    },
+
+    removeProbe: function(probe)
+    {
+        for (var frame of this.frames)
+            delete frames[i][probe.id];
+    },
+
+    // Protected - can be overridden by subclasses.
+
+    createFrame: function()
+    {
+        return new WebInspector.ProbeSetDataFrame(this._frames.length);
+    },
+
+    addFrame: function(frame)
+    {
+        this._frames.push(frame);
+        this.dispatchEventToListeners(WebInspector.ProbeSetDataTable.Event.FrameInserted, frame);
+    },
+
+    addSeparator: function()
+    {
+        // Separators must be associated with a frame.
+        if (!this._frames.length)
+            return;
+
+        var previousFrame = this._frames.lastValue;
+        // Don't send out duplicate events for adjacent separators.
+        if (previousFrame.isSeparator)
+            return;
+
+        previousFrame.isSeparator = true;
+        this.dispatchEventToListeners(WebInspector.ProbeSetDataTable.Event.SeparatorInserted, previousFrame);
+    }
+};
</ins></span></pre>
</div>
</div>

</body>
</html>