Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 16 Jan 2017 21:42:59 -0800
changeset 329649 3e275d37a06236981bff399b7d7aa0646be3fee7
parent 329648 792c6f70dde581401b8afedd6e96bb4ad37f9655 (current diff)
parent 329636 f81835544ab8e371a6d59a609a88567fce2183f5 (diff)
child 329650 4ac5466b4c416faabe9f4a3498e82d682203447d
child 329677 33504378a3a990e3b4f18848416fd1a439a1300b
child 329732 cee10a2c348a6768803bf01b7852d811df50b587
child 342168 c52fa5ad5b28d10afb19beb3d2d9e7769d3b74d6
push id85758
push userphilringnalda@gmail.com
push dateTue, 17 Jan 2017 05:46:54 +0000
treeherdermozilla-inbound@4ac5466b4c41 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone53.0a1
first release with
nightly linux32
3e275d37a062 / 53.0a1 / 20170117030218 / files
nightly linux64
3e275d37a062 / 53.0a1 / 20170117030218 / files
nightly mac
3e275d37a062 / 53.0a1 / 20170117030218 / files
nightly win32
3e275d37a062 / 53.0a1 / 20170117030218 / files
nightly win64
3e275d37a062 / 53.0a1 / 20170117030218 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-i to m-c, a=merge
testing/web-platform/meta/eventsource/dedicated-worker/eventsource-close.htm.ini
testing/web-platform/meta/eventsource/dedicated-worker/eventsource-constructor-non-same-origin.htm.ini
testing/web-platform/meta/eventsource/dedicated-worker/eventsource-constructor-url-bogus.htm.ini
testing/web-platform/meta/eventsource/dedicated-worker/eventsource-eventtarget.worker.js.ini
testing/web-platform/meta/eventsource/dedicated-worker/eventsource-onmesage.htm.ini
testing/web-platform/meta/eventsource/dedicated-worker/eventsource-onopen.htm.ini
testing/web-platform/meta/eventsource/dedicated-worker/eventsource-prototype.htm.ini
testing/web-platform/meta/eventsource/dedicated-worker/eventsource-url.htm.ini
testing/web-platform/meta/eventsource/shared-worker/eventsource-close.htm.ini
testing/web-platform/meta/eventsource/shared-worker/eventsource-constructor-non-same-origin.htm.ini
testing/web-platform/meta/eventsource/shared-worker/eventsource-constructor-url-bogus.htm.ini
testing/web-platform/meta/eventsource/shared-worker/eventsource-eventtarget.htm.ini
testing/web-platform/meta/eventsource/shared-worker/eventsource-onmesage.htm.ini
testing/web-platform/meta/eventsource/shared-worker/eventsource-onopen.htm.ini
testing/web-platform/meta/eventsource/shared-worker/eventsource-prototype.htm.ini
testing/web-platform/meta/eventsource/shared-worker/eventsource-url.htm.ini
testing/web-platform/meta/html/semantics/selectors/pseudo-classes/inrange-outofrange.html.ini
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,17 +1,17 @@
 # Always ignore node_modules.
 **/node_modules/**/*.*
 
 # Exclude expected objdirs.
 obj*/**
 
 # We ignore all these directories by default, until we get them enabled.
 # If you are enabling a directory, please add directory specific exclusions
-# below.
+# below.
 addon-sdk/**
 build/**
 caps/**
 chrome/**
 config/**
 db/**
 docshell/**
 dom/**
@@ -97,26 +97,21 @@ devtools/client/webconsole/net/**
 devtools/client/webconsole/test/**
 devtools/client/webconsole/console-output.js
 devtools/client/webconsole/hudservice.js
 devtools/client/webconsole/utils.js
 devtools/client/webconsole/webconsole-connection-proxy.js
 devtools/client/webconsole/webconsole.js
 devtools/client/webide/**
 !devtools/client/webide/components/webideCli.js
-devtools/server/actors/*.js
-!devtools/server/actors/csscoverage.js
-!devtools/server/actors/inspector.js
-!devtools/server/actors/layout.js
-!devtools/server/actors/string.js
-!devtools/server/actors/styles.js
-!devtools/server/actors/tab.js
-!devtools/server/actors/webbrowser.js
-!devtools/server/actors/webextension.js
-!devtools/server/actors/webextension-inspected-window.js
+devtools/server/actors/webconsole.js
+devtools/server/actors/object.js
+devtools/server/actors/script.js
+devtools/server/actors/styleeditor.js
+devtools/server/actors/stylesheets.js
 devtools/server/tests/browser/**
 !devtools/server/tests/browser/browser_webextension_inspected_window.js
 devtools/server/tests/mochitest/**
 devtools/server/tests/unit/**
 devtools/shared/heapsnapshot/**
 devtools/shared/transport/tests/unit/**
 devtools/shared/webconsole/test/**
 
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -338,22 +338,17 @@ nsAccessibilityService* GetOrCreateAccSe
 void MaybeShutdownAccService(uint32_t aFormerConsumer);
 
 /**
  * Return true if we're in a content process and not B2G.
  */
 inline bool
 IPCAccessibilityActive()
 {
-#ifdef MOZ_B2G
-  return false;
-#else
-  return XRE_IsContentProcess() &&
-    mozilla::Preferences::GetBool("accessibility.ipc_architecture.enabled", true);
-#endif
+  return XRE_IsContentProcess();
 }
 
 /**
  * Map nsIAccessibleEvents constants to strings. Used by
  * nsAccessibilityService::GetStringEventType() method.
  */
 static const char kEventTypeNames[][40] = {
   "unknown",                                 //
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -186,16 +186,20 @@ DocAccessibleParent::RecvHideEvent(const
   }
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvEvent(const uint64_t& aID, const uint32_t& aEventType)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
     NS_ERROR("no proxy for event!");
     return IPC_OK();
   }
 
   ProxyEvent(proxy, aEventType);
 
@@ -214,16 +218,20 @@ DocAccessibleParent::RecvEvent(const uin
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvStateChangeEvent(const uint64_t& aID,
                                           const uint64_t& aState,
                                           const bool& aEnabled)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* target = GetAccessible(aID);
   if (!target) {
     NS_ERROR("we don't know about the target of a state change event!");
     return IPC_OK();
   }
 
   ProxyStateChangeEvent(target, aState, aEnabled);
 
@@ -244,16 +252,20 @@ DocAccessibleParent::RecvStateChangeEven
   nsCoreUtils::DispatchAccEvent(Move(event));
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
     NS_ERROR("unknown caret move event target!");
     return IPC_OK();
   }
 
   ProxyCaretMoveEvent(proxy, aOffset);
 
@@ -276,16 +288,20 @@ DocAccessibleParent::RecvCaretMoveEvent(
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID,
                                          const nsString& aStr,
                                          const int32_t& aStart,
                                          const uint32_t& aLen,
                                          const bool& aIsInsert,
                                          const bool& aFromUser)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* target = GetAccessible(aID);
   if (!target) {
     NS_ERROR("text change event target is unknown!");
     return IPC_OK();
   }
 
   ProxyTextChangeEvent(target, aStr, aStart, aLen, aIsInsert, aFromUser);
 
@@ -306,16 +322,20 @@ DocAccessibleParent::RecvTextChangeEvent
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvSelectionEvent(const uint64_t& aID,
                                         const uint64_t& aWidgetID,
                                         const uint32_t& aType)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* target = GetAccessible(aID);
   ProxyAccessible* widget = GetAccessible(aWidgetID);
   if (!target || !widget) {
     NS_ERROR("invalid id in selection event");
     return IPC_OK();
   }
 
   ProxySelectionEvent(target, widget, aType);
@@ -329,16 +349,20 @@ DocAccessibleParent::RecvSelectionEvent(
   nsCoreUtils::DispatchAccEvent(Move(event));
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvRoleChangedEvent(const uint32_t& aRole)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
  if (aRole >= roles::LAST_ROLE) {
    NS_ERROR("child sent bad role in RoleChangedEvent");
    return IPC_FAIL_NO_REASON(this);
  }
 
  mRole = static_cast<a11y::role>(aRole);
  return IPC_OK();
 }
@@ -431,16 +455,21 @@ DocAccessibleParent::Destroy()
     mChildDocs[i]->Destroy();
 
   for (auto iter = mAccessibles.Iter(); !iter.Done(); iter.Next()) {
     MOZ_ASSERT(iter.Get()->mProxy != this);
     ProxyDestroyed(iter.Get()->mProxy);
     iter.Remove();
   }
 
+  // The code above should have already completely cleared these, but to be
+  // extra safe make sure they are cleared here.
+  mAccessibles.Clear();
+  mChildDocs.Clear();
+
   DocManager::NotifyOfRemoteDocShutdown(this);
   ProxyDestroyed(this);
   if (mParentDoc)
     mParentDoc->RemoveChildDoc(this);
   else if (IsTopLevel())
     GetAccService()->RemoteDocShutdown(this);
 }
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1683,17 +1683,18 @@
               }
               if (!isRemote && aBrowser.contentWindow.opener != aOptions.opener) {
                 throw new Error("Cannot change opener on an already non-remote browser!");
               }
             }
 
             // Abort if we're not going to change anything
             if (isRemote == aShouldBeRemote && !aOptions.newFrameloader && !aOptions.freshProcess &&
-                (!isRemote || aBrowser.getAttribute("remoteType") == aOptions.remoteType)) {
+                (!isRemote || aBrowser.getAttribute("remoteType") == aOptions.remoteType) &&
+                !aBrowser.frameLoader.isFreshProcess) {
               return false;
             }
 
             let tab = this.getTabForBrowser(aBrowser);
             let evt = document.createEvent("Events");
             evt.initEvent("BeforeTabRemotenessChange", true, false);
             tab.dispatchEvent(evt);
 
@@ -1830,17 +1831,18 @@
 
             // If this URL can't load in the current browser then flip it to the
             // correct type.
             let currentRemoteType = aBrowser.remoteType;
             aOptions.remoteType =
               E10SUtils.getRemoteTypeForURI(aURL, gMultiProcessBrowser,
                                             currentRemoteType);
             if (currentRemoteType != aOptions.remoteType ||
-                aOptions.freshProcess || aOptions.newFrameloader) {
+                aOptions.freshProcess || aOptions.newFrameloader ||
+                aBrowser.frameLoader.isFreshProcess) {
               let remote = aOptions.remoteType != E10SUtils.NOT_REMOTE;
               return this.updateBrowserRemoteness(aBrowser, remote, aOptions);
             }
 
             return false;
           ]]>
         </body>
       </method>
--- a/browser/components/sessionstore/SessionSaver.jsm
+++ b/browser/components/sessionstore/SessionSaver.jsm
@@ -209,27 +209,30 @@ var SessionSaverInternal = {
           break;
         }
 
         delete state._closedWindows[i]._shouldRestore;
         state.windows.unshift(state._closedWindows.pop());
       }
     }
 
-    // Clear all cookies on clean shutdown according to user preferences
+    // Clear all cookies and storage on clean shutdown according to user preferences
     if (RunState.isClosing) {
       let expireCookies = Services.prefs.getIntPref("network.cookie.lifetimePolicy") ==
                           Services.cookies.QueryInterface(Ci.nsICookieService).ACCEPT_SESSION;
       let sanitizeCookies = Services.prefs.getBoolPref("privacy.sanitize.sanitizeOnShutdown") &&
                             Services.prefs.getBoolPref("privacy.clearOnShutdown.cookies");
       let restart = Services.prefs.getBoolPref("browser.sessionstore.resume_session_once");
-      // Don't clear cookies when restarting
+      // Don't clear when restarting
       if ((expireCookies || sanitizeCookies) && !restart) {
         for (let window of state.windows) {
           delete window.cookies;
+          for (let tab of window.tabs) {
+            delete tab.storage;
+          }
         }
       }
     }
 
     stopWatchFinish("COLLECT_DATA_MS", "COLLECT_DATA_LONGEST_OP_MS");
     return this._writeState(state);
   },
 
--- a/browser/modules/E10SUtils.jsm
+++ b/browser/modules/E10SUtils.jsm
@@ -147,16 +147,23 @@ this.E10SUtils = {
     return remoteType == this.getRemoteTypeForURI(aURI.spec, true, remoteType);
   },
 
   shouldLoadURI(aDocShell, aURI, aReferrer) {
     // Inner frames should always load in the current process
     if (aDocShell.QueryInterface(Ci.nsIDocShellTreeItem).sameTypeParent)
       return true;
 
+    // If we are in a fresh process, and it wouldn't be content visible to
+    // change processes, we want to load into a new process so that we can throw
+    // this one out.
+    if (aDocShell.inFreshProcess && aDocShell.isOnlyToplevelInTabGroup) {
+      return false;
+    }
+
     // If the URI can be loaded in the current process then continue
     return this.shouldLoadURIInThisProcess(aURI);
   },
 
   redirectLoad(aDocShell, aURI, aReferrer, aFreshProcess) {
     // Retarget the load to the correct process
     let messageManager = aDocShell.QueryInterface(Ci.nsIInterfaceRequestor)
                                   .getInterface(Ci.nsIContentFrameMessageManager);
--- a/browser/themes/shared/identity-block/icons.inc.css
+++ b/browser/themes/shared/identity-block/icons.inc.css
@@ -38,25 +38,21 @@
 
 #urlbar[pageproxystate="valid"] > #identity-box.verifiedDomain > #connection-icon@selectorSuffix@,
 #urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon@selectorSuffix@,
 #urlbar[pageproxystate="valid"] > #identity-box.mixedActiveBlocked > #connection-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/connection-secure.svg);
   visibility: visible;
 }
 
+#urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon@selectorSuffix@,
+#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon@selectorSuffix@,
+#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon@selectorSuffix@,
 #urlbar[pageproxystate="valid"] > #identity-box.certUserOverridden > #connection-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon@iconVariant@);
   visibility: visible;
 }
 
 #urlbar[pageproxystate="valid"] > #identity-box.insecureLoginForms > #connection-icon@selectorSuffix@,
 #urlbar[pageproxystate="valid"] > #identity-box.mixedActiveContent > #connection-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon@iconVariant@);
   visibility: visible;
 }
-
-#urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon@selectorSuffix@,
-#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon@selectorSuffix@,
-#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon@selectorSuffix@ {
-  list-style-image: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon@iconVariant@);
-  visibility: visible;
-}
--- a/devtools/.eslintrc.js
+++ b/devtools/.eslintrc.js
@@ -25,17 +25,17 @@ module.exports = {
     "Node": true,
     "reportError": true,
     "require": true,
     "setInterval": true,
     "setTimeout": true,
     "uneval": true,
     "URL": true,
     "WebSocket": true,
-    "XMLHttpRequest": true,
+    "XMLHttpRequest": true
   },
   "rules": {
     // These are the rules that have been configured so far to match the
     // devtools coding style.
 
     // Rules from the mozilla plugin
     "mozilla/no-aArgs": "warn",
     "mozilla/no-cpows-in-tests": "error",
--- a/devtools/client/canvasdebugger/test/browser.ini
+++ b/devtools/client/canvasdebugger/test/browser.ini
@@ -21,20 +21,23 @@ support-files =
 [browser_canvas-actor-test-03.js]
 [browser_canvas-actor-test-04.js]
 [browser_canvas-actor-test-05.js]
 [browser_canvas-actor-test-06.js]
 [browser_canvas-actor-test-07.js]
 [browser_canvas-actor-test-08.js]
 [browser_canvas-actor-test-09.js]
 subsuite = gpu
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_canvas-actor-test-10.js]
 subsuite = gpu
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_canvas-actor-test-11.js]
 subsuite = gpu
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_canvas-actor-test-12.js]
 [browser_canvas-frontend-call-highlight.js]
 [browser_canvas-frontend-call-list.js]
 [browser_canvas-frontend-call-search.js]
 [browser_canvas-frontend-call-stack-01.js]
 [browser_canvas-frontend-call-stack-02.js]
 [browser_canvas-frontend-call-stack-03.js]
 [browser_canvas-frontend-clear.js]
--- a/devtools/client/commandline/test/browser.ini
+++ b/devtools/client/commandline/test/browser.ini
@@ -80,16 +80,17 @@ support-files =
 [browser_cmd_pref1.js]
 [browser_cmd_pref2.js]
 [browser_cmd_pref3.js]
 [browser_cmd_qsa.js]
 [browser_cmd_restart.js]
 [browser_cmd_rulers.js]
 [browser_cmd_screenshot.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 support-files =
   browser_cmd_screenshot.html
 [browser_cmd_settings.js]
 [browser_gcli_async.js]
 [browser_gcli_canon.js]
 [browser_gcli_cli1.js]
 [browser_gcli_cli2.js]
 [browser_gcli_completion1.js]
--- a/devtools/client/debugger/test/mochitest/browser2.ini
+++ b/devtools/client/debugger/test/mochitest/browser2.ini
@@ -280,25 +280,26 @@ skip-if = e10s && debug
 skip-if = e10s && debug
 [browser_dbg_source-maps-03.js]
 skip-if = e10s && debug
 [browser_dbg_source-maps-04.js]
 skip-if = e10s # Bug 1093535
 [browser_dbg_sources-cache.js]
 [browser_dbg_sources-contextmenu-01.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_dbg_sources-contextmenu-02.js]
 skip-if = e10s && debug
 [browser_dbg_sources-eval-01.js]
 skip-if = true # non-named eval sources turned off for now, bug 1124106
 [browser_dbg_sources-eval-02.js]
 [browser_dbg_sources-iframe-reload.js]
 [browser_dbg_sources-keybindings.js]
 subsuite = clipboard
-skip-if = e10s && debug
+skip-if = (e10s && debug) || (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_dbg_sources-labels.js]
 skip-if = e10s && debug
 [browser_dbg_sources-large.js]
 [browser_dbg_sources-sorting.js]
 skip-if = e10s && debug
 [browser_dbg_sources-bookmarklet.js]
 skip-if = e10s && debug
 [browser_dbg_sources-webext-contentscript.js]
@@ -317,17 +318,17 @@ skip-if = e10s && (debug || asan) # time
 [browser_dbg_stack-06.js]
 skip-if = e10s && debug
 [browser_dbg_stack-07.js]
 skip-if = e10s && debug
 [browser_dbg_stack-contextmenu-01.js]
 skip-if = e10s && debug
 [browser_dbg_stack-contextmenu-02.js]
 subsuite = clipboard
-skip-if = e10s && debug
+skip-if = (e10s && debug) || (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_dbg_step-out.js]
 skip-if = e10s && debug
 [browser_dbg_tabactor-01.js]
 skip-if = e10s # TODO
 [browser_dbg_tabactor-02.js]
 skip-if = e10s # TODO
 [browser_dbg_terminate-on-tab-close.js]
 skip-if = e10s && debug
@@ -344,17 +345,17 @@ skip-if = e10s && debug
 [browser_dbg_variables-view-06.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-07.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-08.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-accessibility.js]
 subsuite = clipboard
-skip-if = e10s && debug
+skip-if = (e10s && debug) || (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_dbg_variables-view-data.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-cancel.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-click.js]
 skip-if = e10s || (os == 'mac' || os == 'win') && (debug == false) # Bug 986166
 [browser_dbg_variables-view-edit-getset-01.js]
 skip-if = e10s && debug
--- a/devtools/client/inspector/computed/test/browser.ini
+++ b/devtools/client/inspector/computed/test/browser.ini
@@ -29,13 +29,15 @@ support-files =
 [browser_computed_no-results-placeholder.js]
 [browser_computed_original-source-link.js]
 [browser_computed_pseudo-element_01.js]
 [browser_computed_refresh-on-style-change_01.js]
 [browser_computed_search-filter.js]
 [browser_computed_search-filter_clear.js]
 [browser_computed_search-filter_context-menu.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_computed_search-filter_escape-keypress.js]
 [browser_computed_search-filter_noproperties.js]
 [browser_computed_select-and-copy-styles.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_computed_style-editor-link.js]
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -75,16 +75,17 @@ skip-if = os == "mac" # Full keyboard na
 [browser_markup_accessibility_semantics.js]
 [browser_markup_anonymous_01.js]
 [browser_markup_anonymous_02.js]
 skip-if = e10s # scratchpad.xul is not loading in e10s window
 [browser_markup_anonymous_03.js]
 [browser_markup_anonymous_04.js]
 [browser_markup_copy_image_data.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_markup_css_completion_style_attribute_01.js]
 [browser_markup_css_completion_style_attribute_02.js]
 [browser_markup_css_completion_style_attribute_03.js]
 [browser_markup_dragdrop_autoscroll_01.js]
 [browser_markup_dragdrop_autoscroll_02.js]
 [browser_markup_dragdrop_distance.js]
 [browser_markup_dragdrop_draggable.js]
 [browser_markup_dragdrop_dragRootNode.js]
@@ -113,16 +114,17 @@ skip-if = true # Bug 1177550
 [browser_markup_events_react_production_15.3.1.js]
 [browser_markup_events_react_production_15.3.1_jsx.js]
 [browser_markup_events-windowed-host.js]
 [browser_markup_links_01.js]
 [browser_markup_links_02.js]
 [browser_markup_links_03.js]
 [browser_markup_links_04.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_markup_links_05.js]
 [browser_markup_links_06.js]
 [browser_markup_links_07.js]
 [browser_markup_load_01.js]
 [browser_markup_html_edit_01.js]
 [browser_markup_html_edit_02.js]
 [browser_markup_html_edit_03.js]
 [browser_markup_image_tooltip.js]
--- a/devtools/client/inspector/rules/test/browser.ini
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -85,16 +85,17 @@ support-files =
 [browser_rules_content_01.js]
 [browser_rules_content_02.js]
 skip-if = e10s && debug # Bug 1250058 - Docshell leak on debug e10s
 [browser_rules_context-menu-show-mdn-docs-01.js]
 [browser_rules_context-menu-show-mdn-docs-02.js]
 [browser_rules_context-menu-show-mdn-docs-03.js]
 [browser_rules_copy_styles.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_rules_cssom.js]
 [browser_rules_cubicbezier-appears-on-swatch-click.js]
 [browser_rules_cubicbezier-commit-on-ENTER.js]
 [browser_rules_cubicbezier-revert-on-ESC.js]
 [browser_rules_custom.js]
 [browser_rules_cycle-angle.js]
 [browser_rules_cycle-color.js]
 [browser_rules_edit-display-grid-property.js]
@@ -196,19 +197,21 @@ skip-if = (os == "win" && debug) # bug 9
 [browser_rules_search-filter_05.js]
 [browser_rules_search-filter_06.js]
 [browser_rules_search-filter_07.js]
 [browser_rules_search-filter_08.js]
 [browser_rules_search-filter_09.js]
 [browser_rules_search-filter_10.js]
 [browser_rules_search-filter_context-menu.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_rules_search-filter_escape-keypress.js]
 [browser_rules_select-and-copy-styles.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_rules_selector-highlighter-on-navigate.js]
 [browser_rules_selector-highlighter_01.js]
 [browser_rules_selector-highlighter_02.js]
 [browser_rules_selector-highlighter_03.js]
 [browser_rules_selector-highlighter_04.js]
 [browser_rules_selector_highlight.js]
 [browser_rules_strict-search-filter-computed-list_01.js]
 [browser_rules_strict-search-filter_01.js]
--- a/devtools/client/inspector/shared/test/browser.ini
+++ b/devtools/client/inspector/shared/test/browser.ini
@@ -17,18 +17,20 @@ support-files =
   !/devtools/client/inspector/test/head.js
   !/devtools/client/inspector/test/shared-head.js
   !/devtools/client/shared/test/test-actor.js
   !/devtools/client/shared/test/test-actor-registry.js
 
 [browser_styleinspector_context-menu-copy-color_01.js]
 [browser_styleinspector_context-menu-copy-color_02.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_styleinspector_context-menu-copy-urls.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_styleinspector_csslogic-content-stylesheets.js]
 skip-if = e10s && debug # Bug 1250058 (docshell leak when opening 2 toolboxes)
 [browser_styleinspector_output-parser.js]
 [browser_styleinspector_refresh_when_active.js]
 [browser_styleinspector_tooltip-background-image.js]
 [browser_styleinspector_tooltip-closes-on-new-selection.js]
 skip-if = e10s # Bug 1111546 (e10s)
 [browser_styleinspector_tooltip-longhand-fontfamily.js]
--- a/devtools/client/inspector/test/browser.ini
+++ b/devtools/client/inspector/test/browser.ini
@@ -72,16 +72,17 @@ skip-if = os == "mac" # Full keyboard na
 [browser_inspector_highlighter-cancel.js]
 [browser_inspector_highlighter-comments.js]
 [browser_inspector_highlighter-cssgrid_01.js]
 [browser_inspector_highlighter-csstransform_01.js]
 [browser_inspector_highlighter-csstransform_02.js]
 [browser_inspector_highlighter-embed.js]
 [browser_inspector_highlighter-eyedropper-clipboard.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_inspector_highlighter-eyedropper-csp.js]
 [browser_inspector_highlighter-eyedropper-events.js]
 [browser_inspector_highlighter-eyedropper-image.js]
 [browser_inspector_highlighter-eyedropper-label.js]
 [browser_inspector_highlighter-eyedropper-show-hide.js]
 [browser_inspector_highlighter-eyedropper-xul.js]
 [browser_inspector_highlighter-geometry_01.js]
 [browser_inspector_highlighter-geometry_02.js]
@@ -117,25 +118,30 @@ subsuite = clipboard
 [browser_inspector_infobar_03.js]
 [browser_inspector_infobar_textnode.js]
 [browser_inspector_initialization.js]
 skip-if = (e10s && debug) # Bug 1250058 - Docshell leak on debug e10s
 [browser_inspector_inspect-object-element.js]
 [browser_inspector_invalidate.js]
 [browser_inspector_keyboard-shortcuts-copy-outerhtml.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_inspector_keyboard-shortcuts.js]
 [browser_inspector_menu-01-sensitivity.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_inspector_menu-02-copy-items.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_inspector_menu-03-paste-items.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_inspector_menu-03-paste-items-svg.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_inspector_menu-04-use-in-console.js]
 [browser_inspector_menu-05-attribute-items.js]
 [browser_inspector_menu-06-other.js]
 [browser_inspector_navigation.js]
 [browser_inspector_navigate_to_errors.js]
 [browser_inspector_open_on_neterror.js]
 [browser_inspector_pane-toggle-01.js]
 [browser_inspector_pane-toggle-02.js]
@@ -156,16 +162,17 @@ skip-if = os == "mac" # Full keyboard na
 [browser_inspector_search-04.js]
 [browser_inspector_search-05.js]
 [browser_inspector_search-06.js]
 [browser_inspector_search-07.js]
 [browser_inspector_search-08.js]
 [browser_inspector_search-clear.js]
 [browser_inspector_search-filter_context-menu.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_inspector_search_keyboard_trap.js]
 [browser_inspector_search-label.js]
 [browser_inspector_search-reserved.js]
 [browser_inspector_search-selection.js]
 [browser_inspector_search-sidebar.js]
 [browser_inspector_select-docshell.js]
 [browser_inspector_select-last-selected.js]
 [browser_inspector_search-navigation.js]
--- a/devtools/client/jsonview/test/browser.ini
+++ b/devtools/client/jsonview/test/browser.ini
@@ -13,16 +13,19 @@ support-files =
   valid_json.json
   valid_json.json^headers^
   !/devtools/client/commandline/test/head.js
   !/devtools/client/framework/test/head.js
   !/devtools/client/framework/test/shared-head.js
 
 [browser_jsonview_copy_headers.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_jsonview_copy_json.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_jsonview_copy_rawdata.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_jsonview_filter.js]
 [browser_jsonview_invalid_json.js]
 [browser_jsonview_valid_json.js]
 [browser_jsonview_save_json.js]
--- a/devtools/client/netmonitor/har/test/browser.ini
+++ b/devtools/client/netmonitor/har/test/browser.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 tags = devtools
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 support-files =
   head.js
   html_har_post-data-test-page.html
   !/devtools/client/netmonitor/test/head.js
   !/devtools/client/netmonitor/test/html_simple-test-page.html
 
 [browser_net_har_copy_all_as_har.js]
 [browser_net_har_post_data.js]
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -68,28 +68,35 @@ skip-if = (toolkit == "cocoa" && e10s) #
 [browser_net_charts-07.js]
 [browser_net_clear.js]
 [browser_net_complex-params.js]
 [browser_net_content-type.js]
 [browser_net_brotli.js]
 [browser_net_curl-utils.js]
 [browser_net_copy_image_as_data_uri.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_net_copy_svg_image_as_data_uri.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_net_copy_url.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_net_copy_params.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_net_copy_response.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_net_copy_headers.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_net_copy_as_curl.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_net_cors_requests.js]
 [browser_net_cyrillic-01.js]
 [browser_net_cyrillic-02.js]
 [browser_net_details-no-duplicated-content.js]
 skip-if = true # Test broken in React version, is too low-level
 [browser_net_frame.js]
 skip-if = (os == 'linux' && debug && bits == 32) # Bug 1321434
 [browser_net_filter-01.js]
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
@@ -17,18 +17,20 @@ support-files =
   test-stacktrace-location-debugger-link.html
   !/devtools/client/framework/test/shared-head.js
 
 [browser_webconsole_batching.js]
 [browser_webconsole_console_group.js]
 [browser_webconsole_console_table.js]
 [browser_webconsole_context_menu_copy_entire_message.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_context_menu_copy_link_location.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_context_menu_open_in_var_view.js]
 [browser_webconsole_context_menu_open_url.js]
 [browser_webconsole_context_menu_store_as_global.js]
 [browser_webconsole_filters.js]
 [browser_webconsole_init.js]
 [browser_webconsole_input_focus.js]
 [browser_webconsole_keyboard_accessibility.js]
 [browser_webconsole_location_debugger_link.js]
--- a/devtools/client/webconsole/test/browser.ini
+++ b/devtools/client/webconsole/test/browser.ini
@@ -146,35 +146,38 @@ support-files =
   !/devtools/client/netmonitor/test/sjs_cors-test-server.sjs
   !/image/test/mochitest/blue.png
 
 [browser_bug1045902_console_csp_ignore_reflected_xss_message.js]
 skip-if = (e10s && debug) || (e10s && os == 'win') # Bug 1221499 enabled these on windows
 [browser_bug664688_sandbox_update_after_navigation.js]
 [browser_bug_638949_copy_link_location.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_bug_862916_console_dir_and_filter_off.js]
 skip-if = (e10s && (os == 'win' || os == 'mac')) # Bug 1243976
 [browser_bug_865288_repeat_different_objects.js]
 [browser_bug_865871_variables_view_close_on_esc_key.js]
 [browser_bug_869003_inspect_cross_domain_object.js]
 [browser_bug_871156_ctrlw_close_tab.js]
 [browser_cached_messages.js]
 [browser_console.js]
 [browser_console_addonsdk_loader_exception.js]
 [browser_console_clear_method.js]
 [browser_console_clear_on_reload.js]
 [browser_console_click_focus.js]
 [browser_console_consolejsm_output.js]
 [browser_console_copy_command.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_console_dead_objects.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_console_copy_entire_message_context_menu.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_console_error_source_click.js]
 [browser_console_filters.js]
 [browser_console_iframe_messages.js]
 [browser_console_keyboard_accessibility.js]
 [browser_console_log_inspectable_object.js]
 [browser_console_native_getters.js]
 [browser_console_navigation_marker.js]
 [browser_console_netlogging.js]
@@ -215,16 +218,17 @@ tags = mcb
 [browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js]
 [browser_webconsole_bug_585237_line_limit.js]
 [browser_webconsole_bug_585956_console_trace.js]
 [browser_webconsole_bug_585991_autocomplete_keys.js]
 [browser_webconsole_bug_585991_autocomplete_popup.js]
 [browser_webconsole_bug_586388_select_all.js]
 [browser_webconsole_bug_587617_output_copy.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_bug_588342_document_focus.js]
 [browser_webconsole_bug_588730_text_node_insertion.js]
 [browser_webconsole_bug_588967_input_expansion.js]
 [browser_webconsole_bug_589162_css_filter.js]
 [browser_webconsole_bug_592442_closing_brackets.js]
 [browser_webconsole_bug_593003_iframe_wrong_hud.js]
 [browser_webconsole_bug_594497_history_arrow_keys.js]
 [browser_webconsole_bug_595223_file_uri.js]
@@ -242,16 +246,17 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_webconsole_bug_601177_log_levels.js]
 [browser_webconsole_bug_601352_scroll.js]
 [browser_webconsole_bug_601667_filter_buttons.js]
 [browser_webconsole_bug_603750_websocket.js]
 [browser_webconsole_bug_611795.js]
 [browser_webconsole_bug_613013_console_api_iframe.js]
 [browser_webconsole_bug_613280_jsterm_copy.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_bug_613642_maintain_scroll.js]
 [browser_webconsole_bug_613642_prune_scroll.js]
 [browser_webconsole_bug_614793_jsterm_scroll.js]
 [browser_webconsole_bug_618078_network_exceptions.js]
 [browser_webconsole_bug_621644_jsterm_dollar.js]
 [browser_webconsole_bug_622303_persistent_filters.js]
 [browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js]
 skip-if = os != "win"
@@ -259,16 +264,17 @@ skip-if = os != "win"
 [browser_webconsole_bug_632275_getters_document_width.js]
 [browser_webconsole_bug_632347_iterators_generators.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_632817.js]
 skip-if = true # Bug 1244707
 [browser_webconsole_bug_642108_pruneTest.js]
 [browser_webconsole_autocomplete_and_selfxss.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_bug_644419_log_limits.js]
 [browser_webconsole_bug_646025_console_file_location.js]
 [browser_webconsole_bug_651501_document_body_autocomplete.js]
 [browser_webconsole_bug_653531_highlighter_console_helper.js]
 skip-if = true # Requires direct access to content nodes
 [browser_webconsole_bug_658368_time_methods.js]
 [browser_webconsole_bug_659907_console_dir.js]
 [browser_webconsole_bug_660806_history_nav.js]
@@ -334,16 +340,17 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_webconsole_netlogging_basic.js]
 [browser_webconsole_netlogging_panel.js]
 [browser_webconsole_netlogging_reset_filter.js]
 [browser_webconsole_notifications.js]
 [browser_webconsole_open-links-without-callback.js]
 [browser_webconsole_promise.js]
 [browser_webconsole_output_copy_newlines.js]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_output_order.js]
 [browser_webconsole_property_provider.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_scratchpad_panel_link.js]
 [browser_webconsole_split.js]
 [browser_webconsole_split_escape_key.js]
 [browser_webconsole_split_focus.js]
 [browser_webconsole_split_persist.js]
--- a/devtools/server/actors/actor-registry.js
+++ b/devtools/server/actors/actor-registry.js
@@ -1,20 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const protocol = require("devtools/shared/protocol");
-const { method, custom, Arg, Option, RetVal } = protocol;
 
-const { Cu, CC, components } = require("chrome");
-const Services = require("Services");
-const { DebuggerServer } = require("devtools/server/main");
 const { registerActor, unregisterActor } = require("devtools/server/actors/utils/actor-registry-utils");
 const { actorActorSpec, actorRegistrySpec } = require("devtools/shared/specs/actor-registry");
 
 /**
  * The ActorActor gives you a handle to an actor you've dynamically
  * registered and allows you to unregister it.
  */
 const ActorActor = protocol.ActorClassWithSpec(actorActorSpec, {
--- a/devtools/server/actors/addon.js
+++ b/devtools/server/actors/addon.js
@@ -15,19 +15,19 @@ var { assert, update } = DevToolsUtils;
 
 loader.lazyRequireGetter(this, "AddonThreadActor", "devtools/server/actors/script", true);
 loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/script", true);
 loader.lazyRequireGetter(this, "mapURIToAddonID", "devtools/server/actors/utils/map-uri-to-addon-id");
 loader.lazyRequireGetter(this, "WebConsoleActor", "devtools/server/actors/webconsole", true);
 
 loader.lazyImporter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
 
-function BrowserAddonActor(aConnection, aAddon) {
-  this.conn = aConnection;
-  this._addon = aAddon;
+function BrowserAddonActor(connection, addon) {
+  this.conn = connection;
+  this._addon = addon;
   this._contextPool = new ActorPool(this.conn);
   this.conn.addActorPool(this._contextPool);
   this.threadActor = null;
   this._global = null;
 
   this._shouldAddNewGlobalAsDebuggee = this._shouldAddNewGlobalAsDebuggee.bind(this);
 
   this.makeDebugger = makeDebugger.bind(null, {
@@ -65,17 +65,17 @@ BrowserAddonActor.prototype = {
   get sources() {
     if (!this._sources) {
       assert(this.threadActor, "threadActor should exist when creating sources.");
       this._sources = new TabSources(this.threadActor, this._allowSource);
     }
     return this._sources;
   },
 
-  form: function BAA_form() {
+  form: function BAAForm() {
     assert(this.actorID, "addon should have an actorID.");
     if (!this._consoleActor) {
       this._consoleActor = new AddonConsoleActor(this._addon, this.conn, this);
       this._contextPool.addActor(this._consoleActor);
     }
 
     return {
       actor: this.actorID,
@@ -98,85 +98,86 @@ BrowserAddonActor.prototype = {
     this.conn.removeActorPool(this._contextPool);
     this._contextPool = null;
     this._consoleActor = null;
     this._addon = null;
     this._global = null;
     AddonManager.removeAddonListener(this);
   },
 
-  setOptions: function BAA_setOptions(aOptions) {
-    if ("global" in aOptions) {
-      this._global = aOptions.global;
+  setOptions: function BAASetOptions(options) {
+    if ("global" in options) {
+      this._global = options.global;
     }
   },
 
-  onInstalled: function BAA_updateAddonWrapper(aAddon) {
-    if (aAddon.id != this._addon.id) {
+  onInstalled: function BAAUpdateAddonWrapper(addon) {
+    if (addon.id != this._addon.id) {
       return;
     }
 
     // Update the AddonManager's addon object on reload/update.
-    this._addon = aAddon;
+    this._addon = addon;
   },
 
-  onDisabled: function BAA_onDisabled(aAddon) {
-    if (aAddon != this._addon) {
+  onDisabled: function BAAOnDisabled(addon) {
+    if (addon != this._addon) {
       return;
     }
 
     this._global = null;
   },
 
-  onUninstalled: function BAA_onUninstalled(aAddon) {
-    if (aAddon != this._addon) {
+  onUninstalled: function BAAOnUninstalled(addon) {
+    if (addon != this._addon) {
       return;
     }
 
     if (this.attached) {
       this.onDetach();
 
       // The BrowserAddonActor is not a TabActor and it has to send
       // "tabDetached" directly to close the devtools toolbox window.
       this.conn.send({ from: this.actorID, type: "tabDetached" });
     }
 
     this.destroy();
   },
 
-  onAttach: function BAA_onAttach() {
+  onAttach: function BAAOnAttach() {
     if (this.exited) {
       return { type: "exited" };
     }
 
     if (!this.attached) {
       this.threadActor = new AddonThreadActor(this.conn, this);
       this._contextPool.addActor(this.threadActor);
     }
 
     return { type: "tabAttached", threadActor: this.threadActor.actorID };
   },
 
-  onDetach: function BAA_onDetach() {
+  onDetach: function BAAOnDetach() {
     if (!this.attached) {
       return { error: "wrongState" };
     }
 
     this._contextPool.removeActor(this.threadActor);
 
     this.threadActor = null;
     this._sources = null;
 
     return { type: "detached" };
   },
 
-  onReload: function BAA_onReload() {
+  onReload: function BAAOnReload() {
     return this._addon.reload()
       .then(() => {
-        return {}; // send an empty response
+        // send an empty response
+        return {};
       });
   },
 
   preNest: function () {
     let e = Services.wm.getEnumerator(null);
     while (e.hasMoreElements()) {
       let win = e.getNext();
       let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -196,39 +197,40 @@ BrowserAddonActor.prototype = {
       windowUtils.suppressEventHandling(false);
     }
   },
 
   /**
    * Return true if the given global is associated with this addon and should be
    * added as a debuggee, false otherwise.
    */
-  _shouldAddNewGlobalAsDebuggee: function (aGlobal) {
-    const global = unwrapDebuggerObjectGlobal(aGlobal);
+  _shouldAddNewGlobalAsDebuggee: function (givenGlobal) {
+    const global = unwrapDebuggerObjectGlobal(givenGlobal);
     try {
       // This will fail for non-Sandbox objects, hence the try-catch block.
       let metadata = Cu.getSandboxMetadata(global);
       if (metadata) {
         return metadata.addonID === this.id;
       }
-    } catch (e) {}
+    } catch (e) {
+      // ignore
+    }
 
     if (global instanceof Ci.nsIDOMWindow) {
       return mapURIToAddonID(global.document.documentURIObject) == this.id;
     }
 
     // Check the global for a __URI__ property and then try to map that to an
     // add-on
-    let uridescriptor = aGlobal.getOwnPropertyDescriptor("__URI__");
+    let uridescriptor = givenGlobal.getOwnPropertyDescriptor("__URI__");
     if (uridescriptor && "value" in uridescriptor && uridescriptor.value) {
       let uri;
       try {
         uri = Services.io.newURI(uridescriptor.value);
-      }
-      catch (e) {
+      } catch (e) {
         DevToolsUtils.reportException(
           "BrowserAddonActor.prototype._shouldAddNewGlobalAsDebuggee",
           new Error("Invalid URI: " + uridescriptor.value)
         );
         return false;
       }
 
       if (mapURIToAddonID(uri) == this.id) {
@@ -239,19 +241,19 @@ BrowserAddonActor.prototype = {
     return false;
   },
 
   /**
    * Override the eligibility check for scripts and sources to make
    * sure every script and source with a URL is stored when debugging
    * add-ons.
    */
-  _allowSource: function (aSource) {
+  _allowSource: function (source) {
     // XPIProvider.jsm evals some code in every add-on's bootstrap.js. Hide it.
-    if (aSource.url === "resource://gre/modules/addons/XPIProvider.jsm") {
+    if (source.url === "resource://gre/modules/addons/XPIProvider.jsm") {
       return false;
     }
 
     return true;
   },
 
   /**
    * Yield the current set of globals associated with this addon that should be
@@ -268,27 +270,26 @@ BrowserAddonActor.prototype.requestTypes
   "reload": BrowserAddonActor.prototype.onReload
 };
 
 /**
  * The AddonConsoleActor implements capabilities needed for the add-on web
  * console feature.
  *
  * @constructor
- * @param object aAddon
+ * @param object addon
  *        The add-on that this console watches.
- * @param object aConnection
+ * @param object connection
  *        The connection to the client, DebuggerServerConnection.
- * @param object aParentActor
+ * @param object parentActor
  *        The parent BrowserAddonActor actor.
  */
-function AddonConsoleActor(aAddon, aConnection, aParentActor)
-{
-  this.addon = aAddon;
-  WebConsoleActor.call(this, aConnection, aParentActor);
+function AddonConsoleActor(addon, connection, parentActor) {
+  this.addon = addon;
+  WebConsoleActor.call(this, connection, parentActor);
 }
 
 AddonConsoleActor.prototype = Object.create(WebConsoleActor.prototype);
 
 update(AddonConsoleActor.prototype, {
   constructor: AddonConsoleActor,
 
   actorPrefix: "addonConsole",
@@ -311,27 +312,26 @@ update(AddonConsoleActor.prototype, {
   destroy() {
     WebConsoleActor.prototype.destroy.call(this);
     this.addon = null;
   },
 
   /**
    * Handler for the "startListeners" request.
    *
-   * @param object aRequest
+   * @param object request
    *        The JSON request object received from the Web Console client.
    * @return object
    *         The response object which holds the startedListeners array.
    */
-  onStartListeners: function ACA_onStartListeners(aRequest)
-  {
+  onStartListeners: function ACAOnStartListeners(request) {
     let startedListeners = [];
 
-    while (aRequest.listeners.length > 0) {
-      let listener = aRequest.listeners.shift();
+    while (request.listeners.length > 0) {
+      let listener = request.listeners.shift();
       switch (listener) {
         case "ConsoleAPI":
           if (!this.consoleAPIListener) {
             this.consoleAPIListener =
               new ConsoleAPIListener(null, this, { addonId: this.addon.id });
             this.consoleAPIListener.init();
           }
           startedListeners.push(listener);
@@ -341,10 +341,13 @@ update(AddonConsoleActor.prototype, {
     return {
       startedListeners: startedListeners,
       nativeConsoleAPI: true,
       traits: this.traits,
     };
   },
 });
 
-AddonConsoleActor.prototype.requestTypes = Object.create(WebConsoleActor.prototype.requestTypes);
-AddonConsoleActor.prototype.requestTypes.startListeners = AddonConsoleActor.prototype.onStartListeners;
+AddonConsoleActor.prototype.requestTypes = Object.create(
+  WebConsoleActor.prototype.requestTypes
+);
+AddonConsoleActor.prototype.requestTypes.startListeners =
+  AddonConsoleActor.prototype.onStartListeners;
--- a/devtools/server/actors/addons.js
+++ b/devtools/server/actors/addons.js
@@ -29,13 +29,12 @@ const AddonsActor = protocol.ActorClassW
     // TODO: once the add-on actor has been refactored to use
     // protocol.js, we could return it directly.
     // return new BrowserAddonActor(this.conn, addon);
 
     // Return a pseudo add-on object that a calling client can work
     // with. Provide a flag that the client can use to detect when it
     // gets upgraded to a real actor object.
     return { id: addon.id, actor: false };
-
   }),
 });
 
 exports.AddonsActor = AddonsActor;
--- a/devtools/server/actors/animation.js
+++ b/devtools/server/actors/animation.js
@@ -22,19 +22,18 @@
  * - WebAnimation spec:
  *   http://w3c.github.io/web-animations/
  * - WebAnimation WebIDL files:
  *   /dom/webidl/Animation*.webidl
  */
 
 const {Cu} = require("chrome");
 const promise = require("promise");
-const {Task} = require("devtools/shared/task");
 const protocol = require("devtools/shared/protocol");
-const {Actor, ActorClassWithSpec} = protocol;
+const {Actor} = protocol;
 const {animationPlayerSpec, animationsSpec} = require("devtools/shared/specs/animation");
 const events = require("sdk/event/core");
 
 // Types of animations.
 const ANIMATION_TYPES = {
   CSS_ANIMATION: "cssanimation",
   CSS_TRANSITION: "csstransition",
   SCRIPT_ANIMATION: "scriptanimation",
@@ -469,18 +468,18 @@ var AnimationPlayerActor = protocol.Acto
   }
 });
 
 exports.AnimationPlayerActor = AnimationPlayerActor;
 
 /**
  * The Animations actor lists animation players for a given node.
  */
-var AnimationsActor = exports.AnimationsActor = protocol.ActorClassWithSpec(animationsSpec, {
-  initialize: function(conn, tabActor) {
+exports.AnimationsActor = protocol.ActorClassWithSpec(animationsSpec, {
+  initialize: function (conn, tabActor) {
     Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
 
     this.onWillNavigate = this.onWillNavigate.bind(this);
     this.onNavigate = this.onNavigate.bind(this);
     this.onAnimationMutation = this.onAnimationMutation.bind(this);
 
     this.allAnimationsPaused = false;
--- a/devtools/server/actors/breakpoint.js
+++ b/devtools/server/actors/breakpoint.js
@@ -1,14 +1,16 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+/* global assert */
+
 "use strict";
 
 const { ActorClassWithSpec } = require("devtools/shared/protocol");
 const { breakpointSpec } = require("devtools/shared/specs/breakpoint");
 
 /**
  * Set breakpoints on all the given entry points with the given
  * BreakpointActor as the handler.
@@ -106,30 +108,31 @@ let BreakpointActor = ActorClassWithSpec
         let message = "Unknown exception";
         try {
           if (completion.throw.getOwnPropertyDescriptor) {
             message = completion.throw.getOwnPropertyDescriptor("message")
                       .value;
           } else if (completion.toString) {
             message = completion.toString();
           }
-        } catch (ex) {}
+        } catch (ex) {
+          // ignore
+        }
         return {
           result: true,
           message: message
         };
       } else if (completion.yield) {
         assert(false, "Shouldn't ever get yield completions from an eval");
       } else {
-        return { result: completion.return ? true : false };
+        return { result: !!completion.return };
       }
-    } else {
-      // The evaluation was killed (possibly by the slow script dialog)
-      return { result: undefined };
     }
+    // The evaluation was killed (possibly by the slow script dialog)
+    return { result: undefined };
   },
 
   /**
    * A function that the engine calls when a breakpoint has been hit.
    *
    * @param frame Debugger.Frame
    *        The stack frame that contained the breakpoint.
    */
--- a/devtools/server/actors/call-watcher.js
+++ b/devtools/server/actors/call-watcher.js
@@ -1,20 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const {Cc, Ci, Cu, Cr} = require("chrome");
+/* global XPCNativeWrapper */
+
+const {Ci, Cu} = require("chrome");
 const events = require("sdk/event/core");
 const protocol = require("devtools/shared/protocol");
 const {serializeStack, parseStack} = require("toolkit/loader");
 
-const {on, once, off, emit} = events;
-const {method, Arg, Option, RetVal} = protocol;
+const {on, off, emit} = events;
 
 const { functionCallSpec, callWatcherSpec } = require("devtools/shared/specs/call-watcher");
 const { CallWatcherFront } = require("devtools/shared/fronts/call-watcher");
 
 /**
  * This actor contains information about a function call, like the function
  * type, name, stack, arguments, returned value etc.
  */
@@ -43,17 +44,21 @@ var FunctionCallActor = protocol.ActorCl
    * @param array args
    *        The called function's arguments.
    * @param any result
    *        The value returned by the function call.
    * @param boolean holdWeak
    *        Determines whether or not FunctionCallActor stores a weak reference
    *        to the underlying objects.
    */
-  initialize: function (conn, [window, global, caller, type, name, stack, timestamp, args, result], holdWeak) {
+  initialize: function (
+    conn,
+    [window, global, caller, type, name, stack, timestamp, args, result],
+    holdWeak
+  ) {
     protocol.Actor.prototype.initialize.call(this, conn);
 
     this.details = {
       global: global,
       type: type,
       name: name,
       stack: stack,
       timestamp: timestamp
@@ -71,19 +76,18 @@ var FunctionCallActor = protocol.ActorCl
       };
 
       Object.defineProperties(this.details, {
         window: { get: () => weakRefs.window.get() },
         caller: { get: () => weakRefs.caller.get() },
         args: { get: () => weakRefs.args.get() },
         result: { get: () => weakRefs.result.get() },
       });
-    }
-    // Otherwise, hold strong references to the objects.
-    else {
+    } else {
+      // Otherwise, hold strong references to the objects.
       this.details.window = window;
       this.details.caller = caller;
       this.details.args = args;
       this.details.result = result;
     }
 
     // The caller, args and results are string names for now. It would
     // certainly be nicer if they were Object actors. Make this smarter, so
@@ -221,17 +225,17 @@ var FunctionCallActor = protocol.ActorCl
     }
     return data + "";
   }
 });
 
 /**
  * This actor observes function calls on certain objects or globals.
  */
-var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClassWithSpec(callWatcherSpec, {
+exports.CallWatcherActor = protocol.ActorClassWithSpec(callWatcherSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this._onGlobalCreated = this._onGlobalCreated.bind(this);
     this._onGlobalDestroyed = this._onGlobalDestroyed.bind(this);
     this._onContentFunctionCall = this._onContentFunctionCall.bind(this);
     on(this.tabActor, "window-ready", this._onGlobalCreated);
     on(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
@@ -250,17 +254,19 @@ var CallWatcherActor = exports.CallWatch
    */
   onCall: null,
 
   /**
    * Starts waiting for the current tab actor's document global to be
    * created, in order to instrument the specified objects and become
    * aware of everything the content does with them.
    */
-  setup: function ({ tracedGlobals, tracedFunctions, startRecording, performReload, holdWeak, storeCalls }) {
+  setup: function ({
+    tracedGlobals, tracedFunctions, startRecording, performReload, holdWeak, storeCalls
+  }) {
     if (this._initialized) {
       return;
     }
     this._initialized = true;
     this._timestampEpoch = 0;
 
     this._functionCalls = [];
     this._tracedGlobals = tracedGlobals || [];
@@ -357,110 +363,117 @@ var CallWatcherActor = exports.CallWatch
     for (let name of this._tracedFunctions) {
       overrideSymbol("window", unwrappedWindow, name, callback);
     }
 
     /**
      * Instruments a method, getter or setter on the specified target object to
      * invoke a callback whenever it is called.
      */
-    function overrideSymbol(global, target, name, callback) {
+    function overrideSymbol(global, target, name, subcallback) {
       let propertyDescriptor = Object.getOwnPropertyDescriptor(target, name);
 
       if (propertyDescriptor.get || propertyDescriptor.set) {
-        overrideAccessor(global, target, name, propertyDescriptor, callback);
+        overrideAccessor(global, target, name, propertyDescriptor, subcallback);
         return;
       }
       if (propertyDescriptor.writable && typeof propertyDescriptor.value == "function") {
-        overrideFunction(global, target, name, propertyDescriptor, callback);
-        return;
+        overrideFunction(global, target, name, propertyDescriptor, subcallback);
       }
     }
 
     /**
      * Instruments a function on the specified target object.
      */
-    function overrideFunction(global, target, name, descriptor, callback) {
+    function overrideFunction(global, target, name, descriptor, subcallback) {
       // Invoking .apply on an unxrayed content function doesn't work, because
       // the arguments array is inaccessible to it. Get Xrays back.
       let originalFunc = Cu.unwaiveXrays(target[name]);
 
       Cu.exportFunction(function (...args) {
         let result;
         try {
           result = Cu.waiveXrays(originalFunc.apply(this, args));
         } catch (e) {
           throw createContentError(e, unwrappedWindow);
         }
 
         if (self._recording) {
           let type = CallWatcherFront.METHOD_FUNCTION;
           let stack = getStack(name);
           let timestamp = self.tabActor.window.performance.now() - self._timestampEpoch;
-          callback(unwrappedWindow, global, this, type, name, stack, timestamp, args, result);
+          subcallback(unwrappedWindow, global, this, type, name, stack, timestamp,
+            args, result);
         }
         return result;
       }, target, { defineAs: name });
 
       Object.defineProperty(target, name, {
         configurable: descriptor.configurable,
         enumerable: descriptor.enumerable,
         writable: true
       });
     }
 
     /**
      * Instruments a getter or setter on the specified target object.
      */
-    function overrideAccessor(global, target, name, descriptor, callback) {
+    function overrideAccessor(global, target, name, descriptor, subcallback) {
       // Invoking .apply on an unxrayed content function doesn't work, because
       // the arguments array is inaccessible to it. Get Xrays back.
       let originalGetter = Cu.unwaiveXrays(target.__lookupGetter__(name));
       let originalSetter = Cu.unwaiveXrays(target.__lookupSetter__(name));
 
       Object.defineProperty(target, name, {
         get: function (...args) {
-          if (!originalGetter) return undefined;
+          if (!originalGetter) {
+            return undefined;
+          }
           let result = Cu.waiveXrays(originalGetter.apply(this, args));
 
           if (self._recording) {
             let type = CallWatcherFront.GETTER_FUNCTION;
             let stack = getStack(name);
             let timestamp = self.tabActor.window.performance.now() - self._timestampEpoch;
-            callback(unwrappedWindow, global, this, type, name, stack, timestamp, args, result);
+            subcallback(unwrappedWindow, global, this, type, name, stack, timestamp,
+              args, result);
           }
           return result;
         },
         set: function (...args) {
-          if (!originalSetter) return;
+          if (!originalSetter) {
+            return;
+          }
           originalSetter.apply(this, args);
 
           if (self._recording) {
             let type = CallWatcherFront.SETTER_FUNCTION;
             let stack = getStack(name);
             let timestamp = self.tabActor.window.performance.now() - self._timestampEpoch;
-            callback(unwrappedWindow, global, this, type, name, stack, timestamp, args, undefined);
+            subcallback(unwrappedWindow, global, this, type, name, stack, timestamp,
+              args, undefined);
           }
         },
         configurable: descriptor.configurable,
         enumerable: descriptor.enumerable
       });
     }
 
     /**
      * Stores the relevant information about calls on the stack when
      * a function is called.
      */
     function getStack(caller) {
+      let stack;
       try {
         // Using Components.stack wouldn't be a better idea, since it's
         // much slower because it attempts to retrieve the C++ stack as well.
         throw new Error();
       } catch (e) {
-        var stack = e.stack;
+        stack = e.stack;
       }
 
       // Of course, using a simple regex like /(.*?)@(.*):(\d*):\d*/ would be
       // much prettier, but this is a very hot function, so let's sqeeze
       // every drop of performance out of it.
       let calls = [];
       let callIndex = 0;
       let currNewLinePivot = stack.indexOf("\n") + 1;
@@ -583,50 +596,53 @@ function getBitToEnumValue(type, object,
     // in `table`
     flag = flag | 0;
     if (flag && (arg & flag) === flag) {
       flags.push(table[flag]);
     }
   }
 
   // Cache the combined bitmask value
-  return table[arg] = flags.join(" | ") || arg;
+  table[arg] = flags.join(" | ") || arg;
+  return table[arg];
 }
 
 /**
  * Creates a new error from an error that originated from content but was called
  * from a wrapped overridden method. This is so we can make our own error
  * that does not look like it originated from the call watcher.
  *
  * We use toolkit/loader's parseStack and serializeStack rather than the
  * parsing done in the local `getStack` function, because it does not expose
- * column number, would have to change the protocol models `call-stack-items` and `call-details`
- * which hurts backwards compatibility, and the local `getStack` is an optimized, hot function.
+ * column number, would have to change the protocol models `call-stack-items`
+ * and `call-details` which hurts backwards compatibility, and the local `getStack`
+ * is an optimized, hot function.
  */
 function createContentError(e, win) {
   let { message, name, stack } = e;
   let parsedStack = parseStack(stack);
   let { fileName, lineNumber, columnNumber } = parsedStack[parsedStack.length - 1];
   let error;
 
   let isDOMException = e instanceof Ci.nsIDOMDOMException;
   let constructor = isDOMException ? win.DOMException : (win[e.name] || win.Error);
 
   if (isDOMException) {
     error = new constructor(message, name);
     Object.defineProperties(error, {
       code: { value: e.code },
-      columnNumber: { value: 0 }, // columnNumber is always 0 for DOMExceptions?
-      filename: { value: fileName }, // note the lowercase `filename`
+      // columnNumber is always 0 for DOMExceptions?
+      columnNumber: { value: 0 },
+      // note the lowercase `filename`
+      filename: { value: fileName },
       lineNumber: { value: lineNumber },
       result: { value: e.result },
       stack: { value: serializeStack(parsedStack) }
     });
-  }
-  else {
+  } else {
     // Constructing an error here retains all the stack information,
     // and we can add message, fileName and lineNumber via constructor, though
     // need to manually add columnNumber.
     error = new constructor(message, fileName, lineNumber);
     Object.defineProperty(error, "columnNumber", {
       value: columnNumber
     });
   }
--- a/devtools/server/actors/canvas.js
+++ b/devtools/server/actors/canvas.js
@@ -1,35 +1,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const {Cc, Ci, Cu, Cr} = require("chrome");
-const events = require("sdk/event/core");
+/* global XPCNativeWrapper */
+
 const promise = require("promise");
 const protocol = require("devtools/shared/protocol");
 const {CallWatcherActor} = require("devtools/server/actors/call-watcher");
 const {CallWatcherFront} = require("devtools/shared/fronts/call-watcher");
-const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const {WebGLPrimitiveCounter} = require("devtools/server/primitive");
 const {
   frameSnapshotSpec,
   canvasSpec,
   CANVAS_CONTEXTS,
   ANIMATION_GENERATORS,
-  LOOP_GENERATORS,
-  DRAW_CALLS,
-  INTERESTING_CALLS,
+  LOOP_GENERATORS
 } = require("devtools/shared/specs/canvas");
 const {CanvasFront} = require("devtools/shared/fronts/canvas");
 
-const {on, once, off, emit} = events;
-const {method, custom, Arg, Option, RetVal} = protocol;
-
 /**
  * This actor represents a recorded animation frame snapshot, along with
  * all the corresponding canvas' context methods invoked in that frame,
  * thumbnails for each draw call and a screenshot of the end result.
  */
 var FrameSnapshotActor = protocol.ActorClassWithSpec(frameSnapshotSpec, {
   /**
    * Creates the frame snapshot call actor.
@@ -68,17 +62,16 @@ var FrameSnapshotActor = protocol.ActorC
     };
   },
 
   /**
    * Gets a screenshot of the canvas's contents after the specified
    * function was called.
    */
   generateScreenshotFor: function (functionCall) {
-    let caller = functionCall.details.caller;
     let global = functionCall.details.global;
 
     let canvas = this._contentCanvas;
     let calls = this._functionCalls;
     let index = calls.indexOf(functionCall);
 
     // To get a screenshot, replay all the steps necessary to render the frame,
     // by invoking the context calls up to and including the specified one.
@@ -86,24 +79,30 @@ var FrameSnapshotActor = protocol.ActorC
     let replayData = ContextUtils.replayAnimationFrame({
       contextType: global,
       canvas: canvas,
       calls: calls,
       first: 0,
       last: index
     });
 
-    let { replayContext, replayContextScaling, lastDrawCallIndex, doCleanup } = replayData;
+    let {
+      replayContext,
+      replayContextScaling,
+      lastDrawCallIndex,
+      doCleanup
+    } = replayData;
     let [left, top, width, height] = replayData.replayViewport;
     let screenshot;
 
     // Depending on the canvas' context, generating a screenshot is done
     // in different ways.
     if (global == "WebGLRenderingContext") {
-      screenshot = ContextUtils.getPixelsForWebGL(replayContext, left, top, width, height);
+      screenshot = ContextUtils.getPixelsForWebGL(replayContext, left, top,
+        width, height);
       screenshot.flipped = true;
     } else if (global == "CanvasRenderingContext2D") {
       screenshot = ContextUtils.getPixelsFor2D(replayContext, left, top, width, height);
       screenshot.flipped = false;
     }
 
     // In case of the WebGL context, we also need to reset the framebuffer
     // binding to the original value, after generating the screenshot.
@@ -115,17 +114,17 @@ var FrameSnapshotActor = protocol.ActorC
   }
 });
 
 /**
  * This Canvas Actor handles simple instrumentation of all the methods
  * of a 2D or WebGL context, to provide information regarding all the calls
  * made when drawing frame inside an animation loop.
  */
-var CanvasActor = exports.CanvasActor = protocol.ActorClassWithSpec(canvasSpec, {
+exports.CanvasActor = protocol.ActorClassWithSpec(canvasSpec, {
   // Reset for each recording, boolean indicating whether or not
   // any draw calls were called for a recording.
   _animationContainsDrawCall: false,
 
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this._webGLPrimitiveCounter = new WebGLPrimitiveCounter(tabActor);
@@ -185,17 +184,18 @@ var CanvasActor = exports.CanvasActor = 
    */
   isRecording: function () {
     return !!this._callWatcher.isRecording();
   },
 
   /**
    * Records a snapshot of all the calls made during the next animation frame.
    * The animation should be implemented via the de-facto requestAnimationFrame
-   * utility, or inside recursive `setTimeout`s. `setInterval` at this time are not supported.
+   * utility, or inside recursive `setTimeout`s. `setInterval` at this time are
+   * not supported.
    */
   recordAnimationFrame: function () {
     if (this._callWatcher.isRecording()) {
       return this._currentAnimationFrameSnapshot.promise;
     }
 
     this._recordingContainsDrawCall = false;
     this._callWatcher.eraseRecording();
@@ -246,31 +246,29 @@ var CanvasActor = exports.CanvasActor = 
     // used on the web, especially for old demos; it's nice to support them as well.
     if (CanvasFront.LOOP_GENERATORS.has(name)) {
       this._handleAnimationFrame(functionCall);
       return;
     }
     if (CanvasFront.DRAW_CALLS.has(name) && this._animationStarted) {
       this._handleDrawCall(functionCall);
       this._webGLPrimitiveCounter.handleDrawPrimitive(functionCall);
-      return;
     }
   },
 
   /**
    * Handle animations generated using requestAnimationFrame.
    */
   _handleAnimationFrame: function (functionCall) {
     if (!this._animationStarted) {
       this._handleAnimationFrameBegin();
-    }
-    // Check to see if draw calls occurred yet, as it could be future frames,
-    // like in the scenario where requestAnimationFrame is called to trigger an animation,
-    // and rAF is at the beginning of the animate loop.
-    else if (this._animationContainsDrawCall) {
+    } else if (this._animationContainsDrawCall) {
+      // Check to see if draw calls occurred yet, as it could be future frames,
+      // like in the scenario where requestAnimationFrame is called to trigger
+      // an animation, and rAF is at the beginning of the animate loop.
       this._handleAnimationFrameEnd(functionCall);
     }
   },
 
   /**
    * Called whenever an animation frame rendering begins.
    */
   _handleAnimationFrameBegin: function () {
@@ -289,17 +287,18 @@ var CanvasActor = exports.CanvasActor = 
     this._callWatcher.eraseRecording();
     this._animationContainsDrawCall = false;
 
     // Since the animation frame finished, get a hold of the (already retrieved)
     // canvas pixels to conveniently create a screenshot of the final rendering.
     let index = this._lastDrawCallIndex;
     let width = this._lastContentCanvasWidth;
     let height = this._lastContentCanvasHeight;
-    let flipped = !!this._lastThumbnailFlipped; // undefined -> false
+    // undefined -> false
+    let flipped = !!this._lastThumbnailFlipped;
     let pixels = ContextUtils.getPixelStorage()["8bit"];
     let primitiveResult = this._webGLPrimitiveCounter.getCounts();
     let animationFrameEndScreenshot = {
       index: index,
       width: width,
       height: height,
       scaling: 1,
       flipped: flipped,
@@ -404,18 +403,18 @@ var ContextUtils = {
    * @return object
    *         An objet containing the screenshot's width, height and pixel data,
    *         represented as an 8-bit array buffer of r, g, b, a values.
    */
   getPixelsForWebGL: function (gl,
     srcX = 0, srcY = 0,
     srcWidth = gl.canvas.width,
     srcHeight = gl.canvas.height,
-    dstHeight = srcHeight)
-  {
+    dstHeight = srcHeight
+  ) {
     let contentPixels = ContextUtils.getPixelStorage(srcWidth, srcHeight);
     let { "8bit": charView, "32bit": intView } = contentPixels;
     gl.readPixels(srcX, srcY, srcWidth, srcHeight, gl.RGBA, gl.UNSIGNED_BYTE, charView);
     return this.resizePixels(intView, srcWidth, srcHeight, dstHeight);
   },
 
   /**
    * Gets a hold of the rendered pixels in the most efficient way possible for
@@ -436,18 +435,18 @@ var ContextUtils = {
    * @return object
    *         An objet containing the screenshot's width, height and pixel data,
    *         represented as an 8-bit array buffer of r, g, b, a values.
    */
   getPixelsFor2D: function (ctx,
     srcX = 0, srcY = 0,
     srcWidth = ctx.canvas.width,
     srcHeight = ctx.canvas.height,
-    dstHeight = srcHeight)
-  {
+    dstHeight = srcHeight
+  ) {
     let { data } = ctx.getImageData(srcX, srcY, srcWidth, srcHeight);
     let { "32bit": intView } = ContextUtils.usePixelStorage(data.buffer);
     return this.resizePixels(intView, srcWidth, srcHeight, dstHeight);
   },
 
   /**
    * Resizes the provided pixels to fit inside a rectangle with the specified
    * height and the same aspect ratio as the source.
@@ -559,19 +558,18 @@ var ContextUtils = {
       let { newViewport, oldViewport } = this.setCustomViewport(gl, w, h);
       customViewport = newViewport;
 
       // Revert the framebuffer and viewport to the original values.
       doCleanup = () => {
         gl.bindFramebuffer(gl.FRAMEBUFFER, oldFramebuffer);
         gl.viewport.apply(gl, oldViewport);
       };
-    }
-    // In case of 2D contexts, draw everything on a separate canvas context.
-    else if (contextType == "CanvasRenderingContext2D") {
+    } else if (contextType == "CanvasRenderingContext2D") {
+      // In case of 2D contexts, draw everything on a separate canvas context.
       let contentDocument = canvas.ownerDocument;
       let replayCanvas = contentDocument.createElement("canvas");
       replayCanvas.width = w;
       replayCanvas.height = h;
       replayContext = replayCanvas.getContext("2d");
       replayContextScaling = 1;
       customViewport = [0, 0, w, h];
     }
@@ -584,17 +582,18 @@ var ContextUtils = {
       // to the default value, since we want to perform the rendering offscreen.
       if (name == "bindFramebuffer" && args[1] == null) {
         replayContext.bindFramebuffer(replayContext.FRAMEBUFFER, customFramebuffer);
         continue;
       }
       // Also prevent WebGL context calls that try to change the viewport
       // while our custom framebuffer is bound.
       if (name == "viewport") {
-        let framebufferBinding = replayContext.getParameter(replayContext.FRAMEBUFFER_BINDING);
+        let framebufferBinding = replayContext.getParameter(
+          replayContext.FRAMEBUFFER_BINDING);
         if (framebufferBinding == customFramebuffer) {
           replayContext.viewport.apply(replayContext, customViewport);
           continue;
         }
       }
       if (type == CallWatcherFront.METHOD_FUNCTION) {
         replayContext[name].apply(replayContext, args);
       } else if (type == CallWatcherFront.SETTER_FUNCTION) {
@@ -640,20 +639,21 @@ var ContextUtils = {
    * Creates and saves the array buffer views used by `getPixelStorage`.
    *
    * @param ArrayBuffer buffer
    *        The raw buffer used as storage for various array buffer views.
    */
   usePixelStorage: function (buffer) {
     let array8bit = new Uint8Array(buffer);
     let array32bit = new Uint32Array(buffer);
-    return this._currentPixelStorage = {
+    this._currentPixelStorage = {
       "8bit": array8bit,
       "32bit": array32bit
     };
+    return this._currentPixelStorage;
   },
 
   /**
    * Creates a framebuffer of the specified dimensions for a WebGL context,
    * assuming a RGBA color buffer, a depth buffer and no stencil buffer.
    *
    * @param WebGLRenderingContext gl
    *        The WebGL context to create and bind a framebuffer for.
@@ -675,24 +675,27 @@ var ContextUtils = {
     // Use a texture as the color renderbuffer attachment, since consumers of
     // this function will most likely want to read the rendered pixels back.
     let colorBuffer = gl.createTexture();
     gl.bindTexture(gl.TEXTURE_2D, colorBuffer);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA,
+      gl.UNSIGNED_BYTE, null);
 
     let depthBuffer = gl.createRenderbuffer();
     gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
     gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
 
-    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorBuffer, 0);
-    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
+    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D,
+      colorBuffer, 0);
+    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER,
+      depthBuffer);
 
     gl.bindTexture(gl.TEXTURE_2D, oldTextureBinding);
     gl.bindRenderbuffer(gl.RENDERBUFFER, oldRenderbufferBinding);
 
     return { oldFramebuffer, newFramebuffer };
   },
 
   /**
--- a/devtools/server/actors/child-process.js
+++ b/devtools/server/actors/child-process.js
@@ -5,24 +5,23 @@
 "use strict";
 
 const { Cc, Ci, Cu } = require("chrome");
 
 const { ChromeDebuggerActor } = require("devtools/server/actors/script");
 const { WebConsoleActor } = require("devtools/server/actors/webconsole");
 const makeDebugger = require("devtools/server/actors/utils/make-debugger");
 const { ActorPool } = require("devtools/server/main");
-const Services = require("Services");
 const { assert } = require("devtools/shared/DevToolsUtils");
 const { TabSources } = require("./utils/TabSources");
 
 loader.lazyRequireGetter(this, "WorkerActorList", "devtools/server/actors/worker-list", true);
 
-function ChildProcessActor(aConnection) {
-  this.conn = aConnection;
+function ChildProcessActor(connection) {
+  this.conn = connection;
   this._contextPool = new ActorPool(this.conn);
   this.conn.addActorPool(this._contextPool);
   this.threadActor = null;
 
   // Use a see-everything debugger
   this.makeDebugger = makeDebugger.bind(null, {
     findDebuggees: dbg => dbg.findAllGlobals(),
     shouldAddNewGlobalAsDebuggee: global => true
--- a/devtools/server/actors/childtab.js
+++ b/devtools/server/actors/childtab.js
@@ -21,18 +21,17 @@ var { TabActor } = require("devtools/ser
  * @param connection DebuggerServerConnection
  *        The conection to the client.
  * @param chromeGlobal
  *        The content script global holding |content| and |docShell| properties for a tab.
  * @param prefix
  *        the prefix used in protocol to create IDs for each actor.
  *        Used as ID identifying this particular TabActor from the parent process.
  */
-function ContentActor(connection, chromeGlobal, prefix)
-{
+function ContentActor(connection, chromeGlobal, prefix) {
   this._chromeGlobal = chromeGlobal;
   this._prefix = prefix;
   TabActor.call(this, connection, chromeGlobal);
   this.traits.reconfigure = false;
   this._sendForm = this._sendForm.bind(this);
   this._chromeGlobal.addMessageListener("debug:form", this._sendForm);
 
   Object.defineProperty(this, "docShell", {
--- a/devtools/server/actors/chrome.js
+++ b/devtools/server/actors/chrome.js
@@ -22,21 +22,21 @@ const makeDebugger = require("./utils/ma
  * so that the root actor was also exposing tab actors for the main process.
  * Tab actors ended up having RootActor as parent actor,
  * but more and more features of the tab actors were relying on TabActor.
  * So we are now exposing a process actor that offers the same API as TabActor
  * by inheriting its functionality.
  * Global actors are now only the actors that are meant to be global,
  * and are no longer related to any specific scope/document.
  *
- * @param aConnection DebuggerServerConnection
+ * @param connection DebuggerServerConnection
  *        The connection to the client.
  */
-function ChromeActor(aConnection) {
-  TabActor.call(this, aConnection);
+function ChromeActor(connection) {
+  TabActor.call(this, connection);
 
   // This creates a Debugger instance for chrome debugging all globals.
   this.makeDebugger = makeDebugger.bind(null, {
     findDebuggees: dbg => dbg.findAllGlobals(),
     shouldAddNewGlobalAsDebuggee: () => true
   });
 
   // Ensure catching the creation of any new content docshell
@@ -83,78 +83,78 @@ Object.defineProperty(ChromeActor.protot
                            .QueryInterface(Ci.nsIDocShell);
       docShells = docShells.concat(getChildDocShells(docShell));
     }
 
     return docShells;
   }
 });
 
-ChromeActor.prototype.observe = function (aSubject, aTopic, aData) {
-  TabActor.prototype.observe.call(this, aSubject, aTopic, aData);
+ChromeActor.prototype.observe = function (subject, topic, data) {
+  TabActor.prototype.observe.call(this, subject, topic, data);
   if (!this.attached) {
     return;
   }
-  if (aTopic == "chrome-webnavigation-create") {
-    aSubject.QueryInterface(Ci.nsIDocShell);
-    this._onDocShellCreated(aSubject);
-  } else if (aTopic == "chrome-webnavigation-destroy") {
-    this._onDocShellDestroy(aSubject);
+  if (topic == "chrome-webnavigation-create") {
+    subject.QueryInterface(Ci.nsIDocShell);
+    this._onDocShellCreated(subject);
+  } else if (topic == "chrome-webnavigation-destroy") {
+    this._onDocShellDestroy(subject);
   }
 };
 
 ChromeActor.prototype._attach = function () {
   if (this.attached) {
     return false;
   }
 
   TabActor.prototype._attach.call(this);
 
   // Listen for any new/destroyed chrome docshell
   Services.obs.addObserver(this, "chrome-webnavigation-create", false);
   Services.obs.addObserver(this, "chrome-webnavigation-destroy", false);
 
   // Iterate over all top-level windows.
-  let docShells = [];
   let e = Services.ww.getWindowEnumerator();
   while (e.hasMoreElements()) {
     let window = e.getNext();
     let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIWebNavigation)
                          .QueryInterface(Ci.nsIDocShell);
     if (docShell == this.docShell) {
       continue;
     }
     this._progressListener.watch(docShell);
   }
+  return undefined;
 };
 
 ChromeActor.prototype._detach = function () {
   if (!this.attached) {
     return false;
   }
 
   Services.obs.removeObserver(this, "chrome-webnavigation-create");
   Services.obs.removeObserver(this, "chrome-webnavigation-destroy");
 
   // Iterate over all top-level windows.
-  let docShells = [];
   let e = Services.ww.getWindowEnumerator();
   while (e.hasMoreElements()) {
     let window = e.getNext();
     let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIWebNavigation)
                          .QueryInterface(Ci.nsIDocShell);
     if (docShell == this.docShell) {
       continue;
     }
     this._progressListener.unwatch(docShell);
   }
 
   TabActor.prototype._detach.call(this);
+  return undefined;
 };
 
 /* ThreadActor hooks. */
 
 /**
  * Prepare to enter a nested event loop by disabling debuggee events.
  */
 ChromeActor.prototype.preNest = function () {
@@ -167,17 +167,17 @@ ChromeActor.prototype.preNest = function
     windowUtils.suppressEventHandling(true);
     windowUtils.suspendTimeouts();
   }
 };
 
 /**
  * Prepare to exit a nested event loop by enabling debuggee events.
  */
-ChromeActor.prototype.postNest = function (aNestData) {
+ChromeActor.prototype.postNest = function (nestData) {
   // Enable events in all open windows.
   let e = Services.wm.getEnumerator(null);
   while (e.hasMoreElements()) {
     let win = e.getNext();
     let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIDOMWindowUtils);
     windowUtils.resumeTimeouts();
     windowUtils.suppressEventHandling(false);
--- a/devtools/server/actors/common.js
+++ b/devtools/server/actors/common.js
@@ -73,17 +73,18 @@ function RegisteredActorFactory(options,
     // For old actors, we allow the use of a different prefix for actorID
     // than for listTabs actor names, by fetching a prefix on the actor prototype.
     // (Used by ChromeDebuggerActor)
     if (options.prototype && options.prototype.actorPrefix) {
       this._prefix = options.prototype.actorPrefix;
     }
   }
 }
-RegisteredActorFactory.prototype.createObservedActorFactory = function (conn, parentActor) {
+RegisteredActorFactory.prototype.createObservedActorFactory = function (conn,
+  parentActor) {
   return new ObservedActorFactory(this._getConstructor, this._prefix, conn, parentActor);
 };
 exports.RegisteredActorFactory = RegisteredActorFactory;
 
 /**
  * Creates "observed" actors factory meant for creating real actor instances.
  * These factories lives in actor pools and fake various actor attributes.
  * They will be replaced in actor pools by final actor instances during
@@ -105,157 +106,155 @@ function ObservedActorFactory(getConstru
 
   this.actorPrefix = prefix;
 
   this.actorID = null;
   this.registeredPool = null;
 }
 ObservedActorFactory.prototype.createActor = function () {
   // Fetch the actor constructor
-  let c = this._getConstructor();
+  let C = this._getConstructor();
   // Instantiate a new actor instance
-  let instance = new c(this._conn, this._parentActor);
+  let instance = new C(this._conn, this._parentActor);
   instance.conn = this._conn;
   instance.parentID = this._parentActor.actorID;
   // We want the newly-constructed actor to completely replace the factory
   // actor. Reusing the existing actor ID will make sure ActorPool.addActor
   // does the right thing.
   instance.actorID = this.actorID;
   this.registeredPool.addActor(instance);
   return instance;
 };
 exports.ObservedActorFactory = ObservedActorFactory;
 
-
 /**
  * Methods shared between RootActor and BrowserTabActor.
  */
 
 /**
- * Populate |this._extraActors| as specified by |aFactories|, reusing whatever
+ * Populate |this._extraActors| as specified by |factories|, reusing whatever
  * actors are already there. Add all actors in the final extra actors table to
- * |aPool|.
+ * |pool|.
  *
  * The root actor and the tab actor use this to instantiate actors that other
  * parts of the browser have specified with DebuggerServer.addTabActor and
  * DebuggerServer.addGlobalActor.
  *
- * @param aFactories
+ * @param factories
  *     An object whose own property names are the names of properties to add to
  *     some reply packet (say, a tab actor grip or the "listTabs" response
  *     form), and whose own property values are actor constructor functions, as
  *     documented for addTabActor and addGlobalActor.
  *
  * @param this
  *     The BrowserRootActor or BrowserTabActor with which the new actors will
- *     be associated. It should support whatever API the |aFactories|
+ *     be associated. It should support whatever API the |factories|
  *     constructor functions might be interested in, as it is passed to them.
  *     For the sake of CommonCreateExtraActors itself, it should have at least
  *     the following properties:
  *
  *     - _extraActors
  *        An object whose own property names are factory table (and packet)
  *        property names, and whose values are no-argument actor constructors,
  *        of the sort that one can add to an ActorPool.
  *
  *     - conn
  *        The DebuggerServerConnection in which the new actors will participate.
  *
  *     - actorID
  *        The actor's name, for use as the new actors' parentID.
  */
-exports.createExtraActors = function createExtraActors(aFactories, aPool) {
+exports.createExtraActors = function createExtraActors(factories, pool) {
   // Walk over global actors added by extensions.
-  for (let name in aFactories) {
+  for (let name in factories) {
     let actor = this._extraActors[name];
     if (!actor) {
       // Register another factory, but this time specific to this connection.
       // It creates a fake actor that looks like an regular actor in the pool,
       // but without actually instantiating the actor.
       // It will only be instantiated on the first request made to the actor.
-      actor = aFactories[name].createObservedActorFactory(this.conn, this);
+      actor = factories[name].createObservedActorFactory(this.conn, this);
       this._extraActors[name] = actor;
     }
 
     // If the actor already exists in the pool, it may have been instantiated,
     // so make sure not to overwrite it by a non-instantiated version.
-    if (!aPool.has(actor.actorID)) {
-      aPool.addActor(actor);
+    if (!pool.has(actor.actorID)) {
+      pool.addActor(actor);
     }
   }
 };
 
 /**
  * Append the extra actors in |this._extraActors|, constructed by a prior call
- * to CommonCreateExtraActors, to |aObject|.
+ * to CommonCreateExtraActors, to |object|.
  *
- * @param aObject
+ * @param object
  *     The object to which the extra actors should be added, under the
- *     property names given in the |aFactories| table passed to
+ *     property names given in the |factories| table passed to
  *     CommonCreateExtraActors.
  *
  * @param this
  *     The BrowserRootActor or BrowserTabActor whose |_extraActors| table we
  *     should use; see above.
  */
-exports.appendExtraActors = function appendExtraActors(aObject) {
+exports.appendExtraActors = function appendExtraActors(object) {
   for (let name in this._extraActors) {
     let actor = this._extraActors[name];
-    aObject[name] = actor.actorID;
+    object[name] = actor.actorID;
   }
 };
 
 /**
  * Construct an ActorPool.
  *
  * ActorPools are actorID -> actor mapping and storage.  These are
  * used to accumulate and quickly dispose of groups of actors that
  * share a lifetime.
  */
-function ActorPool(aConnection)
-{
-  this.conn = aConnection;
+function ActorPool(connection) {
+  this.conn = connection;
   this._actors = {};
 }
 
 ActorPool.prototype = {
   /**
    * Destroy the pool. This will remove all actors from the pool.
    */
-  destroy: function AP_destroy() {
+  destroy: function APDestroy() {
     for (let id in this._actors) {
       this.removeActor(this._actors[id]);
     }
   },
 
   /**
    * Add an actor to the pool. If the actor doesn't have an ID, allocate one
    * from the connection.
    *
-   * @param Object aActor
+   * @param Object actor
    *        The actor to be added to the pool.
    */
-  addActor: function AP_addActor(aActor) {
-    aActor.conn = this.conn;
-    if (!aActor.actorID) {
-      let prefix = aActor.actorPrefix;
-      if (!prefix && typeof aActor == "function") {
+  addActor: function APAddActor(actor) {
+    actor.conn = this.conn;
+    if (!actor.actorID) {
+      let prefix = actor.actorPrefix;
+      if (!prefix && typeof actor == "function") {
         // typeName is a convention used with protocol.js-based actors
-        prefix = aActor.prototype.actorPrefix || aActor.prototype.typeName;
+        prefix = actor.prototype.actorPrefix || actor.prototype.typeName;
       }
-      aActor.actorID = this.conn.allocID(prefix || undefined);
+      actor.actorID = this.conn.allocID(prefix || undefined);
     }
 
     // If the actor is already in a pool, remove it without destroying it.
-    if (aActor.registeredPool) {
-      delete aActor.registeredPool._actors[aActor.actorID];
+    if (actor.registeredPool) {
+      delete actor.registeredPool._actors[actor.actorID];
     }
-    aActor.registeredPool = this;
+    actor.registeredPool = this;
 
-    this._actors[aActor.actorID] = aActor;
+    this._actors[actor.actorID] = actor;
   },
 
   /**
    * Remove an actor from the pool. If the actor has a destroy method, call it.
    */
   removeActor(actor) {
     delete this._actors[actor.actorID];
     if (actor.destroy) {
@@ -263,36 +262,36 @@ ActorPool.prototype = {
       return;
     }
     // Obsolete destruction method name (might still be used by custom actors)
     if (actor.disconnect) {
       actor.disconnect();
     }
   },
 
-  get: function AP_get(aActorID) {
-    return this._actors[aActorID] || undefined;
+  get: function APGet(actorID) {
+    return this._actors[actorID] || undefined;
   },
 
-  has: function AP_has(aActorID) {
-    return aActorID in this._actors;
+  has: function APHas(actorID) {
+    return actorID in this._actors;
   },
 
   /**
    * Returns true if the pool is empty.
    */
-  isEmpty: function AP_isEmpty() {
+  isEmpty: function APIsEmpty() {
     return Object.keys(this._actors).length == 0;
   },
 
   /**
    * Match the api expected by the protocol library.
    */
-  unmanage: function (aActor) {
-    return this.removeActor(aActor);
+  unmanage: function (actor) {
+    return this.removeActor(actor);
   },
 
   forEach: function (callback) {
     for (let name in this._actors) {
       callback(this._actors[name]);
     }
   },
 };
@@ -470,33 +469,33 @@ exports.GeneratedLocation = GeneratedLoc
  * returns a rejected promise.
  *
  * The actor's state must be at this.state property.
  *
  * @param String expectedState
  *        The expected state.
  * @param String activity
  *        Additional info about what's going on.
- * @param Function method
+ * @param Function methodFunc
  *        The actor method to proceed with when the actor is in the expected
  *        state.
  *
  * @returns Function
  *          The decorated method.
  */
-function expectState(expectedState, method, activity) {
+function expectState(expectedState, methodFunc, activity) {
   return function (...args) {
     if (this.state !== expectedState) {
       const msg = `Wrong state while ${activity}:` +
                   `Expected '${expectedState}', ` +
                   `but current state is '${this.state}'.`;
       return promise.reject(new Error(msg));
     }
 
-    return method.apply(this, args);
+    return methodFunc.apply(this, args);
   };
 }
 
 exports.expectState = expectState;
 
 /**
  * Proxies a call from an actor to an underlying module, stored
  * as `bridge` on the actor. This allows a module to be defined in one
@@ -512,14 +511,14 @@ function actorBridge(methodName, definit
   }, definition);
 }
 exports.actorBridge = actorBridge;
 
 /**
  * Like `actorBridge`, but without a spec definition, for when the actor is
  * created with `ActorClassWithSpec` rather than vanilla `ActorClass`.
  */
-function actorBridgeWithSpec (methodName) {
+function actorBridgeWithSpec(methodName) {
   return method(function () {
     return this.bridge[methodName].apply(this.bridge, arguments);
   });
 }
 exports.actorBridgeWithSpec = actorBridgeWithSpec;
--- a/devtools/server/actors/css-properties.js
+++ b/devtools/server/actors/css-properties.js
@@ -8,17 +8,17 @@ const { Cc, Ci } = require("chrome");
 
 loader.lazyGetter(this, "DOMUtils", () => {
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 });
 
 const protocol = require("devtools/shared/protocol");
 const { ActorClassWithSpec, Actor } = protocol;
 const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties");
-const { CSS_PROPERTIES, CSS_TYPES } = require("devtools/shared/css/properties-db");
+const { CSS_TYPES } = require("devtools/shared/css/properties-db");
 const { cssColors } = require("devtools/shared/css/color-db");
 
 exports.CssPropertiesActor = ActorClassWithSpec(cssPropertiesSpec, {
   typeName: "cssProperties",
 
   initialize(conn) {
     Actor.prototype.initialize.call(this, conn);
   },
--- a/devtools/server/actors/device.js
+++ b/devtools/server/actors/device.js
@@ -1,25 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const {Ci} = require("chrome");
 const Services = require("Services");
 const protocol = require("devtools/shared/protocol");
 const promise = require("promise");
 const {LongStringActor} = require("devtools/server/actors/string");
 const {DebuggerServer} = require("devtools/server/main");
 const {getSystemInfo, getSetting} = require("devtools/shared/system");
 const {deviceSpec} = require("devtools/shared/specs/device");
 const FileReader = require("FileReader");
 
-var DeviceActor = exports.DeviceActor = protocol.ActorClassWithSpec(deviceSpec, {
+exports.DeviceActor = protocol.ActorClassWithSpec(deviceSpec, {
   _desc: null,
 
   getDescription: function () {
     return getSystemInfo();
   },
 
   getWallpaper: function () {
     let deferred = promise.defer();
@@ -35,17 +34,17 @@ var DeviceActor = exports.DeviceActor = 
       });
       reader.readAsDataURL(blob);
     });
     return deferred.promise;
   },
 
   screenshotToDataURL: function () {
     let window = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
-    var devicePixelRatio = window.devicePixelRatio;
+    let { devicePixelRatio } = window;
     let canvas = window.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
     let width = window.innerWidth;
     let height = window.innerHeight;
     canvas.setAttribute("width", Math.round(width * devicePixelRatio));
     canvas.setAttribute("height", Math.round(height * devicePixelRatio));
     let context = canvas.getContext("2d");
     let flags =
           context.DRAWWINDOW_DRAW_CARET |
--- a/devtools/server/actors/director-manager.js
+++ b/devtools/server/actors/director-manager.js
@@ -4,18 +4,17 @@
 
 "use strict";
 
 const events = require("sdk/event/core");
 const protocol = require("devtools/shared/protocol");
 
 const { Cu, Ci } = require("chrome");
 
-const { on, once, off, emit } = events;
-const { method, Arg, Option, RetVal, types } = protocol;
+const { on, off, emit } = events;
 
 const { sandbox, evaluate } = require("sdk/loader/sandbox");
 const { Class } = require("sdk/core/heritage");
 
 const { PlainTextConsole } = require("sdk/console/plain-text");
 
 const { DirectorRegistry } = require("./director-registry");
 
@@ -33,17 +32,17 @@ const ERR_MESSAGEPORT_FINALIZED = "messa
 
 const ERR_DIRECTOR_UNKNOWN_SCRIPTID = "unkown director-script id";
 const ERR_DIRECTOR_UNINSTALLED_SCRIPTID = "uninstalled director-script id";
 
 /**
  * A MessagePort Actor allowing communication through messageport events
  * over the remote debugging protocol.
  */
-var MessagePortActor = exports.MessagePortActor = protocol.ActorClassWithSpec(messagePortSpec, {
+var MessagePortActor = protocol.ActorClassWithSpec(messagePortSpec, {
   /**
    * Create a MessagePort actor.
    *
    * @param DebuggerServerConnection conn
    *        The server connection.
    * @param MessagePort port
    *        The wrapped MessagePort.
    */
@@ -86,17 +85,17 @@ var MessagePortActor = exports.MessagePo
 
     // NOTE: set port.onmessage to a function is an implicit start
     // and starts to send queued messages.
     // On the client side we should set MessagePortClient.onmessage
     // to a setter which register an handler to the message event
     // and call the actor start method to start receiving messages
     // from the MessagePort's queue.
     this.port.onmessage = (evt) => {
-      var ports;
+      let ports;
 
       // TODO: test these wrapped ports
       if (Array.isArray(evt.ports)) {
         ports = evt.ports.map((port) => {
           let actor = new MessagePortActor(this.conn, port);
           this.manage(actor);
           return actor;
         });
@@ -133,28 +132,30 @@ var MessagePortActor = exports.MessagePo
   },
 
   finalize: function () {
     this.close();
     this.port = null;
   },
 });
 
+exports.MessagePortActor = MessagePortActor;
+
 /**
- * The Director Script Actor manage javascript code running in a non-privileged sandbox with the same
- * privileges of the target global (browser tab or a firefox os app).
+ * The Director Script Actor manage javascript code running in a non-privileged sandbox
+ * with the same privileges of the target global (browser tab or a firefox os app).
  *
- * After retrieving an instance of this actor (from the tab director actor), you'll need to set it up
- * by calling setup().
+ * After retrieving an instance of this actor (from the tab director actor), you'll
+ * need to set it up by calling setup().
  *
- * After the setup, this actor will automatically attach/detach the content script (and optionally a
- * directly connect the debugger client and the content script using a MessageChannel) on tab
- * navigation.
+ * After the setup, this actor will automatically attach/detach the content script
+ * (and optionally a directly connect the debugger client and the content script using
+ * a MessageChannel) on tab navigation.
  */
-var DirectorScriptActor = exports.DirectorScriptActor = protocol.ActorClassWithSpec(directorScriptSpec, {
+var DirectorScriptActor = protocol.ActorClassWithSpec(directorScriptSpec, {
   /**
    * Creates the director script actor
    *
    * @param DebuggerServerConnection conn
    *        The server connection.
    * @param Actor tabActor
    *        The tab (or root) actor.
    * @param String scriptId
@@ -179,18 +180,18 @@ var DirectorScriptActor = exports.Direct
   },
   destroy: function (conn) {
     protocol.Actor.prototype.destroy.call(this, conn);
 
     this.finalize();
   },
 
   /**
-   * Starts listening to the tab global created, in order to create the director-script sandbox
-   * using the configured scriptCode, attached/detached automatically to the tab
+   * Starts listening to the tab global created, in order to create the director-script
+   * sandbox using the configured scriptCode, attached/detached automatically to the tab
    * window on tab navigation.
    *
    * @param Boolean reload
    *        attach the page immediately or reload it first.
    * @param Boolean skipAttach
    *        skip the attach
    */
   setup: function ({ reload, skipAttach }) {
@@ -199,26 +200,31 @@ var DirectorScriptActor = exports.Direct
       return;
     }
 
     this._setupCalled = true;
 
     on(this.tabActor, "window-ready", this._onGlobalCreated);
     on(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
 
-    // optional skip attach (needed by director-manager for director scripts bulk activation)
+    // optional skip attach (needed by director-manager for director scripts
+    // bulk activation)
     if (skipAttach) {
       return;
     }
 
     if (reload) {
       this.window.location.reload();
     } else {
       // fake a global created event to attach without reload
-      this._onGlobalCreated({ id: getWindowID(this.window), window: this.window, isTopLevel: true });
+      this._onGlobalCreated({
+        id: getWindowID(this.window),
+        window: this.window,
+        isTopLevel: true
+      });
     }
   },
 
   /**
    * Get the attached MessagePort actor if any
    */
   getMessagePort: function () {
     return this._messagePortActor;
@@ -267,17 +273,17 @@ var DirectorScriptActor = exports.Direct
       this._scriptSandbox = new DirectorScriptSandbox({
         scriptId: this._scriptId,
         scriptCode: this._scriptCode,
         scriptOptions: this._scriptOptions
       });
 
       // attach the global window
       this._lastAttachedWinId = id;
-      var port = this._scriptSandbox.attach(window, id);
+      let port = this._scriptSandbox.attach(window, id);
       this._onDirectorScriptAttach(window, port);
     } catch (e) {
       this._onDirectorScriptError(e);
     }
   },
   _onGlobalDestroyed: function ({ id }) {
     if (id !== this._lastAttachedWinId) {
        // filter destroyed globals
@@ -329,20 +335,23 @@ var DirectorScriptActor = exports.Direct
       directorScriptId: this._scriptId,
       url: (window && window.location) ? window.location.toString() : "",
       innerId: this._lastAttachedWinId,
       port: this._messagePortActor
     });
   }
 });
 
+exports.DirectorScriptActor = DirectorScriptActor;
+
 /**
- * The DirectorManager Actor is a tab actor which manages enabling/disabling director scripts.
+ * The DirectorManager Actor is a tab actor which manages enabling/disabling
+ * director scripts.
  */
-const DirectorManagerActor = exports.DirectorManagerActor = protocol.ActorClassWithSpec(directorManagerSpec, {
+exports.DirectorManagerActor = protocol.ActorClassWithSpec(directorManagerSpec, {
   /* init & destroy methods */
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this._directorScriptActorsMap = new Map();
   },
   destroy: function (conn) {
     protocol.Actor.prototype.destroy.call(this, conn);
@@ -433,33 +442,32 @@ const DirectorManagerActor = exports.Dir
     }
   },
 
   /**
    * Retrieves the actor instance of an installed director-script
    * (and create the actor instance if it doesn't exists yet).
    */
   getByScriptId: function (scriptId) {
-    var id = scriptId;
+    let id = scriptId;
     // raise an unknown director-script id exception
     if (!DirectorRegistry.checkInstalled(id)) {
       console.error(ERR_DIRECTOR_UNKNOWN_SCRIPTID, id);
       throw Error(ERR_DIRECTOR_UNKNOWN_SCRIPTID);
     }
 
     // get a previous created actor instance
     let actor = this._directorScriptActorsMap.get(id);
 
     // create a new actor instance
     if (!actor) {
       let directorScriptDefinition = DirectorRegistry.get(id);
 
       // test lazy director-script (e.g. uninstalled in the parent process)
       if (!directorScriptDefinition) {
-
         console.error(ERR_DIRECTOR_UNINSTALLED_SCRIPTID, id);
         throw Error(ERR_DIRECTOR_UNINSTALLED_SCRIPTID);
       }
 
       actor = new DirectorScriptActor(this.conn, this.tabActor, directorScriptDefinition);
       this._directorScriptActorsMap.set(id, actor);
 
       on(actor, "error", emit.bind(null, this, "director-script-error"));
@@ -486,22 +494,22 @@ const DirectorManagerActor = exports.Dir
 const DirectorScriptSandbox = Class({
   initialize: function ({scriptId, scriptCode, scriptOptions}) {
     this._scriptId = scriptId;
     this._scriptCode = scriptCode;
     this._scriptOptions = scriptOptions;
   },
 
   attach: function (window, innerId) {
-    this._innerId = innerId,
+    this._innerId = innerId;
     this._window = window;
     this._proto = Cu.createObjectIn(this._window);
 
-    var id = this._scriptId;
-    var uri = this._scriptCode;
+    let id = this._scriptId;
+    let uri = this._scriptCode;
 
     this._sandbox = sandbox(window, {
       sandboxName: uri,
       sandboxPrototype: this._proto,
       sameZoneAs: window,
       wantXrays: true,
       wantComponents: false,
       wantExportHelpers: false,
@@ -510,75 +518,83 @@ const DirectorScriptSandbox = Class({
         addonID: id,
         SDKDirectorScript: true,
         "inner-window-id": innerId
       }
     });
 
     // create a CommonJS module object which match the interface from addon-sdk
     // (addon-sdk/sources/lib/toolkit/loader.js#L678-L686)
-    var module = Cu.cloneInto(Object.create(null, {
+    let module = Cu.cloneInto(Object.create(null, {
       id: { enumerable: true, value: id },
       uri: { enumerable: true, value: uri },
       exports: { enumerable: true, value: Cu.createObjectIn(this._sandbox) }
     }), this._sandbox);
 
     // create a console API object
     let directorScriptConsole = new PlainTextConsole(null, this._innerId);
 
     // inject CommonJS module globals into the sandbox prototype
     Object.defineProperties(this._proto, {
       module: { enumerable: true, value: module },
       exports: { enumerable: true, value: module.exports },
       console: {
         enumerable: true,
-        value: Cu.cloneInto(directorScriptConsole, this._sandbox, { cloneFunctions: true })
+        value: Cu.cloneInto(
+          directorScriptConsole,
+          this._sandbox,
+          { cloneFunctions: true }
+        )
       }
     });
 
     Object.defineProperties(this._sandbox, {
       require: {
         enumerable: true,
         value: Cu.cloneInto(function () {
           throw Error("NOT IMPLEMENTED");
         }, this._sandbox, { cloneFunctions: true })
       }
     });
 
     // TODO: if the debugger target is local, the debugger client could pass
-    // to the director actor the resource url instead of the entire javascript source code.
+    // to the director actor the resource url instead of the entire javascript
+    // source code.
 
     // evaluate the director script source in the sandbox
     evaluate(this._sandbox, this._scriptCode, "javascript:" + this._scriptCode);
 
     // prepare the messageport connected to the debugger client
     let { port1, port2 } = new this._window.MessageChannel();
 
     // prepare the unload callbacks queue
-    var sandboxOnUnloadQueue = this._sandboxOnUnloadQueue = [];
+    let sandboxOnUnloadQueue = this._sandboxOnUnloadQueue = [];
 
     // create the attach options
-    var attachOptions = this._attachOptions = Cu.createObjectIn(this._sandbox);
+    let attachOptions = this._attachOptions = Cu.createObjectIn(this._sandbox);
     Object.defineProperties(attachOptions, {
       port: { enumerable: true, value: port1 },
       window: { enumerable: true, value: window },
-      scriptOptions: { enumerable: true, value: Cu.cloneInto(this._scriptOptions, this._sandbox) },
+      scriptOptions: {
+        enumerable: true,
+        value: Cu.cloneInto(this._scriptOptions, this._sandbox)
+      },
       onUnload: {
         enumerable: true,
         value: Cu.cloneInto(function (cb) {
           // collect unload callbacks
           if (typeof cb == "function") {
             sandboxOnUnloadQueue.push(cb);
           }
         }, this._sandbox, { cloneFunctions: true })
       }
     });
 
     // select the attach method
-    var exports = this._proto.module.exports;
+    let exports = this._proto.module.exports;
     if (this._scriptOptions && "attachMethod" in this._scriptOptions) {
       this._sandboxOnAttach = exports[this._scriptOptions.attachMethod];
     } else {
       this._sandboxOnAttach = exports;
     }
 
     if (typeof this._sandboxOnAttach !== "function") {
       throw Error("the configured attachMethod '" +
@@ -586,17 +602,17 @@ const DirectorScriptSandbox = Class({
                   "' is not exported by the directorScript");
     }
 
     // call the attach method
     this._sandboxOnAttach.call(this._sandbox, attachOptions);
 
     return port2;
   },
-  destroy:  function (onError) {
+  destroy: function (onError) {
     // evaluate queue unload methods if any
     while (this._sandboxOnUnloadQueue && this._sandboxOnUnloadQueue.length > 0) {
       let cb = this._sandboxOnUnloadQueue.pop();
 
       try {
         cb();
       } catch (e) {
         console.error("Exception on DirectorScript Sandbox destroy", e);
--- a/devtools/server/actors/director-registry.js
+++ b/devtools/server/actors/director-registry.js
@@ -16,18 +16,20 @@ const {directorRegistrySpec} = require("
  * Error Messages
  */
 
 const ERR_DIRECTOR_INSTALL_TWICE = "Trying to install a director-script twice";
 const ERR_DIRECTOR_INSTALL_EMPTY = "Trying to install an empty director-script";
 const ERR_DIRECTOR_UNINSTALL_UNKNOWN = "Trying to uninstall an unkown director-script";
 
 const ERR_DIRECTOR_PARENT_UNKNOWN_METHOD = "Unknown parent process method";
-const ERR_DIRECTOR_CHILD_NOTIMPLEMENTED_METHOD = "Unexpected call to notImplemented method";
-const ERR_DIRECTOR_CHILD_MULTIPLE_REPLIES = "Unexpected multiple replies to called parent method";
+const ERR_DIRECTOR_CHILD_NOTIMPLEMENTED_METHOD =
+  "Unexpected call to notImplemented method";
+const ERR_DIRECTOR_CHILD_MULTIPLE_REPLIES =
+  "Unexpected multiple replies to called parent method";
 const ERR_DIRECTOR_CHILD_NO_REPLY = "Unexpected no reply to called parent method";
 
 /**
  * Director Registry
  */
 
 // Map of director scripts ids to director script definitions
 var gDirectorScripts = Object.create(null);
@@ -143,17 +145,17 @@ exports.setupParentProcess = function se
     onDisconnected: () => setMessageManager(null),
   };
 };
 
 /**
  * The DirectorRegistry Actor is a global actor which manages install/uninstall of
  * director scripts definitions.
  */
-const DirectorRegistryActor = exports.DirectorRegistryActor = protocol.ActorClassWithSpec(directorRegistrySpec, {
+exports.DirectorRegistryActor = protocol.ActorClassWithSpec(directorRegistrySpec, {
   /* init & destroy methods */
   initialize: function (conn, parentActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.maybeSetupChildProcess(conn);
   },
   destroy: function (conn) {
     protocol.Actor.prototype.destroy.call(this, conn);
     this.finalize();
@@ -186,17 +188,17 @@ const DirectorRegistryActor = exports.Di
     /* child process helpers */
 
     function notImplemented(method) {
       console.error(ERR_DIRECTOR_CHILD_NOTIMPLEMENTED_METHOD, method);
       throw Error(ERR_DIRECTOR_CHILD_NOTIMPLEMENTED_METHOD);
     }
 
     function callParentProcess(method, ...args) {
-      var reply = sendSyncMessage("debug:director-registry-request", {
+      let reply = sendSyncMessage("debug:director-registry-request", {
         method: method,
         args: args
       });
 
       if (reply.length === 0) {
         console.error(ERR_DIRECTOR_CHILD_NO_REPLY);
         throw Error(ERR_DIRECTOR_CHILD_NO_REPLY);
       } else if (reply.length > 1) {
--- a/devtools/server/actors/environment.js
+++ b/devtools/server/actors/environment.js
@@ -1,15 +1,17 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
+/* global Debugger */
+
 const { ActorClassWithSpec } = require("devtools/shared/protocol");
 const { createValueGrip } = require("devtools/server/actors/object");
 const { environmentSpec } = require("devtools/shared/specs/environment");
 
 /**
  * Creates an EnvironmentActor. EnvironmentActors are responsible for listing
  * the bindings introduced by a lexical environment and assigning new values to
  * those identifier bindings.
@@ -85,20 +87,21 @@ let EnvironmentActor = ActorClassWithSpe
                message: "Changing the value of an immutable binding is not " +
                         "allowed" };
     }*/
 
     try {
       this.obj.setVariable(name, value);
     } catch (e) {
       if (e instanceof Debugger.DebuggeeWouldRun) {
-        throw {
+        const errorObject = {
           error: "threadWouldRun",
           message: "Assigning a value would cause the debuggee to run"
         };
+        throw errorObject;
       } else {
         throw e;
       }
     }
     return { from: this.actorID };
   },
 
   /**
--- a/devtools/server/actors/errordocs.js
+++ b/devtools/server/actors/errordocs.js
@@ -5,17 +5,18 @@
 /**
  * A mapping of error message names to external documentation. Any error message
  * included here will be displayed alongside its link in the web console.
  */
 
 "use strict";
 
 const baseURL = "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/";
-const params = "?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default";
+const params =
+  "?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default";
 const ErrorDocs = {
   JSMSG_READ_ONLY: "Read-only",
   JSMSG_BAD_ARRAY_LENGTH: "Invalid_array_length",
   JSMSG_NEGATIVE_REPETITION_COUNT: "Negative_repetition_count",
   JSMSG_RESULTING_STRING_TOO_LARGE: "Resulting_string_too_large",
   JSMSG_BAD_RADIX: "Bad_radix",
   JSMSG_PRECISION_RANGE: "Precision_range",
   JSMSG_STMT_AFTER_RETURN: "Stmt_after_return",
@@ -66,21 +67,22 @@ const ErrorCategories = {
   "Invalid HSTS Headers": STRICT_TRANSPORT_SECURITY_LEARN_MORE,
   "SHA-1 Signature": WEAK_SIGNATURE_ALGORITHM_LEARN_MORE,
   "Tracking Protection": TRACKING_PROTECTION_LEARN_MORE,
   "MIMEMISMATCH": MIME_TYPE_MISMATCH_LEARN_MORE,
 };
 
 exports.GetURL = (error) => {
   if (!error) {
-    return;
+    return undefined;
   }
 
   let doc = ErrorDocs[error.errorMessageName];
   if (doc) {
     return baseURL + doc + params;
   }
 
   let categoryURL = ErrorCategories[error.category];
   if (categoryURL) {
     return categoryURL + params;
   }
+  return undefined;
 };
--- a/devtools/server/actors/eventlooplag.js
+++ b/devtools/server/actors/eventlooplag.js
@@ -12,17 +12,17 @@
 
 const {Ci} = require("chrome");
 const Services = require("Services");
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 const {Actor, ActorClassWithSpec} = require("devtools/shared/protocol");
 const events = require("sdk/event/core");
 const {eventLoopLagSpec} = require("devtools/shared/specs/eventlooplag");
 
-var EventLoopLagActor = exports.EventLoopLagActor = ActorClassWithSpec(eventLoopLagSpec, {
+exports.EventLoopLagActor = ActorClassWithSpec(eventLoopLagSpec, {
   _observerAdded: false,
 
   /**
    * Start tracking the event loop lags.
    */
   start: function () {
     if (!this._observerAdded) {
       Services.obs.addObserver(this, "event-loop-lag", false);
--- a/devtools/server/actors/frame.js
+++ b/devtools/server/actors/frame.js
@@ -67,17 +67,17 @@ let FrameActor = ActorClassWithSpec(fram
         this.frameLifetimePool
       );
       form.environment = envActor.form();
     }
     form.this = createValueGrip(this.frame.this, threadActor._pausePool,
       threadActor.objectGrip);
     form.arguments = this._args();
     if (this.frame.script) {
-      var generatedLocation = this.threadActor.sources.getFrameLocation(this.frame);
+      let generatedLocation = this.threadActor.sources.getFrameLocation(this.frame);
       form.where = {
         source: generatedLocation.generatedSourceActor.form(),
         line: generatedLocation.generatedLine,
         column: generatedLocation.generatedColumn
       };
     }
 
     if (!this.frame.older) {
--- a/devtools/server/actors/framerate.js
+++ b/devtools/server/actors/framerate.js
@@ -1,26 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
 const { actorBridgeWithSpec } = require("devtools/server/actors/common");
-const { on, once, off, emit } = require("sdk/event/core");
 const { Framerate } = require("devtools/server/performance/framerate");
 const { framerateSpec } = require("devtools/shared/specs/framerate");
 
 /**
  * An actor wrapper around Framerate. Uses exposed
  * methods via bridge and provides RDP definitions.
  *
  * @see devtools/server/performance/framerate.js for documentation.
  */
-var FramerateActor = exports.FramerateActor = ActorClassWithSpec(framerateSpec, {
+exports.FramerateActor = ActorClassWithSpec(framerateSpec, {
   initialize: function (conn, tabActor) {
     Actor.prototype.initialize.call(this, conn);
     this.bridge = new Framerate(tabActor);
   },
   destroy: function (conn) {
     Actor.prototype.destroy.call(this, conn);
     this.bridge.destroy();
   },
--- a/devtools/server/actors/gcli.js
+++ b/devtools/server/actors/gcli.js
@@ -1,33 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const { Task } = require("devtools/shared/task");
-const {
-  method, Arg, Option, RetVal, Actor, ActorClassWithSpec
-} = require("devtools/shared/protocol");
+const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
 const { gcliSpec } = require("devtools/shared/specs/gcli");
 const events = require("sdk/event/core");
 const { createSystem } = require("gcli/system");
 
 /**
  * Manage remote connections that want to talk to GCLI
  */
 const GcliActor = ActorClassWithSpec(gcliSpec, {
   initialize: function (conn, tabActor) {
     Actor.prototype.initialize.call(this, conn);
 
     this._commandsChanged = this._commandsChanged.bind(this);
 
     this._tabActor = tabActor;
-    this._requisitionPromise = undefined; // see _getRequisition()
+    // see _getRequisition()
+    this._requisitionPromise = undefined;
   },
 
   destroy: function () {
     Actor.prototype.destroy.call(this);
 
     // If _getRequisition has not been called, just bail quickly
     if (this._requisitionPromise == null) {
       this._commandsChanged = undefined;
@@ -191,21 +189,23 @@ const GcliActor = ActorClassWithSpec(gcl
     gcliInit.addAllItemsByModule(this._system);
 
     // this._requisitionPromise should be created synchronously with the call
     // to _getRequisition so that destroy can tell whether there is an async
     // init in progress
     this._requisitionPromise = this._system.load().then(() => {
       const environment = {
         get chromeWindow() {
-          throw new Error("environment.chromeWindow is not available in runAt:server commands");
+          throw new Error("environment.chromeWindow is not available in runAt:server" +
+            " commands");
         },
 
         get chromeDocument() {
-          throw new Error("environment.chromeDocument is not available in runAt:server commands");
+          throw new Error("environment.chromeDocument is not available in runAt:server" +
+            " commands");
         },
 
         get window() {
           return tabActor.window;
         },
 
         get document() {
           return tabActor.window && tabActor.window.document;
--- a/devtools/server/actors/heap-snapshot-file.js
+++ b/devtools/server/actors/heap-snapshot-file.js
@@ -1,16 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const protocol = require("devtools/shared/protocol");
-const { method, Arg } = protocol;
 const Services = require("Services");
 const { Task } = require("devtools/shared/task");
 
 const { heapSnapshotFileSpec } = require("devtools/shared/specs/heap-snapshot-file");
 
 loader.lazyRequireGetter(this, "DevToolsUtils",
                          "devtools/shared/DevToolsUtils");
 loader.lazyRequireGetter(this, "OS", "resource://gre/modules/osfile.jsm", true);
--- a/devtools/server/actors/highlighters.js
+++ b/devtools/server/actors/highlighters.js
@@ -77,17 +77,17 @@ exports.register = register;
  *
  * Other types of highlighter actors exist and can be accessed via the
  * InspectorActor's 'getHighlighterByType' method.
  */
 
 /**
  * The HighlighterActor class
  */
-var HighlighterActor = exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
+exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
   initialize: function (inspector, autohide) {
     protocol.Actor.prototype.initialize.call(this, null);
 
     this._autohide = autohide;
     this._inspector = inspector;
     this._walker = this._inspector.walker;
     this._tabActor = this._inspector.tabActor;
     this._highlighterEnv = new HighlighterEnvironment();
@@ -250,17 +250,18 @@ var HighlighterActor = exports.Highlight
 
       if (!this._isEventAllowed(event)) {
         return;
       }
 
       // If shift is pressed, this is only a preview click, send the event to
       // the client, but don't stop picking.
       if (event.shiftKey) {
-        events.emit(this._walker, "picker-node-previewed", this._findAndAttachElement(event));
+        events.emit(this._walker, "picker-node-previewed",
+          this._findAndAttachElement(event));
         return;
       }
 
       this._stopPickerListeners();
       this._isPicking = false;
       if (this._autohide) {
         this._tabActor.window.setTimeout(() => {
           this._highlighter.hide();
@@ -346,18 +347,18 @@ var HighlighterActor = exports.Highlight
           this.cancelPick();
           events.emit(this._walker, "picker-node-canceled");
           return;
         case Ci.nsIDOMKeyEvent.DOM_VK_C:
           if ((IS_OSX && event.metaKey && event.altKey) ||
             (!IS_OSX && event.ctrlKey && event.shiftKey)) {
             this.cancelPick();
             events.emit(this._walker, "picker-node-canceled");
-            return;
           }
+          return;
         default: return;
       }
 
       // Store currently attached element
       this._currentNode = this._walker.attachElement(currentNode);
       this._highlighter.show(this._currentNode.node.rawNode);
       events.emit(this._walker, "picker-node-hovered", this._currentNode);
     };
@@ -365,17 +366,17 @@ var HighlighterActor = exports.Highlight
     this._startPickerListeners();
 
     return null;
   },
 
   /**
    * This pick method also focuses the highlighter's target window.
    */
-  pickAndFocus: function() {
+  pickAndFocus: function () {
     // Go ahead and pass on the results to help future-proof this method.
     let pickResults = this.pick();
     this._highlighterEnv.window.focus();
     return pickResults;
   },
 
   _findAndAttachElement: function (event) {
     // originalTarget allows access to the "real" element before any retargeting
@@ -424,17 +425,17 @@ var HighlighterActor = exports.Highlight
     }
   }
 });
 
 /**
  * A generic highlighter actor class that instantiate a highlighter given its
  * type name and allows to show/hide it.
  */
-var CustomHighlighterActor = exports.CustomHighlighterActor = protocol.ActorClassWithSpec(customHighlighterSpec, {
+exports.CustomHighlighterActor = protocol.ActorClassWithSpec(customHighlighterSpec, {
   /**
    * Create a highlighter instance given its typename
    * The typename must be one of HIGHLIGHTER_CLASSES and the class must
    * implement constructor(tabActor), show(node), hide(), destroy()
    */
   initialize: function (inspector, typeName) {
     protocol.Actor.prototype.initialize.call(this, null);
 
--- a/devtools/server/actors/monitor.js
+++ b/devtools/server/actors/monitor.js
@@ -3,18 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Ci, Cc} = require("chrome");
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 const Services = require("Services");
 
-function MonitorActor(aConnection) {
-  this.conn = aConnection;
+function MonitorActor(connection) {
+  this.conn = connection;
   this._updates = [];
   this._started = false;
 }
 
 MonitorActor.prototype = {
   actorPrefix: "monitor",
 
   // Updates.
@@ -113,31 +113,33 @@ var USSAgent = {
   _timeout: null,
   _packet: {
     graph: "USS",
     time: null,
     value: null
   },
 
   start: function () {
-    USSAgent._mgr = Cc["@mozilla.org/memory-reporter-manager;1"].getService(Ci.nsIMemoryReporterManager);
+    USSAgent._mgr = Cc["@mozilla.org/memory-reporter-manager;1"].getService(
+      Ci.nsIMemoryReporterManager);
     if (!USSAgent._mgr.residentUnique) {
-      throw "Couldn't get USS.";
+      throw new Error("Couldn't get USS.");
     }
     USSAgent.update();
   },
 
   update: function () {
     if (!USSAgent._mgr) {
       USSAgent.stop();
       return;
     }
     USSAgent._packet.time = Date.now();
     USSAgent._packet.value = USSAgent._mgr.residentUnique;
-    Services.obs.notifyObservers(null, "devtools-monitor-update", JSON.stringify(USSAgent._packet));
+    Services.obs.notifyObservers(null, "devtools-monitor-update",
+      JSON.stringify(USSAgent._packet));
     USSAgent._timeout = setTimeout(USSAgent.update, 300);
   },
 
   stop: function () {
     clearTimeout(USSAgent._timeout);
     USSAgent._mgr = null;
   }
 };
--- a/devtools/server/actors/performance-entries.js
+++ b/devtools/server/actors/performance-entries.js
@@ -1,12 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+"use strict";
+
 /**
  * The performanceEntries actor emits events corresponding to performance
  * entries. It receives `performanceentry` events containing the performance
  * entry details and emits an event containing the name, type, origin, and
  * epoch of the performance entry.
  */
 
 const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
--- a/devtools/server/actors/performance-recording.js
+++ b/devtools/server/actors/performance-recording.js
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const { Cu } = require("chrome");
 const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
 const { performanceRecordingSpec } = require("devtools/shared/specs/performance-recording");
 
 loader.lazyRequireGetter(this, "merge", "sdk/util/object", true);
 loader.lazyRequireGetter(this, "RecordingUtils",
   "devtools/shared/performance/recording-utils");
 loader.lazyRequireGetter(this, "PerformanceRecordingCommon",
   "devtools/shared/performance/recording-common", true);
@@ -22,17 +21,18 @@ loader.lazyRequireGetter(this, "Performa
  */
 const PerformanceRecordingActor = ActorClassWithSpec(performanceRecordingSpec, merge({
   form: function (detail) {
     if (detail === "actorid") {
       return this.actorID;
     }
 
     let form = {
-      actor: this.actorID,  // actorID is set when this is added to a pool
+      // actorID is set when this is added to a pool
+      actor: this.actorID,
       configuration: this._configuration,
       startingBufferStatus: this._startingBufferStatus,
       console: this._console,
       label: this._label,
       startTime: this._startTime,
       localStartTime: this._localStartTime,
       recording: this._recording,
       completed: this._completed,
--- a/devtools/server/actors/performance.js
+++ b/devtools/server/actors/performance.js
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const { Cu } = require("chrome");
 const { Task } = require("devtools/shared/task");
 const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
 const { actorBridgeWithSpec } = require("devtools/server/actors/common");
 const { performanceSpec } = require("devtools/shared/specs/performance");
 
 loader.lazyRequireGetter(this, "events", "sdk/event/core");
 loader.lazyRequireGetter(this, "extend", "sdk/util/object", true);
 
--- a/devtools/server/actors/preference.js
+++ b/devtools/server/actors/preference.js
@@ -1,26 +1,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-const {Cc, Ci, Cu, CC} = require("chrome");
+"use strict";
+
+const {Ci} = require("chrome");
 const protocol = require("devtools/shared/protocol");
-const {Arg, method, RetVal} = protocol;
 const Services = require("Services");
 const {preferenceSpec} = require("devtools/shared/specs/preference");
 
 exports.register = function (handle) {
   handle.addGlobalActor(PreferenceActor, "preferenceActor");
 };
 
 exports.unregister = function (handle) {
 };
 
-var PreferenceActor = exports.PreferenceActor = protocol.ActorClassWithSpec(preferenceSpec, {
+var PreferenceActor = protocol.ActorClassWithSpec(preferenceSpec, {
+
   typeName: "preference",
 
   getBoolPref: function (name) {
     return Services.prefs.getBoolPref(name);
   },
 
   getCharPref: function (name) {
     return Services.prefs.getCharPref(name);
@@ -74,8 +76,10 @@ var PreferenceActor = exports.Preference
     Services.prefs.savePrefFile(null);
   },
 
   clearUserPref: function (name) {
     Services.prefs.clearUserPref(name);
     Services.prefs.savePrefFile(null);
   },
 });
+
+exports.PreferenceActor = PreferenceActor;
--- a/devtools/server/actors/pretty-print-worker.js
+++ b/devtools/server/actors/pretty-print-worker.js
@@ -1,14 +1,18 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+"use strict";
+
+/* global importScripts, workerHelper, self, prettyFast */
+
 /**
  * This file is meant to be loaded as a ChromeWorker. It accepts messages which
  * have data of the form:
  *
  *     { id, url, indent, source }
  *
  * Where `id` is a unique ID to identify this request, `url` is the url of the
  * source being pretty printed, `indent` is the number of spaces to indent the
@@ -38,13 +42,12 @@ workerHelper.createTask(self, "pretty-pr
       url: url,
       indent: " ".repeat(indent)
     });
 
     return {
       code: prettified.code,
       mappings: prettified.map._mappings
     };
-  }
-  catch (e) {
+  } catch (e) {
     return new Error(e.message + "\n" + e.stack);
   }
 });
--- a/devtools/server/actors/process.js
+++ b/devtools/server/actors/process.js
@@ -2,36 +2,41 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var { Cc, Ci } = require("chrome");
 
 loader.lazyGetter(this, "ppmm", () => {
-  return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster);
+  return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(
+    Ci.nsIMessageBroadcaster);
 });
 
 function ProcessActorList() {
   this._actors = new Map();
   this._onListChanged = null;
   this._mustNotify = false;
 
   this._onMessage = this._onMessage.bind(this);
   this._processScript = "data:text/javascript,sendAsyncMessage('debug:new-process');";
 }
 
 ProcessActorList.prototype = {
   getList: function () {
     let processes = [];
     for (let i = 0; i < ppmm.childCount; i++) {
       processes.push({
-        id: i, // XXX: may not be a perfect id, but process message manager doesn't expose anything...
-        parent: i == 0, // XXX Weak, but appear to be stable
-        tabCount: undefined, // TODO: exposes process message manager on frameloaders in order to compute this
+        // XXX: may not be a perfect id, but process message manager doesn't
+        // expose anything...
+        id: i,
+        // XXX Weak, but appear to be stable
+        parent: i == 0,
+        // TODO: exposes process message manager on frameloaders in order to compute this
+        tabCount: undefined,
       });
     }
     this._mustNotify = true;
     this._checkListening();
 
     return processes;
   },
 
--- a/devtools/server/actors/profiler.js
+++ b/devtools/server/actors/profiler.js
@@ -11,17 +11,17 @@ const { profilerSpec } = require("devtoo
 loader.lazyRequireGetter(this, "events", "sdk/event/core");
 
 /**
  * This actor wraps the Profiler module at devtools/server/performance/profiler.js
  * and provides RDP definitions.
  *
  * @see devtools/server/performance/profiler.js for documentation.
  */
-var ProfilerActor = exports.ProfilerActor = ActorClassWithSpec(profilerSpec, {
+exports.ProfilerActor = ActorClassWithSpec(profilerSpec, {
   initialize: function (conn) {
     Actor.prototype.initialize.call(this, conn);
     this._onProfilerEvent = this._onProfilerEvent.bind(this);
 
     this.bridge = new Profiler();
     events.on(this.bridge, "*", this._onProfilerEvent);
   },
 
--- a/devtools/server/actors/reflow.js
+++ b/devtools/server/actors/reflow.js
@@ -22,26 +22,25 @@
  * - Dedicated observers: There's only one of them for now: ReflowObserver which
  *   listens to reflow events via the docshell,
  *   These dedicated classes are used by the LayoutChangesObserver.
  */
 
 const {Ci} = require("chrome");
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 const protocol = require("devtools/shared/protocol");
-const {method, Arg} = protocol;
 const events = require("sdk/event/core");
 const Heritage = require("sdk/core/heritage");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {reflowSpec} = require("devtools/shared/specs/reflow");
 
 /**
  * The reflow actor tracks reflows and emits events about them.
  */
-var ReflowActor = exports.ReflowActor = protocol.ActorClassWithSpec(reflowSpec, {
+exports.ReflowActor = protocol.ActorClassWithSpec(reflowSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
 
     this.tabActor = tabActor;
     this._onReflow = this._onReflow.bind(this);
     this.observer = getLayoutChangesObserver(tabActor);
     this._isStarted = false;
   },
@@ -194,17 +193,17 @@ Observable.prototype = {
  * either observed or ignored depending on the current mode.
  *
  * @param {Boolean} ignore
  * @param {DOMNode} syncReflowNode The node to use to force a sync reflow
  */
 var gIgnoreLayoutChanges = false;
 exports.setIgnoreLayoutChanges = function (ignore, syncReflowNode) {
   if (syncReflowNode) {
-    let forceSyncReflow = syncReflowNode.offsetWidth;
+    let forceSyncReflow = syncReflowNode.offsetWidth; // eslint-disable-line
   }
   gIgnoreLayoutChanges = ignore;
 };
 
 /**
  * The LayoutChangesObserver class is instantiated only once per given tab
  * and is used to track reflows and dom and style changes in that tab.
  * The LayoutActor uses this class to send reflow events to its clients.
@@ -427,17 +426,17 @@ exports.releaseLayoutChangesObserver = r
  * @param {Function} callback Executed everytime a reflow occurs
  */
 function ReflowObserver(tabActor, callback) {
   Observable.call(this, tabActor, callback);
 }
 
 ReflowObserver.prototype = Heritage.extend(Observable.prototype, {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
-    Ci.nsISupportsWeakReference]),
+                                         Ci.nsISupportsWeakReference]),
 
   _startListeners: function (windows) {
     for (let window of windows) {
       let docshell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                      .getInterface(Ci.nsIWebNavigation)
                      .QueryInterface(Ci.nsIDocShell);
       docshell.addWeakReflowObserver(this);
     }
--- a/devtools/server/actors/root.js
+++ b/devtools/server/actors/root.js
@@ -2,35 +2,35 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Cc, Ci, Cu } = require("chrome");
-const Services = require("Services");
 const { ActorPool, appendExtraActors, createExtraActors } = require("devtools/server/actors/common");
 const { DebuggerServer } = require("devtools/server/main");
 
 loader.lazyGetter(this, "ppmm", () => {
-  return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster);
+  return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(
+    Ci.nsIMessageBroadcaster);
 });
 
 /* Root actor for the remote debugging protocol. */
 
 /**
  * Create a remote debugging protocol root actor.
  *
- * @param aConnection
+ * @param connection
  *     The DebuggerServerConnection whose root actor we are constructing.
  *
- * @param aParameters
- *     The properties of |aParameters| provide backing objects for the root
- *     actor's requests; if a given property is omitted from |aParameters|, the
+ * @param parameters
+ *     The properties of |parameters| provide backing objects for the root
+ *     actor's requests; if a given property is omitted from |parameters|, the
  *     root actor won't implement the corresponding requests or notifications.
  *     Supported properties:
  *
  *     - tabList: a live list (see below) of tab actors. If present, the
  *       new root actor supports the 'listTabs' request, providing the live
  *       list's elements as its tab actors, and sending 'tabListChanged'
  *       notifications when the live list's contents change. One actor in
  *       this list must have a true '.selected' property.
@@ -84,23 +84,24 @@ loader.lazyGetter(this, "ppmm", () => {
  * live list implementations can use the state of the handler property (set
  * or null) to install and remove observers and event listeners.
  *
  * Note that, as the only way for the root actor to see the members of the
  * live list is to begin an iteration over the list, the live list need not
  * actually produce any actors until they are reached in the course of
  * iteration: alliterative lazy live lists.
  */
-function RootActor(aConnection, aParameters) {
-  this.conn = aConnection;
-  this._parameters = aParameters;
+function RootActor(connection, parameters) {
+  this.conn = connection;
+  this._parameters = parameters;
   this._onTabListChanged = this.onTabListChanged.bind(this);
   this._onAddonListChanged = this.onAddonListChanged.bind(this);
   this._onWorkerListChanged = this.onWorkerListChanged.bind(this);
-  this._onServiceWorkerRegistrationListChanged = this.onServiceWorkerRegistrationListChanged.bind(this);
+  this._onServiceWorkerRegistrationListChanged =
+    this.onServiceWorkerRegistrationListChanged.bind(this);
   this._onProcessListChanged = this.onProcessListChanged.bind(this);
   this._extraActors = {};
 
   this._globalActorPool = new ActorPool(this.conn);
   this.conn.addActorPool(this._globalActorPool);
 
   this._chromeActor = null;
   this._processActors = new Map();
@@ -266,17 +267,18 @@ RootActor.prototype = {
         newActorPool.addActor(tabActor);
         tabActorList.push(tabActor);
       }
       /* DebuggerServer.addGlobalActor support: create actors. */
       if (!this._globalActorPool) {
         this._globalActorPool = new ActorPool(this.conn);
         this.conn.addActorPool(this._globalActorPool);
       }
-      this._createExtraActors(this._parameters.globalActorFactories, this._globalActorPool);
+      this._createExtraActors(this._parameters.globalActorFactories,
+        this._globalActorPool);
       /*
        * Drop the old actorID -> actor map. Actors that still mattered were
        * added to the new map; others will go away.
        */
       if (this._tabActorPool) {
         this.conn.removeActorPool(this._tabActorPool);
       }
       this._tabActorPool = newActorPool;
@@ -322,25 +324,26 @@ RootActor.prototype = {
                     tabActor.parentID = this.actorID;
                     this._tabActorPool.addActor(tabActor);
 
                     return { tab: tabActor.form() };
                   }, error => {
                     if (error.error) {
         // Pipe expected errors as-is to the client
                       return error;
-                    } else {
-                      return { error: "noTab",
-                 message: "Unexpected error while calling getTab(): " + error };
                     }
+                    return {
+                      error: "noTab",
+                      message: "Unexpected error while calling getTab(): " + error
+                    };
                   });
   },
 
   onTabListChanged: function () {
-    this.conn.send({ from: this.actorID, type:"tabListChanged" });
+    this.conn.send({ from: this.actorID, type: "tabListChanged" });
     /* It's a one-shot notification; no need to watch any more. */
     this._parameters.tabList.onListChanged = null;
   },
 
   onListAddons: function () {
     let addonList = this._parameters.addonList;
     if (!addonList) {
       return { from: this.actorID, error: "noAddons",
@@ -447,93 +450,92 @@ RootActor.prototype = {
     };
   },
 
   onProcessListChanged: function () {
     this.conn.send({ from: this.actorID, type: "processListChanged" });
     this._parameters.processList.onListChanged = null;
   },
 
-  onGetProcess: function (aRequest) {
+  onGetProcess: function (request) {
     if (!DebuggerServer.allowChromeProcess) {
       return { error: "forbidden",
                message: "You are not allowed to debug chrome." };
     }
-    if (("id" in aRequest) && typeof (aRequest.id) != "number") {
+    if (("id" in request) && typeof (request.id) != "number") {
       return { error: "wrongParameter",
                message: "getProcess requires a valid `id` attribute." };
     }
     // If the request doesn't contains id parameter or id is 0
     // (id == 0, based on onListProcesses implementation)
-    if ((!("id" in aRequest)) || aRequest.id === 0) {
+    if ((!("id" in request)) || request.id === 0) {
       if (!this._chromeActor) {
         // Create a ChromeActor for the parent process
         let { ChromeActor } = require("devtools/server/actors/chrome");
         this._chromeActor = new ChromeActor(this.conn);
         this._globalActorPool.addActor(this._chromeActor);
       }
 
       return { form: this._chromeActor.form() };
-    } else {
-      let { id } = aRequest;
-      let mm = ppmm.getChildAt(id);
-      if (!mm) {
-        return { error: "noProcess",
-                 message: "There is no process with id '" + id + "'." };
-      }
-      let form = this._processActors.get(id);
-      if (form) {
-        return { form };
-      }
-      let onDestroy = () => {
-        this._processActors.delete(id);
-      };
-      return DebuggerServer.connectToContent(this.conn, mm, onDestroy)
-        .then(form => {
-          this._processActors.set(id, form);
-          return { form };
-        });
+    }
+
+    let { id } = request;
+    let mm = ppmm.getChildAt(id);
+    if (!mm) {
+      return { error: "noProcess",
+               message: "There is no process with id '" + id + "'." };
     }
+    let form = this._processActors.get(id);
+    if (form) {
+      return { form };
+    }
+    let onDestroy = () => {
+      this._processActors.delete(id);
+    };
+    return DebuggerServer.connectToContent(this.conn, mm, onDestroy).then(formResult => {
+      this._processActors.set(id, formResult);
+      return { form: formResult };
+    });
   },
 
   /* This is not in the spec, but it's used by tests. */
-  onEcho: function (aRequest) {
+  onEcho: function (request) {
     /*
-     * Request packets are frozen. Copy aRequest, so that
+     * Request packets are frozen. Copy request, so that
      * DebuggerServerConnection.onPacket can attach a 'from' property.
      */
-    return Cu.cloneInto(aRequest, {});
+    return Cu.cloneInto(request, {});
   },
 
   onProtocolDescription: function () {
     return require("devtools/shared/protocol").dumpProtocolSpec();
   },
 
   /* Support for DebuggerServer.addGlobalActor. */
   _createExtraActors: createExtraActors,
   _appendExtraActors: appendExtraActors,
 
   /**
    * Remove the extra actor (added by DebuggerServer.addGlobalActor or
-   * DebuggerServer.addTabActor) name |aName|.
+   * DebuggerServer.addTabActor) name |name|.
    */
-  removeActorByName: function (aName) {
-    if (aName in this._extraActors) {
-      const actor = this._extraActors[aName];
+  removeActorByName: function (name) {
+    if (name in this._extraActors) {
+      const actor = this._extraActors[name];
       if (this._globalActorPool.has(actor)) {
         this._globalActorPool.removeActor(actor);
       }
       if (this._tabActorPool) {
         // Iterate over TabActor instances to also remove tab actors
         // created during listTabs for each document.
         this._tabActorPool.forEach(tab => {
-          tab.removeActorByName(aName);
+          tab.removeActorByName(name);
         });
       }
-      delete this._extraActors[aName];
+      delete this._extraActors[name];
     }
   }
 };
 
 RootActor.prototype.requestTypes = {
   "listTabs": RootActor.prototype.onListTabs,
   "getTab": RootActor.prototype.onGetTab,
   "listAddons": RootActor.prototype.onListAddons,
--- a/devtools/server/actors/settings.js
+++ b/devtools/server/actors/settings.js
@@ -33,17 +33,19 @@ function getDefaultSettings() {
                   .createInstance(Ci.nsIScriptableUnicodeConverter);
   converter.charset = "UTF-8";
   let rawstr = converter.ConvertToUnicode(NetUtil.readInputStreamToString(
                                           stream,
                                           stream.available()) || "");
 
   try {
     defaultSettings = JSON.parse(rawstr);
-  } catch (e) { }
+  } catch (e) {
+    // ignore
+  }
   stream.close();
 }
 
 function loadSettingsFile() {
   // Loading resource://app/defaults/settings.json doesn't work because
   // settings.json is not in the omnijar.
   // So we look for the app dir instead and go from here...
   if (settingsFile) {
@@ -110,17 +112,17 @@ var SettingsActor = exports.SettingsActo
     let settings = {};
     let self = this;
 
     let deferred = promise.defer();
     let lock = this._getSettingsService().createLock();
     let req = lock.get("*");
 
     req.onsuccess = function () {
-      for (var name in req.result) {
+      for (let name in req.result) {
         settings[name] = {
           value: req.result[name],
           hasUserValue: self._hasUserSetting(name, req.result[name])
         };
       }
       deferred.resolve(settings);
     };
     req.onfailure = function () {
--- a/devtools/server/actors/source.js
+++ b/devtools/server/actors/source.js
@@ -6,22 +6,21 @@
 
 "use strict";
 
 const { Cc, Ci } = require("chrome");
 const Services = require("Services");
 const { BreakpointActor, setBreakpointAtEntryPoints } = require("devtools/server/actors/breakpoint");
 const { OriginalLocation, GeneratedLocation } = require("devtools/server/actors/common");
 const { createValueGrip } = require("devtools/server/actors/object");
-const { ActorClassWithSpec, Arg, RetVal, method } = require("devtools/shared/protocol");
+const { ActorClassWithSpec } = require("devtools/shared/protocol");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const { assert, fetch } = DevToolsUtils;
 const { joinURI } = require("devtools/shared/path");
 const promise = require("promise");
-const { defer, resolve, reject, all } = promise;
 const { sourceSpec } = require("devtools/shared/specs/source");
 
 loader.lazyRequireGetter(this, "SourceMapConsumer", "source-map", true);
 loader.lazyRequireGetter(this, "SourceMapGenerator", "source-map", true);
 loader.lazyRequireGetter(this, "mapURIToAddonID", "devtools/server/actors/utils/map-uri-to-addon-id");
 
 function isEvalSource(source) {
   let introType = source.introductionType;
@@ -39,68 +38,65 @@ exports.isEvalSource = isEvalSource;
 function getSourceURL(source, window) {
   if (isEvalSource(source)) {
     // Eval sources have no urls, but they might have a `displayURL`
     // created with the sourceURL pragma. If the introduction script
     // is a non-eval script, generate an full absolute URL relative to it.
 
     if (source.displayURL && source.introductionScript &&
        !isEvalSource(source.introductionScript.source)) {
-
       if (source.introductionScript.source.url === "debugger eval code") {
         if (window) {
           // If this is a named eval script created from the console, make it
           // relative to the current page. window is only available
           // when we care about this.
           return joinURI(window.location.href, source.displayURL);
         }
-      }
-      else {
+      } else {
         return joinURI(source.introductionScript.source.url, source.displayURL);
       }
     }
 
     return source.displayURL;
-  }
-  else if (source.url === "debugger eval code") {
+  } else if (source.url === "debugger eval code") {
     // Treat code evaluated by the console as unnamed eval scripts
     return null;
   }
   return source.url;
 }
 
 exports.getSourceURL = getSourceURL;
 
 /**
  * Resolve a URI back to physical file.
  *
  * Of course, this works only for URIs pointing to local resources.
  *
- * @param  aURI
+ * @param  uri
  *         URI to resolve
  * @return
  *         resolved nsIURI
  */
-function resolveURIToLocalPath(aURI) {
+function resolveURIToLocalPath(uri) {
   let resolved;
-  switch (aURI.scheme) {
+  switch (uri.scheme) {
     case "jar":
     case "file":
-      return aURI;
+      return uri;
 
     case "chrome":
-      resolved = Cc["@mozilla.org/chrome/chrome-registry;1"].
-                 getService(Ci.nsIChromeRegistry).convertChromeURL(aURI);
+      resolved = Cc["@mozilla.org/chrome/chrome-registry;1"]
+                  .getService(Ci.nsIChromeRegistry).convertChromeURL(uri);
       return resolveURIToLocalPath(resolved);
 
     case "resource":
-      resolved = Cc["@mozilla.org/network/protocol;1?name=resource"].
-                 getService(Ci.nsIResProtocolHandler).resolveURI(aURI);
-      aURI = Services.io.newURI(resolved);
-      return resolveURIToLocalPath(aURI);
+      resolved = Cc["@mozilla.org/network/protocol;1?name=resource"]
+                  .getService(Ci.nsIResProtocolHandler).resolveURI(uri);
+      uri = Services.io.newURI(resolved);
+      return resolveURIToLocalPath(uri);
 
     default:
       return null;
   }
 }
 
 /**
  * A SourceActor provides information about the source of a script. There
@@ -177,30 +173,46 @@ let SourceActor = ActorClassWithSpec(sou
         this.threadActor.sources.isPrettyPrinted(this.url)
     ));
   },
 
   get isInlineSource() {
     return this._isInlineSource;
   },
 
-  get threadActor() { return this._threadActor; },
-  get sources() { return this._threadActor.sources; },
-  get dbg() { return this.threadActor.dbg; },
-  get source() { return this._source; },
-  get generatedSource() { return this._generatedSource; },
-  get breakpointActorMap() { return this.threadActor.breakpointActorMap; },
+  get threadActor() {
+    return this._threadActor;
+  },
+  get sources() {
+    return this._threadActor.sources;
+  },
+  get dbg() {
+    return this.threadActor.dbg;
+  },
+  get source() {
+    return this._source;
+  },
+  get generatedSource() {
+    return this._generatedSource;
+  },
+  get breakpointActorMap() {
+    return this.threadActor.breakpointActorMap;
+  },
   get url() {
     if (this.source) {
       return getSourceURL(this.source, this.threadActor._parent.window);
     }
     return this._originalUrl;
   },
-  get addonID() { return this._addonID; },
-  get addonPath() { return this._addonPath; },
+  get addonID() {
+    return this._addonID;
+  },
+  get addonPath() {
+    return this._addonPath;
+  },
 
   get prettyPrintWorker() {
     return this.threadActor.prettyPrintWorker;
   },
 
   form: function () {
     let source = this.source || this.generatedSource;
     // This might not have a source or a generatedSource because we
@@ -228,20 +240,20 @@ let SourceActor = ActorClassWithSpec(sou
 
   destroy: function () {
     if (this.registeredPool && this.registeredPool.sourceActors) {
       delete this.registeredPool.sourceActors[this.actorID];
     }
   },
 
   _mapSourceToAddon: function () {
+    let nsuri;
     try {
-      var nsuri = Services.io.newURI(this.url.split(" -> ").pop());
-    }
-    catch (e) {
+      nsuri = Services.io.newURI(this.url.split(" -> ").pop());
+    } catch (e) {
       // We can't do anything with an invalid URI
       return;
     }
 
     let localURI = resolveURIToLocalPath(nsuri);
     if (!localURI) {
       return;
     }
@@ -250,18 +262,17 @@ let SourceActor = ActorClassWithSpec(sou
     if (!id) {
       return;
     }
     this._addonID = id;
 
     if (localURI instanceof Ci.nsIJARURI) {
       // The path in the add-on is easy for jar: uris
       this._addonPath = localURI.JAREntry;
-    }
-    else if (localURI instanceof Ci.nsIFileURL) {
+    } else if (localURI instanceof Ci.nsIFileURL) {
       // For file: uris walk up to find the last directory that is part of the
       // add-on
       let target = localURI.file;
       let path = target.leafName;
 
       // We can assume that the directory containing the source file is part
       // of the add-on
       let root = target.parent;
@@ -305,17 +316,19 @@ let SourceActor = ActorClassWithSpec(sou
       console.error("\t", "source map's sourcesContent =");
       map.sourcesContent.forEach(c => {
         if (c.length > 80) {
           c = c.slice(0, 77) + "...";
         }
         c = c.replace(/\n/g, "\\n");
         console.error("\t\t", c);
       });
-    } catch (e) { }
+    } catch (e) {
+      // ignore
+    }
   },
 
   _getSourceText: function () {
     let toResolvedContent = t => ({
       content: t,
       contentType: this._contentType
     });
 
@@ -341,63 +354,62 @@ let SourceActor = ActorClassWithSpec(sou
       // sources to get the contentType from the headers.
       if (this.source &&
           this.source.text !== "[no source]" &&
           this._contentType &&
           (this._contentType.indexOf("javascript") !== -1 ||
            this._contentType === "text/wasm")) {
         return toResolvedContent(this.source.text);
       }
-      else {
-        // Only load the HTML page source from cache (which exists when
-        // there are inline sources). Otherwise, we can't trust the
-        // cache because we are most likely here because we are
-        // fetching the original text for sourcemapped code, and the
-        // page hasn't requested it before (if it has, it was a
-        // previous debugging session).
-        let loadFromCache = this.isInlineSource;
+
+      // Only load the HTML page source from cache (which exists when
+      // there are inline sources). Otherwise, we can't trust the
+      // cache because we are most likely here because we are
+      // fetching the original text for sourcemapped code, and the
+      // page hasn't requested it before (if it has, it was a
+      // previous debugging session).
+      let loadFromCache = this.isInlineSource;
 
-        // Fetch the sources with the same principal as the original document
-        let win = this.threadActor._parent.window;
-        let principal, cacheKey;
-        // On xpcshell, we don't have a window but a Sandbox
-        if (!isWorker && win instanceof Ci.nsIDOMWindow) {
-          let webNav = win.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIWebNavigation);
-          let channel = webNav.currentDocumentChannel;
-          principal = channel.loadInfo.loadingPrincipal;
+      // Fetch the sources with the same principal as the original document
+      let win = this.threadActor._parent.window;
+      let principal, cacheKey;
+      // On xpcshell, we don't have a window but a Sandbox
+      if (!isWorker && win instanceof Ci.nsIDOMWindow) {
+        let webNav = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                        .getInterface(Ci.nsIWebNavigation);
+        let channel = webNav.currentDocumentChannel;
+        principal = channel.loadInfo.loadingPrincipal;
 
-          // Retrieve the cacheKey in order to load POST requests from cache
-          // Note that chrome:// URLs don't support this interface.
-          if (loadFromCache &&
-            webNav.currentDocumentChannel instanceof Ci.nsICacheInfoChannel) {
-            cacheKey = webNav.currentDocumentChannel.cacheKey;
-            assert(
-              cacheKey,
-              "Could not fetch the cacheKey from the related document."
-            );
-          }
+        // Retrieve the cacheKey in order to load POST requests from cache
+        // Note that chrome:// URLs don't support this interface.
+        if (loadFromCache &&
+          webNav.currentDocumentChannel instanceof Ci.nsICacheInfoChannel) {
+          cacheKey = webNav.currentDocumentChannel.cacheKey;
+          assert(
+            cacheKey,
+            "Could not fetch the cacheKey from the related document."
+          );
         }
+      }
 
-        let sourceFetched = fetch(this.url, {
-          principal,
-          cacheKey,
-          loadFromCache
-        });
+      let sourceFetched = fetch(this.url, {
+        principal,
+        cacheKey,
+        loadFromCache
+      });
 
-        // Record the contentType we just learned during fetching
-        return sourceFetched
-          .then(result => {
-            this._contentType = result.contentType;
-            return result;
-          }, error => {
-            this._reportLoadSourceError(error, map);
-            throw error;
-          });
-      }
+      // Record the contentType we just learned during fetching
+      return sourceFetched
+        .then(result => {
+          this._contentType = result.contentType;
+          return result;
+        }, error => {
+          this._reportLoadSourceError(error, map);
+          throw error;
+        });
     });
   },
 
   /**
    * Get all executable lines from the current source
    * @return Array - Executable lines of the current script
    **/
   getExecutableLines: function () {
@@ -451,29 +463,29 @@ let SourceActor = ActorClassWithSpec(sou
 
     return offsets;
   },
 
   /**
    * Handler for the "source" packet.
    */
   onSource: function () {
-    return resolve(this._init)
+    return promise.resolve(this._init)
       .then(this._getSourceText)
       .then(({ content, contentType }) => {
         return {
           source: createValueGrip(content, this.threadActor.threadLifetimePool,
             this.threadActor.objectGrip),
           contentType: contentType
         };
       })
-      .then(null, aError => {
-        reportError(aError, "Got an exception during SA_onSource: ");
+      .then(null, error => {
+        reportError(error, "Got an exception during SA_onSource: ");
         throw new Error("Could not load the source for " + this.url + ".\n" +
-                        DevToolsUtils.safeErrorString(aError));
+                        DevToolsUtils.safeErrorString(error));
       });
   },
 
   /**
    * Handler for the "prettyPrint" packet.
    */
   prettyPrint: function (indent) {
     this.threadActor.sources.prettyPrint(this.url, indent);
@@ -493,29 +505,29 @@ let SourceActor = ActorClassWithSpec(sou
         throw new Error(DevToolsUtils.safeErrorString(error));
       });
   },
 
   /**
    * Return a function that sends a request to the pretty print worker, waits on
    * the worker's response, and then returns the pretty printed code.
    *
-   * @param Number aIndent
+   * @param Number indent
    *        The number of spaces to indent by the code by, when we send the
    *        request to the pretty print worker.
    * @returns Function
    *          Returns a function which takes an AST, and returns a promise that
    *          is resolved with `{ code, mappings }` where `code` is the pretty
    *          printed code, and `mappings` is an array of source mappings.
    */
-  _sendToPrettyPrintWorker: function (aIndent) {
+  _sendToPrettyPrintWorker: function (indent) {
     return ({ content }) => {
       return this.prettyPrintWorker.performTask("pretty-print", {
         url: this.url,
-        indent: aIndent,
+        indent,
         source: content
       });
     };
   },
 
   /**
    * Invert a source map. So if a source map maps from a to b, return a new
    * source map from b to a. We need to do this because the source map we get
@@ -571,29 +583,28 @@ let SourceActor = ActorClassWithSpec(sou
           map: prevMap
         };
 
         prevMap = SourceMapGenerator.fromSourceMap(prevMap);
         prevMap.applySourceMap(sm, this.url);
         sm = SourceMapConsumer.fromSourceMap(prevMap);
       }
 
-      let sources = this.threadActor.sources;
-      sources.clearSourceMapCache(source.sourceMapURL);
-      sources.setSourceMapHard(source, null, sm);
+      let actorSources = this.threadActor.sources;
+      actorSources.clearSourceMapCache(source.sourceMapURL);
+      actorSources.setSourceMapHard(source, null, sm);
     });
   },
 
   /**
    * Handler for the "disablePrettyPrint" packet.
    */
   disablePrettyPrint: function () {
     let source = this.generatedSource || this.source;
     let sources = this.threadActor.sources;
-    let sm = sources.getSourceMap(source);
 
     sources.clearSourceMapCache(source.sourceMapURL, { hard: true });
 
     if (this._oldSourceMapping) {
       sources.setSourceMapHard(source,
                                this._oldSourceMapping.url,
                                this._oldSourceMapping.map);
       this._oldSourceMapping = null;
@@ -636,20 +647,21 @@ let SourceActor = ActorClassWithSpec(sou
    *        If true, disables breakpoint sliding.
    *
    * @returns Promise
    *          A promise that resolves to a JSON object representing the
    *          response.
    */
   setBreakpoint: function (line, column, condition, noSliding) {
     if (this.threadActor.state !== "paused") {
-      throw {
+      let errorObject = {
         error: "wrongState",
         message: "Cannot set breakpoint while debuggee is running."
       };
+      throw errorObject;
     }
 
     let location = new OriginalLocation(this, line, column);
     return this._getOrCreateBreakpointActor(
       location,
       condition,
       noSliding
     ).then((actor) => {
@@ -758,21 +770,21 @@ let SourceActor = ActorClassWithSpec(sou
         // GCed as well, and no scripts will exist on those lines
         // anymore. We will never slide through a GCed script.
         if (originalLocation.originalColumn || scripts.length === 0) {
           return promise.resolve(actor);
         }
 
         // Find the script that spans the largest amount of code to
         // determine the bounds for sliding.
-        const largestScript = scripts.reduce((largestScript, script) => {
-          if (script.lineCount > largestScript.lineCount) {
+        const largestScript = scripts.reduce((largestScr, script) => {
+          if (script.lineCount > largestScr.lineCount) {
             return script;
           }
-          return largestScript;
+          return largestScr;
         });
         const maxLine = largestScript.startLine + largestScript.lineCount - 1;
 
         let actualLine = originalLine;
         for (; actualLine <= maxLine; actualLine++) {
           const loc = new GeneratedLocation(this, actualLine);
           if (this._setBreakpointAtGeneratedLocation(actor, loc)) {
             break;
@@ -800,26 +812,26 @@ let SourceActor = ActorClassWithSpec(sou
           actor = existingActor;
         } else {
           actor.originalLocation = actualLocation;
           this.breakpointActorMap.setActor(actualLocation, actor);
         }
       }
 
       return promise.resolve(actor);
-    } else {
-      return this.sources.getAllGeneratedLocations(originalLocation).then((generatedLocations) => {
+    }
+    return this.sources.getAllGeneratedLocations(originalLocation)
+      .then((generatedLocations) => {
         this._setBreakpointAtAllGeneratedLocations(
           actor,
           generatedLocations
         );
 
         return actor;
       });
-    }
   },
 
   _setBreakpointAtAllGeneratedLocations: function (actor, generatedLocations) {
     let success = false;
     for (let generatedLocation of generatedLocations) {
       if (this._setBreakpointAtGeneratedLocation(
         actor,
         generatedLocation
--- a/devtools/server/actors/storage.js
+++ b/devtools/server/actors/storage.js
@@ -1482,17 +1482,17 @@ function DatabaseMetadata(origin, db, st
 
   if (db.objectStoreNames.length) {
     let transaction = db.transaction(db.objectStoreNames, "readonly");
 
     for (let i = 0; i < transaction.objectStoreNames.length; i++) {
       let objectStore =
         transaction.objectStore(transaction.objectStoreNames[i]);
       this._objectStores.push([transaction.objectStoreNames[i],
-                              new ObjectStoreMetadata(objectStore)]);
+                               new ObjectStoreMetadata(objectStore)]);
     }
   }
 }
 DatabaseMetadata.prototype = {
   get objectStores() {
     return this._objectStores;
   },
 
@@ -1919,17 +1919,17 @@ var indexedDBHelpers = {
    * database `name`.
    */
   openWithPrincipal: function (principal, name, storage) {
     return indexedDBForStorage.openForPrincipal(principal, name,
                                                 { storage: storage });
   },
 
   removeDB: Task.async(function* (host, principal, dbName) {
-    let result = new promise(resolve => {
+    let result = new Promise(resolve => {
       let {name, storage} = this.splitNameAndStorage(dbName);
       let request =
         indexedDBForStorage.deleteForPrincipal(principal, name,
                                                { storage: storage });
 
       request.onsuccess = () => {
         resolve({});
         this.onItemUpdated("deleted", host, [dbName]);
@@ -1956,26 +1956,26 @@ var indexedDBHelpers = {
     return this.backToChild("removeDB", yield result);
   }),
 
   removeDBRecord: Task.async(function* (host, principal, dbName, storeName, id) {
     let db;
     let {name, storage} = this.splitNameAndStorage(dbName);
 
     try {
-      db = yield new promise((resolve, reject) => {
+      db = yield new Promise((resolve, reject) => {
         let request = this.openWithPrincipal(principal, name, storage);
         request.onsuccess = ev => resolve(ev.target.result);
         request.onerror = ev => reject(ev.target.error);
       });
 
       let transaction = db.transaction(storeName, "readwrite");
       let store = transaction.objectStore(storeName);
 
-      yield new promise((resolve, reject) => {
+      yield new Promise((resolve, reject) => {
         let request = store.delete(id);
         request.onsuccess = () => resolve();
         request.onerror = ev => reject(ev.target.error);
       });
 
       this.onItemUpdated("deleted", host, [dbName, storeName, id]);
     } catch (error) {
       let recordPath = [dbName, storeName, id].join("/");
@@ -1989,26 +1989,26 @@ var indexedDBHelpers = {
     return this.backToChild("removeDBRecord", null);
   }),
 
   clearDBStore: Task.async(function* (host, principal, dbName, storeName) {
     let db;
     let {name, storage} = this.splitNameAndStorage(dbName);
 
     try {
-      db = yield new promise((resolve, reject) => {
+      db = yield new Promise((resolve, reject) => {
         let request = this.openWithPrincipal(principal, name, storage);
         request.onsuccess = ev => resolve(ev.target.result);
         request.onerror = ev => reject(ev.target.error);
       });
 
       let transaction = db.transaction(storeName, "readwrite");
       let store = transaction.objectStore(storeName);
 
-      yield new promise((resolve, reject) => {
+      yield new Promise((resolve, reject) => {
         let request = store.clear();
         request.onsuccess = () => resolve();
         request.onerror = ev => reject(ev.target.error);
       });
 
       this.onItemUpdated("cleared", host, [dbName, storeName]);
     } catch (error) {
       let storePath = [dbName, storeName].join("/");
--- a/devtools/server/actors/timeline.js
+++ b/devtools/server/actors/timeline.js
@@ -21,17 +21,17 @@ const { Option, RetVal } = protocol;
 const { actorBridgeWithSpec } = require("devtools/server/actors/common");
 const { Timeline } = require("devtools/server/performance/timeline");
 const { timelineSpec } = require("devtools/shared/specs/timeline");
 const events = require("sdk/event/core");
 
 /**
  * The timeline actor pops and forwards timeline markers registered in docshells.
  */
-var TimelineActor = exports.TimelineActor = protocol.ActorClassWithSpec(timelineSpec, {
+exports.TimelineActor = protocol.ActorClassWithSpec(timelineSpec, {
   /**
    * Initializes this actor with the provided connection and tab actor.
    */
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this.bridge = new Timeline(tabActor);
 
--- a/devtools/server/actors/utils/map-uri-to-addon-id.js
+++ b/devtools/server/actors/utils/map-uri-to-addon-id.js
@@ -19,20 +19,18 @@ const GRAPHENE_ID = "{d1bfe7d9-c01e-4237
 /**
  * This is a wrapper around amIAddonPathService.mapURIToAddonID which always returns
  * false on B2G and graphene to avoid loading the add-on manager there and
  * reports any exceptions rather than throwing so that the caller doesn't have
  * to worry about them.
  */
 if (!Services.appinfo
     || Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT
-
     /* XPCShell */
     || Services.appinfo.ID === undefined
-
     || Services.appinfo.ID == B2G_ID
     || Services.appinfo.ID == GRAPHENE_ID
     || !AddonPathService) {
   module.exports = function mapURIToAddonId(uri) {
     return false;
   };
 } else {
   module.exports = function mapURIToAddonId(uri) {
--- a/devtools/server/actors/utils/webconsole-listeners.js
+++ b/devtools/server/actors/utils/webconsole-listeners.js
@@ -31,17 +31,18 @@ XPCOMUtils.defineLazyServiceGetter(this,
  *        the nsIConsoleMessage, whenever a relevant message is received.
  */
 function ConsoleServiceListener(window, listener) {
   this.window = window;
   this.listener = listener;
 }
 exports.ConsoleServiceListener = ConsoleServiceListener;
 
-ConsoleServiceListener.prototype = {
+ConsoleServiceListener.prototype =
+{
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener]),
 
   /**
    * The content window for which we listen to page errors.
    * @type nsIDOMWindow
    */
   window: null,
 
@@ -195,17 +196,18 @@ ConsoleServiceListener.prototype = {
  */
 function ConsoleAPIListener(window, owner, {addonId} = {}) {
   this.window = window;
   this.owner = owner;
   this.addonId = addonId;
 }
 exports.ConsoleAPIListener = ConsoleAPIListener;
 
-ConsoleAPIListener.prototype = {
+ConsoleAPIListener.prototype =
+{
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   /**
    * The content window for which we listen to window.console API calls.
    * @type nsIDOMWindow
    */
   window: null,
 
@@ -382,17 +384,18 @@ function ConsoleReflowListener(window, l
                          .getInterface(Ci.nsIWebNavigation)
                          .QueryInterface(Ci.nsIDocShell);
   this.listener = listener;
   this.docshell.addWeakReflowObserver(this);
 }
 
 exports.ConsoleReflowListener = ConsoleReflowListener;
 
-ConsoleReflowListener.prototype = {
+ConsoleReflowListener.prototype =
+{
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
                                          Ci.nsISupportsWeakReference]),
   docshell: null,
   listener: null,
 
   /**
    * Forward reflow event to listener.
    *
--- a/devtools/server/actors/webaudio.js
+++ b/devtools/server/actors/webaudio.js
@@ -1,33 +1,27 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const {Cc, Ci, Cu, Cr} = require("chrome");
+/* global XPCNativeWrapper */
 
-const Services = require("Services");
+const { Cu } = require("chrome");
 
 const events = require("sdk/event/core");
-const promise = require("promise");
 const { on: systemOn, off: systemOff } = require("sdk/system/events");
 const protocol = require("devtools/shared/protocol");
 const { CallWatcherActor } = require("devtools/server/actors/call-watcher");
-const { CallWatcherFront } = require("devtools/shared/fronts/call-watcher");
 const { createValueGrip } = require("devtools/server/actors/object");
 const AutomationTimeline = require("./utils/automation-timeline");
-const { on, once, off, emit } = events;
-const { types, method, Arg, Option, RetVal, preEvent } = protocol;
+const { on, off, emit } = events;
 const {
   audionodeSpec,
-  webAudioSpec,
-  AUTOMATION_METHODS,
-  NODE_CREATION_METHODS,
-  NODE_ROUTING_METHODS,
+  webAudioSpec
 } = require("devtools/shared/specs/webaudio");
 const { WebAudioFront } = require("devtools/shared/fronts/webaudio");
 const AUDIO_NODE_DEFINITION = require("devtools/server/actors/utils/audionodes.json");
 const ENABLE_AUTOMATION = false;
 const AUTOMATION_GRANULARITY = 2000;
 const AUTOMATION_GRANULARITY_MAX = 6000;
 
 const AUDIO_GLOBALS = [
@@ -40,17 +34,18 @@ const AUDIO_GLOBALS = [
  */
 var AudioNodeActor = exports.AudioNodeActor = protocol.ActorClassWithSpec(audionodeSpec, {
   form: function (detail) {
     if (detail === "actorid") {
       return this.actorID;
     }
 
     return {
-      actor: this.actorID, // actorID is set when this is added to a pool
+      // actorID is set when this is added to a pool
+      actor: this.actorID,
       type: this.type,
       source: this.source,
       bypassable: this.bypassable,
     };
   },
 
   /**
    * Create the Audio Node actor.
@@ -112,29 +107,29 @@ var AudioNodeActor = exports.AudioNodeAc
 
     // Cast to boolean incase `passThrough` is undefined,
     // like for AudioDestinationNode
     return !!node.passThrough;
   },
 
   /**
    * Takes a boolean, either enabling or disabling the "passThrough" option
-   * on an AudioNode. If a node is bypassed, an effects processing node (like gain, biquad),
-   * will allow the audio stream to pass through the node, unaffected. Returns
-   * the bypass state of the node.
+   * on an AudioNode. If a node is bypassed, an effects processing node (like gain,
+   * biquad), will allow the audio stream to pass through the node, unaffected.
+   * Returns the bypass state of the node.
    *
    * @param Boolean enable
    *        Whether the bypass value should be set on or off.
    * @return Boolean
    */
   bypass: function (enable) {
     let node = this.node.get();
 
     if (node === null) {
-      return;
+      return undefined;
     }
 
     if (this.bypassable) {
       node.passThrough = enable;
     }
 
     return this.isBypassed();
   },
@@ -154,18 +149,17 @@ var AudioNodeActor = exports.AudioNodeAc
     if (node === null) {
       return CollectedAudioNodeError();
     }
 
     try {
       if (isAudioParam(node, param)) {
         node[param].value = value;
         this.automation[param].setValue(value);
-      }
-      else {
+      } else {
         node[param] = value;
       }
       return undefined;
     } catch (e) {
       return constructError(e);
     }
   },
 
@@ -234,16 +228,17 @@ var AudioNodeActor = exports.AudioNodeAc
       // patched method that fires the webaudio actor's `connect-param` event.
       // Connect directly to the wrapped `destNode`, otherwise
       // the patched method thinks this is a new node and won't be
       // able to find it in `_nativeToActorID`.
       XPCNativeWrapper.unwrap(srcNode).connect(destNode[paramName], output);
     } catch (e) {
       return constructError(e);
     }
+    return undefined;
   },
 
   /**
    * Connects this audionode to another via `node.connect(dest)`.
    */
   connectNode: function (destActor, output, input) {
     let srcNode = this.node.get();
     let destNode = destActor.node.get();
@@ -257,16 +252,17 @@ var AudioNodeActor = exports.AudioNodeAc
       // patched method that fires the webaudio actor's `connect-node` event.
       // Connect directly to the wrapped `destNode`, otherwise
       // the patched method thinks this is a new node and won't be
       // able to find it in `_nativeToActorID`.
       XPCNativeWrapper.unwrap(srcNode).connect(destNode, output, input);
     } catch (e) {
       return constructError(e);
     }
+    return undefined;
   },
 
   /**
    * Disconnects this audionode from all connections via `node.disconnect()`.
    */
   disconnect: function (destActor, output) {
     let node = this.node.get();
 
@@ -276,34 +272,34 @@ var AudioNodeActor = exports.AudioNodeAc
 
     try {
       // Disconnect via the unwrapped node, so we can call the
       // patched method that fires the webaudio actor's `disconnect` event.
       XPCNativeWrapper.unwrap(node).disconnect(output);
     } catch (e) {
       return constructError(e);
     }
+    return undefined;
   },
 
   getAutomationData: function (paramName) {
     let timeline = this.automation[paramName];
     if (!timeline) {
       return null;
     }
 
-    let events = timeline.events;
     let values = [];
     let i = 0;
 
     if (!timeline.events.length) {
-      return { events, values };
+      return { events: timeline.events, values };
     }
 
-    let firstEvent = events[0];
-    let lastEvent = events[timeline.events.length - 1];
+    let firstEvent = timeline.events[0];
+    let lastEvent = timeline.events[timeline.events.length - 1];
     // `setValueCurveAtTime` will have a duration value -- other
     // events will have duration of `0`.
     let timeDelta = (lastEvent.time + lastEvent.duration) - firstEvent.time;
     let scale = timeDelta / AUTOMATION_GRANULARITY;
 
     for (; i < AUTOMATION_GRANULARITY; i++) {
       let delta = firstEvent.time + (i * scale);
       let value = timeline.getValueAtTime(delta);
@@ -317,17 +313,17 @@ var AudioNodeActor = exports.AudioNodeAc
     if (lastEvent.type === "setTargetAtTime") {
       for (; i < AUTOMATION_GRANULARITY_MAX; i++) {
         let delta = firstEvent.time + (++i * scale);
         let value = timeline.getValueAtTime(delta);
         values.push({ delta, value });
       }
     }
 
-    return { events, values };
+    return { events: timeline.events, values };
   },
 
   /**
    * Called via WebAudioActor, registers an automation event
    * for the AudioParam called.
    *
    * @param String paramName
    *        Name of the AudioParam.
@@ -373,16 +369,17 @@ var AudioNodeActor = exports.AudioNodeAc
 
       // Apply the args back from the content scope, which is necessary
       // due to the method wrapping changing in bug 1130901 to be exported
       // directly to the content scope.
       param[eventName].apply(param, contentArgs);
     } catch (e) {
       return constructError(e);
     }
+    return undefined;
   },
 
   /**
    * Registers the automation event in the AudioNodeActor's
    * internal timeline. Called when setting automation via
    * `addAutomationEvent`, or from the WebAudioActor's listening
    * to the event firing via content.
    *
@@ -399,17 +396,17 @@ var AudioNodeActor = exports.AudioNodeAc
   }
 });
 
 /**
  * The Web Audio Actor handles simple interaction with an BaseAudioContext
  * high-level methods. After instantiating this actor, you'll need to set it
  * up by calling setup().
  */
-var WebAudioActor = exports.WebAudioActor = protocol.ActorClassWithSpec(webAudioSpec, {
+exports.WebAudioActor = protocol.ActorClassWithSpec(webAudioSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
 
     this._onContentFunctionCall = this._onContentFunctionCall.bind(this);
 
     // Store ChromeOnly ID (`nativeID` property on AudioNodeActor) mapped
     // to the associated actorID, so we don't have to expose `nativeID`
@@ -482,41 +479,37 @@ var WebAudioActor = exports.WebAudioActo
    */
   _onContentFunctionCall: function (functionCall) {
     let { name } = functionCall.details;
 
     // All Web Audio nodes inherit from AudioNode's prototype, so
     // hook into the `connect` and `disconnect` methods
     if (WebAudioFront.NODE_ROUTING_METHODS.has(name)) {
       this._handleRoutingCall(functionCall);
-    }
-    else if (WebAudioFront.NODE_CREATION_METHODS.has(name)) {
+    } else if (WebAudioFront.NODE_CREATION_METHODS.has(name)) {
       this._handleCreationCall(functionCall);
-    }
-    else if (ENABLE_AUTOMATION && WebAudioFront.AUTOMATION_METHODS.has(name)) {
+    } else if (ENABLE_AUTOMATION && WebAudioFront.AUTOMATION_METHODS.has(name)) {
       this._handleAutomationCall(functionCall);
     }
   },
 
   _handleRoutingCall: function (functionCall) {
     let { caller, args, name } = functionCall.details;
     let source = caller;
     let dest = args[0];
-    let isAudioParam = dest ? getConstructorName(dest) === "AudioParam" : false;
+    let isAudioPar = dest ? getConstructorName(dest) === "AudioParam" : false;
 
     // audionode.connect(param)
-    if (name === "connect" && isAudioParam) {
+    if (name === "connect" && isAudioPar) {
       this._onConnectParam(source, dest);
-    }
-    // audionode.connect(node)
-    else if (name === "connect") {
+    } else if (name === "connect") {
+      // audionode.connect(node)
       this._onConnectNode(source, dest);
-    }
-    // audionode.disconnect()
-    else if (name === "disconnect") {
+    } else if (name === "disconnect") {
+      // audionode.disconnect()
       this._onDisconnectNode(source);
     }
   },
 
   _handleCreationCall: function (functionCall) {
     let { caller, result } = functionCall.details;
     // Keep track of the first node created, so we can alert
     // the front end that an audio context is being used since
@@ -822,17 +815,18 @@ function createObjectGrip(value) {
 }
 
 /**
  * Converts all TypedArrays of the array that cannot
  * be passed over the wire into a normal Array equivilent.
  */
 function sanitizeAutomationArgs(args) {
   return args.reduce((newArgs, el) => {
-    newArgs.push(typeof el === "object" && getConstructorName(el) === "Float32Array" ? castToArray(el) : el);
+    let isArray = typeof el === "object" && getConstructorName(el) === "Float32Array";
+    newArgs.push(isArray ? castToArray(el) : el);
     return newArgs;
   }, []);
 }
 
 /**
  * Casts TypedArray to a normal array via a
  * new scope.
  */
--- a/devtools/server/actors/webgl.js
+++ b/devtools/server/actors/webgl.js
@@ -1,20 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const {Cc, Ci, Cu, Cr} = require("chrome");
+/* global XPCNativeWrapper */
+
+const {Cu} = require("chrome");
 const events = require("sdk/event/core");
 const promise = require("promise");
 const protocol = require("devtools/shared/protocol");
 const { ContentObserver } = require("devtools/shared/content-observer");
-const { on, once, off, emit } = events;
-const { method, Arg, Option, RetVal } = protocol;
+const { on, off, emit } = events;
 const {
   shaderSpec,
   programSpec,
   webGLSpec,
 } = require("devtools/shared/specs/webgl");
 
 const WEBGL_CONTEXT_NAMES = ["webgl", "experimental-webgl", "moz-webgl"];
 
@@ -170,26 +171,27 @@ var ProgramActor = protocol.ActorClassWi
    */
   _getShaderActor: function (type) {
     if (this._shaderActorsCache[type]) {
       return this._shaderActorsCache[type];
     }
     let proxy = this.linkedProxy;
     let shader = proxy.getShaderOfType(this.shaders, type);
     let shaderActor = new ShaderActor(this.conn, this.program, shader, proxy);
-    return this._shaderActorsCache[type] = shaderActor;
+    this._shaderActorsCache[type] = shaderActor;
+    return this._shaderActorsCache[type];
   }
 });
 
 /**
  * The WebGL Actor handles simple interaction with a WebGL context via a few
  * high-level methods. After instantiating this actor, you'll need to set it
  * up by calling setup().
  */
-var WebGLActor = exports.WebGLActor = protocol.ActorClassWithSpec(webGLSpec, {
+exports.WebGLActor = protocol.ActorClassWithSpec(webGLSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this._onGlobalCreated = this._onGlobalCreated.bind(this);
     this._onGlobalDestroyed = this._onGlobalDestroyed.bind(this);
     this._onProgramLinked = this._onProgramLinked.bind(this);
   },
   destroy: function (conn) {
@@ -264,44 +266,46 @@ var WebGLActor = exports.WebGLActor = pr
   /**
    * Gets a pixel's RGBA value from a context specified by selector
    * and the coordinates of the pixel in question.
    * Currently only used in tests.
    *
    * @param string selector
    *        A string selector to select the canvas in question from the DOM.
    * @param Object position
-   *        An object with an `x` and `y` property indicating coordinates of the pixel being inspected.
+   *        An object with an `x` and `y` property indicating coordinates of
+   *        the pixel being inspected.
    * @return Object
    *        An object containing `r`, `g`, `b`, and `a` properties of the pixel.
    */
   getPixel: function ({ selector, position }) {
     let { x, y } = position;
     let canvas = this.tabActor.window.document.querySelector(selector);
     let context = XPCNativeWrapper.unwrap(canvas.getContext("webgl"));
     let { proxy } = this._webglObserver.for(context);
     let height = canvas.height;
 
     let buffer = new this.tabActor.window.Uint8Array(4);
     buffer = XPCNativeWrapper.unwrap(buffer);
 
-    proxy.readPixels(x, height - y - 1, 1, 1, context.RGBA, context.UNSIGNED_BYTE, buffer);
+    proxy.readPixels(
+      x, height - y - 1, 1, 1, context.RGBA, context.UNSIGNED_BYTE, buffer
+    );
 
     return { r: buffer[0], g: buffer[1], b: buffer[2], a: buffer[3] };
   },
 
   /**
    * Gets an array of all cached program actors belonging to all windows.
    * This should only be used for tests.
    */
   _getAllPrograms: function () {
     return this._programActorsCache;
   },
 
-
   /**
    * Invoked whenever the current tab actor's document global is created.
    */
   _onGlobalCreated: function ({id, window, isTopLevel}) {
     if (isTopLevel) {
       WebGLInstrumenter.handle(window, this._webglObserver);
       events.emit(this, "global-created", id);
     }
@@ -407,79 +411,89 @@ var WebGLInstrumenter = {
     let { cache, proxy } = observer.for(context);
     let originalFunc = context[funcName];
     let beforeFuncName = callbackName[0] || funcName;
     let afterFuncName = callbackName[1] || callbackName[0] || funcName;
 
     context[funcName] = function (...glArgs) {
       if (timing <= 0 && !observer.suppressHandlers) {
         let glBreak = observer[beforeFuncName](glArgs, cache, proxy);
-        if (glBreak) return undefined;
+        if (glBreak) {
+          return undefined;
+        }
       }
 
       // Invoking .apply on an unxrayed content function doesn't work, because
       // the arguments array is inaccessible to it. Get Xrays back.
       let glResult = Cu.waiveXrays(Cu.unwaiveXrays(originalFunc).apply(this, glArgs));
 
       if (timing >= 0 && !observer.suppressHandlers) {
         let glBreak = observer[afterFuncName](glArgs, glResult, cache, proxy);
-        if (glBreak) return undefined;
+        if (glBreak) {
+          return undefined;
+        }
       }
 
       return glResult;
     };
   },
 
   /**
    * Override mappings for WebGL methods.
    */
   _methods: [{
-    timing: 1, // after
+    // after
+    timing: 1,
     functions: [
       "linkProgram", "getAttribLocation", "getUniformLocation"
     ]
   }, {
-    timing: -1, // before
+    // before
+    timing: -1,
     callback: [
       "toggleVertexAttribArray"
     ],
     functions: [
       "enableVertexAttribArray", "disableVertexAttribArray"
     ]
   }, {
-    timing: -1, // before
+    // before
+    timing: -1,
     callback: [
       "attribute_"
     ],
     functions: [
       "vertexAttrib1f", "vertexAttrib2f", "vertexAttrib3f", "vertexAttrib4f",
       "vertexAttrib1fv", "vertexAttrib2fv", "vertexAttrib3fv", "vertexAttrib4fv",
       "vertexAttribPointer"
     ]
   }, {
-    timing: -1, // before
+    // before
+    timing: -1,
     callback: [
       "uniform_"
     ],
     functions: [
       "uniform1i", "uniform2i", "uniform3i", "uniform4i",
       "uniform1f", "uniform2f", "uniform3f", "uniform4f",
       "uniform1iv", "uniform2iv", "uniform3iv", "uniform4iv",
       "uniform1fv", "uniform2fv", "uniform3fv", "uniform4fv",
       "uniformMatrix2fv", "uniformMatrix3fv", "uniformMatrix4fv"
     ]
   }, {
-    timing: -1, // before
+    // before
+    timing: -1,
     functions: [
       "useProgram", "enable", "disable", "blendColor",
       "blendEquation", "blendEquationSeparate",
       "blendFunc", "blendFuncSeparate"
     ]
   }, {
-    timing: 0, // before and after
+    // before and after
+    timing: 0,
     callback: [
       "beforeDraw_", "afterDraw_"
     ],
     functions: [
       "drawArrays", "drawElements"
     ]
   }]
   // TODO: It'd be a good idea to handle other functions as well:
@@ -609,43 +623,46 @@ WebGLObserver.prototype = {
    *
    * @param array glArgs
    *        Overridable arguments with which the function is called.
    * @param WebGLCache cache
    *        The state storage for the WebGL context initiating this call.
    */
   toggleVertexAttribArray: function (glArgs, cache) {
     glArgs[0] = cache.getCurrentAttributeLocation(glArgs[0]);
-    return glArgs[0] < 0; // Return true to break original function call.
+    // Return true to break original function call.
+    return glArgs[0] < 0;
   },
 
   /**
    * Called immediately *before* 'attribute_' is requested in the context.
    *
    * @param array glArgs
    *        Overridable arguments with which the function is called.
    * @param WebGLCache cache
    *        The state storage for the WebGL context initiating this call.
    */
   attribute_: function (glArgs, cache) {
     glArgs[0] = cache.getCurrentAttributeLocation(glArgs[0]);
-    return glArgs[0] < 0; // Return true to break original function call.
+    // Return true to break original function call.
+    return glArgs[0] < 0;
   },
 
   /**
    * Called immediately *before* 'uniform_' is requested in the context.
    *
    * @param array glArgs
    *        Overridable arguments with which the function is called.
    * @param WebGLCache cache
    *        The state storage for the WebGL context initiating this call.
    */
   uniform_: function (glArgs, cache) {
     glArgs[0] = cache.getCurrentUniformLocation(glArgs[0]);
-    return !glArgs[0]; // Return true to break original function call.
+    // Return true to break original function call.
+    return !glArgs[0];
   },
 
   /**
    * Called immediately *before* 'useProgram' is requested in the context.
    *
    * @param array glArgs
    *        Overridable arguments with which the function is called.
    * @param WebGLCache cache
@@ -765,17 +782,18 @@ WebGLObserver.prototype = {
    * @param WebGLProxy proxy
    *        The proxy methods for the WebGL context initiating this call.
    */
   beforeDraw_: function (glArgs, cache, proxy) {
     let traits = cache.currentProgramTraits;
 
     // Handle program blackboxing.
     if (traits & PROGRAM_BLACKBOX_TRAIT) {
-      return true; // Return true to break original function call.
+      // Return true to break original function call.
+      return true;
     }
     // Handle program highlighting.
     if (traits & PROGRAM_HIGHLIGHT_TRAIT) {
       proxy.enableHighlighting();
     }
 
     return false;
   },
@@ -870,18 +888,20 @@ WebGLCache.prototype = {
    * @param WebGLProgram program
    *        The shader for which the traits are to be cached.
    * @param number traits
    *        A default properties mask set for the program.
    */
   addProgram: function (program, traits) {
     this._programs.set(program, {
       traits: traits,
-      attributes: [], // keys are GLints (numbers)
-      uniforms: new Map() // keys are WebGLUniformLocations (objects)
+      // keys are GLints (numbers)
+      attributes: [],
+      // keys are WebGLUniformLocations (objects)
+      uniforms: new Map()
     });
   },
 
   /**
    * Adds a specific trait to a program. The effect of such properties is
    * determined by the consumer of this cache.
    *
    * @param WebGLProgram program
@@ -1054,17 +1074,19 @@ function WebGLProxy(id, context, cache, 
     "getAttachedShaders",
     "getShaderSource",
     "getShaderOfType",
     "compileShader",
     "enableHighlighting",
     "disableHighlighting",
     "readPixels"
   ];
-  exports.forEach(e => this[e] = (...args) => this._call(e, args));
+  exports.forEach(e => {
+    this[e] = (...args) => this._call(e, args);
+  });
 }
 
 WebGLProxy.prototype = {
   _id: 0,
   _gl: null,
   _cache: null,
   _observer: null,
 
@@ -1123,17 +1145,17 @@ WebGLProxy.prototype = {
    * @param string type
    *        The framebuffer object attachment point, for example "COLOR_ATTACHMENT0".
    * @param string name
    *        The WebGL parameter name, for example "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME".
    *        If unspecified, defaults to "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE".
    * @return any
    *         The corresponding parameter's value.
    */
-  _getFramebufferAttachmentParameter: function (type, name = "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE") {
+  _getFramebufferAttachmentParameter(type, name = "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE") {
     if (!this._getParameter("FRAMEBUFFER_BINDING")) {
       return null;
     }
     let gl = this._gl;
     return gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl[type], gl[name]);
   },
 
   /**
--- a/devtools/server/actors/worker.js
+++ b/devtools/server/actors/worker.js
@@ -166,17 +166,19 @@ let WorkerActor = protocol.ActorClassWit
       this._threadActor = null;
     }
 
     // If the worker is already destroyed, nsIWorkerDebugger.type throws
     // (_dbg.closed appears to be false when it throws)
     let type;
     try {
       type = this._dbg.type;
-    } catch (e) {}
+    } catch (e) {
+      // nothing
+    }
 
     if (type == Ci.nsIWorkerDebugger.TYPE_SERVICE) {
       let worker = this._getServiceWorkerInfo();
       if (worker) {
         worker.detachDebugger();
       }
     }
 
--- a/devtools/shared/platform/content/test/mochitest.ini
+++ b/devtools/shared/platform/content/test/mochitest.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 support-files =
 
 [test_clipboard.html]
 subsuite = clipboard
+skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -14753,8 +14753,15 @@ nsDocShell::GetIsOnlyToplevelInTabGroup(
     return NS_OK;
   }
   MOZ_ASSERT(toplevelWindows.Length() == 1);
   MOZ_ASSERT(toplevelWindows[0] == outer);
 
   *aResult = true;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsDocShell::GetInFreshProcess(bool* aResult)
+{
+  *aResult = TabChild::GetWasFreshProcess();
+  return NS_OK;
+}
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -1119,9 +1119,14 @@ interface nsIDocShell : nsIDocShellTreeI
    * The value is `false` otherwise. This is the case if the docshell is an
    * iframe, has window.opener set, or another window with window.opener
    * referring to this window exists.
    *
    * If this value is `false`, it would be web content visible for a load
    * occuring in this docshell to be performed within a different docshell.
    */
   [infallible] readonly attribute boolean isOnlyToplevelInTabGroup;
+
+  /**
+   * Returns `true` if this docshell was created by a Large-Allocation load.
+   */
+  [infallible] readonly attribute boolean inFreshProcess;
 };
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -9,333 +9,631 @@
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/EventSourceBinding.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
-
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/WorkerRunnable.h"
+#include "mozilla/dom/WorkerScope.h"
+#include "mozilla/UniquePtrExtensions.h"
 #include "nsAutoPtr.h"
 #include "nsNetUtil.h"
 #include "nsIAuthPrompt.h"
 #include "nsIAuthPrompt2.h"
 #include "nsIInputStream.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsMimeTypes.h"
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
 #include "nsPresContext.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIStringBundle.h"
 #include "nsIConsoleService.h"
 #include "nsIObserverService.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsJSUtils.h"
+#include "nsIThreadRetargetableRequest.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIScriptError.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
 #include "xpcpublic.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/Attributes.h"
 #include "nsError.h"
 
 namespace mozilla {
 namespace dom {
 
+using namespace workers;
+
 #define REPLACEMENT_CHAR     (char16_t)0xFFFD
 #define BOM_CHAR             (char16_t)0xFEFF
 #define SPACE_CHAR           (char16_t)0x0020
 #define CR_CHAR              (char16_t)0x000D
 #define LF_CHAR              (char16_t)0x000A
 #define COLON_CHAR           (char16_t)0x003A
 
-#define DEFAULT_BUFFER_SIZE 4096
-
 // Reconnection time related values in milliseconds. The default one is equal
 // to the default value of the pref dom.server-events.default-reconnection-time
 #define MIN_RECONNECTION_TIME_VALUE       500
 #define DEFAULT_RECONNECTION_TIME_VALUE   5000
 #define MAX_RECONNECTION_TIME_VALUE       PR_IntervalToMilliseconds(DELAY_INTERVAL_LIMIT)
 
-EventSource::EventSource(nsPIDOMWindowInner* aOwnerWindow) :
-  DOMEventTargetHelper(aOwnerWindow),
-  mStatus(PARSE_STATE_OFF),
-  mFrozen(false),
-  mErrorLoadOnRedirect(false),
-  mGoingToDispatchAllMessages(false),
-  mWithCredentials(false),
-  mWaitingForOnStopRequest(false),
-  mLastConvertionResult(NS_OK),
-  mReadyState(CONNECTING),
-  mScriptLine(0),
-  mScriptColumn(0),
-  mInnerWindowID(0)
+class EventSourceImpl final : public nsIObserver
+                            , public nsIStreamListener
+                            , public nsIChannelEventSink
+                            , public nsIInterfaceRequestor
+                            , public nsSupportsWeakReference
+                            , public nsIEventTarget
+                            , public nsIThreadRetargetableStreamListener
 {
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+  NS_DECL_NSIREQUESTOBSERVER
+  NS_DECL_NSISTREAMLISTENER
+  NS_DECL_NSICHANNELEVENTSINK
+  NS_DECL_NSIINTERFACEREQUESTOR
+  NS_DECL_NSIEVENTTARGET
+  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
+
+  explicit EventSourceImpl(EventSource* aEventSource);
+
+  enum {
+    CONNECTING = 0U,
+    OPEN = 1U,
+    CLOSED = 2U
+  };
+
+  void Close();
+
+  void Init(nsIPrincipal* aPrincipal, const nsAString& aURL, ErrorResult& aRv);
+
+  nsresult GetBaseURI(nsIURI** aBaseURI);
+
+  void SetupHttpChannel();
+  nsresult SetupReferrerPolicy();
+  nsresult InitChannelAndRequestEventSource();
+  nsresult ResetConnection();
+  void ResetDecoder();
+  nsresult SetReconnectionTimeout();
+
+  void AnnounceConnection();
+  void DispatchAllMessageEvents();
+  nsresult RestartConnection();
+  void ReestablishConnection();
+  void DispatchFailConnection();
+  void FailConnection();
+
+  nsresult Thaw();
+  nsresult Freeze();
+
+  static void TimerCallback(nsITimer* aTimer, void* aClosure);
+
+  nsresult PrintErrorOnConsole(const char* aBundleURI,
+                               const char16_t* aError,
+                               const char16_t** aFormatStrings,
+                               uint32_t aFormatStringsLen);
+  nsresult ConsoleError();
+
+  static nsresult StreamReaderFunc(nsIInputStream* aInputStream,
+                                   void* aClosure,
+                                   const char* aFromRawSegment,
+                                   uint32_t aToOffset,
+                                   uint32_t aCount,
+                                   uint32_t* aWriteCount);
+  void ParseSegment(const char* aBuffer, uint32_t aLength);
+  nsresult SetFieldAndClear();
+  nsresult ClearFields();
+  nsresult ResetEvent();
+  nsresult DispatchCurrentMessageEvent();
+  nsresult ParseCharacter(char16_t aChr);
+  nsresult CheckHealthOfRequestCallback(nsIRequest* aRequestCallback);
+  nsresult OnRedirectVerifyCallback(nsresult result);
+  nsresult ParseURL(const nsAString& aURL);
+  nsresult AddWindowObservers();
+  void RemoveWindowObservers();
+
+  void CloseInternal();
+  void CleanupOnMainThread();
+  void AddRefObject();
+  void ReleaseObject();
+
+  bool RegisterWorkerHolder();
+  void UnregisterWorkerHolder();
+
+  void AssertIsOnTargetThread() const
+  {
+    MOZ_ASSERT(IsTargetThread());
+  }
+
+  bool IsTargetThread() const
+  {
+    return NS_IsMainThread() == mIsMainThread;
+  }
+
+  uint16_t ReadyState()
+  {
+    if (mEventSource) {
+      MutexAutoLock lock(mMutex);
+      return mEventSource->mReadyState;
+    }
+    // EventSourceImpl keeps EventSource alive. If mEventSource is null, it
+    // means that the EventSource has been closed.
+    return CLOSED;
+  }
+
+  void SetReadyState(uint16_t aReadyState)
+  {
+    MOZ_ASSERT(mEventSource);
+    MutexAutoLock lock(mMutex);
+    mEventSource->mReadyState = aReadyState;
+  }
+
+  bool IsFrozen()
+  {
+    MutexAutoLock lock(mMutex);
+    return mFrozen;
+  }
+
+  void SetFrozen(bool aFrozen)
+  {
+    MutexAutoLock lock(mMutex);
+    mFrozen = aFrozen;
+  }
+
+  bool IsClosed()
+  {
+    return ReadyState() == CLOSED;
+  }
+
+  RefPtr<EventSource> mEventSource;
+
+  /**
+   * A simple state machine used to manage the event-source's line buffer
+   *
+   * PARSE_STATE_OFF              -> PARSE_STATE_BEGIN_OF_STREAM
+   *
+   * PARSE_STATE_BEGIN_OF_STREAM  -> PARSE_STATE_BOM_WAS_READ |
+   *                                 PARSE_STATE_CR_CHAR |
+   *                                 PARSE_STATE_BEGIN_OF_LINE |
+   *                                 PARSE_STATE_COMMENT |
+   *                                 PARSE_STATE_FIELD_NAME
+   *
+   * PARSE_STATE_BOM_WAS_READ     -> PARSE_STATE_CR_CHAR |
+   *                                 PARSE_STATE_BEGIN_OF_LINE |
+   *                                 PARSE_STATE_COMMENT |
+   *                                 PARSE_STATE_FIELD_NAME
+   *
+   * PARSE_STATE_CR_CHAR -> PARSE_STATE_CR_CHAR |
+   *                        PARSE_STATE_COMMENT |
+   *                        PARSE_STATE_FIELD_NAME |
+   *                        PARSE_STATE_BEGIN_OF_LINE
+   *
+   * PARSE_STATE_COMMENT -> PARSE_STATE_CR_CHAR |
+   *                        PARSE_STATE_BEGIN_OF_LINE
+   *
+   * PARSE_STATE_FIELD_NAME   -> PARSE_STATE_CR_CHAR |
+   *                             PARSE_STATE_BEGIN_OF_LINE |
+   *                             PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE
+   *
+   * PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE  -> PARSE_STATE_FIELD_VALUE |
+   *                                           PARSE_STATE_CR_CHAR |
+   *                                           PARSE_STATE_BEGIN_OF_LINE
+   *
+   * PARSE_STATE_FIELD_VALUE      -> PARSE_STATE_CR_CHAR |
+   *                                 PARSE_STATE_BEGIN_OF_LINE
+   *
+   * PARSE_STATE_BEGIN_OF_LINE   -> PARSE_STATE_CR_CHAR |
+   *                                PARSE_STATE_COMMENT |
+   *                                PARSE_STATE_FIELD_NAME |
+   *                                PARSE_STATE_BEGIN_OF_LINE
+   *
+   * Whenever the parser find an empty line or the end-of-file
+   * it dispatches the stacked event.
+   *
+   */
+  enum ParserStatus {
+    PARSE_STATE_OFF = 0,
+    PARSE_STATE_BEGIN_OF_STREAM,
+    PARSE_STATE_BOM_WAS_READ,
+    PARSE_STATE_CR_CHAR,
+    PARSE_STATE_COMMENT,
+    PARSE_STATE_FIELD_NAME,
+    PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE,
+    PARSE_STATE_FIELD_VALUE,
+    PARSE_STATE_BEGIN_OF_LINE
+  };
+
+  // Connection related data members. Should only be accessed on main thread.
+  nsCOMPtr<nsIURI> mSrc;
+  uint32_t mReconnectionTime; // in ms
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+  nsString mOrigin;
+  nsCOMPtr<nsITimer> mTimer;
+  nsCOMPtr<nsIHttpChannel> mHttpChannel;
+
+  struct Message
+  {
+    nsString mEventName;
+    nsString mLastEventID;
+    nsString mData;
+  };
+
+  // Message related data members. May be set / initialized when initializing
+  // EventSourceImpl on target thread but should only be used on target thread.
+  nsString mLastEventID;
+  Message mCurrentMessage;
+  nsDeque mMessagesToDispatch;
+  ParserStatus mStatus;
+  nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
+  nsresult mLastConvertionResult;
+  nsString mLastFieldName;
+  nsString mLastFieldValue;
+
+  // EventSourceImpl internal states.
+  // The worker private where the EventSource is created. nullptr if created on
+  // main thread. (accessed on worker thread only)
+  WorkerPrivate* mWorkerPrivate;
+  // Holder to worker to keep worker alive. (accessed on worker thread only)
+  nsAutoPtr<WorkerHolder> mWorkerHolder;
+  // This mutex protects mFrozen and mEventSource->mReadyState that are used in
+  // different threads.
+  mozilla::Mutex mMutex;
+  // Whether the window is frozen. May be set on main thread and read on target
+  // thread. Use mMutex to protect it before accessing it.
+  bool mFrozen;
+  // There are some messages are going to be dispatched when thaw.
+  bool mGoingToDispatchAllMessages;
+  // Whether the EventSource is run on main thread.
+  bool mIsMainThread;
+  // Whether the EventSourceImpl is going to be destroyed.
+  bool mIsClosing;
+
+  // Event Source owner information:
+  // - the script file name
+  // - source code line number and column number where the Event Source object
+  //   was constructed.
+  // - the ID of the inner window where the script lives. Note that this may not
+  //   be the same as the Event Source owner window.
+  // These attributes are used for error reporting. Should only be accessed on
+  // target thread
+  nsString mScriptFile;
+  uint32_t mScriptLine;
+  uint32_t mScriptColumn;
+  uint64_t mInnerWindowID;
+
+private:
+  // prevent bad usage
+  EventSourceImpl(const EventSourceImpl& x) = delete;
+  EventSourceImpl& operator=(const EventSourceImpl& x) = delete;
+  ~EventSourceImpl()
+  {
+    if (IsClosed()) {
+      return;
+    }
+    // If we threw during Init we never called Close
+    SetReadyState(CLOSED);
+    CloseInternal();
+  }
+};
+
+NS_IMPL_ISUPPORTS(EventSourceImpl,
+                  nsIObserver,
+                  nsIStreamListener,
+                  nsIRequestObserver,
+                  nsIChannelEventSink,
+                  nsIInterfaceRequestor,
+                  nsISupportsWeakReference,
+                  nsIEventTarget,
+                  nsIThreadRetargetableStreamListener)
+
+EventSourceImpl::EventSourceImpl(EventSource* aEventSource)
+  : mEventSource(aEventSource)
+  , mReconnectionTime(0)
+  , mStatus(PARSE_STATE_OFF)
+  , mLastConvertionResult(NS_OK)
+  , mMutex("EventSourceImpl::mMutex")
+  , mFrozen(false)
+  , mGoingToDispatchAllMessages(false)
+  , mIsMainThread(NS_IsMainThread())
+  , mIsClosing(false)
+  , mScriptLine(0)
+  , mScriptColumn(0)
+  , mInnerWindowID(0)
+{
+  MOZ_ASSERT(mEventSource);
+  if (!mIsMainThread) {
+    mWorkerPrivate = GetCurrentThreadWorkerPrivate();
+    MOZ_ASSERT(mWorkerPrivate);
+    mEventSource->mIsMainThread = false;
+  }
+  SetReadyState(CONNECTING);
 }
 
-EventSource::~EventSource()
+class CleanupRunnable final : public WorkerMainThreadRunnable
 {
-  Close();
-}
-
-//-----------------------------------------------------------------------------
-// EventSource::nsISupports
-//-----------------------------------------------------------------------------
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(EventSource)
+public:
+  explicit CleanupRunnable(EventSourceImpl* aEventSourceImpl)
+    : WorkerMainThreadRunnable(aEventSourceImpl->mWorkerPrivate,
+                               NS_LITERAL_CSTRING("EventSource :: Cleanup"))
+    , mImpl(aEventSourceImpl)
+  {
+    mImpl->mWorkerPrivate->AssertIsOnWorkerThread();
+  }
 
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(EventSource)
-  bool isBlack = tmp->IsBlack();
-  if (isBlack || tmp->mWaitingForOnStopRequest) {
-    if (tmp->mListenerManager) {
-      tmp->mListenerManager->MarkForCC();
-    }
-    if (!isBlack && tmp->PreservingWrapper()) {
-      // This marks the wrapper black.
-      tmp->GetWrapper();
-    }
+  bool MainThreadRun() override
+  {
+    mImpl->CleanupOnMainThread();
     return true;
   }
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(EventSource)
-  return tmp->IsBlack();
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
-
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(EventSource)
-  return tmp->IsBlack();
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(EventSource,
-                                               DOMEventTargetHelper)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(EventSource,
-                                                  DOMEventTargetHelper)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrc)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadGroup)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHttpChannel)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimer)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnicodeDecoder)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(EventSource,
-                                                DOMEventTargetHelper)
-  tmp->Close();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(EventSource)
-  NS_INTERFACE_MAP_ENTRY(nsIObserver)
-  NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
-  NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
-  NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
-  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
-  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-NS_IMPL_ADDREF_INHERITED(EventSource, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(EventSource, DOMEventTargetHelper)
+protected:
+  // Raw pointer because this runnable is sync.
+  EventSourceImpl* mImpl;
+};
 
 void
-EventSource::DisconnectFromOwner()
+EventSourceImpl::Close()
 {
-  DOMEventTargetHelper::DisconnectFromOwner();
-  Close();
+  if (IsClosed()) {
+    return;
+  }
+  SetReadyState(CLOSED);
+  // Asynchronously call CloseInternal to prevent EventSourceImpl from being
+  // synchronously destoryed while dispatching DOM event.
+  DebugOnly<nsresult> rv =
+    Dispatch(NewRunnableMethod(this, &EventSourceImpl::CloseInternal),
+             NS_DISPATCH_NORMAL);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 }
 
 void
-EventSource::Close()
+EventSourceImpl::CloseInternal()
 {
-  if (mReadyState == CLOSED) {
+  AssertIsOnTargetThread();
+  MOZ_ASSERT(IsClosed());
+  if (mIsClosing) {
     return;
   }
+  mIsClosing = true;
+  while (mMessagesToDispatch.GetSize() != 0) {
+    delete static_cast<Message*>(mMessagesToDispatch.PopFront());
+  }
 
-  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-  if (os) {
-    os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
-    os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
-    os->RemoveObserver(this, DOM_WINDOW_THAWED_TOPIC);
+  if (NS_IsMainThread()) {
+    CleanupOnMainThread();
+  } else {
+    ErrorResult rv;
+    // run CleanupOnMainThread synchronously on main thread since it touches
+    // observers and members only can be accessed on main thread.
+    RefPtr<CleanupRunnable> runnable = new CleanupRunnable(this);
+    runnable->Dispatch(Killing, rv);
+    MOZ_ASSERT(!rv.Failed());
+    UnregisterWorkerHolder();
+  }
+
+  SetFrozen(false);
+  ResetDecoder();
+  mUnicodeDecoder = nullptr;
+  // UpdateDontKeepAlive() can release the object. Don't access to any members
+  // after it.
+  mEventSource->UpdateDontKeepAlive();
+}
+
+void EventSourceImpl::CleanupOnMainThread()
+{
+  AssertIsOnMainThread();
+  if (mIsMainThread) {
+    RemoveWindowObservers();
   }
 
   if (mTimer) {
     mTimer->Cancel();
     mTimer = nullptr;
   }
 
   ResetConnection();
-
-  ClearFields();
-
-  while (mMessagesToDispatch.GetSize() != 0) {
-    delete static_cast<Message*>(mMessagesToDispatch.PopFront());
-  }
-
+  mPrincipal = nullptr;
   mSrc = nullptr;
-  mFrozen = false;
-
-  mUnicodeDecoder = nullptr;
-
-  mReadyState = CLOSED;
 }
 
-nsresult
-EventSource::Init(nsISupports* aOwner,
-                  const nsAString& aURL,
-                  bool aWithCredentials)
+class InitRunnable final : public WorkerMainThreadRunnable
 {
-  if (mReadyState != CONNECTING) {
-    return NS_ERROR_DOM_SECURITY_ERR;
+public:
+  explicit InitRunnable(EventSourceImpl* aEventSourceImpl,
+                        const nsAString& aURL)
+    : WorkerMainThreadRunnable(aEventSourceImpl->mWorkerPrivate,
+                               NS_LITERAL_CSTRING("EventSource :: Init"))
+    , mImpl(aEventSourceImpl)
+    , mURL(aURL)
+  {
+    mImpl->mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(sgo);
-  // XXXbz why are we checking this?  This doesn't match anything in the spec.
-  nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
-  NS_ENSURE_STATE(scriptContext);
-
-  nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
-    do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(scriptPrincipal);
-  nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
-  NS_ENSURE_STATE(principal);
-
-  mPrincipal = principal;
-  mWithCredentials = aWithCredentials;
-
-  // The conditional here is historical and not necessarily sane.
-  if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
-    nsJSUtils::GetCallingLocation(cx, mScriptFile, &mScriptLine,
-                                  &mScriptColumn);
-    mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
+  bool MainThreadRun() override
+  {
+    // Get principal from worker's owner document or from worker.
+    WorkerPrivate* wp = mImpl->mWorkerPrivate;
+    while (wp->GetParent()) {
+      wp = wp->GetParent();
+    }
+    nsPIDOMWindowInner* window = wp->GetWindow();
+    nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
+    nsCOMPtr<nsIPrincipal> principal = doc ? doc->NodePrincipal() :
+                                             wp->GetPrincipal();
+    if (!principal) {
+      mRv = NS_ERROR_FAILURE;
+      return true;
+    }
+    ErrorResult rv;
+    mImpl->Init(principal, mURL, rv);
+    mRv = rv.StealNSResult();
+    return true;
   }
 
-  // Get the load group for the page. When requesting we'll add ourselves to it.
-  // This way any pending requests will be automatically aborted if the user
-  // leaves the page.
-  nsCOMPtr<nsIDocument> doc = GetDocumentIfCurrent();
-  if (doc) {
-    mLoadGroup = doc->GetDocumentLoadGroup();
-  }
+  nsresult ErrorCode() const { return mRv; }
+
+protected:
+  // Raw pointer because this runnable is sync.
+  EventSourceImpl* mImpl;
+  const nsAString& mURL;
+  nsresult mRv;
+};
+
+nsresult
+EventSourceImpl::ParseURL(const nsAString& aURL)
+{
+  AssertIsOnMainThread();
   // get the src
   nsCOMPtr<nsIURI> baseURI;
   nsresult rv = GetBaseURI(getter_AddRefs(baseURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> srcURI;
   rv = NS_NewURI(getter_AddRefs(srcURI), aURL, nullptr, baseURI);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
 
-  // we observe when the window freezes and thaws
-  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-  NS_ENSURE_STATE(os);
-
-  rv = os->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, true);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = os->AddObserver(this, DOM_WINDOW_FROZEN_TOPIC, true);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = os->AddObserver(this, DOM_WINDOW_THAWED_TOPIC, true);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsAutoString origin;
   rv = nsContentUtils::GetUTFOrigin(srcURI, origin);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString spec;
   rv = srcURI->GetSpec(spec);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mOriginalURL = NS_ConvertUTF8toUTF16(spec);
+  mEventSource->mOriginalURL = NS_ConvertUTF8toUTF16(spec);
   mSrc = srcURI;
   mOrigin = origin;
+  return NS_OK;
+}
+
+nsresult
+EventSourceImpl::AddWindowObservers()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mIsMainThread);
+  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+  NS_ENSURE_STATE(os);
+
+  nsresult rv = os->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, true);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = os->AddObserver(this, DOM_WINDOW_FROZEN_TOPIC, true);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = os->AddObserver(this, DOM_WINDOW_THAWED_TOPIC, true);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
+}
+
+void
+EventSourceImpl::RemoveWindowObservers()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mIsMainThread);
+  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+  if (os) {
+    os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
+    os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
+    os->RemoveObserver(this, DOM_WINDOW_THAWED_TOPIC);
+  }
+}
+
+void
+EventSourceImpl::Init(nsIPrincipal* aPrincipal,
+                      const nsAString& aURL,
+                      ErrorResult& aRv)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aPrincipal);
+  if (IsClosed()) {
+    return;
+  }
+  mPrincipal = aPrincipal;
+  aRv = ParseURL(aURL);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+  // The conditional here is historical and not necessarily sane.
+  if (JSContext* cx = nsContentUtils::GetCurrentJSContext()) {
+    nsJSUtils::GetCallingLocation(cx, mScriptFile, &mScriptLine,
+                                  &mScriptColumn);
+    mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
+  }
+
+  if (mIsMainThread) {
+    // we observe when the window freezes and thaws
+    aRv = AddWindowObservers();
+    if (NS_WARN_IF(aRv.Failed())) {
+      return;
+    }
+  }
 
   mReconnectionTime =
     Preferences::GetInt("dom.server-events.default-reconnection-time",
                         DEFAULT_RECONNECTION_TIME_VALUE);
 
   mUnicodeDecoder = EncodingUtils::DecoderForEncoding("UTF-8");
 
   // the constructor should throw a SYNTAX_ERROR only if it fails resolving the
   // url parameter, so we don't care about the InitChannelAndRequestEventSource
   // result.
   InitChannelAndRequestEventSource();
-
-  return NS_OK;
-}
-
-/* virtual */ JSObject*
-EventSource::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
-  return EventSourceBinding::Wrap(aCx, this, aGivenProto);
-}
-
-/* static */ already_AddRefed<EventSource>
-EventSource::Constructor(const GlobalObject& aGlobal,
-                         const nsAString& aURL,
-                         const EventSourceInit& aEventSourceInitDict,
-                         ErrorResult& aRv)
-{
-  nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
-    do_QueryInterface(aGlobal.GetAsSupports());
-  if (!ownerWindow) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return nullptr;
-  }
-  MOZ_ASSERT(ownerWindow->IsInnerWindow());
-
-  RefPtr<EventSource> eventSource = new EventSource(ownerWindow);
-  aRv = eventSource->Init(aGlobal.GetAsSupports(), aURL,
-                          aEventSourceInitDict.mWithCredentials);
-  return eventSource.forget();
 }
 
 //-----------------------------------------------------------------------------
-// EventSource::nsIObserver
+// EventSourceImpl::nsIObserver
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-EventSource::Observe(nsISupports* aSubject,
-                     const char* aTopic,
-                     const char16_t* aData)
+EventSourceImpl::Observe(nsISupports* aSubject,
+                         const char* aTopic,
+                         const char16_t* aData)
 {
-  if (mReadyState == CLOSED) {
+  AssertIsOnMainThread();
+  if (IsClosed()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aSubject);
-  if (!GetOwner() || window != GetOwner()) {
+  if (!mEventSource->GetOwner() || window != mEventSource->GetOwner()) {
     return NS_OK;
   }
 
   DebugOnly<nsresult> rv;
   if (strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) {
     rv = Freeze();
-    NS_ASSERTION(NS_SUCCEEDED(rv), "Freeze() failed");
+    MOZ_ASSERT(NS_SUCCEEDED(rv), "Freeze() failed");
   } else if (strcmp(aTopic, DOM_WINDOW_THAWED_TOPIC) == 0) {
     rv = Thaw();
-    NS_ASSERTION(NS_SUCCEEDED(rv), "Thaw() failed");
+    MOZ_ASSERT(NS_SUCCEEDED(rv), "Thaw() failed");
   } else if (strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0) {
     Close();
   }
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
-// EventSource::nsIStreamListener
+// EventSourceImpl::nsIStreamListener
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-EventSource::OnStartRequest(nsIRequest *aRequest,
-                            nsISupports *ctxt)
+EventSourceImpl::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt)
 {
+  AssertIsOnMainThread();
+  if (IsClosed()) {
+    return NS_ERROR_ABORT;
+  }
   nsresult rv = CheckHealthOfRequestCallback(aRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsresult status;
   rv = aRequest->GetStatus(&status);
@@ -360,98 +658,158 @@ EventSource::OnStartRequest(nsIRequest *
   rv = httpChannel->GetContentType(contentType);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!contentType.EqualsLiteral(TEXT_EVENT_STREAM)) {
     DispatchFailConnection();
     return NS_ERROR_ABORT;
   }
 
-  rv = NS_DispatchToMainThread(NewRunnableMethod(this, &EventSource::AnnounceConnection));
+  if (!mIsMainThread) {
+    // Try to retarget to worker thread, otherwise fall back to main thread.
+    nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(httpChannel);
+    if (rr) {
+      rv = rr->RetargetDeliveryTo(this);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+  rv = Dispatch(NewRunnableMethod(this, &EventSourceImpl::AnnounceConnection),
+                NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
-
   mStatus = PARSE_STATE_BEGIN_OF_STREAM;
-
   return NS_OK;
 }
 
 // this method parses the characters as they become available instead of
 // buffering them.
 nsresult
-EventSource::StreamReaderFunc(nsIInputStream *aInputStream,
-                              void *aClosure,
-                              const char *aFromRawSegment,
-                              uint32_t aToOffset,
-                              uint32_t aCount,
-                              uint32_t *aWriteCount)
+EventSourceImpl::StreamReaderFunc(nsIInputStream* aInputStream,
+                                  void* aClosure,
+                                  const char* aFromRawSegment,
+                                  uint32_t aToOffset,
+                                  uint32_t aCount,
+                                  uint32_t* aWriteCount)
 {
-  EventSource* thisObject = static_cast<EventSource*>(aClosure);
+  EventSourceImpl* thisObject = static_cast<EventSourceImpl*>(aClosure);
+  thisObject->AssertIsOnTargetThread();
   if (!thisObject || !aWriteCount) {
     NS_WARNING("EventSource cannot read from stream: no aClosure or aWriteCount");
     return NS_ERROR_FAILURE;
   }
-
-  *aWriteCount = 0;
-
-  int32_t srcCount, outCount;
-  char16_t out[2];
-  nsresult rv;
-
-  const char *p = aFromRawSegment,
-             *end = aFromRawSegment + aCount;
-
-  do {
-    srcCount = aCount - (p - aFromRawSegment);
-    outCount = 2;
-
-    thisObject->mLastConvertionResult =
-      thisObject->mUnicodeDecoder->Convert(p, &srcCount, out, &outCount);
-    MOZ_ASSERT(thisObject->mLastConvertionResult != NS_ERROR_ILLEGAL_INPUT);
-
-    for (int32_t i = 0; i < outCount; ++i) {
-      rv = thisObject->ParseCharacter(out[i]);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    p = p + srcCount;
-  } while (p < end &&
-           thisObject->mLastConvertionResult != NS_PARTIAL_MORE_INPUT &&
-           thisObject->mLastConvertionResult != NS_OK);
-
+  thisObject->ParseSegment((const char*)aFromRawSegment, aCount);
   *aWriteCount = aCount;
   return NS_OK;
 }
 
+void
+EventSourceImpl::ParseSegment(const char* aBuffer, uint32_t aLength)
+{
+  AssertIsOnTargetThread();
+  if (IsClosed()) {
+    return;
+  }
+  int32_t srcCount, outCount;
+  char16_t out[2];
+  const char* p = aBuffer;
+  const char* end = aBuffer + aLength;
+
+  do {
+    srcCount = aLength - (p - aBuffer);
+    outCount = 2;
+
+    mLastConvertionResult =
+      mUnicodeDecoder->Convert(p, &srcCount, out, &outCount);
+    MOZ_ASSERT(mLastConvertionResult != NS_ERROR_ILLEGAL_INPUT);
+
+    for (int32_t i = 0; i < outCount; ++i) {
+      nsresult rv = ParseCharacter(out[i]);
+      NS_ENSURE_SUCCESS_VOID(rv);
+    }
+    p = p + srcCount;
+  } while (p < end &&
+           mLastConvertionResult != NS_PARTIAL_MORE_INPUT &&
+           mLastConvertionResult != NS_OK);
+}
+
+class DataAvailableRunnable final : public Runnable
+{
+  private:
+    RefPtr<EventSourceImpl> mEventSourceImpl;
+    UniquePtr<char[]> mData;
+    uint32_t mLength;
+  public:
+    DataAvailableRunnable(EventSourceImpl* aEventSourceImpl,
+                          UniquePtr<char[]> aData,
+                          uint32_t aLength)
+      : mEventSourceImpl(aEventSourceImpl)
+      , mData(Move(aData))
+      , mLength(aLength)
+    {
+    }
+
+    NS_IMETHOD Run() override
+    {
+      mEventSourceImpl->ParseSegment(mData.get(), mLength);
+      return NS_OK;
+    }
+};
+
 NS_IMETHODIMP
-EventSource::OnDataAvailable(nsIRequest *aRequest,
-                             nsISupports *aContext,
-                             nsIInputStream *aInputStream,
-                             uint64_t aOffset,
-                             uint32_t aCount)
+EventSourceImpl::OnDataAvailable(nsIRequest* aRequest,
+                                 nsISupports* aContext,
+                                 nsIInputStream* aInputStream,
+                                 uint64_t aOffset,
+                                 uint32_t aCount)
 {
+  // Although we try to retarget OnDataAvailable to target thread, it may fail
+  // and fallback to main thread.
   NS_ENSURE_ARG_POINTER(aInputStream);
+  if (IsClosed()) {
+    return NS_ERROR_ABORT;
+  }
 
   nsresult rv = CheckHealthOfRequestCallback(aRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t totalRead;
-  return aInputStream->ReadSegments(EventSource::StreamReaderFunc, this,
+  if (IsTargetThread()) {
+    rv = aInputStream->ReadSegments(EventSourceImpl::StreamReaderFunc, this,
                                     aCount, &totalRead);
+  } else {
+    // This could be happened when fail to retarget to target thread and
+    // fallback to the main thread.
+    AssertIsOnMainThread();
+    auto data = MakeUniqueFallible<char[]>(aCount);
+    if (!data) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    rv = aInputStream->Read(data.get(), aCount, &totalRead);
+    NS_ENSURE_SUCCESS(rv, rv);
+    MOZ_ASSERT(totalRead <= aCount, "EventSource read more than available!!");
+
+    nsCOMPtr<nsIRunnable> dataAvailable =
+      new DataAvailableRunnable(this, Move(data), totalRead);
+
+    MOZ_ASSERT(mWorkerPrivate);
+    rv = Dispatch(dataAvailable.forget(), NS_DISPATCH_NORMAL);
+  }
+  return rv;
 }
 
 NS_IMETHODIMP
-EventSource::OnStopRequest(nsIRequest *aRequest,
-                           nsISupports *aContext,
-                           nsresult aStatusCode)
+EventSourceImpl::OnStopRequest(nsIRequest* aRequest,
+                               nsISupports* aContext,
+                               nsresult aStatusCode)
 {
-  mWaitingForOnStopRequest = false;
+  AssertIsOnMainThread();
 
-  if (mReadyState == CLOSED) {
+  if (IsClosed()) {
     return NS_ERROR_ABORT;
   }
-
+  MOZ_ASSERT(mSrc);
   // "Network errors that prevents the connection from being established in the
   //  first place (e.g. DNS errors), must cause the user agent to asynchronously
   //  reestablish the connection.
   //
   //  (...) the cancelation of the fetch algorithm by the user agent (e.g. in
   //  response to window.stop() or the user canceling the network connection
   //  manually) must cause the user agent to fail the connection.
 
@@ -464,51 +822,52 @@ EventSource::OnStopRequest(nsIRequest *a
       aStatusCode != NS_ERROR_DNS_LOOKUP_QUEUE_FULL) {
     DispatchFailConnection();
     return NS_ERROR_ABORT;
   }
 
   nsresult rv = CheckHealthOfRequestCallback(aRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  ClearFields();
-
-  rv = NS_DispatchToMainThread(NewRunnableMethod(this, &EventSource::ReestablishConnection));
+  rv = Dispatch(
+         NewRunnableMethod(this, &EventSourceImpl::ReestablishConnection),
+         NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
-// EventSource::nsIChannelEventSink
+// EventSourceImpl::nsIChannelEventSink
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-EventSource::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
-                                    nsIChannel *aNewChannel,
-                                    uint32_t    aFlags,
-                                    nsIAsyncVerifyRedirectCallback *aCallback)
+EventSourceImpl::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
+                                        nsIChannel* aNewChannel,
+                                        uint32_t aFlags,
+                                        nsIAsyncVerifyRedirectCallback* aCallback)
 {
+  AssertIsOnMainThread();
   nsCOMPtr<nsIRequest> aOldRequest = do_QueryInterface(aOldChannel);
   NS_PRECONDITION(aOldRequest, "Redirect from a null request?");
 
   nsresult rv = CheckHealthOfRequestCallback(aOldRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
 
   nsCOMPtr<nsIURI> newURI;
   rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool isValidScheme =
     (NS_SUCCEEDED(newURI->SchemeIs("http", &isValidScheme)) && isValidScheme) ||
     (NS_SUCCEEDED(newURI->SchemeIs("https", &isValidScheme)) && isValidScheme);
 
-  rv = CheckInnerWindowCorrectness();
+  rv = mEventSource->CheckInnerWindowCorrectness();
   if (NS_FAILED(rv) || !isValidScheme) {
      DispatchFailConnection();
      return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // update our channel
 
   mHttpChannel = do_QueryInterface(aNewChannel);
@@ -524,63 +883,71 @@ EventSource::AsyncOnChannelRedirect(nsIC
   }
 
   aCallback->OnRedirectVerifyCallback(NS_OK);
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
-// EventSource::nsIInterfaceRequestor
+// EventSourceImpl::nsIInterfaceRequestor
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-EventSource::GetInterface(const nsIID & aIID,
-                          void **aResult)
+EventSourceImpl::GetInterface(const nsIID& aIID, void** aResult)
 {
+  AssertIsOnMainThread();
   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
     *aResult = static_cast<nsIChannelEventSink*>(this);
     NS_ADDREF_THIS();
     return NS_OK;
   }
 
   if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
       aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
-    nsresult rv = CheckInnerWindowCorrectness();
+    nsresult rv = mEventSource->CheckInnerWindowCorrectness();
     NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
 
     nsCOMPtr<nsIPromptFactory> wwatch =
       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Get the an auth prompter for our window so that the parenting
     // of the dialogs works as it should when using tabs.
 
     nsCOMPtr<nsPIDOMWindowOuter> window;
-    if (GetOwner()) {
-      window = GetOwner()->GetOuterWindow();
+    if (mEventSource->GetOwner()) {
+      window = mEventSource->GetOwner()->GetOuterWindow();
     }
 
     return wwatch->GetPrompt(window, aIID, aResult);
   }
 
   return QueryInterface(aIID, aResult);
 }
 
+NS_IMETHODIMP
+EventSourceImpl::IsOnCurrentThread(bool* aResult)
+{
+  *aResult = IsTargetThread();
+  return NS_OK;
+}
+
 nsresult
-EventSource::GetBaseURI(nsIURI **aBaseURI)
+EventSourceImpl::GetBaseURI(nsIURI** aBaseURI)
 {
+  AssertIsOnMainThread();
   NS_ENSURE_ARG_POINTER(aBaseURI);
 
   *aBaseURI = nullptr;
 
   nsCOMPtr<nsIURI> baseURI;
 
   // first we try from document->GetBaseURI()
-  nsCOMPtr<nsIDocument> doc = GetDocumentIfCurrent();
+  nsCOMPtr<nsIDocument> doc = mEventSource->GetDocumentIfCurrent();
   if (doc) {
     baseURI = doc->GetBaseURI();
   }
 
   // otherwise we get from the doc's principal
   if (!baseURI) {
     nsresult rv = mPrincipal->GetURI(getter_AddRefs(baseURI));
     NS_ENSURE_SUCCESS(rv, rv);
@@ -588,94 +955,98 @@ EventSource::GetBaseURI(nsIURI **aBaseUR
 
   NS_ENSURE_STATE(baseURI);
 
   baseURI.forget(aBaseURI);
   return NS_OK;
 }
 
 void
-EventSource::SetupHttpChannel()
+EventSourceImpl::SetupHttpChannel()
 {
+  AssertIsOnMainThread();
   mHttpChannel->SetRequestMethod(NS_LITERAL_CSTRING("GET"));
 
   /* set the http request headers */
 
   mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
     NS_LITERAL_CSTRING(TEXT_EVENT_STREAM), false);
 
   // LOAD_BYPASS_CACHE already adds the Cache-Control: no-cache header
 
   if (!mLastEventID.IsEmpty()) {
     mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Last-Event-ID"),
       NS_ConvertUTF16toUTF8(mLastEventID), false);
   }
 }
 
 nsresult
-EventSource::SetupReferrerPolicy()
+EventSourceImpl::SetupReferrerPolicy()
 {
-  nsCOMPtr<nsIDocument> doc = GetDocumentIfCurrent();
+  AssertIsOnMainThread();
+  nsCOMPtr<nsIDocument> doc = mEventSource->GetDocumentIfCurrent();
   if (doc) {
     nsresult rv = mHttpChannel->SetReferrerWithPolicy(doc->GetDocumentURI(),
                                                       doc->GetReferrerPolicy());
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
-EventSource::InitChannelAndRequestEventSource()
+EventSourceImpl::InitChannelAndRequestEventSource()
 {
-  if (mReadyState == CLOSED) {
+  AssertIsOnMainThread();
+  if (IsClosed()) {
     return NS_ERROR_ABORT;
   }
 
   bool isValidScheme =
     (NS_SUCCEEDED(mSrc->SchemeIs("http", &isValidScheme)) && isValidScheme) ||
     (NS_SUCCEEDED(mSrc->SchemeIs("https", &isValidScheme)) && isValidScheme);
 
-  nsresult rv = CheckInnerWindowCorrectness();
+  nsresult rv = mEventSource->CheckInnerWindowCorrectness();
   if (NS_FAILED(rv) || !isValidScheme) {
     DispatchFailConnection();
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsLoadFlags loadFlags;
   loadFlags = nsIRequest::LOAD_BACKGROUND | nsIRequest::LOAD_BYPASS_CACHE;
 
-  nsCOMPtr<nsIDocument> doc = GetDocumentIfCurrent();
+  nsCOMPtr<nsIDocument> doc = mEventSource->GetDocumentIfCurrent();
 
   nsSecurityFlags securityFlags =
     nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
 
-  if (mWithCredentials) {
+  if (mEventSource->mWithCredentials) {
     securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
   }
 
   nsCOMPtr<nsIChannel> channel;
   // If we have the document, use it
   if (doc) {
+    nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
     rv = NS_NewChannel(getter_AddRefs(channel),
                        mSrc,
                        doc,
                        securityFlags,
                        nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE,
-                       mLoadGroup,       // loadGroup
+                       loadGroup,
                        nullptr,          // aCallbacks
                        loadFlags);       // aLoadFlags
   } else {
     // otherwise use the principal
     rv = NS_NewChannel(getter_AddRefs(channel),
                        mSrc,
                        mPrincipal,
                        securityFlags,
                        nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE,
-                       mLoadGroup,       // loadGroup
+                       nullptr,          // loadGroup
                        nullptr,          // aCallbacks
                        loadFlags);       // aLoadFlags
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   mHttpChannel = do_QueryInterface(channel);
   NS_ENSURE_TRUE(mHttpChannel, NS_ERROR_NO_INTERFACE);
@@ -694,117 +1065,146 @@ EventSource::InitChannelAndRequestEventS
   mHttpChannel->SetNotificationCallbacks(this);
 
   // Start reading from the channel
   rv = mHttpChannel->AsyncOpen2(this);
   if (NS_FAILED(rv)) {
     DispatchFailConnection();
     return rv;
   }
-  mWaitingForOnStopRequest = true;
+  // Create the connection. Ask EventSource to hold reference until Close is
+  // called or network error is received.
+  mEventSource->UpdateMustKeepAlive();
   return rv;
 }
 
 void
-EventSource::AnnounceConnection()
+EventSourceImpl::AnnounceConnection()
 {
-  if (mReadyState == CLOSED) {
-    return;
-  }
-
-  if (mReadyState != CONNECTING) {
+  AssertIsOnTargetThread();
+  if (ReadyState() != CONNECTING) {
     NS_WARNING("Unexpected mReadyState!!!");
     return;
   }
 
   // When a user agent is to announce the connection, the user agent must set
   // the readyState attribute to OPEN and queue a task to fire a simple event
   // named open at the EventSource object.
 
-  mReadyState = OPEN;
+  SetReadyState(OPEN);
 
-  nsresult rv = CheckInnerWindowCorrectness();
+  nsresult rv = mEventSource->CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
-
-  RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
-
-  // it doesn't bubble, and it isn't cancelable
-  event->InitEvent(NS_LITERAL_STRING("open"), false, false);
-  event->SetTrusted(true);
-
-  rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+  rv = mEventSource->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open"));
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch the open event!!!");
+    NS_WARNING("Failed to dispatch the error event!!!");
     return;
   }
 }
 
 nsresult
-EventSource::ResetConnection()
+EventSourceImpl::ResetConnection()
 {
+  AssertIsOnMainThread();
   if (mHttpChannel) {
     mHttpChannel->Cancel(NS_ERROR_ABORT);
-  }
-
-  if (mUnicodeDecoder) {
-    mUnicodeDecoder->Reset();
+    mHttpChannel = nullptr;
   }
-  mLastConvertionResult = NS_OK;
-
-  mHttpChannel = nullptr;
-  mStatus = PARSE_STATE_OFF;
-
-  mReadyState = CONNECTING;
-
   return NS_OK;
 }
 
 void
-EventSource::ReestablishConnection()
+EventSourceImpl::ResetDecoder()
+{
+  AssertIsOnTargetThread();
+  if (mUnicodeDecoder) {
+    mUnicodeDecoder->Reset();
+  }
+  mStatus = PARSE_STATE_OFF;
+  mLastConvertionResult = NS_OK;
+  ClearFields();
+}
+
+class CallRestartConnection final : public WorkerMainThreadRunnable
 {
-  if (mReadyState == CLOSED) {
+public:
+  explicit CallRestartConnection(EventSourceImpl* aEventSourceImpl)
+    : WorkerMainThreadRunnable(
+        aEventSourceImpl->mWorkerPrivate,
+        NS_LITERAL_CSTRING("EventSource :: RestartConnection"))
+    , mImpl(aEventSourceImpl)
+  {
+    mImpl->mWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+  bool MainThreadRun() override
+  {
+    mImpl->RestartConnection();
+    return true;
+  }
+
+protected:
+  // Raw pointer because this runnable is sync.
+  EventSourceImpl* mImpl;
+};
+
+nsresult
+EventSourceImpl::RestartConnection()
+{
+  AssertIsOnMainThread();
+  nsresult rv = ResetConnection();
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = SetReconnectionTimeout();
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
+}
+
+void
+EventSourceImpl::ReestablishConnection()
+{
+  AssertIsOnTargetThread();
+  if (IsClosed()) {
     return;
   }
 
-  nsresult rv = ResetConnection();
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to reset the connection!!!");
-    return;
+  nsresult rv;
+  if (mIsMainThread) {
+    rv = RestartConnection();
+  } else {
+    RefPtr<CallRestartConnection> runnable = new CallRestartConnection(this);
+    ErrorResult result;
+    runnable->Dispatch(Terminating, result);
+    MOZ_ASSERT(!result.Failed());
+    rv = result.StealNSResult();
   }
-
-  rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
-  RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
-
-  // it doesn't bubble, and it isn't cancelable
-  event->InitEvent(NS_LITERAL_STRING("error"), false, false);
-  event->SetTrusted(true);
-
-  rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+  rv = mEventSource->CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch the error event!!!");
     return;
   }
 
-  rv = SetReconnectionTimeout();
+  SetReadyState(CONNECTING);
+  ResetDecoder();
+  rv = mEventSource->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
   if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to set the timeout for reestablishing the connection!!!");
+    NS_WARNING("Failed to dispatch the error event!!!");
     return;
   }
 }
 
 nsresult
-EventSource::SetReconnectionTimeout()
+EventSourceImpl::SetReconnectionTimeout()
 {
-  if (mReadyState == CLOSED) {
+  AssertIsOnMainThread();
+  if (IsClosed()) {
     return NS_ERROR_ABORT;
   }
 
   // the timer will be used whenever the requests are going finished.
   if (!mTimer) {
     mTimer = do_CreateInstance("@mozilla.org/timer;1");
     NS_ENSURE_STATE(mTimer);
   }
@@ -813,21 +1213,22 @@ EventSource::SetReconnectionTimeout()
                                              mReconnectionTime,
                                              nsITimer::TYPE_ONE_SHOT);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-EventSource::PrintErrorOnConsole(const char *aBundleURI,
-                                 const char16_t *aError,
-                                 const char16_t **aFormatStrings,
-                                 uint32_t aFormatStringsLen)
+EventSourceImpl::PrintErrorOnConsole(const char* aBundleURI,
+                                     const char16_t* aError,
+                                     const char16_t** aFormatStrings,
+                                     uint32_t aFormatStringsLen)
 {
+  AssertIsOnMainThread();
   nsCOMPtr<nsIStringBundleService> bundleService =
     mozilla::services::GetStringBundleService();
   NS_ENSURE_STATE(bundleService);
 
   nsCOMPtr<nsIStringBundle> strBundle;
   nsresult rv =
     bundleService->CreateBundle(aBundleURI, getter_AddRefs(strBundle));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -862,159 +1263,161 @@ EventSource::PrintErrorOnConsole(const c
   // print the error message directly to the JS console
   rv = console->LogMessage(errObj);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-EventSource::ConsoleError()
+EventSourceImpl::ConsoleError()
 {
+  AssertIsOnMainThread();
   nsAutoCString targetSpec;
   nsresult rv = mSrc->GetSpec(targetSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertUTF8toUTF16 specUTF16(targetSpec);
-  const char16_t *formatStrings[] = { specUTF16.get() };
+  const char16_t* formatStrings[] = { specUTF16.get() };
 
-  if (mReadyState == CONNECTING) {
+  if (ReadyState() == CONNECTING) {
     rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
                              u"connectionFailure",
                              formatStrings, ArrayLength(formatStrings));
   } else {
     rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
                              u"netInterrupt",
                              formatStrings, ArrayLength(formatStrings));
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
-nsresult
-EventSource::DispatchFailConnection()
+void
+EventSourceImpl::DispatchFailConnection()
 {
-
-  return NS_DispatchToMainThread(NewRunnableMethod(this, &EventSource::FailConnection));
-}
-
-void
-EventSource::FailConnection()
-{
-  if (mReadyState == CLOSED) {
+  AssertIsOnMainThread();
+  if (IsClosed()) {
     return;
   }
-
   nsresult rv = ConsoleError();
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to print to the console error");
   }
-
-  // When a user agent is to fail the connection, the user agent must set the
-  // readyState attribute to CLOSED and queue a task to fire a simple event
-  // named error at the EventSource  object.
+  rv = Dispatch(NewRunnableMethod(this, &EventSourceImpl::FailConnection),
+                NS_DISPATCH_NORMAL);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+}
 
-  Close(); // it sets mReadyState to CLOSED
-
-  rv = CheckInnerWindowCorrectness();
-  if (NS_FAILED(rv)) {
+void
+EventSourceImpl::FailConnection()
+{
+  AssertIsOnTargetThread();
+  if (IsClosed()) {
     return;
   }
-
-  RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
-
-  // it doesn't bubble, and it isn't cancelable
-  event->InitEvent(NS_LITERAL_STRING("error"), false, false);
-  event->SetTrusted(true);
-
-  rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to dispatch the error event!!!");
-    return;
+  // Must change state to closed before firing event to content.
+  SetReadyState(CLOSED);
+  // When a user agent is to fail the connection, the user agent must set the
+  // readyState attribute to CLOSED and queue a task to fire a simple event
+  // named error at the EventSource object.
+  nsresult rv = mEventSource->CheckInnerWindowCorrectness();
+  if (NS_SUCCEEDED(rv)) {
+    rv = mEventSource->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
+    if (NS_FAILED(rv)) {
+      NS_WARNING("Failed to dispatch the error event!!!");
+    }
   }
+  // Call CloseInternal in the end of function because it may release
+  // EventSourceImpl.
+  CloseInternal();
 }
 
 // static
 void
-EventSource::TimerCallback(nsITimer* aTimer, void* aClosure)
+EventSourceImpl::TimerCallback(nsITimer* aTimer, void* aClosure)
 {
-  RefPtr<EventSource> thisObject = static_cast<EventSource*>(aClosure);
+  AssertIsOnMainThread();
+  RefPtr<EventSourceImpl> thisObject = static_cast<EventSourceImpl*>(aClosure);
 
-  if (thisObject->mReadyState == CLOSED) {
+  if (thisObject->IsClosed()) {
     return;
   }
 
   NS_PRECONDITION(!thisObject->mHttpChannel,
                   "the channel hasn't been cancelled!!");
 
-  if (!thisObject->mFrozen) {
+  if (!thisObject->IsFrozen()) {
     nsresult rv = thisObject->InitChannelAndRequestEventSource();
     if (NS_FAILED(rv)) {
       NS_WARNING("thisObject->InitChannelAndRequestEventSource() failed");
       return;
     }
   }
 }
 
 nsresult
-EventSource::Thaw()
+EventSourceImpl::Thaw()
 {
-  if (mReadyState == CLOSED || !mFrozen) {
+  AssertIsOnMainThread();
+  if (IsClosed() || !IsFrozen()) {
     return NS_OK;
   }
 
-  NS_ASSERTION(!mHttpChannel, "the connection hasn't been closed!!!");
+  MOZ_ASSERT(!mHttpChannel, "the connection hasn't been closed!!!");
 
-  mFrozen = false;
+  SetFrozen(false);
   nsresult rv;
   if (!mGoingToDispatchAllMessages && mMessagesToDispatch.GetSize() > 0) {
     nsCOMPtr<nsIRunnable> event =
-      NewRunnableMethod(this, &EventSource::DispatchAllMessageEvents);
+      NewRunnableMethod(this, &EventSourceImpl::DispatchAllMessageEvents);
     NS_ENSURE_STATE(event);
 
     mGoingToDispatchAllMessages = true;
 
-    rv = NS_DispatchToMainThread(event);
+    rv = Dispatch(event.forget(), NS_DISPATCH_NORMAL);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = InitChannelAndRequestEventSource();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-EventSource::Freeze()
+EventSourceImpl::Freeze()
 {
-  if (mReadyState == CLOSED || mFrozen) {
+  AssertIsOnMainThread();
+  if (IsClosed() || IsFrozen()) {
     return NS_OK;
   }
 
-  NS_ASSERTION(!mHttpChannel, "the connection hasn't been closed!!!");
-  mFrozen = true;
+  MOZ_ASSERT(!mHttpChannel, "the connection hasn't been closed!!!");
+  SetFrozen(true);
   return NS_OK;
 }
 
 nsresult
-EventSource::DispatchCurrentMessageEvent()
+EventSourceImpl::DispatchCurrentMessageEvent()
 {
+  AssertIsOnTargetThread();
   nsAutoPtr<Message> message(new Message());
   *message = mCurrentMessage;
 
   ClearFields();
 
   if (message->mData.IsEmpty()) {
     return NS_OK;
   }
 
   // removes the trailing LF from mData
-  NS_ASSERTION(message->mData.CharAt(message->mData.Length() - 1) == LF_CHAR,
-               "Invalid trailing character! LF was expected instead.");
+  MOZ_ASSERT(message->mData.CharAt(message->mData.Length() - 1) == LF_CHAR,
+             "Invalid trailing character! LF was expected instead.");
   message->mData.SetLength(message->mData.Length() - 1);
 
   if (message->mEventName.IsEmpty()) {
     message->mEventName.AssignLiteral("message");
   }
 
   if (message->mLastEventID.IsEmpty() && !mLastEventID.IsEmpty()) {
     message->mLastEventID.Assign(mLastEventID);
@@ -1023,44 +1426,52 @@ EventSource::DispatchCurrentMessageEvent
   size_t sizeBefore = mMessagesToDispatch.GetSize();
   mMessagesToDispatch.Push(message.forget());
   NS_ENSURE_TRUE(mMessagesToDispatch.GetSize() == sizeBefore + 1,
                  NS_ERROR_OUT_OF_MEMORY);
 
 
   if (!mGoingToDispatchAllMessages) {
     nsCOMPtr<nsIRunnable> event =
-      NewRunnableMethod(this, &EventSource::DispatchAllMessageEvents);
+      NewRunnableMethod(this, &EventSourceImpl::DispatchAllMessageEvents);
     NS_ENSURE_STATE(event);
 
     mGoingToDispatchAllMessages = true;
 
-    return NS_DispatchToMainThread(event);
+    return Dispatch(event.forget(), NS_DISPATCH_NORMAL);
   }
 
   return NS_OK;
 }
 
 void
-EventSource::DispatchAllMessageEvents()
+EventSourceImpl::DispatchAllMessageEvents()
 {
-  if (mReadyState == CLOSED || mFrozen) {
+  AssertIsOnTargetThread();
+  if (IsClosed() || IsFrozen()) {
     return;
   }
 
   mGoingToDispatchAllMessages = false;
 
-  nsresult rv = CheckInnerWindowCorrectness();
+  nsresult rv = mEventSource->CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
   AutoJSAPI jsapi;
-  if (NS_WARN_IF(!jsapi.Init(GetOwner()))) {
-    return;
+  if (mIsMainThread) {
+    if (NS_WARN_IF(!jsapi.Init(mEventSource->GetOwner()))) {
+      return;
+    }
+  } else {
+    MOZ_ASSERT(mWorkerPrivate);
+    if (NS_WARN_IF(!jsapi.Init(mWorkerPrivate->GlobalScope()))) {
+      return;
+    }
   }
   JSContext* cx = jsapi.cx();
 
   while (mMessagesToDispatch.GetSize() > 0) {
     nsAutoPtr<Message>
       message(static_cast<Message*>(mMessagesToDispatch.PopFront()));
 
     // Now we can turn our string into a jsval
@@ -1073,62 +1484,67 @@ EventSource::DispatchAllMessageEvents()
       NS_ENSURE_TRUE_VOID(jsString);
 
       jsData.setString(jsString);
     }
 
     // create an event that uses the MessageEvent interface,
     // which does not bubble, is not cancelable, and has no default action
 
-    RefPtr<MessageEvent> event = new MessageEvent(this, nullptr, nullptr);
+    RefPtr<MessageEvent> event = new MessageEvent(mEventSource, nullptr,
+                                                  nullptr);
 
     event->InitMessageEvent(nullptr, message->mEventName, false, false, jsData,
                             mOrigin, message->mLastEventID, nullptr,
                             Sequence<OwningNonNull<MessagePort>>());
     event->SetTrusted(true);
 
-    rv = DispatchDOMEvent(nullptr, static_cast<Event*>(event), nullptr,
-                          nullptr);
+    rv = mEventSource->DispatchDOMEvent(nullptr, static_cast<Event*>(event),
+                                        nullptr, nullptr);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to dispatch the message event!!!");
       return;
     }
 
     mLastEventID.Assign(message->mLastEventID);
+    if (IsClosed() || IsFrozen()) {
+      return;
+    }
   }
 }
 
 nsresult
-EventSource::ClearFields()
+EventSourceImpl::ClearFields()
 {
+  AssertIsOnTargetThread();
   // mLastEventID and mReconnectionTime must be cached
-
   mCurrentMessage.mEventName.Truncate();
   mCurrentMessage.mLastEventID.Truncate();
   mCurrentMessage.mData.Truncate();
 
   mLastFieldName.Truncate();
   mLastFieldValue.Truncate();
 
   return NS_OK;
 }
 
 nsresult
-EventSource::SetFieldAndClear()
+EventSourceImpl::SetFieldAndClear()
 {
+  AssertIsOnTargetThread();
   if (mLastFieldName.IsEmpty()) {
     mLastFieldValue.Truncate();
     return NS_OK;
   }
 
   char16_t first_char;
   first_char = mLastFieldName.CharAt(0);
 
-  switch (first_char)  // with no case folding performed
-  {
+  // with no case folding performed
+  switch (first_char) {
     case char16_t('d'):
       if (mLastFieldName.EqualsLiteral("data")) {
         // If the field name is "data" append the field value to the data
         // buffer, then append a single U+000A LINE FEED (LF) character
         // to the data buffer.
         mCurrentMessage.mData.Append(mLastFieldValue);
         mCurrentMessage.mData.Append(LF_CHAR);
       }
@@ -1143,17 +1559,17 @@ EventSource::SetFieldAndClear()
     case char16_t('i'):
       if (mLastFieldName.EqualsLiteral("id")) {
         mCurrentMessage.mLastEventID.Assign(mLastFieldValue);
       }
       break;
 
     case char16_t('r'):
       if (mLastFieldName.EqualsLiteral("retry")) {
-        uint32_t newValue=0;
+        uint32_t newValue = 0;
         uint32_t i = 0;  // we must ensure that there are only digits
         bool assign = true;
         for (i = 0; i < mLastFieldValue.Length(); ++i) {
           if (mLastFieldValue.CharAt(i) < (char16_t)'0' ||
               mLastFieldValue.CharAt(i) > (char16_t)'9') {
             assign = false;
             break;
           }
@@ -1178,47 +1594,49 @@ EventSource::SetFieldAndClear()
 
   mLastFieldName.Truncate();
   mLastFieldValue.Truncate();
 
   return NS_OK;
 }
 
 nsresult
-EventSource::CheckHealthOfRequestCallback(nsIRequest *aRequestCallback)
+EventSourceImpl::CheckHealthOfRequestCallback(nsIRequest* aRequestCallback)
 {
+  // This function could be run on target thread if http channel support
+  // nsIThreadRetargetableRequest. otherwise, it's run on main thread.
+
   // check if we have been closed or if the request has been canceled
   // or if we have been frozen
-  if (mReadyState == CLOSED || !mHttpChannel ||
-      mFrozen || mErrorLoadOnRedirect) {
+  if (IsClosed() || IsFrozen() || !mHttpChannel) {
     return NS_ERROR_ABORT;
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequestCallback);
   NS_ENSURE_STATE(httpChannel);
 
   if (httpChannel != mHttpChannel) {
     NS_WARNING("wrong channel from request callback");
     return NS_ERROR_ABORT;
   }
 
   return NS_OK;
 }
 
 nsresult
-EventSource::ParseCharacter(char16_t aChr)
+EventSourceImpl::ParseCharacter(char16_t aChr)
 {
+  AssertIsOnTargetThread();
   nsresult rv;
 
-  if (mReadyState == CLOSED) {
+  if (IsClosed()) {
     return NS_ERROR_ABORT;
   }
 
-  switch (mStatus)
-  {
+  switch (mStatus) {
     case PARSE_STATE_OFF:
       NS_ERROR("Invalid state");
       return NS_ERROR_FAILURE;
       break;
 
     case PARSE_STATE_BEGIN_OF_STREAM:
       if (aChr == BOM_CHAR) {
         mStatus = PARSE_STATE_BOM_WAS_READ;  // ignore it
@@ -1347,10 +1765,335 @@ EventSource::ParseCharacter(char16_t aCh
       }
 
       break;
   }
 
   return NS_OK;
 }
 
+void
+EventSourceImpl::AddRefObject()
+{
+  AddRef();
+}
+
+void
+EventSourceImpl::ReleaseObject()
+{
+  Release();
+}
+
+namespace {
+class EventSourceWorkerHolder final : public WorkerHolder
+{
+public:
+  explicit EventSourceWorkerHolder(EventSourceImpl* aEventSourceImpl)
+    : mEventSourceImpl(aEventSourceImpl)
+  {
+  }
+
+  bool Notify(Status aStatus) override
+  {
+    MOZ_ASSERT(aStatus > workers::Running);
+    if (aStatus >= Canceling) {
+      mEventSourceImpl->Close();
+    }
+    return true;
+  }
+
+private:
+  // Raw pointer because the EventSourceImpl object keeps alive the holder.
+  EventSourceImpl* mEventSourceImpl;
+};
+
+class WorkerRunnableDispatcher final : public WorkerRunnable
+{
+  RefPtr<EventSourceImpl> mEventSourceImpl;
+
+public:
+  WorkerRunnableDispatcher(EventSourceImpl* aImpl,
+                           WorkerPrivate* aWorkerPrivate,
+                           already_AddRefed<nsIRunnable> aEvent)
+    : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
+    , mEventSourceImpl(aImpl)
+    , mEvent(Move(aEvent))
+  {
+  }
+
+  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+  {
+    aWorkerPrivate->AssertIsOnWorkerThread();
+    return !NS_FAILED(mEvent->Run());
+  }
+
+  void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+               bool aRunResult) override
+  {
+  }
+
+  bool PreDispatch(WorkerPrivate* aWorkerPrivate) override
+  {
+    // We don't call WorkerRunnable::PreDispatch because it would assert the
+    // wrong thing about which thread we're on.  We're on whichever thread the
+    // channel implementation is running on (probably the main thread or
+    // transport thread).
+    return true;
+  }
+
+  void PostDispatch(WorkerPrivate* aWorkerPrivate,
+                    bool aDispatchResult) override
+  {
+    // We don't call WorkerRunnable::PostDispatch because it would assert the
+    // wrong thing about which thread we're on.  We're on whichever thread the
+    // channel implementation is running on (probably the main thread or
+    // transport thread).
+  }
+
+private:
+  nsCOMPtr<nsIRunnable> mEvent;
+};
+
+} // namespace
+
+bool EventSourceImpl::RegisterWorkerHolder()
+{
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate->AssertIsOnWorkerThread();
+  MOZ_ASSERT(!mWorkerHolder);
+  mWorkerHolder = new EventSourceWorkerHolder(this);
+  if (NS_WARN_IF(!mWorkerHolder->HoldWorker(mWorkerPrivate, Canceling))) {
+    mWorkerHolder = nullptr;
+    return false;
+  }
+  return true;
+}
+
+void EventSourceImpl::UnregisterWorkerHolder()
+{
+  // RegisterWorkerHolder fail will destroy EventSourceImpl and invoke
+  // UnregisterWorkerHolder.
+  MOZ_ASSERT(IsClosed());
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate->AssertIsOnWorkerThread();
+  // The DTOR of this WorkerHolder will release the worker for us.
+  mWorkerHolder = nullptr;
+  mWorkerPrivate = nullptr;
+}
+
+//-----------------------------------------------------------------------------
+// EventSourceImpl::nsIEventTarget
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+EventSourceImpl::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
+{
+  nsCOMPtr<nsIRunnable> event(aEvent);
+  return Dispatch(event.forget(), aFlags);
+}
+
+NS_IMETHODIMP
+EventSourceImpl::Dispatch(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags)
+{
+  nsCOMPtr<nsIRunnable> event_ref(aEvent);
+  if (mIsMainThread) {
+    return NS_DispatchToMainThread(event_ref.forget());
+  }
+  MOZ_ASSERT(mWorkerPrivate);
+  // If the target is a worker, we have to use a custom WorkerRunnableDispatcher
+  // runnable.
+  RefPtr<WorkerRunnableDispatcher> event =
+    new WorkerRunnableDispatcher(this, mWorkerPrivate, event_ref.forget());
+
+  if (!event->Dispatch()) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+
+NS_IMETHODIMP
+EventSourceImpl::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
+                                 uint32_t aDelayMs)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+//-----------------------------------------------------------------------------
+// EventSourceImpl::nsIThreadRetargetableStreamListener
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+EventSourceImpl::CheckListenerChain()
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread!");
+  return NS_OK;
+}
+////////////////////////////////////////////////////////////////////////////////
+// EventSource
+////////////////////////////////////////////////////////////////////////////////
+
+EventSource::EventSource(nsPIDOMWindowInner* aOwnerWindow,
+                         bool aWithCredentials)
+  : DOMEventTargetHelper(aOwnerWindow)
+  , mWithCredentials(aWithCredentials)
+  , mIsMainThread(true)
+  , mKeepingAlive(false)
+{
+  mImpl = new EventSourceImpl(this);
+}
+
+EventSource::~EventSource()
+{
+}
+
+nsresult
+EventSource::CreateAndDispatchSimpleEvent(const nsAString& aName)
+{
+  RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
+  // it doesn't bubble, and it isn't cancelable
+  event->InitEvent(aName, false, false);
+  event->SetTrusted(true);
+  return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+}
+
+/* static */ already_AddRefed<EventSource>
+EventSource::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
+                         const EventSourceInit& aEventSourceInitDict,
+                         ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
+    do_QueryInterface(aGlobal.GetAsSupports());
+
+  MOZ_ASSERT(!NS_IsMainThread() ||
+             (ownerWindow && ownerWindow->IsInnerWindow()));
+
+  RefPtr<EventSource> eventSource =
+    new EventSource(ownerWindow, aEventSourceInitDict.mWithCredentials);
+  RefPtr<EventSourceImpl> eventSourceImp = eventSource->mImpl;
+
+  if (NS_IsMainThread()) {
+    // Get principal from document and init EventSourceImpl
+    nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
+      do_QueryInterface(aGlobal.GetAsSupports());
+    if (!scriptPrincipal) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return nullptr;
+    }
+    nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
+    if (!principal) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return nullptr;
+    }
+    eventSourceImp->Init(principal, aURL, aRv);
+  } else {
+    // In workers we have to keep the worker alive using a WorkerHolder in order
+    // to dispatch messages correctly.
+    if (!eventSourceImp->RegisterWorkerHolder()) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return nullptr;
+    }
+    RefPtr<InitRunnable> runnable = new InitRunnable(eventSourceImp, aURL);
+    runnable->Dispatch(Terminating, aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
+    aRv = runnable->ErrorCode();
+  }
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+  return eventSource.forget();
+}
+
+// nsWrapperCache
+JSObject*
+EventSource::WrapObject(JSContext* aCx,
+                        JS::Handle<JSObject*> aGivenProto)
+{
+  return EventSourceBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+EventSource::Close()
+{
+  AssertIsOnTargetThread();
+  if (mImpl) {
+    mImpl->Close();
+  }
+}
+
+void
+EventSource::UpdateMustKeepAlive()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mImpl);
+  if (mKeepingAlive) {
+    return;
+  }
+  mKeepingAlive = true;
+  mImpl->AddRefObject();
+}
+
+void
+EventSource::UpdateDontKeepAlive()
+{
+  // Here we could not have mImpl.
+  MOZ_ASSERT(NS_IsMainThread() == mIsMainThread);
+  if (mKeepingAlive) {
+    MOZ_ASSERT(mImpl);
+    mKeepingAlive = false;
+    mImpl->mEventSource = nullptr;
+    mImpl->ReleaseObject();
+  }
+  mImpl = nullptr;
+}
+
+//-----------------------------------------------------------------------------
+// EventSource::nsISupports
+//-----------------------------------------------------------------------------
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(EventSource)
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(EventSource)
+  bool isBlack = tmp->IsBlack();
+  if (isBlack || tmp->mKeepingAlive) {
+    if (tmp->mListenerManager) {
+      tmp->mListenerManager->MarkForCC();
+    }
+    if (!isBlack && tmp->PreservingWrapper()) {
+      // This marks the wrapper black.
+      tmp->GetWrapper();
+    }
+    return true;
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(EventSource)
+  return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(EventSource)
+  return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(EventSource,
+                                               DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(EventSource,
+                                                  DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(EventSource,
+                                                DOMEventTargetHelper)
+  if (tmp->mImpl) {
+    tmp->mImpl->Close();
+    MOZ_ASSERT(!tmp->mImpl);
+  }
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(EventSource)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(EventSource, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(EventSource, DOMEventTargetHelper)
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/EventSource.h
+++ b/dom/base/EventSource.h
@@ -31,229 +31,89 @@ class nsPIDOMWindowInner;
 namespace mozilla {
 
 class ErrorResult;
 
 namespace dom {
 
 struct EventSourceInit;
 
+class EventSourceImpl;
+
 class EventSource final : public DOMEventTargetHelper
-                        , public nsIObserver
-                        , public nsIStreamListener
-                        , public nsIChannelEventSink
-                        , public nsIInterfaceRequestor
-                        , public nsSupportsWeakReference
 {
+  friend class EventSourceImpl;
 public:
-  explicit EventSource(nsPIDOMWindowInner* aOwnerWindow);
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(
     EventSource, DOMEventTargetHelper)
 
-  NS_DECL_NSIOBSERVER
-  NS_DECL_NSISTREAMLISTENER
-  NS_DECL_NSIREQUESTOBSERVER
-  NS_DECL_NSICHANNELEVENTSINK
-  NS_DECL_NSIINTERFACEREQUESTOR
+  // EventTarget
+  void DisconnectFromOwner() override
+  {
+    DOMEventTargetHelper::DisconnectFromOwner();
+    Close();
+  }
 
-  // nsWrapperCache
-  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+  JSObject* WrapObject(JSContext* aCx,
+                       JS::Handle<JSObject*> aGivenProto) override;
 
   // WebIDL
-  nsPIDOMWindowInner*
-  GetParentObject() const
-  {
-    return GetOwner();
-  }
   static already_AddRefed<EventSource>
   Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
-              const EventSourceInit& aEventSourceInitDict,
-              ErrorResult& aRv);
+              const EventSourceInit& aEventSourceInitDict, ErrorResult& aRv);
 
   void GetUrl(nsAString& aURL) const
   {
+    AssertIsOnTargetThread();
     aURL = mOriginalURL;
   }
+
   bool WithCredentials() const
   {
+    AssertIsOnTargetThread();
     return mWithCredentials;
   }
 
-  enum {
-    CONNECTING = 0U,
-    OPEN = 1U,
-    CLOSED = 2U
-  };
   uint16_t ReadyState() const
   {
+    AssertIsOnTargetThread();
     return mReadyState;
   }
 
   IMPL_EVENT_HANDLER(open)
   IMPL_EVENT_HANDLER(message)
   IMPL_EVENT_HANDLER(error)
+
   void Close();
 
-  virtual void DisconnectFromOwner() override;
-
-protected:
+private:
+  EventSource(nsPIDOMWindowInner* aOwnerWindow, bool aWithCredentials);
   virtual ~EventSource();
-
-  MOZ_IS_CLASS_INIT
-  nsresult Init(nsISupports* aOwner,
-                const nsAString& aURL,
-                bool aWithCredentials);
-
-  nsresult GetBaseURI(nsIURI **aBaseURI);
-
-  void SetupHttpChannel();
-  nsresult SetupReferrerPolicy();
-  nsresult InitChannelAndRequestEventSource();
-  nsresult ResetConnection();
-  nsresult DispatchFailConnection();
-  nsresult SetReconnectionTimeout();
-
-  void AnnounceConnection();
-  void DispatchAllMessageEvents();
-  void ReestablishConnection();
-  void FailConnection();
-
-  nsresult Thaw();
-  nsresult Freeze();
-
-  static void TimerCallback(nsITimer *aTimer, void *aClosure);
+  // prevent bad usage
+  EventSource(const EventSource& x) = delete;
+  EventSource& operator=(const EventSource& x) = delete;
 
-  nsresult PrintErrorOnConsole(const char       *aBundleURI,
-                               const char16_t  *aError,
-                               const char16_t **aFormatStrings,
-                               uint32_t          aFormatStringsLen);
-  nsresult ConsoleError();
-
-  static nsresult StreamReaderFunc(nsIInputStream *aInputStream,
-                                   void           *aClosure,
-                                   const char     *aFromRawSegment,
-                                   uint32_t        aToOffset,
-                                   uint32_t        aCount,
-                                   uint32_t       *aWriteCount);
-  nsresult SetFieldAndClear();
-  nsresult ClearFields();
-  nsresult ResetEvent();
-  nsresult DispatchCurrentMessageEvent();
-  nsresult ParseCharacter(char16_t aChr);
-  nsresult CheckHealthOfRequestCallback(nsIRequest *aRequestCallback);
-  nsresult OnRedirectVerifyCallback(nsresult result);
-
-  nsCOMPtr<nsIURI> mSrc;
-
-  nsString mLastEventID;
-  uint32_t mReconnectionTime;  // in ms
-
-  struct Message {
-    nsString mEventName;
-    nsString mLastEventID;
-    nsString mData;
-  };
-  nsDeque mMessagesToDispatch;
-  Message mCurrentMessage;
+  void AssertIsOnTargetThread() const
+  {
+    MOZ_ASSERT(NS_IsMainThread() == mIsMainThread);
+  }
 
-  /**
-   * A simple state machine used to manage the event-source's line buffer
-   *
-   * PARSE_STATE_OFF              -> PARSE_STATE_BEGIN_OF_STREAM
-   *
-   * PARSE_STATE_BEGIN_OF_STREAM  -> PARSE_STATE_BOM_WAS_READ |
-   *                                 PARSE_STATE_CR_CHAR |
-   *                                 PARSE_STATE_BEGIN_OF_LINE |
-   *                                 PARSE_STATE_COMMENT |
-   *                                 PARSE_STATE_FIELD_NAME
-   *
-   * PARSE_STATE_BOM_WAS_READ     -> PARSE_STATE_CR_CHAR |
-   *                                 PARSE_STATE_BEGIN_OF_LINE |
-   *                                 PARSE_STATE_COMMENT |
-   *                                 PARSE_STATE_FIELD_NAME
-   *
-   * PARSE_STATE_CR_CHAR -> PARSE_STATE_CR_CHAR |
-   *                        PARSE_STATE_COMMENT |
-   *                        PARSE_STATE_FIELD_NAME |
-   *                        PARSE_STATE_BEGIN_OF_LINE
-   *
-   * PARSE_STATE_COMMENT -> PARSE_STATE_CR_CHAR |
-   *                        PARSE_STATE_BEGIN_OF_LINE
-   *
-   * PARSE_STATE_FIELD_NAME   -> PARSE_STATE_CR_CHAR |
-   *                             PARSE_STATE_BEGIN_OF_LINE |
-   *                             PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE
-   *
-   * PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE  -> PARSE_STATE_FIELD_VALUE |
-   *                                           PARSE_STATE_CR_CHAR |
-   *                                           PARSE_STATE_BEGIN_OF_LINE
-   *
-   * PARSE_STATE_FIELD_VALUE      -> PARSE_STATE_CR_CHAR |
-   *                                 PARSE_STATE_BEGIN_OF_LINE
-   *
-   * PARSE_STATE_BEGIN_OF_LINE   -> PARSE_STATE_CR_CHAR |
-   *                                PARSE_STATE_COMMENT |
-   *                                PARSE_STATE_FIELD_NAME |
-   *                                PARSE_STATE_BEGIN_OF_LINE
-   *
-   * Whenever the parser find an empty line or the end-of-file
-   * it dispatches the stacked event.
-   *
-   */
-  enum ParserStatus {
-    PARSE_STATE_OFF,
-    PARSE_STATE_BEGIN_OF_STREAM,
-    PARSE_STATE_BOM_WAS_READ,
-    PARSE_STATE_CR_CHAR,
-    PARSE_STATE_COMMENT,
-    PARSE_STATE_FIELD_NAME,
-    PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE,
-    PARSE_STATE_FIELD_VALUE,
-    PARSE_STATE_BEGIN_OF_LINE
-  };
-  ParserStatus mStatus;
+  nsresult CreateAndDispatchSimpleEvent(const nsAString& aName);
 
-  bool mFrozen;
-  bool mErrorLoadOnRedirect;
-  bool mGoingToDispatchAllMessages;
-  bool mWithCredentials;
-  bool mWaitingForOnStopRequest;
-
-  // used while reading the input streams
-  nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
-  nsresult mLastConvertionResult;
-  nsString mLastFieldName;
-  nsString mLastFieldValue;
-
-  nsCOMPtr<nsILoadGroup> mLoadGroup;
-
-  nsCOMPtr<nsIHttpChannel> mHttpChannel;
-
-  nsCOMPtr<nsITimer> mTimer;
-
-  uint16_t mReadyState;
+  // Raw pointer because this EventSourceImpl is created, managed and destroyed
+  // by EventSource.
+  EventSourceImpl* mImpl;
   nsString mOriginalURL;
-
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-  nsString mOrigin;
+  uint16_t mReadyState;
+  bool mWithCredentials;
+  bool mIsMainThread;
+  // This is used to keep EventSourceImpl instance when there is a connection.
+  bool mKeepingAlive;
 
-  // Event Source owner information:
-  // - the script file name
-  // - source code line number and column number where the Event Source object
-  //   was constructed.
-  // - the ID of the inner window where the script lives. Note that this may not
-  //   be the same as the Event Source owner window.
-  // These attributes are used for error reporting.
-  nsString mScriptFile;
-  uint32_t mScriptLine;
-  uint32_t mScriptColumn;
-  uint64_t mInnerWindowID;
-
-private:
-  EventSource(const EventSource& x);   // prevent bad usage
-  EventSource& operator=(const EventSource& x);
+  void UpdateMustKeepAlive();
+  void UpdateDontKeepAlive();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_EventSource_h
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -2241,16 +2241,17 @@ public:
       mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY,
                                       EmptyCString());
     }
 
     return true;
   }
 
 private:
+  // RawPointer because this proxy keeps alive the holder.
   WebSocketImpl* mWebSocketImpl;
 };
 
 } // namespace
 
 void
 WebSocketImpl::AddRefObject()
 {
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -3663,14 +3663,21 @@ nsFrameLoader::PopulateUserContextIdFrom
 
 NS_IMETHODIMP
 nsFrameLoader::GetIsDead(bool* aIsDead)
 {
   *aIsDead = mDestroyCalled;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsFrameLoader::GetIsFreshProcess(bool* aIsFreshProcess)
+{
+  *aIsFreshProcess = mFreshProcess;
+  return NS_OK;
+}
+
 nsIMessageSender*
 nsFrameLoader::GetProcessMessageManager() const
 {
   return mRemoteBrowser ? mRemoteBrowser->Manager()->GetMessageManager()
                         : nullptr;
 };
--- a/dom/base/nsIFrameLoader.idl
+++ b/dom/base/nsIFrameLoader.idl
@@ -263,16 +263,22 @@ interface nsIFrameLoader : nsISupports
    * across root docshells.
    */
   readonly attribute nsIGroupedSHistory groupedSHistory;
 
   /**
    * Is `true` if the frameloader is dead (destroy has been called on it)
    */
   [infallible] readonly attribute boolean isDead;
+
+  /**
+   * Is `true` if the <xul:browser> which created this frameloader had the
+   * freshProcess attribute set when it was created.
+   */
+  [infallible] readonly attribute boolean isFreshProcess;
 };
 
 %{C++
 class nsFrameLoader;
 %}
 
 native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
 
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -7692,18 +7692,17 @@ HTMLInputElement::HasPatternMismatch() c
   nsIDocument* doc = OwnerDoc();
 
   return !nsContentUtils::IsPatternMatching(value, pattern, doc);
 }
 
 bool
 HTMLInputElement::IsRangeOverflow() const
 {
-  // TODO: this is temporary until bug 888331 is fixed.
-  if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_DATETIME_LOCAL) {
+  if (!DoesMinMaxApply()) {
     return false;
   }
 
   Decimal maximum = GetMaximum();
   if (maximum.isNaN()) {
     return false;
   }
 
@@ -7713,18 +7712,17 @@ HTMLInputElement::IsRangeOverflow() cons
   }
 
   return value > maximum;
 }
 
 bool
 HTMLInputElement::IsRangeUnderflow() const
 {
-  // TODO: this is temporary until bug 888331 is fixed.
-  if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_DATETIME_LOCAL) {
+  if (!DoesMinMaxApply()) {
     return false;
   }
 
   Decimal minimum = GetMinimum();
   if (minimum.isNaN()) {
     return false;
   }
 
@@ -8718,18 +8716,17 @@ HTMLInputElement::UpdateHasRange()
 {
   /*
    * There is a range if min/max applies for the type and if the element
    * currently have a valid min or max.
    */
 
   mHasRange = false;
 
-  // TODO: this is temporary until bug 888331 is fixed.
-  if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_DATETIME_LOCAL) {
+  if (!DoesMinMaxApply()) {
     return;
   }
 
   Decimal minimum = GetMinimum();
   if (!minimum.isNaN()) {
     mHasRange = true;
     return;
   }
--- a/dom/html/test/forms/test_max_attribute.html
+++ b/dom/html/test/forms/test_max_attribute.html
@@ -26,18 +26,17 @@ var data = [
   { type: 'tel', apply: false },
   { type: 'url', apply: false },
   { type: 'email', apply: false },
   { type: 'password', apply: false },
   { type: 'date', apply: true },
   { type: 'month', apply: true },
   { type: 'week', apply: true },
   { type: 'time', apply: true },
-  // TODO: temporary set to false until bug 888331 is fixed.
-  { type: 'datetime-local', apply: false },
+  { type: 'datetime-local', apply: true },
   { type: 'number', apply: true },
   { type: 'range', apply: true },
   { type: 'color', apply: false },
   { type: 'checkbox', apply: false },
   { type: 'radio', apply: false },
   { type: 'file', apply: false },
   { type: 'submit', apply: false },
   { type: 'image', apply: false },
@@ -66,17 +65,18 @@ function checkValidity(aElement, aValidi
   aValidity = aApply ? aValidity : true;
 
   is(aElement.validity.valid, aValidity,
      "element validity should be " + aValidity);
   is(aElement.validity.rangeOverflow, !aValidity,
      "element overflow status should be " + !aValidity);
   var overflowMsg =
         (aElement.type == "date" || aElement.type == "time" ||
-         aElement.type == "month" || aElement.type == "week") ?
+         aElement.type == "month" || aElement.type == "week" ||
+         aElement.type == "datetime-local") ?
         ("Please select a value that is no later than " + aElement.max + ".") :
         ("Please select a value that is no more than " + aElement.max + ".");
   is(aElement.validationMessage,
      aValidity ? "" : overflowMsg, "Checking range overflow validation message");
 
   is(aElement.matches(":valid"), aElement.willValidate && aValidity,
      (aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply");
   is(aElement.matches(":invalid"), aElement.willValidate && !aValidity,
@@ -143,17 +143,17 @@ for (var test of data) {
       break;
     case 'month':
       input.max = '2016-12';
       break;
     case 'week':
       input.max = '2016-W39';
       break;
     case 'datetime-local':
-      // TODO: this is temporary until bug 888331 is fixed.
+      input.max = '2016-12-31T23:59:59';
       break;
     default:
       ok(false, 'please, add a case for this new type (' + input.type + ')');
   }
 
   checkValidity(input, true, apply, apply);
 
   switch (input.type) {
@@ -416,17 +416,54 @@ for (var test of data) {
       input.max = '';
       checkValidity(input, true, apply, false);
 
       input.max = 'foo';
       checkValidity(input, true, apply, false);
 
       break;
     case 'datetime-local':
-      // TODO: this is temporary until bug 888331 is fixed.
+      input.value = '2016-01-01T12:00';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2016-12-31T23:59:59';
+      checkValidity(input, true, apply, apply);
+
+      input.value = 'foo';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2016-12-31T23:59:59.123';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '2017-01-01T10:00';
+      checkValidity(input, false, apply, apply);
+
+      input.max = '2017-01-01T10:00';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2017-01-01T10:00:30';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '1000-01-01T12:00';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2100-01-01T12:00';
+      checkValidity(input, false, apply, apply);
+
+      input.max = '0050-12-31T23:59:59.999';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '0050-12-31T23:59:59';
+      checkValidity(input, true, apply, apply);
+
+      input.max = '';
+      checkValidity(input, true, apply, false);
+
+      input.max = 'foo';
+      checkValidity(input, true, apply, false);
 
       break;
   }
 
   // Cleaning up,
   input.removeAttribute('max');
   input.value = '';
 }
--- a/dom/html/test/forms/test_min_attribute.html
+++ b/dom/html/test/forms/test_min_attribute.html
@@ -26,18 +26,17 @@ var data = [
   { type: 'tel', apply: false },
   { type: 'url', apply: false },
   { type: 'email', apply: false },
   { type: 'password', apply: false },
   { type: 'date', apply: true },
   { type: 'month', apply: true },
   { type: 'week', apply: true },
   { type: 'time', apply: true },
-  // TODO: temporary set to false until bug 888331 is fixed.
-  { type: 'datetime-local', apply: false },
+  { type: 'datetime-local', apply: true },
   { type: 'number', apply: true },
   { type: 'range', apply: true },
   { type: 'color', apply: false },
   { type: 'checkbox', apply: false },
   { type: 'radio', apply: false },
   { type: 'file', apply: false },
   { type: 'submit', apply: false },
   { type: 'image', apply: false },
@@ -66,17 +65,18 @@ function checkValidity(aElement, aValidi
   aValidity = aApply ? aValidity : true;
 
   is(aElement.validity.valid, aValidity,
      "element validity should be " + aValidity);
   is(aElement.validity.rangeUnderflow, !aValidity,
      "element underflow status should be " + !aValidity);
   var underflowMsg =
         (aElement.type == "date" || aElement.type == "time" ||
-         aElement.type == "month" || aElement.type == "week") ?
+         aElement.type == "month" || aElement.type == "week" ||
+         aElement.type == "datetime-local") ?
         ("Please select a value that is no earlier than " + aElement.min + ".") :
         ("Please select a value that is no less than " + aElement.min + ".");
   is(aElement.validationMessage,
      aValidity ? "" : underflowMsg, "Checking range underflow validation message");
 
   is(aElement.matches(":valid"), aElement.willValidate && aValidity,
      (aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply");
   is(aElement.matches(":invalid"), aElement.willValidate && !aValidity,
@@ -141,20 +141,20 @@ for (var test of data) {
       // range is special, since setting min to 999 will make it invalid since
       // it's default maximum is 100, its value would be 999, and it would
       // suffer from overflow.
       break;
     case 'month':
       input.min = '2016-06';
       break;
     case 'week':
-      input.min = "2016-W39";
+      input.min = '2016-W39';
       break;
     case 'datetime-local':
-      // TODO: this is temporary until bug 888331 is fixed.
+      input.min = '2017-01-01T00:00';
       break;
     default:
       ok(false, 'please, add a case for this new type (' + input.type + ')');
   }
 
   // The element should still be valid and range should apply if it can.
   checkValidity(input, true, apply, apply);
 
@@ -415,17 +415,54 @@ for (var test of data) {
 
       input.min = '';
       checkValidity(input, true, apply, false);
 
       input.min = 'foo';
       checkValidity(input, true, apply, false);
       break;
     case 'datetime-local':
-      // TODO: this is temporary until bug 888331 is fixed.
+      input.value = '2017-12-31T23:59';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2017-01-01T00:00';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2017-01-01T00:00:00.123';
+      checkValidity(input, true, apply, apply);
+
+      input.value = 'foo';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2016-12-31T23:59';
+      checkValidity(input, false, apply, apply);
+
+      input.min = '2016-01-01T00:00';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2015-12-31T23:59';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '1000-01-01T00:00';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '10000-01-01T00:00';
+      checkValidity(input, true, apply, apply);
+
+      input.min = '0010-01-01T12:00';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '0010-01-01T10:00';
+      checkValidity(input, false, apply, apply);
+
+      input.min = '';
+      checkValidity(input, true, apply, false);
+
+      input.min = 'foo';
+      checkValidity(input, true, apply, false);
       break;
     default:
       ok(false, 'write tests for ' + input.type);
   }
 
   // Cleaning up,
   input.removeAttribute('min');
   input.value = '';
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -150,16 +150,17 @@ NS_IMPL_ISUPPORTS(TabChildSHistoryListen
                   nsISHistoryListener,
                   nsIPartialSHistoryListener,
                   nsISupportsWeakReference)
 
 static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
 
 typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
 static TabChildMap* sTabChildren;
+bool TabChild::sWasFreshProcess = false;
 
 TabChildBase::TabChildBase()
   : mTabChildGlobal(nullptr)
 {
   mozilla::HoldJSObjects(this);
 }
 
 TabChildBase::~TabChildBase()
@@ -3063,16 +3064,17 @@ TabChild::RecvThemeChanged(nsTArray<Look
     }
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvSetFreshProcess()
 {
+  MOZ_ASSERT(!sWasFreshProcess, "Can only be a fresh process once!");
   mIsFreshProcess = true;
   return IPC_OK();
 }
 
 mozilla::plugins::PPluginWidgetChild*
 TabChild::AllocPPluginWidgetChild()
 {
     return new mozilla::plugins::PluginWidgetChild();
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -655,25 +655,38 @@ public:
   void ForcePaint(uint64_t aLayerObserverEpoch);
 
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
   uintptr_t GetNativeWindowHandle() const { return mNativeWindowHandle; }
 #endif
 
   bool TakeIsFreshProcess()
   {
-    bool wasFreshProcess = mIsFreshProcess;
-    mIsFreshProcess = false;
-    return wasFreshProcess;
+    if (mIsFreshProcess) {
+      MOZ_ASSERT(!sWasFreshProcess,
+                 "At most one tabGroup may be a fresh process per process");
+      sWasFreshProcess = true;
+      mIsFreshProcess = false;
+      return true;
+    }
+    return false;
   }
 
   already_AddRefed<nsISHistory> GetRelatedSHistory();
 
   mozilla::dom::TabGroup* TabGroup();
 
+  // Returns `true` if this this process was created to load a docshell in a
+  // "Fresh Process". This value is initialized to `false`, and is set to `true`
+  // in RecvSetFreshProcess.
+  static bool GetWasFreshProcess()
+  {
+    return sWasFreshProcess;
+  }
+
 protected:
   virtual ~TabChild();
 
   virtual PRenderFrameChild* AllocPRenderFrameChild() override;
 
   virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) override;
 
   virtual mozilla::ipc::IPCResult RecvDestroy() override;
@@ -813,15 +826,17 @@ private:
   // The most recently seen layer observer epoch in RecvSetDocShellIsActive.
   uint64_t mLayerObserverEpoch;
 
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
   // The handle associated with the native window that contains this tab
   uintptr_t mNativeWindowHandle;
 #endif // defined(XP_WIN)
 
+  static bool sWasFreshProcess;
+
   DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_TabChild_h
--- a/dom/network/Connection.cpp
+++ b/dom/network/Connection.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Connection.h"
 #include "ConnectionMainThread.h"
 #include "ConnectionWorker.h"
 #include "nsIDOMClassInfo.h"
 #include "Constants.h"
+#include "mozilla/Telemetry.h"
 #include "WorkerPrivate.h"
 
 /**
  * We have to use macros here because our leak analysis tool things we are
  * leaking strings when we have |static const nsString|. Sad :(
  */
 #define CHANGE_EVENT_NAME NS_LITERAL_STRING("typechange")
 
@@ -34,16 +35,17 @@ NS_IMPL_RELEASE_INHERITED(dom::network::
 
 Connection::Connection(nsPIDOMWindowInner* aWindow)
   : DOMEventTargetHelper(aWindow)
   , mType(static_cast<ConnectionType>(kDefaultType))
   , mIsWifi(kDefaultIsWifi)
   , mDHCPGateway(kDefaultDHCPGateway)
   , mBeenShutDown(false)
 {
+  Telemetry::Accumulate(Telemetry::NETWORK_CONNECTION_COUNT, 1);
 }
 
 Connection::~Connection()
 {
   NS_ASSERT_OWNINGTHREAD(Connection);
   MOZ_ASSERT(mBeenShutDown);
 }
 
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -5,16 +5,18 @@ support-files =
   position.html
   test-console-api.html
   test_bug1004814.html
   worker_bug1004814.js
   geo_leak_test.html
   dummy.html
   test_largeAllocation.html
   test_largeAllocation.html^headers^
+  test_largeAllocation2.html
+  test_largeAllocation2.html^headers^
   !/dom/tests/mochitest/geolocation/network_geolocation.sjs
 
 [browser_allocateGigabyte.js]
 disabled = Does not reliably pass on 32-bit systems - bug 1314098
 skip-if = !e10s
 [browser_autofocus_background.js]
 [browser_autofocus_preference.js]
 [browser_bug396843.js]
--- a/dom/tests/browser/browser_largeAllocation.js
+++ b/dom/tests/browser/browser_largeAllocation.js
@@ -1,13 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const TEST_URI = "http://example.com/browser/dom/tests/browser/test_largeAllocation.html";
+const TEST_URI_2 = "http://example.com/browser/dom/tests/browser/test_largeAllocation2.html";
 
 function expectProcessCreated() {
   let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
   return new Promise(resolve => {
     let topic = "ipc:content-created";
     function observer() {
       os.removeObserver(observer, topic);
       ok(true, "Expect process created");
@@ -39,22 +40,25 @@ function getPID(aBrowser) {
 
 add_task(function*() {
   // I'm terrible and put this set of tests into a single file, so I need a longer timeout
   requestLongerTimeout(2);
 
   yield SpecialPowers.pushPrefEnv({
     set: [
       ["dom.largeAllocationHeader.enabled", true],
+      // Increase processCount.webLargeAllocation to avoid any races where
+      // processes aren't being cleaned up quickly enough.
+      ["dom.ipc.processCount.webLargeAllocation", 20]
     ]
   });
 
   // A toplevel tab should be able to navigate cross process!
   yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
-    ok(true, "Starting test 0");
+    info("Starting test 0");
     let pid1 = yield getPID(aBrowser);
 
     let epc = expectProcessCreated();
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.location = TEST_URI;
     });
 
     // Wait for the new process to be created
@@ -63,17 +67,17 @@ add_task(function*() {
     let pid2 = yield getPID(aBrowser);
 
     isnot(pid1, pid2, "The pids should be different between the initial load and the new load");
   });
 
   // When a Large-Allocation document is loaded in an iframe, the header should
   // be ignored, and the tab should stay in the current process.
   yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
-    ok(true, "Starting test 1");
+    info("Starting test 1");
     let pid1 = yield getPID(aBrowser);
 
     // Fail the test if we create a process
     let stopExpectNoProcess = expectNoProcess();
 
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.body.innerHTML = `<iframe src='${TEST_URI}'></iframe>`;
 
@@ -89,17 +93,17 @@ add_task(function*() {
 
     is(pid1, pid2, "The PID should not have changed");
 
     stopExpectNoProcess();
   });
 
   // If you have an opener cross process navigation shouldn't work
   yield BrowserTestUtils.withNewTab("http://example.com", function*(aBrowser) {
-    ok(true, "Starting test 2");
+    info("Starting test 2");
     let pid1 = yield getPID(aBrowser);
 
     // Fail the test if we create a process
     let stopExpectNoProcess = expectNoProcess();
 
     let loaded = ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.body.innerHTML = '<button>CLICK ME</button>';
 
@@ -123,17 +127,17 @@ add_task(function*() {
 
     is(pid1, pid2, "The PID should not have changed");
 
     stopExpectNoProcess();
   });
 
   // Load Large-Allocation twice with about:blank load in between
   yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
-    ok(true, "Starting test 3");
+    info("Starting test 3");
     let pid1 = yield getPID(aBrowser);
 
     let epc = expectProcessCreated();
 
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.location = TEST_URI;
     });
 
@@ -148,33 +152,35 @@ add_task(function*() {
     yield BrowserTestUtils.browserLoaded(aBrowser);
 
     yield ContentTask.spawn(aBrowser, null, () => content.document.location = "about:blank");
 
     yield BrowserTestUtils.browserLoaded(aBrowser);
 
     let pid3 = yield getPID(aBrowser);
 
-    is(pid2, pid3);
+    // We should have been kicked out of the large-allocation process by the
+    // load, meaning we're back in the first process.
+    is(pid1, pid3); // XXX: This may be flakey in multiple content process e10s?
 
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.location = TEST_URI;
     });
 
     yield epc;
 
     let pid4 = yield getPID(aBrowser);
 
     isnot(pid1, pid4);
     isnot(pid2, pid4);
   });
 
   // Load Large-Allocation then about:blank load, then back button press should load from bfcache.
   yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
-    ok(true, "Starting test 4");
+    info("Starting test 4");
     let pid1 = yield getPID(aBrowser);
 
     let epc = expectProcessCreated();
 
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.location = TEST_URI;
     });
 
@@ -192,23 +198,103 @@ add_task(function*() {
     yield ContentTask.spawn(aBrowser, null, () => {
       content.document.location = "about:blank";
     });
 
     yield BrowserTestUtils.browserLoaded(aBrowser);
 
     let pid3 = yield getPID(aBrowser);
 
-    is(pid2, pid3, "PIDs 2 and 3 should match");
+    // We should have been kicked out of the large-allocation process by the
+    // load, meaning we're back in the first process.
+    is(pid1, pid3, "PIDs 1 and 3 should match");
 
-    // Navigate back to the previous page, loading it from bfcache
+    stopExpectNoProcess();
+
+    epc = expectProcessCreated();
+
+    // Navigate back to the previous page. As the large alloation process was
+    // left, it won't be in bfcache and will have to be loaded fresh.
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.window.history.back();
     });
 
+    yield epc;
+
     let pid4 = yield getPID(aBrowser);
 
     isnot(pid1, pid4, "PID 4 shouldn't match PID 1");
-    is(pid2, pid4, "PID 4 should match PID 2");
+    isnot(pid2, pid4, "PID 4 shouldn't match PID 2");
+
+  });
+
+  // Two consecutive large-allocation loads should create two processes.
+  yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
+    info("Starting test 5");
+    let pid1 = yield getPID(aBrowser);
+
+    let ready = Promise.all([expectProcessCreated(),
+                             BrowserTestUtils.browserLoaded(aBrowser)]);
+
+    yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
+      content.document.location = TEST_URI;
+    });
+
+    yield ready;
+
+    let pid2 = yield getPID(aBrowser);
+
+    isnot(pid1, pid2, "PIDs 1 and 2 should not match");
+
+    let epc = expectProcessCreated();
+
+    yield ContentTask.spawn(aBrowser, TEST_URI_2, TEST_URI_2 => {
+      content.document.location = TEST_URI_2;
+    });
+
+    yield epc;
+
+    let pid3 = yield getPID(aBrowser);
+
+    isnot(pid1, pid3, "PIDs 1 and 3 should not match");
+    isnot(pid2, pid3, "PIDs 1 and 3 should not match");
+  });
+
+  // Opening a window from the large-allocation window should prevent the process switch.
+  yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
+    info("Starting test 6");
+    let pid1 = yield getPID(aBrowser);
+
+    let ready = Promise.all([expectProcessCreated(),
+                             BrowserTestUtils.browserLoaded(aBrowser)]);
+
+    yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
+      content.document.location = TEST_URI;
+    });
+
+    yield ready;
+
+    let pid2 = yield getPID(aBrowser);
+
+    isnot(pid1, pid2, "PIDs 1 and 2 should not match");
+
+    yield BrowserTestUtils.synthesizeMouse("a", 0, 0, {}, aBrowser);
+
+    let stopExpectNoProcess = expectNoProcess();
+
+    yield ContentTask.spawn(aBrowser, null, () => {
+      content.document.location = "about:blank";
+    });
+
+    yield BrowserTestUtils.browserLoaded(aBrowser);
+
+    let pid3 = yield getPID(aBrowser);
+
+    is(pid3, pid2, "PIDs 2 and 3 should match");
 
     stopExpectNoProcess();
+
+    is(gBrowser.tabs.length, 3, "There should be 3 tabs");
+
+    // Get rid of that other tab. It should always be the last one.
+    gBrowser.removeTab(gBrowser.tabs[2]);
   });
 });
--- a/dom/tests/browser/test_largeAllocation.html
+++ b/dom/tests/browser/test_largeAllocation.html
@@ -1,4 +1,9 @@
 <!doctype html>
 <html>
-    <body>Loaded in a new process!</body>
+  <script>
+    function onClick() {
+      window.open("about:blank");
+    }
+  </script>
+  <body><a onclick="onClick()">clicky</a>Loaded in a new process!</body>
 </html>
copy from dom/tests/browser/test_largeAllocation.html
copy to dom/tests/browser/test_largeAllocation2.html
new file mode 100644
--- /dev/null
+++ b/dom/tests/browser/test_largeAllocation2.html^headers^
@@ -0,0 +1,1 @@
+Large-Allocation: 0
\ No newline at end of file
--- a/dom/webidl/EventSource.webidl
+++ b/dom/webidl/EventSource.webidl
@@ -6,17 +6,18 @@
  * The origin of this IDL file is
  * https://html.spec.whatwg.org/multipage/comms.html#the-eventsource-interface
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
-[Constructor(USVString url, optional EventSourceInit eventSourceInitDict)]
+[Exposed=(Window,DedicatedWorker,SharedWorker),
+ Constructor(USVString url, optional EventSourceInit eventSourceInitDict)]
 interface EventSource : EventTarget {
   [Constant]
   readonly attribute DOMString url;
   [Constant]
   readonly attribute boolean withCredentials;
 
   // ready state
   const unsigned short CONNECTING = 0;
--- a/dom/workers/ServiceWorkerRegistrar.cpp
+++ b/dom/workers/ServiceWorkerRegistrar.cpp
@@ -105,42 +105,40 @@ ServiceWorkerRegistrar::~ServiceWorkerRe
 
 void
 ServiceWorkerRegistrar::GetRegistrations(
                                nsTArray<ServiceWorkerRegistrationData>& aValues)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aValues.IsEmpty());
 
+  MonitorAutoLock lock(mMonitor);
+
   // If we don't have the profile directory, profile is not started yet (and
   // probably we are in a utest).
   if (!mProfileDir) {
     return;
   }
 
   // We care just about the first execution because this can be blocked by
   // loading data from disk.
   static bool firstTime = true;
   TimeStamp startTime;
 
   if (firstTime) {
     startTime = TimeStamp::NowLoRes();
   }
 
-  {
-    MonitorAutoLock lock(mMonitor);
+  // Waiting for data loaded.
+  mMonitor.AssertCurrentThreadOwns();
+  while (!mDataLoaded) {
+    mMonitor.Wait();
+  }
 
-    // Waiting for data loaded.
-    mMonitor.AssertCurrentThreadOwns();
-    while (!mDataLoaded) {
-      mMonitor.Wait();
-    }
-
-    aValues.AppendElements(mData);
-  }
+  aValues.AppendElements(mData);
 
   if (firstTime) {
     firstTime = false;
     Telemetry::AccumulateTimeDelta(
       Telemetry::SERVICE_WORKER_REGISTRATION_LOADING,
       startTime);
   }
 }
@@ -269,25 +267,32 @@ ServiceWorkerRegistrar::LoadData()
 }
 
 nsresult
 ServiceWorkerRegistrar::ReadData()
 {
   // We cannot assert about the correct thread because normally this method
   // runs on a IO thread, but in gTests we call it from the main-thread.
 
-  MOZ_ASSERT(mProfileDir);
+  nsCOMPtr<nsIFile> file;
+
+  {
+    MonitorAutoLock lock(mMonitor);
 
-  nsCOMPtr<nsIFile> file;
-  nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+    if (!mProfileDir) {
+      return NS_ERROR_FAILURE;
+    }
+
+    nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
-  rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
+  nsresult rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   bool exists;
   rv = file->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -562,30 +567,33 @@ ServiceWorkerRegistrar::ReadData()
 }
 
 void
 ServiceWorkerRegistrar::DeleteData()
 {
   // We cannot assert about the correct thread because normally this method
   // runs on a IO thread, but in gTests we call it from the main-thread.
 
-  MOZ_ASSERT(mProfileDir);
+  nsCOMPtr<nsIFile> file;
 
   {
     MonitorAutoLock lock(mMonitor);
     mData.Clear();
+
+    if (!mProfileDir) {
+      return;
+    }
+
+    nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
   }
 
-  nsCOMPtr<nsIFile> file;
-  nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
-
-  rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
+  nsresult rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   rv = file->Remove(false);
   if (rv == NS_ERROR_FILE_NOT_FOUND) {
     return;
   }
@@ -724,25 +732,32 @@ ServiceWorkerRegistrar::IsSupportedVersi
 }
 
 nsresult
 ServiceWorkerRegistrar::WriteData()
 {
   // We cannot assert about the correct thread because normally this method
   // runs on a IO thread, but in gTests we call it from the main-thread.
 
-  MOZ_ASSERT(mProfileDir);
+  nsCOMPtr<nsIFile> file;
+
+  {
+    MonitorAutoLock lock(mMonitor);
 
-  nsCOMPtr<nsIFile> file;
-  nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+    if (!mProfileDir) {
+      return NS_ERROR_FAILURE;
+    }
+
+    nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
-  rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
+  nsresult rv = file->Append(NS_LITERAL_STRING(SERVICEWORKERREGISTRAR_FILE));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // We need a lock to take a snapshot of the data.
   nsTArray<ServiceWorkerRegistrationData> data;
   {
     MonitorAutoLock lock(mMonitor);
@@ -830,17 +845,19 @@ ServiceWorkerRegistrar::WriteData()
 
   return NS_OK;
 }
 
 void
 ServiceWorkerRegistrar::ProfileStarted()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!mProfileDir);
+
+  MonitorAutoLock lock(mMonitor);
+  MOZ_DIAGNOSTIC_ASSERT(!mProfileDir);
 
   nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
                                        getter_AddRefs(mProfileDir));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   nsCOMPtr<nsIEventTarget> target =
@@ -855,16 +872,18 @@ ServiceWorkerRegistrar::ProfileStarted()
   }
 }
 
 void
 ServiceWorkerRegistrar::ProfileStopped()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  MonitorAutoLock lock(mMonitor);
+
   if (!mProfileDir) {
     nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
                                          getter_AddRefs(mProfileDir));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
   }
 
--- a/dom/workers/ServiceWorkerRegistrar.h
+++ b/dom/workers/ServiceWorkerRegistrar.h
@@ -79,23 +79,23 @@ private:
   void ShutdownCompleted();
   void MaybeScheduleShutdownCompleted();
 
   bool IsSupportedVersion(const nsACString& aVersion) const;
 
   mozilla::Monitor mMonitor;
 
 protected:
-  // mData and mDataLoaded are protected by mMonitor.
+  // protected by mMonitor.
+  nsCOMPtr<nsIFile> mProfileDir;
   nsTArray<ServiceWorkerRegistrationData> mData;
   bool mDataLoaded;
 
+  // PBackground thread only
   bool mShuttingDown;
   bool* mShutdownCompleteFlag;
   uint32_t mRunnableCounter;
-
-  nsCOMPtr<nsIFile> mProfileDir;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_ServiceWorkerRegistrar_h
--- a/dom/workers/test/gtest/TestReadWrite.cpp
+++ b/dom/workers/test/gtest/TestReadWrite.cpp
@@ -21,19 +21,18 @@ using namespace mozilla::ipc;
 
 class ServiceWorkerRegistrarTest : public ServiceWorkerRegistrar
 {
 public:
   ServiceWorkerRegistrarTest()
   {
     nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
                                        getter_AddRefs(mProfileDir));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return;
-    }
+    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+    MOZ_DIAGNOSTIC_ASSERT(mProfileDir);
   }
 
   nsresult TestReadData() { return ReadData(); }
   nsresult TestWriteData() { return WriteData(); }
   void TestDeleteData() { DeleteData(); }
 
   void TestRegisterServiceWorker(const ServiceWorkerRegistrationData& aData)
   {
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -100,16 +100,18 @@ var interfaceNamesInGlobalScope =
     "DOMException",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMRequest",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMStringList",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Event",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    "EventSource",
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "EventTarget",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "File",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FileReader",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FileReaderSync",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -35,16 +35,17 @@
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
 #include "nsID.h"
 #include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMText.h"
+#include "nsIFrame.h"
 #include "nsIHTMLAbsPosEditor.h"
 #include "nsIHTMLDocument.h"
 #include "nsINode.h"
 #include "nsLiteralString.h"
 #include "nsRange.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsStringFwd.h"
@@ -1705,24 +1706,43 @@ HTMLEditRules::SplitMailCites(Selection*
     }
 
     NS_ENSURE_STATE(mHTMLEditor);
     NS_ENSURE_STATE(selNode->IsContent());
     int32_t newOffset = mHTMLEditor->SplitNodeDeep(*citeNode,
         *selNode->AsContent(), selOffset, HTMLEditor::EmptyContainers::no,
         getter_AddRefs(leftCite), getter_AddRefs(rightCite));
     NS_ENSURE_STATE(newOffset != -1);
+
+    // Add an invisible <br> to the end of the left part if it was a <span> of
+    // style="display: block". This is important, since when serialising the
+    // cite to plain text, the span which caused the visual break is discarded.
+    // So the added <br> will guarantee that the serialiser will insert a
+    // break where the user saw one.
+    if (leftCite &&
+        leftCite->IsHTMLElement(nsGkAtoms::span) &&
+        leftCite->GetPrimaryFrame()->IsFrameOfType(nsIFrame::eBlockFrame)) {
+       nsCOMPtr<nsINode> lastChild = leftCite->GetLastChild();
+       if (lastChild && !lastChild->IsHTMLElement(nsGkAtoms::br)) {
+         // We ignore the result here.
+         nsCOMPtr<Element> invisBR =
+           mHTMLEditor->CreateBR(leftCite, leftCite->Length());
+      }
+    }
+
     selNode = citeNode->GetParentNode();
     NS_ENSURE_STATE(mHTMLEditor);
     nsCOMPtr<Element> brNode = mHTMLEditor->CreateBR(selNode, newOffset);
     NS_ENSURE_STATE(brNode);
+
     // want selection before the break, and on same line
     aSelection->SetInterlinePosition(true);
     rv = aSelection->Collapse(selNode, newOffset);
     NS_ENSURE_SUCCESS(rv, rv);
+
     // if citeNode wasn't a block, we might also want another break before it.
     // We need to examine the content both before the br we just added and also
     // just after it.  If we don't have another br or block boundary adjacent,
     // then we will need a 2nd br added to achieve blank line that user expects.
     if (IsInlineNode(*citeNode)) {
       NS_ENSURE_STATE(mHTMLEditor);
       WSRunObject wsObj(mHTMLEditor, selNode, newOffset);
       nsCOMPtr<nsINode> visNode;
@@ -1732,39 +1752,43 @@ HTMLEditRules::SplitMailCites(Selection*
                              &visOffset, &wsType);
       if (wsType == WSType::normalWS || wsType == WSType::text ||
           wsType == WSType::special) {
         NS_ENSURE_STATE(mHTMLEditor);
         WSRunObject wsObjAfterBR(mHTMLEditor, selNode, newOffset+1);
         wsObjAfterBR.NextVisibleNode(selNode, newOffset + 1,
                                      address_of(visNode), &visOffset, &wsType);
         if (wsType == WSType::normalWS || wsType == WSType::text ||
-            wsType == WSType::special) {
+            wsType == WSType::special ||
+            // In case we're at the very end.
+            wsType == WSType::thisBlock) {
           NS_ENSURE_STATE(mHTMLEditor);
           brNode = mHTMLEditor->CreateBR(selNode, newOffset);
           NS_ENSURE_STATE(brNode);
         }
       }
     }
+
     // delete any empty cites
     bool bEmptyCite = false;
     if (leftCite) {
       NS_ENSURE_STATE(mHTMLEditor);
       rv = mHTMLEditor->IsEmptyNode(leftCite, &bEmptyCite, true, false);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       if (bEmptyCite) {
         NS_ENSURE_STATE(mHTMLEditor);
         rv = mHTMLEditor->DeleteNode(leftCite);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
     }
+
     if (rightCite) {
       NS_ENSURE_STATE(mHTMLEditor);
       rv = mHTMLEditor->IsEmptyNode(rightCite, &bEmptyCite, true, false);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       if (bEmptyCite) {
         NS_ENSURE_STATE(mHTMLEditor);
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -211,16 +211,17 @@ skip-if = toolkit == 'android'
 [test_bug1248185.html]
 [test_bug1258085.html]
 [test_bug1268736.html]
 [test_bug1310912.html]
 skip-if = toolkit == 'android' # bug 1315898
 [test_bug1314790.html]
 [test_bug1315065.html]
 [test_bug1316302.html]
+[test_bug1330796.html]
 
 [test_CF_HTML_clipboard.html]
 subsuite = clipboard
 [test_composition_event_created_in_chrome.html]
 [test_contenteditable_focus.html]
 [test_dom_input_event_on_htmleditor.html]
 skip-if = toolkit == 'android' # bug 1054087
 [test_dom_input_event_on_texteditor.html]
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_bug1330796.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1330796
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 772796</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style> .pre { white-space: pre } </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=772796">Mozilla Bug 1330796</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<div id="editable" contenteditable></div>
+
+<pre id="test">
+
+<script type="application/javascript">
+// We want to test what happens when the user splits a mail cite by clicking
+// at the start, the middle and the end of the cite and hitting the enter key.
+// Mail cites are spans, and since bug 1288911 they are displayed as blocks.
+// The _moz_quote attribute is used to give the cite a blue color via CSS.
+// As an internal attribute, it's not returned from the innerHTML.
+// To the user the tests look like:
+// > mailcite
+// This text is 10 characters long, so we position at 0, 5 and 10.
+// Althought since bug 1288911 those cites are displayed as block,
+// the tests are repeated also for inline display.
+// Each entry of the 'tests' array has the original HTML, the offset to click
+// at and the expected result HTML.
+var tests = [
+  // With style="display: block;".
+  [ "<span _moz_quote=true style=\"display: block;\">&gt; mailcite<br></span>", 0,
+    "x<br><span style=\"display: block;\">&gt; mailcite<br></span>" ],
+  [ "<span _moz_quote=true style=\"display: block;\">&gt; mailcite<br></span>", 5,
+    "<span style=\"display: block;\">&gt; mai<br></span>x<br><span style=\"display: block;\">lcite<br></span>"],
+  [ "<span _moz_quote=true style=\"display: block;\">&gt; mailcite<br></span>", 10,
+    "<span style=\"display: block;\">&gt; mailcite<br></span>x<br>" ],
+  // No <br> at the end to simulate prior deletion to the end of the quote.
+  [ "<span _moz_quote=true style=\"display: block;\">&gt; mailcite</span>", 10,
+    "<span style=\"display: block;\">&gt; mailcite<br></span>x<br>" ],
+
+  // Without style="display: block;".
+  [ "<span _moz_quote=true>&gt; mailcite<br></span>", 0,
+    "x<br><span>&gt; mailcite<br></span>" ],
+  [ "<span _moz_quote=true>&gt; mailcite<br></span>", 5,
+    "<span>&gt; mai</span><br>x<br><span>lcite<br></span>" ],
+  [ "<span _moz_quote=true>&gt; mailcite<br></span>", 10,
+    "<span>&gt; mailcite<br></span>x<br>" ],
+  // No <br> at the end to simulate prior deletion to the end of the quote.
+  [ "<span _moz_quote=true>&gt; mailcite</span>", 10,
+    "<span>&gt; mailcite</span><br>x<br>" ]
+];
+
+/** Test for Bug 1330796 **/
+
+SimpleTest.waitForExplicitFinish();
+
+SimpleTest.waitForFocus(function() {
+
+  var sel = window.getSelection();
+  var theEdit = document.getElementById("editable");
+  makeMailEditor();
+
+  for (i = 0; i < tests.length; i++) {
+    theEdit.innerHTML = tests[i][0];
+    theEdit.focus();
+    var theText = theEdit.firstChild.firstChild;
+    // Position set at the beginning , middle and end of the text.
+    sel.collapse(theText, tests[i][1]);
+
+    synthesizeKey("KEY_Enter", {});
+    synthesizeKey("x", {});
+    is(theEdit.innerHTML, tests[i][2], "unexpected HTML for test " + i.toString());
+  }
+
+  SimpleTest.finish();
+
+});
+
+function makeMailEditor() {
+  var Ci = SpecialPowers.Ci;
+  var editingSession = SpecialPowers.wrap(window)
+    .QueryInterface(Ci.nsIInterfaceRequestor)
+    .getInterface(Ci.nsIWebNavigation)
+    .QueryInterface(Ci.nsIInterfaceRequestor)
+    .getInterface(Ci.nsIEditingSession);
+  var editor = editingSession.getEditorForWindow(window);
+  editor.flags |= Ci.nsIPlaintextEditor.eEditorMailMask;
+}
+</script>
+
+</pre>
+</body>
+</html>
--- a/editor/libeditor/tests/test_bug772796.html
+++ b/editor/libeditor/tests/test_bug772796.html
@@ -149,18 +149,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 
       var sel = window.getSelection();
       var theEdit = document.getElementById("editable");
       var testName;
       var theDiv;
 
       for (i = 0; i < tests.length; i++) {
         testName = "test" + i.toString();
-        dump (testName+"\n");
-        dump (tests[i][0]+"\n");
 
         /* Set up the selection. */
         theEdit.innerHTML = "<div id=\"" + testName + "\">" + tests[i][0] + "</div>";
         theDiv = document.getElementById(testName);
         theDiv.focus();
         sel.collapse(theDiv, 0);
         synthesizeMouse(theDiv, 100, 2, {}); /* click behind and down */
 
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -998,17 +998,17 @@ GetPropIRGenerator::tryAttachStringChar(
     if (size_t(index) >= str->length() ||
         !str->isLinear() ||
         str->asLinear().latin1OrTwoByteChar(index) >= StaticStrings::UNIT_STATIC_LIMIT)
     {
         return false;
     }
 
     StringOperandId strId = writer.guardIsString(valId);
-    Int32OperandId int32IndexId = writer.guardIsInt32(indexId);
+    Int32OperandId int32IndexId = writer.guardIsInt32Index(indexId);
     writer.loadStringCharResult(strId, int32IndexId);
     writer.returnFromIC();
     return true;
 }
 
 bool
 GetPropIRGenerator::tryAttachMagicArgumentsName(ValOperandId valId, HandleId id)
 {
@@ -1040,17 +1040,17 @@ GetPropIRGenerator::tryAttachMagicArgume
     MOZ_ASSERT(idVal_.isInt32());
 
     if (!val_.isMagic(JS_OPTIMIZED_ARGUMENTS))
         return false;
 
     writer.guardMagicValue(valId, JS_OPTIMIZED_ARGUMENTS);
     writer.guardFrameHasNoArgumentsObject();
 
-    Int32OperandId int32IndexId = writer.guardIsInt32(indexId);
+    Int32OperandId int32IndexId = writer.guardIsInt32Index(indexId);
     writer.loadFrameArgumentResult(int32IndexId);
     writer.typeMonitorResult();
     return true;
 }
 
 bool
 GetPropIRGenerator::tryAttachArgumentsObjectArg(HandleObject obj, ObjOperandId objId,
                                                 uint32_t index, Int32OperandId indexId)
@@ -1501,17 +1501,17 @@ IRGenerator::maybeGuardInt32Index(const 
             if (!cx_->runtime()->jitSupportsFloatingPoint)
                 return false;
         }
 
         if (indexSigned < 0)
             return false;
 
         *int32Index = uint32_t(indexSigned);
-        *int32IndexId = writer.guardIsInt32(indexId);
+        *int32IndexId = writer.guardIsInt32Index(indexId);
         return true;
     }
 
     if (index.isString()) {
         int32_t indexSigned = GetIndexFromString(index.toString());
         if (indexSigned < 0)
             return false;
 
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -135,17 +135,17 @@ enum class CacheKind : uint8_t
     GetElem,
     GetName,
 };
 
 #define CACHE_IR_OPS(_)                   \
     _(GuardIsObject)                      \
     _(GuardIsString)                      \
     _(GuardIsSymbol)                      \
-    _(GuardIsInt32)                       \
+    _(GuardIsInt32Index)                  \
     _(GuardType)                          \
     _(GuardShape)                         \
     _(GuardGroup)                         \
     _(GuardProto)                         \
     _(GuardClass)                         \
     _(GuardIsProxy)                       \
     _(GuardNotDOMProxy)                   \
     _(GuardSpecificObject)                \
@@ -408,19 +408,21 @@ class MOZ_RAII CacheIRWriter : public JS
     StringOperandId guardIsString(ValOperandId val) {
         writeOpWithOperandId(CacheOp::GuardIsString, val);
         return StringOperandId(val.id());
     }
     SymbolOperandId guardIsSymbol(ValOperandId val) {
         writeOpWithOperandId(CacheOp::GuardIsSymbol, val);
         return SymbolOperandId(val.id());
     }
-    Int32OperandId guardIsInt32(ValOperandId val) {
-        writeOpWithOperandId(CacheOp::GuardIsInt32, val);
-        return Int32OperandId(val.id());
+    Int32OperandId guardIsInt32Index(ValOperandId val) {
+        Int32OperandId res(nextOperandId_++);
+        writeOpWithOperandId(CacheOp::GuardIsInt32Index, val);
+        writeOperandId(res);
+        return res;
     }
     void guardType(ValOperandId val, JSValueType type) {
         writeOpWithOperandId(CacheOp::GuardType, val);
         static_assert(sizeof(type) == sizeof(uint8_t), "JSValueType should fit in a byte");
         buffer_.writeByte(uint32_t(type));
     }
     void guardShape(ObjOperandId obj, Shape* shape) {
         writeOpWithOperandId(CacheOp::GuardShape, obj);
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -1030,63 +1030,64 @@ CacheIRCompiler::emitGuardIsSymbol()
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
     masm.branchTestSymbol(Assembler::NotEqual, input, failure->label());
     return true;
 }
 
 bool
-CacheIRCompiler::emitGuardIsInt32()
+CacheIRCompiler::emitGuardIsInt32Index()
 {
     ValOperandId inputId = reader.valOperandId();
-    if (allocator.knownType(inputId) == JSVAL_TYPE_INT32)
-        return true;
+    Register output = allocator.defineRegister(masm, reader.int32OperandId());
 
-    ValueOperand input = allocator.useValueRegister(masm, inputId);
-    AutoScratchRegister scratch(allocator, masm);
+    if (allocator.knownType(inputId) == JSVAL_TYPE_INT32) {
+        Register input = allocator.useRegister(masm, Int32OperandId(inputId.id()));
+        masm.move32(input, output);
+        return true;
+    }
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
+    ValueOperand input = allocator.useValueRegister(masm, inputId);
+
+    Label notInt32, done;
+    masm.branchTestInt32(Assembler::NotEqual, input, &notInt32);
+    masm.unboxInt32(input, output);
+    masm.jump(&done);
+
+    masm.bind(&notInt32);
+
     if (cx_->runtime()->jitSupportsFloatingPoint) {
-        Label done;
-        masm.branchTestInt32(Assembler::Equal, input, &done);
-        {
-            // If the value is a double, try to convert it to int32 in place.
-            // It's fine to modify |input| in this case, as the difference is not
-            // observable.
-
-            masm.branchTestDouble(Assembler::NotEqual, input, failure->label());
-
-            // If we're compiling a Baseline IC, FloatReg0 is always available.
-            Label failurePopReg;
-            if (mode_ != Mode::Baseline)
-                masm.push(FloatReg0);
+        masm.branchTestDouble(Assembler::NotEqual, input, failure->label());
 
-            masm.unboxDouble(input, FloatReg0);
-            masm.convertDoubleToInt32(FloatReg0, scratch,
-                                      (mode_ == Mode::Baseline) ? failure->label() : &failurePopReg);
-            masm.tagValue(JSVAL_TYPE_INT32, scratch, input);
-
-            if (mode_ != Mode::Baseline) {
-                masm.pop(FloatReg0);
-                masm.jump(&done);
+        // If we're compiling a Baseline IC, FloatReg0 is always available.
+        Label failurePopReg;
+        if (mode_ != Mode::Baseline)
+            masm.push(FloatReg0);
 
-                masm.bind(&failurePopReg);
-                masm.pop(FloatReg0);
-                masm.jump(failure->label());
-            }
+        masm.unboxDouble(input, FloatReg0);
+        masm.convertDoubleToInt32(FloatReg0, output,
+                                  (mode_ == Mode::Baseline) ? failure->label() : &failurePopReg);
+        if (mode_ != Mode::Baseline) {
+            masm.pop(FloatReg0);
+            masm.jump(&done);
+
+            masm.bind(&failurePopReg);
+            masm.pop(FloatReg0);
+            masm.jump(failure->label());
         }
-        masm.bind(&done);
     } else {
-        masm.branchTestInt32(Assembler::NotEqual, input, failure->label());
+        masm.jump(failure->label());
     }
 
+    masm.bind(&done);
     return true;
 }
 
 bool
 CacheIRCompiler::emitGuardType()
 {
     ValOperandId inputId = reader.valOperandId();
     JSValueType type = reader.valueType();
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -13,17 +13,17 @@ namespace js {
 namespace jit {
 
 // The ops below are defined in CacheIRCompiler and codegen is shared between
 // BaselineCacheIRCompiler and IonCacheIRCompiler.
 #define CACHE_IR_SHARED_OPS(_)            \
     _(GuardIsObject)                      \
     _(GuardIsString)                      \
     _(GuardIsSymbol)                      \
-    _(GuardIsInt32)                       \
+    _(GuardIsInt32Index)                  \
     _(GuardType)                          \
     _(GuardClass)                         \
     _(GuardIsProxy)                       \
     _(GuardNotDOMProxy)                   \
     _(GuardMagicValue)                    \
     _(GuardNoUnboxedExpando)              \
     _(GuardAndLoadUnboxedExpando)         \
     _(GuardNoDetachedTypedObjects)        \
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1331272.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<style>
+  div::before {
+    content: "PASS";
+    display: none;
+  }
+  .foo::before {
+    display: none;
+  }
+</style>
+<div></div>
+<script>
+window.onload = function() {
+  document.querySelector('div').className = "foo";
+}
+</script>
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -162,8 +162,9 @@ asserts-if(stylo,1) pref(dom.animations-
 load 1290994-4.html
 load 1314531.html
 load 1315889-1.html
 load 1315894-1.html
 skip-if(stylo) load 1319072-1.html # bug 1323733
 HTTP load 1320423-1.html
 asserts-if(stylo,5-9) load 1321357-1.html # bug 1324669
 load 1328535-1.html
+load 1331272.html
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -430,17 +430,21 @@ nsImageBoxFrame::PaintImage(nsRenderingC
            dest, dirty, nullptr, aFlags,
            anchorPoint.ptrOr(nullptr),
            hasSubRect ? &mSubRect : nullptr);
 }
 
 void nsDisplayXULImage::Paint(nsDisplayListBuilder* aBuilder,
                               nsRenderingContext* aCtx)
 {
-  uint32_t flags = imgIContainer::FLAG_NONE;
+  // Even though we call StartDecoding when we get a new image we pass
+  // FLAG_SYNC_DECODE_IF_FAST here for the case where the size we draw at is not
+  // the intrinsic size of the image and we aren't likely to implement predictive
+  // decoding at the correct size for this class like nsImageFrame has.
+  uint32_t flags = imgIContainer::FLAG_SYNC_DECODE_IF_FAST;
   if (aBuilder->ShouldSyncDecodeImages())
     flags |= imgIContainer::FLAG_SYNC_DECODE;
   if (aBuilder->IsPaintingToWindow())
     flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
 
   DrawResult result = static_cast<nsImageBoxFrame*>(mFrame)->
     PaintImage(*aCtx, mVisibleRect, ToReferenceFrame(), flags);
 
--- a/media/libpng/CHANGES
+++ b/media/libpng/CHANGES
@@ -5767,17 +5767,37 @@ Version 1.6.27rc01 [December 27, 2016]
     "generates" 'defined' is not permitted, but the use of the word
     "generates" within the C90 standard seems to imply more than simple
     substitution of an expression itself containing a well-formed defined
     operation.
   Added ARM support to CMakeLists.txt (Andreas Franek).
 
 Version 1.6.27 [December 29, 2016]
   Fixed a potential null pointer dereference in png_set_text_2() (bug report
-    and patch by Patrick Keshishian).
+    and patch by Patrick Keshishian, CVE-2016-10087).
+
+Version 1.6.28rc01 [January 3, 2017]
+  Fixed arm/aarch64 detection in CMakeLists.txt (Gianfranco Costamagna).
+  Added option to Cmake build allowing a custom location of zlib to be
+    specified in a scenario where libpng is being built as a subproject
+    alongside zlib by another project (Sam Serrels).
+  Changed png_ptr->options from a png_byte to png_uint_32, to accomodate
+    up to 16 options.
+
+Version 1.6.28rc02 [January 4, 2017]
+  Added "include(GNUInstallDirs)" to CMakeLists.txt (Gianfranco Costamagna).
+  Moved SSE2 optimization code into the main libpng source directory.
+    Configure libpng with "configure --enable-intel-sse" or compile
+    libpng with "-DPNG_INTEL_SSE" in CPPFLAGS to enable it.
+
+Version 1.6.28rc03 [January 4, 2017]
+  Backed out the SSE optimization and last CMakeLists.txt to allow time for QA.
+
+Version 1.6.28 [January 5, 2017]
+  No changes.
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement
 to subscribe)
 or to glennrp at users.sourceforge.net
 
 Glenn R-P
--- a/media/libpng/LICENSE
+++ b/media/libpng/LICENSE
@@ -13,36 +13,32 @@ v. 2.0. If a copy of the MPL was not dis
 obtain one at http://mozilla.org/MPL/2.0/.
 
 This modified version of libpng code adds animated PNG support and is
 released under the libpng license described below. The modifications are
 Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2016 Max Stepin,
 and are delimited by "#ifdef PNG_APNG_SUPPORTED / #endif" directives
 surrounding them in the modified libpng source files.
 
-This modified version of libpng code adds Intel-SSE support and is
-released under the libpng license described below. The modifications are
-Copyright (c) 2016 Google, Inc., and consist of the source files in the
-"sse2" subdirectory and added code in pngpriv.h delimited by
-#ifndef PNG_INTEL_SSE_OPT / #endif directives.
-
 This code is released under the libpng license.
 
-libpng versions 1.0.7, July 1, 2000 through 1.6.27, December 29, 2016 are
-Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are
+libpng versions 1.0.7, July 1, 2000 through 1.6.28, January 5, 2017 are
+Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are
 derived from libpng-1.0.6, and are distributed according to the same
 disclaimer and license as libpng-1.0.6 with the following individuals
 added to the list of Contributing Authors:
 
    Simon-Pierre Cadieux
    Eric S. Raymond
    Mans Rullgard
    Cosmin Truta
    Gilles Vollant
    James Yu
+   Mandar Sahastrabuddhe
+   Google Inc.
 
 and with the following additions to the disclaimer:
 
    There is no warranty against interference with your enjoyment of the
    library or against infringement.  There is no warranty that our
    efforts or the library will fulfill any of your particular purposes
    or needs.  This library is provided with all faults, and the entire
    risk of satisfactory quality, performance, accuracy, and effort is with
@@ -138,9 +134,9 @@ The Copyright owner believes that the Ex
 Number (ECCN) for libpng is EAR99, which means not subject to export
 controls or International Traffic in Arms Regulations (ITAR) because
 it is open source, publicly available software, that does not contain
 any encryption software.  See the EAR, paragraphs 734.3(b)(3) and
 734.7(b).
 
 Glenn Randers-Pehrson
 glennrp at users.sourceforge.net
-December 29, 2016
+January 5, 2017
--- a/media/libpng/MOZCHANGES
+++ b/media/libpng/MOZCHANGES
@@ -1,11 +1,13 @@
 
 Changes made to pristine libpng source by mozilla.org developers.
 
+2017/01/06  -- Synced with libpng-1.6.28 (bug #1328354).
+
 2016/12/29  -- Synced with libpng-1.6.27 (bug #1326234).
 
 2016/10/20  -- Synced with libpng-1.6.26 (bug #1311776).
 
 2016/09/01  -- Synced with libpng-1.6.25 (bug #1299590).
 
 2016/08/11  -- Enabled SSE2 support (bug #1276127).
 
--- a/media/libpng/README
+++ b/media/libpng/README
@@ -1,9 +1,9 @@
-README for libpng version 1.6.27 - December 29, 2016 (shared library 16.0)
+README for libpng version 1.6.28 - January 5, 2017 (shared library 16.0)
 See the note about version numbers near the top of png.h
 
 See INSTALL for instructions on how to install libpng.
 
 Libpng comes in several distribution formats.  Get libpng-*.tar.gz or
 libpng-*.tar.xz or if you want UNIX-style line endings in the text files,
 or lpng*.7z or lpng*.zip if you want DOS-style line endings.
 
--- a/media/libpng/apng.patch
+++ b/media/libpng/apng.patch
@@ -3,23 +3,23 @@ Index: LICENSE
 --- LICENSE
 +++ LICENSE
 @@ -8,6 +8,12 @@
  If you modify libpng you may insert additional notices immediately following
  this sentence.
  
 +This modified version of libpng code adds animated PNG support and is
 +released under the libpng license described below. The modifications are
-+Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2016 Max Stepin,
++Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2017 Max Stepin,
 +and are delimited by "#ifdef PNG_APNG_SUPPORTED / #endif" directives
 +surrounding them in the modified libpng source files.
 +
  This code is released under the libpng license.
  
- libpng versions 1.0.7, July 1, 2000 through 1.6.27, December 29, 2016 are
+ libpng versions 1.0.7, July 1, 2000 through 1.6.28, January 5, 2017 are
 Index: pngread.c
 ===================================================================
 --- pngread.c
 +++ pngread.c
 @@ -161,6 +161,9 @@
  
        else if (chunk_name == png_IDAT)
        {
@@ -294,79 +294,79 @@ Index: pngget.c
 Index: png.c
 ===================================================================
 --- png.c
 +++ png.c
 @@ -776,17 +776,21 @@
  #else
  #  ifdef __STDC__
     return PNG_STRING_NEWLINE \
--      "libpng version 1.6.27 - December 29, 2016" PNG_STRING_NEWLINE \
-+      "libpng version 1.6.27+apng - December 29, 2016" PNG_STRING_NEWLINE \
-       "Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson" \
+-      "libpng version 1.6.28 - January 5, 2017" PNG_STRING_NEWLINE \
++      "libpng version 1.6.28+apng - January 5, 2017" PNG_STRING_NEWLINE \
+       "Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson" \
        PNG_STRING_NEWLINE \
        "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
        "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
 -      PNG_STRING_NEWLINE;
 +      PNG_STRING_NEWLINE \
 +      "Portions Copyright (c) 2006-2007 Andrew Smith" PNG_STRING_NEWLINE \
-+      "Portions Copyright (c) 2008-2016 Max Stepin" PNG_STRING_NEWLINE ;
++      "Portions Copyright (c) 2008-2017 Max Stepin" PNG_STRING_NEWLINE ;
  #  else
--   return "libpng version 1.6.27 - December 29, 2016\
-+   return "libpng version 1.6.27+apng - December 29, 2016\
-       Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson\
+-   return "libpng version 1.6.28 - January 5, 2017\
++   return "libpng version 1.6.28+apng - January 5, 2017\
+       Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\
        Copyright (c) 1996-1997 Andreas Dilger\
 -      Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
 +      Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\
 +      Portions Copyright (c) 2006-2007 Andrew Smith\
-+      Portions Copyright (c) 2008-2016 Max Stepin";
++      Portions Copyright (c) 2008-2017 Max Stepin";
  #  endif
  #endif
  }
 Index: png.h
 ===================================================================
 --- png.h
 +++ png.h
 @@ -23,6 +23,12 @@
   * If you modify libpng you may insert additional notices immediately following
   * this sentence.
   *
 + * This modified version of libpng code adds animated PNG support and is
 + * released under the libpng license described below. The modifications are
-+ * Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2016 Max Stepin,
++ * Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2017 Max Stepin,
 + * and are delimited by "#ifdef PNG_APNG_SUPPORTED / #endif" directives
 + * surrounding them in the modified libpng source files.
 + *
   * This code is released under the libpng license.
   *
-  * Some files in the "contrib" directory and some configure-generated
-@@ -314,8 +320,9 @@
+  * libpng versions 1.0.7, July 1, 2000 through 1.6.28, January 5, 2017 are
+@@ -307,8 +313,9 @@
   */
  
  /* Version information for png.h - this should match the version in png.c */
--#define PNG_LIBPNG_VER_STRING "1.6.27"
--#define PNG_HEADER_VERSION_STRING " libpng version 1.6.27 - December 29, 2016\n"
-+#define PNG_LIBPNG_VER_STRING "1.6.27+apng"
+-#define PNG_LIBPNG_VER_STRING "1.6.28"
+-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.28 - January 5, 2017\n"
++#define PNG_LIBPNG_VER_STRING "1.6.28+apng"
 +#define PNG_HEADER_VERSION_STRING \
-+     " libpng version 1.6.27+apng - December 29, 2016\n"
++     " libpng version 1.6.28+apng - January 5, 2017\n"
  
  #define PNG_LIBPNG_VER_SONUM   16
  #define PNG_LIBPNG_VER_DLLNUM  16
-@@ -366,6 +373,10 @@
+@@ -359,6 +366,10 @@
  #   include "pnglibconf.h"
  #endif
  
 +#define PNG_APNG_SUPPORTED
 +#define PNG_READ_APNG_SUPPORTED
 +#define PNG_WRITE_APNG_SUPPORTED
 +
  #ifndef PNG_VERSION_INFO_ONLY
  /* Machine specific configuration. */
  #  include "pngconf.h"
-@@ -461,6 +472,17 @@
+@@ -454,6 +465,17 @@
   * See pngconf.h for base types that vary by machine/system
   */
  
 +#ifdef PNG_APNG_SUPPORTED
 +/* dispose_op flags from inside fcTL */
 +#define PNG_DISPOSE_OP_NONE        0x00
 +#define PNG_DISPOSE_OP_BACKGROUND  0x01
 +#define PNG_DISPOSE_OP_PREVIOUS    0x02
@@ -374,39 +374,39 @@ Index: png.h
 +/* blend_op flags from inside fcTL */
 +#define PNG_BLEND_OP_SOURCE        0x00
 +#define PNG_BLEND_OP_OVER          0x01
 +#endif /* APNG */
 +
  /* This triggers a compiler error in png.c, if png.c and png.h
   * do not agree upon the version number.
   */
-@@ -781,6 +803,10 @@
+@@ -774,6 +796,10 @@
  #define PNG_INFO_sPLT 0x2000U  /* ESR, 1.0.6 */
  #define PNG_INFO_sCAL 0x4000U  /* ESR, 1.0.6 */
  #define PNG_INFO_IDAT 0x8000U  /* ESR, 1.0.6 */
 +#ifdef PNG_APNG_SUPPORTED
 +#define PNG_INFO_acTL 0x10000U
 +#define PNG_INFO_fcTL 0x20000U
 +#endif
  
  /* This is used for the transformation routines, as some of them
   * change these values for the row.  It also should enable using
-@@ -818,6 +844,10 @@
+@@ -811,6 +837,10 @@
  #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
  typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
  typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
 +#ifdef PNG_APNG_SUPPORTED
 +typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
 +    png_uint_32));
 +#endif
  
  /* The following callback receives png_uint_32 row_number, int pass for the
   * png_bytep data of the row.  When transforming an interlaced image the
-@@ -3247,6 +3277,75 @@
+@@ -3240,6 +3270,75 @@
   *  END OF HARDWARE AND SOFTWARE OPTIONS
   ******************************************************************************/
  
 +#ifdef PNG_APNG_SUPPORTED
 +PNG_EXPORT(246, png_uint_32, png_get_acTL, (png_structp png_ptr,
 +   png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
 +
 +PNG_EXPORT(247, png_uint_32, png_set_acTL, (png_structp png_ptr,
@@ -472,17 +472,17 @@ Index: png.h
 +PNG_EXPORT(265, void, png_write_frame_tail, (png_structp png_ptr,
 +   png_infop info_ptr));
 +#endif /* WRITE_APNG */
 +#endif /* APNG */
 +
  /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
   * defs, and in scripts/symbols.def.
   */
-@@ -3255,7 +3354,11 @@
+@@ -3248,7 +3347,11 @@
   * one to use is one more than this.)
   */
  #ifdef PNG_EXPORT_LAST_ORDINAL
 +#ifdef PNG_APNG_SUPPORTED
 +  PNG_EXPORT_LAST_ORDINAL(265);
 +#else
    PNG_EXPORT_LAST_ORDINAL(245);
 +#endif /* APNG */
--- a/media/libpng/libpng-manual.txt
+++ b/media/libpng/libpng-manual.txt
@@ -1,22 +1,22 @@
 libpng-manual.txt - A description on how to use and modify libpng
 
- libpng version 1.6.27 - December 29, 2016
+ libpng version 1.6.28 - January 5, 2017
  Updated and distributed by Glenn Randers-Pehrson
  <glennrp at users.sourceforge.net>
  Copyright (c) 1998-2016 Glenn Randers-Pehrson
 
  This document is released under the libpng license.
  For conditions of distribution and use, see the disclaimer
  and license in png.h
 
  Based on:
 
- libpng versions 0.97, January 1998, through 1.6.27 - December 29, 2016
+ libpng versions 0.97, January 1998, through 1.6.28 - January 5, 2017
  Updated and distributed by Glenn Randers-Pehrson
  Copyright (c) 1998-2016 Glenn Randers-Pehrson
 
  libpng 1.0 beta 6 - version 0.96 - May 28, 1997
  Updated and distributed by Andreas Dilger
  Copyright (c) 1996, 1997 Andreas Dilger
 
  libpng 1.0 beta 2 - version 0.88 - January 26, 1996
@@ -5350,17 +5350,17 @@ Lines do not exceed 80 characters.
 Other rules can be inferred by inspecting the libpng source.
 
 XVI. Y2K Compliance in libpng
 
 Since the PNG Development group is an ad-hoc body, we can't make
 an official declaration.
 
 This is your unofficial assurance that libpng from version 0.71 and
-upward through 1.6.27 are Y2K compliant.  It is my belief that earlier
+upward through 1.6.28 are Y2K compliant.  It is my belief that earlier
 versions were also Y2K compliant.
 
 Libpng only has two year fields.  One is a 2-byte unsigned integer
 that will hold years up to 65535.  The other, which is deprecated,
 holds the date in text format, and will hold years up to 9999.
 
 The integer is
     "png_uint_16 year" in png_time_struct.
--- a/media/libpng/png.c
+++ b/media/libpng/png.c
@@ -1,25 +1,25 @@
 
 /* png.c - location for general purpose libpng functions
  *
- * Last changed in libpng 1.6.27 [December 29, 2016]
- * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.28 [January 5, 2017]
+ * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
 
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_27 Your_png_h_is_not_version_1_6_27;
+typedef png_libpng_version_1_6_28 Your_png_h_is_not_version_1_6_28;
 
 /* Tells libpng that we have already handled the first "num_bytes" bytes
  * of the PNG file signature.  If the PNG data is embedded into another
  * stream we can set num_bytes = 8 so that libpng will not attempt to read
  * or write any of the magic bytes before it starts on the IHDR.
  */
 
 #ifdef PNG_READ_SUPPORTED
@@ -771,31 +771,31 @@ png_const_charp PNGAPI
 png_get_copyright(png_const_structrp png_ptr)
 {
    PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */
 #ifdef PNG_STRING_COPYRIGHT
    return PNG_STRING_COPYRIGHT
 #else
 #  ifdef __STDC__
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.27+apng - December 29, 2016" PNG_STRING_NEWLINE \
-      "Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson" \
+      "libpng version 1.6.28+apng - January 5, 2017" PNG_STRING_NEWLINE \
+      "Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
       "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
       "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
       PNG_STRING_NEWLINE \
       "Portions Copyright (c) 2006-2007 Andrew Smith" PNG_STRING_NEWLINE \
-      "Portions Copyright (c) 2008-2016 Max Stepin" PNG_STRING_NEWLINE ;
+      "Portions Copyright (c) 2008-2017 Max Stepin" PNG_STRING_NEWLINE ;
 #  else
-   return "libpng version 1.6.27+apng - December 29, 2016\
-      Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson\
+   return "libpng version 1.6.28+apng - January 5, 2017\
+      Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\
       Copyright (c) 1996-1997 Andreas Dilger\
       Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\
       Portions Copyright (c) 2006-2007 Andrew Smith\
-      Portions Copyright (c) 2008-2016 Max Stepin";
+      Portions Copyright (c) 2008-2017 Max Stepin";
 #  endif
 #endif
 }
 
 /* The following return the library version as a short string in the
  * format 1.0.0 through 99.99.99zz.  To get the version of *.h files
  * used with your application, print out PNG_LIBPNG_VER_STRING, which
  * is defined in png.h.
@@ -4259,21 +4259,21 @@ png_build_gamma_table(png_structrp png_p
 /* HARDWARE OR SOFTWARE OPTION SUPPORT */
 #ifdef PNG_SET_OPTION_SUPPORTED
 int PNGAPI
 png_set_option(png_structrp png_ptr, int option, int onoff)
 {
    if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT &&
       (option & 1) == 0)
    {
-      int mask = 3 << option;
-      int setting = (2 + (onoff != 0)) << option;
-      int current = png_ptr->options;
-
-      png_ptr->options = (png_byte)(((current & ~mask) | setting) & 0xff);
+      png_uint_32 mask = 3 << option;
+      png_uint_32 setting = (2 + (onoff != 0)) << option;
+      png_uint_32 current = png_ptr->options;
+
+      png_ptr->options = (png_uint_32)(((current & ~mask) | setting) & 0xff);
 
       return (current & mask) >> option;
    }
 
    return PNG_OPTION_INVALID;
 }
 #endif
 
--- a/media/libpng/png.h
+++ b/media/libpng/png.h
@@ -1,85 +1,79 @@
 
 /* png.h - header file for PNG reference library
  *
- * libpng version 1.6.27, December 29, 2016
+ * libpng version 1.6.28, January 5, 2017
  *
- * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
+ * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license (See LICENSE, below)
  *
  * Authors and maintainers:
  *   libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
- *   libpng versions 0.97, January 1998, through 1.6.27, December 29, 2016:
+ *   libpng versions 0.97, January 1998, through 1.6.28, January 5, 2017:
  *     Glenn Randers-Pehrson.
  *   See also "Contributing Authors", below.
  */
 
 /*
  * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
  *
  * If you modify libpng you may insert additional notices immediately following
  * this sentence.
  *
  * This modified version of libpng code adds animated PNG support and is
  * released under the libpng license described below. The modifications are
- * Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2016 Max Stepin,
+ * Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2017 Max Stepin,
  * and are delimited by "#ifdef PNG_APNG_SUPPORTED / #endif" directives
  * surrounding them in the modified libpng source files.
  *
  * This code is released under the libpng license.
  *
- * Some files in the "contrib" directory and some configure-generated
- * files that are distributed with libpng have other copyright owners and
- * are released under other open source licenses.
- *
- * libpng versions 1.0.7, July 1, 2000 through 1.6.27, December 29, 2016 are
- * Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are
+ * libpng versions 1.0.7, July 1, 2000 through 1.6.28, January 5, 2017 are
+ * Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are
  * derived from libpng-1.0.6, and are distributed according to the same
  * disclaimer and license as libpng-1.0.6 with the following individuals
  * added to the list of Contributing Authors:
  *
  *    Simon-Pierre Cadieux
  *    Eric S. Raymond
  *    Mans Rullgard
  *    Cosmin Truta
  *    Gilles Vollant
  *    James Yu
  *    Mandar Sahastrabuddhe
+ *    Google Inc.
  *
  * and with the following additions to the disclaimer:
  *
  *    There is no warranty against interference with your enjoyment of the
  *    library or against infringement.  There is no warranty that our
  *    efforts or the library will fulfill any of your particular purposes
  *    or needs.  This library is provided with all faults, and the entire
  *    risk of satisfactory quality, performance, accuracy, and effort is with
  *    the user.
  *
- * Some files in the "contrib" directory have other copyright owners and
+ * Some files in the "contrib" directory and some configure-generated
+ * files that are distributed with libpng have other copyright owners and
  * are released under other open source licenses.
  *
- *
  * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
  * Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from
  * libpng-0.96, and are distributed according to the same disclaimer and
  * license as libpng-0.96, with the following individuals added to the list
  * of Contributing Authors:
  *
  *    Tom Lane
  *    Glenn Randers-Pehrson
  *    Willem van Schaik
  *
- * Some files in the "scripts" directory have different copyright owners
- * but are also released under this license.
- *
  * libpng versions 0.89, June 1996, through 0.96, May 1997, are
  * Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,
  * and are distributed according to the same disclaimer and license as
  * libpng-0.88, with the following individuals added to the list of
  * Contributing Authors:
  *
  *    John Bowler
  *    Kevin Bracey
@@ -215,21 +209,21 @@
  *    1.0.6j                        10007  2.1.0.6j (incompatible with 1.0.0)
  *    1.0.7beta11-14        DLLNUM  10007  2.1.0.7beta11-14 (binary compatible)
  *    1.0.7beta15-18           1    10007  2.1.0.7beta15-18 (binary compatible)
  *    1.0.7rc1-2               1    10007  2.1.0.7rc1-2 (binary compatible)
  *    1.0.7                    1    10007  (still compatible)
  *    ...
  *    1.0.19                  10    10019  10.so.0.19[.0]
  *    ...
- *    1.2.56                  13    10256  12.so.0.56[.0]
+ *    1.2.57                  13    10257  12.so.0.57[.0]
  *    ...
- *    1.5.27                  15    10527  15.so.15.27[.0]
+ *    1.5.28                  15    10527  15.so.15.28[.0]
  *    ...
- *    1.6.27                  16    10627  16.so.16.27[.0]
+ *    1.6.28                  16    10628  16.so.16.28[.0]
  *
  *    Henceforth the source version will match the shared-library major
  *    and minor numbers; the shared-library major version number will be
  *    used for changes in backward compatibility, as it is intended.  The
  *    PNG_LIBPNG_VER macro, which is not used within libpng but is available
  *    for applications, is an unsigned integer of the form xyyzz corresponding
  *    to the source version x.y.z (leading zeros in y and z).  Beta versions
  *    were given the previous public release number plus a letter, until
@@ -247,23 +241,23 @@
  * is available as a W3C Recommendation and as an ISO Specification,
  * <http://www.w3.org/TR/2003/REC-PNG-20031110/
  */
 
 /*
  * Y2K compliance in libpng:
  * =========================
  *
- *    December 29, 2016
+ *    January 5, 2017
  *
  *    Since the PNG Development group is an ad-hoc body, we can't make
  *    an official declaration.
  *
  *    This is your unofficial assurance that libpng from version 0.71 and
- *    upward through 1.6.27 are Y2K compliant.  It is my belief that
+ *    upward through 1.6.28 are Y2K compliant.  It is my belief that
  *    earlier versions were also Y2K compliant.
  *
  *    Libpng only has two year fields.  One is a 2-byte unsigned integer
  *    that will hold years up to 65535.  The other, which is deprecated,
  *    holds the date in text format, and will hold years up to 9999.
  *
  *    The integer is
  *        "png_uint_16 year" in png_time_struct.
@@ -315,27 +309,27 @@
  * file has been stripped from your copy of libpng, you can find it at
  * <http://www.libpng.org/pub/png/libpng-manual.txt>
  *
  * If you just need to read a PNG file and don't want to read the documentation
  * skip to the end of this file and read the section entitled 'simplified API'.
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.27+apng"
+#define PNG_LIBPNG_VER_STRING "1.6.28+apng"
 #define PNG_HEADER_VERSION_STRING \
-     " libpng version 1.6.27+apng - December 29, 2016\n"
+     " libpng version 1.6.28+apng - January 5, 2017\n"
 
 #define PNG_LIBPNG_VER_SONUM   16
 #define PNG_LIBPNG_VER_DLLNUM  16
 
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 27
+#define PNG_LIBPNG_VER_RELEASE 28
 
 /* This should match the numeric part of the final component of
  * PNG_LIBPNG_VER_STRING, omitting any leading zero:
  */
 
 #define PNG_LIBPNG_VER_BUILD  0
 
 /* Release Status */
@@ -356,17 +350,17 @@
 #define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE
 
 /* Careful here.  At one time, Guy wanted to use 082, but that would be octal.
  * We must not include leading zeros.
  * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only
  * version 1.0.0 was mis-numbered 100 instead of 10000).  From
  * version 1.0.1 it's    xxyyzz, where x=major, y=minor, z=release
  */
-#define PNG_LIBPNG_VER 10627 /* 1.6.27 */
+#define PNG_LIBPNG_VER 10628 /* 1.6.28 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
  */
 #ifndef PNGLCONF_H
 /* If pnglibconf.h is missing, you can
  * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h
  */
@@ -481,17 +475,17 @@ extern "C" {
 /* blend_op flags from inside fcTL */
 #define PNG_BLEND_OP_SOURCE        0x00
 #define PNG_BLEND_OP_OVER          0x01
 #endif /* APNG */
 
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char* png_libpng_version_1_6_27;
+typedef char* png_libpng_version_1_6_28;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
  * png_struct is the cache of information used while reading or writing a single
  * PNG file.  One of these is always required, although the simplified API
  * (below) hides the creation and destruction of it.
  */
 typedef struct png_struct_def png_struct;
--- a/media/libpng/pngconf.h
+++ b/media/libpng/pngconf.h
@@ -1,12 +1,12 @@
 
 /* pngconf.h - machine configurable file for libpng
  *
- * libpng version 1.6.27, December 29, 2016
+ * libpng version 1.6.28, January 5, 2017
  *
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
--- a/media/libpng/pngrutil.c
+++ b/media/libpng/pngrutil.c
@@ -1,12 +1,12 @@
 
 /* pngrutil.c - utilities to read a PNG file
  *
- * Last changed in libpng 1.6.27 [December 29, 2016]
+ * Last changed in libpng 1.6.27 [January 5, 2017]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  *
--- a/media/libpng/pngstruct.h
+++ b/media/libpng/pngstruct.h
@@ -1,13 +1,13 @@
 
 /* pngstruct.h - header file for PNG reference library
  *
- * Last changed in libpng 1.6.24 [August 4, 2016]
- * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.28 [January 5, 2017]
+ * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
 
@@ -348,17 +348,17 @@ struct png_struct_def
 
 #ifdef PNG_READ_QUANTIZE_SUPPORTED
    png_bytep palette_lookup; /* lookup table for quantizing */
    png_bytep quantize_index; /* index translation for palette files */
 #endif
 
 /* Options */
 #ifdef PNG_SET_OPTION_SUPPORTED
-   png_byte options;           /* On/off state (up to 4 options) */
+   png_uint_32 options;           /* On/off state (up to 16 options) */
 #endif
 
 #if PNG_LIBPNG_VER < 10700
 /* To do: remove this from libpng-1.7 */
 #ifdef PNG_TIME_RFC1123_SUPPORTED
    char time_buffer[29]; /* String to hold RFC 1123 time text */
 #endif
 #endif
--- a/mobile/android/docs/activitystreamtelemetry.rst
+++ b/mobile/android/docs/activitystreamtelemetry.rst
@@ -1,13 +1,14 @@
 .. -*- Mode: rst; fill-column: 80; -*-
 
-==============
+============================
 Activity Stream UI Telemetry
-==============
+============================
+
 Building on top of UI Telemetry, Activity Stream records additional information about events and user context in which they occur.
 The ``extras`` field is used for that purpose; additional information is structured as JSON blobs.
 
 Session
 =======
 Activity Stream events are recorded as part of the "activitystream.1" session.
 
 Global extras
@@ -23,125 +24,135 @@ Top Site interactions
 ---------------------
 Two event types are recorded:
 
 1) User clicked on a Top Site: event="loadurl.1", method="listitem"
 2) User clicked on the menu button: event="show.1", method="contextmenu"
 
 For each event, in addition to global extras, the following information is recorded:
 
-extras: {
-    ...
-    "source_type": "topsites",
-    "source_subtype": "pinned"/"suggested"/"top"
-}
+.. code-block:: js
+
+    extras: {
+        ...
+        "source_type": "topsites",
+        "source_subtype": "pinned"/"suggested"/"top"
+    }
 
 Subtype indicates a reason an item which is being interacted with appeared in the Top Sites:
+
 - "pinned": a pinned top site, specifically a non-positioned "Activity Stream pinned" site
 - "suggested": a suggested top site, one of the default ones displayed when there's not enough browsing history available
 - "top": a frecency-based top site, based on browsing history. Neither "pinned" nor "suggested".
 
 Highlight interactions
 ----------------------
 Two event types are recorded:
 
 1) User clicked on a Highlight: event="loadurl.1", method="listitem"
 2) User clicked on the menu button: event="show.1", method="contextmenu"
 
 For both event types, in addition to global extras, the following information is recorded:
 
-extras: {
-    ...
-    "source_type": "highlights",
-    "source_subtype": "visited"/"bookmarked"
-}
+.. code-block:: js
+
+    extras: {
+        ...
+        "source_type": "highlights",
+        "source_subtype": "visited"/"bookmarked"
+    }
 
 Subtype indicates reason an item being which is being interacted with appeared in the Highlights:
 - "visited": a website has been visited recently
 - "bookmarked": a website has been bookmarked recently
 
 For "loadurl.1" event, the following extra information is also recorded:
 
-extras: {
-    ...
-    "action_position": number, /* 0-based index of a highlight being interacted with */
-    "count": number, /* total number of highlights displayed */
-}
+.. code-block:: js
+
+    extras: {
+        ...
+        "action_position": number, /* 0-based index of a highlight being interacted with */
+        "count": number, /* total number of highlights displayed */
+    }
 
 Context Menu interactions
 -------------------------
 Every interaction with a context menu item is recorded using: event="action.1", method="contextmenu"
 
 For all interactions, in addition to global extras, the following information is recorded:
 
-extras: {
-    ...
-    "item": string, /* name of a menu item */
-    "source_type": "topsites"/"highlights",
-    "source_subtype": string, /* depending on type, one of: "pinned", "suggested", "top", "visited", "bookmarked" */
-}
+.. code-block:: js
+
+    extras: {
+        ...
+        "item": string, /* name of a menu item */
+        "source_type": "topsites"/"highlights",
+        "source_subtype": string, /* depending on type, one of: "pinned", "suggested", "top", "visited", "bookmarked" */
+    }
 
 Possible values for "item" key (names of menu items), in no particular order:
+
 - "share"
 - "add_bookmark"
 - "remove_bookmark"
 - "pin"
 - "unpin"
 - "copy"
 - "homescreen"
 - "newtab" (private tab actions are collapsed into "newtab" telemetry due to our privacy guidelines)
 - "dismiss"
 - "delete"
 
 Full Examples
 =============
 Following examples of events are here to provide a better feel for the overall shape of telemetry data being recorded.
 
 1) User with an active Firefox Account clicked on a menu item for a "visited highlight":
-``
-session="activitystream.1"
-event="show.1"
-method="contextmenu"
-extras="{
-    'fx_account_present': true,
-    'source_type': 'highlights',
-    'source_subtype': 'visited'
-}"
-``
+    ::
+
+        session="activitystream.1"
+        event="show.1"
+        method="contextmenu"
+        extras="{
+            'fx_account_present': true,
+            'source_type': 'highlights',
+            'source_subtype': 'visited'
+        }"
 
 2) User with no active Firefox Account clicked on a second highlight (recent bookmark), with total of 7 highlights being displayed:
-``
-session="activitystream.1"
-event="loadurl.1"
-method="listitem"
-extras="{
-    'fx_account_present': false,
-    'source_type': 'highlights',
-    'source_subtype': 'bookmarked'
-    'action_position': 1,
-    'count': 7
-}"
-``
+    ::
+
+        session="activitystream.1"
+        event="loadurl.1"
+        method="listitem"
+        extras="{
+            'fx_account_present': false,
+            'source_type': 'highlights',
+            'source_subtype': 'bookmarked'
+            'action_position': 1,
+            'count': 7
+        }"
 
 3) User with an active Firefox Account clicked on a pinned top site:
-``
-session="activitystream.1"
-event="loadurl.1"
-method="listitem"
-extras="{
-    'fx_account_present': true,
-    'source_type': 'topsites',
-    'source_subtype': 'pinned'
-}"
-``
+    ::
+
+        session="activitystream.1"
+        event="loadurl.1"
+        method="listitem"
+        extras="{
+            'fx_account_present': true,
+            'source_type': 'topsites',
+            'source_subtype': 'pinned'
+        }"
 
 4) User with an active Firefox Account clicked on a "share" context menu item, which was displayed for a regular top site:
-``
-session="activitystream.1"
-event="action.1"
-method="contextmenu"
-extras="{
-    'fx_account_present': true,
-    'source_type': 'topsites',
-    'source_subtype': 'top',
-    'item': 'share'
-}"
-``
\ No newline at end of file
+    ::
+
+        session="activitystream.1"
+        event="action.1"
+        method="contextmenu"
+        extras="{
+            'fx_account_present': true,
+            'source_type': 'topsites',
+            'source_subtype': 'top',
+            'item': 'share'
+        }"
--- a/mobile/android/docs/index.rst
+++ b/mobile/android/docs/index.rst
@@ -8,16 +8,17 @@ Firefox for Android
 
 Contents:
 
 .. toctree::
    :maxdepth: 2
 
    localeswitching
    uitelemetry
+   activitystreamtelemetry
    adjust
    defaultdomains
    bouncer
    shutdown
    push
 
 Indices and tables
 ==================
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -854,18 +854,16 @@ pref("canvas.imagebitmap_extensions.enab
 //
 // This pref is checked only once, and the browser needs a restart to
 // pick up any changes.
 //
 // Values are -1 always on. 1 always off, 0 is auto as some platform perform
 // further checks.
 pref("accessibility.force_disabled", 0);
 
-pref("accessibility.ipc_architecture.enabled", true);
-
 pref("accessibility.AOM.enabled", false);
 
 #ifdef XP_WIN
 // Some accessibility tools poke at windows in the plugin process during setup
 // which can cause hangs.  To hack around this set accessibility.delay_plugins
 // to true, you can also try increasing accessibility.delay_plugin_time if your
 // machine is slow and you still experience hangs.
 // See bug 781791.
--- a/old-configure.in
+++ b/old-configure.in
@@ -41,17 +41,17 @@ dnl ====================================
 _SUBDIR_HOST_CFLAGS="$HOST_CFLAGS"
 _SUBDIR_HOST_CXXFLAGS="$HOST_CXXFLAGS"
 _SUBDIR_HOST_LDFLAGS="$HOST_LDFLAGS"
 _SUBDIR_CONFIG_ARGS="$ac_configure_args"
 
 dnl Set the version number of the libs included with mozilla
 dnl ========================================================
 MOZJPEG=62
-MOZPNG=10627
+MOZPNG=10628
 NSPR_VERSION=4
 NSPR_MINVER=4.13.1
 NSS_VERSION=3
 
 dnl Set the minimum version of toolkit libs used by mozilla
 dnl ========================================================
 GLIB_VERSION=2.22
 # 2_26 is the earliest version we can set GLIB_VERSION_MIN_REQUIRED.
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/dedicated-worker/eventsource-close.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-close.htm]
-  type: testharness
-  [dedicated worker - EventSource: close()]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/dedicated-worker/eventsource-constructor-non-same-origin.htm.ini
+++ /dev/null
@@ -1,20 +0,0 @@
-[eventsource-constructor-non-same-origin.htm]
-  type: testharness
-  [dedicated worker - EventSource: constructor (act as if there is a network error) (http://example.not/)]
-    expected: FAIL
-
-  [dedicated worker - EventSource: constructor (act as if there is a network error) (https://example.not/test)]
-    expected: FAIL
-
-  [dedicated worker - EventSource: constructor (act as if there is a network error) (ftp://example.not/)]
-    expected: FAIL
-
-  [dedicated worker - EventSource: constructor (act as if there is a network error) (about:blank)]
-    expected: FAIL
-
-  [dedicated worker - EventSource: constructor (act as if there is a network error) (mailto:whatwg@awesome.example)]
-    expected: FAIL
-
-  [dedicated worker - EventSource: constructor (act as if there is a network error) (javascript:alert('FAIL'))]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/dedicated-worker/eventsource-constructor-url-bogus.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-constructor-url-bogus.htm]
-  type: testharness
-  [dedicated worker - EventSource: constructor (invalid URL)]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/dedicated-worker/eventsource-eventtarget.worker.js.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-[eventsource-eventtarget.worker]
-  type: testharness
-  [dedicated worker - EventSource: addEventListener()]
-    expected: FAIL
-
-
-[eventsource-eventtarget.worker.html]
-  type: testharness
-  [dedicated worker - EventSource: addEventListener()]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/dedicated-worker/eventsource-onmesage.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-onmesage.htm]
-  type: testharness
-  [dedicated worker - EventSource: onmessage]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/dedicated-worker/eventsource-onopen.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-onopen.htm]
-  type: testharness
-  [dedicated worker - EventSource: onopen (announcing the connection)]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/dedicated-worker/eventsource-prototype.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-prototype.htm]
-  type: testharness
-  [dedicated worker - EventSource: prototype et al]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/dedicated-worker/eventsource-url.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-url.htm]
-  type: testharness
-  [dedicated worker - EventSource: url]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/shared-worker/eventsource-close.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-close.htm]
-  type: testharness
-  [shared worker - EventSource: close()]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/shared-worker/eventsource-constructor-non-same-origin.htm.ini
+++ /dev/null
@@ -1,20 +0,0 @@
-[eventsource-constructor-non-same-origin.htm]
-  type: testharness
-  [shared worker - EventSource: constructor (act as if there is a network error) (http://example.not)]
-    expected: FAIL
-
-  [shared worker - EventSource: constructor (act as if there is a network error) (https://example.not/test)]
-    expected: FAIL
-
-  [shared worker - EventSource: constructor (act as if there is a network error) (ftp://example.not)]
-    expected: FAIL
-
-  [shared worker - EventSource: constructor (act as if there is a network error) (about:blank)]
-    expected: FAIL
-
-  [shared worker - EventSource: constructor (act as if there is a network error) (mailto:whatwg@awesome.example)]
-    expected: FAIL
-
-  [shared worker - EventSource: constructor (act as if there is a network error) (javascript:alert('FAIL'))]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/shared-worker/eventsource-constructor-url-bogus.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-constructor-url-bogus.htm]
-  type: testharness
-  [shared worker - EventSource: constructor (invalid URL)]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/shared-worker/eventsource-eventtarget.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-eventtarget.htm]
-  type: testharness
-  [shared worker - EventSource: addEventListener()]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/shared-worker/eventsource-onmesage.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-onmesage.htm]
-  type: testharness
-  [shared worker - EventSource: onmessage]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/shared-worker/eventsource-onopen.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-onopen.htm]
-  type: testharness
-  [shared worker - EventSource: onopen (announcing the connection)]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/shared-worker/eventsource-prototype.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-prototype.htm]
-  type: testharness
-  [shared worker - EventSource: prototype et al]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/eventsource/shared-worker/eventsource-url.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[eventsource-url.htm]
-  type: testharness
-  [shared worker - EventSource: url]
-    expected: FAIL
-
--- a/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-checkValidity.html.ini
+++ b/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-checkValidity.html.ini
@@ -28,29 +28,14 @@
     expected: FAIL
 
   [[INPUT in EMAIL status\] suffering from being too long (in a form)]
     expected: FAIL
 
   [[INPUT in DATETIME status\] The datetime type must be supported.]
     expected: FAIL
 
-  [[INPUT in DATETIME-LOCAL status\] The datetime-local type must be supported.]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] suffering from an overflow]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] suffering from an overflow (in a form)]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] suffering from an underflow]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] suffering from an underflow (in a form)]
-    expected: FAIL
-
   [[INPUT in DATETIME-LOCAL status\] suffering from a step mismatch]
     expected: FAIL
 
   [[INPUT in DATETIME-LOCAL status\] suffering from a step mismatch (in a form)]
     expected: FAIL
 
--- a/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-reportValidity.html.ini
+++ b/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-reportValidity.html.ini
@@ -34,29 +34,14 @@
     expected: FAIL
 
   [[INPUT in EMAIL status\] suffering from being too long (in a form)]
     expected: FAIL
 
   [[INPUT in DATETIME status\] The datetime type must be supported.]
     expected: FAIL
 
-  [[INPUT in DATETIME-LOCAL status\] The datetime-local type must be supported.]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] suffering from an overflow]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] suffering from an overflow (in a form)]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] suffering from an underflow]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] suffering from an underflow (in a form)]
-    expected: FAIL
-
   [[INPUT in DATETIME-LOCAL status\] suffering from a step mismatch]
     expected: FAIL
 
   [[INPUT in DATETIME-LOCAL status\] suffering from a step mismatch (in a form)]
     expected: FAIL
 
--- a/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-validity-rangeOverflow.html.ini
+++ b/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-validity-rangeOverflow.html.ini
@@ -1,23 +1,4 @@
 [form-validation-validity-rangeOverflow.html]
   type: testharness
   [[INPUT in DATETIME status\] The datetime type must be supported.]
     expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] The datetime-local type must be supported.]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] The value is greater than max]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] The value is greater than max(with millisecond in 1 digit)]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] The value is greater than max(with millisecond in 2 digits)]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL sta