Web Inspector: Include DebuggerAgent in Workers - see, pause, and step through scripts
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Nov 2016 21:51:36 +0000 (21:51 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Nov 2016 21:51:36 +0000 (21:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=164136
<rdar://problem/29028462>

Reviewed by Brian Burg.
Source/WebCore:

Tests: inspector/worker/debugger-pause.html
       inspector/worker/debugger-scripts.html

* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:
* inspector/InspectorAllInOne.cpp:
New file.

* inspector/PageDebuggerAgent.h:
* inspector/WorkerDebuggerAgent.cpp: Added.
(WebCore::WorkerDebuggerAgent::WorkerDebuggerAgent):
(WebCore::WorkerDebuggerAgent::~WorkerDebuggerAgent):
(WebCore::WorkerDebuggerAgent::breakpointActionLog):
(WebCore::WorkerDebuggerAgent::injectedScriptForEval):
* inspector/WorkerDebuggerAgent.h: Added.
DebuggerAgent customizations for Workers.

* inspector/WorkerInspectorController.cpp:
(WebCore::WorkerInspectorController::WorkerInspectorController):
Add the new agent.

* inspector/WorkerScriptDebugServer.cpp:
(WebCore::WorkerScriptDebugServer::runEventLoopWhilePaused):
Implement the nested run loop for Workers.

Source/WebInspectorUI:

By implementing DebuggerAgent, Workers will inform the frontend about
Scripts that evaluate in the Worker's VM and the Worker VM can pause
and send the pausing CallFrames to the frontend. This means that
WebInspector.Script and WebInspector.CallFrame will need to be made
target aware. This also means that each Target will have its own
set of debugger data, such as the list of scripts and pause data
like the pause reason / call frames. Previously all this data was
managed by DebuggerManager.

With this change we split that data out of DebuggerManager to be
per-target DebuggerData. DebuggerManager keeps `activeCallFrame`
but the list of scripts and pause data have moved into `DebuggerData`
which is per-target, accessed through DebuggerManager's new
dataForTarget(target) method.

Finally we make a few changes to the UserInterface to make Workers
and their scripts, appear grouped together. The Resources sidebar
previously had a single top level item for the Main Frame, which
has all its resources as its children (potentially grouped into
folders). With this change, each Worker gets its own top level
item as well, and the Worker's subresources (imported scripts)
become its children.

We also now associate a single mainResource with Targets. In the
case of Workers, we assume and assert that this is a Script. If
this were to ever change we would need to adjust the assumptions.

* UserInterface/Main.html:
* UserInterface/Test.html:
New files.

* UserInterface/Base/Main.js:
* UserInterface/Test/Test.js:
Add WebInspector.assumingMainTarget to fill in all the places where
we assume the main target right now, but would need to handle non-main
targets as other agents are implemented in workers. For example profile
data that assumes the main target right now could be worker targets
when we implement ScriptProfiler / Heap agents.

* UserInterface/Protocol/Connection.js:
(InspectorBackend.WorkerConnection):
* UserInterface/Protocol/Target.js:
(WebInspector.Target):
(WebInspector.Target.prototype.get DebuggerAgent):
(WebInspector.Target.prototype.get mainResource):
(WebInspector.Target.prototype.set mainResource):
(WebInspector.WorkerTarget.prototype.initialize):
(WebInspector.WorkerTarget):
Include DebuggerAgent in Targets.
Include a mainResource for Worker Targets.

* UserInterface/Protocol/DebuggerObserver.js:
(WebInspector.DebuggerObserver.prototype.scriptParsed):
(WebInspector.DebuggerObserver.prototype.breakpointResolved):
(WebInspector.DebuggerObserver.prototype.paused):
(WebInspector.DebuggerObserver.prototype.resumed):
Pass the target on to managers when necessary.

* UserInterface/Models/DebuggerData.js: Added.
(WebInspector.DebuggerData):
(WebInspector.DebuggerData.prototype.get target):
(WebInspector.DebuggerData.prototype.get callFrames):
(WebInspector.DebuggerData.prototype.get pauseReason):
(WebInspector.DebuggerData.prototype.get pauseData):
(WebInspector.DebuggerData.prototype.get scripts):
(WebInspector.DebuggerData.prototype.scriptForIdentifier):
(WebInspector.DebuggerData.prototype.scriptsForURL):
(WebInspector.DebuggerData.prototype.reset):
(WebInspector.DebuggerData.prototype.addScript):
(WebInspector.DebuggerData.prototype.pause):
(WebInspector.DebuggerData.prototype.unpause):
Extract per-target data from DebuggerManager. This includes the list
of scripts evaluated in a Target, and any pause data for this target
such as the pause reason and call frames.

* UserInterface/Controllers/DebuggerManager.js:
(WebInspector.DebuggerManager.prototype.dataForTarget):
(WebInspector.DebuggerManager.prototype.get pauseReason): Deleted.
(WebInspector.DebuggerManager.prototype.get pauseData): Deleted.
(WebInspector.DebuggerManager.prototype.get callFrames): Deleted.
(WebInspector.DebuggerManager.prototype.reset):
New way to access per-target debugger data.

(WebInspector.DebuggerManager.prototype.initializeTarget):
When a new Target is created, synchronize frontend state with the target.
Things like the list of breakpoints and global breakpoint states.

(WebInspector.DebuggerManager.prototype.scriptForIdentifier):
(WebInspector.DebuggerManager.prototype.scriptsForURL):
Convenience accessors for scripts must now provide a Target.

(WebInspector.DebuggerManager.prototype.get knownNonResourceScripts):
This is a convenience accessors for a list of all scripts across all targets
so this handles getting the list across all targets.

(WebInspector.DebuggerManager.prototype.pause):
(WebInspector.DebuggerManager.prototype.resume):
(WebInspector.DebuggerManager.prototype.stepOver):
(WebInspector.DebuggerManager.prototype.stepInto):
(WebInspector.DebuggerManager.prototype.stepOut):
(WebInspector.DebuggerManager.prototype.continueToLocation):
Stepping commands affect the current target with the active call frame.
Eventually we will change Pause and Resume behavior to affect all targets.

(WebInspector.DebuggerManager.prototype.addBreakpoint):
(WebInspector.DebuggerManager.prototype.breakpointResolved):
(WebInspector.DebuggerManager.prototype._setBreakpoint.didSetBreakpoint):
(WebInspector.DebuggerManager.prototype._setBreakpoint):
(WebInspector.DebuggerManager.prototype._removeBreakpoint):
Breakpoints should be set on all targets, but we need a way
to set them on a specific target, when initializing an
individual target when we want to inform that single target
of all of the breakpoints.

(WebInspector.DebuggerManager.prototype._breakpointDisabledStateDidChange):
(WebInspector.DebuggerManager.prototype._updateBreakOnExceptionsState):
Changing global breakpoint state should inform all targets.

(WebInspector.DebuggerManager.prototype.scriptDidParse):
Associate Scripts with a Target. Identify the main resource of a
Worker Target and set it as soon as we can.

(WebInspector.DebuggerManager.prototype.debuggerDidPause):
(WebInspector.DebuggerManager.prototype.debuggerDidResume):
(WebInspector.DebuggerManager.prototype._sourceCodeLocationFromPayload):
(WebInspector.DebuggerManager.prototype._scopeChainFromPayload):
(WebInspector.DebuggerManager.prototype._scopeChainNodeFromPayload):
(WebInspector.DebuggerManager.prototype._mainResourceDidChange):
(WebInspector.DebuggerManager.prototype._didResumeInternal):
Pausing and resuming now happens per-target, so associate
created model objects (CallFrame, ScopeChain objects) and any
other necessary data with the target.

* UserInterface/Models/Breakpoint.js:
(WebInspector.Breakpoint):
(WebInspector.Breakpoint.prototype.get target):
(WebInspector.Breakpoint.prototype.get info):
* UserInterface/Models/CallFrame.js:
(WebInspector.CallFrame):
(WebInspector.CallFrame.prototype.get target):
(WebInspector.CallFrame.fromDebuggerPayload):
(WebInspector.CallFrame.fromPayload):
* UserInterface/Models/ConsoleMessage.js:
(WebInspector.ConsoleMessage):
* UserInterface/Models/Script.js:
(WebInspector.Script):
(WebInspector.Script.prototype.get target):
(WebInspector.Script.prototype.isMainResource):
(WebInspector.Script.prototype.requestContentFromBackend):
(WebInspector.Script.prototype._resolveResource):
* UserInterface/Models/StackTrace.js:
(WebInspector.StackTrace.fromPayload):
(WebInspector.StackTrace.fromString):
* UserInterface/Models/ProbeManager.js:
(WebInspector.ProbeManager.prototype.didSampleProbe):
* UserInterface/Models/Probe.js:
(WebInspector.ProbeSample):
* UserInterface/Views/ConsoleMessageView.js:
(WebInspector.ConsoleMessageView.prototype._appendLocationLink):
(WebInspector.ConsoleMessageView.prototype._formatParameterAsString):
Associate model objects with a specific target where necessary.

* UserInterface/Views/ObjectTreeBaseTreeElement.js:
(WebInspector.ObjectTreeBaseTreeElement.prototype._appendMenusItemsForObject):
* UserInterface/Controllers/RuntimeManager.js:
(WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow):
* UserInterface/Protocol/RemoteObject.js:
(WebInspector.RemoteObject.prototype.findFunctionSourceCodeLocation):
Use target specific DebuggerAgent where necessary.

* UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js:
* UserInterface/Controllers/TimelineManager.js:
(WebInspector.TimelineManager.prototype._callFramesFromPayload):
* UserInterface/Models/ScriptTimelineRecord.js:
(WebInspector.ScriptTimelineRecord.prototype._initializeProfileFromPayload.profileNodeFromPayload):
* UserInterface/Views/EventListenerSectionGroup.js:
(WebInspector.EventListenerSectionGroup.prototype._functionTextOrLink):
(WebInspector.EventListenerSectionGroup):
* UserInterface/Views/HeapSnapshotInstanceDataGridNode.js:
(WebInspector.HeapSnapshotInstanceDataGridNode.logHeapSnapshotNode.node.shortestGCRootPath.):
(WebInspector.HeapSnapshotInstanceDataGridNode.logHeapSnapshotNode):
(WebInspector.HeapSnapshotInstanceDataGridNode.prototype._populateWindowPreview):
(WebInspector.HeapSnapshotInstanceDataGridNode.prototype._populatePreview):
(WebInspector.HeapSnapshotInstanceDataGridNode.prototype._mouseoverHandler.appendPathRow):
* UserInterface/Views/ProfileDataGridNode.js:
(WebInspector.ProfileDataGridNode.prototype.iconClassName):
(WebInspector.ProfileDataGridNode.prototype.filterableDataForColumn):
(WebInspector.ProfileDataGridNode.prototype._displayContent):
Use assumed main target and audit these when the Worker gets more Agents.

* UserInterface/Controllers/FrameResourceManager.js:
(WebInspector.FrameResourceManager.prototype._initiatorSourceCodeLocationFromPayload):
This will always be the main target because only the main target
has access to the DOM.

* UserInterface/Views/SourceCodeTextEditor.js:
(WebInspector.SourceCodeTextEditor.prototype.get target):
(WebInspector.SourceCodeTextEditor.prototype.customPerformSearch):
(WebInspector.SourceCodeTextEditor.prototype.textEditorGutterContextMenu):
(WebInspector.SourceCodeTextEditor.prototype._tokenTrackingControllerHighlightedJavaScriptExpression.populate):
(WebInspector.SourceCodeTextEditor.prototype._tokenTrackingControllerHighlightedJavaScriptExpression):
(WebInspector.SourceCodeTextEditor.prototype._showPopoverForFunction.didGetDetails):
(WebInspector.SourceCodeTextEditor.prototype._showPopoverForFunction):
Update target specific actions to use the proper target's agents.

* UserInterface/Views/TargetTreeElement.js: Added.
(WebInspector.TargetTreeElement):
(WebInspector.TargetTreeElement.prototype.get target):
(WebInspector.TargetTreeElement.prototype.onexpand):
(WebInspector.TargetTreeElement.prototype.oncollapse):
Add a new tree element for a Target. We currently assume that the
main resource for a Target will be a Script right now, as is the
case for Web Workers. This simply remembers its expanded or
collapsed state and has a better icon.

* UserInterface/Views/ResourceIcons.css:
(body:matches(.mac-platform, .windows-platform) .script.worker-icon .icon):
(body:matches(.mac-platform, .windows-platform) .large .script.worker-icon .icon):
* UserInterface/Images/WorkerScript.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocument.png.
* UserInterface/Images/WorkerScript@2x.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocument@2x.png.
* UserInterface/Images/WorkerScriptLarge.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocumentLarge.png.
* UserInterface/Images/WorkerScriptLarge@2x.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocumentLarge@2x.png.
Improve icon for a Worker's main resource script.

* UserInterface/Views/ResourceSidebarPanel.js:
(WebInspector.ResourceSidebarPanel):
(WebInspector.ResourceSidebarPanel.prototype._scriptWasAdded):
(WebInspector.ResourceSidebarPanel.prototype._scriptsCleared):
(WebInspector.ResourceSidebarPanel.prototype._addScriptForNonMainTarget):
(WebInspector.ResourceSidebarPanel.prototype._addTargetWithMainResource):
(WebInspector.ResourceSidebarPanel.prototype._targetRemoved):
* UserInterface/Views/SearchSidebarPanel.js:
(WebInspector.SearchSidebarPanel.prototype.performSearch.searchScripts):
(WebInspector.SearchSidebarPanel.prototype._searchTreeElementForScript):
* UserInterface/Views/OpenResourceDialog.js:
(WebInspector.OpenResourceDialog.prototype._populateResourceTreeOutline.createTreeElement):
(WebInspector.OpenResourceDialog.prototype._populateResourceTreeOutline):
(WebInspector.OpenResourceDialog.prototype.didDismissDialog):
(WebInspector.OpenResourceDialog.prototype.didPresentDialog):
(WebInspector.OpenResourceDialog.prototype._addResourcesForFrame):
(WebInspector.OpenResourceDialog.prototype._addScriptsForTarget):
(WebInspector.OpenResourceDialog.prototype._scriptAdded):
(WebInspector.OpenResourceDialog):
* UserInterface/Views/DebuggerSidebarPanel.js:
(WebInspector.DebuggerSidebarPanel.prototype._addTreeElementForSourceCodeToTreeOutline):
(WebInspector.DebuggerSidebarPanel.prototype._debuggerCallFramesDidChange):
(WebInspector.DebuggerSidebarPanel.prototype._debuggerActiveCallFrameDidChange):
(WebInspector.DebuggerSidebarPanel.prototype._updatePauseReasonSection):
Include scripts from non-main targets in sidebars.

LayoutTests:

* inspector/worker/debugger-pause-expected.txt: Added.
* inspector/worker/debugger-pause.html: Added.
* inspector/worker/debugger-scripts-expected.txt: Added.
* inspector/worker/debugger-scripts.html: Added.
* inspector/worker/resources/worker-debugger-pause.js: Added.
* inspector/worker/resources/worker-import-1.js: Added.
* inspector/worker/resources/worker-scripts.js: Added.
New tests for Debugger features in a Worker.

* inspector/debugger/break-on-exception-throw-in-promise.html:
* inspector/debugger/break-on-exception.html:
* inspector/debugger/break-on-uncaught-exception.html:
* inspector/debugger/evaluateOnCallFrame-CommandLineAPI.html:
* inspector/debugger/pause-reason.html:
* inspector/debugger/paused-scopes.html:
* inspector/debugger/resources/log-pause-location.js:
* inspector/debugger/stepping/stepInto.html:
* inspector/debugger/stepping/stepOut.html:
* inspector/debugger/stepping/stepOver.html:
* inspector/debugger/stepping/stepping-through-autoContinue-breakpoint.html:
* inspector/debugger/tail-deleted-frames-from-vm-entry.html:
* inspector/debugger/tail-deleted-frames-this-value.html:
* inspector/debugger/tail-deleted-frames.html:
* inspector/debugger/tail-recursion.html:
Most debugger data moved from DebuggerManager into DebuggerData for a target.
Update tests that access such data like pauseReason / pauseData / callFrames.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208304 268f45cc-cd09-0410-ab3c-d52691b4dbfc

76 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise.html
LayoutTests/inspector/debugger/break-on-exception.html
LayoutTests/inspector/debugger/break-on-uncaught-exception.html
LayoutTests/inspector/debugger/evaluateOnCallFrame-CommandLineAPI.html
LayoutTests/inspector/debugger/pause-reason.html
LayoutTests/inspector/debugger/paused-scopes.html
LayoutTests/inspector/debugger/resources/log-pause-location.js
LayoutTests/inspector/debugger/stepping/stepInto.html
LayoutTests/inspector/debugger/stepping/stepOut.html
LayoutTests/inspector/debugger/stepping/stepOver.html
LayoutTests/inspector/debugger/stepping/stepping-through-autoContinue-breakpoint.html
LayoutTests/inspector/debugger/tail-deleted-frames-from-vm-entry.html
LayoutTests/inspector/debugger/tail-deleted-frames-this-value.html
LayoutTests/inspector/debugger/tail-deleted-frames.html
LayoutTests/inspector/debugger/tail-recursion.html
LayoutTests/inspector/model/remote-object-weak-collection.html
LayoutTests/inspector/worker/console-basic-expected.txt
LayoutTests/inspector/worker/console-basic.html
LayoutTests/inspector/worker/debugger-pause-expected.txt [new file with mode: 0644]
LayoutTests/inspector/worker/debugger-pause.html [new file with mode: 0644]
LayoutTests/inspector/worker/debugger-scripts-expected.txt [new file with mode: 0644]
LayoutTests/inspector/worker/debugger-scripts.html [new file with mode: 0644]
LayoutTests/inspector/worker/resources/worker-debugger-pause.js [new file with mode: 0644]
LayoutTests/inspector/worker/resources/worker-import-1.js [new file with mode: 0644]
LayoutTests/inspector/worker/resources/worker-scripts.js [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSWorkerGlobalScopeCustom.cpp
Source/WebCore/inspector/InspectorAllInOne.cpp
Source/WebCore/inspector/PageDebuggerAgent.h
Source/WebCore/inspector/WorkerDebuggerAgent.cpp [new file with mode: 0644]
Source/WebCore/inspector/WorkerDebuggerAgent.h [new file with mode: 0644]
Source/WebCore/inspector/WorkerInspectorController.cpp
Source/WebCore/inspector/WorkerScriptDebugServer.cpp
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Base/Main.js
Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js
Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js
Source/WebInspectorUI/UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js
Source/WebInspectorUI/UserInterface/Controllers/ProbeManager.js
Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js
Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js
Source/WebInspectorUI/UserInterface/Images/WorkerScript.png [moved from Source/WebInspectorUI/UserInterface/Images/WorkerDocument.png with 100% similarity]
Source/WebInspectorUI/UserInterface/Images/WorkerScript@2x.png [moved from Source/WebInspectorUI/UserInterface/Images/WorkerDocument@2x.png with 100% similarity]
Source/WebInspectorUI/UserInterface/Images/WorkerScriptLarge.png [moved from Source/WebInspectorUI/UserInterface/Images/WorkerDocumentLarge.png with 100% similarity]
Source/WebInspectorUI/UserInterface/Images/WorkerScriptLarge@2x.png [moved from Source/WebInspectorUI/UserInterface/Images/WorkerDocumentLarge@2x.png with 100% similarity]
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/Breakpoint.js
Source/WebInspectorUI/UserInterface/Models/CallFrame.js
Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js
Source/WebInspectorUI/UserInterface/Models/DebuggerData.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/Probe.js
Source/WebInspectorUI/UserInterface/Models/Script.js
Source/WebInspectorUI/UserInterface/Models/ScriptTimelineRecord.js
Source/WebInspectorUI/UserInterface/Models/StackTrace.js
Source/WebInspectorUI/UserInterface/Protocol/Connection.js
Source/WebInspectorUI/UserInterface/Protocol/DebuggerObserver.js
Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js
Source/WebInspectorUI/UserInterface/Protocol/Target.js
Source/WebInspectorUI/UserInterface/Test.html
Source/WebInspectorUI/UserInterface/Test/Test.js
Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.js
Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/EventListenerSectionGroup.js
Source/WebInspectorUI/UserInterface/Views/HeapSnapshotInstanceDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/ObjectTreeBaseTreeElement.js
Source/WebInspectorUI/UserInterface/Views/OpenResourceDialog.js
Source/WebInspectorUI/UserInterface/Views/ProfileDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/ResourceIcons.css
Source/WebInspectorUI/UserInterface/Views/ResourceSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/ScriptTreeElement.js
Source/WebInspectorUI/UserInterface/Views/SearchSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js
Source/WebInspectorUI/UserInterface/Views/TargetTreeElement.js [new file with mode: 0644]

index a4065b0..705cc42 100644 (file)
@@ -1,3 +1,38 @@
+2016-11-02  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Include DebuggerAgent in Workers - see, pause, and step through scripts
+        https://bugs.webkit.org/show_bug.cgi?id=164136
+        <rdar://problem/29028462>
+
+        Reviewed by Brian Burg.
+
+        * inspector/worker/debugger-pause-expected.txt: Added.
+        * inspector/worker/debugger-pause.html: Added.
+        * inspector/worker/debugger-scripts-expected.txt: Added.
+        * inspector/worker/debugger-scripts.html: Added.
+        * inspector/worker/resources/worker-debugger-pause.js: Added.
+        * inspector/worker/resources/worker-import-1.js: Added.
+        * inspector/worker/resources/worker-scripts.js: Added.
+        New tests for Debugger features in a Worker.
+
+        * inspector/debugger/break-on-exception-throw-in-promise.html:
+        * inspector/debugger/break-on-exception.html:
+        * inspector/debugger/break-on-uncaught-exception.html:
+        * inspector/debugger/evaluateOnCallFrame-CommandLineAPI.html:
+        * inspector/debugger/pause-reason.html:
+        * inspector/debugger/paused-scopes.html:
+        * inspector/debugger/resources/log-pause-location.js:
+        * inspector/debugger/stepping/stepInto.html:
+        * inspector/debugger/stepping/stepOut.html:
+        * inspector/debugger/stepping/stepOver.html:
+        * inspector/debugger/stepping/stepping-through-autoContinue-breakpoint.html:
+        * inspector/debugger/tail-deleted-frames-from-vm-entry.html:
+        * inspector/debugger/tail-deleted-frames-this-value.html:
+        * inspector/debugger/tail-deleted-frames.html:
+        * inspector/debugger/tail-recursion.html:
+        Most debugger data moved from DebuggerManager into DebuggerData for a target.
+        Update tests that access such data like pauseReason / pauseData / callFrames.
+
 2016-11-02  Ryosuke Niwa  <rniwa@webkit.org>
 
         Load stylesheets in link elements inside a connected shadow tree
index 78231df..8f31650 100644 (file)
@@ -18,7 +18,8 @@ function test()
             test: (resolve, reject) => {
                 InspectorTest.evaluateInPage(expression);
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
-                    InspectorTest.expectThat(WebInspector.debuggerManager.pauseReason === "exception", "Should pause for exception.");
+                    let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+                    InspectorTest.expectThat(targetData.pauseReason === "exception", "Should pause for exception.");
                     let callFrame = WebInspector.debuggerManager.activeCallFrame;
                     let name = callFrame.functionName || "<anonymous>";
                     let location = callFrame.sourceCodeLocation;
@@ -77,9 +78,11 @@ function test()
 
                 phase++;
 
+                let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+
                 // Pause at throw inside then.
                 if (phase === 1) {
-                    InspectorTest.expectThat(WebInspector.debuggerManager.pauseReason === "exception", "Should pause for exception.");
+                    InspectorTest.expectThat(targetData.pauseReason === "exception", "Should pause for exception.");
                     logPauseLocation();
                     WebInspector.debuggerManager.resume();
                     return;
@@ -87,7 +90,7 @@ function test()
 
                 // Pause at re-throw inside catch.
                 if (phase === 2) {
-                    InspectorTest.expectThat(WebInspector.debuggerManager.pauseReason === "exception", "Should pause for exception.");
+                    InspectorTest.expectThat(targetData.pauseReason === "exception", "Should pause for exception.");
                     logPauseLocation();
                     WebInspector.debuggerManager.resume().then(() => {
                         WebInspector.debuggerManager.removeEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, listener);
index cb6d60b..bd174fa 100644 (file)
@@ -18,7 +18,8 @@ function test()
             test: (resolve, reject) => {
                 InspectorTest.evaluateInPage(expression);
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
-                    InspectorTest.expectThat(WebInspector.debuggerManager.pauseReason === "exception", "Should pause for exception.");
+                    let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+                    InspectorTest.expectThat(targetData.pauseReason === "exception", "Should pause for exception.");
                     let callFrame = WebInspector.debuggerManager.activeCallFrame;
                     let name = callFrame.functionName || "<anonymous>";
                     let location = callFrame.sourceCodeLocation;
index 7c4d44c..389ad99 100644 (file)
@@ -18,7 +18,8 @@ function test()
             test: (resolve, reject) => {
                 InspectorTest.evaluateInPage(expression);
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
-                    InspectorTest.expectThat(WebInspector.debuggerManager.pauseReason === "exception", "Should pause for exception.");
+                    let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+                    InspectorTest.expectThat(targetData.pauseReason === "exception", "Should pause for exception.");
                     let callFrame = WebInspector.debuggerManager.activeCallFrame;
                     let name = callFrame.functionName || "<anonymous>";
                     let location = callFrame.sourceCodeLocation;
index d8a9acf..d4657cd 100644 (file)
@@ -61,12 +61,14 @@ function test()
     }
 
     function testEvaluateOnNonStrictCallFrame(expression, callback) {
-        let callFrame = WebInspector.debuggerManager.callFrames[1]; // foo
+        let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+        let callFrame = targetData.callFrames[1]; // foo
         testEvaluateOnCallFrame(callFrame, expression, callback);
     }
 
     function testEvaluateOnNonStrictCallFrameThrows(expression, callback) {
-        let callFrame = WebInspector.debuggerManager.callFrames[1]; // foo
+        let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+        let callFrame = targetData.callFrames[1]; // foo
         testEvaluateOnCallFrameThrows(callFrame, expression, callback);
     }
 
@@ -76,8 +78,9 @@ function test()
         name: "ValidateCallFrames",
         description: "Test6 evaluate can access CommandLineAPI methods.",
         test: (resolve, reject) => {
+            let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
             InspectorTest.expectThat(WebInspector.debuggerManager.activeCallFrame.functionName === "bar", "Strict call frame is `bar`.");
-            InspectorTest.expectThat(WebInspector.debuggerManager.callFrames[1].functionName === "foo", "Non-strict call frame is `foo`.");
+            InspectorTest.expectThat(targetData.callFrames[1].functionName === "foo", "Non-strict call frame is `foo`.");
 
             testEvaluateOnStrictCallFrame("a", (x) => { InspectorTest.expectThat(x === 6, "`a` should be 5 in `bar`."); });
             testEvaluateOnStrictCallFrame("b", (x) => { InspectorTest.expectThat(x === 123, "`b` should be 123 in `bar`."); });
index 9157e42..f5b2310 100644 (file)
@@ -62,10 +62,11 @@ function test()
     });
 
     WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Paused, function(event) {
+        let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
         InspectorTest.log("PAUSE #" + (++pauses));
-        InspectorTest.log("  REASON: " + WebInspector.debuggerManager.pauseReason);
-        if (WebInspector.debuggerManager.pauseData)
-            InspectorTest.log("  DATA: " + JSON.stringify(sanitizePauseData(WebInspector.debuggerManager.pauseData)));
+        InspectorTest.log("  REASON: " + targetData.pauseReason);
+        if (targetData.pauseData)
+            InspectorTest.log("  DATA: " + JSON.stringify(sanitizePauseData(targetData.pauseData)));
         else
             InspectorTest.log("  NO DATA");
 
index 100a1e0..7dc88a5 100644 (file)
@@ -72,7 +72,8 @@ function test()
     }
 
     function dumpCallFrames() {
-        let callFrames = WebInspector.debuggerManager.callFrames;
+        let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+        let callFrames = targetData.callFrames;
         let chain = Promise.resolve();
         for (let callFrame of callFrames)
             chain = chain.then(() => dumpCallFrame(callFrame));
index 2b65f72..f60e5d5 100644 (file)
@@ -178,7 +178,7 @@ TestPage.registerInitializer(() => {
                 InspectorTest.log(`EXPRESSION: ${expression}`);
                 InspectorTest.log(`STEPS: ${steps.join(", ")}`);
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
-                    InspectorTest.log(`PAUSED (${WebInspector.debuggerManager.pauseReason})`);
+                    InspectorTest.log(`PAUSED (${WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target).pauseReason})`);
                 });
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Resumed, (event) => {
                     InspectorTest.log("RESUMED");
index a1f8918..26d7e4d 100644 (file)
@@ -56,7 +56,7 @@ function test()
             test(resolve, reject) {
                 InspectorTest.evaluateInPage(expression);
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
-                    InspectorTest.log(`PAUSED (${WebInspector.debuggerManager.pauseReason})`);
+                    InspectorTest.log(`PAUSED (${WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target).pauseReason})`);
                 });
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Resumed, (event) => {
                     InspectorTest.log("RESUMED");
index fbbbcdf..c141cac 100644 (file)
@@ -54,7 +54,7 @@ function test()
             test(resolve, reject) {
                 InspectorTest.evaluateInPage(expression);
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
-                    InspectorTest.log(`PAUSED (${WebInspector.debuggerManager.pauseReason})`);
+                    InspectorTest.log(`PAUSED (${WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target).pauseReason})`);
                 });
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Resumed, (event) => {
                     InspectorTest.log("RESUMED");
index 034bf7b..3aed45c 100644 (file)
@@ -56,7 +56,7 @@ function test()
             test(resolve, reject) {
                 InspectorTest.evaluateInPage(expression);
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
-                    InspectorTest.log(`PAUSED (${WebInspector.debuggerManager.pauseReason})`);
+                    InspectorTest.log(`PAUSED (${WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target).pauseReason})`);
                 });
                 WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Resumed, (event) => {
                     InspectorTest.log("RESUMED");
index 31a4ac8..7e40717 100644 (file)
@@ -32,7 +32,7 @@ function test()
             // Step through the breakpoint.
             InspectorTest.evaluateInPage("setTimeout(entry)");
             WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
-                InspectorTest.log(`PAUSED (${WebInspector.debuggerManager.pauseReason})`);
+                InspectorTest.log(`PAUSED (${WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target).pauseReason})`);
             });
             WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, (event) => {
                 if (!WebInspector.debuggerManager.activeCallFrame)
index 7ba30d6..c44a80a 100644 (file)
@@ -46,10 +46,13 @@ function test()
             expectedFrames.push({functionName: 'bar', scope: ['i', i], isTailDeleted: i > 0 ? true : false});
         expectedFrames.push({functionName: 'timeout', scope: ['foo', 25], isTailDeleted: true});
 
-        InspectorTest.assert(WebInspector.debuggerManager.callFrames.length >= expectedFrames.length);
+        let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+        let callFrames = targetData.callFrames;
+
+        InspectorTest.assert(callFrames.length >= expectedFrames.length);
 
         for (let i = 0; i < expectedFrames.length; i++) {
-            let callFrame = WebInspector.debuggerManager.callFrames[i];
+            let callFrame = callFrames[i];
             let expectedFrame = expectedFrames[i];
             InspectorTest.log("Expected frame: " + JSON.stringify(expectedFrame));
             InspectorTest.expectThat(callFrame.functionName === expectedFrame.functionName, `Function name: ${callFrame.functionName} is correct.`);
index 45e2efc..f2098bc 100644 (file)
@@ -39,10 +39,13 @@ function test()
             {functionName: 'c', thisValue: ['cThis', 0], isTailDeleted: true}
         ];
 
-        InspectorTest.assert(WebInspector.debuggerManager.callFrames.length >= expectedFrames.length);
+        let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+        let callFrames = targetData.callFrames;
+
+        InspectorTest.assert(callFrames.length >= expectedFrames.length);
 
         for (let i = 0; i < expectedFrames.length; i++) {
-            let callFrame = WebInspector.debuggerManager.callFrames[i];
+            let callFrame = callFrames[i];
             let expectedFrame = expectedFrames[i];
             InspectorTest.log("Expected frame: " + JSON.stringify(expectedFrame));
             InspectorTest.assert(callFrame.functionName === expectedFrame.functionName);
index 3c497d6..3ac1d94 100644 (file)
@@ -47,10 +47,13 @@ function test()
             {functionName: 'c', scope: ['z', 60], isTailDeleted: true}
         ];
 
-        InspectorTest.assert(WebInspector.debuggerManager.callFrames.length >= expectedFrames.length);
+        let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+        let callFrames = targetData.callFrames;
+
+        InspectorTest.assert(callFrames.length >= expectedFrames.length);
 
         for (let i = 0; i < expectedFrames.length; i++) {
-            let callFrame = WebInspector.debuggerManager.callFrames[i];
+            let callFrame = callFrames[i];
             let expectedFrame = expectedFrames[i];
             InspectorTest.log("Expected frame: " + JSON.stringify(expectedFrame));
             InspectorTest.assert(callFrame.functionName === expectedFrame.functionName);
index 1fc8b1e..bb94f08 100644 (file)
@@ -47,9 +47,12 @@ function test()
         InspectorTest.log("Going to look at the top " + numFramesToInspect + " frames.");
         InspectorTest.log("------------------------------------");
 
-        InspectorTest.assert(WebInspector.debuggerManager.callFrames.length > numFramesToInspect); // We just look at top 50. This isn't a precise number. But it gets at the gist of the debugging experience.
+        let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.debuggerManager.activeCallFrame.target);
+        let callFrames = targetData.callFrames;
+
+        InspectorTest.assert(callFrames.length > numFramesToInspect); // We just look at top 50. This isn't a precise number. But it gets at the gist of the debugging experience.
         for (let i = 0; i < numFramesToInspect; i++) {
-            let callFrame = WebInspector.debuggerManager.callFrames[i];
+            let callFrame = callFrames[i];
             InspectorTest.assert(callFrame.functionName === "recurse");
             let topScope = callFrame.scopeChain[0];
 
index 5e2fde1..bc286f6 100644 (file)
@@ -59,8 +59,8 @@ function test()
                 InspectorTest.assert(remoteObject instanceof WebInspector.RemoteObject);
                 remoteObject.getCollectionEntries(0, 100, function(entries) {
                     InspectorTest.log("ENTRIES:");
-                    entries.sort(function(a, b) { return a.value.value - b.value.value; });
-                    for (var entry of entries)
+                    entries.sort((a, b) => a.value.value - b.value.value);
+                    for (let entry of entries)
                         InspectorTest.assert(entry instanceof WebInspector.CollectionEntry);
                     InspectorTest.log(JSON.stringify(entries, remoteObjectJSONFilter, "  "));
                     remoteObject.releaseWeakCollectionEntries();
index 792d429..5d57d3a 100644 (file)
@@ -12,6 +12,7 @@ PASS: ConsoleMessage parameter RemoteObjects should be from the Worker target.
   "_url": "inspector/worker/resources/worker-console.js",
   "_line": 4,
   "_column": 20,
+  "_sourceCodeLocation": "<filtered>",
   "_repeatCount": 1,
   "_parameters": [
     {
@@ -71,7 +72,7 @@ PASS: ConsoleMessage parameter RemoteObjects should be from the Worker target.
   "_url": "inspector/worker/resources/worker-console.js",
   "_line": 7,
   "_column": 21,
-  "_sourceCodeLocation": null,
+  "_sourceCodeLocation": "<filtered>",
   "_repeatCount": 1,
   "_parameters": [
     {
@@ -93,7 +94,7 @@ PASS: ConsoleMessage parameter RemoteObjects should be from the Worker target.
   "_url": "inspector/worker/resources/worker-console.js",
   "_line": 10,
   "_column": 22,
-  "_sourceCodeLocation": null,
+  "_sourceCodeLocation": "<filtered>",
   "_repeatCount": 1,
   "_parameters": [
     {
@@ -115,7 +116,7 @@ PASS: ConsoleMessage parameter RemoteObjects should be from the Worker target.
   "_url": "inspector/worker/resources/worker-console.js",
   "_line": 14,
   "_column": 23,
-  "_sourceCodeLocation": null,
+  "_sourceCodeLocation": "<filtered>",
   "_repeatCount": 1,
   "_parameters": [
     {
@@ -137,6 +138,7 @@ PASS: ConsoleMessage parameter RemoteObjects should be from the Worker target.
   "_url": "inspector/worker/resources/worker-console.js",
   "_line": 18,
   "_column": 24,
+  "_sourceCodeLocation": "<filtered>",
   "_repeatCount": 1,
   "_stackTrace": "<filtered>",
   "_request": null
@@ -151,6 +153,7 @@ PASS: ConsoleMessage parameter RemoteObjects should be from the Worker target.
   "_url": "inspector/worker/resources/worker-console.js",
   "_line": 21,
   "_column": 22,
+  "_sourceCodeLocation": "<filtered>",
   "_repeatCount": 1,
   "_stackTrace": "<filtered>",
   "_request": null
index f185cdd..1b358bd 100644 (file)
@@ -15,10 +15,10 @@ function test()
         return url.replace(/^.*?LayoutTests\//, "");
     }
 
-    function remoteObjectJSONFilter(key, value) {
+    function consoleMessageJSONFilter(key, value) {
         if (key === "_target" || key === "_hasChildren" || key === "_listeners")
             return undefined;
-        if (key === "_objectId" || key === "_stackTrace")
+        if (key === "_objectId" || key === "_stackTrace" || key === "_sourceCodeLocation")
             return "<filtered>";
         if (key === "_url")
             return sanitizeURL(value);
@@ -62,7 +62,7 @@ function test()
                             validate(message);
                         if (preprocess)
                             preprocess(message);
-                        InspectorTest.log(JSON.stringify(message, remoteObjectJSONFilter, "  "));
+                        InspectorTest.log(JSON.stringify(message, consoleMessageJSONFilter, "  "));
                         resolve();
                     }).catch(reject);
             }
diff --git a/LayoutTests/inspector/worker/debugger-pause-expected.txt b/LayoutTests/inspector/worker/debugger-pause-expected.txt
new file mode 100644 (file)
index 0000000..a6fcd60
--- /dev/null
@@ -0,0 +1,61 @@
+CONSOLE MESSAGE: line 14: TypeError: undefined is not an object (evaluating '[].x.x')
+Ensure we can pause in Workers.
+
+
+== Running test suite: Worker.Debugger.Pause
+-- Running test case: Worker.Debugger.Pause.DebuggerStatement
+PASS: Paused
+PASS: Should be paused in a Worker CallFrame.
+PASS: Pause reason should be a debugger statement.
+PAUSE AT triggerDebuggerStatement:3:5
+      0    function triggerDebuggerStatement() {
+      1        let before = 1;
+ ->   2        |debugger;
+      3        let after = 2;
+      4    }
+      5    
+
+
+-- Running test case: Worker.Debugger.Pause.Breakpoint
+PASS: Paused
+PASS: Should be paused in a Worker CallFrame.
+PASS: Pause reason should be a breakpoint.
+PAUSE AT triggerBreakpoint:9:5
+      5    
+      6    function triggerBreakpoint() {
+      7        let alpha = 1;
+ ->   8        |let beta = 2; // BREAKPOINT
+      9        let gamma = 3;
+     10    }
+     11    
+
+
+-- Running test case: Worker.Debugger.Pause.Exception
+PASS: Paused
+PASS: Should be paused in a Worker CallFrame.
+PASS: Pause reason should be an exception.
+PAUSE AT triggerException:14:9
+     10    }
+     11    
+     12    function triggerException() {
+ ->  13        [].x|.x;
+     14    }
+     15    
+     16    function triggerAssertion() {
+
+Uncaught exception in test page: TypeError: undefined is not an object (evaluating '[].x.x') [worker-debugger-pause.js:14]
+
+-- Running test case: Worker.Debugger.Pause.Assert
+PASS: Paused
+PASS: Should be paused in a Worker CallFrame.
+PASS: Pause reason should be an exception.
+PAUSE AT triggerAssertion:18:19
+     14    }
+     15    
+     16    function triggerAssertion() {
+ ->  17        console.assert|(false, "Assertion");
+     18    }
+     19    
+     20    onmessage = function(event) {
+
+
diff --git a/LayoutTests/inspector/worker/debugger-pause.html b/LayoutTests/inspector/worker/debugger-pause.html
new file mode 100644 (file)
index 0000000..1d156f7
--- /dev/null
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script src="../debugger/resources/log-pause-location.js"></script>
+<script>
+TestPage.allowUncaughtExceptions = true;
+TestPage.needToSanitizeUncaughtExceptionURLs = true;
+
+let worker = new Worker("resources/worker-debugger-pause.js");
+
+function test()
+{
+    let workerTarget = Array.from(WebInspector.targets).find((target) => target.type === WebInspector.Target.Type.Worker);
+    let workerDebuggerData = WebInspector.debuggerManager.dataForTarget(workerTarget);
+    if (!workerTarget) {
+        InspectorTest.fail("Missing Worker Target");
+        InspectorTest.completeTest();
+        return;
+    }
+
+    WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+    WebInspector.debuggerManager.assertionsBreakpoint.disabled = false;
+
+
+    let suite = InspectorTest.createAsyncSuite("Worker.Debugger.Pause");
+
+    suite.addTestCase({
+        name: "Worker.Debugger.Pause.DebuggerStatement",
+        description: "Worker should pause on debugger statement.",
+        test(resolve, reject) {
+            InspectorTest.evaluateInPage(`worker.postMessage("triggerDebuggerStatement")`);
+            WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
+                InspectorTest.pass("Paused");
+                InspectorTest.expectEqual(WebInspector.debuggerManager.activeCallFrame.target, workerTarget, "Should be paused in a Worker CallFrame.");
+                InspectorTest.expectEqual(workerDebuggerData.pauseReason, WebInspector.DebuggerManager.PauseReason.DebuggerStatement, "Pause reason should be a debugger statement.");
+                logPauseLocation();
+                WebInspector.debuggerManager.resume().then(resolve, reject);
+            });
+        }
+    });
+
+    suite.addTestCase({
+        name: "Worker.Debugger.Pause.Breakpoint",
+        description: "Worker should pause on breakpoint.",
+        test(resolve, reject) {
+            let location = workerTarget.mainResource.createSourceCodeLocation(8, 0);
+            let breakpoint = new WebInspector.Breakpoint(location);
+            WebInspector.debuggerManager.addBreakpoint(breakpoint);
+            InspectorTest.evaluateInPage(`worker.postMessage("triggerBreakpoint")`);
+            WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
+                InspectorTest.pass("Paused");
+                InspectorTest.expectEqual(WebInspector.debuggerManager.activeCallFrame.target, workerTarget, "Should be paused in a Worker CallFrame.");
+                InspectorTest.expectEqual(workerDebuggerData.pauseReason, WebInspector.DebuggerManager.PauseReason.Breakpoint, "Pause reason should be a breakpoint.");
+                logPauseLocation();
+                WebInspector.debuggerManager.resume().then(resolve, reject);
+            });
+        }
+    });
+
+    suite.addTestCase({
+        name: "Worker.Debugger.Pause.Exception",
+        description: "Worker should pause on exception.",
+        test(resolve, reject) {
+            InspectorTest.evaluateInPage(`worker.postMessage("triggerException")`);
+            WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
+                InspectorTest.pass("Paused");
+                InspectorTest.expectEqual(WebInspector.debuggerManager.activeCallFrame.target, workerTarget, "Should be paused in a Worker CallFrame.");
+                InspectorTest.expectEqual(workerDebuggerData.pauseReason, WebInspector.DebuggerManager.PauseReason.Exception, "Pause reason should be an exception.");
+                logPauseLocation();
+                WebInspector.debuggerManager.resume().then(resolve, reject);
+            });
+        }
+    });
+
+    suite.addTestCase({
+        name: "Worker.Debugger.Pause.Assert",
+        description: "Worker should pause on assert.",
+        test(resolve, reject) {
+            InspectorTest.evaluateInPage(`worker.postMessage("triggerAssertion")`);
+            WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
+                InspectorTest.pass("Paused");
+                InspectorTest.expectEqual(WebInspector.debuggerManager.activeCallFrame.target, workerTarget, "Should be paused in a Worker CallFrame.");
+                InspectorTest.expectEqual(workerDebuggerData.pauseReason, WebInspector.DebuggerManager.PauseReason.Assertion, "Pause reason should be an exception.");
+                logPauseLocation();
+                WebInspector.debuggerManager.resume().then(resolve, reject);
+            });
+        }
+    });
+
+    window.loadLinesFromSourceCode(workerTarget.mainResource).then(() => {
+        suite.runTestCasesAndFinish();
+    });
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Ensure we can pause in Workers.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/worker/debugger-scripts-expected.txt b/LayoutTests/inspector/worker/debugger-scripts-expected.txt
new file mode 100644 (file)
index 0000000..f03ff64
--- /dev/null
@@ -0,0 +1,30 @@
+Ensure we can associate scripts with Workers and get their contents.
+
+
+== Running test suite: Worker.Debugger.Script
+-- Running test case: Worker.Debugger.Script.MainResource
+PASS: Worker target's main resource should be a Script.
+PASS: Worker target's main resource should be owned by a Worker target.
+PASS: Worker DebuggerData should include script.
+PASS: Worker DebuggerData should include script by identifier.
+PASS: Worker DebuggerData should include script by URL.
+PASS: Main DebuggerData should not include the script.
+PASS: Worker target's main resource should have content.
+
+-- Running test case: Worker.Debugger.Script.ImportedScript
+PASS: ScriptAdded - inspector/worker/resources/worker-import-1.js
+PASS: Script should be owned by a Worker target.
+PASS: Worker DebuggerData should include script.
+PASS: Worker DebuggerData should include script by identifier.
+PASS: Worker DebuggerData should include script by URL.
+PASS: Main DebuggerData should not include the script.
+PASS: Imported script content should have 'workerImport1'.
+
+-- Running test case: Worker.Debugger.Script.NamedEval
+PASS: ScriptAdded - worker-eval.js
+PASS: Script should be owned by a Worker target.
+PASS: Worker DebuggerData should include script.
+PASS: Worker DebuggerData should include script by identifier.
+PASS: Main DebuggerData should not include the script.
+PASS: Eval script content should have 'workerEval'.
+
diff --git a/LayoutTests/inspector/worker/debugger-scripts.html b/LayoutTests/inspector/worker/debugger-scripts.html
new file mode 100644 (file)
index 0000000..36be502
--- /dev/null
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script>
+let worker = new Worker("resources/worker-scripts.js");
+
+function test()
+{
+    function sanitizeURL(url) {
+        return url.replace(/^.*?LayoutTests\//, "");
+    }
+
+    let mainTarget = WebInspector.mainTarget;
+    let workerTarget = Array.from(WebInspector.targets).find((target) => target.type === WebInspector.Target.Type.Worker);
+    let mainDebuggerData = WebInspector.debuggerManager.dataForTarget(mainTarget);
+    let workerDebuggerData = WebInspector.debuggerManager.dataForTarget(workerTarget);
+    if (!workerTarget) {
+        InspectorTest.fail("Missing Worker Target");
+        InspectorTest.completeTest();
+        return;
+    }
+
+    let suite = InspectorTest.createAsyncSuite("Worker.Debugger.Script");
+
+    suite.addTestCase({
+        name: "Worker.Debugger.Script.MainResource",
+        description: "Worker main resource should be a script tied to the Worker.",
+        test(resolve, reject) {
+            let script = workerTarget.mainResource;
+            InspectorTest.expectThat(script instanceof WebInspector.Script, "Worker target's main resource should be a Script.");
+            InspectorTest.expectEqual(script.target, workerTarget, "Worker target's main resource should be owned by a Worker target.");
+            InspectorTest.expectThat(workerDebuggerData.scripts.includes(script), "Worker DebuggerData should include script.");
+            InspectorTest.expectThat(workerDebuggerData.scriptForIdentifier(script.id), "Worker DebuggerData should include script by identifier.");
+            InspectorTest.expectEqual(workerDebuggerData.scriptsForURL(script.url).length, 1, "Worker DebuggerData should include script by URL.");
+            InspectorTest.expectThat(!mainDebuggerData.scripts.includes(script), "Main DebuggerData should not include the script.");
+            script.requestContent()
+                .then(({content}) => {
+                    InspectorTest.expectGreaterThan(content.length, 100, "Worker target's main resource should have content.");
+                    resolve();
+                }).catch(reject);
+        }
+    });
+
+    suite.addTestCase({
+        name: "Worker.Debugger.Script.ImportedScript",
+        description: "Worker should be told of all scripts, like imported scripts.",
+        test(resolve, reject) {
+            InspectorTest.evaluateInPage(`worker.postMessage("triggerImportScripts")`);
+            let listener = WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, (event) => {
+                let script = event.data.script;
+                if (!/worker-import-1\.js$/.test(script.url))
+                    return;
+
+                InspectorTest.pass(`ScriptAdded - ${sanitizeURL(script.url)}`);
+                InspectorTest.expectEqual(script.target, workerTarget, "Script should be owned by a Worker target.");
+                InspectorTest.expectThat(workerDebuggerData.scripts.includes(script), "Worker DebuggerData should include script.");
+                InspectorTest.expectThat(workerDebuggerData.scriptForIdentifier(script.id), "Worker DebuggerData should include script by identifier.");
+                InspectorTest.expectEqual(workerDebuggerData.scriptsForURL(script.url).length, 1, "Worker DebuggerData should include script by URL.");
+                InspectorTest.expectThat(!mainDebuggerData.scripts.includes(script), "Main DebuggerData should not include the script.");
+                script.requestContent()
+                    .then(({content}) => {
+                        InspectorTest.expectThat(content.includes("workerImport1"), "Imported script content should have 'workerImport1'.");
+                        WebInspector.debuggerManager.removeEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, listener);
+                        resolve();
+                    }).catch(reject);
+            });
+        }
+    });
+
+    suite.addTestCase({
+        name: "Worker.Debugger.Script.NamedEval",
+        description: "Worker should be told of all scripts, like named evaluations.",
+        test(resolve, reject) {
+            InspectorTest.evaluateInPage(`worker.postMessage("triggerEvalScript")`);
+            let listener = WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, (event) => {
+                let script = event.data.script;
+                if (!/worker-eval\.js$/.test(script.sourceURL))
+                    return;
+
+                InspectorTest.pass(`ScriptAdded - ${script.sourceURL}`);
+                InspectorTest.expectEqual(script.target, workerTarget, "Script should be owned by a Worker target.");
+                InspectorTest.expectThat(workerDebuggerData.scripts.includes(script), "Worker DebuggerData should include script.");
+                InspectorTest.expectThat(workerDebuggerData.scriptForIdentifier(script.id), "Worker DebuggerData should include script by identifier.");
+                InspectorTest.expectThat(!mainDebuggerData.scripts.includes(script), "Main DebuggerData should not include the script.");
+                script.requestContent()
+                    .then(({content}) => {
+                        InspectorTest.expectThat(content.includes("workerEval"), "Eval script content should have 'workerEval'.");
+                        WebInspector.debuggerManager.removeEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, listener);
+                        resolve();
+                    }).catch(reject);
+            });
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Ensure we can associate scripts with Workers and get their contents.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/worker/resources/worker-debugger-pause.js b/LayoutTests/inspector/worker/resources/worker-debugger-pause.js
new file mode 100644 (file)
index 0000000..cb3766b
--- /dev/null
@@ -0,0 +1,30 @@
+function triggerDebuggerStatement() {
+    let before = 1;
+    debugger;
+    let after = 2;
+}
+
+function triggerBreakpoint() {
+    let alpha = 1;
+    let beta = 2; // BREAKPOINT
+    let gamma = 3;
+}
+
+function triggerException() {
+    [].x.x;
+}
+
+function triggerAssertion() {
+    console.assert(false, "Assertion");
+}
+
+onmessage = function(event) {
+    if (event.data === "triggerDebuggerStatement")
+        triggerDebuggerStatement();
+    else if (event.data === "triggerBreakpoint")
+        triggerBreakpoint();
+    else if (event.data === "triggerException")
+        triggerException();
+    else if (event.data === "triggerAssertion")
+        triggerAssertion();
+}
diff --git a/LayoutTests/inspector/worker/resources/worker-import-1.js b/LayoutTests/inspector/worker/resources/worker-import-1.js
new file mode 100644 (file)
index 0000000..26f7a49
--- /dev/null
@@ -0,0 +1,3 @@
+function workerImport1() {
+    console.log("workerImport1");
+}
diff --git a/LayoutTests/inspector/worker/resources/worker-scripts.js b/LayoutTests/inspector/worker/resources/worker-scripts.js
new file mode 100644 (file)
index 0000000..5092c14
--- /dev/null
@@ -0,0 +1,14 @@
+function triggerImportScripts() {
+    importScripts("worker-import-1.js");
+}
+
+function triggerEvalScript() {
+    eval("function workerEval() { }\n//# sourceURL=worker-eval.js");
+}
+
+onmessage = function(event) {
+    if (event.data === "triggerImportScripts")
+        triggerImportScripts();
+    else if (event.data === "triggerEvalScript")
+        triggerEvalScript();
+}
index 56f9b63..42e2f21 100644 (file)
@@ -1903,6 +1903,7 @@ set(WebCore_SOURCES
     inspector/WebInjectedScriptHost.cpp
     inspector/WebInjectedScriptManager.cpp
     inspector/WorkerConsoleAgent.cpp
+    inspector/WorkerDebuggerAgent.cpp
     inspector/WorkerInspectorController.cpp
     inspector/WorkerRuntimeAgent.cpp
     inspector/WorkerScriptDebugServer.cpp
index a32f189..6b3146a 100644 (file)
@@ -1,3 +1,36 @@
+2016-11-02  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Include DebuggerAgent in Workers - see, pause, and step through scripts
+        https://bugs.webkit.org/show_bug.cgi?id=164136
+        <rdar://problem/29028462>
+
+        Reviewed by Brian Burg.
+
+        Tests: inspector/worker/debugger-pause.html
+               inspector/worker/debugger-scripts.html
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * inspector/InspectorAllInOne.cpp:
+        New file.
+
+        * inspector/PageDebuggerAgent.h:
+        * inspector/WorkerDebuggerAgent.cpp: Added.
+        (WebCore::WorkerDebuggerAgent::WorkerDebuggerAgent):
+        (WebCore::WorkerDebuggerAgent::~WorkerDebuggerAgent):
+        (WebCore::WorkerDebuggerAgent::breakpointActionLog):
+        (WebCore::WorkerDebuggerAgent::injectedScriptForEval):
+        * inspector/WorkerDebuggerAgent.h: Added.
+        DebuggerAgent customizations for Workers.
+
+        * inspector/WorkerInspectorController.cpp:
+        (WebCore::WorkerInspectorController::WorkerInspectorController):
+        Add the new agent.
+
+        * inspector/WorkerScriptDebugServer.cpp:
+        (WebCore::WorkerScriptDebugServer::runEventLoopWhilePaused):
+        Implement the nested run loop for Workers.
+
 2016-11-02  Simon Fraser  <simon.fraser@apple.com>
 
         Add Battery Status to features.json, marked as "Removed".
index 0a68d6e..56a81a2 100644 (file)
                A516E8B8136E04DB0076C3C0 /* LocalizedDateCache.mm in Sources */ = {isa = PBXBuildFile; fileRef = A516E8B5136E04DB0076C3C0 /* LocalizedDateCache.mm */; };
                A52A68611DBB0F630083373F /* WorkerConsoleAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A52A685F1DBB0F5B0083373F /* WorkerConsoleAgent.cpp */; };
                A52A68621DBB0F630083373F /* WorkerConsoleAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = A52A68601DBB0F5B0083373F /* WorkerConsoleAgent.h */; };
+               A52A68651DBD4B5D0083373F /* WorkerDebuggerAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A52A68631DBD4B580083373F /* WorkerDebuggerAgent.cpp */; };
+               A52A68661DBD4B5D0083373F /* WorkerDebuggerAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = A52A68641DBD4B580083373F /* WorkerDebuggerAgent.h */; };
                A5416FE518810EF80009FC5F /* YouTubeEmbedShadowElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5416FE318810EF80009FC5F /* YouTubeEmbedShadowElement.cpp */; };
                A5416FE618810EF80009FC5F /* YouTubeEmbedShadowElement.h in Headers */ = {isa = PBXBuildFile; fileRef = A5416FE418810EF80009FC5F /* YouTubeEmbedShadowElement.h */; };
                A54A0C5D1DB6D9C00017A90B /* InspectorWorkerAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A54A0C5B1DB6D9B10017A90B /* InspectorWorkerAgent.cpp */; };
                A518225517E2A0D400A9BA1D /* InspectorOverlayPage.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = InspectorOverlayPage.js; sourceTree = "<group>"; };
                A52A685F1DBB0F5B0083373F /* WorkerConsoleAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerConsoleAgent.cpp; sourceTree = "<group>"; };
                A52A68601DBB0F5B0083373F /* WorkerConsoleAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WorkerConsoleAgent.h; sourceTree = "<group>"; };
+               A52A68631DBD4B580083373F /* WorkerDebuggerAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerDebuggerAgent.cpp; sourceTree = "<group>"; };
+               A52A68641DBD4B580083373F /* WorkerDebuggerAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WorkerDebuggerAgent.h; sourceTree = "<group>"; };
                A5416FE318810EF80009FC5F /* YouTubeEmbedShadowElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YouTubeEmbedShadowElement.cpp; sourceTree = "<group>"; };
                A5416FE418810EF80009FC5F /* YouTubeEmbedShadowElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YouTubeEmbedShadowElement.h; sourceTree = "<group>"; };
                A54A0C5B1DB6D9B10017A90B /* InspectorWorkerAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorWorkerAgent.cpp; sourceTree = "<group>"; };
                                A584FE2E1864CB8400843B10 /* WebInjectedScriptManager.h */,
                                A52A685F1DBB0F5B0083373F /* WorkerConsoleAgent.cpp */,
                                A52A68601DBB0F5B0083373F /* WorkerConsoleAgent.h */,
+                               A52A68631DBD4B580083373F /* WorkerDebuggerAgent.cpp */,
+                               A52A68641DBD4B580083373F /* WorkerDebuggerAgent.h */,
                                A54A0C5F1DB7F8B70017A90B /* WorkerInspectorController.cpp */,
                                A54A0C601DB7F8B70017A90B /* WorkerInspectorController.h */,
                                A57FD7191DB94236006AE24B /* WorkerRuntimeAgent.cpp */,
                                2E4346460F546A8200B0F1BA /* Worker.h in Headers */,
                                A52A68621DBB0F630083373F /* WorkerConsoleAgent.h in Headers */,
                                A55639D11C6F09E300806D8E /* WorkerConsoleClient.h in Headers */,
+                               A52A68661DBD4B5D0083373F /* WorkerDebuggerAgent.h in Headers */,
                                A3E2643114748991005A8588 /* WorkerEventQueue.h in Headers */,
                                2E4346490F546A8200B0F1BA /* WorkerGlobalScope.h in Headers */,
                                5185FCB41BB4C4E80012898F /* WorkerGlobalScopeIndexedDatabase.h in Headers */,
                                2E4346450F546A8200B0F1BA /* Worker.cpp in Sources */,
                                A52A68611DBB0F630083373F /* WorkerConsoleAgent.cpp in Sources */,
                                A55639D21C6F09E700806D8E /* WorkerConsoleClient.cpp in Sources */,
+                               A52A68651DBD4B5D0083373F /* WorkerDebuggerAgent.cpp in Sources */,
                                A3E2643014748991005A8588 /* WorkerEventQueue.cpp in Sources */,
                                2E4346480F546A8200B0F1BA /* WorkerGlobalScope.cpp in Sources */,
                                418C395A1C8DD6990051C8A3 /* WorkerGlobalScopeFetch.cpp in Sources */,
index 0da7ddf..980a61e 100644 (file)
  */
 
 #include "config.h"
-
 #include "JSWorkerGlobalScope.h"
 
-#include "ExceptionCode.h"
-#include "JSDOMBinding.h"
-#include "JSDOMGlobalObject.h"
-#include "JSEventListener.h"
-#include "JSEventSource.h"
-#include "JSMessageChannel.h"
-#include "JSMessagePort.h"
-#include "JSWorkerLocation.h"
-#include "JSWorkerNavigator.h"
-#include "JSXMLHttpRequest.h"
 #include "ScheduledAction.h"
 #include "WorkerGlobalScope.h"
-#include "WorkerLocation.h"
-#include "WorkerNavigator.h"
-
-#if ENABLE(WEB_SOCKETS)
-#include "JSWebSocket.h"
-#endif
 
 using namespace JSC;
 
index 6f28e6a..cbcbf69 100644 (file)
@@ -64,6 +64,7 @@
 #include "WebInjectedScriptHost.cpp"
 #include "WebInjectedScriptManager.cpp"
 #include "WorkerConsoleAgent.cpp"
+#include "WorkerDebuggerAgent.cpp"
 #include "WorkerInspectorController.cpp"
 #include "WorkerRuntimeAgent.cpp"
 #include "WorkerScriptDebugServer.cpp"
index f197249..6f6f052 100644 (file)
@@ -62,7 +62,7 @@ private:
     void muteConsole() override;
     void unmuteConsole() override;
 
-    void breakpointActionLog(JSC::ExecState&, const String&) final;
+    void breakpointActionLog(JSC::ExecState&, const String&) override;
 
     Inspector::InjectedScript injectedScriptForEval(ErrorString&, const int* executionContextId) override;
     void setOverlayMessage(ErrorString&, const String*) final;
diff --git a/Source/WebCore/inspector/WorkerDebuggerAgent.cpp b/Source/WebCore/inspector/WorkerDebuggerAgent.cpp
new file mode 100644 (file)
index 0000000..e4050ed
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WorkerDebuggerAgent.h"
+
+#include "ScriptState.h"
+#include "WorkerGlobalScope.h"
+#include <inspector/ConsoleMessage.h>
+#include <inspector/InjectedScript.h>
+#include <inspector/InjectedScriptManager.h>
+#include <inspector/ScriptCallStack.h>
+#include <inspector/ScriptCallStackFactory.h>
+
+using namespace JSC;
+using namespace Inspector;
+
+namespace WebCore {
+
+WorkerDebuggerAgent::WorkerDebuggerAgent(WorkerAgentContext& context)
+    : WebDebuggerAgent(context)
+    , m_workerGlobalScope(context.workerGlobalScope)
+{
+}
+
+WorkerDebuggerAgent::~WorkerDebuggerAgent()
+{
+}
+
+void WorkerDebuggerAgent::breakpointActionLog(ExecState& state, const String& message)
+{
+    m_workerGlobalScope.addConsoleMessage(std::make_unique<ConsoleMessage>(MessageSource::JS, MessageType::Log, MessageLevel::Log, message, createScriptCallStack(&state, ScriptCallStack::maxCallStackSizeToCapture)));
+}
+
+InjectedScript WorkerDebuggerAgent::injectedScriptForEval(ErrorString& errorString, const int* executionContextId)
+{
+    if (executionContextId) {
+        errorString = ASCIILiteral("Execution context id is not supported for workers as there is only one execution context.");
+        return InjectedScript();
+    }
+
+    JSC::ExecState* scriptState = execStateFromWorkerGlobalScope(&m_workerGlobalScope);
+    return injectedScriptManager().injectedScriptFor(scriptState);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/inspector/WorkerDebuggerAgent.h b/Source/WebCore/inspector/WorkerDebuggerAgent.h
new file mode 100644 (file)
index 0000000..5094e6c
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "WebDebuggerAgent.h"
+
+namespace WebCore {
+
+class WorkerGlobalScope;
+
+class WorkerDebuggerAgent final : public WebDebuggerAgent {
+    WTF_MAKE_NONCOPYABLE(WorkerDebuggerAgent);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    WorkerDebuggerAgent(WorkerAgentContext&);
+    ~WorkerDebuggerAgent();
+
+private:
+    // We don't need to mute console for workers.
+    void muteConsole() override { }
+    void unmuteConsole() override { }
+
+    void breakpointActionLog(JSC::ExecState&, const String&) override;
+    Inspector::InjectedScript injectedScriptForEval(ErrorString&, const int* executionContextId) override;
+
+    WorkerGlobalScope& m_workerGlobalScope;
+};
+
+} // namespace WebCore
index cf01e2b..1f912a4 100644 (file)
@@ -32,6 +32,7 @@
 #include "WebInjectedScriptHost.h"
 #include "WebInjectedScriptManager.h"
 #include "WorkerConsoleAgent.h"
+#include "WorkerDebuggerAgent.h"
 #include "WorkerGlobalScope.h"
 #include "WorkerRuntimeAgent.h"
 #include "WorkerThread.h"
@@ -73,14 +74,13 @@ WorkerInspectorController::WorkerInspectorController(WorkerGlobalScope& workerGl
         workerGlobalScope,
     };
 
-    auto runtimeAgent = std::make_unique<WorkerRuntimeAgent>(workerContext);
-    m_agents.append(WTFMove(runtimeAgent));
+    m_agents.append(std::make_unique<WorkerRuntimeAgent>(workerContext));
+    m_agents.append(std::make_unique<WorkerDebuggerAgent>(workerContext));
 
     auto consoleAgent = std::make_unique<WorkerConsoleAgent>(workerContext, nullptr);
     m_instrumentingAgents->setWebConsoleAgent(consoleAgent.get());
     m_agents.append(WTFMove(consoleAgent));
 
-    // FIXME: DebuggerAgent
     // FIXME: HeapAgent
 
     if (CommandLineAPIHost* commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost()) {
index 31e3b97..014dde3 100644 (file)
@@ -72,7 +72,10 @@ void WorkerScriptDebugServer::runEventLoopWhilePaused()
 {
     TimerBase::fireTimersInNestedEventLoop();
 
-    // FIXME: Implement Worker Debugger Run Loop.
+    MessageQueueWaitResult result;
+    do {
+        result = m_workerGlobalScope.thread().runLoop().runInMode(&m_workerGlobalScope, WorkerRunLoop::debuggerMode());
+    } while (result != MessageQueueTerminated && !m_doneProcessingDebuggerEvents);
 }
 
 void WorkerScriptDebugServer::reportException(JSC::ExecState* exec, JSC::Exception* exception) const
index 12c0a2e..3e37028 100644 (file)
@@ -1,3 +1,261 @@
+2016-11-02  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Include DebuggerAgent in Workers - see, pause, and step through scripts
+        https://bugs.webkit.org/show_bug.cgi?id=164136
+        <rdar://problem/29028462>
+
+        Reviewed by Brian Burg.
+        
+        By implementing DebuggerAgent, Workers will inform the frontend about
+        Scripts that evaluate in the Worker's VM and the Worker VM can pause
+        and send the pausing CallFrames to the frontend. This means that
+        WebInspector.Script and WebInspector.CallFrame will need to be made
+        target aware. This also means that each Target will have its own
+        set of debugger data, such as the list of scripts and pause data
+        like the pause reason / call frames. Previously all this data was
+        managed by DebuggerManager.
+
+        With this change we split that data out of DebuggerManager to be
+        per-target DebuggerData. DebuggerManager keeps `activeCallFrame`
+        but the list of scripts and pause data have moved into `DebuggerData`
+        which is per-target, accessed through DebuggerManager's new
+        dataForTarget(target) method.
+
+        Finally we make a few changes to the UserInterface to make Workers
+        and their scripts, appear grouped together. The Resources sidebar
+        previously had a single top level item for the Main Frame, which
+        has all its resources as its children (potentially grouped into
+        folders). With this change, each Worker gets its own top level
+        item as well, and the Worker's subresources (imported scripts)
+        become its children.
+
+        We also now associate a single mainResource with Targets. In the
+        case of Workers, we assume and assert that this is a Script. If
+        this were to ever change we would need to adjust the assumptions.
+
+        * UserInterface/Main.html:
+        * UserInterface/Test.html:
+        New files.
+
+        * UserInterface/Base/Main.js:
+        * UserInterface/Test/Test.js:
+        Add WebInspector.assumingMainTarget to fill in all the places where
+        we assume the main target right now, but would need to handle non-main
+        targets as other agents are implemented in workers. For example profile
+        data that assumes the main target right now could be worker targets
+        when we implement ScriptProfiler / Heap agents.
+
+        * UserInterface/Protocol/Connection.js:
+        (InspectorBackend.WorkerConnection):
+        * UserInterface/Protocol/Target.js:
+        (WebInspector.Target):
+        (WebInspector.Target.prototype.get DebuggerAgent):
+        (WebInspector.Target.prototype.get mainResource):
+        (WebInspector.Target.prototype.set mainResource):
+        (WebInspector.WorkerTarget.prototype.initialize):
+        (WebInspector.WorkerTarget):
+        Include DebuggerAgent in Targets.
+        Include a mainResource for Worker Targets.
+
+        * UserInterface/Protocol/DebuggerObserver.js:
+        (WebInspector.DebuggerObserver.prototype.scriptParsed):
+        (WebInspector.DebuggerObserver.prototype.breakpointResolved):
+        (WebInspector.DebuggerObserver.prototype.paused):
+        (WebInspector.DebuggerObserver.prototype.resumed):
+        Pass the target on to managers when necessary.
+
+        * UserInterface/Models/DebuggerData.js: Added.
+        (WebInspector.DebuggerData):
+        (WebInspector.DebuggerData.prototype.get target):
+        (WebInspector.DebuggerData.prototype.get callFrames):
+        (WebInspector.DebuggerData.prototype.get pauseReason):
+        (WebInspector.DebuggerData.prototype.get pauseData):
+        (WebInspector.DebuggerData.prototype.get scripts):
+        (WebInspector.DebuggerData.prototype.scriptForIdentifier):
+        (WebInspector.DebuggerData.prototype.scriptsForURL):
+        (WebInspector.DebuggerData.prototype.reset):
+        (WebInspector.DebuggerData.prototype.addScript):
+        (WebInspector.DebuggerData.prototype.pause):
+        (WebInspector.DebuggerData.prototype.unpause):
+        Extract per-target data from DebuggerManager. This includes the list
+        of scripts evaluated in a Target, and any pause data for this target
+        such as the pause reason and call frames.
+
+        * UserInterface/Controllers/DebuggerManager.js:
+        (WebInspector.DebuggerManager.prototype.dataForTarget):
+        (WebInspector.DebuggerManager.prototype.get pauseReason): Deleted.
+        (WebInspector.DebuggerManager.prototype.get pauseData): Deleted.
+        (WebInspector.DebuggerManager.prototype.get callFrames): Deleted.
+        (WebInspector.DebuggerManager.prototype.reset):
+        New way to access per-target debugger data.
+
+        (WebInspector.DebuggerManager.prototype.initializeTarget):
+        When a new Target is created, synchronize frontend state with the target.
+        Things like the list of breakpoints and global breakpoint states.
+
+        (WebInspector.DebuggerManager.prototype.scriptForIdentifier):
+        (WebInspector.DebuggerManager.prototype.scriptsForURL):
+        Convenience accessors for scripts must now provide a Target.
+
+        (WebInspector.DebuggerManager.prototype.get knownNonResourceScripts):
+        This is a convenience accessors for a list of all scripts across all targets
+        so this handles getting the list across all targets.
+
+        (WebInspector.DebuggerManager.prototype.pause):
+        (WebInspector.DebuggerManager.prototype.resume):
+        (WebInspector.DebuggerManager.prototype.stepOver):
+        (WebInspector.DebuggerManager.prototype.stepInto):
+        (WebInspector.DebuggerManager.prototype.stepOut):
+        (WebInspector.DebuggerManager.prototype.continueToLocation):
+        Stepping commands affect the current target with the active call frame.
+        Eventually we will change Pause and Resume behavior to affect all targets.
+        
+        (WebInspector.DebuggerManager.prototype.addBreakpoint):
+        (WebInspector.DebuggerManager.prototype.breakpointResolved):
+        (WebInspector.DebuggerManager.prototype._setBreakpoint.didSetBreakpoint):
+        (WebInspector.DebuggerManager.prototype._setBreakpoint):
+        (WebInspector.DebuggerManager.prototype._removeBreakpoint):
+        Breakpoints should be set on all targets, but we need a way
+        to set them on a specific target, when initializing an
+        individual target when we want to inform that single target
+        of all of the breakpoints.
+
+        (WebInspector.DebuggerManager.prototype._breakpointDisabledStateDidChange):
+        (WebInspector.DebuggerManager.prototype._updateBreakOnExceptionsState):
+        Changing global breakpoint state should inform all targets.
+
+        (WebInspector.DebuggerManager.prototype.scriptDidParse):
+        Associate Scripts with a Target. Identify the main resource of a
+        Worker Target and set it as soon as we can.
+
+        (WebInspector.DebuggerManager.prototype.debuggerDidPause):
+        (WebInspector.DebuggerManager.prototype.debuggerDidResume):
+        (WebInspector.DebuggerManager.prototype._sourceCodeLocationFromPayload):
+        (WebInspector.DebuggerManager.prototype._scopeChainFromPayload):
+        (WebInspector.DebuggerManager.prototype._scopeChainNodeFromPayload):
+        (WebInspector.DebuggerManager.prototype._mainResourceDidChange):
+        (WebInspector.DebuggerManager.prototype._didResumeInternal):
+        Pausing and resuming now happens per-target, so associate
+        created model objects (CallFrame, ScopeChain objects) and any
+        other necessary data with the target.
+
+        * UserInterface/Models/Breakpoint.js:
+        (WebInspector.Breakpoint):
+        (WebInspector.Breakpoint.prototype.get target):
+        (WebInspector.Breakpoint.prototype.get info):
+        * UserInterface/Models/CallFrame.js:
+        (WebInspector.CallFrame):
+        (WebInspector.CallFrame.prototype.get target):
+        (WebInspector.CallFrame.fromDebuggerPayload):
+        (WebInspector.CallFrame.fromPayload):
+        * UserInterface/Models/ConsoleMessage.js:
+        (WebInspector.ConsoleMessage):
+        * UserInterface/Models/Script.js:
+        (WebInspector.Script):
+        (WebInspector.Script.prototype.get target):
+        (WebInspector.Script.prototype.isMainResource):
+        (WebInspector.Script.prototype.requestContentFromBackend):
+        (WebInspector.Script.prototype._resolveResource):
+        * UserInterface/Models/StackTrace.js:
+        (WebInspector.StackTrace.fromPayload):
+        (WebInspector.StackTrace.fromString):
+        * UserInterface/Models/ProbeManager.js:
+        (WebInspector.ProbeManager.prototype.didSampleProbe):
+        * UserInterface/Models/Probe.js:
+        (WebInspector.ProbeSample):
+        * UserInterface/Views/ConsoleMessageView.js:
+        (WebInspector.ConsoleMessageView.prototype._appendLocationLink):
+        (WebInspector.ConsoleMessageView.prototype._formatParameterAsString):
+        Associate model objects with a specific target where necessary.
+
+        * UserInterface/Views/ObjectTreeBaseTreeElement.js:
+        (WebInspector.ObjectTreeBaseTreeElement.prototype._appendMenusItemsForObject):
+        * UserInterface/Controllers/RuntimeManager.js:
+        (WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow):
+        * UserInterface/Protocol/RemoteObject.js:
+        (WebInspector.RemoteObject.prototype.findFunctionSourceCodeLocation):
+        Use target specific DebuggerAgent where necessary.
+
+        * UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js:
+        * UserInterface/Controllers/TimelineManager.js:
+        (WebInspector.TimelineManager.prototype._callFramesFromPayload):
+        * UserInterface/Models/ScriptTimelineRecord.js:
+        (WebInspector.ScriptTimelineRecord.prototype._initializeProfileFromPayload.profileNodeFromPayload):
+        * UserInterface/Views/EventListenerSectionGroup.js:
+        (WebInspector.EventListenerSectionGroup.prototype._functionTextOrLink):
+        (WebInspector.EventListenerSectionGroup):
+        * UserInterface/Views/HeapSnapshotInstanceDataGridNode.js:
+        (WebInspector.HeapSnapshotInstanceDataGridNode.logHeapSnapshotNode.node.shortestGCRootPath.):
+        (WebInspector.HeapSnapshotInstanceDataGridNode.logHeapSnapshotNode):
+        (WebInspector.HeapSnapshotInstanceDataGridNode.prototype._populateWindowPreview):
+        (WebInspector.HeapSnapshotInstanceDataGridNode.prototype._populatePreview):
+        (WebInspector.HeapSnapshotInstanceDataGridNode.prototype._mouseoverHandler.appendPathRow):
+        * UserInterface/Views/ProfileDataGridNode.js:
+        (WebInspector.ProfileDataGridNode.prototype.iconClassName):
+        (WebInspector.ProfileDataGridNode.prototype.filterableDataForColumn):
+        (WebInspector.ProfileDataGridNode.prototype._displayContent):
+        Use assumed main target and audit these when the Worker gets more Agents.
+
+        * UserInterface/Controllers/FrameResourceManager.js:
+        (WebInspector.FrameResourceManager.prototype._initiatorSourceCodeLocationFromPayload):
+        This will always be the main target because only the main target
+        has access to the DOM.
+
+        * UserInterface/Views/SourceCodeTextEditor.js:
+        (WebInspector.SourceCodeTextEditor.prototype.get target):
+        (WebInspector.SourceCodeTextEditor.prototype.customPerformSearch):
+        (WebInspector.SourceCodeTextEditor.prototype.textEditorGutterContextMenu):
+        (WebInspector.SourceCodeTextEditor.prototype._tokenTrackingControllerHighlightedJavaScriptExpression.populate):
+        (WebInspector.SourceCodeTextEditor.prototype._tokenTrackingControllerHighlightedJavaScriptExpression):
+        (WebInspector.SourceCodeTextEditor.prototype._showPopoverForFunction.didGetDetails):
+        (WebInspector.SourceCodeTextEditor.prototype._showPopoverForFunction):
+        Update target specific actions to use the proper target's agents.
+
+        * UserInterface/Views/TargetTreeElement.js: Added.
+        (WebInspector.TargetTreeElement):
+        (WebInspector.TargetTreeElement.prototype.get target):
+        (WebInspector.TargetTreeElement.prototype.onexpand):
+        (WebInspector.TargetTreeElement.prototype.oncollapse):
+        Add a new tree element for a Target. We currently assume that the
+        main resource for a Target will be a Script right now, as is the
+        case for Web Workers. This simply remembers its expanded or
+        collapsed state and has a better icon.
+
+        * UserInterface/Views/ResourceIcons.css:
+        (body:matches(.mac-platform, .windows-platform) .script.worker-icon .icon):
+        (body:matches(.mac-platform, .windows-platform) .large .script.worker-icon .icon):
+        * UserInterface/Images/WorkerScript.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocument.png.
+        * UserInterface/Images/WorkerScript@2x.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocument@2x.png.
+        * UserInterface/Images/WorkerScriptLarge.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocumentLarge.png.
+        * UserInterface/Images/WorkerScriptLarge@2x.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocumentLarge@2x.png.
+        Improve icon for a Worker's main resource script.
+
+        * UserInterface/Views/ResourceSidebarPanel.js:
+        (WebInspector.ResourceSidebarPanel):
+        (WebInspector.ResourceSidebarPanel.prototype._scriptWasAdded):
+        (WebInspector.ResourceSidebarPanel.prototype._scriptsCleared):
+        (WebInspector.ResourceSidebarPanel.prototype._addScriptForNonMainTarget):
+        (WebInspector.ResourceSidebarPanel.prototype._addTargetWithMainResource):
+        (WebInspector.ResourceSidebarPanel.prototype._targetRemoved):
+        * UserInterface/Views/SearchSidebarPanel.js:
+        (WebInspector.SearchSidebarPanel.prototype.performSearch.searchScripts):
+        (WebInspector.SearchSidebarPanel.prototype._searchTreeElementForScript):
+        * UserInterface/Views/OpenResourceDialog.js:
+        (WebInspector.OpenResourceDialog.prototype._populateResourceTreeOutline.createTreeElement):
+        (WebInspector.OpenResourceDialog.prototype._populateResourceTreeOutline):
+        (WebInspector.OpenResourceDialog.prototype.didDismissDialog):
+        (WebInspector.OpenResourceDialog.prototype.didPresentDialog):
+        (WebInspector.OpenResourceDialog.prototype._addResourcesForFrame):
+        (WebInspector.OpenResourceDialog.prototype._addScriptsForTarget):
+        (WebInspector.OpenResourceDialog.prototype._scriptAdded):
+        (WebInspector.OpenResourceDialog):
+        * UserInterface/Views/DebuggerSidebarPanel.js:
+        (WebInspector.DebuggerSidebarPanel.prototype._addTreeElementForSourceCodeToTreeOutline):
+        (WebInspector.DebuggerSidebarPanel.prototype._debuggerCallFramesDidChange):
+        (WebInspector.DebuggerSidebarPanel.prototype._debuggerActiveCallFrameDidChange):
+        (WebInspector.DebuggerSidebarPanel.prototype._updatePauseReasonSection):
+        Include scripts from non-main targets in sidebars.
+
 2016-11-01  Devin Rousso  <dcrousso+webkit@gmail.com>
 
         Web Inspector: Creating a new pseudo-selector in the Styles sidebar doesn't work on first attempt
index 4f66a79..21592d1 100644 (file)
@@ -2212,10 +2212,11 @@ WebInspector.linkifyElement = function(linkElement, sourceCodeLocation) {
     linkElement.addEventListener("click", showSourceCodeLocation.bind(this));
 };
 
-WebInspector.sourceCodeForURL = function(url) {
+WebInspector.sourceCodeForURL = function(url)
+{
     var sourceCode = WebInspector.frameResourceManager.resourceForURL(url);
     if (!sourceCode) {
-        sourceCode = WebInspector.debuggerManager.scriptsForURL(url)[0];
+        sourceCode = WebInspector.debuggerManager.scriptsForURL(url, WebInspector.assumingMainTarget())[0];
         if (sourceCode)
             sourceCode = sourceCode.resource || sourceCode;
     }
@@ -2527,6 +2528,15 @@ Object.defineProperty(WebInspector, "targets",
     get() { return this.targetManager.targets; }
 });
 
+// Many places assume the main target because they cannot yet be
+// used by reached by Worker debugging. Eventually, once all
+// Worker domains have been implemented, all of these must be
+// handled properly.
+WebInspector.assumingMainTarget = function()
+{
+    return WebInspector.mainTarget;
+}
+
 // OpenResourceDialog delegate
 
 WebInspector.dialogWasDismissed = function(dialog)
index 70a7b3e..2101b02 100644 (file)
@@ -45,6 +45,8 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
 
         WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
 
+        this._breakpointsSetting = new WebInspector.Setting("breakpoints", []);
+        this._breakpointsEnabledSetting = new WebInspector.Setting("breakpoints-enabled", true);
         this._allExceptionsBreakpointEnabledSetting = new WebInspector.Setting("break-on-all-exceptions", false);
         this._allUncaughtExceptionsBreakpointEnabledSetting = new WebInspector.Setting("break-on-all-uncaught-exceptions", false);
         this._assertionsBreakpointEnabledSetting = new WebInspector.Setting("break-on-assertions", false);
@@ -64,18 +66,16 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         this._breakpointScriptIdentifierMap = new Map;
         this._breakpointIdMap = new Map;
 
+        this._breakOnExceptionsState = "none";
+        this._updateBreakOnExceptionsState();
+
         this._nextBreakpointActionIdentifier = 1;
 
         this._paused = false;
-        this._pauseReason = null;
-        this._pauseData = null;
+        this._activeCallFrame = null;
 
         this._internalWebKitScripts = [];
-        this._scriptIdMap = new Map;
-        this._scriptContentIdentifierMap = new Map;
-
-        this._breakpointsSetting = new WebInspector.Setting("breakpoints", []);
-        this._breakpointsEnabledSetting = new WebInspector.Setting("breakpoints-enabled", true);
+        this._targetDebuggerDataMap = new Map;
 
         // Restore the correct breakpoints enabled setting if Web Inspector had
         // previously been left in a state where breakpoints were temporarily disabled.
@@ -86,8 +86,7 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         }
 
         DebuggerAgent.setBreakpointsActive(this._breakpointsEnabledSetting.value);
-
-        this._updateBreakOnExceptionsState();
+        DebuggerAgent.setPauseOnExceptions(this._breakOnExceptionsState);
 
         // COMPATIBILITY (iOS 10): DebuggerAgent.setPauseOnAssertions did not exist yet.
         if (DebuggerAgent.setPauseOnAssertions)
@@ -114,21 +113,6 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         return this._paused;
     }
 
-    get pauseReason()
-    {
-        return this._pauseReason;
-    }
-
-    get pauseData()
-    {
-        return this._pauseData;
-    }
-
-    get callFrames()
-    {
-        return this._callFrames;
-    }
-
     get activeCallFrame()
     {
         return this._activeCallFrame;
@@ -144,6 +128,17 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange);
     }
 
+    dataForTarget(target)
+    {
+        let targetData = this._targetDebuggerDataMap.get(target);
+        if (targetData)
+            return targetData;
+
+        targetData = new WebInspector.DebuggerData(target);
+        this._targetDebuggerDataMap.set(target, targetData);
+        return targetData;
+    }
+
     get allExceptionsBreakpoint()
     {
         return this._allExceptionsBreakpoint;
@@ -225,11 +220,14 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
 
         this._breakpointsEnabledSetting.value = enabled;
 
-        this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.BreakpointsEnabledDidChange);
+        this._updateBreakOnExceptionsState();
 
-        DebuggerAgent.setBreakpointsActive(enabled);
+        for (let target of WebInspector.targets) {
+            target.DebuggerAgent.setBreakpointsActive(enabled);
+            target.DebuggerAgent.setPauseOnExceptions(this._breakOnExceptionsState);
+        }
 
-        this._updateBreakOnExceptionsState();
+        this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.BreakpointsEnabledDidChange);
     }
 
     get breakpointsDisabledTemporarily()
@@ -237,15 +235,17 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         return this._temporarilyDisabledBreakpointsRestoreSetting.value !== null;
     }
 
-    scriptForIdentifier(id)
+    scriptForIdentifier(id, target)
     {
-        return this._scriptIdMap.get(id) || null;
+        console.assert(target instanceof WebInspector.Target);
+        return this.dataForTarget(target).scriptForIdentifier(id);
     }
 
-    scriptsForURL(url)
+    scriptsForURL(url, target)
     {
         // FIXME: This may not be safe. A Resource's URL may differ from a Script's URL.
-        return this._scriptContentIdentifierMap.get(url) || [];
+        console.assert(target instanceof WebInspector.Target);
+        return this.dataForTarget(target).scriptsForURL(url);
     }
 
     get searchableScripts()
@@ -256,12 +256,15 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
     get knownNonResourceScripts()
     {
         let knownScripts = [];
-        for (let script of this._scriptIdMap.values()) {
-            if (script.resource)
-                continue;
-            if (!WebInspector.isDebugUIEnabled() && isWebKitInternalScript(script.sourceURL))
-                continue;
-            knownScripts.push(script);
+
+        for (let [target, targetData] of this._targetDebuggerDataMap) {
+            for (let script of targetData.scripts) {
+                if (script.resource)
+                    continue;
+                if (!WebInspector.isDebugUIEnabled() && isWebKitInternalScript(script.sourceURL))
+                    continue;
+                knownScripts.push(script);
+            }
         }
 
         return knownScripts;
@@ -280,6 +283,9 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             listener.connect(WebInspector.debuggerManager, WebInspector.DebuggerManager.Event.Paused, resolve);
         });
 
+        // FIXME: <https://webkit.org/b/164305> Web Inspector: Worker debugging should pause all targets and view call frames in all targets
+        // We should pause all targets.
+
         let protocolResult = DebuggerAgent.pause()
             .catch(function(error) {
                 listener.disconnect();
@@ -301,7 +307,10 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             listener.connect(WebInspector.debuggerManager, WebInspector.DebuggerManager.Event.Resumed, resolve);
         });
 
-        let protocolResult = DebuggerAgent.resume()
+        // FIXME: <https://webkit.org/b/164305> Web Inspector: Worker debugging should pause all targets and view call frames in all targets
+        // We should resume all targets.
+
+        let protocolResult = this._activeCallFrame.target.DebuggerAgent.resume()
             .catch(function(error) {
                 listener.disconnect();
                 console.error("DebuggerManager.resume failed: ", error);
@@ -322,7 +331,7 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             listener.connect(WebInspector.debuggerManager, WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange, resolve);
         });
 
-        let protocolResult = DebuggerAgent.stepOver()
+        let protocolResult = this._activeCallFrame.target.DebuggerAgent.stepOver()
             .catch(function(error) {
                 listener.disconnect();
                 console.error("DebuggerManager.stepOver failed: ", error);
@@ -343,7 +352,7 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             listener.connect(WebInspector.debuggerManager, WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange, resolve);
         });
 
-        let protocolResult = DebuggerAgent.stepInto()
+        let protocolResult = this._activeCallFrame.target.DebuggerAgent.stepInto()
             .catch(function(error) {
                 listener.disconnect();
                 console.error("DebuggerManager.stepInto failed: ", error);
@@ -364,7 +373,7 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             listener.connect(WebInspector.debuggerManager, WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange, resolve);
         });
 
-        let protocolResult = DebuggerAgent.stepOut()
+        let protocolResult = this._activeCallFrame.target.DebuggerAgent.stepOut()
             .catch(function(error) {
                 listener.disconnect();
                 console.error("DebuggerManager.stepOut failed: ", error);
@@ -374,9 +383,9 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         return Promise.all([managerResult, protocolResult]);
     }
 
-    continueToLocation(scriptId, lineNumber, columnNumber)
+    continueToLocation(script, lineNumber, columnNumber)
     {
-        return DebuggerAgent.continueToLocation({scriptId, lineNumber, columnNumber});
+        return script.target.DebuggerAgent.continueToLocation({scriptId: script.id, lineNumber, columnNumber});
     }
 
     addBreakpoint(breakpoint, shouldSpeculativelyResolve)
@@ -406,7 +415,8 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         this._breakpoints.push(breakpoint);
 
         if (!breakpoint.disabled) {
-            this._setBreakpoint(breakpoint, () => {
+            const specificTarget = undefined;
+            this._setBreakpoint(breakpoint, specificTarget, () => {
                 if (shouldSpeculativelyResolve)
                     breakpoint.resolved = true;
             });
@@ -464,9 +474,34 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         return this._nextBreakpointActionIdentifier++;
     }
 
+    initializeTarget(target)
+    {
+        let DebuggerAgent = target.DebuggerAgent;
+
+        // Initialize global state.
+        DebuggerAgent.enable();
+        DebuggerAgent.setBreakpointsActive(this._breakpointsEnabledSetting.value);
+        DebuggerAgent.setPauseOnAssertions(this._assertionsBreakpointEnabledSetting.value);
+        DebuggerAgent.setPauseOnExceptions(this._breakOnExceptionsState);
+
+        // FIXME: <https://webkit.org/b/164305> Web Inspector: Worker debugging should pause all targets and view call frames in all targets
+        // Pause this Target if we are currently paused.
+
+        // Initialize breakpoints.
+        this._restoringBreakpoints = true;
+        for (let breakpoint of this._breakpoints) {
+            if (breakpoint.disabled)
+                continue;
+            if (!breakpoint.contentIdentifier)
+                continue;
+            this._setBreakpoint(breakpoint, target);
+        }
+        this._restoringBreakpoints = false;
+    }
+
     // Protected (Called from WebInspector.DebuggerObserver)
 
-    breakpointResolved(breakpointIdentifier, location)
+    breakpointResolved(target, breakpointIdentifier, location)
     {
         // Called from WebInspector.DebuggerObserver.
 
@@ -478,7 +513,7 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         console.assert(breakpoint.identifier === breakpointIdentifier);
 
         if (!breakpoint.sourceCodeLocation.sourceCode) {
-            let sourceCodeLocation = this._sourceCodeLocationFromPayload(location);
+            let sourceCodeLocation = this._sourceCodeLocationFromPayload(target, location);
             breakpoint.sourceCodeLocation.sourceCode = sourceCodeLocation.sourceCode;
         }
 
@@ -494,12 +529,9 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         WebInspector.Script.resetUniqueDisplayNameNumbers();
 
         this._paused = false;
-        this._pauseReason = null;
-        this._pauseData = null;
 
         this._internalWebKitScripts = [];
-        this._scriptIdMap.clear();
-        this._scriptContentIdentifierMap.clear();
+        this._targetDebuggerDataMap.clear();
 
         this._ignoreBreakpointDisplayLocationDidChangeEvent = true;
 
@@ -519,7 +551,7 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.Resumed);
     }
 
-    debuggerDidPause(callFramesPayload, reason, data)
+    debuggerDidPause(target, callFramesPayload, reason, data)
     {
         // Called from WebInspector.DebuggerObserver.
 
@@ -528,17 +560,17 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             this._delayedResumeTimeout = undefined;
         }
 
-        var wasStillPaused = this._paused;
+        let wasPaused = this._paused;
 
         this._paused = true;
-        this._callFrames = [];
 
-        this._pauseReason = this._pauseReasonFromPayload(reason);
-        this._pauseData = data || null;
+        let callFrames = [];
+        let pauseReason = this._pauseReasonFromPayload(reason);
+        let pauseData = data || null;
 
         for (var i = 0; i < callFramesPayload.length; ++i) {
             var callFramePayload = callFramesPayload[i];
-            var sourceCodeLocation = this._sourceCodeLocationFromPayload(callFramePayload.location);
+            var sourceCodeLocation = this._sourceCodeLocationFromPayload(target, callFramePayload.location);
             // FIXME: There may be useful call frames without a source code location (native callframes), should we include them?
             if (!sourceCodeLocation)
                 continue;
@@ -549,34 +581,39 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             if (!WebInspector.isDebugUIEnabled() && isWebKitInternalScript(sourceCodeLocation.sourceCode.sourceURL))
                 continue;
 
-            let scopeChain = this._scopeChainFromPayload(callFramePayload.scopeChain);
-            let callFrame = WebInspector.CallFrame.fromDebuggerPayload(callFramePayload, scopeChain, sourceCodeLocation);
-            this._callFrames.push(callFrame);
+            let scopeChain = this._scopeChainFromPayload(target, callFramePayload.scopeChain);
+            let callFrame = WebInspector.CallFrame.fromDebuggerPayload(target, callFramePayload, scopeChain, sourceCodeLocation);
+            callFrames.push(callFrame);
         }
 
-        this._activeCallFrame = this._callFrames[0];
+        let activeCallFrame = callFrames[0];
 
-        if (!this._activeCallFrame) {
+        if (!activeCallFrame) {
             // This indicates we were pausing in internal scripts only (Injected Scripts, built-ins).
             // Just resume and skip past this pause.
-            DebuggerAgent.resume();
-            this._didResumeInternal();
+            target.DebuggerAgent.resume();
+            this._didResumeInternal(target);
             return;
         }
 
-        if (!wasStillPaused)
+        let targetData = this._targetDebuggerDataMap.get(target);
+        targetData.updateForPause(callFrames, pauseReason, pauseData);
+
+        this._activeCallFrame = activeCallFrame;
+
+        if (!wasPaused)
             this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.Paused);
         this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.CallFramesDidChange);
         this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange);
     }
 
-    debuggerDidResume()
+    debuggerDidResume(target)
     {
         // Called from WebInspector.DebuggerObserver.
 
         // We delay clearing the state and firing events so the user interface does not flash
         // between brief steps or successive breakpoints.
-        this._delayedResumeTimeout = setTimeout(this._didResumeInternal.bind(this), 50);
+        this._delayedResumeTimeout = setTimeout(this._didResumeInternal.bind(this, target), 50);
     }
 
     playBreakpointActionSound(breakpointActionIdentifier)
@@ -586,37 +623,34 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         InspectorFrontendHost.beep();
     }
 
-    scriptDidParse(scriptIdentifier, url, startLine, startColumn, endLine, endColumn, isContentScript, sourceURL, sourceMapURL)
+    scriptDidParse(target, scriptIdentifier, url, startLine, startColumn, endLine, endColumn, isContentScript, sourceURL, sourceMapURL)
     {
         // Called from WebInspector.DebuggerObserver.
 
         // Don't add the script again if it is already known.
-        if (this._scriptIdMap.has(scriptIdentifier)) {
-            const script = this._scriptIdMap.get(scriptIdentifier);
-            console.assert(script.url === (url || null));
-            console.assert(script.range.startLine === startLine);
-            console.assert(script.range.startColumn === startColumn);
-            console.assert(script.range.endLine === endLine);
-            console.assert(script.range.endColumn === endColumn);
+        let targetData = this.dataForTarget(target);
+        let existingScript = targetData.scriptForIdentifier(scriptIdentifier);
+        if (existingScript) {
+            console.assert(existingScript.url === (url || null));
+            console.assert(existingScript.range.startLine === startLine);
+            console.assert(existingScript.range.startColumn === startColumn);
+            console.assert(existingScript.range.endLine === endLine);
+            console.assert(existingScript.range.endColumn === endColumn);
             return;
         }
 
         if (!WebInspector.isDebugUIEnabled() && isWebKitInternalScript(sourceURL))
             return;
 
-        let script = new WebInspector.Script(scriptIdentifier, new WebInspector.TextRange(startLine, startColumn, endLine, endColumn), url, isContentScript, sourceURL, sourceMapURL);
+        let script = new WebInspector.Script(target, scriptIdentifier, new WebInspector.TextRange(startLine, startColumn, endLine, endColumn), url, isContentScript, sourceURL, sourceMapURL);
 
-        this._scriptIdMap.set(scriptIdentifier, script);
-
-        if (script.contentIdentifier) {
-            let scripts = this._scriptContentIdentifierMap.get(script.contentIdentifier);
-            if (!scripts) {
-                scripts = [];
-                this._scriptContentIdentifierMap.set(script.contentIdentifier, scripts);
-            }
-            scripts.push(script);
+        if (!target.mainResource && target.type === WebInspector.Target.Type.Worker) {
+            if (script.url === target.name)
+                target.mainResource = script;
         }
 
+        targetData.addScript(script);
+
         if (isWebKitInternalScript(script.sourceURL)) {
             this._internalWebKitScripts.push(script);
             if (!WebInspector.isDebugUIEnabled())
@@ -632,24 +666,25 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
 
     // Private
 
-    _sourceCodeLocationFromPayload(payload)
+    _sourceCodeLocationFromPayload(target, payload)
     {
-        let script = this._scriptIdMap.get(payload.scriptId);
+        let targetData = this.dataForTarget(target);
+        let script = targetData.scriptForIdentifier(payload.scriptId);
         if (!script)
             return null;
 
         return script.createSourceCodeLocation(payload.lineNumber, payload.columnNumber);
     }
 
-    _scopeChainFromPayload(payload)
+    _scopeChainFromPayload(target, payload)
     {
-        var scopeChain = [];
-        for (var i = 0; i < payload.length; ++i)
-            scopeChain.push(this._scopeChainNodeFromPayload(payload[i]));
+        let scopeChain = [];
+        for (let i = 0; i < payload.length; ++i)
+            scopeChain.push(this._scopeChainNodeFromPayload(target, payload[i]));
         return scopeChain;
     }
 
-    _scopeChainNodeFromPayload(payload)
+    _scopeChainNodeFromPayload(target, payload)
     {
         var type = null;
         switch (payload.type) {
@@ -686,7 +721,7 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             console.error("Unknown type: " + payload.type);
         }
 
-        let object = WebInspector.RemoteObject.fromPayload(payload.object);
+        let object = WebInspector.RemoteObject.fromPayload(payload.object, target);
         return new WebInspector.ScopeChainNode(type, [object], payload.name, payload.location, payload.empty);
     }
 
@@ -728,12 +763,11 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         }
     }
 
-    _setBreakpoint(breakpoint, callback)
+    _setBreakpoint(breakpoint, specificTarget, callback)
     {
-        console.assert(!breakpoint.identifier);
         console.assert(!breakpoint.disabled);
 
-        if (breakpoint.identifier || breakpoint.disabled)
+        if (breakpoint.disabled)
             return;
 
         if (!this._restoringBreakpoints && !this.breakpointsDisabledTemporarily) {
@@ -742,7 +776,7 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             this.breakpointsEnabled = true;
         }
 
-        function didSetBreakpoint(error, breakpointIdentifier, locations)
+        function didSetBreakpoint(target, error, breakpointIdentifier, locations)
         {
             if (error)
                 return;
@@ -756,7 +790,7 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
                 locations = [locations];
 
             for (let location of locations)
-                this.breakpointResolved(breakpointIdentifier, location);
+                this.breakpointResolved(target, breakpointIdentifier, location);
 
             if (typeof callback === "function")
                 callback();
@@ -764,37 +798,43 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
 
         // The breakpoint will be resolved again by calling DebuggerAgent, so mark it as unresolved.
         // If something goes wrong it will stay unresolved and show up as such in the user interface.
-        breakpoint.resolved = false;
+        // When setting for a new target, don't change the resolved target.
+        if (!specificTarget)
+            breakpoint.resolved = false;
 
         // Convert BreakpointAction types to DebuggerAgent protocol types.
         // NOTE: Breakpoint.options returns new objects each time, so it is safe to modify.
         // COMPATIBILITY (iOS 7): Debugger.BreakpointActionType did not exist yet.
-        var options;
+        let options;
         if (DebuggerAgent.BreakpointActionType) {
             options = breakpoint.options;
             if (options.actions.length) {
-                for (var i = 0; i < options.actions.length; ++i)
-                    options.actions[i].type = this._debuggerBreakpointActionType(options.actions[i].type);
+                for (let action of options.actions)
+                    action.type = this._debuggerBreakpointActionType(action.type);
             }
         }
 
         // COMPATIBILITY (iOS 7): iOS 7 and earlier, DebuggerAgent.setBreakpoint* took a "condition" string argument.
         // This has been replaced with an "options" BreakpointOptions object.
         if (breakpoint.contentIdentifier) {
-            DebuggerAgent.setBreakpointByUrl.invoke({
-                lineNumber: breakpoint.sourceCodeLocation.lineNumber,
-                url: breakpoint.contentIdentifier,
-                urlRegex: undefined,
-                columnNumber: breakpoint.sourceCodeLocation.columnNumber,
-                condition: breakpoint.condition,
-                options
-            }, didSetBreakpoint.bind(this));
+            let targets = specificTarget ? [specificTarget] : WebInspector.targets;
+            for (let target of targets) {
+                target.DebuggerAgent.setBreakpointByUrl.invoke({
+                    lineNumber: breakpoint.sourceCodeLocation.lineNumber,
+                    url: breakpoint.contentIdentifier,
+                    urlRegex: undefined,
+                    columnNumber: breakpoint.sourceCodeLocation.columnNumber,
+                    condition: breakpoint.condition,
+                    options
+                }, didSetBreakpoint.bind(this, target), target.DebuggerAgent);
+            }
         } else if (breakpoint.scriptIdentifier) {
-            DebuggerAgent.setBreakpoint.invoke({
+            let target = breakpoint.target;
+            target.DebuggerAgent.setBreakpoint.invoke({
                 location: {scriptId: breakpoint.scriptIdentifier, lineNumber: breakpoint.sourceCodeLocation.lineNumber, columnNumber: breakpoint.sourceCodeLocation.columnNumber},
                 condition: breakpoint.condition,
                 options
-            }, didSetBreakpoint.bind(this));
+            }, didSetBreakpoint.bind(this, target), target.DebuggerAgent);
         }
     }
 
@@ -819,7 +859,12 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
                 callback();
         }
 
-        DebuggerAgent.removeBreakpoint(breakpoint.identifier, didRemoveBreakpoint.bind(this));
+        if (breakpoint.target)
+            breakpoint.target.DebuggerAgent.removeBreakpoint(breakpoint.identifier, didRemoveBreakpoint.bind(this));
+        else {
+            for (let target of WebInspector.targets)
+                target.DebuggerAgent.removeBreakpoint(breakpoint.identifier, didRemoveBreakpoint.bind(this));
+        }
     }
 
     _breakpointDisplayLocationDidChange(event)
@@ -853,6 +898,8 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
                 this.breakpointsEnabled = true;
             this._allExceptionsBreakpointEnabledSetting.value = !breakpoint.disabled;
             this._updateBreakOnExceptionsState();
+            for (let target of WebInspector.targets)
+                target.DebuggerAgent.setPauseOnExceptions(this._breakOnExceptionsState);
             return;
         }
 
@@ -861,6 +908,8 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
                 this.breakpointsEnabled = true;
             this._allUncaughtExceptionsBreakpointEnabledSetting.value = !breakpoint.disabled;
             this._updateBreakOnExceptionsState();
+            for (let target of WebInspector.targets)
+                target.DebuggerAgent.setPauseOnExceptions(this._breakOnExceptionsState);
             return;
         }
 
@@ -868,7 +917,8 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             if (!breakpoint.disabled && !this.breakpointsDisabledTemporarily)
                 this.breakpointsEnabled = true;
             this._assertionsBreakpointEnabledSetting.value = !breakpoint.disabled;
-            DebuggerAgent.setPauseOnAssertions(this._assertionsBreakpointEnabledSetting.value);
+            for (let target of WebInspector.targets)
+                target.DebuggerAgent.setPauseOnAssertions(this._assertionsBreakpointEnabledSetting.value);
             return;
         }
 
@@ -941,10 +991,10 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         if (!event.target.isMainFrame())
             return;
 
-        this._didResumeInternal();
+        this._didResumeInternal(WebInspector.mainTarget);
     }
 
-    _didResumeInternal()
+    _didResumeInternal(target)
     {
         if (!this._paused)
             return;
@@ -955,9 +1005,10 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
         }
 
         this._paused = false;
-        this._callFrames = null;
         this._activeCallFrame = null;
 
+        this.dataForTarget(target).updateForResume();
+
         this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.Resumed);
         this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.CallFramesDidChange);
         this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange);
@@ -974,6 +1025,8 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
                 state = "uncaught";
         }
 
+        this._breakOnExceptionsState = state;
+
         switch (state) {
         case "all":
             // Mark the uncaught breakpoint as unresolved since "all" includes "uncaught".
@@ -986,8 +1039,6 @@ WebInspector.DebuggerManager = class DebuggerManager extends WebInspector.Object
             this._allUncaughtExceptionsBreakpoint.resolved = true;
             break;
         }
-
-        DebuggerAgent.setPauseOnExceptions(state);
     }
 
     _saveBreakpoints()
index 57602ba..8b731d7 100644 (file)
@@ -485,7 +485,7 @@ WebInspector.FrameResourceManager = class FrameResourceManager extends WebInspec
 
         var sourceCode = WebInspector.frameResourceManager.resourceForURL(url);
         if (!sourceCode)
-            sourceCode = WebInspector.debuggerManager.scriptsForURL(url)[0];
+            sourceCode = WebInspector.debuggerManager.scriptsForURL(url, WebInspector.mainTarget)[0];
 
         if (!sourceCode)
             return null;
index 72db7e4..134b2f0 100644 (file)
@@ -223,8 +223,11 @@ WebInspector.JavaScriptRuntimeCompletionProvider = class JavaScriptRuntimeComple
 
             if (!base) {
                 var commandLineAPI = ["$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners", "$0", "$_"];
-                if (WebInspector.debuggerManager.paused && WebInspector.debuggerManager.pauseReason === WebInspector.DebuggerManager.PauseReason.Exception)
-                    commandLineAPI.push("$exception");
+                if (WebInspector.debuggerManager.paused) {
+                    let targetData = WebInspector.debuggerManager.dataForTarget(WebInspector.runtimeManager.activeExecutionContext.target);
+                    if (targetData.pauseReason === WebInspector.DebuggerManager.PauseReason.Exception)
+                        commandLineAPI.push("$exception");
+                }
                 for (var i = 0; i < commandLineAPI.length; ++i)
                     propertyNames[commandLineAPI[i]] = true;
 
index d5e43d3..b7f100f 100644 (file)
@@ -60,12 +60,13 @@ WebInspector.ProbeManager = class ProbeManager extends WebInspector.Object
 
     // Protected (called by WebInspector.DebuggerObserver)
 
-    didSampleProbe(sample)
+    didSampleProbe(target, sample)
     {
         console.assert(this._probesByIdentifier.has(sample.probeId), "Unknown probe identifier specified for sample: ", sample);
-        var probe = this._probesByIdentifier.get(sample.probeId);
-        var elapsedTime = WebInspector.timelineManager.computeElapsedTime(sample.timestamp);
-        probe.addSample(new WebInspector.ProbeSample(sample.sampleId, sample.batchId, elapsedTime, sample.payload));
+        let probe = this._probesByIdentifier.get(sample.probeId);
+        let elapsedTime = WebInspector.timelineManager.computeElapsedTime(sample.timestamp);
+        let object = WebInspector.RemoteObject.fromPayload(sample.payload, target);
+        probe.addSample(new WebInspector.ProbeSample(sample.sampleId, sample.batchId, elapsedTime, object));
     }
 
     // Private
index 17326c6..b8c4fe4 100644 (file)
@@ -81,6 +81,11 @@ WebInspector.RuntimeManager = class RuntimeManager extends WebInspector.Object
         let target = this._activeExecutionContext.target;
         let executionContextId = this._activeExecutionContext.id;
 
+        if (WebInspector.debuggerManager.activeCallFrame) {
+            target = WebInspector.debuggerManager.activeCallFrame.target;
+            executionContextId = target.executionContext.id;
+        }
+
         function evalCallback(error, result, wasThrown, savedResultIndex)
         {
             this.dispatchEventToListeners(WebInspector.RuntimeManager.Event.DidEvaluate, {objectGroup});
@@ -99,7 +104,7 @@ WebInspector.RuntimeManager = class RuntimeManager extends WebInspector.Object
 
         if (WebInspector.debuggerManager.activeCallFrame) {
             // COMPATIBILITY (iOS 8): "saveResult" did not exist.
-            DebuggerAgent.evaluateOnCallFrame.invoke({callFrameId: WebInspector.debuggerManager.activeCallFrame.id, expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, saveResult}, evalCallback.bind(this));
+            target.DebuggerAgent.evaluateOnCallFrame.invoke({callFrameId: WebInspector.debuggerManager.activeCallFrame.id, expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, saveResult}, evalCallback.bind(this), target.DebuggerAgent);
             return;
         }
 
index dac3faa..9c5925d 100644 (file)
@@ -684,7 +684,7 @@ WebInspector.TimelineManager = class TimelineManager extends WebInspector.Object
         if (!payload)
             return null;
 
-        return payload.map(WebInspector.CallFrame.fromPayload);
+        return payload.map((x) => WebInspector.CallFrame.fromPayload(WebInspector.assumingMainTarget(), x));
     }
 
     _addRecord(record)
index 7b98bb3..f15ace2 100644 (file)
     <script src="Models/DatabaseObject.js"></script>
     <script src="Models/DatabaseTableObject.js"></script>
     <script src="Models/DebuggerDashboard.js"></script>
+    <script src="Models/DebuggerData.js"></script>
     <script src="Models/DefaultDashboard.js"></script>
     <script src="Models/ExecutionContext.js"></script>
     <script src="Models/ExecutionContextList.js"></script>
     <script src="Models/ProfileNodeCall.js"></script>
     <script src="Models/PropertyDescriptor.js"></script>
     <script src="Models/PropertyPath.js"></script>
-    <script src="Models/PropertyPreview.js"></script>    
+    <script src="Models/PropertyPreview.js"></script>
     <script src="Models/RenderingFrameTimelineRecord.js"></script>
     <script src="Models/ReplayDashboard.js"></script>
     <script src="Models/ReplaySession.js"></script>
     <script src="Views/StackedLineChart.js"></script>
     <script src="Views/StorageSidebarPanel.js"></script>
     <script src="Views/SyntaxHighlightingSupport.js"></script>
+    <script src="Views/TargetTreeElement.js"></script>
     <script src="Views/TextContentView.js"></script>
     <script src="Views/TextNavigationItem.js"></script>
     <script src="Views/TextResourceContentView.js"></script>
index f02f7df..03f85de 100644 (file)
@@ -33,6 +33,7 @@ WebInspector.Breakpoint = class Breakpoint extends WebInspector.Object
             var sourceCode = sourceCodeLocationOrInfo.sourceCode;
             var contentIdentifier = sourceCode ? sourceCode.contentIdentifier : null;
             var scriptIdentifier = sourceCode instanceof WebInspector.Script ? sourceCode.id : null;
+            var target = sourceCode instanceof WebInspector.Script ? sourceCode.target : null;
             var location = sourceCodeLocationOrInfo;
         } else if (sourceCodeLocationOrInfo && typeof sourceCodeLocationOrInfo === "object") {
             // The 'url' fallback is for transitioning from older frontends and should be removed.
@@ -53,6 +54,7 @@ WebInspector.Breakpoint = class Breakpoint extends WebInspector.Object
         this._id = null;
         this._contentIdentifier = contentIdentifier || null;
         this._scriptIdentifier = scriptIdentifier || null;
+        this._target = target || null;
         this._disabled = disabled || false;
         this._condition = condition || "";
         this._ignoreCount = ignoreCount || 0;
@@ -87,6 +89,11 @@ WebInspector.Breakpoint = class Breakpoint extends WebInspector.Object
         return this._scriptIdentifier;
     }
 
+    get target()
+    {
+        return this._target;
+    }
+
     get sourceCodeLocation()
     {
         return this._sourceCodeLocation;
@@ -195,7 +202,7 @@ WebInspector.Breakpoint = class Breakpoint extends WebInspector.Object
 
     get info()
     {
-        // The id, scriptIdentifier and resolved state are tied to the current session, so don't include them for serialization.
+        // The id, scriptIdentifier, target, and resolved state are tied to the current session, so don't include them for serialization.
         return {
             contentIdentifier: this._contentIdentifier,
             lineNumber: this._sourceCodeLocation.lineNumber,
index c6c0249..67778a6 100644 (file)
 
 WebInspector.CallFrame = class CallFrame extends WebInspector.Object
 {
-    constructor(id, sourceCodeLocation, functionName, thisObject, scopeChain, nativeCode, programCode, isTailDeleted)
+    constructor(target, id, sourceCodeLocation, functionName, thisObject, scopeChain, nativeCode, programCode, isTailDeleted)
     {
         super();
 
+        console.assert(target instanceof WebInspector.Target);
         console.assert(!sourceCodeLocation || sourceCodeLocation instanceof WebInspector.SourceCodeLocation);
         console.assert(!thisObject || thisObject instanceof WebInspector.RemoteObject);
         console.assert(!scopeChain || scopeChain instanceof Array);
 
+        this._target = target;
         this._id = id || null;
         this._sourceCodeLocation = sourceCodeLocation || null;
         this._functionName = functionName || "";
@@ -45,6 +47,7 @@ WebInspector.CallFrame = class CallFrame extends WebInspector.Object
 
     // Public
 
+    get target() { return this._target; }
     get id() { return this._id; }
     get sourceCodeLocation() { return this._sourceCodeLocation; }
     get functionName() { return this._functionName; }
@@ -193,10 +196,10 @@ WebInspector.CallFrame = class CallFrame extends WebInspector.Object
         return payload.functionName.endsWith(" code");
     }
 
-    static fromDebuggerPayload(payload, scopeChain, sourceCodeLocation)
+    static fromDebuggerPayload(target, payload, scopeChain, sourceCodeLocation)
     {
         let id = payload.callFrameId;
-        let thisObject = WebInspector.RemoteObject.fromPayload(payload.this);
+        let thisObject = WebInspector.RemoteObject.fromPayload(payload.this, target);
         let functionName = WebInspector.CallFrame.functionNameFromPayload(payload);
         let nativeCode = false;
         let programCode = WebInspector.CallFrame.programCodeFromPayload(payload);
@@ -207,10 +210,10 @@ WebInspector.CallFrame = class CallFrame extends WebInspector.Object
             programCode = true;
         }
 
-        return new WebInspector.CallFrame(id, sourceCodeLocation, functionName, thisObject, scopeChain, nativeCode, programCode, isTailDeleted);
+        return new WebInspector.CallFrame(target, id, sourceCodeLocation, functionName, thisObject, scopeChain, nativeCode, programCode, isTailDeleted);
     }
 
-    static fromPayload(payload)
+    static fromPayload(target, payload)
     {
         console.assert(payload);
 
@@ -226,14 +229,14 @@ WebInspector.CallFrame = class CallFrame extends WebInspector.Object
         } else if (url || scriptId) {
             let sourceCode = null;
             if (scriptId) {
-                sourceCode = WebInspector.debuggerManager.scriptForIdentifier(scriptId);
+                sourceCode = WebInspector.debuggerManager.scriptForIdentifier(scriptId, target);
                 if (sourceCode && sourceCode.resource)
                     sourceCode = sourceCode.resource;
             }
             if (!sourceCode)
                 sourceCode = WebInspector.frameResourceManager.resourceForURL(url);
             if (!sourceCode)
-                sourceCode = WebInspector.debuggerManager.scriptsForURL(url)[0];
+                sourceCode = WebInspector.debuggerManager.scriptsForURL(url, target)[0];
 
             if (sourceCode) {
                 // The lineNumber is 1-based, but we expect 0-based.
@@ -252,6 +255,6 @@ WebInspector.CallFrame = class CallFrame extends WebInspector.Object
             programCode = true;
         }
 
-        return new WebInspector.CallFrame(null, sourceCodeLocation, functionName, null, null, nativeCode, programCode);
+        return new WebInspector.CallFrame(target, null, sourceCodeLocation, functionName, null, null, nativeCode, programCode);
     }
 };
index 9a8c736..bd0d6c2 100644 (file)
@@ -49,7 +49,7 @@ WebInspector.ConsoleMessage = class ConsoleMessage extends WebInspector.Object
         this._repeatCount = repeatCount || 0;
         this._parameters = parameters;
 
-        this._stackTrace = WebInspector.StackTrace.fromPayload(stackTrace || []);
+        this._stackTrace = WebInspector.StackTrace.fromPayload(this._target, stackTrace || []);
 
         this._request = request;
     }
diff --git a/Source/WebInspectorUI/UserInterface/Models/DebuggerData.js b/Source/WebInspectorUI/UserInterface/Models/DebuggerData.js
new file mode 100644 (file)
index 0000000..79ccf52
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.DebuggerData = class DebuggerData extends WebInspector.Object
+{
+    constructor(target)
+    {
+        super();
+
+        console.assert(target instanceof WebInspector.Target);
+
+        this._target = target;
+
+        this._callFrames = [];
+        this._pauseReason = null;
+        this._pauseData = null;
+
+        this._scriptIdMap = new Map;
+        this._scriptContentIdentifierMap = new Map;
+    }
+
+    // Public
+
+    get target() { return this._target; }
+    get callFrames() { return this._callFrames; }
+    get pauseReason() { return this._pauseReason; }
+    get pauseData() { return this._pauseData; }
+
+    get scripts()
+    {
+        return Array.from(this._scriptIdMap.values());
+    }
+
+    scriptForIdentifier(id)
+    {
+        return this._scriptIdMap.get(id);
+    }
+
+    scriptsForURL(url)
+    {
+        return this._scriptContentIdentifierMap.get(url) || [];
+    }
+
+    // Protected (Called by DebuggerManager)
+
+    reset()
+    {
+        this._scriptIdMap.clear();
+    }
+
+    addScript(script)
+    {
+        this._scriptIdMap.set(script.id, script);
+
+        if (script.contentIdentifier) {
+            let scripts = this._scriptContentIdentifierMap.get(script.contentIdentifier);
+            if (!scripts) {
+                scripts = [];
+                this._scriptContentIdentifierMap.set(script.contentIdentifier, scripts);
+            }
+            scripts.push(script);
+        }
+    }
+
+    updateForPause(callFrames, pauseReason, pauseData)
+    {
+        this._callFrames = callFrames;
+        this._pauseReason = pauseReason;
+        this._pauseData = pauseData;
+    }
+
+    updateForResume()
+    {
+        this._callFrames = [];
+        this._pauseReason = null;
+        this._pauseData = null;
+    }
+};
index 45bd5d6..a6ee37a 100644 (file)
 
 WebInspector.ProbeSample = class ProbeSample extends WebInspector.Object
 {
-    constructor(sampleId, batchId, elapsedTime, payload)
+    constructor(sampleId, batchId, elapsedTime, object)
     {
         super();
 
+        console.assert(object instanceof WebInspector.RemoteObject);
+
         this.sampleId = sampleId;
         this.batchId = batchId;
         this.timestamp = elapsedTime;
-        this.object = WebInspector.RemoteObject.fromPayload(payload);
+        this.object = object;
     }
 };
 
index db4180a..42022c5 100644 (file)
 
 WebInspector.Script = class Script extends WebInspector.SourceCode
 {
-    constructor(id, range, url, injected, sourceURL, sourceMapURL)
+    constructor(target, id, range, url, injected, sourceURL, sourceMapURL)
     {
         super();
 
         console.assert(id);
+        console.assert(target instanceof WebInspector.Target);
         console.assert(range instanceof WebInspector.TextRange);
 
+        this._target = target;
         this._id = id || null;
         this._range = range || null;
         this._url = url || null;
@@ -75,6 +77,11 @@ WebInspector.Script = class Script extends WebInspector.SourceCode
 
     // Public
 
+    get target()
+    {
+        return this._target;
+    }
+
     get id()
     {
         return this._id;
@@ -197,6 +204,11 @@ WebInspector.Script = class Script extends WebInspector.SourceCode
         return this._scriptSyntaxTree;
     }
 
+    isMainResource()
+    {
+        return this._target.mainResource === this;
+    }
+
     requestContentFromBackend()
     {
         if (!this._id) {
@@ -205,7 +217,7 @@ WebInspector.Script = class Script extends WebInspector.SourceCode
             return Promise.reject(new Error("There is no identifier to request content with."));
         }
 
-        return DebuggerAgent.getScriptSource(this._id);
+        return this._target.DebuggerAgent.getScriptSource(this._id);
     }
 
     saveIdentityToCookie(cookie)
@@ -254,6 +266,10 @@ WebInspector.Script = class Script extends WebInspector.SourceCode
         if (!this._url)
             return null;
 
+        // Only associate Scripts on the Page with Resources on the Page.
+        if (this._target !== WebInspector.mainTarget)
+            return null;
+
         try {
             // Try with the Script's full URL.
             var resource = WebInspector.frameResourceManager.resourceForURL(this.url);
index b117271..4a4231d 100644 (file)
@@ -113,7 +113,7 @@ WebInspector.ScriptTimelineRecord = class ScriptTimelineRecord extends WebInspec
             if (nodePayload.url) {
                 var sourceCode = WebInspector.frameResourceManager.resourceForURL(nodePayload.url);
                 if (!sourceCode)
-                    sourceCode = WebInspector.debuggerManager.scriptsForURL(nodePayload.url)[0];
+                    sourceCode = WebInspector.debuggerManager.scriptsForURL(nodePayload.url, WebInspector.assumingMainTarget())[0];
 
                 // The lineNumber is 1-based, but we expect 0-based.
                 var lineNumber = nodePayload.lineNumber - 1;
index 77da9c3..e38134b 100644 (file)
@@ -36,16 +36,16 @@ WebInspector.StackTrace = class StackTrace extends WebInspector.Object
 
     // Static
 
-    static fromPayload(payload)
+    static fromPayload(target, payload)
     {
-        var callFrames = payload.map(WebInspector.CallFrame.fromPayload);
+        let callFrames = payload.map((x) => WebInspector.CallFrame.fromPayload(target, x));
         return new WebInspector.StackTrace(callFrames);
     }
 
-    static fromString(stack)
+    static fromString(target, stack)
     {
-        var payload = WebInspector.StackTrace._parseStackTrace(stack);
-        return WebInspector.StackTrace.fromPayload(payload);
+        let payload = WebInspector.StackTrace._parseStackTrace(stack);
+        return WebInspector.StackTrace.fromPayload(target, payload);
     }
 
     // May produce false negatives; must not produce any false positives.
index 3d2ba26..8e2bd66 100644 (file)
@@ -296,7 +296,7 @@ InspectorBackend.WorkerConnection = class InspectorBackendWorkerConnection exten
         this._workerId = workerId;
 
         // FIXME: Get this list from generated InspectorBackendCommands / InspectorBackend.
-        const workerDomains = ["Runtime", "Console"];
+        const workerDomains = ["Runtime", "Console", "Debugger"];
 
         for (let domain of workerDomains) {
             let agent = InspectorBackend._agents[domain];
index c3583cf..092d77b 100644 (file)
@@ -46,11 +46,11 @@ WebInspector.DebuggerObserver = class DebuggerObserver
             let legacySourceMapURL = arguments[7];
             let hasSourceURL = arguments[8];
             let legacySourceURL = hasSourceURL ? url : undefined;
-            WebInspector.debuggerManager.scriptDidParse(scriptId, url, startLine, startColumn, endLine, endColumn, isContentScript, legacySourceURL, legacySourceMapURL);
+            WebInspector.debuggerManager.scriptDidParse(this.target, scriptId, url, startLine, startColumn, endLine, endColumn, isContentScript, legacySourceURL, legacySourceMapURL);
             return;
         }
 
-        WebInspector.debuggerManager.scriptDidParse(scriptId, url, startLine, startColumn, endLine, endColumn, isContentScript, sourceURL, sourceMapURL);
+        WebInspector.debuggerManager.scriptDidParse(this.target, scriptId, url, startLine, startColumn, endLine, endColumn, isContentScript, sourceURL, sourceMapURL);
     }
 
     scriptFailedToParse(url, scriptSource, startLine, errorLine, errorMessage)
@@ -60,17 +60,17 @@ WebInspector.DebuggerObserver = class DebuggerObserver
 
     breakpointResolved(breakpointId, location)
     {
-        WebInspector.debuggerManager.breakpointResolved(breakpointId, location);
+        WebInspector.debuggerManager.breakpointResolved(this.target, breakpointId, location);
     }
 
     paused(callFrames, reason, data)
     {
-        WebInspector.debuggerManager.debuggerDidPause(callFrames, reason, data);
+        WebInspector.debuggerManager.debuggerDidPause(this.target, callFrames, reason, data);
     }
 
     resumed()
     {
-        WebInspector.debuggerManager.debuggerDidResume();
+        WebInspector.debuggerManager.debuggerDidResume(this.target);
     }
 
     playBreakpointActionSound(breakpointActionIdentifier)
@@ -80,6 +80,6 @@ WebInspector.DebuggerObserver = class DebuggerObserver
 
     didSampleProbe(sample)
     {
-        WebInspector.probeManager.didSampleProbe(sample);
+        WebInspector.probeManager.didSampleProbe(this.target, sample);
     }
 };
index 418e0ac..f4c99fb 100644 (file)
@@ -520,14 +520,14 @@ WebInspector.RemoteObject = class RemoteObject
             return result.promise;
         }
 
-        DebuggerAgent.getFunctionDetails(this._objectId, function(error, response) {
+        this._target.DebuggerAgent.getFunctionDetails(this._objectId, (error, response) => {
             if (error) {
                 result.reject(error);
                 return;
             }
 
             var location = response.location;
-            var sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId);
+            var sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId, this._target);
 
             if (!sourceCode || (!WebInspector.isDebugUIEnabled() && isWebKitInternalScript(sourceCode.sourceURL))) {
                 result.resolve(WebInspector.RemoteObject.SourceCodeLocationPromise.NoSourceFound);
index 4e4b8c2..c6af80b 100644 (file)
@@ -33,6 +33,7 @@ WebInspector.Target = class Target extends WebInspector.Object
         this._type = type;
         this._connection = connection;
         this._executionContext = null;
+        this._mainResource = null;
 
         this._connection.target = this;
 
@@ -43,6 +44,7 @@ WebInspector.Target = class Target extends WebInspector.Object
 
     get RuntimeAgent() { return this._connection._agents.Runtime; }
     get ConsoleAgent() { return this._connection._agents.Console; }
+    get DebuggerAgent() { return this._connection._agents.Debugger; }
 
     // Public
 
@@ -50,6 +52,9 @@ WebInspector.Target = class Target extends WebInspector.Object
     get type() { return this._type; }
     get connection() { return this._connection; }
     get executionContext() { return this._executionContext; }
+
+    get mainResource() { return this._mainResource; }
+    set mainResource(resource) { this._mainResource = resource; }
 };
 
 WebInspector.Target.Type = {
@@ -98,8 +103,13 @@ WebInspector.WorkerTarget = class WorkerTarget extends WebInspector.Target
         if (this.RuntimeAgent) {
             this.RuntimeAgent.enable();
             this._executionContext = new WebInspector.ExecutionContext(this, WebInspector.RuntimeManager.TopLevelContextExecutionIdentifier, this.displayName, false, null);
+            // FIXME: Enable Type Profiler
+            // FIXME: Enable Code Coverage Profiler
         }
 
+        if (this.DebuggerAgent)
+            WebInspector.debuggerManager.initializeTarget(this);
+
         if (this.ConsoleAgent)
             this.ConsoleAgent.enable();
     }
index 7d905a4..f466365 100644 (file)
     <script src="Models/DOMNodeStyles.js"></script>
     <script src="Models/DOMStorageObject.js"></script>
     <script src="Models/DOMTree.js"></script>
+    <script src="Models/DebuggerData.js"></script>
     <script src="Models/ExecutionContext.js"></script>
     <script src="Models/ExecutionContextList.js"></script>
     <script src="Models/FPSInstrument.js"></script>
index 78cab87..74cbadb 100644 (file)
@@ -97,6 +97,8 @@ Object.defineProperty(WebInspector, "targets",
     get() { return this.targetManager.targets; }
 });
 
+WebInspector.assumingMainTarget = () => WebInspector.mainTarget;
+
 WebInspector.isDebugUIEnabled = () => false;
 
 WebInspector.UIString = (string) => string;
index 3122aab..e9839bd 100644 (file)
@@ -335,7 +335,7 @@ WebInspector.ConsoleMessageView = class ConsoleMessageView extends WebInspector.
             callFrame = firstNonNativeNonAnonymousCallFrame;
         } else if (this._message.url && !this._shouldHideURL(this._message.url)) {
             // CSS warnings have no stack traces.
-            callFrame = WebInspector.CallFrame.fromPayload({
+            callFrame = WebInspector.CallFrame.fromPayload(this._message.target, {
                 functionName: "",
                 url: this._message.url,
                 lineNumber: this._message.line,
@@ -557,7 +557,7 @@ WebInspector.ConsoleMessageView = class ConsoleMessageView extends WebInspector.
     _formatParameterAsString(object, fragment)
     {
         if (this._isStackTrace(object)) {
-            let stackTrace = WebInspector.StackTrace.fromString(object.description);
+            let stackTrace = WebInspector.StackTrace.fromString(this._message.target, object.description);
             if (stackTrace.callFrames.length) {
                 let stackView = new WebInspector.StackTraceView(stackTrace);
                 fragment.appendChild(stackView.element);
index 988094f..dcc99a8 100644 (file)
@@ -620,7 +620,14 @@ WebInspector.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WebInspec
         this._callStackContentTreeOutline.removeChildren();
         this._activeCallFrameTreeElement = null;
 
-        var callFrames = WebInspector.debuggerManager.callFrames;
+        if (!WebInspector.debuggerManager.activeCallFrame) {
+            this._callStackRow.showEmptyMessage();
+            return;
+        }
+
+        let target = WebInspector.debuggerManager.activeCallFrame.target;
+        let targetData = WebInspector.debuggerManager.dataForTarget(target);
+        let callFrames = targetData.callFrames;
         if (!callFrames || !callFrames.length) {
             this._callStackRow.showEmptyMessage();
             return;
@@ -629,10 +636,10 @@ WebInspector.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WebInspec
         this._callStackRow.hideEmptyMessage();
         this._callStackRow.element.appendChild(this._callStackContentTreeOutline.element);
 
-        var activeCallFrame = WebInspector.debuggerManager.activeCallFrame;
-        for (var i = 0; i < callFrames.length; ++i) {
-            var callFrameTreeElement = new WebInspector.CallFrameTreeElement(callFrames[i]);
-            if (callFrames[i] === activeCallFrame)
+        let activeCallFrame = WebInspector.debuggerManager.activeCallFrame;
+        for (let callFrame of callFrames) {
+            let callFrameTreeElement = new WebInspector.CallFrameTreeElement(callFrame);
+            if (callFrame === activeCallFrame)
                 this._activeCallFrameTreeElement = callFrameTreeElement;
             this._callStackContentTreeOutline.appendChild(callFrameTreeElement);
         }
@@ -645,7 +652,12 @@ WebInspector.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WebInspec
 
     _debuggerActiveCallFrameDidChange()
     {
-        var callFrames = WebInspector.debuggerManager.callFrames;
+        if (!WebInspector.debuggerManager.activeCallFrame)
+            return;
+
+        let target = WebInspector.debuggerManager.activeCallFrame.target;
+        let targetData = WebInspector.debuggerManager.dataForTarget(target);
+        let callFrames = targetData.callFrames;
         if (!callFrames)
             return;
 
@@ -653,13 +665,15 @@ WebInspector.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WebInspec
             this._activeCallFrameTreeElement.isActiveCallFrame = false;
 
         this._activeCallFrameTreeElement = this._callStackContentTreeOutline.findTreeElement(WebInspector.debuggerManager.activeCallFrame);
+
         if (this._activeCallFrameTreeElement)
             this._activeCallFrameTreeElement.isActiveCallFrame = true;
 
-        var indexOfActiveCallFrame = callFrames.indexOf(WebInspector.debuggerManager.activeCallFrame);
+        // FIXME: What is this, and is it still relevant?
         // It is useful to turn off the step out button when there is no call frame to go through
         // since there might be call frames in the backend that were removed when processing the call
         // frame payload.
+        let indexOfActiveCallFrame = callFrames.indexOf(WebInspector.debuggerManager.activeCallFrame);
         this._debuggerStepOutButtonItem.enabled = indexOfActiveCallFrame < callFrames.length - 1;
     }
 
@@ -825,9 +839,11 @@ WebInspector.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WebInspec
 
     _updatePauseReasonSection()
     {
-        var pauseData = WebInspector.debuggerManager.pauseData;
+        let target = WebInspector.debuggerManager.activeCallFrame.target;
+        let targetData = WebInspector.debuggerManager.dataForTarget(target);
+        let {pauseReason, pauseData} = targetData;
 
-        switch (WebInspector.debuggerManager.pauseReason) {
+        switch (pauseReason) {
         case WebInspector.DebuggerManager.PauseReason.Assertion:
             // FIXME: We should include the assertion condition string.
             console.assert(pauseData, "Expected data with an assertion, but found none.");
@@ -876,7 +892,7 @@ WebInspector.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WebInspec
             console.assert(pauseData, "Expected data with an exception, but found none.");
             if (pauseData) {
                 // FIXME: We should improve the appearance of thrown objects. This works well for exception strings.
-                var data = WebInspector.RemoteObject.fromPayload(pauseData);
+                var data = WebInspector.RemoteObject.fromPayload(pauseData, target);
                 this._pauseReasonTextRow.text = WebInspector.UIString("Exception with thrown value: %s").format(data.description);
                 this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
                 return true;
index ee24773..92b7e42 100644 (file)
@@ -79,7 +79,7 @@ WebInspector.EventListenerSectionGroup = class EventListenerSectionGroup extends
         if (!this._eventListener.location)
             return functionName;
 
-        var sourceCode = WebInspector.debuggerManager.scriptForIdentifier(this._eventListener.location.scriptId);
+        var sourceCode = WebInspector.debuggerManager.scriptForIdentifier(this._eventListener.location.scriptId, WebInspector.mainTarget);
         if (!sourceCode)
             return functionName;
 
index 8404484..fa75d25 100644 (file)
@@ -84,7 +84,7 @@ WebInspector.HeapSnapshotInstanceDataGridNode = class HeapSnapshotInstanceDataGr
                 });
             } else {
                 HeapAgent.getRemoteObject(heapObjectIdentifier, WebInspector.RuntimeManager.ConsoleObjectGroup, function(error, remoteObjectPayload) {
-                    let remoteObject = error ? WebInspector.RemoteObject.fromPrimitiveValue(undefined) : WebInspector.RemoteObject.fromPayload(remoteObjectPayload);
+                    let remoteObject = error ? WebInspector.RemoteObject.fromPrimitiveValue(undefined) : WebInspector.RemoteObject.fromPayload(remoteObjectPayload, WebInspector.assumingMainTarget());
                     WebInspector.consoleLogViewController.appendImmediateExecutionWithResult(text, remoteObject, shouldRevealConsole);
                 });
             }
@@ -259,7 +259,7 @@ WebInspector.HeapSnapshotInstanceDataGridNode = class HeapSnapshotInstanceDataGr
                 return this.location.href;
             }
 
-            let remoteObject = WebInspector.RemoteObject.fromPayload(remoteObjectPayload);
+            let remoteObject = WebInspector.RemoteObject.fromPayload(remoteObjectPayload, WebInspector.assumingMainTarget());
             remoteObject.callFunctionJSON(inspectedPage_window_getLocationHref, undefined, (href) => {
                 remoteObject.release();
 
@@ -292,7 +292,7 @@ WebInspector.HeapSnapshotInstanceDataGridNode = class HeapSnapshotInstanceDataGr
                 let functionNameElement = containerElement.appendChild(document.createElement("span"));
                 functionNameElement.classList.add("function-name");
                 functionNameElement.textContent = name || displayName || WebInspector.UIString("(anonymous function)");
-                let sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId);
+                let sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId, WebInspector.assumingMainTarget());
                 if (sourceCode) {
                     let locationElement = containerElement.appendChild(document.createElement("span"));
                     locationElement.classList.add("location");
@@ -411,7 +411,7 @@ WebInspector.HeapSnapshotInstanceDataGridNode = class HeapSnapshotInstanceDataGr
                 HeapAgent.getPreview(node.id, function(error, string, functionDetails, objectPreviewPayload) {
                     if (functionDetails) {
                         let location = functionDetails.location;
-                        let sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId);
+                        let sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId, WebInspector.assumingMainTarget());
                         if (sourceCode) {
                             const dontFloat = true;
                             const useGoToArrowButton = true;
index d8a71f5..06dfaab 100644 (file)
@@ -223,12 +223,12 @@ WebInspector.ObjectTreeBaseTreeElement = class ObjectTreeBaseTreeElement extends
             // FIXME: We should better handle bound functions.
             if (!isFunctionStringNativeCode(resolvedValue.description)) {
                 contextMenu.appendItem(WebInspector.UIString("Jump to Definition"), function() {
-                    DebuggerAgent.getFunctionDetails(resolvedValue.objectId, function(error, response) {
+                    resolvedValue.target.DebuggerAgent.getFunctionDetails(resolvedValue.objectId, function(error, response) {
                         if (error)
                             return;
 
                         let location = response.location;
-                        let sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId);
+                        let sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId, resolvedValue.target);
                         if (!sourceCode)
                             return;
 
index b320637..d3c51ba 100644 (file)
@@ -122,6 +122,7 @@ WebInspector.OpenResourceDialog = class OpenResourceDialog extends WebInspector.
     {
         WebInspector.Frame.removeEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
         WebInspector.Frame.removeEventListener(WebInspector.Frame.Event.ResourceWasAdded, this._resourceWasAdded, this);
+        WebInspector.debuggerManager.removeEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, this._scriptAdded, this);
 
         this._queryController.reset();
     }
@@ -130,10 +131,18 @@ WebInspector.OpenResourceDialog = class OpenResourceDialog extends WebInspector.
     {
         WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
         WebInspector.Frame.addEventListener(WebInspector.Frame.Event.ResourceWasAdded, this._resourceWasAdded, this);
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, this._scriptAdded, this);
 
         if (WebInspector.frameResourceManager.mainFrame)
             this._addResourcesForFrame(WebInspector.frameResourceManager.mainFrame);
 
+        for (let target of WebInspector.targets) {
+            if (target !== WebInspector.mainTarget)
+                this._addScriptsForTarget(target);
+        }
+
+        this._updateFilter();
+
         this._inputElement.focus();
         this._clear();
     }
@@ -274,8 +283,18 @@ WebInspector.OpenResourceDialog = class OpenResourceDialog extends WebInspector.
 
             frames = frames.concat(currentFrame.childFrameCollection.toArray());
         }
+    }
 
-        this._updateFilter();
+    _addScriptsForTarget(target)
+    {
+        const suppressFilterUpdate = true;
+
+        let targetData = WebInspector.debuggerManager.dataForTarget(target);
+        for (let script of targetData.scripts) {
+            if (isWebKitInternalScript(script.sourceURL) || isWebInspectorConsoleEvaluationScript(script.sourceURL))
+                continue;
+            this._addResource(script, suppressFilterUpdate);
+        }
     }
 
     _mainResourceDidChange(event)
@@ -290,6 +309,15 @@ WebInspector.OpenResourceDialog = class OpenResourceDialog extends WebInspector.
     {
         this._addResource(event.data.resource);
     }
+
+    _scriptAdded(event)
+    {
+        let script = event.data.script;
+        if (script.target === WebInspector.mainTarget)
+            return;
+
+        this._addResource(script);
+    }
 };
 
 WebInspector.OpenResourceDialog.ResourceMatchCookieDataSymbol = Symbol("open-resource-dialog-resource-match-cookie-data");
index f48085f..1c11572 100644 (file)
@@ -60,7 +60,7 @@ WebInspector.ProfileDataGridNode = class ProfileDataGridNode extends WebInspecto
 
     iconClassName()
     {
-        let script = WebInspector.debuggerManager.scriptForIdentifier(this._node.sourceID);
+        let script = WebInspector.debuggerManager.scriptForIdentifier(this._node.sourceID, WebInspector.assumingMainTarget());
         if (!script || !script.url)
             return "native-icon";
         if (this._node.name === "(program)")
@@ -130,7 +130,7 @@ WebInspector.ProfileDataGridNode = class ProfileDataGridNode extends WebInspecto
     {
         if (columnIdentifier === "function") {
             let filterableData = [this.displayName()];
-            let script = WebInspector.debuggerManager.scriptForIdentifier(this._node.sourceID);
+            let script = WebInspector.debuggerManager.scriptForIdentifier(this._node.sourceID, WebInspector.assumingMainTarget());
             if (script && script.url && this._node.line >= 0 && this._node.column >= 0)
                 filterableData.push(script.url);
             return filterableData;
@@ -232,7 +232,7 @@ WebInspector.ProfileDataGridNode = class ProfileDataGridNode extends WebInspecto
         let titleElement = fragment.appendChild(document.createElement("span"));
         titleElement.textContent = title;
 
-        let script = WebInspector.debuggerManager.scriptForIdentifier(this._node.sourceID);
+        let script = WebInspector.debuggerManager.scriptForIdentifier(this._node.sourceID, WebInspector.assumingMainTarget());
         if (script && script.url && this._node.line >= 0 && this._node.column >= 0) {
             // Convert from 1-based line and column to 0-based.
             let sourceCodeLocation = script.createSourceCodeLocation(this._node.line - 1, this._node.column - 1);
index c8eb973..e4beda5 100644 (file)
     content: image-set(url(../Images/ClippingJS.png) 1x, url(../Images/ClippingJS@2x.png) 2x);
 }
 
+/* FIXME: <https://webkit.org/b/164138> [GTK] Web Inspector: Add new GTK+ icons for Worker Scripts */
+body:matches(.mac-platform, .windows-platform) .script.worker-icon .icon {
+    content: image-set(url(../Images/WorkerScript.png) 1x, url(../Images/WorkerScript@2x.png) 2x);
+}
+
 .large .resource-icon .icon {
     content: image-set(url(../Images/DocumentGenericLarge.png) 1x, url(../Images/DocumentGenericLarge@2x.png) 2x);
 }
 .large .source-map-resource.resource-icon.resource-type-script .icon {
     content: image-set(url(../Images/ClippingJSLarge.png) 1x, url(../Images/ClippingJSLarge@2x.png) 2x);
 }
+
+/* FIXME: <https://webkit.org/b/164138> [GTK] Web Inspector: Add new GTK+ icons for Worker Scripts */
+body:matches(.mac-platform, .windows-platform) .large .script.worker-icon .icon {
+    content: image-set(url(../Images/WorkerScriptLarge.png) 1x, url(../Images/WorkerScriptLarge@2x.png) 2x);
+}
index 8f3f463..5942349 100644 (file)
@@ -36,6 +36,9 @@ WebInspector.ResourceSidebarPanel = class ResourceSidebarPanel extends WebInspec
         this._navigationBar = new WebInspector.NavigationBar;
         this.addSubview(this._navigationBar);
 
+        this._targetTreeElementMap = new Map;
+        this._deferredTargetScripts = [];
+
         var scopeItemPrefix = "resource-sidebar-";
         var scopeBarItems = [];
 
@@ -61,6 +64,8 @@ WebInspector.ResourceSidebarPanel = class ResourceSidebarPanel extends WebInspec
         WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptRemoved, this._scriptWasRemoved, this);
         WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptsCleared, this._scriptsCleared, this);
 
+        WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Event.TargetRemoved, this._targetRemoved, this);
+
         WebInspector.notifications.addEventListener(WebInspector.Notification.ExtraDomainsActivated, this._extraDomainsActivated, this);
 
         this.contentTreeOutline.addEventListener(WebInspector.TreeOutline.Event.SelectionDidChange, this._treeSelectionDidChange, this);
@@ -282,6 +287,12 @@ WebInspector.ResourceSidebarPanel = class ResourceSidebarPanel extends WebInspec
         if (script.resource || script.dynamicallyAddedScriptElement)
             return;
 
+        // Worker script.
+        if (script.target !== WebInspector.mainTarget) {
+            this._addScriptForNonMainTarget(script);
+            return;
+        }
+
         var insertIntoTopLevel = false;
 
         if (script.injected) {
@@ -349,6 +360,62 @@ WebInspector.ResourceSidebarPanel = class ResourceSidebarPanel extends WebInspec
                 this._anonymousScriptsFolderTreeElement.parent.removeChild(this._anonymousScriptsFolderTreeElement, suppressOnDeselect, suppressSelectSibling);
             this._anonymousScriptsFolderTreeElement = null;
         }
+
+        this._deferredTargetScripts = [];
+        if (this._targetTreeElementMap.size) {
+            for (let treeElement of this._targetTreeElementMap)
+                treeElement.parent.removeChild(treeElement, suppressOnDeselect, suppressSelectSibling);
+            this._targetTreeElementMap.clear();
+        }
+    }
+
+    _addScriptForNonMainTarget(script)
+    {
+        let targetTreeElement = this._targetTreeElementMap.get(script.target);
+        if (!targetTreeElement) {
+            // Defer adding this script until we have the main resource for the Target.
+            // This can happen when opening the inspector after a page has already loaded,
+            // in those cases the scriptDidParse events are in random order.
+            if (script.isMainResource())
+                this._addTargetWithMainResource(script.target);
+            else
+                this._deferredTargetScripts.push(script);
+            return;
+        }
+
+        let scriptTreeElement = new WebInspector.ScriptTreeElement(script);
+        let index = insertionIndexForObjectInListSortedByFunction(scriptTreeElement, targetTreeElement.children, this._compareTreeElements);
+        targetTreeElement.insertChild(scriptTreeElement, index);
+    }
+
+    _addTargetWithMainResource(target)
+    {
+        console.assert(target.type === WebInspector.Target.Type.Worker);
+
+        let targetTreeElement = new WebInspector.TargetTreeElement(target);
+        this._targetTreeElementMap.set(target, targetTreeElement);
+
+        let index = insertionIndexForObjectInListSortedByFunction(targetTreeElement, this.contentTreeOutline.children, this._compareTreeElements);
+        this.contentTreeOutline.insertChild(targetTreeElement, index);
+
+        let [deferredScriptsForThisTarget, deferredScriptsForAnotherTarget] = this._deferredTargetScripts.partition((script) => script.target === target);
+        this._deferredTargetScripts = deferredScriptsForAnotherTarget;
+        for (let script of deferredScriptsForThisTarget) {
+            let scriptTreeElement = new WebInspector.ScriptTreeElement(script);
+            let index = insertionIndexForObjectInListSortedByFunction(scriptTreeElement, targetTreeElement.children, this._compareTreeElements);
+            targetTreeElement.insertChild(scriptTreeElement, index);
+        }
+    }
+
+    _targetRemoved(event)
+    {
+        let removedTarget = event.data.target;
+
+        let targetTreeElement = this._targetTreeElementMap.take(removedTarget);
+        if (targetTreeElement)
+            targetTreeElement.parent.removeChild(targetTreeElement);
+
+        this._deferredTargetScripts = this._deferredTargetScripts.filter((script) => script.target !== removedTarget);
     }
 
     _treeSelectionDidChange(event)
index 6494c3c..6fceb44 100644 (file)
@@ -45,6 +45,11 @@ WebInspector.ScriptTreeElement = class ScriptTreeElement extends WebInspector.So
         } else
             this.addClassName(WebInspector.ScriptTreeElement.AnonymousScriptIconStyleClassName);
 
+        if (script.isMainResource()) {
+            console.assert(script.target.type === WebInspector.Target.Type.Worker);
+            this.addClassName("worker-icon");
+        }
+
         this._script = script;
     }
 
index aceb148..65e3e99 100644 (file)
@@ -195,8 +195,8 @@ WebInspector.SearchSidebarPanel = class SearchSidebarPanel extends WebInspector.
                 updateEmptyContentPlaceholder.call(this);
             }
 
-            for (var script of scriptsToSearch)
-                DebuggerAgent.searchInContent(script.id, searchQuery, isCaseSensitive, isRegex, scriptCallback.bind(this, script));
+            for (let script of scriptsToSearch)
+                script.target.DebuggerAgent.searchInContent(script.id, searchQuery, isCaseSensitive, isRegex, scriptCallback.bind(this, script));
         }
 
         function domCallback(error, searchId, resultsCount)
index bdbc508..065b851 100644 (file)
@@ -101,6 +101,19 @@ WebInspector.SourceCodeTextEditor = class SourceCodeTextEditor extends WebInspec
         return this._sourceCode;
     }
 
+    get target()
+    {
+        if (this._sourceCode instanceof WebInspector.SourceMapResource) {
+            if (this._sourceCode.sourceMap.originalSourceCode instanceof WebInspector.Script)
+                return this._sourceCode.sourceMap.originalSourceCode.target;
+        }
+
+        if (this._sourceCode instanceof WebInspector.Script)
+            return this._sourceCode.target;
+
+        return WebInspector.mainTarget;
+    }
+
     shown()
     {
         super.shown();
@@ -236,7 +249,7 @@ WebInspector.SourceCodeTextEditor = class SourceCodeTextEditor extends WebInspec
         if (this._sourceCode instanceof WebInspector.Resource)
             PageAgent.searchInResource(this._sourceCode.parentFrame.id, this._sourceCode.url, query, false, false, searchResultCallback.bind(this));
         else if (this._sourceCode instanceof WebInspector.Script)
-            DebuggerAgent.searchInContent(this._sourceCode.id, query, false, false, searchResultCallback.bind(this));
+            this._sourceCode.target.DebuggerAgent.searchInContent(this._sourceCode.id, query, false, false, searchResultCallback.bind(this));
         return true;
     }
 
@@ -1037,7 +1050,7 @@ WebInspector.SourceCodeTextEditor = class SourceCodeTextEditor extends WebInspec
 
             if (script) {
                 contextMenu.appendItem(WebInspector.UIString("Continue to Here"), () => {
-                    WebInspector.debuggerManager.continueToLocation(script.id, sourceCodeLocation.lineNumber, sourceCodeLocation.columnNumber);
+                    WebInspector.debuggerManager.continueToLocation(script, sourceCodeLocation.lineNumber, sourceCodeLocation.columnNumber);
                 });
                 contextMenu.appendSeparator();
             }
@@ -1510,7 +1523,7 @@ WebInspector.SourceCodeTextEditor = class SourceCodeTextEditor extends WebInspec
             if (candidate !== this.tokenTrackingController.candidate)
                 return;
 
-            var data = WebInspector.RemoteObject.fromPayload(result);
+            let data = WebInspector.RemoteObject.fromPayload(result, this.target);
             switch (data.type) {
             case "function":
                 this._showPopoverForFunction(data);
@@ -1531,15 +1544,16 @@ WebInspector.SourceCodeTextEditor = class SourceCodeTextEditor extends WebInspec
             }
         }
 
-        var expression = appendWebInspectorSourceURL(candidate.expression);
+        let target = WebInspector.debuggerManager.activeCallFrame ? WebInspector.debuggerManager.activeCallFrame.target : this.target;
+        let expression = appendWebInspectorSourceURL(candidate.expression);
 
         if (WebInspector.debuggerManager.activeCallFrame) {
-            DebuggerAgent.evaluateOnCallFrame.invoke({callFrameId: WebInspector.debuggerManager.activeCallFrame.id, expression, objectGroup: "popover", doNotPauseOnExceptionsAndMuteConsole: true}, populate.bind(this));
+            target.DebuggerAgent.evaluateOnCallFrame.invoke({callFrameId: WebInspector.debuggerManager.activeCallFrame.id, expression, objectGroup: "popover", doNotPauseOnExceptionsAndMuteConsole: true}, populate.bind(this), target.DebuggerAgent);
             return;
         }
 
-        // No call frame available. Use the main page's context.
-        RuntimeAgent.evaluate.invoke({expression, objectGroup: "popover", doNotPauseOnExceptionsAndMuteConsole: true}, populate.bind(this));
+        // No call frame available. Use the SourceCode's page's context.
+        target.RuntimeAgent.evaluate.invoke({expression, objectGroup: "popover", doNotPauseOnExceptionsAndMuteConsole: true}, populate.bind(this), target.RuntimeAgent);
     }
 
     _tokenTrackingControllerHighlightedJavaScriptTypeInformation(candidate)
@@ -1632,7 +1646,7 @@ WebInspector.SourceCodeTextEditor = class SourceCodeTextEditor extends WebInspec
             content.appendChild(title);
 
             let location = response.location;
-            let sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId);
+            let sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId, this.target);
             let sourceCodeLocation = sourceCode.createSourceCodeLocation(location.lineNumber, location.columnNumber);
             let functionSourceCodeLink = WebInspector.createSourceCodeLocationLink(sourceCodeLocation);
             title.appendChild(functionSourceCodeLink);
@@ -1659,7 +1673,8 @@ WebInspector.SourceCodeTextEditor = class SourceCodeTextEditor extends WebInspec
 
             this._showPopover(content);
         }
-        DebuggerAgent.getFunctionDetails(data.objectId, didGetDetails.bind(this));
+
+        data.target.DebuggerAgent.getFunctionDetails(data.objectId, didGetDetails.bind(this));
     }
 
     _showPopoverForObject(data)
diff --git a/Source/WebInspectorUI/UserInterface/Views/TargetTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/TargetTreeElement.js
new file mode 100644 (file)
index 0000000..38280fb
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.TargetTreeElement = class TargetTreeElement extends WebInspector.ScriptTreeElement
+{
+    constructor(target)
+    {
+        super(target.mainResource);
+
+        console.assert(target instanceof WebInspector.Target);
+        console.assert(target.type === WebInspector.Target.Type.Worker);
+        console.assert(target.mainResource instanceof WebInspector.Script);
+
+        this._target = target;
+
+        this._expandedSetting = new WebInspector.Setting("target-expanded-" + this.target.name.hash, true);
+
+        if (this._expandedSetting.value)
+            this.expand();
+    }
+
+    // Public
+
+    get target() { return this._target; }
+
+    // Protected (TreeElement)
+
+    onexpand()
+    {
+        this._expandedSetting.value = true;
+    }
+
+    oncollapse()
+    {
+        if (this.hasChildren)
+            this._expandedSetting.value = false;
+    }
+};