Merge m-c to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 16 Sep 2014 07:07:55 +0200
changeset 228662 bda9c2c58b8886cc8954e733a8af92a8a48ef7d6
parent 228661 de389f79f43eb220128e1f408180980b78e212b7 (current diff)
parent 228658 3b7921328fc126999fa908e6379cbd555d028c50 (diff)
child 228663 11b2ef45231d0275db7a635e547d68eb4616968d
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team
js/src/tests/js1_7/block/regress-411279.js
js/src/tests/js1_8_1/regress/regress-452498-103.js
security/manager/ssl/src/nsNSSCleaner.cpp
security/manager/ssl/src/nsNSSCleaner.h
testing/mochitest/mochitest-e10s-utils-content.js
--- a/addon-sdk/source/lib/sdk/deprecated/symbiont.js
+++ b/addon-sdk/source/lib/sdk/deprecated/symbiont.js
@@ -175,17 +175,16 @@ const Symbiont = Worker.resolve({
             self._onInit();
           }
 
         });
       return;
     }
 
     let eventName = 'end' == this.contentScriptWhen ? 'load' : 'DOMContentLoaded';
-    let self = this;
     this._loadEvent = eventName;
     frame.addEventListener(eventName,
       this._loadListener = function _onReady(event) {
 
         if (event.target != frame.contentDocument)
           return;
         self._unregisterListener();
 
--- a/addon-sdk/source/lib/sdk/io/fs.js
+++ b/addon-sdk/source/lib/sdk/io/fs.js
@@ -643,35 +643,35 @@ exports.closeSync = closeSync;
  */
 let close = Async(closeSync);
 exports.close = close;
 
 /**
  * Synchronous open(2).
  */
 function openSync(path, flags, mode) {
-  let [ fd, flags, mode, file ] =
+  let [ fd, flags_, mode_, file ] =
       [ { path: path }, Flags(flags), Mode(mode), nsILocalFile(path) ];
 
   nsIFile(fd, file);
 
   // If trying to open file for just read that does not exists
   // need to throw exception as node does.
-  if (!file.exists() && !isWritable(flags))
+  if (!file.exists() && !isWritable(flags_))
     throw FSError("open", "ENOENT", 34, path);
 
   // If we want to open file in read mode we initialize input stream.
-  if (isReadable(flags)) {
-    let input = FileInputStream(file, flags, mode, DEFER_OPEN);
+  if (isReadable(flags_)) {
+    let input = FileInputStream(file, flags_, mode_, DEFER_OPEN);
     nsIFileInputStream(fd, input);
   }
 
   // If we want to open file in write mode we initialize output stream for it.
-  if (isWritable(flags)) {
-    let output = FileOutputStream(file, flags, mode, DEFER_OPEN);
+  if (isWritable(flags_)) {
+    let output = FileOutputStream(file, flags_, mode_, DEFER_OPEN);
     nsIFileOutputStream(fd, output);
   }
 
   return fd;
 }
 exports.openSync = openSync;
 /**
  * Asynchronous file open. See open(2). Flags can be
--- a/addon-sdk/source/lib/sdk/windows/fennec.js
+++ b/addon-sdk/source/lib/sdk/windows/fennec.js
@@ -59,17 +59,17 @@ function getBrowserWindow(options) {
 
   // if we have a BrowserWindow already then use it
   if ('window' in options)
     window = getRegisteredWindow(options.window);
   if (window)
     return window;
 
   // we don't have a BrowserWindow yet, so create one
-  var window = BrowserWindow(options);
+  window = BrowserWindow(options);
   addListItem(browserWindows, window);
   return window;
 }
 
 WindowTracker({
   onTrack: function onTrack(chromeWindow) {
     if (!isBrowser(chromeWindow)) return;
     let window = getBrowserWindow({ window: chromeWindow });
--- a/browser/base/content/aboutSocialError.xhtml
+++ b/browser/base/content/aboutSocialError.xhtml
@@ -56,17 +56,17 @@
           document.getElementById("btnCloseSidebar").style.display = 'none';
           break;
         case "tryAgainOnly":
           document.getElementById("btnCloseSidebar").style.display = 'none';
           //intentional fall-through
         case "tryAgain":
           let urlMatch = queryString.match(/url=([^&]+)/);
           let encodedURL = urlMatch && urlMatch[1] ? urlMatch[1] : "";
-          let url = decodeURIComponent(encodedURL);
+          url = decodeURIComponent(encodedURL);
 
           config.tryAgainCallback = loadQueryURL;
           config.queryURL = url;
           break;
         case "workerFailure":
           config.tryAgainCallback = reloadProvider;
           break;
         default:
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -1305,18 +1305,18 @@ var gPluginHandler = {
         accessKey: submitKey,
         popup: null,
           callback: function() { gPluginHandler.submitReport(pluginDumpID, browserDumpID); },
       };
       if (pluginDumpID)
         buttons.push(submitButton);
 #endif
 
-      let notification = notificationBox.appendNotification(messageString, "plugin-crashed",
-                                                            iconURL, priority, buttons);
+      notification = notificationBox.appendNotification(messageString, "plugin-crashed",
+                                                        iconURL, priority, buttons);
 
       // Add the "learn more" link.
       let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
       let link = notification.ownerDocument.createElementNS(XULNS, "label");
       link.className = "text-link";
       link.setAttribute("value", gNavigatorBundle.getString("crashedpluginsMessage.learnMore"));
       let crashurl = formatURL("app.support.baseURL", true);
       crashurl += "plugin-crashed-notificationbar";
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -735,17 +735,17 @@ nsContextMenu.prototype = {
 
       if (this.target.ownerDocument.isSrcdocDocument) {
           this.inSrcdocFrame = true;
       }
     }
 
     // if the document is editable, show context menu like in text inputs
     if (!this.onEditableArea) {
-      var win = this.target.ownerDocument.defaultView;
+      win = this.target.ownerDocument.defaultView;
       if (win) {
         var isEditable = false;
         try {
           var editingSession = win.QueryInterface(Ci.nsIInterfaceRequestor)
                                   .getInterface(Ci.nsIWebNavigation)
                                   .QueryInterface(Ci.nsIInterfaceRequestor)
                                   .getInterface(Ci.nsIEditingSession);
           if (editingSession.windowIsEditable(win) &&
--- a/browser/base/content/test/general/browser_bug1003461-switchtab-override.js
+++ b/browser/base/content/test/general/browser_bug1003461-switchtab-override.js
@@ -37,17 +37,17 @@ add_task(function* test_switchtab_overri
   EventUtils.synthesizeKey("e" , {});
   yield deferred.promise;
 
   info("Select first autocomplete popup entry");
   EventUtils.synthesizeKey("VK_DOWN" , {});
   ok(/moz-action:switchtab/.test(gURLBar.value), "switch to tab entry found");
 
   info("Override switch-to-tab");
-  let deferred = Promise.defer();
+  deferred = Promise.defer();
   // In case of failure this would switch tab.
   let onTabSelect = event => {
     deferred.reject(new Error("Should have overridden switch to tab"));
   };
   gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect, false);
   registerCleanupFunction(() => {
     gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect, false);
   });
--- a/browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js
+++ b/browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js
@@ -97,17 +97,17 @@ function get_test_function_for_localhost
     // check pref value
     let prefValue = Services.prefs.getBoolPref(pref);
     is(prefValue, !isPrivate, "Pref should have the correct state.");
 
     yield docLoadPromise;
     browser.removeTab(tab);
 
     // Now try again with the pref set.
-    let tab = browser.selectedTab = browser.addTab();
+    tab = browser.selectedTab = browser.addTab();
     // In a private window, the notification should appear again.
     yield* runURLBarSearchTest(hostName, isPrivate, isPrivate, win);
     browser.removeTab(tab);
     if (isPrivate) {
       info("Waiting for private window to close");
       yield promiseWindowClosed(win);
       let deferredFocus = Promise.defer();
       info("Waiting for focus");
--- a/browser/base/content/test/newtab/browser_newtab_enhanced.js
+++ b/browser/base/content/test/newtab/browser_newtab_enhanced.js
@@ -44,35 +44,35 @@ function runTests() {
   isnot(enhanced, "", "directory link has enhanced image");
   is(title, "title");
 
   is(getData(1), null, "history link pushed out by directory link");
 
   // Test with enhanced = true
   NewTabUtils.allPages.enhanced = true;
   yield addNewTabPageTab();
-  let {type, enhanced, title} = getData(0);
+  ({type, enhanced, title} = getData(0));
   is(type, "organic", "directory link is still organic");
   isnot(enhanced, "", "directory link still has enhanced image");
   is(title, "title");
 
   is(getData(1), null, "history link still pushed out by directory link");
 
   // Test with a pinned link
   setPinnedLinks("-1");
   yield addNewTabPageTab();
-  let {type, enhanced, title} = getData(0);
+  ({type, enhanced, title} = getData(0));
   is(type, "enhanced", "pinned history link is enhanced");
   isnot(enhanced, "", "pinned history link has enhanced image");
   is(title, "title");
 
   is(getData(1), null, "directory link pushed out by pinned history link");
 
   // Test pinned link with enhanced = false
   NewTabUtils.allPages.enhanced = false;
   yield addNewTabPageTab();
-  let {type, enhanced, title} = getData(0);
+  ({type, enhanced, title} = getData(0));
   isnot(type, "enhanced", "history link is not enhanced");
   is(enhanced, "", "history link has no enhanced image");
   is(title, "site#-1");
 
   is(getData(1), null, "directory link still pushed out by pinned history link");
 }
--- a/browser/base/content/test/plugins/browser_pageInfo_plugins.js
+++ b/browser/base/content/test/plugins/browser_pageInfo_plugins.js
@@ -65,17 +65,17 @@ function test() {
 }
 
 // The first test plugin is CtP and the second test plugin is enabled.
 function testPart1a() {
   let test = gTestBrowser.contentDocument.getElementById("test");
   let objLoadingContent = test.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "part 1a: Test plugin should not be activated");
   let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA");
-  let objLoadingContent = secondtest.QueryInterface(Ci.nsIObjectLoadingContent);
+  objLoadingContent = secondtest.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "part 1a: Second Test plugin should be activated");
 
   doOnOpenPageInfo(testPart1b);
 }
 
 function testPart1b() {
   let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
   let testRadioDefault = gPageInfo.document.getElementById(gTestPermissionString + "#0");
--- a/browser/base/content/webrtcIndicator.js
+++ b/browser/base/content/webrtcIndicator.js
@@ -142,17 +142,17 @@ let PositionHandler = {
                     availTop.value);
     } else {
       // This will ensure we're at y=0.
       this.setXPosition(window.screenX);
     }
   },
   setXPosition: function(desiredX) {
     // Ensure the indicator isn't moved outside the available area of the screen.
-    let desiredX = Math.max(desiredX, screen.availLeft);
+    desiredX = Math.max(desiredX, screen.availLeft);
     let maxX =
       screen.availLeft + screen.availWidth - document.documentElement.clientWidth;
     window.moveTo(Math.min(desiredX, maxX), screen.availTop);
   },
   handleEvent: function(aEvent) {
     switch (aEvent.type) {
       case "mousedown":
         if (aEvent.button != 0 || aEvent.defaultPrevented)
--- a/browser/components/customizableui/test/browser_884402_customize_from_overflow.js
+++ b/browser/components/customizableui/test/browser_884402_customize_from_overflow.js
@@ -69,14 +69,14 @@ add_task(function() {
   ok(homeButtonPlacement, "Home button should still have a placement");
   is(homeButtonPlacement && homeButtonPlacement.area, "PanelUI-contents", "Home button should be in the panel now");
   CustomizableUI.reset();
 
   // In some cases, it can take a tick for the navbar to overflow again. Wait for it:
   yield waitForCondition(() => navbar.hasAttribute("overflowing"));
   ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
 
-  let homeButtonPlacement = CustomizableUI.getPlacementOfWidget("home-button");
+  homeButtonPlacement = CustomizableUI.getPlacementOfWidget("home-button");
   ok(homeButtonPlacement, "Home button should still have a placement");
   is(homeButtonPlacement && homeButtonPlacement.area, "nav-bar", "Home button should be back in the navbar now");
 
   is(homeButton.getAttribute("overflowedItem"), "true", "Home button should still be overflowed");
 });
--- a/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js
+++ b/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js
@@ -29,17 +29,17 @@ add_task(function() {
                        "Placements should have changed because widget is removable.");
   let btn = document.getElementById(kButtonId);
   btn.setAttribute("removable", "false");
   gLazyArea.customizationTarget = gLazyArea;
   CustomizableUI.registerToolbarNode(gLazyArea, []);
   assertAreaPlacements(kLazyAreaId, [], "Placements should no longer include widget.");
   is(btn.parentNode.id, gNavBar.customizationTarget.id,
      "Button shouldn't actually have moved as it's not removable");
-  let btn = document.getElementById(kButtonId);
+  btn = document.getElementById(kButtonId);
   if (btn) btn.remove();
   CustomizableUI.removeWidgetFromArea(kButtonId);
   CustomizableUI.unregisterArea(kLazyAreaId);
   gLazyArea.remove();
 });
 
 add_task(function asyncCleanup() {
   yield resetCustomization();
--- a/browser/components/customizableui/test/browser_888817_currentset_updating.js
+++ b/browser/components/customizableui/test/browser_888817_currentset_updating.js
@@ -7,17 +7,17 @@
 // Adding, moving and removing items should update the relevant currentset attributes
 add_task(function() {
   ok(CustomizableUI.inDefaultState, "Should be in the default state when we start");
   let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
   setToolbarVisibility(personalbar, true);
   ok(!CustomizableUI.inDefaultState, "Making the bookmarks toolbar visible takes it out of the default state");
 
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
-  let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
+  personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
   let navbarCurrentset = navbar.getAttribute("currentset") || navbar.currentSet;
   let personalbarCurrentset = personalbar.getAttribute("currentset") || personalbar.currentSet;
 
   let otherWin = yield openAndLoadWindow();
   let otherNavbar = otherWin.document.getElementById(CustomizableUI.AREA_NAVBAR);
   let otherPersonalbar = otherWin.document.getElementById(CustomizableUI.AREA_BOOKMARKS);
 
   CustomizableUI.moveWidgetWithinArea("home-button", 0);
--- a/browser/components/customizableui/test/browser_901207_searchbar_in_panel.js
+++ b/browser/components/customizableui/test/browser_901207_searchbar_in_panel.js
@@ -84,17 +84,17 @@ add_task(function() {
   let chevron = document.getElementById("nav-bar-overflow-button");
   yield waitForCondition(function() chevron.open);
 
   yield waitForSearchBarFocus();
 
   let hiddenPanelPromise = promiseOverflowHidden(window);
   EventUtils.synthesizeKey("VK_ESCAPE", {});
   yield hiddenPanelPromise;
-  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+  navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
   window.resizeTo(this.originalWindowWidth, window.outerHeight);
   yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
   ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar.");
 });
 
 // Ctrl+K should focus the search bar if it is in the navbar and not overflowing.
 add_task(function() {
   let placement = CustomizableUI.getPlacementOfWidget("search-container");
--- a/browser/components/customizableui/test/browser_952963_areaType_getter_no_area.js
+++ b/browser/components/customizableui/test/browser_952963_areaType_getter_no_area.js
@@ -30,17 +30,17 @@ add_task(function() {
   checkAreaType(w);
 
   w = CustomizableUI.getWidget(kTestWidget);
   checkAreaType(w);
 
   let spec = {id: kUnregisterAreaTestWidget, type: 'button', removable: true,
               label: "areaType test", tooltiptext: "areaType test"};
   CustomizableUI.createWidget(spec);
-  let toolbarNode = createToolbarWithPlacements(kToolbarName, [kUnregisterAreaTestWidget]);
+  toolbarNode = createToolbarWithPlacements(kToolbarName, [kUnregisterAreaTestWidget]);
   CustomizableUI.unregisterArea(kToolbarName);
   toolbarNode.remove();
   w = CustomizableUI.getWidget(spec.id);
   checkAreaType(w);
   CustomizableUI.removeWidgetFromArea(kUnregisterAreaTestWidget);
   checkAreaType(w);
   //XXXgijs: ensure cleanup function doesn't barf:
   gAddedToolbars.delete(kToolbarName);
--- a/browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js
+++ b/browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js
@@ -26,35 +26,35 @@ add_task(function() {
 
   characterEncoding.setAttribute("label", kNormalLabel);
 
   yield PanelUI.show();
 
   isnot(characterEncoding.getAttribute("auto-hyphens"), "off",
         "Hyphens should not be disabled if the &shy; character is not present in the label");
   multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
-  let multilineTextCS = getComputedStyle(multilineText);
+  multilineTextCS = getComputedStyle(multilineText);
   is(multilineTextCS.MozHyphens, "auto", "-moz-hyphens should be set to auto by default.")
 
   hiddenPanelPromise = promisePanelHidden(window);
   PanelUI.toggle();
   yield hiddenPanelPromise;
 
   characterEncoding.setAttribute("label", "\u00ad" + kNormalLabel);
   CustomizableUI.removeWidgetFromArea("characterencoding-button");
   yield startCustomizing();
 
   isnot(characterEncoding.getAttribute("auto-hyphens"), "off",
         "Hyphens should not be disabled when the widget is in the palette");
 
   gCustomizeMode.addToPanel(characterEncoding);
   is(characterEncoding.getAttribute("auto-hyphens"), "off",
      "Hyphens should be disabled if the &shy; character is present in the label in customization mode");
-  let multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
-  let multilineTextCS = getComputedStyle(multilineText);
+  multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text");
+  multilineTextCS = getComputedStyle(multilineText);
   is(multilineTextCS.MozHyphens, "manual", "-moz-hyphens should be set to manual when the &shy; character is present in customization mode.")
 
   yield endCustomizing();
 
   CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_NAVBAR);
   ok(!characterEncoding.hasAttribute("auto-hyphens"),
      "Removing the widget from the panel should remove the auto-hyphens attribute");
 
--- a/browser/components/customizableui/test/browser_987492_window_api.js
+++ b/browser/components/customizableui/test/browser_987492_window_api.js
@@ -40,15 +40,15 @@ add_task(function* testOpenCloseWindow()
     }
   }
   CustomizableUI.addListener(closeListener);
   yield promiseWindowClosed(newWindow);
   isnot(closedWindow, null, "Should have gotten onWindowClosed event")
   is(newWindow, closedWindow, "Closed window should match previously opened window");
   CustomizableUI.removeListener(closeListener);
 
-  let windows = [];
+  windows = [];
   for (let win of CustomizableUI.windows)
     windows.push(win);
   is(windows.length, 1, "Should have one customizable window");
   isnot(windows.indexOf(window), -1, "Current window should be in window collection.");
   is(windows.indexOf(closedWindow), -1, "Closed window should not be in window collection.");
 });
--- a/browser/components/customizableui/test/browser_987640_charEncoding.js
+++ b/browser/components/customizableui/test/browser_987640_charEncoding.js
@@ -43,17 +43,17 @@ add_task(function() {
   // reset the initial encoding
   yield PanelUI.show();
   charEncodingButton.click();
   tabLoadPromise = promiseTabLoadEvent(gBrowser.selectedTab, TEST_PAGE);
   initialEncoding.click();
   yield tabLoadPromise;
   yield PanelUI.show();
   charEncodingButton.click();
-  let checkedButtons = characterEncodingView.querySelectorAll("toolbarbutton[checked='true']");
+  checkedButtons = characterEncodingView.querySelectorAll("toolbarbutton[checked='true']");
   is(checkedButtons[0].getAttribute("label"), "Unicode", "The encoding was reset to Unicode");
 });
 
 add_task(function asyncCleanup() {
   // reset the panel to the default state
   yield resetCustomization();
   ok(CustomizableUI.inDefaultState, "The UI is in default state again.");
 
--- a/browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js
+++ b/browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js
@@ -45,23 +45,23 @@ function checkRestoredPresence(aWidgetID
     CustomizableUI.addWidgetToArea(aWidgetID, kTestBarID);
     let placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
     is(placement.area, kTestBarID,
        "Expected " + aWidgetID + " to be in the test toolbar");
 
     CustomizableUI.unregisterArea(testBar.id);
     testBar.remove();
 
-    let placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
+    placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
     is(placement, null, "Expected " + aWidgetID + " to be in the palette");
 
     testBar = createTestBar(aLegacy);
 
     yield startCustomizing();
-    let placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
+    placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
     is(placement.area, kTestBarID,
        "Expected " + aWidgetID + " to be in the test toolbar");
     yield endCustomizing();
 
     CustomizableUI.unregisterArea(testBar.id);
     testBar.remove();
 
     yield resetCustomization();
--- a/browser/components/loop/test/mochitest/browser_CardDavImporter.js
+++ b/browser/components/loop/test/mochitest/browser_CardDavImporter.js
@@ -322,43 +322,43 @@ add_task(function* test_CardDavImport() 
         "host": "example.com",
         "auth": kAuth.method,
         "user": kAuth.user,
         "password": "invalidpassword"
       }, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
   });
   Assert.equal(error.message, "401 Auth Failure", "Auth error should propagate");
 
-  let error = yield new Promise ((resolve, reject) => {
+  error = yield new Promise ((resolve, reject) => {
     info("Initiating import");
     importer.startImport({
         "host": "example.invalid",
         "auth": kAuth.method,
         "user": kAuth.user,
         "password": kAuth.password
       }, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
   });
   Assert.equal(error.message, "404 Not Found", "Not found error should propagate");
 
   let tmp = mockDb.getByServiceId;
   mockDb.getByServiceId = function(serviceId, callback) {
     callback(new Error("getByServiceId failed"));
   };
-  let error = yield new Promise ((resolve, reject) => {
+  error = yield new Promise ((resolve, reject) => {
     info("Initiating import");
     importer.startImport({
         "host": "example.com",
         "auth": kAuth.method,
         "user": kAuth.user,
         "password": kAuth.password
       }, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
   });
   Assert.equal(error.message, "getByServiceId failed", "Database error should propagate");
   mockDb.getByServiceId = tmp;
 
-  let error = yield new Promise ((resolve, reject) => {
+  error = yield new Promise ((resolve, reject) => {
     info("Initiating import");
     importer.startImport({
         "host": "example.com",
       }, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
   });
   Assert.equal(error.message, "No authentication specified", "Missing parameters should generate error");
 })
--- a/browser/components/loop/test/mochitest/browser_LoopContacts.js
+++ b/browser/components/loop/test/mochitest/browser_LoopContacts.js
@@ -188,26 +188,26 @@ add_task(function* () {
   LoopContacts.get(contacts[1]._guid, (err, contact) => {
     Assert.ok(!err, "There shouldn't be an error");
     compareContacts(contact, kContacts[1]);
     deferred.resolve();
   });
   yield deferred.promise;
 
   info("Get a single contact by id.");
-  let deferred = Promise.defer();
+  deferred = Promise.defer();
   LoopContacts.getByServiceId(2, (err, contact) => {
     Assert.ok(!err, "There shouldn't be an error");
     compareContacts(contact, kContacts[1]);
     deferred.resolve();
   });
   yield deferred.promise;
 
   info("Get a couple of contacts.");
-  let deferred = Promise.defer();
+  deferred = Promise.defer();
   let toRetrieve = [contacts[0], contacts[2], contacts[3]];
   LoopContacts.getMany(toRetrieve.map(contact => contact._guid), (err, result) => {
     Assert.ok(!err, "There shouldn't be an error");
     Assert.equal(result.length, toRetrieve.length, "Result list should be the same " +
                  "size as the list of items to retrieve");
     for (let contact of toRetrieve) {
       let found = result.filter(c => c._guid == contact._guid);
       Assert.ok(found.length, "Contact " + contact._guid + " should be in the list");
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2165,19 +2165,19 @@ let DefaultBrowserCheck = {
     let label = bundle.getString("setDefaultBrowserNotNow.label");
     notNowItem.setAttribute("label", label);
     let accesskey = bundle.getString("setDefaultBrowserNotNow.accesskey");
     notNowItem.setAttribute("accesskey", accesskey);
     popup.appendChild(notNowItem);
 
     let neverItem = doc.createElement("menuitem");
     neverItem.id = "defaultBrowserNever";
-    let label = bundle.getString("setDefaultBrowserNever.label");
+    label = bundle.getString("setDefaultBrowserNever.label");
     neverItem.setAttribute("label", label);
-    let accesskey = bundle.getString("setDefaultBrowserNever.accesskey");
+    accesskey = bundle.getString("setDefaultBrowserNever.accesskey");
     neverItem.setAttribute("accesskey", accesskey);
     popup.appendChild(neverItem);
 
     popup.addEventListener("command", this);
 
     let popupset = doc.getElementById("mainPopupSet");
     popupset.appendChild(popup);
   },
--- a/browser/components/places/tests/unit/test_421483.js
+++ b/browser/components/places/tests/unit/test_421483.js
@@ -41,17 +41,17 @@ add_task(function create_smart_bookmarks
 add_task(function remove_smart_bookmark_and_restore() {
   let smartBookmarkItemIds =
     PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
   let smartBookmarksCount = smartBookmarkItemIds.length;
   do_log_info("remove one smart bookmark and restore");
   PlacesUtils.bookmarks.removeItem(smartBookmarkItemIds[0]);
   Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0);
   gluesvc.ensurePlacesDefaultQueriesInitialized();
-  let smartBookmarkItemIds =
+  smartBookmarkItemIds =
     PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
   do_check_eq(smartBookmarkItemIds.length, smartBookmarksCount);
   do_log_info("check that pref has been bumped up");
   do_check_true(Services.prefs.getIntPref("browser.places.smartBookmarksVersion") > 0);
 });
 
 add_task(function move_smart_bookmark_rename_and_restore() {
   let smartBookmarkItemIds =
--- a/browser/components/preferences/tests/browser_chunk_permissions.js
+++ b/browser/components/preferences/tests/browser_chunk_permissions.js
@@ -116,21 +116,21 @@ var tests = [
   },
   {
     desc: "test removing from sites-list before it is fully constructed.",
     preInit: function() {
       ForgetAboutSite.removeDataFromDomain(TEST_URI_2.host);
     },
     run: function() {
       let testSite1 = getSiteItem(TEST_URI_1.host);
-      ok(!testSite2, "test site 1 was not removed from sites list");
+      ok(testSite1, "test site 1 was not removed from sites list");
       let testSite2 = getSiteItem(TEST_URI_2.host);
       ok(!testSite2, "test site 2 was pre-removed from sites list");
       let testSite3 = getSiteItem(TEST_URI_3.host);
-      ok(!testSite2, "test site 3 was not removed from sites list");
+      ok(testSite3, "test site 3 was not removed from sites list");
 
       runNextTest();
     }
   }
 ];
 
 function getSiteItem(aHost) {
   return gBrowser.contentDocument.
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js
@@ -233,18 +233,18 @@ function runTest() {
    * ====================
    */
 
   // check that the last dir store got cleared in a new PB window
   pbWin.close();
   // And give it time to close
   executeSoon(moveAlong);
   yield;
-  let pbWin = yield createWindow({private: true});
-  let pbDownloadLastDir = new DownloadLastDir(pbWin);
+  pbWin = yield createWindow({private: true});
+  pbDownloadLastDir = new DownloadLastDir(pbWin);
 
   is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory");
 
   yield clearHistoryAndWait();
 
   // check clearHistory inside PB mode clears data outside PB mode
   yield setFile(pbDownloadLastDir, uri1, dir2);
 
--- a/browser/components/search/test/browser_426329.js
+++ b/browser/components/search/test/browser_426329.js
@@ -246,17 +246,17 @@ add_task(function testDropInternalText()
   let event = yield promiseOnLoad();
   is(event.originalTarget.URL, expectedURL(searchBar.value), "testDropInternalText opened correct search page");
   is(searchBar.value, "More Text", "drop text/x-moz-text-internal on searchbar");
 
   // testDropLink implicitly depended on testDropInternalText, so these two tests
   // were merged so that if testDropInternalText failed it wouldn't cause testDropLink
   // to fail unexplainably.
   yield prepareTest();
-  let promisePreventPopup = promiseEvent(searchBar, "popupshowing", true);
+  promisePreventPopup = promiseEvent(searchBar, "popupshowing", true);
   ChromeUtils.synthesizeDrop(searchBar.searchButton, searchBar.searchButton, [[ {type: "text/uri-list", data: "http://www.mozilla.org" } ]], "copy", window);
   yield promisePreventPopup;
   is(searchBar.value, "More Text", "drop text/uri-list on searchbar shouldn't change anything");
 });
 
 add_task(function testRightClick() {
   preTabNo = gBrowser.tabs.length;
   content.location.href = "about:blank";
--- a/browser/components/sessionstore/test/browser_463205.js
+++ b/browser/components/sessionstore/test/browser_463205.js
@@ -22,17 +22,17 @@ add_task(function test_check_urls_before
 
   let value = yield getInputValue(browser, {id: "text"});
   is(value, "foobar", "value was restored");
 
   // Restore form data with an invalid URL.
   ss.setTabState(tab, getState("http://example.com/"));
   yield promiseTabRestored(tab);
 
-  let value = yield getInputValue(browser, {id: "text"});
+  value = yield getInputValue(browser, {id: "text"});
   is(value, "", "value was not restored");
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 function getState(url) {
   return JSON.stringify({
--- a/browser/components/sessionstore/test/browser_662743.js
+++ b/browser/components/sessionstore/test/browser_662743.js
@@ -84,17 +84,17 @@ function testTabRestoreData(aFormData, a
       }
 
       // test select options values
       is(value, aExpectedValue,
         "Select Option by selectedIndex &/or value has been restored correctly");
 
       let restoredFormData = restoredTabState.formdata;
       let selectIdFormData = restoredFormData.id.select_id;
-      let value = restoredFormData.id.select_id.value;
+      value = restoredFormData.id.select_id.value;
 
       // test format
       ok("id" in restoredFormData || "xpath" in restoredFormData,
         "FormData format is valid");
       // test format
       ok("selectedIndex" in selectIdFormData && "value" in selectIdFormData,
         "select format is valid");
        // test set collection values
--- a/browser/components/sessionstore/test/browser_attributes.js
+++ b/browser/components/sessionstore/test/browser_attributes.js
@@ -29,17 +29,17 @@ function runTests() {
   let {attributes} = JSON.parse(ss.getTabState(tab));
   ok(!("image" in attributes), "'image' attribute not saved");
   ok(!("custom" in attributes), "'custom' attribute not saved");
 
   // Test persisting a custom attribute.
   tab.setAttribute("custom", "foobar");
   ss.persistTabAttribute("custom");
 
-  let {attributes} = JSON.parse(ss.getTabState(tab));
+  ({attributes} = JSON.parse(ss.getTabState(tab)));
   is(attributes.custom, "foobar", "'custom' attribute is correct");
 
   // Make sure we're backwards compatible and restore old 'image' attributes.
   let state = {
     entries: [{url: "about:mozilla"}],
     attributes: {custom: "foobaz", image: gBrowser.getIcon(tab)}
   };
 
@@ -50,17 +50,17 @@ function runTests() {
   ok(tab.hasAttribute("pending"), "tab is pending");
   is(gBrowser.getIcon(tab), state.attributes.image, "tab has correct icon");
 
   // Let the pending tab load.
   gBrowser.selectedTab = tab;
   yield whenTabRestored(tab);
 
   // Ensure no 'image' or 'pending' attributes are stored.
-  let {attributes} = JSON.parse(ss.getTabState(tab));
+  ({attributes} = JSON.parse(ss.getTabState(tab)));
   ok(!("image" in attributes), "'image' attribute not saved");
   ok(!("pending" in attributes), "'pending' attribute not saved");
   is(attributes.custom, "foobaz", "'custom' attribute is correct");
 
   // Clean up.
   gBrowser.removeTab(tab);
 }
 
--- a/browser/components/sessionstore/test/browser_broadcast.js
+++ b/browser/components/sessionstore/test/browser_broadcast.js
@@ -54,18 +54,18 @@ add_task(function flush_on_duplicate() {
 
   yield modifySessionStorage(browser, {test: "on-duplicate"});
   let tab2 = ss.duplicateTab(window, tab);
   let {storage} = JSON.parse(ss.getTabState(tab2));
   is(storage["http://example.com"].test, "on-duplicate",
     "sessionStorage data has been flushed when duplicating tabs");
 
   yield promiseTabRestored(tab2);
-  gBrowser.removeTab(tab2)
-  let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
+  gBrowser.removeTab(tab2);
+  [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://example.com"].test, "on-duplicate",
     "sessionStorage data has been flushed when duplicating tabs");
 
   gBrowser.removeTab(tab);
 });
 
 /**
  * This test ensures we won't lose tab data queued in the content script when
--- a/browser/components/sessionstore/test/browser_dynamic_frames.js
+++ b/browser/components/sessionstore/test/browser_dynamic_frames.js
@@ -72,17 +72,17 @@ add_task(function () {
   is(entries.length, 1, "there is one root entry ...");
   is(entries[0].children.length, 1, "... with a single child entry");
 
   // Navigate the subframe.
   browser.messageManager.sendAsyncMessage("ss-test:click", {id: "lnk"});
   yield promiseBrowserLoaded(browser, false /* don't ignore subframes */);
 
   SyncHandlers.get(browser).flush();
-  let {entries} = JSON.parse(ss.getTabState(tab));
+  ({entries} = JSON.parse(ss.getTabState(tab)));
 
   // Check URLs.
   ok(entries[0].url.startsWith("data:text/html"), "correct 1st root url");
   ok(entries[1].url.startsWith("data:text/html"), "correct 2nd root url");
   is(entries[0].children[0].url, "about:mozilla", "correct url for 1st static frame");
   is(entries[1].children[0].url, "about:robots", "correct url for 2ns static frame");
 
   // Check the number of children.
--- a/browser/components/sessionstore/test/browser_formdata.js
+++ b/browser/components/sessionstore/test/browser_formdata.js
@@ -38,25 +38,25 @@ add_task(function test_formdata() {
   let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
   is(formdata.id.txt, OUTER_VALUE, "outer value is correct");
   is(formdata.children[0].id.txt, INNER_VALUE, "inner value is correct");
 
   // Disable saving data for encrypted sites.
   Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1);
 
   yield createAndRemoveTab();
-  let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
+  [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
   is(formdata.id.txt, OUTER_VALUE, "outer value is correct");
   ok(!formdata.children, "inner value was *not* stored");
 
   // Disable saving data for any site.
   Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2);
 
   yield createAndRemoveTab();
-  let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
+  [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
   ok(!formdata, "form data has *not* been stored");
 
   // Restore the default privacy level.
   Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
 });
 
 /**
  * This test ensures that we maintain backwards compatibility with the form
@@ -171,23 +171,23 @@ add_task(function test_nested() {
 
   // Remove the tab and check that we stored form data correctly.
   gBrowser.removeTab(tab);
   let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
   is(JSON.stringify(formdata), JSON.stringify(FORM_DATA),
     "formdata for iframe stored correctly");
 
   // Restore the closed tab.
-  let tab = ss.undoCloseTab(window, 0);
-  let browser = tab.linkedBrowser;
+  tab = ss.undoCloseTab(window, 0);
+  browser = tab.linkedBrowser;
   yield promiseTabRestored(tab);
 
   // Check that the input field has the right value.
   SyncHandlers.get(browser).flush();
-  let {formdata} = JSON.parse(ss.getTabState(tab));
+  ({formdata} = JSON.parse(ss.getTabState(tab)));
   is(JSON.stringify(formdata), JSON.stringify(FORM_DATA),
     "formdata for iframe restored correctly");
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
@@ -219,18 +219,18 @@ add_task(function test_design_mode() {
 
   // Close and restore the tab.
   gBrowser.removeTab(tab);
   tab = ss.undoCloseTab(window, 0);
   browser = tab.linkedBrowser;
   yield promiseTabRestored(tab);
 
   // Check that the innerHTML value was restored.
-  let html = yield getInnerHTML(browser);
-  let expected = "<h1>Mmozilla</h1><script>document.designMode='on'</script>";
+  html = yield getInnerHTML(browser);
+  expected = "<h1>Mmozilla</h1><script>document.designMode='on'</script>";
   is(html, expected, "editable document has been restored correctly");
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * This test ensures that credit card numbers in form data will not be
--- a/browser/components/sessionstore/test/browser_label_and_icon.js
+++ b/browser/components/sessionstore/test/browser_label_and_icon.js
@@ -26,17 +26,17 @@ add_task(function test_label_and_icon() 
 
   // Retrieve the tab state.
   SyncHandlers.get(browser).flush();
   let state = ss.getTabState(tab);
   gBrowser.removeTab(tab);
   browser = null;
 
   // Open a new tab to restore into.
-  let tab = gBrowser.addTab("about:blank");
+  tab = gBrowser.addTab("about:blank");
   ss.setTabState(tab, state);
   yield promiseTabRestoring(tab);
 
   // Check that label and icon are set for the restoring tab.
   ok(gBrowser.getIcon(tab).startsWith("data:image/png;"), "icon is set");
   is(tab.label, "Gort! Klaatu barada nikto!", "label is set");
 
   // Cleanup.
--- a/browser/components/sessionstore/test/browser_privatetabs.js
+++ b/browser/components/sessionstore/test/browser_privatetabs.js
@@ -87,23 +87,23 @@ add_task(function () {
   let state = JSON.parse(ss.getTabState(tab));
   ok(state.isPrivate, "tab considered private");
 
   // Ensure we don't allow restoring closed private tabs in non-private windows.
   win.gBrowser.removeTab(tab);
   is(ss.getClosedTabCount(win), 0, "no tabs to restore");
 
   // Create a new tab in the new window that will load the frame script.
-  let tab = win.gBrowser.addTab("about:mozilla");
-  let browser = tab.linkedBrowser;
+  tab = win.gBrowser.addTab("about:mozilla");
+  browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
   SyncHandlers.get(browser).flush();
 
   // Check that we consider the tab as private.
-  let state = JSON.parse(ss.getTabState(tab));
+  state = JSON.parse(ss.getTabState(tab));
   ok(state.isPrivate, "tab considered private");
 
   // Check that all private tabs are removed when the non-private
   // window is closed and we don't save windows without any tabs.
   yield promiseWindowClosed(win);
   is(ss.getClosedWindowCount(), 0, "no windows to restore");
 });
 
--- a/browser/components/sessionstore/test/browser_sessionHistory.js
+++ b/browser/components/sessionstore/test/browser_sessionHistory.js
@@ -47,17 +47,17 @@ add_task(function test_purge() {
   let {entries} = JSON.parse(ss.getTabState(tab));
   is(entries.length, 2, "there are two shistory entries");
 
   // Purge session history.
   yield sendMessage(browser, "ss-test:purgeSessionHistory");
 
   // Check that we are left with a single shistory entry.
   SyncHandlers.get(browser).flush();
-  let {entries} = JSON.parse(ss.getTabState(tab));
+  ({entries} = JSON.parse(ss.getTabState(tab)));
   is(entries.length, 1, "there is one shistory entry");
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * Ensure that anchor navigation invalidates shistory.
@@ -76,17 +76,17 @@ add_task(function test_hashchange() {
   is(entries.length, 1, "there is one shistory entry");
 
   // Click the link and wait for a hashchange event.
   browser.messageManager.sendAsyncMessage("ss-test:click", {id: "a"});
   yield promiseContentMessage(browser, "ss-test:hashchange");
 
   // Check that we now have two shistory entries.
   SyncHandlers.get(browser).flush();
-  let {entries} = JSON.parse(ss.getTabState(tab));
+  ({entries} = JSON.parse(ss.getTabState(tab)));
   is(entries.length, 2, "there are two shistory entries");
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
  * Ensure that loading pages from the bfcache invalidates shistory.
@@ -139,31 +139,31 @@ add_task(function test_subframes() {
   is(entries[0].children.length, 1, "the entry has one child");
 
   // Navigate the subframe.
   browser.messageManager.sendAsyncMessage("ss-test:click", {id: "a1"});
   yield promiseBrowserLoaded(browser, false /* don't ignore subframes */);
 
   // Check shistory.
   SyncHandlers.get(browser).flush();
-  let {entries} = JSON.parse(ss.getTabState(tab));
+  ({entries} = JSON.parse(ss.getTabState(tab)));
   is(entries.length, 2, "there now are two shistory entries");
   is(entries[1].children.length, 1, "the second entry has one child");
 
   // Go back in history.
   browser.goBack();
   yield promiseBrowserLoaded(browser, false /* don't ignore subframes */);
 
   // Navigate the subframe again.
   browser.messageManager.sendAsyncMessage("ss-test:click", {id: "a2"});
   yield promiseContentMessage(browser, "ss-test:hashchange");
 
   // Check shistory.
   SyncHandlers.get(browser).flush();
-  let {entries} = JSON.parse(ss.getTabState(tab));
+  ({entries} = JSON.parse(ss.getTabState(tab)));
   is(entries.length, 2, "there now are two shistory entries");
   is(entries[1].children.length, 1, "the second entry has one child");
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
@@ -181,17 +181,17 @@ add_task(function test_about_page_naviga
   is(entries.length, 1, "there is one shistory entry");
   is(entries[0].url, "about:blank", "url is correct");
 
   browser.loadURI("about:robots");
   yield promiseBrowserLoaded(browser);
 
   // Check that we have changed the history entry.
   SyncHandlers.get(browser).flush();
-  let {entries} = JSON.parse(ss.getTabState(tab));
+  ({entries} = JSON.parse(ss.getTabState(tab)));
   is(entries.length, 1, "there is one shistory entry");
   is(entries[0].url, "about:robots", "url is correct");
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
@@ -210,27 +210,27 @@ add_task(function test_pushstate_replace
   is(entries[0].url, "http://example.com/1", "url is correct");
 
   browser.messageManager.
     sendAsyncMessage("ss-test:historyPushState", {url: 'test-entry/'});
   yield promiseContentMessage(browser, "ss-test:historyPushState");
 
   // Check that we have added the history entry.
   SyncHandlers.get(browser).flush();
-  let {entries} = JSON.parse(ss.getTabState(tab));
+  ({entries} = JSON.parse(ss.getTabState(tab)));
   is(entries.length, 2, "there is another shistory entry");
   is(entries[1].url, "http://example.com/test-entry/", "url is correct");
 
   browser.messageManager.
     sendAsyncMessage("ss-test:historyReplaceState", {url: 'test-entry2/'});
   yield promiseContentMessage(browser, "ss-test:historyReplaceState");
 
   // Check that we have modified the history entry.
   SyncHandlers.get(browser).flush();
-  let {entries} = JSON.parse(ss.getTabState(tab));
+  ({entries} = JSON.parse(ss.getTabState(tab)));
   is(entries.length, 2, "there is still two shistory entries");
   is(entries[1].url, "http://example.com/test-entry/test-entry2/", "url is correct");
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
 
 /**
--- a/browser/components/sessionstore/test/browser_sessionStorage.js
+++ b/browser/components/sessionstore/test/browser_sessionStorage.js
@@ -29,53 +29,53 @@ add_task(function session_storage() {
   is(storage["http://mochi.test:8888"].test, OUTER_VALUE,
     "sessionStorage data for mochi.test has been serialized correctly");
 
   // Ensure that modifying sessionStore values works.
   yield modifySessionStorage(browser, {test: "modified"});
   yield modifySessionStorage2(browser, {test: "modified2"});
   SyncHandlers.get(browser).flush();
 
-  let {storage} = JSON.parse(ss.getTabState(tab));
+  ({storage} = JSON.parse(ss.getTabState(tab)));
   is(storage["http://example.com"].test, "modified2",
     "sessionStorage data for example.com has been serialized correctly");
   is(storage["http://mochi.test:8888"].test, "modified",
     "sessionStorage data for mochi.test has been serialized correctly");
 
   // Test that duplicating a tab works.
   let tab2 = gBrowser.duplicateTab(tab);
   let browser2 = tab2.linkedBrowser;
   yield promiseTabRestored(tab2);
 
   // Flush to make sure chrome received all data.
   SyncHandlers.get(browser2).flush();
 
-  let {storage} = JSON.parse(ss.getTabState(tab2));
+  ({storage} = JSON.parse(ss.getTabState(tab2)));
   is(storage["http://example.com"].test, "modified2",
     "sessionStorage data for example.com has been duplicated correctly");
   is(storage["http://mochi.test:8888"].test, "modified",
     "sessionStorage data for mochi.test has been duplicated correctly");
 
   // Ensure that the content script retains restored data
   // (by e.g. duplicateTab) and sends it along with new data.
   yield modifySessionStorage(browser2, {test: "modified3"});
   SyncHandlers.get(browser2).flush();
 
-  let {storage} = JSON.parse(ss.getTabState(tab2));
+  ({storage} = JSON.parse(ss.getTabState(tab2)));
   is(storage["http://example.com"].test, "modified2",
     "sessionStorage data for example.com has been duplicated correctly");
   is(storage["http://mochi.test:8888"].test, "modified3",
     "sessionStorage data for mochi.test has been duplicated correctly");
 
   // Check that loading a new URL discards data.
   browser2.loadURI("http://mochi.test:8888/");
   yield promiseBrowserLoaded(browser2);
   SyncHandlers.get(browser2).flush();
 
-  let {storage} = JSON.parse(ss.getTabState(tab2));
+  ({storage} = JSON.parse(ss.getTabState(tab2)));
   is(storage["http://mochi.test:8888"].test, "modified3",
     "navigating retains correct storage data");
   ok(!storage["http://example.com"], "storage data was discarded");
 
   // Check that loading a new URL discards data.
   browser2.loadURI("about:mozilla");
   yield promiseBrowserLoaded(browser2);
   SyncHandlers.get(browser2).flush();
@@ -125,46 +125,46 @@ add_task(function respect_privacy_level(
   is(storage["http://mochi.test:8888"].test, OUTER_VALUE,
     "http sessionStorage data has been saved");
   is(storage["https://example.com"].test, INNER_VALUE,
     "https sessionStorage data has been saved");
 
   // Disable saving data for encrypted sites.
   Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1);
 
-  let tab = gBrowser.addTab(URL + "&secure");
+  tab = gBrowser.addTab(URL + "&secure");
   yield promiseBrowserLoaded(tab.linkedBrowser);
   gBrowser.removeTab(tab);
 
-  let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
+  [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://mochi.test:8888"].test, OUTER_VALUE,
     "http sessionStorage data has been saved");
   ok(!storage["https://example.com"],
     "https sessionStorage data has *not* been saved");
 
   // Disable saving data for any site.
   Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2);
 
   // Check that duplicating a tab copies all private data.
-  let tab = gBrowser.addTab(URL + "&secure");
+  tab = gBrowser.addTab(URL + "&secure");
   yield promiseBrowserLoaded(tab.linkedBrowser);
   let tab2 = gBrowser.duplicateTab(tab);
   yield promiseTabRestored(tab2);
   gBrowser.removeTab(tab);
 
   // With privacy_level=2 the |tab| shouldn't have any sessionStorage data.
-  let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
+  [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   ok(!storage, "sessionStorage data has *not* been saved");
 
   // Restore the default privacy level and close the duplicated tab.
   Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
   gBrowser.removeTab(tab2);
 
   // With privacy_level=0 the duplicated |tab2| should persist all data.
-  let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
+  [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://mochi.test:8888"].test, OUTER_VALUE,
     "http sessionStorage data has been saved");
   is(storage["https://example.com"].test, INNER_VALUE,
     "https sessionStorage data has been saved");
 });
 
 function waitForStorageEvent(browser) {
   return promiseContentMessage(browser, "ss-test:MozStorageChanged");
--- a/browser/components/tabview/test/browser_tabview_bug631752.js
+++ b/browser/components/tabview/test/browser_tabview_bug631752.js
@@ -14,17 +14,17 @@ function test() {
   let getAspectRange = function () {
     let aspect = cw.TabItems.tabAspect;
     let variance = aspect / 100 * 1.5;
     return new cw.Range(aspect - variance, aspect + variance);
   }
 
   let dragTabItem = function (tabItem) {
     let doc = cw.document.documentElement;
-    let tabItem = groupItem.getChild(0);
+    tabItem = groupItem.getChild(0);
     let container = tabItem.container;
     let aspectRange = getAspectRange();
 
     EventUtils.synthesizeMouseAtCenter(container, {type: "mousedown"}, cw);
     for (let x = 200; x <= 400; x += 100)
       EventUtils.synthesizeMouse(doc, x, 100, {type: "mousemove"}, cw);
     ok(aspectRange.contains(getTabItemAspect(tabItem)), "tabItem's aspect is correct");
 
--- a/browser/components/translation/test/unit/test_healthreport.js
+++ b/browser/components/translation/test/unit/test_healthreport.js
@@ -141,24 +141,24 @@ add_task(function* test_record_translati
   Assert.equal(countsByLanguage["fr"]["es"], 1);
 
   // Record more translations.
   yield provider.recordTranslation("fr", "es", 1, now);
   yield provider.recordTranslation("fr", "en", 2, now);
   yield provider.recordTranslation("es", "en", 4, now);
 
   values = yield m.getValues();
-  let day = values.days.getDay(now);
+  day = values.days.getDay(now);
   Assert.ok(day.has("pageTranslatedCount"));
   Assert.equal(day.get("pageTranslatedCount"), 4);
   Assert.ok(day.has("charactersTranslatedCount"));
   Assert.equal(day.get("charactersTranslatedCount"), 1007);
 
   Assert.ok(day.has("pageTranslatedCountsByLanguage"));
-  let countsByLanguage = JSON.parse(day.get("pageTranslatedCountsByLanguage"));
+  countsByLanguage = JSON.parse(day.get("pageTranslatedCountsByLanguage"));
   Assert.ok("fr" in countsByLanguage);
   Assert.equal(countsByLanguage["fr"]["total"], 3);
   Assert.equal(countsByLanguage["fr"]["es"], 2);
   Assert.equal(countsByLanguage["fr"]["en"], 1);
   Assert.ok("es" in countsByLanguage);
   Assert.equal(countsByLanguage["es"]["total"], 1);
   Assert.equal(countsByLanguage["es"]["en"], 1);
 
--- a/browser/devtools/canvasdebugger/test/browser_canvas-actor-test-10.js
+++ b/browser/devtools/canvasdebugger/test/browser_canvas-actor-test-10.js
@@ -68,17 +68,17 @@ function ifTestingSupported() {
     "The second screenshot has the correct red component.");
   is(new Uint8Array(secondScreenshot.pixels.buffer)[1], 0,
     "The second screenshot has the correct green component.");
   is(new Uint8Array(secondScreenshot.pixels.buffer)[2], 255,
     "The second screenshot has the correct blue component.");
   is(new Uint8Array(secondScreenshot.pixels.buffer)[3], 255,
     "The second screenshot has the correct alpha component.");
 
-  let gl = debuggee.gl;
+  gl = debuggee.gl;
   is(gl.getParameter(gl.FRAMEBUFFER_BINDING), debuggee.customFramebuffer,
     "The debuggee's gl context framebuffer still wasn't changed.");
   is(gl.getParameter(gl.RENDERBUFFER_BINDING), debuggee.customRenderbuffer,
     "The debuggee's gl context renderbuffer still wasn't changed.");
   is(gl.getParameter(gl.TEXTURE_BINDING_2D), debuggee.customTexture,
     "The debuggee's gl context texture binding still wasn't changed.");
   is(gl.getParameter(gl.VIEWPORT)[0], 128,
     "The debuggee's gl context viewport's left coord. still wasn't changed.");
--- a/browser/devtools/canvasdebugger/test/browser_canvas-frontend-call-search.js
+++ b/browser/devtools/canvasdebugger/test/browser_canvas-frontend-call-search.js
@@ -39,17 +39,17 @@ function ifTestingSupported() {
   is(CallsListView.visibleItems[0].attachment.actor.line, 25,
     "The visible item's line has the expected value.");
   is(CallsListView.visibleItems[0].attachment.actor.argsPreview, "0, 0, 128, 128",
     "The visible item's args have the expected value.");
   is(CallsListView.visibleItems[0].attachment.actor.callerPreview, "ctx",
     "The visible item's caller has the expected value.");
 
   let secondRecordingFinished = once(window, EVENTS.SNAPSHOT_RECORDING_FINISHED);
-  let callListPopulated = once(window, EVENTS.CALL_LIST_POPULATED);
+  callListPopulated = once(window, EVENTS.CALL_LIST_POPULATED);
 
   SnapshotsListView._onRecordButtonClick();
   yield secondRecordingFinished;
 
   SnapshotsListView.selectedIndex = 1;
   yield callListPopulated;
 
   is(searchbox.value, "clear",
--- a/browser/devtools/canvasdebugger/test/browser_canvas-frontend-slider-02.js
+++ b/browser/devtools/canvasdebugger/test/browser_canvas-frontend-slider-02.js
@@ -29,49 +29,49 @@ function ifTestingSupported() {
   let thumbnailPixels = yield thumbnailImageElementSet;
 
   ok(sameArray(thumbnailPixels, thumbnails[0].pixels),
     "The screenshot element should have a thumbnail as an immediate background.");
 
   yield once(window, EVENTS.CALL_SCREENSHOT_DISPLAYED);
   ok(true, "The full-sized screenshot was displayed for the item at index 1.");
 
-  let thumbnailImageElementSet = waitForMozSetImageElement(window);
+  thumbnailImageElementSet = waitForMozSetImageElement(window);
   $("#calls-slider").value = 2;
-  let thumbnailPixels = yield thumbnailImageElementSet;
+  thumbnailPixels = yield thumbnailImageElementSet;
 
   ok(sameArray(thumbnailPixels, thumbnails[1].pixels),
     "The screenshot element should have a thumbnail as an immediate background.");
 
   yield once(window, EVENTS.CALL_SCREENSHOT_DISPLAYED);
   ok(true, "The full-sized screenshot was displayed for the item at index 2.");
 
-  let thumbnailImageElementSet = waitForMozSetImageElement(window);
+  thumbnailImageElementSet = waitForMozSetImageElement(window);
   $("#calls-slider").value = 7;
-  let thumbnailPixels = yield thumbnailImageElementSet;
+  thumbnailPixels = yield thumbnailImageElementSet;
 
   ok(sameArray(thumbnailPixels, thumbnails[3].pixels),
     "The screenshot element should have a thumbnail as an immediate background.");
 
   yield once(window, EVENTS.CALL_SCREENSHOT_DISPLAYED);
   ok(true, "The full-sized screenshot was displayed for the item at index 7.");
 
-  let thumbnailImageElementSet = waitForMozSetImageElement(window);
+  thumbnailImageElementSet = waitForMozSetImageElement(window);
   $("#calls-slider").value = 4;
-  let thumbnailPixels = yield thumbnailImageElementSet;
+  thumbnailPixels = yield thumbnailImageElementSet;
 
   ok(sameArray(thumbnailPixels, thumbnails[2].pixels),
     "The screenshot element should have a thumbnail as an immediate background.");
 
   yield once(window, EVENTS.CALL_SCREENSHOT_DISPLAYED);
   ok(true, "The full-sized screenshot was displayed for the item at index 4.");
 
-  let thumbnailImageElementSet = waitForMozSetImageElement(window);
+  thumbnailImageElementSet = waitForMozSetImageElement(window);
   $("#calls-slider").value = 0;
-  let thumbnailPixels = yield thumbnailImageElementSet;
+  thumbnailPixels = yield thumbnailImageElementSet;
 
   ok(sameArray(thumbnailPixels, thumbnails[0].pixels),
     "The screenshot element should have a thumbnail as an immediate background.");
 
   yield once(window, EVENTS.CALL_SCREENSHOT_DISPLAYED);
   ok(true, "The full-sized screenshot was displayed for the item at index 0.");
 
   yield teardown(panel);
--- a/browser/devtools/canvasdebugger/test/browser_canvas-frontend-snapshot-select.js
+++ b/browser/devtools/canvasdebugger/test/browser_canvas-frontend-snapshot-select.js
@@ -48,17 +48,17 @@ function ifTestingSupported() {
   info("First draw call in the second snapshot selected.");
 
   is(SnapshotsListView.selectedIndex, 1,
     "The second snapshot should still be selected.");
   is(CallsListView.selectedIndex, 2,
     "The first draw call should now be selected in the snapshot.");
 
   let firstSnapshotTarget = SnapshotsListView.getItemAtIndex(0).target;
-  let snapshotSelected = waitForSnapshotSelection();
+  snapshotSelected = waitForSnapshotSelection();
   EventUtils.sendMouseEvent({ type: "mousedown" }, firstSnapshotTarget, window);
 
   yield snapshotSelected;
   info("First snapshot re-selected.");
 
   is(SnapshotsListView.selectedIndex, 0,
     "The first snapshot should now be re-selected.");
   is(CallsListView.selectedIndex, -1,
--- a/browser/devtools/commandline/test/browser_cmd_csscoverage_util.js
+++ b/browser/devtools/commandline/test/browser_cmd_csscoverage_util.js
@@ -12,13 +12,13 @@ let test = asyncTest(function*() {
 function testDeconstructRuleId() {
   // This is the easy case
   let rule = csscoverage.deconstructRuleId("http://thing/blah|10|20");
   is(rule.url, "http://thing/blah", "1 url");
   is(rule.line, 10, "1 line");
   is(rule.column, 20, "1 column");
 
   // This is the harder case with a URL containing a '|'
-  let rule = csscoverage.deconstructRuleId("http://thing/blah?q=a|b|11|22");
+  rule = csscoverage.deconstructRuleId("http://thing/blah?q=a|b|11|22");
   is(rule.url, "http://thing/blah?q=a|b", "2 url");
   is(rule.line, 11, "2 line");
   is(rule.column, 22, "2 column");
 }
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -211,17 +211,17 @@ let DebuggerView = {
     let extraKeys = {};
     bindKey("_doTokenSearch", "tokenSearchKey");
     bindKey("_doGlobalSearch", "globalSearchKey", { alt: true });
     bindKey("_doFunctionSearch", "functionSearchKey");
     extraKeys[Editor.keyFor("jumpToLine")] = false;
     extraKeys["Esc"] = false;
 
     function bindKey(func, key, modifiers = {}) {
-      let key = document.getElementById(key).getAttribute("key");
+      key = document.getElementById(key).getAttribute("key");
       let shortcut = Editor.accel(key, modifiers);
       extraKeys[shortcut] = () => DebuggerView.Filtering[func]();
     }
 
     let gutters = ["breakpoints"];
     if (Services.prefs.getBoolPref("devtools.debugger.tracer")) {
       gutters.unshift("hit-counts");
     }
--- a/browser/devtools/debugger/test/browser_dbg_break-on-dom-04.js
+++ b/browser/devtools/debugger/test/browser_dbg_break-on-dom-04.js
@@ -40,17 +40,17 @@ function test() {
       testEventItem(1, false);
       testEventItem(2, false);
       testEventItem(3, false);
       testEventGroup("interactionEvents", false);
       testEventGroup("keyboardEvents", false);
       testEventGroup("mouseEvents", false);
       testEventArrays("change,click,keydown,keyup", "change");
 
-      let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
+      updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
       EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger);
       yield updated;
 
       testEventItem(0, false);
       testEventItem(1, false);
       testEventItem(2, false);
       testEventItem(3, false);
       testEventGroup("interactionEvents", false);
--- a/browser/devtools/debugger/test/browser_dbg_break-on-dom-05.js
+++ b/browser/devtools/debugger/test/browser_dbg_break-on-dom-05.js
@@ -41,43 +41,43 @@ function test() {
       testEventItem(1, false);
       testEventItem(2, false);
       testEventItem(3, false);
       testEventGroup("interactionEvents", true);
       testEventGroup("keyboardEvents", false);
       testEventGroup("mouseEvents", false);
       testEventArrays("change,click,keydown,keyup", "change");
 
-      let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
+      updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
       EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("interactionEvents"), gDebugger);
       yield updated;
 
       testEventItem(0, false);
       testEventItem(1, false);
       testEventItem(2, false);
       testEventItem(3, false);
       testEventGroup("interactionEvents", false);
       testEventGroup("keyboardEvents", false);
       testEventGroup("mouseEvents", false);
       testEventArrays("change,click,keydown,keyup", "");
 
-      let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
+      updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
       EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("keyboardEvents"), gDebugger);
       yield updated;
 
       testEventItem(0, false);
       testEventItem(1, false);
       testEventItem(2, true);
       testEventItem(3, true);
       testEventGroup("interactionEvents", false);
       testEventGroup("keyboardEvents", true);
       testEventGroup("mouseEvents", false);
       testEventArrays("change,click,keydown,keyup", "keydown,keyup");
 
-      let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
+      updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
       EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("keyboardEvents"), gDebugger);
       yield updated;
 
       testEventItem(0, false);
       testEventItem(1, false);
       testEventItem(2, false);
       testEventItem(3, false);
       testEventGroup("interactionEvents", false);
--- a/browser/devtools/debugger/test/browser_dbg_break-on-dom-06.js
+++ b/browser/devtools/debugger/test/browser_dbg_break-on-dom-06.js
@@ -53,17 +53,17 @@ function test() {
       testEventItem(1, true);
       testEventItem(2, true);
       testEventItem(3, false);
       testEventGroup("interactionEvents", false);
       testEventGroup("keyboardEvents", false);
       testEventGroup("mouseEvents", false);
       testEventArrays("change,click,keydown,keyup", "change,click,keydown");
 
-      let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
+      updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED);
       EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger);
       EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(1), gDebugger);
       EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(2), gDebugger);
       yield updated;
 
       testEventItem(0, false);
       testEventItem(1, false);
       testEventItem(2, false);
--- a/browser/devtools/debugger/test/browser_dbg_cmd-blackbox.js
+++ b/browser/devtools/debugger/test/browser_dbg_cmd-blackbox.js
@@ -37,53 +37,53 @@ function spawnTest() {
 
   let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
   ok(bbButton.checked,
      "Should be able to black box a specific source.");
 
   // test Un-Black-Box Source
   yield cmd("dbg unblackbox " + BLACKBOXME_URL);
 
-  let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
+  bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
   ok(!bbButton.checked,
      "Should be able to stop black boxing a specific source.");
 
   // test Black-Box Glob
   yield cmd("dbg blackbox --glob *blackboxing_t*.js", 2,
             [/blackboxing_three\.js/g, /blackboxing_two\.js/g]);
 
-  let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
+  bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
   ok(!bbButton.checked,
      "blackboxme should not be black boxed because it doesn't match the glob.");
   bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXONE_URL);
   ok(!bbButton.checked,
      "blackbox_one should not be black boxed because it doesn't match the glob.");
 
   bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTWO_URL);
   ok(bbButton.checked,
      "blackbox_two should be black boxed because it matches the glob.");
   bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTHREE_URL);
   ok(bbButton.checked,
     "blackbox_three should be black boxed because it matches the glob.");
 
   // test Un-Black-Box Glob
   yield cmd("dbg unblackbox --glob *blackboxing_t*.js", 2);
 
-  let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTWO_URL);
+  bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTWO_URL);
   ok(!bbButton.checked,
      "blackbox_two should be un-black boxed because it matches the glob.");
   bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTHREE_URL);
   ok(!bbButton.checked,
     "blackbox_three should be un-black boxed because it matches the glob.");
 
   // test Black-Box Invert
   yield cmd("dbg blackbox --invert --glob *blackboxing_t*.js", 3,
             [/blackboxing_three\.js/g, /blackboxing_two\.js/g]);
 
-  let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
+  bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
   ok(bbButton.checked,
     "blackboxme should be black boxed because it doesn't match the glob.");
   bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXONE_URL);
   ok(bbButton.checked,
     "blackbox_one should be black boxed because it doesn't match the glob.");
   bbButton = yield selectSourceAndGetBlackBoxButton(panel, TEST_URL);
   ok(bbButton.checked,
     "TEST_URL should be black boxed because it doesn't match the glob.");
@@ -93,17 +93,17 @@ function spawnTest() {
     "blackbox_two should not be black boxed because it matches the glob.");
   bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTHREE_URL);
   ok(!bbButton.checked,
     "blackbox_three should not be black boxed because it matches the glob.");
 
   // test Un-Black-Box Invert
   yield cmd("dbg unblackbox --invert --glob *blackboxing_t*.js", 3);
 
-  let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
+  bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL);
   ok(!bbButton.checked,
     "blackboxme should be un-black boxed because it does not match the glob.");
   bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXONE_URL);
   ok(!bbButton.checked,
     "blackbox_one should be un-black boxed because it does not match the glob.");
   bbButton = yield selectSourceAndGetBlackBoxButton(panel, TEST_URL);
   ok(!bbButton.checked,
     "TEST_URL should be un-black boxed because it doesn't match the glob.");
--- a/browser/devtools/debugger/test/browser_dbg_controller-evaluate-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_controller-evaluate-01.js
@@ -57,17 +57,17 @@ function test() {
     is(result.return.type, "object", "The evaluation return type is correct.");
     is(result.return.class, "Function", "The evaluation return class is correct.");
 
     yield updatedView;
     checkView(0, 1, 1, [/secondCall/, 118]);
     ok(true, "Evaluating in the topmost frame works properly.");
 
     // Eval in a different frame, while paused.
-    let updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
+    updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES);
     try {
       yield frames.evaluate("foo", { depth: 3 }); // oldest frame
     } catch (result) {
       is(result.return.type, "object", "The evaluation thrown type is correct.");
       is(result.return.class, "Error", "The evaluation thrown class is correct.");
       ok(!result.return, "The evaluation hasn't returned.");
     }
 
--- a/browser/devtools/debugger/test/browser_dbg_file-reload.js
+++ b/browser/devtools/debugger/test/browser_dbg_file-reload.js
@@ -38,17 +38,17 @@ function test() {
 
       is(gSources.itemCount, 1,
         "There should be one source displayed in the view after reloading.")
       is(gSources.selectedValue, JS_URL,
         "The correct source is currently selected in the view after reloading.");
       ok(gEditor.getText().contains("bacon"),
         "The newly shown source contains bacon. Mmm, delicious!");
 
-      let { source } = gSources.selectedItem.attachment;
+      ({ source } = gSources.selectedItem.attachment);
       let [, secondText] = yield gControllerSources.getText(source);
       let secondNumber = parseFloat(secondText.match(/\d\.\d+/)[0]);
 
       is(secondText, gEditor.getText(),
         "gControllerSources.getText() returned the expected contents.");
       ok(secondNumber <= 1 && secondNumber >= 0,
         "The generated number seems to be created correctly.");
 
--- a/browser/devtools/debugger/test/browser_dbg_optimized-out-vars.js
+++ b/browser/devtools/debugger/test/browser_dbg_optimized-out-vars.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test that optimized out variables aren't present in the variables view.
 
 function test() {
   Task.spawn(function* () {
     const TAB_URL = EXAMPLE_URL + "doc_closure-optimized-out.html";
-    let panel, debuggee, gDebugger, sources;
+    let gDebugger, sources;
 
     let [, debuggee, panel] = yield initDebugger(TAB_URL);
     gDebugger = panel.panelWin;
     sources = gDebugger.DebuggerView.Sources;
 
     yield waitForSourceShown(panel, ".html");
     yield panel.addBreakpoint({ url: sources.values[0], line: 18 });
     yield ensureThreadClientState(panel, "resumed");
--- a/browser/devtools/debugger/test/browser_dbg_paused-keybindings.js
+++ b/browser/devtools/debugger/test/browser_dbg_paused-keybindings.js
@@ -2,17 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test that keybindings still work when the content window is paused and
 // the tab is selected again.
 
 function test() {
   Task.spawn(function* () {
     const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
-    let panel, debuggee, gDebugger, searchBox;
+    let gDebugger, searchBox;
 
     let [, debuggee, panel] = yield initDebugger(TAB_URL);
     gDebugger = panel.panelWin;
     searchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     // Spin the event loop before causing the debuggee to pause, to allow
     // this function to return first.
     executeSoon(() => {
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-05.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-05.js
@@ -39,17 +39,18 @@ function test() {
       try {
         yield gControllerSources.togglePrettyPrint(source);
         ok(false, "The promise for a prettified source should be rejected!");
       } catch ([source, error]) {
         is(error, "Can't prettify non-javascript files.",
           "The promise was correctly rejected with a meaningful message.");
       }
 
-      let [source, text] = yield gControllerSources.getText(source);
+      let text;
+      [source, text] = yield gControllerSources.getText(source);
       is(gSources.selectedValue, TAB_URL,
         "The correct source is still selected.");
       ok(gEditor.getText().contains("myFunction"),
         "The displayed source hasn't changed.");
       ok(text.contains("myFunction"),
         "The cached source text wasn't altered in any way.");
 
       yield closeDebuggerAndFinish(gPanel);
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-06.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-06.js
@@ -55,17 +55,18 @@ function test() {
       try {
         yield gControllerSources.togglePrettyPrint(source);
         ok(false, "The promise for a prettified source should be rejected!");
       } catch ([source, error]) {
         ok(error.contains("prettyPrintError"),
           "The promise was correctly rejected with a meaningful message.");
       }
 
-      let [source, text] = yield gControllerSources.getText(source);
+      let text;
+      [source, text] = yield gControllerSources.getText(source);
       is(gSources.selectedValue, JS_URL,
         "The correct source is still selected.");
       ok(gEditor.getText().contains("myFunction"),
         "The displayed source hasn't changed.");
       ok(text.contains("myFunction"),
         "The cached source text wasn't altered in any way.");
 
       is(gPrettyPrinted, true,
--- a/browser/devtools/debugger/test/browser_dbg_variables-view-data.js
+++ b/browser/devtools/debugger/test/browser_dbg_variables-view-data.js
@@ -298,17 +298,17 @@ function testSecondLevelContents() {
   let objectItem1 = someProp6.get("p1");
   let objectItem2 = someProp6.get("p2");
   let objectItem3 = someProp6.get("p3");
   let objectItem4 = someProp6.get("p4");
   let objectItem5 = someProp6.get("p5");
   let objectItem6 = someProp6.get("p6");
   let objectItem7 = someProp6.get("p7");
   let objectItem8 = someProp6.get("p8");
-  let __proto__ = someProp6.get("__proto__");
+  __proto__ = someProp6.get("__proto__");
 
   is(objectItem0.visible, true, "The first object item visible state is correct.");
   is(objectItem1.visible, true, "The second object item visible state is correct.");
   is(objectItem2.visible, true, "The third object item visible state is correct.");
   is(objectItem3.visible, true, "The fourth object item visible state is correct.");
   is(objectItem4.visible, true, "The fifth object item visible state is correct.");
   is(objectItem5.visible, true, "The sixth object item visible state is correct.");
   is(objectItem6.visible, true, "The seventh object item visible state is correct.");
--- a/browser/devtools/debugger/test/browser_dbg_variables-view-override-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_variables-view-override-01.js
@@ -78,32 +78,32 @@ function test() {
     let calleeProp1 = argsVar1.get("callee");
     let calleeOwner1 = variables.getOwnerScopeForVariableOrProperty(calleeProp1);
     is(calleeOwner1, firstScope,
       "The getOwnerScopeForVariableOrProperty method works properly (3).");
 
     // Test getOwnerScopeForVariableOrProperty with second-degree properties.
 
     let protoVar1 = argsVar1.get("__proto__");
-    let fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES);
+    fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES);
     protoVar1.expand();
     yield fetched;
 
     let constrProp1 = protoVar1.get("constructor");
     let constrOwner1 = variables.getOwnerScopeForVariableOrProperty(constrProp1);
     is(constrOwner1, firstScope,
       "The getOwnerScopeForVariableOrProperty method works properly (4).");
 
     // Test getOwnerScopeForVariableOrProperty with a simple variable
     // from non-topmost scopes.
 
     // Only need to wait for a single FETCHED_VARIABLES event, just for the
     // global scope, because the other local scopes already have the
     // arguments and variables available as evironment bindings.
-    let fetched = waitForDebuggerEvents(panel, events.FETCHED_VARIABLES);
+    fetched = waitForDebuggerEvents(panel, events.FETCHED_VARIABLES);
     secondScope.expand();
     thirdScope.expand();
     globalScope.expand();
     yield fetched;
 
     let someVar2 = secondScope.get("a");
     let someOwner2 = variables.getOwnerScopeForVariableOrProperty(someVar2);
     is(someOwner2, secondScope,
@@ -113,50 +113,50 @@ function test() {
     let someOwner3 = variables.getOwnerScopeForVariableOrProperty(someVar3);
     is(someOwner3, thirdScope,
       "The getOwnerScopeForVariableOrProperty method works properly (6).");
 
     // Test getOwnerScopeForVariableOrProperty with first-degree properies
     // from non-topmost scopes.
 
     let argsVar2 = secondScope.get("arguments");
-    let fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES);
+    fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES);
     argsVar2.expand();
     yield fetched;
 
     let calleeProp2 = argsVar2.get("callee");
     let calleeOwner2 = variables.getOwnerScopeForVariableOrProperty(calleeProp2);
     is(calleeOwner2, secondScope,
       "The getOwnerScopeForVariableOrProperty method works properly (7).");
 
     let argsVar3 = thirdScope.get("arguments");
-    let fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES);
+    fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES);
     argsVar3.expand();
     yield fetched;
 
     let calleeProp3 = argsVar3.get("callee");
     let calleeOwner3 = variables.getOwnerScopeForVariableOrProperty(calleeProp3);
     is(calleeOwner3, thirdScope,
       "The getOwnerScopeForVariableOrProperty method works properly (8).");
 
     // Test getOwnerScopeForVariableOrProperty with second-degree properties
     // from non-topmost scopes.
 
     let protoVar2 = argsVar2.get("__proto__");
-    let fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES);
+    fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES);
     protoVar2.expand();
     yield fetched;
 
     let constrProp2 = protoVar2.get("constructor");
     let constrOwner2 = variables.getOwnerScopeForVariableOrProperty(constrProp2);
     is(constrOwner2, secondScope,
       "The getOwnerScopeForVariableOrProperty method works properly (9).");
 
     let protoVar3 = argsVar3.get("__proto__");
-    let fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES);
+    fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES);
     protoVar3.expand();
     yield fetched;
 
     let constrProp3 = protoVar3.get("constructor");
     let constrOwner3 = variables.getOwnerScopeForVariableOrProperty(constrProp3);
     is(constrOwner3, thirdScope,
       "The getOwnerScopeForVariableOrProperty method works properly (10).");
 
--- a/browser/devtools/debugger/test/browser_dbg_variables-view-popup-10.js
+++ b/browser/devtools/debugger/test/browser_dbg_variables-view-popup-10.js
@@ -44,17 +44,17 @@ function test() {
     tooltip.addEventListener("popuphiding", failPopup);
     editorContainer.addEventListener("scroll", failScroll);
     editor.on("scroll", () => {
       if (editor.getScrollInfo().top > topmostScrollPosition) {
         ok(false, "The editor scrolled back to the breakpoint location.");
       }
     });
 
-    let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
+    expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     yield openVarPopup(panel, { line: 14, ch: 15 });
     yield expressionsEvaluated;
 
     tooltip.removeEventListener("popuphiding", failPopup);
     editorContainer.removeEventListener("scroll", failScroll);
 
     yield resumeDebuggerThenCloseAndFinish(panel);
   });
--- a/browser/devtools/debugger/test/browser_dbg_variables-view-popup-11.js
+++ b/browser/devtools/debugger/test/browser_dbg_variables-view-popup-11.js
@@ -45,34 +45,34 @@ function test() {
     yield openVarPopup(panel, { line: 15, ch: 12 });
     let popupHiding = once(tooltip, "popuphiding");
     let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     testExpressionButton(label, className, "a");
     yield promise.all([popupHiding, expressionsEvaluated]);
     ok(true, "The new watch expressions were re-evaluated and the panel got hidden (1).");
 
     // Inspect non primitive value variable.
-    let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
+    expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     yield openVarPopup(panel, { line: 16, ch: 12 }, true);
     yield expressionsEvaluated;
     ok(true, "The watch expressions were re-evaluated when a new panel opened (1).");
 
-    let popupHiding = once(tooltip, "popuphiding");
-    let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
+    popupHiding = once(tooltip, "popuphiding");
+    expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     testExpressionButton(label, className, "b");
     yield promise.all([popupHiding, expressionsEvaluated]);
     ok(true, "The new watch expressions were re-evaluated and the panel got hidden (2).");
 
     // Inspect property of an object.
-    let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
+    expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     yield openVarPopup(panel, { line: 17, ch: 10 });
     yield expressionsEvaluated;
     ok(true, "The watch expressions were re-evaluated when a new panel opened (2).");
 
-    let popupHiding = once(tooltip, "popuphiding");
-    let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
+    popupHiding = once(tooltip, "popuphiding");
+    expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     testExpressionButton(label, className, "b.a");
     yield promise.all([popupHiding, expressionsEvaluated]);
     ok(true, "The new watch expressions were re-evaluated and the panel got hidden (3).");
 
     yield resumeDebuggerThenCloseAndFinish(panel);
   });
 }
--- a/browser/devtools/debugger/test/browser_dbg_variables-view-popup-12.js
+++ b/browser/devtools/debugger/test/browser_dbg_variables-view-popup-12.js
@@ -36,36 +36,36 @@ function test() {
     let popupHiding = once(tooltip, "popuphiding");
     let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     tooltip.querySelector("button").click();
     verifyContent("a", 1);
     yield promise.all([popupHiding, expressionsEvaluated]);
     ok(true, "The new watch expressions were re-evaluated and the panel got hidden (1).");
 
     // Inspect property of an object.
-    let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
+    expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     yield openVarPopup(panel, { line: 17, ch: 10 });
     yield expressionsEvaluated;
     ok(true, "The watch expressions were re-evaluated when a new panel opened (1).");
 
-    let popupHiding = once(tooltip, "popuphiding");
-    let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
+    popupHiding = once(tooltip, "popuphiding");
+    expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     tooltip.querySelector("button").click();
     verifyContent("b.a", 2);
     yield promise.all([popupHiding, expressionsEvaluated]);
     ok(true, "The new watch expressions were re-evaluated and the panel got hidden (2).");
 
     // Re-inspect primitive value variable.
-    let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
+    expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     yield openVarPopup(panel, { line: 15, ch: 12 });
     yield expressionsEvaluated;
     ok(true, "The watch expressions were re-evaluated when a new panel opened (2).");
 
-    let popupHiding = once(tooltip, "popuphiding");
-    let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
+    popupHiding = once(tooltip, "popuphiding");
+    expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS);
     tooltip.querySelector("button").click();
     verifyContent("b.a", 2);
     yield promise.all([popupHiding, expressionsEvaluated]);
     ok(true, "The new watch expressions were re-evaluated and the panel got hidden (3).");
 
     yield resumeDebuggerThenCloseAndFinish(panel);
   });
 }
--- a/browser/devtools/debugger/test/browser_dbg_watch-expressions-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_watch-expressions-02.js
@@ -307,17 +307,17 @@ function test() {
     ok(w25, "The 25th watch expression should be present in the scope.");
     ok(w26, "The 26th watch expression should be present in the scope.");
     ok(!w27, "The 27th watch expression should not be present in the scope.");
 
     is(w1.value, "a", "The first value is correct.");
     is(w2.value, "a", "The second value is correct.");
     is(w3.value, "a\"\"", "The third value is correct.");
     is(w4.value, "a''", "The fourth value is correct.");
-    is(w5.value, "SyntaxError: syntax error", "The fifth value is correct.");
+    is(w5.value, "SyntaxError: expected expression, got '?'", "The fifth value is correct.");
 
     if (typeof expected_a == "object") {
       is(w6.value.type, expected_a.type, "The sixth value type is correct.");
       is(w6.value.class, expected_a.class, "The sixth value class is correct.");
     } else {
       is(w6.value, expected_a, "The sixth value is correct.");
     }
 
@@ -356,17 +356,17 @@ function test() {
     is(w17.value, "URIError: malformed URI sequence", "The 17th value is correct.");
 
     is(w18.value.type, "undefined", "The 18th value type is correct.");
     is(w18.value.class, undefined, "The 18th value class is correct.");
 
     is(w19.value.type, "undefined", "The 19th value type is correct.");
     is(w19.value.class, undefined, "The 19th value class is correct.");
 
-    is(w20.value, "SyntaxError: syntax error", "The 20th value is correct.");
-    is(w21.value, "SyntaxError: syntax error", "The 21th value is correct.");
+    is(w20.value, "SyntaxError: expected expression, got '.'", "The 20th value is correct.");
+    is(w21.value, "SyntaxError: expected expression, got '.'", "The 21th value is correct.");
     is(w22.value, "TypeError: (intermediate value).foo is not a function", "The 22th value is correct.");
     is(w23.value, "RangeError: invalid array length", "The 23th value is correct.");
     is(w24.value, "RangeError: precision -4 out of range", "The 24th value is correct.");
     is(w25.value, "Error: bazinga", "The 25th value is correct.");
     is(w26.value, "Error: bazinga", "The 26th value is correct.");
   }
 }
--- a/browser/devtools/framework/test/browser_toolbox_theme_registration.js
+++ b/browser/devtools/framework/test/browser_toolbox_theme_registration.js
@@ -60,23 +60,23 @@ function applyTheme()
   let lightThemeOption = doc.querySelector("#devtools-theme-box > radio[value=light]");
 
   let color = panelWin.getComputedStyle(testThemeOption).color;
   isnot(color, "rgb(255, 0, 0)", "style unapplied");
 
   // Select test theme.
   testThemeOption.click();
 
-  let color = panelWin.getComputedStyle(testThemeOption).color;
+  color = panelWin.getComputedStyle(testThemeOption).color;
   is(color, "rgb(255, 0, 0)", "style applied");
 
   // Select light theme
   lightThemeOption.click();
 
-  let color = panelWin.getComputedStyle(testThemeOption).color;
+  color = panelWin.getComputedStyle(testThemeOption).color;
   isnot(color, "rgb(255, 0, 0)", "style unapplied");
 
   // Select test theme again.
   testThemeOption.click();
 
   // Then unregister the test theme.
   testUnregister();
 }
--- a/browser/devtools/framework/toolbox-process-window.js
+++ b/browser/devtools/framework/toolbox-process-window.js
@@ -133,13 +133,13 @@ function quitApp() {
 
   let shouldProceed = !quit.data;
   if (shouldProceed) {
     Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
   }
 }
 
 function getParameterByName (name) {
-  let name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
+  name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
   let regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
   let results = regex.exec(window.location.search);
   return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
 }
--- a/browser/devtools/inspector/test/browser_inspector_breadcrumbs_highlight_hover.js
+++ b/browser/devtools/inspector/test/browser_inspector_breadcrumbs_highlight_hover.js
@@ -16,17 +16,17 @@ let test = asyncTest(function*() {
 
   let onNodeHighlighted = toolbox.once("node-highlight");
   let button = bcButtons.childNodes[1];
   EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"}, button.ownerDocument.defaultView);
   yield onNodeHighlighted;
   ok(isHighlighting(), "The highlighter is shown on a markup container hover");
   is(getHighlitNode(), getNode("body"), "The highlighter highlights the right node");
 
-  let onNodeHighlighted = toolbox.once("node-highlight");
-  let button = bcButtons.childNodes[2];
+  onNodeHighlighted = toolbox.once("node-highlight");
+  button = bcButtons.childNodes[2];
   EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"}, button.ownerDocument.defaultView);
   yield onNodeHighlighted;
   ok(isHighlighting(), "The highlighter is shown on a markup container hover");
   is(getHighlitNode(), getNode("span"), "The highlighter highlights the right node");
 
   gBrowser.removeCurrentTab();
-});
\ No newline at end of file
+});
--- a/browser/devtools/inspector/test/browser_inspector_highlighter-02.js
+++ b/browser/devtools/inspector/test/browser_inspector_highlighter-02.js
@@ -27,17 +27,17 @@ let test = asyncTest(function*() {
   let onBoxModelUpdate = waitForBoxModelUpdate();
   yield selectAndHighlightNode(rotated, inspector);
   yield onBoxModelUpdate;
 
   testMouseOverRotatedHighlights(rotated);
 
   info("Selecting the zero width height DIV");
   let zeroWidthHeight = getNode("#widthHeightZero-div");
-  let onBoxModelUpdate = waitForBoxModelUpdate();
+  onBoxModelUpdate = waitForBoxModelUpdate();
   yield selectAndHighlightNode(zeroWidthHeight, inspector);
   yield onBoxModelUpdate;
 
   testMouseOverWidthHeightZeroDiv(zeroWidthHeight);
 
 });
 
 function testSimpleDivHighlighted(div) {
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -1277,17 +1277,17 @@ MarkupView.prototype = {
         "px;transform:translateY(" + scrollTo + "px)");
     } else {
       this._previewBar.setAttribute("style", "height:100%");
     }
 
     let bgSize = ~~width + "px " + ~~height + "px";
     this._preview.setAttribute("style", "background-size:" + bgSize);
 
-    let height = ~~(win.innerHeight * ratio) + "px";
+    height = ~~(win.innerHeight * ratio) + "px";
     let top = ~~(win.scrollY * ratio) + "px";
     this._viewbox.setAttribute("style", "height:" + height +
       ";transform: translateY(" + top + ")");
   },
 
   /**
    * Hide the preview while resizing, to avoid slowness.
    */
--- a/browser/devtools/markupview/test/browser_markupview_highlight_hover_03.js
+++ b/browser/devtools/markupview/test/browser_markupview_highlight_hover_03.js
@@ -37,19 +37,19 @@ let test = asyncTest(function*() {
   info("Hover over <p#one> line in the markup-view");
   yield hoverContainer("#one", inspector);
   yield isHighlighting("#one", "<p#one> is highlighted");
 
   info("Navigate to <p#two> with the keyboard");
   let onUpdated = inspector.once("inspector-updated");
   EventUtils.synthesizeKey("VK_DOWN", {});
   yield onUpdated;
-  let onUpdated = inspector.once("inspector-updated");
+  onUpdated = inspector.once("inspector-updated");
   EventUtils.synthesizeKey("VK_DOWN", {});
   yield onUpdated;
   yield isHighlighting("#two", "<p#two> is highlighted");
 
   info("Navigate back to <p#one> with the keyboard");
-  let onUpdated = inspector.once("inspector-updated");
+  onUpdated = inspector.once("inspector-updated");
   EventUtils.synthesizeKey("VK_UP", {});
   yield onUpdated;
   yield isHighlighting("#one", "<p#one> is highlighted again");
 });
--- a/browser/devtools/markupview/test/browser_markupview_tag_edit_03.js
+++ b/browser/devtools/markupview/test/browser_markupview_tag_edit_03.js
@@ -25,15 +25,15 @@ let test = asyncTest(function*() {
 
   info("Changing the tagname");
   let mutated = inspector.once("markupmutation");
   let tagEditor = container.editor.tag;
   setEditableFieldValue(tagEditor, "p", inspector);
   yield mutated;
 
   info("Checking that the tagname change was done");
-  let node = content.document.querySelector("#retag-me");
-  let container = yield getContainerForSelector("#retag-me", inspector);
+  node = content.document.querySelector("#retag-me");
+  container = yield getContainerForSelector("#retag-me", inspector);
   is(node.tagName, "P", "We've got #retag-me, it should now be a P");
   ok(container.expanded, "It is still expanded");
   ok(container.selected, "It is still selected");
   is(child.parentNode, node, "Child #retag-me-2 is still inside #retag-me");
 });
--- a/browser/devtools/netmonitor/test/browser_net_post-data-03.js
+++ b/browser/devtools/netmonitor/test/browser_net_post-data-03.js
@@ -49,18 +49,18 @@ function test() {
       is(requestFromUploadScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
         "\"hello world!\"", "The second request header value was incorrect.");
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[2]);
 
       yield waitFor(aMonitor.panelWin, TAB_UPDATED);
 
-      let tab = document.querySelectorAll("#details-pane tab")[2];
-      let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
+      tab = document.querySelectorAll("#details-pane tab")[2];
+      tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
       let formDataScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
 
       is(tab.getAttribute("selected"), "true",
         "The response tab in the network details pane should be selected.");
       is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
         "There should be 1 header scope displayed in this tabpanel.");
 
       is(formDataScope.querySelector(".name").getAttribute("value"),
--- a/browser/devtools/profiler/test/browser_profiler_data-massaging-01.js
+++ b/browser/devtools/profiler/test/browser_profiler_data-massaging-01.js
@@ -28,17 +28,17 @@ let test = Task.async(function*() {
   ok(firstRecordingData.recordingDuration >= WAIT_TIME,
     "The first recording duration is correct.");
   ok(firstRecordingFinishTime >= WAIT_TIME,
     "The first recording finish time is correct.");
 
   // Perform the second recording...
 
   yield front.startRecording();
-  let profilingStartTime = front._profilingStartTime;
+  profilingStartTime = front._profilingStartTime;
   info("Started profiling at: " + profilingStartTime);
 
   busyWait(WAIT_TIME); // allow the profiler module to sample more cpu activity
 
   let secondRecordingData = yield front.stopRecording();
   let secondRecordingFinishTime = secondRecordingData.profilerData.currentTime;
   let secondRecordingProfile = secondRecordingData.profilerData.profile;
   let secondRecordingSamples = secondRecordingProfile.threads[0].samples;
--- a/browser/devtools/profiler/test/browser_profiler_jump-to-debugger-02.js
+++ b/browser/devtools/profiler/test/browser_profiler_jump-to-debugger-02.js
@@ -25,17 +25,17 @@ let test = Task.async(function*() {
   let profilerPanel = toolbox.getCurrentPanel();
   let profilerWin = profilerPanel.panelWin;
   let profilerEvents = profilerWin.EVENTS;
 
   let whenSourceShown = profilerWin.once(profilerEvents.SOURCE_SHOWN_IN_JS_DEBUGGER);
   profilerWin.viewSourceInDebugger(SIMPLE_URL, 14);
   yield whenSourceShown;
 
-  let debuggerPanel = toolbox.getPanel("jsdebugger");
+  debuggerPanel = toolbox.getPanel("jsdebugger");
   ok(debuggerPanel, "The debugger panel was reselected.");
 
   is(DebuggerView.Sources.selectedValue, SIMPLE_URL,
     "The correct source is still shown in the debugger.");
   is(DebuggerView.editor.getCursor().line + 1, 14,
     "The correct line is now highlighted in the debugger's source editor.");
 
   yield teardown(profilerPanel);
--- a/browser/devtools/profiler/test/browser_profiler_shared-connection-03.js
+++ b/browser/devtools/profiler/test/browser_profiler_shared-connection-03.js
@@ -13,17 +13,17 @@ let test = Task.async(function*() {
     "The built-in profiler module should not have been automatically started.");
 
   let result = yield front._request("profiler", "startProfiler");
   is(result.started, true,
     "The request finished successfully and the profiler should've been started.");
   ok(nsIProfilerModule.IsActive(),
     "The built-in profiler module should now be active.");
 
-  let result = yield front._request("profiler", "stopProfiler");
+  result = yield front._request("profiler", "stopProfiler");
   is(result.started, false,
     "The request finished successfully and the profiler should've been stopped.");
   ok(!nsIProfilerModule.IsActive(),
     "The built-in profiler module should now be inactive.");
 
   yield teardown(panel);
   finish();
 });
--- a/browser/devtools/profiler/test/browser_profiler_tree-abstract-01.js
+++ b/browser/devtools/profiler/test/browser_profiler_tree-abstract-01.js
@@ -85,26 +85,26 @@ let test = Task.async(function*() {
   is(barItem.container, container,
     "The 'bar' node's container is correct.");
 
   // Test other events on the child nodes...
 
   let receivedFocusEvent = treeRoot.once("focus");
   EventUtils.sendMouseEvent({ type: "mousedown" }, fooItem.target);
 
-  let eventItem = yield receivedFocusEvent;
+  eventItem = yield receivedFocusEvent;
   is(eventItem, fooItem,
     "The 'focus' event target is correct.");
   is(document.commandDispatcher.focusedElement, fooItem.target,
     "The 'foo' node is now focused.");
 
   let receivedDblClickEvent = treeRoot.once("focus");
   EventUtils.sendMouseEvent({ type: "dblclick" }, barItem.target);
 
-  let eventItem = yield receivedDblClickEvent;
+  eventItem = yield receivedDblClickEvent;
   is(eventItem, barItem,
     "The 'dblclick' event target is correct.");
   is(document.commandDispatcher.focusedElement, barItem.target,
     "The 'bar' node is now focused.");
 
   // A child item got expanded, test the descendants...
 
   let bazItem = barItem.getChild(0);
--- a/browser/devtools/profiler/test/browser_profiler_tree-view-06.js
+++ b/browser/devtools/profiler/test/browser_profiler_tree-view-06.js
@@ -24,17 +24,17 @@ let test = Task.async(function*() {
   EventUtils.sendMouseEvent({ type: "mousedown" }, C.target.querySelector(".call-tree-url"));
 
   let eventItem = yield receivedLinkEvent;
   is(eventItem, C, "The 'link' event target is correct.");
 
   let receivedZoomEvent = treeRoot.once("zoom");
   EventUtils.sendMouseEvent({ type: "mousedown" }, C.target.querySelector(".call-tree-zoom"));
 
-  let eventItem = yield receivedZoomEvent;
+  eventItem = yield receivedZoomEvent;
   is(eventItem, C, "The 'zoom' event target is correct.");
 
   finish();
 });
 
 let gSamples = [{
   time: 5,
   frames: [
--- a/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_01.js
+++ b/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_01.js
@@ -13,15 +13,15 @@ let test = asyncTest(function*() {
   ok(projecteditor, "ProjectEditor has loaded");
 
   let contextMenuPopup = projecteditor.document.querySelector("#context-menu-popup");
   let textEditorContextMenuPopup = projecteditor.document.querySelector("#texteditor-context-popup");
   ok (contextMenuPopup, "The menu has loaded in the projecteditor document");
   ok (textEditorContextMenuPopup, "The menu has loaded in the projecteditor document");
 
   let projecteditor2 = yield addProjectEditorTabForTempDirectory();
-  let contextMenuPopup = projecteditor2.document.getElementById("context-menu-popup");
-  let textEditorContextMenuPopup = projecteditor2.document.getElementById("texteditor-context-popup");
+  contextMenuPopup = projecteditor2.document.getElementById("context-menu-popup");
+  textEditorContextMenuPopup = projecteditor2.document.getElementById("texteditor-context-popup");
   ok (!contextMenuPopup, "The menu has NOT loaded in the projecteditor document");
   ok (!textEditorContextMenuPopup, "The menu has NOT loaded in the projecteditor document");
   ok (content.document.querySelector("#context-menu-popup"), "The menu has loaded in the specified element");
   ok (content.document.querySelector("#texteditor-context-popup"), "The menu has loaded in the specified element");
-});
\ No newline at end of file
+});
--- a/browser/devtools/projecteditor/test/browser_projecteditor_editors_image.js
+++ b/browser/devtools/projecteditor/test/browser_projecteditor_editors_image.js
@@ -53,16 +53,16 @@ function testEditor(projecteditor, fileP
   is (editor.image.getAttribute("src"), resource.uri, "The image has the resource URL");
 
   info ("Selecting another resource, then reselecting this one");
   projecteditor.projectTree.selectResource(resource.store.root);
   yield onceEditorActivated(projecteditor);
   projecteditor.projectTree.selectResource(resource);
   yield onceEditorActivated(projecteditor);
 
-  let editor = projecteditor.currentEditor;
-  let images = editor.elt.querySelectorAll("image");
+  editor = projecteditor.currentEditor;
+  images = editor.elt.querySelectorAll("image");
   ok (images.length, 1, "There is one image inside the editor");
   is (images[0], editor.image, "The image property is set correctly with the DOM");
   is (editor.image.getAttribute("src"), resource.uri, "The image has the resource URL");
 
   info ("Finished checking saving for " + filePath);
 }
--- a/browser/devtools/projecteditor/test/browser_projecteditor_external_change.js
+++ b/browser/devtools/projecteditor/test/browser_projecteditor_external_change.js
@@ -45,17 +45,17 @@ function testChangeUnsavedFileExternally
   yield writeToFile(resource.path, newData);
 
   info ("Selecting another resource, then reselecting this one");
   projecteditor.projectTree.selectResource(resource.store.root);
   yield onceEditorActivated(projecteditor);
   projecteditor.projectTree.selectResource(resource);
   yield onceEditorActivated(projecteditor);
 
-  let editor = projecteditor.currentEditor;
+  editor = projecteditor.currentEditor;
   info ("Checking to make sure the editor is now populated correctly");
   is (editor.editor.getText(), "foobar", "Editor has not been updated with new file contents");
 
   info ("Finished checking saving for " + filePath);
 }
 
 function testChangeFileExternally(projecteditor, filePath, newData) {
   info ("Testing file external changes for: " + filePath);
@@ -71,14 +71,14 @@ function testChangeFileExternally(projec
   yield writeToFile(resource.path, newData);
 
   info ("Selecting another resource, then reselecting this one");
   projecteditor.projectTree.selectResource(resource.store.root);
   yield onceEditorActivated(projecteditor);
   projecteditor.projectTree.selectResource(resource);
   yield onceEditorActivated(projecteditor);
 
-  let editor = projecteditor.currentEditor;
+  editor = projecteditor.currentEditor;
   info ("Checking to make sure the editor is now populated correctly");
   is (editor.editor.getText(), newData, "Editor has been updated with correct file contents");
 
   info ("Finished checking saving for " + filePath);
 }
--- a/browser/devtools/projecteditor/test/browser_projecteditor_menubar_01.js
+++ b/browser/devtools/projecteditor/test/browser_projecteditor_menubar_01.js
@@ -14,15 +14,15 @@ let test = asyncTest(function*() {
 
   let fileMenu = projecteditor.document.getElementById("file-menu");
   let editMenu = projecteditor.document.getElementById("edit-menu");
   ok (fileMenu, "The menu has loaded in the projecteditor document");
   ok (editMenu, "The menu has loaded in the projecteditor document");
 
   let projecteditor2 = yield addProjectEditorTabForTempDirectory();
   let menubar = projecteditor2.menubar;
-  let fileMenu = projecteditor2.document.getElementById("file-menu");
-  let editMenu = projecteditor2.document.getElementById("edit-menu");
+  fileMenu = projecteditor2.document.getElementById("file-menu");
+  editMenu = projecteditor2.document.getElementById("edit-menu");
   ok (!fileMenu, "The menu has NOT loaded in the projecteditor document");
   ok (!editMenu, "The menu has NOT loaded in the projecteditor document");
   ok (content.document.querySelector("#file-menu"), "The menu has loaded in the specified element");
   ok (content.document.querySelector("#edit-menu"), "The menu has loaded in the specified element");
-});
\ No newline at end of file
+});
--- a/browser/devtools/responsivedesign/test/browser_responsiveui.js
+++ b/browser/devtools/responsivedesign/test/browser_responsiveui.js
@@ -185,20 +185,20 @@ function test() {
     is(content.innerHeight, initialHeight, "Size hasn't changed (height).");
 
     // Only the `change` event must change the size
     EventUtils.synthesizeKey("VK_RETURN", {});
 
     is(content.innerWidth, expectedWidth, "Size correctly updated (width).");
     is(content.innerHeight, expectedHeight, "Size correctly updated (height).");
     is(instance.menulist.selectedIndex, -1, "Custom menuitem cannot be selected");
-    let label = instance.menulist.firstChild.firstChild.getAttribute("label");
-    let value = instance.menulist.value;
-    isnot(label, value, "Label from the menulist item is different than the value of the menulist")
-    let [width, height] = extractSizeFromString(label);
+    label = instance.menulist.firstChild.firstChild.getAttribute("label");
+    value = instance.menulist.value;
+    isnot(label, value, "Label from the menulist item is different than the value of the menulist");
+    [width, height] = extractSizeFromString(label);
     is(width, expectedWidth, "Label updated (width).");
     is(height, expectedHeight, "Label updated (height).");
     [width, height] = extractSizeFromString(value);
     is(width, expectedWidth, "Value updated (width).");
     is(height, expectedHeight, "Value updated (height).");
 
     testCustomInput2();
   }
--- a/browser/devtools/scratchpad/test/browser_scratchpad_display_outputs_errors.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_display_outputs_errors.js
@@ -38,17 +38,17 @@ function runTests()
     code: error,
     result: error + openComment + "Exception: Ouch!\n@" +
             scratchpad.uniqueName + ":1:7" + closeComment,
     label: "error display output",
   },
   {
     method: "display",
     code: syntaxError,
-    result: syntaxError + openComment + "Exception: syntax error\n@" +
+    result: syntaxError + openComment + "Exception: expected expression, got end of script\n@" +
             scratchpad.uniqueName + ":1" + closeComment,
     label: "syntaxError display output",
   },
   {
     method: "run",
     code: message,
     result: message,
     label: "message run output",
@@ -58,15 +58,15 @@ function runTests()
     code: error,
     result: error + openComment + "Exception: Ouch!\n@" +
             scratchpad.uniqueName + ":1:7" + closeComment,
     label: "error run output",
   },
   {
     method: "run",
     code: syntaxError,
-    result: syntaxError + openComment + "Exception: syntax error\n@" +
+    result: syntaxError + openComment + "Exception: expected expression, got end of script\n@" +
             scratchpad.uniqueName + ":1" + closeComment,
     label: "syntaxError run output",
   }];
 
   runAsyncTests(scratchpad, tests).then(finish);
 }
--- a/browser/devtools/shadereditor/test/browser_se_shaders-edit-02.js
+++ b/browser/devtools/shadereditor/test/browser_se_shaders-edit-02.js
@@ -31,38 +31,38 @@ function ifWebGLSupported() {
   is(error.link.split("ERROR").length - 1, 2,
     "The linkage status contains two errors.");
   ok(error.link.contains("ERROR: 0:8: 'constructor'"),
     "A constructor error is contained in the linkage status.");
   ok(error.link.contains("ERROR: 0:8: 'assign'"),
     "An assignment error is contained in the linkage status.");
 
   fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
-  let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+  [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
 
   ok(error,
     "The new fragment shader source was compiled with errors.");
   is(error.compile, "",
     "The compilation status should be empty.");
   isnot(error.link, "",
     "The linkage status should not be empty.");
   is(error.link.split("ERROR").length - 1, 1,
     "The linkage status contains one error.");
   ok(error.link.contains("ERROR: 0:6: 'constructor'"),
     "A constructor error is contained in the linkage status.");
 
   yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
   yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
 
   vsEditor.replaceText("vec4", { line: 7, ch: 22 }, { line: 7, ch: 26 });
-  let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+  [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
   ok(!error, "The new vertex shader source was compiled successfully.");
 
   fsEditor.replaceText("vec3", { line: 2, ch: 14 }, { line: 2, ch: 18 });
-  let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
+  [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
   ok(!error, "The new fragment shader source was compiled successfully.");
 
   yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
   yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
 
   yield teardown(panel);
   finish();
 }
--- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-07.js
+++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-07.js
@@ -28,34 +28,34 @@ function ifWebGLSupported() {
   let status = yield vertexShader.compile(newVertSource);
   ok(!status,
     "The new vertex shader source was compiled without errors.");
 
   yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
   yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 255 }, true);
   yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true);
 
-  let vertSource = yield vertexShader.getText();
-  let fragSource = yield fragmentShader.getText();
+  vertSource = yield vertexShader.getText();
+  fragSource = yield fragmentShader.getText();
   ok(vertSource.contains("2.0"),
     "The vertex shader source is correct after changing it.");
   ok(!fragSource.contains("0.5"),
     "The fragment shader source is correct after changing the vertex shader.");
 
   let newFragSource = fragSource.replace("1.0", "0.5");
-  let status = yield fragmentShader.compile(newFragSource);
+  status = yield fragmentShader.compile(newFragSource);
   ok(!status,
     "The new fragment shader source was compiled without errors.");
 
   yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
   yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 127 }, true);
   yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true);
 
-  let vertSource = yield vertexShader.getText();
-  let fragSource = yield fragmentShader.getText();
+  vertSource = yield vertexShader.getText();
+  fragSource = yield fragmentShader.getText();
   ok(vertSource.contains("2.0"),
     "The vertex shader source is correct after changing the fragment shader.");
   ok(fragSource.contains("0.5"),
     "The fragment shader source is correct after changing it.");
 
   yield removeTab(target.tab);
   finish();
 }
--- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-14.js
+++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-14.js
@@ -23,19 +23,19 @@ function ifWebGLSupported() {
 
   yield front.waitForFrame();
   yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
   yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
   ok(true, "The first fragment shader was changed.");
 
-  let oldFragSource = yield secondFragmentShader.getText();
-  let newFragSource = oldFragSource.replace("vec4(uColor", "vec4(0.75, 0.75, 0.75");
-  let status = yield secondFragmentShader.compile(newFragSource);
+  oldFragSource = yield secondFragmentShader.getText();
+  newFragSource = oldFragSource.replace("vec4(uColor", "vec4(0.75, 0.75, 0.75");
+  status = yield secondFragmentShader.compile(newFragSource);
   ok(!status,
     "The second new fragment shader source was compiled without errors.");
 
   yield front.waitForFrame();
   yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 191, g: 191, b: 191, a: 255 }, true, "#canvas2");
   yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 191, g: 191, b: 191, a: 255 }, true, "#canvas2");
--- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js
+++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js
@@ -27,64 +27,64 @@ function ifWebGLSupported() {
   let allPrograms = yield front._getAllPrograms();
   is(allPrograms.length, 1,
     "Should be only one program in cache.");
 
   // 1. Perform a simple navigation.
 
   navigate(target, MULTIPLE_CONTEXTS_URL);
   let [secondProgram, thirdProgram] = yield getPrograms(front, 2);
-  let programs = yield front.getPrograms();
+  programs = yield front.getPrograms();
   is(programs.length, 2,
     "The second and third programs should be returned by a call to getPrograms().");
   is(programs[0], secondProgram,
     "The second programs was correctly retrieved from the cache.");
   is(programs[1], thirdProgram,
     "The third programs was correctly retrieved from the cache.");
 
-  let allPrograms = yield front._getAllPrograms();
+  allPrograms = yield front._getAllPrograms();
   is(allPrograms.length, 3,
     "Should be three programs in cache.");
 
   // 2. Perform a bfcache navigation.
 
   yield navigateInHistory(target, "back");
   let globalDestroyed = once(front, "global-created");
   let globalCreated = once(front, "global-destroyed");
   let programsLinked = once(front, "program-linked");
   reload(target);
 
   yield promise.all([programsLinked, globalDestroyed, globalCreated]);
-  let allPrograms = yield front._getAllPrograms();
+  allPrograms = yield front._getAllPrograms();
   is(allPrograms.length, 3,
     "Should be 3 programs total in cache.");
 
-  let programs = yield front.getPrograms();
+  programs = yield front.getPrograms();
   is(programs.length, 1,
     "There should be 1 cached program actor now.");
 
   yield checkHighlightingInTheFirstPage(programs[0]);
   ok(true, "The cached programs behave correctly after navigating back and reloading.");
 
   // 3. Perform a bfcache navigation and a page reload.
 
   yield navigateInHistory(target, "forward");
 
-  let globalDestroyed = once(front, "global-created");
-  let globalCreated = once(front, "global-destroyed");
-  let programsLinked = getPrograms(front, 2);
+  globalDestroyed = once(front, "global-created");
+  globalCreated = once(front, "global-destroyed");
+  programsLinked = getPrograms(front, 2);
 
   reload(target);
 
   yield promise.all([programsLinked, globalDestroyed, globalCreated]);
-  let allPrograms = yield front._getAllPrograms();
+  allPrograms = yield front._getAllPrograms();
   is(allPrograms.length, 3,
     "Should be 3 programs total in cache.");
 
-  let programs = yield front.getPrograms();
+  programs = yield front.getPrograms();
   is(programs.length, 2,
     "There should be 2 cached program actors now.");
 
   yield checkHighlightingInTheSecondPage(programs[0], programs[1]);
   ok(true, "The cached programs behave correctly after navigating forward and reloading.");
 
   yield removeTab(target.tab);
   finish();
--- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-18.js
+++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-18.js
@@ -15,17 +15,17 @@ function ifWebGLSupported() {
   yield front.waitForFrame();
 
   let pixel = yield front.getPixel({ selector: "#canvas1", position: { x: 0, y: 0 }});
   is(pixel.r, 255, "correct `r` value for first canvas.")
   is(pixel.g, 255, "correct `g` value for first canvas.")
   is(pixel.b, 0, "correct `b` value for first canvas.")
   is(pixel.a, 255, "correct `a` value for first canvas.")
 
-  let pixel = yield front.getPixel({ selector: "#canvas2", position: { x: 0, y: 0 }});
+  pixel = yield front.getPixel({ selector: "#canvas2", position: { x: 0, y: 0 }});
   is(pixel.r, 0, "correct `r` value for second canvas.")
   is(pixel.g, 255, "correct `g` value for second canvas.")
   is(pixel.b, 255, "correct `b` value for second canvas.")
   is(pixel.a, 255, "correct `a` value for second canvas.")
 
   yield removeTab(target.tab);
   finish();
 }
--- a/browser/devtools/shared/test/browser_cubic-bezier-02.js
+++ b/browser/devtools/shared/test/browser_cubic-bezier-02.js
@@ -40,26 +40,26 @@ function* pointsCanBeDragged(widget) {
 
   let bezier = yield onUpdated;
   ok(true, "The widget fired the updated event");
   ok(bezier, "The updated event contains a bezier argument");
   is(bezier.P1[0], 0, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 1, "The new P1 progress coordinate is correct");
 
   info("Listening for the update event");
-  let onUpdated = widget.once("updated");
+  onUpdated = widget.once("updated");
 
   info("Generating a mousedown/move/up on P2");
   widget._onPointMouseDown({target: widget.p2});
   EventUtils.synthesizeMouse(content.document.documentElement, 200, 300,
     {type: "mousemove"}, content.window);
   EventUtils.synthesizeMouse(content.document.documentElement, 200, 300,
     {type: "mouseup"}, content.window);
 
-  let bezier = yield onUpdated;
+  bezier = yield onUpdated;
   is(bezier.P2[0], 1, "The new P2 time coordinate is correct");
   is(bezier.P2[1], 0, "The new P2 progress coordinate is correct");
 }
 
 function* curveCanBeClicked(widget) {
   info("Checking that clicking on the curve moves the closest control point");
 
   info("Listening for the update event");
@@ -71,22 +71,22 @@ function* curveCanBeClicked(widget) {
   let bezier = yield onUpdated;
   ok(true, "The widget fired the updated event");
   is(bezier.P1[0], 0.25, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 0.75, "The new P1 progress coordinate is correct");
   is(bezier.P2[0], 1, "P2 time coordinate remained unchanged");
   is(bezier.P2[1], 0, "P2 progress coordinate remained unchanged");
 
   info("Listening for the update event");
-  let onUpdated = widget.once("updated");
+  onUpdated = widget.once("updated");
 
   info("Click close to P2");
   widget._onCurveClick({pageX: 150, pageY: 250});
 
-  let bezier = yield onUpdated;
+  bezier = yield onUpdated;
   is(bezier.P2[0], 0.75, "The new P2 time coordinate is correct");
   is(bezier.P2[1], 0.25, "The new P2 progress coordinate is correct");
   is(bezier.P1[0], 0.25, "P1 time coordinate remained unchanged");
   is(bezier.P1[1], 0.75, "P1 progress coordinate remained unchanged");
 }
 
 function* pointsCanBeMovedWithKeyboard(widget) {
   info("Checking that points respond to keyboard events");
@@ -94,55 +94,55 @@ function* pointsCanBeMovedWithKeyboard(w
   info("Moving P1 to the left");
   let onUpdated = widget.once("updated");
   widget._onPointKeyDown(getKeyEvent(widget.p1, 37));
   let bezier = yield onUpdated;
   is(bezier.P1[0], 0.235, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 0.75, "The new P1 progress coordinate is correct");
 
   info("Moving P1 to the left, fast");
-  let onUpdated = widget.once("updated");
+  onUpdated = widget.once("updated");
   widget._onPointKeyDown(getKeyEvent(widget.p1, 37, true));
-  let bezier = yield onUpdated;
+  bezier = yield onUpdated;
   is(bezier.P1[0], 0.085, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 0.75, "The new P1 progress coordinate is correct");
 
   info("Moving P1 to the right, fast");
-  let onUpdated = widget.once("updated");
+  onUpdated = widget.once("updated");
   widget._onPointKeyDown(getKeyEvent(widget.p1, 39, true));
-  let bezier = yield onUpdated;
+  bezier = yield onUpdated;
   is(bezier.P1[0], 0.235, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 0.75, "The new P1 progress coordinate is correct");
 
   info("Moving P1 to the bottom");
-  let onUpdated = widget.once("updated");
+  onUpdated = widget.once("updated");
   widget._onPointKeyDown(getKeyEvent(widget.p1, 40));
-  let bezier = yield onUpdated;
+  bezier = yield onUpdated;
   is(bezier.P1[0], 0.235, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 0.735, "The new P1 progress coordinate is correct");
 
   info("Moving P1 to the bottom, fast");
-  let onUpdated = widget.once("updated");
+  onUpdated = widget.once("updated");
   widget._onPointKeyDown(getKeyEvent(widget.p1, 40, true));
-  let bezier = yield onUpdated;
+  bezier = yield onUpdated;
   is(bezier.P1[0], 0.235, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 0.585, "The new P1 progress coordinate is correct");
 
   info("Moving P1 to the top, fast");
-  let onUpdated = widget.once("updated");
+  onUpdated = widget.once("updated");
   widget._onPointKeyDown(getKeyEvent(widget.p1, 38, true));
-  let bezier = yield onUpdated;
+  bezier = yield onUpdated;
   is(bezier.P1[0], 0.235, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 0.735, "The new P1 progress coordinate is correct");
 
   info("Checking that keyboard events also work with P2");
   info("Moving P2 to the left");
-  let onUpdated = widget.once("updated");
+  onUpdated = widget.once("updated");
   widget._onPointKeyDown(getKeyEvent(widget.p2, 37));
-  let bezier = yield onUpdated;
+  bezier = yield onUpdated;
   is(bezier.P2[0], 0.735, "The new P2 time coordinate is correct");
   is(bezier.P2[1], 0.25, "The new P2 progress coordinate is correct");
 }
 
 function getKeyEvent(target, keyCode, shift=false) {
   return {
     target: target,
     keyCode: keyCode,
--- a/browser/devtools/shared/test/browser_cubic-bezier-03.js
+++ b/browser/devtools/shared/test/browser_cubic-bezier-03.js
@@ -50,18 +50,18 @@ function* coordinatesCanBeChangedByProvi
   ok(true, "The updated event was fired as a result of setting cssValue");
 
   is(bezier.P1[0], 0, "The new P1 time coordinate is correct");
   is(bezier.P1[1], 0, "The new P1 progress coordinate is correct");
   is(bezier.P2[0], 1, "The new P2 time coordinate is correct");
   is(bezier.P2[1], 1, "The new P2 progress coordinate is correct");
 
   info("Setting a custom cubic-bezier css value");
-  let onUpdated = widget.once("updated");
+  onUpdated = widget.once("updated");
   widget.cssCubicBezierValue = "cubic-bezier(.25,-0.5, 1, 1.45)";
-  let bezier = yield onUpdated;
+  bezier = yield onUpdated;
   ok(true, "The updated event was fired as a result of setting cssValue");
 
   is(bezier.P1[0], .25, "The new P1 time coordinate is correct");
   is(bezier.P1[1], -.5, "The new P1 progress coordinate is correct");
   is(bezier.P2[0], 1, "The new P2 time coordinate is correct");
   is(bezier.P2[1], 1.45, "The new P2 progress coordinate is correct");
 }
--- a/browser/devtools/shared/test/browser_layoutHelpers-getBoxQuads.js
+++ b/browser/devtools/shared/test/browser_layoutHelpers-getBoxQuads.js
@@ -166,17 +166,17 @@ function takesScrollingIntoAccount(doc, 
   let quad = helper.getAdjustedQuads(innerNode, "content");
   is(quad.p1.x, 0, "p1.x of the scrolled node is correct after scrolling down");
   is(quad.p1.y, -300, "p1.y of the scrolled node is correct after scrolling down");
 
   info("Scrolling back up");
   scrolledNode.scrollTop = 0;
   subScrolledNode.scrollTop = 0;
 
-  let quad = helper.getAdjustedQuads(innerNode, "content");
+  quad = helper.getAdjustedQuads(innerNode, "content");
   is(quad.p1.x, 0, "p1.x of the scrolled node is correct after scrolling up");
   is(quad.p1.y, 0, "p1.y of the scrolled node is correct after scrolling up");
 }
 
 function takesZoomIntoAccount(doc, helper) {
   info("Checks that if the page is zoomed in/out, the quad returned is correct");
 
   // Hard-coding coordinates in this zoom test is a bad idea as it can vary
--- a/browser/devtools/shared/test/browser_outputparser.js
+++ b/browser/devtools/shared/test/browser_outputparser.js
@@ -37,17 +37,17 @@ function testParseCssProperty() {
   target.appendChild(frag);
 
   is(target.innerHTML,
      '1px solid <span data-color="#F00"><span style="background-color:red" class="test-colorswatch"></span><span>#F00</span></span>',
      "CSS property correctly parsed");
 
   target.innerHTML = "";
 
-  let frag = parser.parseCssProperty("background-image", "linear-gradient(to right, #F60 10%, rgba(0,0,0,1))", {
+  frag = parser.parseCssProperty("background-image", "linear-gradient(to right, #F60 10%, rgba(0,0,0,1))", {
     colorSwatchClass: "test-colorswatch",
     colorClass: "test-color"
   });
   target.appendChild(frag);
   is(target.innerHTML,
      'linear-gradient(to right, <span data-color="#F60"><span style="background-color:#F60" class="test-colorswatch"></span><span class="test-color">#F60</span></span> 10%, ' +
      '<span data-color="#000"><span style="background-color:rgba(0,0,0,1)" class="test-colorswatch"></span><span class="test-color">#000</span></span>)',
      "Gradient CSS property correctly parsed");
--- a/browser/devtools/shared/test/browser_tableWidget_basic.js
+++ b/browser/devtools/shared/test/browser_tableWidget_basic.js
@@ -334,36 +334,36 @@ function testAPI() {
   }
   // Calling it on an unsorted column should sort by it in ascending manner
   table.sortBy("col2");
   let cell = table.tbody.children[2].firstChild.children[2];
   checkAscendingOrder(cell);
 
   // Calling it again should sort by it in descending manner
   table.sortBy("col2");
-  let cell = table.tbody.children[2].firstChild.lastChild.previousSibling;
+  cell = table.tbody.children[2].firstChild.lastChild.previousSibling;
   checkDescendingOrder(cell);
 
   // Calling it again should sort by it in ascending manner
   table.sortBy("col2");
-  let cell = table.tbody.children[2].firstChild.children[2];
+  cell = table.tbody.children[2].firstChild.children[2];
   checkAscendingOrder(cell);
 
   table.clear();
   populateTable();
 
   // testing if sorting works should sort by ascending manner
   table.sortBy("col4");
-  let cell = table.tbody.children[6].firstChild.children[1];
+  cell = table.tbody.children[6].firstChild.children[1];
   is(cell.textContent, "domnode", "DOMNode sorted correctly");
   checkAscendingOrder(cell.nextSibling);
 
   // Calling it again should sort it in descending order
   table.sortBy("col4");
-  let cell = table.tbody.children[6].firstChild.children[9];
+  cell = table.tbody.children[6].firstChild.children[9];
   is(cell.textContent, "domnode", "DOMNode sorted correctly");
   checkDescendingOrder(cell.previousSibling);
 }
 
 function checkAscendingOrder(cell) {
   while(cell) {
     let currentCell = cell.value || cell.textContent;
     let prevCell = cell.previousSibling.value || cell.previousSibling.textContent;
--- a/browser/devtools/shared/test/browser_tableWidget_keyboard_interaction.js
+++ b/browser/devtools/shared/test/browser_tableWidget_keyboard_interaction.js
@@ -142,17 +142,17 @@ let testKeyboardInteraction = Task.async
 
   node = table.tbody.firstChild.firstChild.children[2];
   // node should not have selected class
   ok(!node.classList.contains("theme-selected"),
      "Row should not have selected class");
   info("Pressing down key to select next row");
   event = table.once(TableWidget.EVENTS.ROW_SELECTED);
   EventUtils.sendKey("DOWN", doc.defaultView);
-  let id = yield event;
+  id = yield event;
   is(id, "id2", "Correct row was selected after pressing down");
   ok(node.classList.contains("theme-selected"), "row has selected class");
   let nodes = doc.querySelectorAll(".theme-selected");
   for (let i = 0; i < nodes.length; i++) {
     is(nodes[i].getAttribute("data-id"), "id2",
        "Correct cell selected in all columns");
   }
 
@@ -161,34 +161,34 @@ let testKeyboardInteraction = Task.async
   ok(!node.classList.contains("theme-selected"),
      "Row should not have selected class");
   info("Pressing down key to select next row");
   event = table.once(TableWidget.EVENTS.ROW_SELECTED);
   EventUtils.sendKey("DOWN", doc.defaultView);
   id = yield event;
   is(id, "id3", "Correct row was selected after pressing down");
   ok(node.classList.contains("theme-selected"), "row has selected class");
-  let nodes = doc.querySelectorAll(".theme-selected");
+  nodes = doc.querySelectorAll(".theme-selected");
   for (let i = 0; i < nodes.length; i++) {
     is(nodes[i].getAttribute("data-id"), "id3",
        "Correct cell selected in all columns");
   }
 
   // pressing up arrow key to select previous row
   node = table.tbody.firstChild.firstChild.children[2];
   // node should not have selected class
   ok(!node.classList.contains("theme-selected"),
      "Row should not have selected class");
   info("Pressing up key to select previous row");
   event = table.once(TableWidget.EVENTS.ROW_SELECTED);
   EventUtils.sendKey("UP", doc.defaultView);
   id = yield event;
   is(id, "id2", "Correct row was selected after pressing down");
   ok(node.classList.contains("theme-selected"), "row has selected class");
-  let nodes = doc.querySelectorAll(".theme-selected");
+  nodes = doc.querySelectorAll(".theme-selected");
   for (let i = 0; i < nodes.length; i++) {
     is(nodes[i].getAttribute("data-id"), "id2",
        "Correct cell selected in all columns");
   }
 
   // selecting last item node to test edge navigation cycling case
   table.selectedRow = "id9";
   // pressing down now should move to first row.
@@ -197,31 +197,31 @@ let testKeyboardInteraction = Task.async
   ok(!node.classList.contains("theme-selected"),
      "Row should not have selected class");
   info("Pressing down key on last row to select first row");
   event = table.once(TableWidget.EVENTS.ROW_SELECTED);
   EventUtils.sendKey("DOWN", doc.defaultView);
   id = yield event;
   is(id, "id1", "Correct row was selected after pressing down");
   ok(node.classList.contains("theme-selected"), "row has selected class");
-  let nodes = doc.querySelectorAll(".theme-selected");
+  nodes = doc.querySelectorAll(".theme-selected");
   for (let i = 0; i < nodes.length; i++) {
     is(nodes[i].getAttribute("data-id"), "id1",
        "Correct cell selected in all columns");
   }
 
   // pressing up now should move to last row.
   node = table.tbody.firstChild.firstChild.lastChild;
   // node should not have selected class
   ok(!node.classList.contains("theme-selected"),
      "Row should not have selected class");
   info("Pressing down key on last row to select first row");
   event = table.once(TableWidget.EVENTS.ROW_SELECTED);
   EventUtils.sendKey("UP", doc.defaultView);
   id = yield event;
   is(id, "id9", "Correct row was selected after pressing down");
   ok(node.classList.contains("theme-selected"), "row has selected class");
-  let nodes = doc.querySelectorAll(".theme-selected");
+  nodes = doc.querySelectorAll(".theme-selected");
   for (let i = 0; i < nodes.length; i++) {
     is(nodes[i].getAttribute("data-id"), "id9",
        "Correct cell selected in all columns");
   }
 });
--- a/browser/devtools/shared/test/browser_tableWidget_mouse_interaction.js
+++ b/browser/devtools/shared/test/browser_tableWidget_mouse_interaction.js
@@ -142,157 +142,157 @@ let testMouseInteraction = Task.async(fu
   ok(!node.classList.contains("theme-selected"),
      "Node should not have selected class before clicking");
   click(node);
   let id = yield event;
   ok(node.classList.contains("theme-selected"), "Node has selected class after click");
   is(id, "id1", "Correct row was selected");
 
   info("clicking on third row to select it");
-  let event = table.once(TableWidget.EVENTS.ROW_SELECTED);
+  event = table.once(TableWidget.EVENTS.ROW_SELECTED);
   let node2 = table.tbody.firstChild.firstChild.children[3];
   // node should not have selected class
   ok(!node2.classList.contains("theme-selected"),
      "New node should not have selected class before clicking");
   click(node2);
-  let id = yield event;
+  id = yield event;
   ok(node2.classList.contains("theme-selected"),
      "New node has selected class after clicking");
   is(id, "id3", "Correct table path is emitted for new node")
   isnot(node, node2, "Old and new node are different");
   ok(!node.classList.contains("theme-selected"),
      "Old node should not have selected class after the click on new node");
 
   // clicking on table header to sort by it
-  let event = table.once(TableWidget.EVENTS.COLUMN_SORTED);
-  let node = table.tbody.children[6].firstChild.children[0];
+  event = table.once(TableWidget.EVENTS.COLUMN_SORTED);
+  node = table.tbody.children[6].firstChild.children[0];
   info("clicking on the 4th coulmn header to sort the table by it");
   ok(!node.hasAttribute("sorted"),
      "Node should not have sorted attribute before clicking");
   ok(doc.querySelector("[sorted]"), "Although, something else should be sorted on");
   isnot(doc.querySelector("[sorted]"), node, "Which is not equal to this node");
   click(node);
-  let id = yield event;
+  id = yield event;
   is(id, "col4", "Correct column was sorted on");
   ok(node.hasAttribute("sorted"),
      "Node should now have sorted attribute after clicking");
   is(doc.querySelectorAll("[sorted]").length, 1,
      "Now only one column should be sorted on");
   is(doc.querySelector("[sorted]"), node, "Which should be this column");
 
   // test context menu opening.
   // hiding second column
   // event listener for popupshown
-  let event = Promise.defer();
+  event = Promise.defer();
   table.menupopup.addEventListener("popupshown", function onPopupShown(e) {
     table.menupopup.removeEventListener("popupshown", onPopupShown);
     event.resolve();
   })
   info("right clicking on the first column header");
-  let node = table.tbody.firstChild.firstChild.firstChild;
+  node = table.tbody.firstChild.firstChild.firstChild;
   click(node, 2);
   yield event.promise;
   is(table.menupopup.querySelectorAll("[disabled]").length, 1,
      "Only 1 menuitem is disabled");
   is(table.menupopup.querySelector("[disabled]"),
      table.menupopup.querySelector("[data-id='col1']"),
      "Which is the unique column");
   // popup should be open now
   // clicking on second column label
-  let event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU);
-  let node = table.menupopup.querySelector("[data-id='col2']");
+  event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU);
+  node = table.menupopup.querySelector("[data-id='col2']");
   info("selecting to hide the second column");
   ok(!table.tbody.children[2].hasAttribute("hidden"),
      "Column is not hidden before hiding it");
   click(node);
-  let id = yield event;
+  id = yield event;
   is(id, "col2", "Correct column was triggered to be hidden");
   is(table.tbody.children[2].getAttribute("hidden"), "true",
      "Column is hidden after hiding it");
 
   // hiding third column
   // event listener for popupshown
-  let event = Promise.defer();
+  event = Promise.defer();
   table.menupopup.addEventListener("popupshown", function onPopupShown(e) {
     table.menupopup.removeEventListener("popupshown", onPopupShown);
     event.resolve();
   })
   info("right clicking on the first column header");
-  let node = table.tbody.firstChild.firstChild.firstChild;
+  node = table.tbody.firstChild.firstChild.firstChild;
   click(node, 2);
   yield event.promise;
   is(table.menupopup.querySelectorAll("[disabled]").length, 1,
      "Only 1 menuitem is disabled");
   // popup should be open now
   // clicking on second column label
-  let event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU);
-  let node = table.menupopup.querySelector("[data-id='col3']");
+  event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU);
+  node = table.menupopup.querySelector("[data-id='col3']");
   info("selecting to hide the second column");
   ok(!table.tbody.children[4].hasAttribute("hidden"),
      "Column is not hidden before hiding it");
   click(node);
-  let id = yield event;
+  id = yield event;
   is(id, "col3", "Correct column was triggered to be hidden");
   is(table.tbody.children[4].getAttribute("hidden"), "true",
      "Column is hidden after hiding it");
 
   // opening again to see if 2 items are disabled now
   // event listener for popupshown
-  let event = Promise.defer();
+  event = Promise.defer();
   table.menupopup.addEventListener("popupshown", function onPopupShown(e) {
     table.menupopup.removeEventListener("popupshown", onPopupShown);
     event.resolve();
   })
   info("right clicking on the first column header");
-  let node = table.tbody.firstChild.firstChild.firstChild;
+  node = table.tbody.firstChild.firstChild.firstChild;
   click(node, 2);
   yield event.promise;
   is(table.menupopup.querySelectorAll("[disabled]").length, 2,
      "2 menuitems are disabled now as only 2 columns remain visible");
   is(table.menupopup.querySelectorAll("[disabled]")[0],
      table.menupopup.querySelector("[data-id='col1']"),
      "First is the unique column");
   is(table.menupopup.querySelectorAll("[disabled]")[1],
      table.menupopup.querySelector("[data-id='col4']"),
      "Second is the last column");
 
   // showing back 2nd column
   // popup should be open now
   // clicking on second column label
-  let event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU);
-  let node = table.menupopup.querySelector("[data-id='col2']");
+  event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU);
+  node = table.menupopup.querySelector("[data-id='col2']");
   info("selecting to hide the second column");
   is(table.tbody.children[2].getAttribute("hidden"), "true",
      "Column is hidden before unhiding it");
   click(node);
-  let id = yield event;
+  id = yield event;
   is(id, "col2", "Correct column was triggered to be hidden");
   ok(!table.tbody.children[2].hasAttribute("hidden"),
      "Column is not hidden after unhiding it");
 
   // showing back 3rd column
   // event listener for popupshown
-  let event = Promise.defer();
+  event = Promise.defer();
   table.menupopup.addEventListener("popupshown", function onPopupShown(e) {
     table.menupopup.removeEventListener("popupshown", onPopupShown);
     event.resolve();
   })
   info("right clicking on the first column header");
-  let node = table.tbody.firstChild.firstChild.firstChild;
+  node = table.tbody.firstChild.firstChild.firstChild;
   click(node, 2);
   yield event.promise;
   // popup should be open now
   // clicking on second column label
-  let event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU);
-  let node = table.menupopup.querySelector("[data-id='col3']");
+  event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU);
+  node = table.menupopup.querySelector("[data-id='col3']");
   info("selecting to hide the second column");
   is(table.tbody.children[4].getAttribute("hidden"), "true",
      "Column is hidden before unhiding it");
   click(node);
-  let id = yield event;
+  id = yield event;
   is(id, "col3", "Correct column was triggered to be hidden");
   ok(!table.tbody.children[4].hasAttribute("hidden"),
      "Column is not hidden after unhiding it");
 
   // reset table state
   table.clearSelection();
   table.sortBy("col1");
 });
--- a/browser/devtools/shared/test/browser_treeWidget_keyboard_interaction.js
+++ b/browser/devtools/shared/test/browser_treeWidget_keyboard_interaction.js
@@ -119,36 +119,36 @@ let testKeyboardInteraction = Task.async
   ok(!attachment, "null attachment was emitted");
   ok(node.classList.contains("theme-selected"), "Node has selected class");
   ok(node.hasAttribute("expanded"), "Node is expanded now");
 
   info("Pressing down key again to select next item");
   event = Promise.defer();
   tree.once("select", pass);
   EventUtils.sendKey("DOWN", content);
-  let [name, data, attachment] = yield event.promise;
+  [name, data, attachment] = yield event.promise;
   is(data.length, 2, "Correct level item was selected after second down keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2", "Correct second level");
 
   info("Pressing down key again to select next item");
   event = Promise.defer();
   tree.once("select", pass);
   EventUtils.sendKey("DOWN", content);
-  let [name, data, attachment] = yield event.promise;
+  [name, data, attachment] = yield event.promise;
   is(data.length, 3, "Correct level item was selected after third down keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2", "Correct second level");
   is(data[2], "level3", "Correct third level");
 
   info("Pressing down key again to select next item");
   event = Promise.defer();
   tree.once("select", pass);
   EventUtils.sendKey("DOWN", content);
-  let [name, data, attachment] = yield event.promise;
+  [name, data, attachment] = yield event.promise;
   is(data.length, 2, "Correct level item was selected after fourth down keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2-1", "Correct second level");
 
   // pressing left to check expand collapse feature.
   // This does not emit any event, so listening for keypress
   tree.root.children.addEventListener("keypress", function onClick() {
     tree.root.children.removeEventListener("keypress", onClick);
@@ -168,30 +168,30 @@ let testKeyboardInteraction = Task.async
 
   info("Pressing left key on collapsed item to select previous");
   tree.once("select", pass);
   event = Promise.defer();
   // parent node should have no effect of this keypress
   node = tree.root.children.firstChild.nextSibling.firstChild;
   ok(node.hasAttribute("expanded"), "Parent is expanded");
   EventUtils.sendKey("LEFT", content);
-  let [name, data] = yield event.promise;
+  [name, data] = yield event.promise;
   is(data.length, 3, "Correct level item was selected after second left keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2", "Correct second level");
   is(data[2], "level3", "Correct third level");
   ok(node.hasAttribute("expanded"), "Parent is still expanded after left keypress");
 
   // pressing down again
 
   info("Pressing down key to select next item");
   event = Promise.defer();
   tree.once("select", pass);
   EventUtils.sendKey("DOWN", content);
-  let [name, data, attachment] = yield event.promise;
+  [name, data, attachment] = yield event.promise;
   is(data.length, 2, "Correct level item was selected after fifth down keypress");
   is(data[0], "level1", "Correct parent level");
   is(data[1], "level2-1", "Correct second level");
 
   // collapsing the item to check expand feature.
 
   tree.root.children.addEventListener("keypress", function onClick() {
     tree.root.children.removeEventListener("keypress", onClick);
--- a/browser/devtools/shared/test/browser_treeWidget_mouse_interaction.js
+++ b/browser/devtools/shared/test/browser_treeWidget_mouse_interaction.js
@@ -118,17 +118,17 @@ let testMouseInteraction = Task.async(fu
   let node2 = tree.root.children.firstChild.nextSibling.firstChild;
   event = Promise.defer();
   // node should not have selected class
   ok(!node2.classList.contains("theme-selected"),
      "New node should not have selected class before clicking");
   ok(!node2.hasAttribute("expanded"), "New node is not expanded before clicking");
   tree.once("select", pass);
   click(node2);
-  let [name, data, attachment] = yield event.promise;
+  [name, data, attachment] = yield event.promise;
   ok(node2.classList.contains("theme-selected"),
      "New node has selected class after clicking");
   is(data[0], "level1", "Correct tree path is emitted for new node")
   ok(!attachment, "null attachment should be emitted for new node")
   ok(node2.hasAttribute("expanded"), "New node expanded after click");
 
   ok(!node.classList.contains("theme-selected"),
      "Old node should not have selected class after the click on new node");
--- a/browser/devtools/shared/test/unit/test_bezierCanvas.js
+++ b/browser/devtools/shared/test/unit/test_bezierCanvas.js
@@ -33,18 +33,18 @@ function offsetsGetterReturnsData() {
 
   do_check_eq(offsets[0].top, "300px");
   do_check_eq(offsets[0].left, "0px");
   do_check_eq(offsets[1].top, "100px");
   do_check_eq(offsets[1].left, "200px");
 
   do_print("offsets getter returns data according to current padding");
 
-  let b = new BezierCanvas(getCanvasMock(), getCubicBezier(), [0, 0]);
-  let offsets = b.offsets;
+  b = new BezierCanvas(getCanvasMock(), getCubicBezier(), [0, 0]);
+  offsets = b.offsets;
 
   do_check_eq(offsets[0].top, "400px");
   do_check_eq(offsets[0].left, "0px");
   do_check_eq(offsets[1].top, "0px");
   do_check_eq(offsets[1].left, "200px");
 }
 
 function convertsOffsetsToCoordinates() {
@@ -55,24 +55,24 @@ function convertsOffsetsToCoordinates() 
   let coordinates = b.offsetsToCoordinates({style: {
     left: "0px",
     top: "0px"
   }});
   do_check_eq(coordinates.length, 2);
   do_check_eq(coordinates[0], 0);
   do_check_eq(coordinates[1], 1.5);
 
-  let coordinates = b.offsetsToCoordinates({style: {
+  coordinates = b.offsetsToCoordinates({style: {
     left: "0px",
     top: "300px"
   }});
   do_check_eq(coordinates[0], 0);
   do_check_eq(coordinates[1], 0);
 
-  let coordinates = b.offsetsToCoordinates({style: {
+  coordinates = b.offsetsToCoordinates({style: {
     left: "200px",
     top: "100px"
   }});
   do_check_eq(coordinates[0], 1);
   do_check_eq(coordinates[1], 1);
 }
 
 function plotsCanvas() {
--- a/browser/devtools/shared/test/unit/test_cubicBezier.js
+++ b/browser/devtools/shared/test/unit/test_cubicBezier.js
@@ -61,18 +61,18 @@ function convertsStringCoordinates() {
 
 function coordinatesToStringOutputsAString() {
   do_print("coordinates.toString() outputs a string representation");
 
   let c = new CubicBezier(["0", "1", "0.5", "-2"]);
   let string = c.coordinates.toString();
   do_check_eq(string, "0,1,.5,-2");
 
-  let c = new CubicBezier([1, 1, 1, 1]);
-  let string = c.coordinates.toString();
+  c = new CubicBezier([1, 1, 1, 1]);
+  string = c.coordinates.toString();
   do_check_eq(string, "1,1,1,1");
 }
 
 function pointGettersReturnPointCoordinatesArrays() {
   do_print("Points getters return arrays of coordinates");
 
   let c = new CubicBezier([0, .2, .5, 1]);
   do_check_eq(c.P1[0], 0);
--- a/browser/devtools/shared/theme-switching.js
+++ b/browser/devtools/shared/theme-switching.js
@@ -20,17 +20,16 @@
   }
 
   function switchTheme(newTheme, oldTheme) {
     if (newTheme === oldTheme) {
       return;
     }
 
     let oldThemeDef = gDevTools.getThemeDefinition(oldTheme);
-    let newThemeDef = gDevTools.getThemeDefinition(newTheme);
 
     // Unload all theme stylesheets related to the old theme.
     if (oldThemeDef) {
       for (let url of oldThemeDef.stylesheets) {
         StylesheetUtils.removeSheet(window, url, "author");
       }
     }
 
--- a/browser/devtools/shared/widgets/TableWidget.js
+++ b/browser/devtools/shared/widgets/TableWidget.js
@@ -201,17 +201,17 @@ TableWidget.prototype = {
   /**
    * Event handler for the `command` event on the column headers context menu
    */
   onPopupCommand: function(event) {
     let item = event.originalTarget;
     let checked = !!item.getAttribute("checked");
     let id = item.getAttribute("data-id");
     this.emit(EVENTS.HEADER_CONTEXT_MENU, id, checked);
-    let checked = this.menupopup.querySelectorAll("menuitem[checked]");
+    checked = this.menupopup.querySelectorAll("menuitem[checked]");
     let disabled = this.menupopup.querySelectorAll("menuitem[disabled]");
     if (checked.length == 2) {
       checked[checked.length - 1].setAttribute("disabled", "true");
     } else if (disabled.length > 1) {
       disabled[disabled.length - 1].removeAttribute("disabled");
     }
   },
 
--- a/browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.js
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.js
@@ -188,17 +188,17 @@ function spawnTest() {
             }
           }
         }
       },
       exec: { output: "" }
     },
   ]);
 
-  let toolbox = gDevTools.getToolbox(options.target);
+  toolbox = gDevTools.getToolbox(options.target);
   ok(toolbox != null, "toolbox is open");
 
   let styleEditor = toolbox.getCurrentPanel();
   ok(typeof styleEditor.selectStyleSheet === "function", "styleeditor is open");
 
   yield toolbox.destroy();
 
   yield helpers.closeToolbar(options);
--- a/browser/devtools/styleeditor/test/browser_styleeditor_new.js
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_new.js
@@ -68,17 +68,17 @@ function testInitialState(aEditor) {
 
   let summary = aEditor.summary;
 
   ok(aEditor.sourceLoaded, "new editor is loaded when attached");
   ok(aEditor.isNew, "new editor has isNew flag");
 
   ok(aEditor.sourceEditor.hasFocus(), "new editor has focus");
 
-  let summary = aEditor.summary;
+  summary = aEditor.summary;
   let ruleCount = summary.querySelector(".stylesheet-rule-count").textContent;
   is(parseInt(ruleCount), 0,
      "new editor initially shows 0 rules");
 
   let computedStyle = content.getComputedStyle(content.document.body, null);
   is(computedStyle.backgroundColor, "rgb(255, 255, 255)",
      "content's background color is initially white");
 }
--- a/browser/devtools/styleinspector/test/browser_computedview_keybindings_02.js
+++ b/browser/devtools/styleinspector/test/browser_computedview_keybindings_02.js
@@ -45,17 +45,17 @@ let test = asyncTest(function*() {
   yield onExpanded;
 
   info("Verify the 2nd style has been expanded");
   let secondStyleSelectors = view.styleDocument.querySelectorAll(
     ".property-content .matchedselectors")[1];
   ok(secondStyleSelectors.childNodes.length > 0, "Matched selectors expanded");
 
   info("Tab back up and test the same thing, with space");
-  let onExpanded = inspector.once("computed-view-property-expanded");
+  onExpanded = inspector.once("computed-view-property-expanded");
   EventUtils.synthesizeKey("VK_TAB", {shiftKey: true});
   EventUtils.synthesizeKey("VK_SPACE", {});
   yield onExpanded;
 
   info("Verify the 1st style has been expanded too");
   let firstStyleSelectors = view.styleDocument.querySelectorAll(
     ".property-content .matchedselectors")[0];
   ok(firstStyleSelectors.childNodes.length > 0, "Matched selectors expanded");
--- a/browser/devtools/styleinspector/test/browser_ruleview_add-property-cancel_02.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_add-property-cancel_02.js
@@ -40,40 +40,40 @@ let test = asyncTest(function*() {
 
   info("Entering a value in the property name editor");
   let onModifications = elementRuleEditor.rule._applyingModifications;
   input.value = "color";
   yield onModifications;
 
   info("Pressing return to commit and focus the new value field");
   let onValueFocus = once(elementRuleEditor.element, "focus", true);
-  let onModifications = elementRuleEditor.rule._applyingModifications;
+  onModifications = elementRuleEditor.rule._applyingModifications;
   EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
   yield onValueFocus;
   yield onModifications;
 
   // Getting the new value editor after focus
   editor = inplaceEditor(view.doc.activeElement);
   let textProp = elementRuleEditor.rule.textProps[1];
 
   is(elementRuleEditor.rule.textProps.length,  2, "Created a new text property.");
   is(elementRuleEditor.propertyList.children.length, 2, "Created a property editor.");
   is(editor, inplaceEditor(textProp.editor.valueSpan), "Editing the value span now.");
 
   info("Entering a property value");
   editor.input.value = "red";
 
   info("Escaping out of the field");
-  let onModifications = elementRuleEditor.rule._applyingModifications;
+  onModifications = elementRuleEditor.rule._applyingModifications;
   EventUtils.synthesizeKey("VK_ESCAPE", {}, view.doc.defaultView);
   yield onModifications;
 
   info("Checking that the previous field is focused");
   let focusedElement = inplaceEditor(elementRuleEditor.rule.textProps[0].editor.valueSpan).input;
   is(focusedElement, focusedElement.ownerDocument.activeElement, "Correct element has focus");
 
-  let onModifications = elementRuleEditor.rule._applyingModifications;
+  onModifications = elementRuleEditor.rule._applyingModifications;
   EventUtils.synthesizeKey("VK_ESCAPE", {}, view.doc.defaultView);
   yield onModifications;
 
   is(elementRuleEditor.rule.textProps.length,  1, "Removed the new text property.");
   is(elementRuleEditor.propertyList.children.length, 1, "Removed the property editor.");
 });
--- a/browser/devtools/styleinspector/test/browser_ruleview_add-property_01.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_add-property_01.js
@@ -63,17 +63,17 @@ function* testCreateNew(view) {
 
   is(elementRuleEditor.rule.textProps.length,  1, "Created a new text property.");
   is(elementRuleEditor.propertyList.children.length, 1, "Created a property editor.");
   is(editor, inplaceEditor(textProp.editor.valueSpan), "Editing the value span now.");
 
   info("Entering a value and bluring the field to expect a rule change");
   editor.input.value = "#XYZ";
   let onBlur = once(editor.input, "blur");
-  let onModifications = elementRuleEditor.rule._applyingModifications;
+  onModifications = elementRuleEditor.rule._applyingModifications;
   editor.input.blur();
   yield onBlur;
   yield onModifications;
 
   is(textProp.value, "#XYZ", "Text prop should have been changed.");
   is(textProp.overridden, false, "Property should not be overridden");
   is(textProp.editor.isValid(), false, "#XYZ should not be a valid entry");
 }
--- a/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_01.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_01.js
@@ -49,12 +49,12 @@ function* testImageTooltipAfterColorChan
   let onHidden = picker.tooltip.once("hidden");
   EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView);
   yield onHidden;
 
   info("Verify again that the image preview tooltip works");
   // After a color change, the property is re-populated, we need to get the new
   // dom node
   url = getRuleViewProperty(ruleView, "body", "background").valueSpan.querySelector(".theme-link");
-  let anchor = yield isHoverTooltipTarget(ruleView.tooltips.previewTooltip, url);
+  anchor = yield isHoverTooltipTarget(ruleView.tooltips.previewTooltip, url);
   ok(anchor, "The image preview tooltip is shown on the url span");
   is(anchor, url, "The anchor returned by the showOnHover callback is correct");
 }
--- a/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_02.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_02.js
@@ -44,18 +44,18 @@ function* testColorChangeIsntRevertedWhe
   let spectrum = yield picker.spectrum;
   let onHidden = picker.tooltip.once("hidden");
   EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView);
   yield onHidden;
 
   info("Open the image preview tooltip");
   let value = getRuleViewProperty(ruleView, "body", "background").valueSpan;
   let url = value.querySelector(".theme-link");
-  let onShown = ruleView.tooltips.previewTooltip.once("shown");
+  onShown = ruleView.tooltips.previewTooltip.once("shown");
   let anchor = yield isHoverTooltipTarget(ruleView.tooltips.previewTooltip, url);
   ruleView.tooltips.previewTooltip.show(anchor);
   yield onShown;
 
   info("Image tooltip is shown, verify that the swatch is still correct");
-  let swatch = value.querySelector(".ruleview-colorswatch");
+  swatch = value.querySelector(".ruleview-colorswatch");
   is(swatch.style.backgroundColor, "rgb(0, 0, 0)", "The swatch's color is correct");
   is(swatch.nextSibling.textContent, "#000", "The color name is correct");
 }
--- a/browser/devtools/styleinspector/test/browser_ruleview_edit-property_01.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-property_01.js
@@ -60,17 +60,17 @@ function* testEditProperty(view, name, v
 
   // Getting the value editor after focus
   editor = inplaceEditor(view.doc.activeElement);
   input = editor.input;
   is(inplaceEditor(propEditor.valueSpan), editor, "Focus moved to the value.");
 
   info("Entering a new value, including ; to commit and blur the value");
   let onBlur = once(input, "blur");
-  let onModifications = idRuleEditor.rule._applyingModifications;
+  onModifications = idRuleEditor.rule._applyingModifications;
   for (let ch of value + ";") {
     EventUtils.sendChar(ch, view.doc.defaultView);
   }
   yield onBlur;
   yield onModifications;
 
   is(propEditor.isValid(), true, value + " is a valid entry");
 
--- a/browser/devtools/styleinspector/test/browser_ruleview_edit-property_02.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-property_02.js
@@ -71,27 +71,27 @@ function* testEditProperty(inspector, ru
   let newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "border-color"
   });
   is(newValue, "red", "border-color should have been set.");
 
   info("Entering property name \"color\" followed by a colon to focus the value");
-  let onFocus = once(idRuleEditor.element, "focus", true);
+  onFocus = once(idRuleEditor.element, "focus", true);
   for (let ch of "color:") {
     EventUtils.sendChar(ch, ruleView.doc.defaultView);
   }
   yield onFocus;
 
   info("Verifying that the focused field is the valueSpan");
   editor = inplaceEditor(ruleView.doc.activeElement);
 
   info("Entering a value following by a semi-colon to commit it");
-  let onBlur = once(editor.input, "blur");
+  onBlur = once(editor.input, "blur");
   for (let ch of "red;") {
     EventUtils.sendChar(ch, ruleView.doc.defaultView);
   }
   yield onBlur;
   yield idRuleEditor.rule._applyingModifications;
 
   let props = ruleView.element.querySelectorAll(".ruleview-property");
   for (let i = 0; i < props.length; i++) {
@@ -114,17 +114,17 @@ function* testDisableProperty(inspector,
     name: "border-color"
   });
   is(newValue, "", "Border-color should have been unset.");
 
   info("Enabling the property again");
   propEditor.enable.click();
   yield idRuleEditor.rule._applyingModifications;
 
-  let newValue = yield executeInContent("Test:GetRulePropertyValue", {
+  newValue = yield executeInContent("Test:GetRulePropertyValue", {
     styleSheetIndex: 0,
     ruleIndex: 0,
     name: "border-color"
   });
   is(newValue, "red", "Border-color should have been reset.");
 }
 
 function* testPropertyStillMarkedDirty(inspector, ruleView) {
--- a/browser/devtools/styleinspector/test/browser_ruleview_keybindings.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_keybindings.js
@@ -22,27 +22,27 @@ let test = asyncTest(function*() {
   brace.click();
   yield onFocus;
 
   info("Entering a property name");
   let editor = getCurrentInplaceEditor(view);
   editor.input.value = "color";
 
   info("Typing ENTER to focus the next field: property value");
-  let onFocus = once(brace.parentNode, "focus", true);
+  onFocus = once(brace.parentNode, "focus", true);
   EventUtils.sendKey("return");
   yield onFocus;
   ok(true, "The value field was focused");
 
   info("Entering a property value");
-  let editor = getCurrentInplaceEditor(view);
+  editor = getCurrentInplaceEditor(view);
   editor.input.value = "green";
 
   info("Typing ENTER again should focus a new property name");
-  let onFocus = once(brace.parentNode, "focus", true);
+  onFocus = once(brace.parentNode, "focus", true);
   EventUtils.sendKey("return");
   yield onFocus;
   ok(true, "The new property name field was focused");
   getCurrentInplaceEditor(view).input.blur();
 });
 
 function getCurrentInplaceEditor(view) {
   return inplaceEditor(view.doc.activeElement);
--- a/browser/devtools/styleinspector/test/browser_ruleview_pseudo-element.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_pseudo-element.js
@@ -105,17 +105,17 @@ function* testTopLeft(inspector, view) {
   secondProp.setEnabled(true);
   yield elementAfterRule._applyingModifications;
 
   is(defaultView.getComputedStyle(element, ":after").getPropertyValue("padding-top"), "100px",
     "Enabled property should have been used.");
   is(defaultView.getComputedStyle(element).getPropertyValue("padding-top"), "32px",
     "Added property should not apply to element");
 
-  let firstProp = elementRuleView.addProperty("background-color", "rgb(0, 0, 255)", "");
+  firstProp = elementRuleView.addProperty("background-color", "rgb(0, 0, 255)", "");
   yield elementRule._applyingModifications;
 
   is(defaultView.getComputedStyle(element).getPropertyValue("background-color"), "rgb(0, 0, 255)",
     "Added property should have been used.");
   is(defaultView.getComputedStyle(element, ":after").getPropertyValue("background-color"), "rgb(0, 255, 0)",
     "Added prop does not apply to pseudo");
 }
 
--- a/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-attribute-change_01.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-attribute-change_01.js
@@ -33,17 +33,17 @@ let test = asyncTest(function*() {
   let ruleViewRefreshed = inspector.once("rule-view-refreshed");
   testElement.setAttribute("id", "differentid");
   yield ruleViewRefreshed;
 
   info("Checking that the rule-view doesn't have the #testid selector anymore");
   checkRuleViewContent(view, ["element", ".testclass"]);
 
   info("Reverting the ID attribute change");
-  let ruleViewRefreshed = inspector.once("rule-view-refreshed");
+  ruleViewRefreshed = inspector.once("rule-view-refreshed");
   testElement.setAttribute("id", "testid");
   yield ruleViewRefreshed;
 
   info("Checking that the rule-view has all the selectors again");
   checkRuleViewContent(view, ["element", "#testid", ".testclass"]);
 });
 
 function checkRuleViewContent(view, expectedSelectors) {
--- a/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-style-change.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-style-change.js
@@ -29,13 +29,13 @@ let test = asyncTest(function*() {
   let onUpdated = inspector.once("rule-view-refreshed");
   div.style.cssText = "font-size: 3em; color: lightgoldenrodyellow; text-align: right; text-transform: uppercase";
   yield onUpdated;
 
   let textAlign = getRuleViewPropertyValue(view, "element", "text-align");
   is(textAlign, "right", "The rule view shows the new text align.");
   let color = getRuleViewPropertyValue(view, "element", "color");
   is(color, "lightgoldenrodyellow", "The rule view shows the new color.")
-  let fontSize = getRuleViewPropertyValue(view, "element", "font-size");
+  fontSize = getRuleViewPropertyValue(view, "element", "font-size");
   is(fontSize, "3em", "The rule view shows the new font size.");
   let textTransform = getRuleViewPropertyValue(view, "element", "text-transform");
   is(textTransform, "uppercase", "The rule view shows the new text transform.");
 });
--- a/browser/devtools/styleinspector/test/browser_ruleview_selector-highlighter_02.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_selector-highlighter_02.js
@@ -58,25 +58,25 @@ let test = asyncTest(function*() {
   info("Checking that the HighlighterFront's show/hide methods are called");
   rView.highlighters._onMouseMove({target: selectorSpan});
   ok(HighlighterFront.isShown, "The highlighter is shown");
   rView.highlighters._onMouseLeave();
   ok(!HighlighterFront.isShown, "The highlighter is hidden");
 
   info("Checking that the right NodeFront reference and options are passed");
   yield selectNode("p", inspector);
-  let selectorSpan = getRuleViewSelector(rView, "p").firstElementChild;
+  selectorSpan = getRuleViewSelector(rView, "p").firstElementChild;
   rView.highlighters._onMouseMove({target: selectorSpan});
   is(HighlighterFront.nodeFront.tagName, "P",
     "The right NodeFront is passed to the highlighter (1)");
   is(HighlighterFront.options.selector, "p",
     "The right selector option is passed to the highlighter (1)");
 
   yield selectNode("body", inspector);
-  let selectorSpan = getRuleViewSelector(rView, "body").firstElementChild;
+  selectorSpan = getRuleViewSelector(rView, "body").firstElementChild;
   rView.highlighters._onMouseMove({target: selectorSpan});
   is(HighlighterFront.nodeFront.tagName, "BODY",
     "The right NodeFront is passed to the highlighter (2)");
   is(HighlighterFront.options.selector, "body",
     "The right selector option is passed to the highlighter (2)");
 
   info("Checking that the highlighter gets hidden when hovering somewhere else");
   let {valueSpan} = getRuleViewProperty(rView, "body", "background");
--- a/browser/devtools/styleinspector/test/browser_ruleview_urls-clickable.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_urls-clickable.js
@@ -26,17 +26,17 @@ function* selectNodes(inspector, ruleVie
   let inlineresolved = ".inline-resolved";
 
   yield selectNode(relative1, inspector);
   let relativeLink = ruleView.doc.querySelector(".ruleview-propertycontainer a");
   ok(relativeLink, "Link exists for relative1 node");
   is(relativeLink.getAttribute("href"), TEST_IMAGE, "href matches");
 
   yield selectNode(relative2, inspector);
-  let relativeLink = ruleView.doc.querySelector(".ruleview-propertycontainer a");
+  relativeLink = ruleView.doc.querySelector(".ruleview-propertycontainer a");
   ok(relativeLink, "Link exists for relative2 node");
   is(relativeLink.getAttribute("href"), TEST_IMAGE, "href matches");
 
   yield selectNode(absolute, inspector);
   let absoluteLink = ruleView.doc.querySelector(".ruleview-propertycontainer a");
   ok(absoluteLink, "Link exists for absolute node");
   is(absoluteLink.getAttribute("href"), TEST_IMAGE, "href matches");
 
--- a/browser/devtools/styleinspector/test/browser_ruleview_user-agent-styles.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_user-agent-styles.js
@@ -61,26 +61,26 @@ function* userAgentStylesVisible(inspect
   let userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable);
   let uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable);
   is (userRules.length, 1, "Correct number of user rules");
   ok (uaRules.length > 0, "Has UA rules");
 
   yield selectNode("pre", inspector);
   yield compareAppliedStylesWithUI(inspector, view, "ua");
 
-  let userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable);
-  let uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable);
+  userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable);
+  uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable);
   is (userRules.length, 1, "Correct number of user rules");
   ok (uaRules.length > 0, "Has UA rules");
 
   yield selectNode("a", inspector);
   yield compareAppliedStylesWithUI(inspector, view, "ua");
 
-  let userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable);
-  let uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable);
+  userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable);
+  uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable);
   is (userRules.length, 1, "Correct number of user rules");
 
   ok (userRules.some(rule=> rule.matchedSelectors.length === 0),
     "There is an inline style for element in user styles");
 
   ok (uaRules.some(rule=> rule.matchedSelectors.indexOf(":-moz-any-link")),
     "There is a rule for :-moz-any-link");
   ok (uaRules.some(rule=> rule.matchedSelectors.indexOf("*|*:link")),
@@ -98,26 +98,26 @@ function* userAgentStylesNotVisible(insp
   let userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable);
   let uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable);
   is (userRules.length, 1, "Correct number of user rules");
   is (uaRules.length, 0, "No UA rules");
 
   yield selectNode("pre", inspector);
   yield compareAppliedStylesWithUI(inspector, view);
 
-  let userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable);
-  let uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable);
+  userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable);
+  uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable);
   is (userRules.length, 1, "Correct number of user rules");
   is (uaRules.length, 0, "No UA rules");
 
   yield selectNode("a", inspector);
   yield compareAppliedStylesWithUI(inspector, view);
 
-  let userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable);
-  let uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable);
+  userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable);
+  uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable);
   is (userRules.length, 1, "Correct number of user rules");
   is (uaRules.length, 0, "No UA rules");
 }
 
 function* compareAppliedStylesWithUI(inspector, view, filter) {
   info ("Making sure that UI is consistent with pageStyle.getApplied");
 
   let entries = yield inspector.pageStyle.getApplied(inspector.selection.nodeFront, {
--- a/browser/devtools/styleinspector/test/browser_styleinspector_csslogic-content-stylesheets.js
+++ b/browser/devtools/styleinspector/test/browser_styleinspector_csslogic-content-stylesheets.js
@@ -29,18 +29,18 @@ let test = asyncTest(function*() {
   info("Checking stylesheets");
   yield checkSheets(target);
 
   info("Checking stylesheets on XUL document");
   info("Allowing XUL content");
   allowXUL();
   yield addTab(TEST_URI_XUL);
 
-  let {toolbox, inspector, view} = yield openRuleView();
-  let target = getNode("#target");
+  ({toolbox, inspector, view} = yield openRuleView());
+  target = getNode("#target");
   yield selectNode("#target", inspector);
 
   yield checkSheets(target);
   info("Disallowing XUL content");
   disallowXUL();
 });
 
 function allowXUL() {
--- a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-background-image.js
+++ b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-background-image.js
@@ -37,17 +37,17 @@ let test = asyncTest(function*() {
   yield selectNode(".test-element", inspector);
   info("Testing the the background property on the .test-element rule");
   yield testDivRuleView(view);
 
   info("Testing that image preview tooltips show even when there are fields being edited");
   yield testTooltipAppearsEvenInEditMode(view);
 
   info("Switching over to the computed-view");
-  let {view} = yield openComputedView();
+  ({view} = yield openComputedView());
 
   info("Testing that the background-image computed style has a tooltip too");
   yield testComputedView(view);
 });
 
 function* testBodyRuleView(view) {
   info("Testing tooltips in the rule view");
   let panel = view.tooltips.previewTooltip.panel;
--- a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-closes-on-new-selection.js
+++ b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-closes-on-new-selection.js
@@ -11,17 +11,17 @@ let test = asyncTest(function*() {
 
   let {toolbox, inspector, view} = yield openRuleView();
   yield selectNode(".one", inspector);
 
   info("Testing rule view tooltip closes on new selection");
   yield testRuleView(view, inspector);
 
   info("Testing computed view tooltip closes on new selection");
-  let {view} = yield openComputedView();
+  ({view} = yield openComputedView());
   yield testComputedView(view, inspector);
 });
 
 function* testRuleView(ruleView, inspector) {
   info("Showing the tooltip");
   let tooltip = ruleView.tooltips.previewTooltip;
   let onShown = tooltip.once("shown");
   tooltip.show();
--- a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-longhand-fontfamily.js
+++ b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-longhand-fontfamily.js
@@ -27,17 +27,17 @@ let test = asyncTest(function*() {
   let {toolbox, inspector, view} = yield openRuleView();
 
   info("Selecting the test node");
   yield selectNode("#testElement", inspector);
 
   yield testRuleView(view, inspector.selection.nodeFront);
 
   info("Opening the computed view");
-  let {toolbox, inspector, view} = yield openComputedView();
+  ({toolbox, inspector, view} = yield openComputedView());
 
   yield testComputedView(view, inspector.selection.nodeFront);
 
   yield testExpandedComputedViewProperty(view, inspector.selection.nodeFront);
 });
 
 function* testRuleView(ruleView, nodeFront) {
   info("Testing font-family tooltips in the rule view");
--- a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-01.js
+++ b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-01.js
@@ -26,17 +26,17 @@ let test = asyncTest(function*() {
   ok(!overlay.highlighters[TYPE], "No highlighter exists in the rule-view");
   let h = yield overlay._getHighlighter(TYPE);
   ok(overlay.highlighters[TYPE], "The highlighter has been created in the rule-view");
   is(h, overlay.highlighters[TYPE], "The right highlighter has been created");
   let h2 = yield overlay._getHighlighter(TYPE);
   is(h, h2, "The same instance of highlighter is returned everytime in the rule-view");
 
   let {view: cView} = yield openComputedView();
-  let overlay = cView.highlighters;
+  overlay = cView.highlighters;
 
   ok(!overlay.highlighters[TYPE], "No highlighter exists in the computed-view");
-  let h = yield overlay._getHighlighter(TYPE);
+  h = yield overlay._getHighlighter(TYPE);
   ok(overlay.highlighters[TYPE], "The highlighter has been created in the computed-view");
   is(h, overlay.highlighters[TYPE], "The right highlighter has been created");
-  let h2 = yield overlay._getHighlighter(TYPE);
+  h2 = yield overlay._getHighlighter(TYPE);
   is(h, h2, "The same instance of highlighter is returned everytime in the computed-view");
 });
--- a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-02.js
+++ b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-02.js
@@ -31,33 +31,33 @@ let test = asyncTest(function*() {
 
   info("Faking a mousemove on a non-transform property");
   let {valueSpan} = getRuleViewProperty(rView, "body", "color");
   hs._onMouseMove({target: valueSpan});
   ok(!hs.highlighters[TYPE], "No highlighter exists in the rule-view (2)");
   ok(!hs.promises[TYPE], "No highlighter is being created in the rule-view (2)");
 
   info("Faking a mousemove on a transform property");
-  let {valueSpan} = getRuleViewProperty(rView, "body", "transform");
+  ({valueSpan} = getRuleViewProperty(rView, "body", "transform"));
   hs._onMouseMove({target: valueSpan});
   ok(hs.promises[TYPE], "The highlighter is being initialized");
   let h = yield hs.promises[TYPE];
   is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
 
   let {view: cView} = yield openComputedView();
-  let hs = cView.highlighters;
+  hs = cView.highlighters;
 
   ok(!hs.highlighters[TYPE], "No highlighter exists in the computed-view (1)");
   ok(!hs.promises[TYPE], "No highlighter is being created in the computed-view (1)");
 
   info("Faking a mousemove on a non-transform property");
-  let {valueSpan} = getComputedViewProperty(cView, "color");
+  ({valueSpan} = getComputedViewProperty(cView, "color"));
   hs._onMouseMove({target: valueSpan});
   ok(!hs.highlighters[TYPE], "No highlighter exists in the computed-view (2)");
   ok(!hs.promises[TYPE], "No highlighter is being created in the computed-view (2)");
 
   info("Faking a mousemove on a transform property");
-  let {valueSpan} = getComputedViewProperty(cView, "transform");
+  ({valueSpan} = getComputedViewProperty(cView, "transform"));
   hs._onMouseMove({target: valueSpan});
   ok(hs.promises[TYPE], "The highlighter is being initialized");
-  let h = yield hs.promises[TYPE];
+  h = yield hs.promises[TYPE];
   is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
 });
--- a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-03.js
+++ b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-03.js
@@ -68,24 +68,24 @@ let test = asyncTest(function*() {
   is(HighlighterFront.nbOfTimesShown, nb + 1, "The highlighter was shown once");
   rView.highlighters._onMouseMove({target: valueSpan});
   rView.highlighters._onMouseMove({target: valueSpan});
   is(HighlighterFront.nbOfTimesShown, nb + 1,
     "The highlighter was shown once, after several mousemove");
 
   info("Checking that the right NodeFront reference is passed");
   yield selectNode("html", inspector);
-  let {valueSpan} = getRuleViewProperty(rView, "html", "transform");
+  ({valueSpan} = getRuleViewProperty(rView, "html", "transform"));
   rView.highlighters._onMouseMove({target: valueSpan});
   is(HighlighterFront.nodeFront.tagName, "HTML",
     "The right NodeFront is passed to the highlighter (1)");
 
   yield selectNode("body", inspector);
-  let {valueSpan} = getRuleViewProperty(rView, "body", "transform");
+  ({valueSpan} = getRuleViewProperty(rView, "body", "transform"));
   rView.highlighters._onMouseMove({target: valueSpan});
   is(HighlighterFront.nodeFront.tagName, "BODY",
     "The right NodeFront is passed to the highlighter (2)");
 
   info("Checking that the highlighter gets hidden when hovering a non-transform property");
-  let {valueSpan} = getRuleViewProperty(rView, "body", "color");
+  ({valueSpan} = getRuleViewProperty(rView, "body", "color"));
   rView.highlighters._onMouseMove({target: valueSpan});
   ok(!HighlighterFront.isShown, "The highlighter is hidden");
 });
--- a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-04.js
+++ b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-04.js
@@ -43,20 +43,20 @@ let test = asyncTest(function*() {
 
   info("Disabling the applied property");
   let classRuleEditor = getRuleViewRuleEditor(rView, 1);
   let propEditor = classRuleEditor.rule.textProps[0].editor;
   propEditor.enable.click();
   yield classRuleEditor.rule._applyingModifications;
 
   info("Faking a mousemove on the disabled property");
-  let {valueSpan} = getRuleViewProperty(rView, ".test", "transform");
+  ({valueSpan} = getRuleViewProperty(rView, ".test", "transform"));
   hs._onMouseMove({target: valueSpan});
   ok(!hs.highlighters[TYPE], "No highlighter was created for the disabled property");
   ok(!hs.promises[TYPE], "And no highlighter is being initialized either");
 
   info("Faking a mousemove on the now unoverriden property");
-  let {valueSpan} = getRuleViewProperty(rView, "div", "transform");
+  ({valueSpan} = getRuleViewProperty(rView, "div", "transform"));
   hs._onMouseMove({target: valueSpan});
   ok(hs.promises[TYPE], "The highlighter is being initialized now");
   let h = yield hs.promises[TYPE];
   is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
 });
--- a/browser/devtools/webaudioeditor/test/browser_audionode-actor-get-set-param.js
+++ b/browser/devtools/webaudioeditor/test/browser_audionode-actor-get-set-param.js
@@ -14,27 +14,27 @@ function spawnTest () {
 
   let freq = yield oscNode.getParam("frequency");
   info(typeof freq);
   ise(freq, 440, "AudioNode:getParam correctly fetches AudioParam");
 
   let type = yield oscNode.getParam("type");
   ise(type, "sine", "AudioNode:getParam correctly fetches non-AudioParam");
 
-  let type = yield oscNode.getParam("not-a-valid-param");
+  type = yield oscNode.getParam("not-a-valid-param");
   ok(type.type === "undefined",
     "AudioNode:getParam correctly returns a grip value for `undefined` for an invalid param.");
 
   let resSuccess = yield oscNode.setParam("frequency", 220);
-  let freq = yield oscNode.getParam("frequency");
+  freq = yield oscNode.getParam("frequency");
   ise(freq, 220, "AudioNode:setParam correctly sets a `number` AudioParam");
   is(resSuccess, undefined, "AudioNode:setParam returns undefined for correctly set AudioParam");
 
   resSuccess = yield oscNode.setParam("type", "square");
-  let type = yield oscNode.getParam("type");
+  type = yield oscNode.getParam("type");
   ise(type, "square", "AudioNode:setParam correctly sets a `string` non-AudioParam");
   is(resSuccess, undefined, "AudioNode:setParam returns undefined for correctly set AudioParam");
 
   try {
     yield oscNode.setParam("frequency", "hello");
     ok(false, "setParam with invalid types should throw");
   } catch (e) {
     ok(/is not a finite floating-point/.test(e.message), "AudioNode:setParam returns error with correct message when attempting an invalid assignment");
--- a/browser/devtools/webaudioeditor/test/browser_wa_reset-01.js
+++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-01.js
@@ -35,18 +35,18 @@ function spawnTest() {
 
   is($("#reload-notice").hidden, true,
     "The 'reload this page' notice should be hidden after context found.");
   is($("#waiting-notice").hidden, true,
     "The 'waiting for an audio context' notice should be hidden after context found.");
   is($("#content").hidden, false,
     "The tool's content should not be hidden anymore.");
 
-  let navigating = once(target, "will-navigate");
-  let started = once(gFront, "start-context");
+  navigating = once(target, "will-navigate");
+  started = once(gFront, "start-context");
 
   reload(target);
 
   yield Promise.all([navigating, started]);
 
   is($("#reload-notice").hidden, true,
     "The 'reload this page' notice should be hidden after context found after reload.");
   is($("#waiting-notice").hidden, true,
--- a/browser/devtools/webaudioeditor/test/browser_wa_reset-02.js
+++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-02.js
@@ -19,20 +19,20 @@ function spawnTest() {
   ]);
 
   let { nodes, edges } = countGraphObjects(panelWin);
   ise(nodes, 3, "should only be 3 nodes.");
   ise(edges, 2, "should only be 2 edges.");
 
   reload(target);
 
-  let [actors] = yield Promise.all([
+  [actors] = yield Promise.all([
     get3(gFront, "create-node"),
     waitForGraphRendered(panelWin, 3, 2)
   ]);
 
-  let { nodes, edges } = countGraphObjects(panelWin);
+  ({ nodes, edges } = countGraphObjects(panelWin));
   ise(nodes, 3, "after reload, should only be 3 nodes.");
   ise(edges, 2, "after reload, should only be 2 edges.");
 
   yield teardown(panel);
   finish();
 }
--- a/browser/devtools/webaudioeditor/test/browser_wa_reset-03.js
+++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-03.js
@@ -24,21 +24,21 @@ function spawnTest() {
   is(WebAudioInspectorView.getCurrentAudioNode().id, nodeIds[1], "InspectorView has correct node set.");
 
   /**
    * Reload
    */
 
   reload(target);
 
-  let [actors] = yield Promise.all([
+  [actors] = yield Promise.all([
     get3(gFront, "create-node"),
     waitForGraphRendered(panelWin, 3, 2)
   ]);
-  let nodeIds = actors.map(actor => actor.actorID);
+  nodeIds = actors.map(actor => actor.actorID);
 
   ok(!WebAudioInspectorView.isVisible(), "InspectorView hidden on start.");
   ise(WebAudioInspectorView.getCurrentAudioNode(), null,
     "InspectorView has no current node set on reset.");
 
   yield clickGraphNode(panelWin, nodeIds[2], true);
   ok(WebAudioInspectorView.isVisible(),
     "InspectorView visible after selecting a node after a reset.");
--- a/browser/devtools/webaudioeditor/test/browser_wa_reset-04.js
+++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-04.js
@@ -32,17 +32,17 @@ function spawnTest() {
 
   is($("#reload-notice").hidden, false,
     "The 'reload this page' notice should still be visible when switching to a frame.");
   is($("#waiting-notice").hidden, true,
     "The 'waiting for an audio context' notice should be kept hidden when switching to a frame.");
   is($("#content").hidden, true,
     "The tool's content should still be hidden.");
 
-  let navigating = once(target, "will-navigate");
+  navigating = once(target, "will-navigate");
   let started = once(gFront, "start-context");
 
   reload(target);
 
   yield Promise.all([navigating, started]);
 
   is($("#reload-notice").hidden, true,
     "The 'reload this page' notice should be hidden after reloading the frame.");
--- a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-connect-param.js
+++ b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-connect-param.js
@@ -2,17 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Test the `connect-param` event on the web audio actor.
  */
 
 function spawnTest () {
   let [target, debuggee, front] = yield initBackend(CONNECT_PARAM_URL);
-  let [_, _, [destNode, carrierNode, modNode, gainNode], _, connectParam] = yield Promise.all([
+  let [, , [destNode, carrierNode, modNode, gainNode], , connectParam] = yield Promise.all([
     front.setup({ reload: true }),
     once(front, "start-context"),
     getN(front, "create-node", 4),
     get2(front, "connect-node"),
     once(front, "connect-param")
   ]);
 
   info(connectParam);
--- a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-destroy-node.js
+++ b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-destroy-node.js
@@ -4,17 +4,17 @@
 /**
  * Test `destroy-node` event on WebAudioActor.
  */
 
 function spawnTest () {
   let [target, debuggee, front] = yield initBackend(DESTROY_NODES_URL);
 
   let waitUntilDestroyed = getN(front, "destroy-node", 10);
-  let [_, _, created] = yield Promise.all([
+  let [, , created] = yield Promise.all([
     front.setup({ reload: true }),
     once(front, "start-context"),
     // Should create 1 destination node and 10 disposable buffer nodes
     getN(front, "create-node", 13)
   ]);
 
   // Force CC so we can ensure it's run to clear out dead AudioNodes
   forceCC();
--- a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-simple.js
+++ b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-simple.js
@@ -21,15 +21,15 @@ function spawnTest () {
   is(destType, "AudioDestinationNode", "WebAudioActor:create-node returns AudioNodeActor for AudioDestination");
   is(oscType, "OscillatorNode", "WebAudioActor:create-node returns AudioNodeActor");
   is(gainType, "GainNode", "WebAudioActor:create-node returns AudioNodeActor");
 
   let { source, dest } = connect1;
   is(source.actorID, oscNode.actorID, "WebAudioActor:connect-node returns correct actor with ID on source (osc->gain)");
   is(dest.actorID, gainNode.actorID, "WebAudioActor:connect-node returns correct actor with ID on dest (osc->gain)");
 
-  let { source, dest } = connect2;
+  ({ source, dest } = connect2);
   is(source.actorID, gainNode.actorID, "WebAudioActor:connect-node returns correct actor with ID on source (gain->dest)");
   is(dest.actorID, destNode.actorID, "WebAudioActor:connect-node returns correct actor with ID on dest (gain->dest)");
 
   yield removeTab(target.tab);
   finish();
 }
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js
@@ -75,17 +75,17 @@ function test() {
     let selectAllItem = contextMenu.querySelector("*[command='cmd_selectAll']");
     ok(selectAllItem != null,
        "the context menu on the output node has a \"Select All\" item");
 
     outputNode.focus();
 
     selectAllItem.doCommand();
 
-    let selectedCount = hud.ui.output.getSelectedMessages().length;
+    selectedCount = hud.ui.output.getSelectedMessages().length;
     is(selectedCount, outputNode.childNodes.length,
        "all console messages are selected after performing a select-all " +
        "operation from the context menu");
 
     hud.iframeWindow.getSelection().removeAllRanges();
 
     finishTest();
   }
--- a/browser/devtools/webconsole/test/browser_webconsole_network_panel.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_network_panel.js
@@ -355,17 +355,17 @@ function testGen() {
     requestCookie: true,
     responseContainer: true,
     responseBody: false,
     responseNoBody: false,
     responseImage: false,
     responseImageCached: true
   });
 
-  let imgNode = networkPanel.document.getElementById("responseImageCachedNode");
+  imgNode = networkPanel.document.getElementById("responseImageCachedNode");
   is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64,
      "Displayed image is correct");
 
   networkPanel.panel.hidePopup();
 
   // Test sent form data.
   info("test 9: sent form data");
   httpActivity.request.postData.text = [
--- a/browser/devtools/webconsole/test/browser_webconsole_split.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_split.js
@@ -112,17 +112,17 @@ function test()
       is (currentUIState.deckHeight, 0, "Deck has a height == 0 when console is opened.");
       is (currentUIState.webconsoleHeight, currentUIState.containerHeight, "Web console is full height.");
       ok (currentUIState.openedConsolePanel, "The console panel is the current tool");
       ok (currentUIState.buttonSelected, "The command button is still selected.");
 
       // Make sure splitting console does nothing while webconsole is opened
       toolbox.toggleSplitConsole();
 
-      let currentUIState = getCurrentUIState();
+      currentUIState = getCurrentUIState();
 
       ok (!currentUIState.splitterVisibility, "Splitter is hidden when console is opened.");
       is (currentUIState.deckHeight, 0, "Deck has a height == 0 when console is opened.");
       is (currentUIState.webconsoleHeight, currentUIState.containerHeight, "Web console is full height.");
       ok (currentUIState.openedConsolePanel, "The console panel is the current tool");
       ok (currentUIState.buttonSelected, "The command button is still selected.");
 
       // Make sure that split state is saved after opening another panel
@@ -171,30 +171,30 @@ function test()
     ok (!currentUIState.splitterVisibility, "Splitter is hidden by default");
     is (currentUIState.deckHeight, currentUIState.containerHeight, "Deck has a height > 0 by default");
     is (currentUIState.webconsoleHeight, 0, "Web console is collapsed by default");
     ok (!currentUIState.openedConsolePanel, "The console panel is not the current tool");
     ok (!currentUIState.buttonSelected, "The command button is not selected.");
 
     toolbox.toggleSplitConsole();
 
-    let currentUIState = getCurrentUIState();
+    currentUIState = getCurrentUIState();
 
     ok (currentUIState.splitterVisibility, "Splitter is visible when console is split");
     ok (currentUIState.deckHeight > 0, "Deck has a height > 0 when console is split");
     ok (currentUIState.webconsoleHeight > 0, "Web console has a height > 0 when console is split");
     is (Math.round(currentUIState.deckHeight + currentUIState.webconsoleHeight),
           currentUIState.containerHeight,
         "Everything adds up to container height");
     ok (!currentUIState.openedConsolePanel, "The console panel is not the current tool");
     ok (currentUIState.buttonSelected, "The command button is selected.");
 
     toolbox.toggleSplitConsole();
 
-    let currentUIState = getCurrentUIState();
+    currentUIState = getCurrentUIState();
 
     ok (!currentUIState.splitterVisibility, "Splitter is hidden after toggling");
     is (currentUIState.deckHeight, currentUIState.containerHeight, "Deck has a height > 0 after toggling");
     is (currentUIState.webconsoleHeight, 0, "Web console is collapsed after toggling");
     ok (!currentUIState.openedConsolePanel, "The console panel is not the current tool");
     ok (!currentUIState.buttonSelected, "The command button is not selected.");
   }
 
--- a/browser/devtools/webconsole/test/browser_webconsole_split_focus.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_split_focus.js
@@ -28,26 +28,26 @@ function test() {
     activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
     is (activeElement, inspector.searchBox, "Search box is focused");
 
     yield toolbox.openSplitConsole();
 
     ok(toolbox.splitConsole, "Split console is now visible");
 
     // Use the binding element since jsterm.inputNode is a XUL textarea element.
-    let activeElement = getActiveElement(toolbox.doc);
+    activeElement = getActiveElement(toolbox.doc);
     activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
     let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
     is(activeElement, inputNode, "Split console input is focused by default");
 
     yield toolbox.closeSplitConsole();
 
     info ("Making sure that the search box is refocused after closing the split console");
     // Use the binding element since inspector.searchBox is a XUL element.
-    let activeElement = getActiveElement(inspector.panelDoc);
+    activeElement = getActiveElement(inspector.panelDoc);
     activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
     is (activeElement, inspector.searchBox, "Search box is focused");
 
     yield toolbox.destroy();
   }
 
   function getActiveElement(doc) {
     let activeElement = doc.activeElement;
--- a/browser/devtools/webconsole/test/browser_webconsole_split_persist.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_split_persist.js
@@ -25,18 +25,18 @@ function test() {
     ok(getVisiblePrefValue(), "Visibility pref is true");
 
     is(getHeightPrefValue(), toolbox.webconsolePanel.height, "Panel height matches the pref");
     toolbox.webconsolePanel.height = 200;
 
     yield toolbox.destroy();
 
     info("Opening a tab while there is a true user setting on split console pref");
-    let {tab} = yield loadTab(TEST_URI);
-    let target = TargetFactory.forTab(tab);
+    ({tab} = yield loadTab(TEST_URI));
+    target = TargetFactory.forTab(tab);
     toolbox = yield gDevTools.showToolbox(target, "inspector");
 
     ok(toolbox.splitConsole, "Split console is visible by default.");
     ok(isCommandButtonChecked(), "Split console button is checked by default.");
     is(getHeightPrefValue(), 200, "Height is set based on panel height after closing");
 
     // Use the binding element since jsterm.inputNode is a XUL textarea element.
     let activeElement = getActiveElement(toolbox.doc);
@@ -58,18 +58,18 @@ function test() {
     ok(!getVisiblePrefValue(), "Visibility pref is false");
 
     yield toolbox.destroy();
 
     is(getHeightPrefValue(), 10000, "Height is set based on panel height after closing");
 
 
     info("Opening a tab while there is a false user setting on split console pref");
-    let {tab} = yield loadTab(TEST_URI);
-    let target = TargetFactory.forTab(tab);
+    ({tab} = yield loadTab(TEST_URI));
+    target = TargetFactory.forTab(tab);
     toolbox = yield gDevTools.showToolbox(target, "inspector");
 
     ok(!toolbox.splitConsole, "Split console is hidden by default.");
     ok(!getVisiblePrefValue(), "Visibility pref is false");
 
     yield toolbox.destroy();
   }
 
--- a/browser/devtools/webconsole/test/head.js
+++ b/browser/devtools/webconsole/test/head.js
@@ -343,29 +343,29 @@ function finishTest()
   if (browserConsole) {
     if (browserConsole.jsterm) {
       browserConsole.jsterm.clearOutput(true);
     }
     HUDService.toggleBrowserConsole().then(finishTest);
     return;
   }
 
-  let hud = HUDService.getHudByWindow(content);
-  if (!hud) {
+  let contentHud = HUDService.getHudByWindow(content);
+  if (!contentHud) {
     finish();
     return;
   }
 
-  if (hud.jsterm) {
-    hud.jsterm.clearOutput(true);
+  if (contentHud.jsterm) {
+    contentHud.jsterm.clearOutput(true);
   }
 
-  closeConsole(hud.target.tab, finish);
+  closeConsole(contentHud.target.tab, finish);
 
-  hud = null;
+  contentHud = null;
 }
 
 function tearDown()
 {
   dumpConsoles();
 
   if (HUDService.getBrowserConsole()) {
     HUDService.toggleBrowserConsole();
--- a/browser/devtools/webide/test/test_newapp.html
+++ b/browser/devtools/webide/test/test_newapp.html
@@ -23,17 +23,17 @@
             let tmpDir = FileUtils.getDir("TmpD", []);
             yield win.Cmds.newApp({
               index: 0,
               name: "webideTmpApp",
               folder: tmpDir
             });
 
             let project = win.AppManager.selectedProject;
-            let tmpDir = FileUtils.getDir("TmpD", ["webidetmpapp"]);
+            tmpDir = FileUtils.getDir("TmpD", ["webidetmpapp"]);
             ok(tmpDir.isDirectory(), "Directory created");
             is(project.location, tmpDir.path, "Location is valid (and lowercase)");
             is(project.name, "webideTmpApp", "name field has been updated");
 
             // Clean up
             tmpDir.remove(true);
             yield closeWebIDE(win);
             yield removeAllProjects();
--- a/browser/experiments/test/xpcshell/test_activate.js
+++ b/browser/experiments/test/xpcshell/test_activate.js
@@ -121,17 +121,17 @@ add_task(function* test_startStop() {
   Assert.equal(changes, experiment.ADDON_CHANGE_INSTALL, "Add-on was installed.");
   addons = yield getExperimentAddons();
   Assert.equal(experiment.enabled, true, "Experiment should now be enabled.");
   Assert.equal(addons.length, 1, "1 experiment add-on is installed.");
   Assert.equal(addons[0].id, experiment._addonId, "The add-on is the one we expect.");
   Assert.equal(addons[0].userDisabled, false, "The add-on is not userDisabled.");
   Assert.ok(addons[0].isActive, "The add-on is active.");
 
-  let result = yield experiment.shouldStop();
+  result = yield experiment.shouldStop();
   Assert.equal(result.shouldStop, false, "shouldStop should be false.");
   Assert.equal(experiment.enabled, true, "Experiment should be enabled.");
   addons = yield getExperimentAddons();
   Assert.equal(addons.length, 1, "Experiment still in add-ons manager.");
   Assert.ok(addons[0].isActive, "The add-on is still active.");
 
   defineNow(gPolicy, futureDate(endDate, MS_IN_ONE_DAY));
   result = yield experiment.shouldStop();
@@ -151,13 +151,13 @@ add_task(function* test_startStop() {
   } catch (ex) {
     errored = true;
   }
   Assert.ok(experiment._failedStart, "Experiment failed to start.");
   Assert.ok(errored, "start() threw an exception.");
 
   // Make sure "ignore hashes" mode works.
   gPolicy.ignoreHashes = true;
-  let changes = yield experiment.start();
+  changes = yield experiment.start();
   Assert.equal(changes, experiment.ADDON_CHANGE_INSTALL);
   yield experiment.stop();
   gPolicy.ignoreHashes = false;
 });
--- a/browser/experiments/test/xpcshell/test_api.js
+++ b/browser/experiments/test/xpcshell/test_api.js
@@ -1627,30 +1627,30 @@ add_task(function* test_foreignUninstall
 
   addons = yield getExperimentAddons();
   Assert.equal(addons.length, 1, "A single experiment add-on is installed.");
   Assert.ok(addons[0].isActive, "That experiment is active.");
 
   yield AddonTestUtils.uninstallAddonByID(EXPERIMENT1_ID);
   yield experiments._mainTask;
 
-  let addons = yield getExperimentAddons();
+  addons = yield getExperimentAddons();
   Assert.equal(addons.length, 0, "Experiment add-on should have been removed.");
 
   experimentList = yield experiments.getExperiments();
   Assert.equal(experimentList.length, 1, "A single experiment is known.");
   Assert.equal(experimentList[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
   Assert.ok(!experimentList[0].active, "Experiment 1 should not be active anymore.");
 
   // Fake restart behaviour.
   yield promiseRestartManager();
   experiments = new Experiments.Experiments(gPolicy);
   yield experiments.updateManifest();
 
-  let addons = yield getExperimentAddons();
+  addons = yield getExperimentAddons();
   Assert.equal(addons.length, 0, "No experiment add-ons installed.");
 
   experimentList = yield experiments.getExperiments();
   Assert.equal(experimentList.length, 1, "A single experiment is known.");
   Assert.equal(experimentList[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
   Assert.ok(!experimentList[0].active, "Experiment 1 should not be active.");
 
   yield testCleanup(experiments);
--- a/browser/modules/test/browser_ContentSearch.js
+++ b/browser/modules/test/browser_ContentSearch.js
@@ -54,17 +54,17 @@ add_task(function* SetCurrentEngine() {
   yield deferred.promise;
   let msg = yield searchPromise;
   checkMsg(msg, {
     type: "CurrentEngine",
     data: yield currentEngineObj(newCurrentEngine),
   });
 
   Services.search.currentEngine = oldCurrentEngine;
-  let msg = yield waitForTestMsg("CurrentEngine");
+  msg = yield waitForTestMsg("CurrentEngine");
   checkMsg(msg, {
     type: "CurrentEngine",
     data: yield currentEngineObj(oldCurrentEngine),
   });
 });
 
 add_task(function* ManageEngines() {
   yield addTab();
--- a/browser/modules/test/browser_UITour2.js
+++ b/browser/modules/test/browser_UITour2.js
@@ -73,17 +73,17 @@ let tests = [
     isnot(tabInfo, null, "Should have recorded data about a pinned tab after addPinnedTab()");
     isnot(tabInfo.tab, null, "Should have added a pinned tab after addPinnedTab()");
     is(tabInfo.tab.pinned, true, "Tab should be marked as pinned");
 
     let tab = tabInfo.tab;
 
     gContentAPI.removePinnedTab();
     isnot(gBrowser.tabs[0], tab, "First tab should not be the pinned tab");
-    let tabInfo = UITour.pinnedTabs.get(window);
+    tabInfo = UITour.pinnedTabs.get(window);
     is(tabInfo, null, "Should not have any data about the removed pinned tab after removePinnedTab()");
 
     gContentAPI.addPinnedTab();
     gContentAPI.addPinnedTab();
     gContentAPI.addPinnedTab();
     is(gBrowser.tabs[1].pinned, false, "After multiple calls of addPinnedTab, should still only have one pinned tab");
 
     done();
--- a/caps/tests/mochitest/test_disableScript.xul
+++ b/caps/tests/mochitest/test_disableScript.xul
@@ -93,17 +93,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   function setScriptEnabledForDocShell(win, enabled) {
     win.QueryInterface(Ci.nsIInterfaceRequestor)
        .getInterface(Ci.nsIDocShell)
        .allowJavascript = enabled;
   }
 
   function testList(expectEnabled, win, list, idx) {
-    let idx = idx || 0;
+    idx = idx || 0;
     let deferred = Promise.defer();
     let target = list[idx] + path;
     info("Testing scriptability for: " + target + ". expecting " + expectEnabled);
     navigateFrame(win.frameElement, target).then(function() {
       checkScriptEnabled(win, expectEnabled);
       if (idx == list.length - 1)
         deferred.resolve();
       else
--- a/content/media/mediasource/MediaSourceReader.cpp
+++ b/content/media/mediasource/MediaSourceReader.cpp
@@ -80,17 +80,17 @@ MediaSourceReader::RequestAudioData()
 {
   MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData", this);
   if (!mAudioReader) {
     MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called with no audio reader", this);
     GetCallback()->OnDecodeError();
     return;
   }
   mAudioIsSeeking = false;
-  SwitchAudioReader(double(mLastAudioTime) / USECS_PER_S);
+  SwitchAudioReader(mLastAudioTime);
   mAudioReader->RequestAudioData();
 }
 
 void
 MediaSourceReader::OnAudioDecoded(AudioData* aSample)
 {
   MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
@@ -114,17 +114,17 @@ MediaSourceReader::OnAudioDecoded(AudioD
   GetCallback()->OnAudioDecoded(aSample);
 }
 
 void
 MediaSourceReader::OnAudioEOS()
 {
   MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p (decoders=%u)",
             this, mAudioReader.get(), mAudioTrack->Decoders().Length());
-  if (SwitchAudioReader(double(mLastAudioTime) / USECS_PER_S)) {
+  if (SwitchAudioReader(mLastAudioTime)) {
     // Success! Resume decoding with next audio decoder.
     RequestAudioData();
   } else if (IsEnded()) {
     // End of stream.
     MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p EOS (decoders=%u)",
               this, mAudioReader.get(), mAudioTrack->Decoders().Length());
     GetCallback()->OnAudioEOS();
   }
@@ -141,17 +141,17 @@ MediaSourceReader::RequestVideoData(bool
     return;
   }
   if (aSkipToNextKeyframe) {
     mTimeThreshold = aTimeThreshold;
     mDropAudioBeforeThreshold = true;
     mDropVideoBeforeThreshold = true;
   }
   mVideoIsSeeking = false;
-  SwitchVideoReader(double(mLastVideoTime) / USECS_PER_S);
+  SwitchVideoReader(mLastVideoTime);
   mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold);
 }
 
 void
 MediaSourceReader::OnVideoDecoded(VideoData* aSample)
 {
   MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
@@ -176,17 +176,17 @@ MediaSourceReader::OnVideoDecoded(VideoD
 }
 
 void
 MediaSourceReader::OnVideoEOS()
 {
   // End of stream. See if we can switch to another video decoder.
   MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p (decoders=%u)",
             this, mVideoReader.get(), mVideoTrack->Decoders().Length());
-  if (SwitchVideoReader(double(mLastVideoTime) / USECS_PER_S)) {
+  if (SwitchVideoReader(mLastVideoTime)) {
     // Success! Resume decoding with next video decoder.
     RequestVideoData(false, 0);
   } else if (IsEnded()) {
     // End of stream.
     MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p EOS (decoders=%u)",
               this, mVideoReader.get(), mVideoTrack->Decoders().Length());
     GetCallback()->OnVideoEOS();
   }
@@ -222,115 +222,68 @@ MediaSourceReader::BreakCycles()
   mVideoTrack = nullptr;
   mVideoReader = nullptr;
   for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
     mTrackBuffers[i]->BreakCycles();
   }
   mTrackBuffers.Clear();
 }
 
-bool
-MediaSourceReader::CanSelectAudioReader(MediaDecoderReader* aNewReader)
-{
-  AudioInfo currentInfo = mAudioReader->GetMediaInfo().mAudio;
-  AudioInfo newInfo = aNewReader->GetMediaInfo().mAudio;
-
-  // TODO: We can't handle switching audio formats yet.
-  if (currentInfo.mRate != newInfo.mRate ||
-      currentInfo.mChannels != newInfo.mChannels) {
-    MSE_DEBUGV("MediaSourceReader(%p)::CanSelectAudioReader(%p) skip reader due to format mismatch",
-               this, aNewReader);
-    return false;
-  }
-
-  if (aNewReader->AudioQueue().AtEndOfStream()) {
-    MSE_DEBUGV("MediaSourceReader(%p)::CanSelectAudioReader(%p) skip reader due to queue EOS",
-               this, aNewReader);
-    return false;
-  }
-
-  return true;
-}
-
-bool
-MediaSourceReader::CanSelectVideoReader(MediaDecoderReader* aNewReader)
-{
-  if (aNewReader->VideoQueue().AtEndOfStream()) {
-    MSE_DEBUGV("MediaSourceReader(%p)::CanSelectVideoReader(%p) skip reader due to queue EOS",
-               this, aNewReader);
-    return false;
-  }
-
-  return true;
-}
-
 already_AddRefed<MediaDecoderReader>
-MediaSourceReader::SelectReader(double aTarget,
-                                bool (MediaSourceReader::*aCanSelectReader)(MediaDecoderReader*),
+MediaSourceReader::SelectReader(int64_t aTarget,
                                 const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders)
 {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
   // Consider decoders in order of newest to oldest, as a newer decoder
   // providing a given buffered range is expected to replace an older one.
   for (int32_t i = aTrackDecoders.Length() - 1; i >= 0; --i) {
     nsRefPtr<MediaDecoderReader> newReader = aTrackDecoders[i]->GetReader();
 
-    // Check the track-type-specific aspects first, as it's assumed these
-    // are cheaper than a buffered range comparison, which seems worthwhile
-    // to avoid on any reader we'd subsequently reject.
-    if (!(this->*aCanSelectReader)(newReader)) {
-      continue;
-    }
-
     nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
     aTrackDecoders[i]->GetBuffered(ranges);
-    if (ranges->Find(aTarget) == dom::TimeRanges::NoIndex) {
-      MSE_DEBUGV("MediaSourceReader(%p)::SelectReader(%f) newReader=%p target not in ranges=%s",
+    if (ranges->Find(double(aTarget) / USECS_PER_S) == dom::TimeRanges::NoIndex) {
+      MSE_DEBUGV("MediaSourceReader(%p)::SelectReader(%lld) newReader=%p target not in ranges=%s",
                  this, aTarget, newReader.get(), DumpTimeRanges(ranges).get());
       continue;
     }
 
     return newReader.forget();
   }
 
   return nullptr;
 }
 
 bool
-MediaSourceReader::SwitchAudioReader(double aTarget)
+MediaSourceReader::SwitchAudioReader(int64_t aTarget)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   // XXX: Can't handle adding an audio track after ReadMetadata.
   if (!mAudioTrack) {
     return false;
   }
-  nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget,
-                                                        &MediaSourceReader::CanSelectAudioReader,
-                                                        mAudioTrack->Decoders());
+  nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, mAudioTrack->Decoders());
   if (newReader && newReader != mAudioReader) {
     mAudioReader->SetIdle();
     mAudioReader = newReader;
     MSE_DEBUGV("MediaSourceReader(%p)::SwitchAudioReader switched reader to %p", this, mAudioReader.get());
     return true;
   }
   return false;
 }
 
 bool
-MediaSourceReader::SwitchVideoReader(double aTarget)
+MediaSourceReader::SwitchVideoReader(int64_t aTarget)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   // XXX: Can't handle adding a video track after ReadMetadata.
   if (!mVideoTrack) {
     return false;
   }
-  nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget,
-                                                        &MediaSourceReader::CanSelectVideoReader,
-                                                        mVideoTrack->Decoders());
+  nsRefPtr<MediaDecoderReader> newReader = SelectReader(aTarget, mVideoTrack->Decoders());
   if (newReader && newReader != mVideoReader) {
     mVideoReader->SetIdle();
     mVideoReader = newReader;
     MSE_DEBUGV("MediaSourceReader(%p)::SwitchVideoReader switched reader to %p", this, mVideoReader.get());
     return true;
   }
   return false;
 }
@@ -434,32 +387,32 @@ public:
     return NS_OK;
   }
 
 private:
   nsRefPtr<AbstractMediaDecoder> mDecoder;
 };
 
 void
-MediaSourceReader::WaitForTimeRange(double aTime)
+MediaSourceReader::WaitForTimeRange(int64_t aTime)
 {
-  MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%f)", this, aTime);
+  MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%lld)", this, aTime);
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
   // Loop until we have the requested time range in the active TrackBuffers.
   // Ideally, this wait loop would use an async request and callback
   // instead.  Bug 1056441 covers that change.
   while (!TrackBuffersContainTime(aTime) && !IsShutdown() && !IsEnded()) {
-    MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%f) waiting", this, aTime);
+    MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%lld) waiting", this, aTime);
     mon.Wait();
   }
 }
 
 bool
-MediaSourceReader::TrackBuffersContainTime(double aTime)
+MediaSourceReader::TrackBuffersContainTime(int64_t aTime)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   if (mAudioTrack && !mAudioTrack->ContainsTime(aTime)) {
     return false;
   }
   if (mVideoTrack && !mVideoTrack->ContainsTime(aTime)) {
     return false;
   }
@@ -477,42 +430,39 @@ MediaSourceReader::Seek(int64_t aTime, i
   for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
     mTrackBuffers[i]->ResetDecode();
   }
 
   // Decoding discontinuity upon seek, reset last times to seek target.
   mLastAudioTime = aTime;
   mLastVideoTime = aTime;
 
-  double target = static_cast<double>(aTime) / USECS_PER_S;
-  if (!TrackBuffersContainTime(target)) {
-    MSE_DEBUG("MediaSourceReader(%p)::Seek no active buffer contains target=%f", this, target);
+  if (!TrackBuffersContainTime(aTime)) {
+    MSE_DEBUG("MediaSourceReader(%p)::Seek no active buffer contains target=%lld", this, aTime);
     NS_DispatchToMainThread(new ChangeToHaveMetadata(mDecoder));
   }
 
-  WaitForTimeRange(target);
+  WaitForTimeRange(aTime);
 
   if (IsShutdown()) {
     return NS_ERROR_FAILURE;
   }
 
   if (mAudioTrack) {
     mAudioIsSeeking = true;
-    SwitchAudioReader(target);
-    MOZ_ASSERT(static_cast<SourceBufferDecoder*>(mAudioReader->GetDecoder())->ContainsTime(target));
+    SwitchAudioReader(aTime);
     nsresult rv = mAudioReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
     MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p rv=%x", this, mAudioReader.get(), rv);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
   if (mVideoTrack) {
     mVideoIsSeeking = true;
-    SwitchVideoReader(target);
-    MOZ_ASSERT(static_cast<SourceBufferDecoder*>(mVideoReader->GetDecoder())->ContainsTime(target));
+    SwitchVideoReader(aTime);
     nsresult rv = mVideoReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
     MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p rv=%x", this, mVideoReader.get(), rv);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
   return NS_OK;
 }
--- a/content/media/mediasource/MediaSourceReader.h
+++ b/content/media/mediasource/MediaSourceReader.h
@@ -88,48 +88,37 @@ public:
 
   bool IsShutdown()
   {
     ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
     return mDecoder->IsShutdown();
   }
 
   // Return true if all of the active tracks contain data for the specified time.
-  bool TrackBuffersContainTime(double aTime);
+  bool TrackBuffersContainTime(int64_t aTime);
 
   // Mark the reader to indicate that EndOfStream has been called on our MediaSource
   void Ended();
 
   // Return true if the Ended method has been called
   bool IsEnded();
 
 private:
-  bool SwitchAudioReader(double aTarget);
-  bool SwitchVideoReader(double aTarget);
+  bool SwitchAudioReader(int64_t aTarget);
+  bool SwitchVideoReader(int64_t aTarget);
 
-  // Return a reader from the set available in aTrackDecoders that is considered
-  // usable by the aCanUserReader callback and has data available in the range
-  // requested by aTarget.
-  // aCanSelectReader is passed each reader available in aTrackDecoders and is
-  // expected to return true if the reader is considerable selectable.
-  already_AddRefed<MediaDecoderReader> SelectReader(double aTarget,
-                                                    bool (MediaSourceReader::*aCanSelectReader)(MediaDecoderReader*),
+  // Return a reader from the set available in aTrackDecoders that has data
+  // available in the range requested by aTarget.
+  already_AddRefed<MediaDecoderReader> SelectReader(int64_t aTarget,
                                                     const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
 
-  // Passed to SelectReader to enforce any track format specific requirements.
-  // In the case of CanSelectAudioReader, verifies that aNewReader has a
-  // matching audio format to the existing reader, as format switching is not
-  // yet supported.
-  bool CanSelectAudioReader(MediaDecoderReader* aNewReader);
-  bool CanSelectVideoReader(MediaDecoderReader* aNewReader);
-
   // Waits on the decoder monitor for aTime to become available in the active
   // TrackBuffers.  Used to block a Seek call until the necessary data has been
   // provided to the relevant SourceBuffers.
-  void WaitForTimeRange(double aTime);
+  void WaitForTimeRange(int64_t aTime);
 
   nsRefPtr<MediaDecoderReader> mAudioReader;
   nsRefPtr<MediaDecoderReader> mVideoReader;
 
   nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
   nsRefPtr<TrackBuffer> mAudioTrack;
   nsRefPtr<TrackBuffer> mVideoTrack;
--- a/content/media/mediasource/SourceBuffer.cpp
+++ b/content/media/mediasource/SourceBuffer.cpp
@@ -42,44 +42,62 @@ extern PRLogModuleInfo* GetMediaSourceAP
 #endif
 
 namespace mozilla {
 
 class ContainerParser {
 public:
   virtual ~ContainerParser() {}
 
+  // Return true if aData starts with an initialization segment.
+  // The base implementation exists only for debug logging and is expected
+  // to be called first from the overriding implementation.
   virtual bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
   {
     MSE_DEBUG("ContainerParser(%p)::IsInitSegmentPresent aLength=%u [%x%x%x%x]",
               this, aLength,
               aLength > 0 ? aData[0] : 0,
               aLength > 1 ? aData[1] : 0,
               aLength > 2 ? aData[2] : 0,
               aLength > 3 ? aData[3] : 0);
     return false;
   }
 
+  // Return true if aData starts with a media segment.
+  // The base implementation exists only for debug logging and is expected
+  // to be called first from the overriding implementation.
   virtual bool IsMediaSegmentPresent(const uint8_t* aData, uint32_t aLength)
   {
     MSE_DEBUG("ContainerParser(%p)::IsMediaSegmentPresent aLength=%u [%x%x%x%x]",
               this, aLength,
               aLength > 0 ? aData[0] : 0,
               aLength > 1 ? aData[1] : 0,
               aLength > 2 ? aData[2] : 0,
               aLength > 3 ? aData[3] : 0);
     return false;
   }
 
+  // Parse aData to extract the start and end frame times from the media
+  // segment.  aData may not start on a parser sync boundary.  Return true
+  // if aStart and aEnd have been updated.
   virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
-                                          double& aStart, double& aEnd)
+                                          int64_t& aStart, int64_t& aEnd)
   {
     return false;
   }
 
+  // Compare aLhs and rHs, considering any error that may exist in the
+  // timestamps from the format's base representation.  Return true if aLhs
+  // == aRhs within the error epsilon.
+  virtual bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs)
+  {
+    NS_WARNING("Using default ContainerParser::TimestampFuzzyEquals implementation");
+    return aLhs == aRhs;
+  }
+
   virtual const nsTArray<uint8_t>& InitData()
   {
     MOZ_ASSERT(mInitData.Length() > 0);
     return mInitData;
   }
 
   static ContainerParser* CreateForMIMEType(const nsACString& aType);
 
@@ -88,16 +106,18 @@ protected:
 };
 
 class WebMContainerParser : public ContainerParser {
 public:
   WebMContainerParser()
     : mParser(0), mOffset(0)
   {}
 
+  static const unsigned NS_PER_USEC = 1000;
+
   bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
   {
     ContainerParser::IsInitSegmentPresent(aData, aLength);
     // XXX: This is overly primitive, needs to collect data as it's appended
     // to the SB and handle, rather than assuming everything is present in a
     // single aData segment.
     // 0x1a45dfa3 // EBML
     // ...
@@ -128,18 +148,18 @@ public:
     // 0x1654ae6b // -> One or more Tracks
     if (aLength >= 4 &&
         aData[0] == 0x1f && aData[1] == 0x43 && aData[2] == 0xb6 && aData[3] == 0x75) {
       return true;
     }
     return false;
   }
 
-  virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
-                                          double& aStart, double& aEnd)
+  bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
+                                  int64_t& aStart, int64_t& aEnd)
   {
     bool initSegment = IsInitSegmentPresent(aData, aLength);
     if (initSegment) {
       mOffset = 0;
       mParser = WebMBufferedParser(0);
       mOverlappedMapping.Clear();
     }
 
@@ -176,30 +196,35 @@ public:
     while (mOffset < mapping[endIdx].mEndOffset && endIdx > 0) {
       endIdx -= 1;
     }
 
     if (endIdx == 0) {
       return false;
     }
 
-    static const double NS_PER_S = 1e9;
-    aStart = mapping[0].mTimecode / NS_PER_S;
-    aEnd = mapping[endIdx].mTimecode / NS_PER_S;
-    aEnd += (mapping[endIdx].mTimecode - mapping[endIdx - 1].mTimecode) / NS_PER_S;
+    uint64_t frameDuration = mapping[endIdx].mTimecode - mapping[endIdx - 1].mTimecode;
+    aStart = mapping[0].mTimecode / NS_PER_USEC;
+    aEnd = (mapping[endIdx].mTimecode + frameDuration) / NS_PER_USEC;
 
-    MSE_DEBUG("WebMContainerParser(%p)::ParseStartAndEndTimestamps: [%f, %f] [fso=%lld, leo=%lld, l=%u endIdx=%u]",
+    MSE_DEBUG("WebMContainerParser(%p)::ParseStartAndEndTimestamps: [%lld, %lld] [fso=%lld, leo=%lld, l=%u endIdx=%u]",
               this, aStart, aEnd, mapping[0].mSyncOffset, mapping[endIdx].mEndOffset, mapping.Length(), endIdx);
 
     mapping.RemoveElementsAt(0, endIdx + 1);
     mOverlappedMapping.AppendElements(mapping);
 
     return true;
   }
 
+  bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs)
+  {
+    int64_t error = mParser.GetTimecodeScale() / NS_PER_USEC;
+    return llabs(aLhs - aRhs) <= error * 2;
+  }
+
 private:
   WebMBufferedParser mParser;
   nsTArray<WebMTimeDataOffset> mOverlappedMapping;
   int64_t mOffset;
 };
 
 class MP4ContainerParser : public ContainerParser {
 public:
@@ -227,18 +252,18 @@ public:
         return true;
       }
     }
 
     return aData[4] == 'f' && aData[5] == 't' && aData[6] == 'y' &&
            aData[7] == 'p';
   }
 
-  virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
-                                          double& aStart, double& aEnd)
+  bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
+                                  int64_t& aStart, int64_t& aEnd)
   {
     bool initSegment = IsInitSegmentPresent(aData, aLength);
     if (initSegment) {
       mStream = new mp4_demuxer::BufferStream();
       mParser = new mp4_demuxer::MoofParser(mStream, 0);
     } else if (!mStream || !mParser) {
       return false;
     }
@@ -261,19 +286,19 @@ public:
     mp4_demuxer::Interval<mp4_demuxer::Microseconds> compositionRange =
       mParser->GetCompositionRange(byteRanges);
 
     mStream->DiscardBefore(mParser->mOffset);
 
     if (compositionRange.IsNull()) {
       return false;
     }
-    aStart = static_cast<double>(compositionRange.start) / USECS_PER_S;
-    aEnd = static_cast<double>(compositionRange.end) / USECS_PER_S;
-    MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: [%f, %f]",
+    aStart = compositionRange.start;
+    aEnd = compositionRange.end;
+    MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: [%lld, %lld]",
               this, aStart, aEnd);
     return true;
   }
 
 private:
   nsRefPtr<mp4_demuxer::BufferStream> mStream;
   nsAutoPtr<mp4_demuxer::MoofParser> mParser;
 };
@@ -586,23 +611,23 @@ SourceBuffer::AppendData(const uint8_t* 
   } else if (!mTrackBuffer->HasInitSegment()) {
     MSE_DEBUG("SourceBuffer(%p)::AppendData: Non-init segment appended during initialization.", this);
     Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
     ErrorResult dummy;
     mMediaSource->EndOfStream(decodeError, dummy);
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
-  double start, end;
+  int64_t start, end;
   if (mParser->ParseStartAndEndTimestamps(aData, aLength, start, end)) {
-    double lastStart, lastEnd;
+    int64_t lastStart, lastEnd;
     mTrackBuffer->LastTimestamp(lastStart, lastEnd);
     if (mParser->IsMediaSegmentPresent(aData, aLength) &&
-        (start < lastEnd || start - lastEnd > 0.1)) {
-      MSE_DEBUG("SourceBuffer(%p)::AppendData: Data last=[%f, %f] overlaps [%f, %f]",
+        !mParser->TimestampsFuzzyEqual(start, lastEnd)) {
+      MSE_DEBUG("SourceBuffer(%p)::AppendData: Data last=[%lld, %lld] overlaps [%lld, %lld]",
                 this, lastStart, lastEnd, start, end);
 
       // This data is earlier in the timeline than data we have already
       // processed, so we must create a new decoder to handle the decoding.
       mTrackBuffer->DiscardDecoder();
 
       // If we've got a decoder here, it's not initialized, so we can use it
       // rather than creating a new one.
@@ -611,17 +636,17 @@ SourceBuffer::AppendData(const uint8_t* 
         return;
       }
       MSE_DEBUG("SourceBuffer(%p)::AppendData: Decoder marked as initialized.", this);
       const nsTArray<uint8_t>& initData = mParser->InitData();
       mTrackBuffer->AppendData(initData.Elements(), initData.Length());
       mTrackBuffer->SetLastStartTimestamp(start);
     }
     mTrackBuffer->SetLastEndTimestamp(end);
-    MSE_DEBUG("SourceBuffer(%p)::AppendData: Segment last=[%f, %f] [%f, %f]",
+    MSE_DEBUG("SourceBuffer(%p)::AppendData: Segment last=[%lld, %lld] [%lld, %lld]",
               this, lastStart, lastEnd, start, end);
   }
   if (!mTrackBuffer->AppendData(aData, aLength)) {
     Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
     ErrorResult dummy;
     mMediaSource->EndOfStream(decodeError, dummy);
     aRv.Throw(NS_ERROR_FAILURE);
     return;
--- a/content/media/mediasource/SourceBufferDecoder.cpp
+++ b/content/media/mediasource/SourceBufferDecoder.cpp
@@ -231,21 +231,9 @@ SourceBufferDecoder::ConvertToByteOffset
     return -1;
   }
   int64_t length = GetResource()->GetLength();
   MOZ_ASSERT(length > 0);
   int64_t offset = (aTime / (double(mMediaDuration) / USECS_PER_S)) * length;
   return offset;
 }
 
-bool
-SourceBufferDecoder::ContainsTime(double aTime)
-{
-  ErrorResult dummy;
-  nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
-  nsresult rv = GetBuffered(ranges);
-  if (NS_FAILED(rv) || ranges->Length() == 0) {
-    return false;
-  }
-  return ranges->Find(aTime) != dom::TimeRanges::NoIndex;
-}
-
 } // namespace mozilla
--- a/content/media/mediasource/SourceBufferDecoder.h
+++ b/content/media/mediasource/SourceBufferDecoder.h
@@ -80,19 +80,16 @@ public:
     MOZ_ASSERT((!mTaskQueue && aTaskQueue) || (mTaskQueue && !aTaskQueue));
     mTaskQueue = aTaskQueue;
   }
 
   // Given a time convert it into an approximate byte offset from the
   // cached data. Returns -1 if no such value is computable.
   int64_t ConvertToByteOffset(double aTime);
 
-  // Returns true if the data buffered by this decoder contains the given time.
-  bool ContainsTime(double aTime);
-
 private:
   virtual ~SourceBufferDecoder();
 
   // Our TrackBuffer's task queue, this is only non-null during initialization.
   RefPtr<MediaTaskQueue> mTaskQueue;
 
   nsRefPtr<MediaResource> mResource;
 
--- a/content/media/mediasource/TrackBuffer.cpp
+++ b/content/media/mediasource/TrackBuffer.cpp
@@ -42,20 +42,18 @@ extern PRLogModuleInfo* GetMediaSourceAP
 #endif
 
 namespace mozilla {
 
 TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType)
   : mParentDecoder(aParentDecoder)
   , mType(aType)
   , mLastStartTimestamp(0)
-  , mLastEndTimestamp(UnspecifiedNaN<double>())
+  , mLastEndTimestamp(0)
   , mHasInit(false)
-  , mHasAudio(false)
-  , mHasVideo(false)
 {
   MOZ_COUNT_CTOR(TrackBuffer);
   mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
   aParentDecoder->AddTrackBuffer(this);
 }
 
 TrackBuffer::~TrackBuffer()
 {
@@ -172,17 +170,17 @@ TrackBuffer::NewDecoder()
   if (!decoder) {
     return false;
   }
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   mCurrentDecoder = decoder;
   mDecoders.AppendElement(decoder);
 
   mLastStartTimestamp = 0;
-  mLastEndTimestamp = UnspecifiedNaN<double>();
+  mLastEndTimestamp = 0;
   mHasInit = true;
 
   return QueueInitializeDecoder(decoder);
 }
 
 bool
 TrackBuffer::QueueInitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
 {
@@ -213,53 +211,76 @@ TrackBuffer::InitializeDecoder(nsRefPtr<
   nsAutoPtr<MetadataTags> tags; // TODO: Handle metadata.
   nsresult rv = reader->ReadMetadata(&mi, getter_Transfers(tags));
   reader->SetIdle();
   if (NS_FAILED(rv) || (!mi.HasVideo() && !mi.HasAudio())) {
     // XXX: Need to signal error back to owning SourceBuffer.
     MSE_DEBUG("TrackBuffer(%p): Reader %p failed to initialize rv=%x audio=%d video=%d",
               this, reader, rv, mi.HasAudio(), mi.HasVideo());
     aDecoder->SetTaskQueue(nullptr);
-    {
-        ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
-        mDecoders.RemoveElement(aDecoder);
-    }
-    NS_DispatchToMainThread(new ReleaseDecoderTask(aDecoder));
+    RemoveDecoder(aDecoder);
     return;
   }
 
   if (mi.HasVideo()) {
     MSE_DEBUG("TrackBuffer(%p): Reader %p video resolution=%dx%d",
               this, reader, mi.mVideo.mDisplay.width, mi.mVideo.mDisplay.height);
   }
   if (mi.HasAudio()) {
     MSE_DEBUG("TrackBuffer(%p): Reader %p audio sampleRate=%d channels=%d",
               this, reader, mi.mAudio.mRate, mi.mAudio.mChannels);
   }
 
+  if (!RegisterDecoder(aDecoder)) {
+    // XXX: Need to signal error back to owning SourceBuffer.
+    MSE_DEBUG("TrackBuffer(%p): Reader %p not activated", this, reader);
+    RemoveDecoder(aDecoder);
+    return;
+  }
   MSE_DEBUG("TrackBuffer(%p): Reader %p activated", this, reader);
-  RegisterDecoder(aDecoder);
 }
 
-void
+bool
+TrackBuffer::ValidateTrackFormats(const MediaInfo& aInfo)
+{
+  if (mInfo.HasAudio() != aInfo.HasAudio() ||
+      mInfo.HasVideo() != aInfo.HasVideo()) {
+    MSE_DEBUG("TrackBuffer(%p)::ValidateTrackFormats audio/video track mismatch", this);
+    return false;
+  }
+
+  // TODO: Support dynamic audio format changes.
+  if (mInfo.HasAudio() &&
+      (mInfo.mAudio.mRate != aInfo.mAudio.mRate ||
+       mInfo.mAudio.mChannels != aInfo.mAudio.mChannels)) {
+    MSE_DEBUG("TrackBuffer(%p)::ValidateTrackFormats audio format mismatch", this);
+    return false;
+  }
+
+  return true;
+}
+
+bool
 TrackBuffer::RegisterDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   aDecoder->SetTaskQueue(nullptr);
   const MediaInfo& info = aDecoder->GetReader()->GetMediaInfo();
   // Initialize the track info since this is the first decoder.
   if (mInitializedDecoders.IsEmpty()) {
-    mHasAudio = info.HasAudio();
-    mHasVideo = info.HasVideo();
-    mParentDecoder->OnTrackBufferConfigured(this, info);
-  } else if ((info.HasAudio() && !mHasAudio) || (info.HasVideo() && !mHasVideo)) {
+    mInfo = info;
+    mParentDecoder->OnTrackBufferConfigured(this, mInfo);
+  }
+  if (!ValidateTrackFormats(info)) {
     MSE_DEBUG("TrackBuffer(%p)::RegisterDecoder with mismatched audio/video tracks", this);
+    return false;
   }
   mInitializedDecoders.AppendElement(aDecoder);
   mParentDecoder->NotifyTimeRangesChanged();
+  return true;
 }
 
 void
 TrackBuffer::DiscardDecoder()
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   if (mCurrentDecoder) {
     mCurrentDecoder->GetResource()->Ended();
@@ -282,50 +303,50 @@ TrackBuffer::HasInitSegment()
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   return mHasInit;
 }
 
 bool
 TrackBuffer::IsReady()
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
-  MOZ_ASSERT((mHasAudio || mHasVideo) || mInitializedDecoders.IsEmpty());
-  return HasInitSegment() && (mHasAudio || mHasVideo);
+  MOZ_ASSERT((mInfo.HasAudio() || mInfo.HasVideo()) || mInitializedDecoders.IsEmpty());
+  return HasInitSegment() && (mInfo.HasAudio() || mInfo.HasVideo());
 }
 
 void
-TrackBuffer::LastTimestamp(double& aStart, double& aEnd)
+TrackBuffer::LastTimestamp(int64_t& aStart, int64_t& aEnd)
 {
   MOZ_ASSERT(NS_IsMainThread());
   aStart = mLastStartTimestamp;
   aEnd = mLastEndTimestamp;
 }
 
 void
-TrackBuffer::SetLastStartTimestamp(double aStart)
+TrackBuffer::SetLastStartTimestamp(int64_t aStart)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mLastStartTimestamp = aStart;
 }
 
 void
-TrackBuffer::SetLastEndTimestamp(double aEnd)
+TrackBuffer::SetLastEndTimestamp(int64_t aEnd)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mLastEndTimestamp = aEnd;
 }
 
 bool
-TrackBuffer::ContainsTime(double aTime)
+TrackBuffer::ContainsTime(int64_t aTime)
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) {
     nsRefPtr<dom::TimeRanges> r = new dom::TimeRanges();
     mInitializedDecoders[i]->GetBuffered(r);
-    if (r->Find(aTime) != dom::TimeRanges::NoIndex) {
+    if (r->Find(double(aTime) / USECS_PER_S) != dom::TimeRanges::NoIndex) {
       return true;
     }
   }
 
   return false;
 }
 
 void
@@ -368,9 +389,18 @@ TrackBuffer::Dump(const char* aPath)
     PR_snprintf(buf, sizeof(buf), "%s/reader-%p", path, mDecoders[i]->GetReader());
     PR_MkDir(buf, 0700);
 
     mDecoders[i]->GetResource()->Dump(buf);
   }
 }
 #endif
 
+void
+TrackBuffer::RemoveDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
+{
+  ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
+  MOZ_ASSERT(!mInitializedDecoders.Contains(aDecoder));
+  mDecoders.RemoveElement(aDecoder);
+  NS_DispatchToMainThread(new ReleaseDecoderTask(aDecoder));
+}
+
 } // namespace mozilla
--- a/content/media/mediasource/TrackBuffer.h
+++ b/content/media/mediasource/TrackBuffer.h
@@ -59,23 +59,23 @@ public:
   // Returns true if an init segment has been appended.
   bool HasInitSegment();
 
   // Returns true iff HasInitSegment() and the decoder using that init
   // segment has successfully initialized by setting mHas{Audio,Video}..
   bool IsReady();
 
   // Query and update mLast{Start,End}Timestamp.
-  void LastTimestamp(double& aStart, double& aEnd);
-  void SetLastStartTimestamp(double aStart);
-  void SetLastEndTimestamp(double aEnd);
+  void LastTimestamp(int64_t& aStart, int64_t& aEnd);
+  void SetLastStartTimestamp(int64_t aStart);
+  void SetLastEndTimestamp(int64_t aEnd);
 
   // Returns true if any of the decoders managed by this track buffer
   // contain aTime in their buffered ranges.
-  bool ContainsTime(double aTime);
+  bool ContainsTime(int64_t aTime);
 
   void BreakCycles();
 
   // Call ResetDecode() on each decoder in mDecoders.
   void ResetDecode();
 
   // Returns a reference to mInitializedDecoders, used by MediaSourceReader
   // to select decoders.
@@ -93,18 +93,29 @@ private:
   bool QueueInitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
 
   // Runs decoder initialization including calling ReadMetadata.  Runs as an
   // event on the decode thread pool.
   void InitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
 
   // Adds a successfully initialized decoder to mDecoders and (if it's the
   // first decoder initialized), initializes mHasAudio/mHasVideo.  Called
-  // from the decode thread pool.
-  void RegisterDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
+  // from the decode thread pool.  Return true if the decoder was
+  // successfully registered.
+  bool RegisterDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
+
+  // Returns true if aInfo is considered a supported or the same format as
+  // the TrackBuffer was initialized as.
+  bool ValidateTrackFormats(const MediaInfo& aInfo);
+
+  // Remove aDecoder from mDecoders and dispatch an event to the main thread
+  // to clean up the decoder.  If aDecoder was added to
+  // mInitializedDecoders, it must have been removed before calling this
+  // function.
+  void RemoveDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
 
   // A task queue using the shared media thread pool.  Used exclusively to
   // initialize (i.e. call ReadMetadata on) decoders as they are created via
   // NewDecoder.
   RefPtr<MediaTaskQueue> mTaskQueue;
 
   // All of the decoders managed by this TrackBuffer.  Access protected by
   // mParentDecoder's monitor.
@@ -117,23 +128,22 @@ private:
   // The decoder that the owning SourceBuffer is currently appending data to.
   nsRefPtr<SourceBufferDecoder> mCurrentDecoder;
 
   nsRefPtr<MediaSourceDecoder> mParentDecoder;
   const nsCString mType;
 
   // The last start and end timestamps added to the TrackBuffer via
   // AppendData.  Accessed on the main thread only.
-  double mLastStartTimestamp;
-  double mLastEndTimestamp;
+  int64_t mLastStartTimestamp;
+  int64_t mLastEndTimestamp;
 
   // Set when the initialization segment is first seen and cached (implied
   // by new decoder creation).  Protected by mParentDecoder's monitor.
   bool mHasInit;
 
   // Set when the first decoder used by this TrackBuffer is initialized.
   // Protected by mParentDecoder's monitor.
-  bool mHasAudio;
-  bool mHasVideo;
+  MediaInfo mInfo;
 };
 
 } // namespace mozilla
 #endif /* MOZILLA_TRACKBUFFER_H_ */
--- a/content/media/mediasource/test/mediasource.js
+++ b/content/media/mediasource/test/mediasource.js
@@ -1,20 +1,34 @@
 // Helpers for Media Source Extensions tests
 
 function runWithMSE(testFunction) {
-  addLoadEvent(() => SpecialPowers.pushPrefEnv({"set": [[ "media.mediasource.enabled", true ]]}, testFunction));
+  function bootstrapTest() {
+    var ms = new MediaSource();
+
+    var el = document.createElement("video");
+    el.src = URL.createObjectURL(ms);
+    el.preload = "auto";
+
+    document.body.appendChild(el);
+    SimpleTest.registerCleanupFunction(function () {
+      el.parentNode.removeChild(el);
+    });
+
+    testFunction(ms, el);
+  }
+
+  addLoadEvent(function () {
+    SpecialPowers.pushPrefEnv({"set": [[ "media.mediasource.enabled", true ]]},
+                              bootstrapTest);
+  });
 }
 
 function fetchWithXHR(uri, onLoadFunction) {
   var xhr = new XMLHttpRequest();
   xhr.open("GET", uri, true);
-  xhr.responseType = "blob";
-  xhr.addEventListener("load", function (e) {
+  xhr.responseType = "arraybuffer";
+  xhr.addEventListener("load", function () {
     is(xhr.status, 200, "fetchWithXHR load uri='" + uri + "' status=" + xhr.status);
-    var rdr = new FileReader();
-    rdr.addEventListener("load", function (e) {
-      onLoadFunction(e.target.result);
-    });
-    rdr.readAsArrayBuffer(e.target.response);
+    onLoadFunction(xhr.response);
   });
   xhr.send();
 };
--- a/content/media/mediasource/test/test_BufferedSeek.html
+++ b/content/media/mediasource/test/test_BufferedSeek.html
@@ -7,24 +7,17 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function () {
-  var ms = new MediaSource();
-
-  var v = document.createElement("video");
-  v.preload = "auto";
-  v.src = URL.createObjectURL(ms);
-  document.body.appendChild(v);
-
+runWithMSE(function (ms, v) {
   ms.addEventListener("sourceopen", function () {
     var sb = ms.addSourceBuffer("video/webm");
 
     fetchWithXHR("seek.webm", function (arrayBuffer) {
       sb.appendBuffer(new Uint8Array(arrayBuffer));
       sb.addEventListener("updateend", function () {
         ms.endOfStream()
       });
@@ -46,17 +39,16 @@ runWithMSE(function () {
     v.addEventListener("seeking", function () {
       wasSeeking = true;
       is(v.currentTime, target, "Video currentTime not at target");
     });
 
     v.addEventListener("seeked", function () {
       ok(wasSeeking, "Received expected seeking and seeked events");
       is(v.currentTime, target, "Video currentTime not at target");
-      v.parentNode.removeChild(v);
       SimpleTest.finish();
     });
   });
 });
 
 </script>
 </pre>
 </body>
--- a/content/media/mediasource/test/test_FrameSelection.html
+++ b/content/media/mediasource/test/test_FrameSelection.html
@@ -7,24 +7,17 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function () {
-  var ms = new MediaSource();
-
-  var v = document.createElement("video");
-  v.preload = "auto";
-  v.src = URL.createObjectURL(ms);
-  document.body.appendChild(v);
-
+runWithMSE(function (ms, v) {
   ms.addEventListener("sourceopen", function () {
     var sb = ms.addSourceBuffer("video/webm");
 
     fetchWithXHR("seek.webm", function (arrayBuffer) {
       // Append entire file covering range [0, 4].
       sb.appendBuffer(new Uint8Array(arrayBuffer));
     });
 
@@ -61,17 +54,16 @@ runWithMSE(function () {
 
       is(v.videoWidth, target.videoWidth, "videoWidth has incorrect final value");
       is(v.videoHeight, target.videoHeight, "videoHeight has incorrect final value");
 
       target = targets.shift();
       if (target) {
         v.currentTime = target.currentTime;
       } else {
-        v.parentNode.removeChild(v);
         SimpleTest.finish();
       }
     });
   });
 });
 
 </script>
 </pre>
--- a/content/media/mediasource/test/test_MediaSource.html
+++ b/content/media/mediasource/test/test_MediaSource.html
@@ -67,18 +67,19 @@ runWithMSE(function () {
   });
 
   ms.addEventListener("sourceended", function () {
     ok(true, "Receive a sourceended event");
     is(ms.readyState, "ended", "MediaSource must be in ended state after sourceended");
   });
 
   v.addEventListener("ended", function () {
-    is(v.duration, 4, "Video has correct duration");
-    is(v.currentTime, 4, "Video has played to end");
+    // XXX: Duration should be exactly 4.0, see bug 1065207.
+    is(v.duration, 4.001, "Video has correct duration");
+    is(v.currentTime, 4.001, "Video has played to end");
     v.parentNode.removeChild(v);
     SimpleTest.finish();
   });
 });
 
 </script>
 </pre>
 </body>
--- a/content/media/mediasource/test/test_SplitAppend.html
+++ b/content/media/mediasource/test/test_SplitAppend.html
@@ -7,24 +7,17 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function () {
-  var ms = new MediaSource();
-
-  var v = document.createElement("video");
-  v.preload = "auto";
-  v.src = URL.createObjectURL(ms);
-  document.body.appendChild(v);
-
+runWithMSE(function (ms, v) {
   ms.addEventListener("sourceopen", function () {
     var sb = ms.addSourceBuffer("video/webm");
 
     fetchWithXHR("seek.webm", function (arrayBuffer) {
       sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
       var first = true;
       sb.addEventListener("updateend", function () {
         if (first) {
@@ -34,19 +27,19 @@ runWithMSE(function () {
           ms.endOfStream();
         }
       });
       v.play();
     });
   });
 
   v.addEventListener("ended", function () {
-    is(v.duration, 4, "Video has correct duration");
-    is(v.currentTime, 4, "Video has played to end");
-    v.parentNode.removeChild(v);
+    // XXX: Duration should be exactly 4.0, see bug 1065207.
+    is(v.duration, 4.001, "Video has correct duration");
+    is(v.currentTime, 4.001, "Video has played to end");
     SimpleTest.finish();
   });
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/media/mediasource/test/test_SplitAppendDelay.html
+++ b/content/media/mediasource/test/test_SplitAppendDelay.html
@@ -7,24 +7,17 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
-runWithMSE(function () {
-  var ms = new MediaSource();
-
-  var v = document.createElement("video");
-  v.preload = "auto";
-  v.src = URL.createObjectURL(ms);
-  document.body.appendChild(v);
-
+runWithMSE(function (ms, v) {
   ms.addEventListener("sourceopen", function () {
     var sb = ms.addSourceBuffer("video/webm");
 
     fetchWithXHR("seek.webm", function (arrayBuffer) {
       sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
       var first = true;
       sb.addEventListener("updateend", function () {
         if (first) {
@@ -36,19 +29,19 @@ runWithMSE(function () {
           ms.endOfStream();
         }
       });
       v.play();
     });
   });
 
   v.addEventListener("ended", function () {
-    is(v.duration, 4, "Video has correct duration");
-    is(v.currentTime, 4, "Video has played to end");
-    v.parentNode.removeChild(v);
+    // XXX: Duration should be exactly 4.0, see bug 1065207.
+    is(v.duration, 4.001, "Video has correct duration");
+    is(v.currentTime, 4.001, "Video has played to end");
     SimpleTest.finish();
   });
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/browser-element/BrowserElementPanning.js
+++ b/dom/browser-element/BrowserElementPanning.js
@@ -507,17 +507,17 @@ const ContentPanning = {
                                        metrics.cssCompositedRect.height);
     this._cssPageRect = new Rect(metrics.cssPageRect.x,
                                  metrics.cssPageRect.y,
                                  metrics.cssPageRect.width,
                                  metrics.cssPageRect.height);
   },
 
   _recvDoubleTap: function(data) {
-    let data = data.json;
+    data = data.json;
 
     // We haven't received a metrics update yet; don't do anything.
     if (this._viewport == null) {
       return;
     }
 
     let win = content;
 
--- a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js
+++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js
@@ -109,26 +109,26 @@ function testReceiving_GSM_MessageId() {
 }
 
 function testReceiving_GSM_Language_and_Body() {
   log("Test receiving GSM Cell Broadcast - Language & Body");
 
   let promise = Promise.resolve();
 
   let testDcs = [];
-  dcs = 0;
+  let dcs = 0;
   while (dcs <= 0xFF) {
     try {
       let dcsInfo = { dcs: dcs };
       [ dcsInfo.encoding, dcsInfo.language,
         dcsInfo.indicator, dcsInfo.messageClass ] = decodeGsmDataCodingScheme(dcs);
       testDcs.push(dcsInfo);
     } catch (e) {
       // Unsupported coding group, skip.
-      let dcs = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10;
+      dcs = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10;
     }
     dcs++;
   }
 
   let verifyCBMessage = (aMessage, aDcsInfo) => {
     if (aDcsInfo.language) {
       is(aMessage.language, aDcsInfo.language, "aMessage.language");
     } else if (aDcsInfo.indicator) {
--- a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_umts.js
+++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_umts.js
@@ -125,26 +125,26 @@ function testReceiving_UMTS_MessageId() 
 }
 
 function testReceiving_UMTS_Language_and_Body() {
   log("Test receiving UMTS Cell Broadcast - Language & Body");
 
   let promise = Promise.resolve();
 
   let testDcs = [];
-  dcs = 0;
+  let dcs = 0;
   while (dcs <= 0xFF) {
     try {
       let dcsInfo = { dcs: dcs };
       [ dcsInfo.encoding, dcsInfo.language,
         dcsInfo.indicator, dcsInfo.messageClass ] = decodeGsmDataCodingScheme(dcs);
       testDcs.push(dcsInfo);
     } catch (e) {
       // Unsupported coding group, skip.
-      let dcs = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10;
+      dcs = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10;
     }
     dcs++;
   }
 
   let verifyCBMessage = (aMessage, aDcsInfo) => {
     if (aDcsInfo.language) {
       is(aMessage.language, aDcsInfo.language, "aMessage.language");
     } else if (aDcsInfo.indicator) {
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -256,17 +256,17 @@ ContactManager.prototype = {
                permValue == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
       if (aCancelCallback) {
         aCancelCallback();
       }
       return;
     }
 
     // Create an array with a single nsIContentPermissionType element.
-    let type = {
+    type = {
       type: "contacts",
       access: access,
       options: [],
       QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
     };
     let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
     typeArray.appendElement(type, false);
 
--- a/dom/contacts/fallback/ContactService.jsm
+++ b/dom/contacts/fallback/ContactService.jsm
@@ -97,16 +97,17 @@ let ContactService = this.ContactService
       msgMgr.sendAsyncMessage(aMsgName, aContent);
     });
   },
 
   receiveMessage: function(aMessage) {
     if (DEBUG) debug("receiveMessage " + aMessage.name);
     let mm = aMessage.target;
     let msg = aMessage.data;
+    let cursorList;
 
     switch (aMessage.name) {
       case "Contacts:Find":
         if (!this.assertPermission(aMessage, "contacts-read")) {
           return null;
         }
         let result = [];
         this._db.find(
@@ -120,17 +121,17 @@ let ContactService = this.ContactService
           }.bind(this),
           function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this),
           msg.options.findOptions);
         break;
       case "Contacts:GetAll":
         if (!this.assertPermission(aMessage, "contacts-read")) {
           return null;
         }
-        let cursorList = this._cursors.get(mm);
+        cursorList = this._cursors.get(mm);
         if (!cursorList) {
           cursorList = [];
           this._cursors.set(mm, cursorList);
         }
         cursorList.push(msg.cursorId);
 
         this._db.getAll(
           function(aContacts) {
--- a/dom/indexedDB/test/error_events_abort_transactions_iframe.html
+++ b/dom/indexedDB/test/error_events_abort_transactions_iframe.html
@@ -91,30 +91,30 @@
       is(originalRequest.transaction, trans, "request.transaction should still be set");
 
       event = yield undefined;
       is(event.type, "error", "Got request error event");
       is(event.target, originalRequest, "error event has right target");
       is(event.target.error.name, "ConstraintError", "Right error");
       is(originalRequest.transaction, null, "request.transaction should now be null");
 
-      let request = indexedDB.open(window.location.pathname, 1);
+      request = indexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
-      let event = yield undefined;
+      event = yield undefined;
 
-      let db = event.target.result;
+      db = event.target.result;
 
       event.target.transaction.oncomplete = grabEventAndContinueHandler;
       event.target.transaction.onabort = unexpectedSuccessHandler;
 
       is(db.version, "1", "Correct version");
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
 
-      let objectStore = db.createObjectStore("foo");
+      objectStore = db.createObjectStore("foo");
 
       is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
       ok(db.objectStoreNames.contains("foo"), "Has correct objectStore");
 
       objectStore.createIndex("baz", "key.path");
       objectStore.createIndex("dontDeleteMe", "");
 
       is(objectStore.indexNames.length, 2, "Correct indexNames length");
@@ -148,33 +148,33 @@
 
       is(db.version, "1", "Correct version");
       is(db.objectStoreNames.length, 2, "Correct objectStoreNames length");
       ok(db.objectStoreNames.contains("foo"), "Has correct objectStore");
       ok(db.objectStoreNames.contains("bar"), "Has correct objectStore");
 
       db.close();
 
-      let request = indexedDB.open(window.location.pathname, 2);
+      request = indexedDB.open(window.location.pathname, 2);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
-      let event = yield undefined;
+      event = yield undefined;
 
-      let db = event.target.result;
+      db = event.target.result;
 
-      let trans = event.target.transaction;
+      trans = event.target.transaction;
       trans.oncomplete = unexpectedSuccessHandler;
 
       is(db.version, "2", "Correct version");
       is(db.objectStoreNames.length, 2, "Correct objectStoreNames length");
       ok(db.objectStoreNames.contains("foo"), "Has correct objectStore");
       ok(db.objectStoreNames.contains("bar"), "Has correct objectStore");
 
       let createdObjectStore = db.createObjectStore("newlyCreated");
-      let objectStore = trans.objectStore("foo");
+      objectStore = trans.objectStore("foo");
       let deletedObjectStore = trans.objectStore("bar");
       deletedObjectStore.deleteIndex("foo");
       db.deleteObjectStore("bar");
 
       createdObjectStore.createIndex("newIndex", "key.path");
       objectStore.createIndex("newIndex", "key.path");
       objectStore.deleteIndex("baz");
 
--- a/dom/indexedDB/test/exceptions_in_events_iframe.html
+++ b/dom/indexedDB/test/exceptions_in_events_iframe.html
@@ -71,23 +71,23 @@
       request.onerror = grabEventAndContinueHandler;
       event = yield undefined;
 
       is(event.type, "error",
          "Throwing during an upgradeneeded event should fire an error.");
 
       // Test 2: Throwing during a request's success handler should abort the
       // transaction.
-      let request = indexedDB.open(window.location.pathname, 1);
+      request = indexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
       request.onblocked = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = unexpectedSuccessHandler;
       let openrequest = request;
-      let event = yield undefined;
+      event = yield undefined;
 
       request.onupgradeneeded = unexpectedSuccessHandler;
 
       let db = event.target.result;
       db.onerror = function(event) {
         event.preventDefault();
       };
 
@@ -116,38 +116,38 @@
       event = yield undefined;
 
       is(event.type, "error", "Got IDBOpenDBRequest error event");
       is(event.target, openrequest, "Right event target");
       is(event.target.error.name, "AbortError", "Right error name");
 
       // Test 3: Throwing during a request's error handler should abort the
       // transaction, even if preventDefault is called on the error event.
-      let request = indexedDB.open(window.location.pathname, 1);
+      request = indexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
       request.onblocked = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = unexpectedSuccessHandler;
-      let openrequest = request;
-      let event = yield undefined;
+      openrequest = request;
+      event = yield undefined;
 
       request.onupgradeneeded = unexpectedSuccessHandler;
 
-      let db = event.target.result;
+      db = event.target.result;
       db.onerror = function(event) {
         event.preventDefault();
       };
 
       event.target.transaction.oncomplete = unexpectedSuccessHandler;
       event.target.transaction.onabort = grabEventAndContinueHandler;
 
       is(db.version, 1, "Correct version");
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
 
-      let objectStore = db.createObjectStore("foo");
+      objectStore = db.createObjectStore("foo");
 
       is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
       ok(db.objectStoreNames.contains("foo"), "Has correct objectStore");
 
       request = objectStore.add({}, 1);
       request.onerror = errorHandler;
       request = objectStore.add({}, 1);
       request.onsuccess = unexpectedSuccessHandler;
--- a/dom/indexedDB/test/test_blob_simple.html
+++ b/dom/indexedDB/test/test_blob_simple.html
@@ -127,17 +127,17 @@
     fileReader.readAsText(cursorResults[0].blob);
     event = yield undefined;
 
     is(event.target.result, BLOB_DATA.join(""), "Correct text");
 
 
     info("Retrieve blobs from database via index and verify contents.");
 
-    let index = db.transaction("foo").objectStore("foo").index("foo");
+    index = db.transaction("foo").objectStore("foo").index("foo");
     index.get(INDEX_KEY).onsuccess = grabEventAndContinueHandler;
     event = yield undefined;
 
     info("Got blob from database");
 
     fileReader = new FileReader();
     fileReader.onload = grabEventAndContinueHandler;
     fileReader.readAsText(event.target.result.blob);
@@ -243,26 +243,26 @@
 
     let txn = db.transaction("foo", "readwrite");
     txn.objectStore("foo").put(event.target.result, key);
     txn.oncomplete = grabEventAndContinueHandler;
     event = yield undefined;
 
     info("Stored blob back into database");
 
-    let fileReader = new FileReader();
+    fileReader = new FileReader();
     fileReader.onload = grabEventAndContinueHandler;
     fileReader.readAsText(blobFromDB);
     event = yield undefined;
 
     is(event.target.result, BLOB_DATA.join(""), "Correct text");
 
-    let blobURL = URL.createObjectURL(blobFromDB);
+    blobURL = URL.createObjectURL(blobFromDB);
 
-    let xhr = new XMLHttpRequest();
+    xhr = new XMLHttpRequest();
     xhr.open("GET", blobURL);
     xhr.onload = grabEventAndContinueHandler;
     xhr.send();
     yield undefined;
 
     URL.revokeObjectURL(blobURL);
 
     is(xhr.responseText, BLOB_DATA.join(""), "Correct responseText");
--- a/dom/indexedDB/test/test_file_transaction_abort.html
+++ b/dom/indexedDB/test/test_file_transaction_abort.html
@@ -27,24 +27,24 @@
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield undefined;
 
       is(event.type, "upgradeneeded", "Got correct event type");
 
       let db = event.target.result;
       db.onerror = errorHandler;
 
-      objectStore = db.createObjectStore(objectStoreName, { });
+      let objectStore = db.createObjectStore(objectStoreName, { });
 
       event = yield undefined;
 
       is(event.type, "success", "Got correct event type");
 
       let trans = db.transaction([objectStoreName], READ_WRITE);
-      let objectStore = trans.objectStore(objectStoreName);
+      objectStore = trans.objectStore(objectStoreName);
 
       request = objectStore.add(fileData.file, fileData.key);
       request.onsuccess = grabEventAndContinueHandler;
       event = yield undefined;
 
       is(event.target.result, fileData.key, "Got correct key");
 
       trans.onabort = grabEventAndContinueHandler;
--- a/dom/indexedDB/test/test_filehandle_store_snapshot.html
+++ b/dom/indexedDB/test/test_filehandle_store_snapshot.html
@@ -54,17 +54,17 @@
 
     request = mutableFile.getFile();
     request.onsuccess = grabEventAndContinueHandler;
     event = yield undefined;
 
     let file = event.target.result;
 
     let trans = db.transaction([objectStoreName], READ_WRITE);
-    let objectStore = trans.objectStore(objectStoreName);
+    objectStore = trans.objectStore(objectStoreName);
 
     request = objectStore.add(file, 42);
     request.onsuccess = grabEventAndContinueHandler;
     event = yield undefined;
 
     // At this moment, the file should not be readable anymore.
     let reader = new FileReader();
     try {
--- a/dom/indexedDB/test/test_persistenceType.html
+++ b/dom/indexedDB/test/test_persistenceType.html
@@ -75,17 +75,17 @@
 
       is(event.target.result, data.key, "Got correct key");
 
       request = indexedDB.open(name, { version: version,
                                        storage: "temporary" });
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+      event = yield undefined;
 
       is(event.type, "upgradeneeded", "Got correct event type");
 
       db = event.target.result;
       db.onerror = errorHandler;
 
       objectStore = db.createObjectStore(objectStoreName, { });
 
--- a/dom/indexedDB/test/unit/test_autoIncrement_indexes.js
+++ b/dom/indexedDB/test/unit/test_autoIncrement_indexes.js
@@ -26,17 +26,17 @@ function testSteps()
   objectStore.add(data).onsuccess = grabEventAndContinueHandler;
   event = yield undefined;
 
   is(event.target.result, 1, "Added entry");
   request.onsuccess = grabEventAndContinueHandler;
 
   event = yield undefined;
 
-  let objectStore = db.transaction("foo").objectStore("foo");
+  objectStore = db.transaction("foo").objectStore("foo");
   let first = objectStore.index("first");
   let second = objectStore.index("second");
   let third = objectStore.index("third");
 
   first.get("foo").onsuccess = grabEventAndContinueHandler;
   event = yield undefined;
 
   is (event.target.result.id, 1, "Entry in first");
--- a/dom/indexedDB/test/unit/test_complex_keyPaths.js
+++ b/dom/indexedDB/test/unit/test_complex_keyPaths.js
@@ -159,18 +159,18 @@ function testSteps()
     store.clear().onsuccess = grabEventAndContinueHandler;
     yield undefined;
   }
 
   // Attempt to create indexes and insert data
   let store = db.createObjectStore("indexStore");
   let indexes = {};
   for (let i = 0; i < keyPaths.length; i++) {
+    let info = keyPaths[i];
     let test = " for index test " + JSON.stringify(info);
-    let info = keyPaths[i];
     let indexName = JSON.stringify(info.keyPath);
     if (!indexes[indexName]) {
       try {
         let index = store.createIndex(indexName, info.keyPath);
         ok(!("exception" in info), "shouldn't throw" + test);
         is(JSON.stringify(index.keyPath), JSON.stringify(info.keyPath),
            "index has correct keyPath property" + test);
         ok(index.keyPath === index.keyPath,
--- a/dom/indexedDB/test/unit/test_create_index_with_integer_keys.js
+++ b/dom/indexedDB/test/unit/test_create_index_with_integer_keys.js
@@ -21,20 +21,20 @@ function testSteps()
   event.target.onsuccess = continueToNextStep;
 
   // Make object store, add data.
   let objectStore = db.createObjectStore("foo", { keyPath: "id" });
   objectStore.add(data);
   yield undefined;
   db.close();
 
-  let request = indexedDB.open(this.window ? window.location.pathname : "Splendid Test", 2);
+  request = indexedDB.open(this.window ? window.location.pathname : "Splendid Test", 2);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
-  let event = yield undefined;
+  event = yield undefined;
 
   let db2 = event.target.result;
   db2.onerror = errorHandler;
 
   event.target.onsuccess = continueToNextStep;
 
   // Create index.
   event.target.transaction.objectStore("foo").createIndex("foo", "num");
--- a/dom/indexedDB/test/unit/test_create_objectStore.js
+++ b/dom/indexedDB/test/unit/test_create_objectStore.js
@@ -108,17 +108,16 @@ function testSteps()
     ex = e;
   }
   ok(ex, "createObjectStore with empty keyPath and autoIncrement should throw");
   is(ex.name, "InvalidAccessError", "should throw right exception");
   ok(ex instanceof DOMException, "should throw right exception");
   is(ex.code, DOMException.INVALID_ACCESS_ERR, "should throw right exception");
 
   // Can't handle autoincrement and array keypath
-  let ex;
   try {
     db.createObjectStore("storefail", { keyPath: ["a"], autoIncrement: true });
   }
   catch(e) {
     ex = e;
   }
   ok(ex, "createObjectStore with array keyPath and autoIncrement should throw");
   is(ex.name, "InvalidAccessError", "should throw right exception");
--- a/dom/indexedDB/test/unit/test_deleteDatabase.js
+++ b/dom/indexedDB/test/unit/test_deleteDatabase.js
@@ -30,17 +30,17 @@ function testSteps()
 
   event = yield undefined;
 
   is(event.type, "success", "Expect a success event");
   is(event.target, request, "Event has right target");
   ok(event.target.result instanceof IDBDatabase, "Result should be a database");
   is(db.objectStoreNames.length, 1, "Expect an objectStore here");
 
-  let request = indexedDB.open(name, 10);
+  request = indexedDB.open(name, 10);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
 
   event = yield undefined;
   is(event.type, "success", "Expect a success event");
   is(event.target, request, "Event has right target");
   ok(event.target.result instanceof IDBDatabase, "Result should be a database");
   let db2 = event.target.result;
@@ -61,45 +61,45 @@ function testSteps()
     db2.onversionchange = unexpectedSuccessHandler;
   };
 
   // The IDB spec doesn't guarantee the order that onversionchange will fire
   // on the dbs.
   db.onversionchange = closeDBs;
   db2.onversionchange = closeDBs;
 
-  let request = indexedDB.deleteDatabase(name);
+  request = indexedDB.deleteDatabase(name);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
 
   ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
 
   event = yield undefined;
   ok(onversionchangecalled, "Expected versionchange events");
   is(event.type, "success", "expect a success event");
   is(event.target, request, "event has right target");
   ok(event.target.result === undefined, "event should have no result");
 
-  let request = indexedDB.open(name, 1);
+  request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
 
   event = yield undefined;
   is(event.target.result.version, 1, "DB has proper version");
   is(event.target.result.objectStoreNames.length, 0, "DB should have no object stores");
 
 
-  let request = indexedDB.deleteDatabase("thisDatabaseHadBetterNotExist");
+  request = indexedDB.deleteDatabase("thisDatabaseHadBetterNotExist");
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
 
   event = yield undefined;
   ok(true, "deleteDatabase on a non-existent database succeeded");
 
-  let request = indexedDB.open("thisDatabaseHadBetterNotExist");
+  request = indexedDB.open("thisDatabaseHadBetterNotExist");
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
 
   event = yield undefined;
   ok(true, "after deleting a non-existent database, open should work");
 
   finishTest();
   yield undefined;
--- a/dom/indexedDB/test/unit/test_deleteDatabase_interactions.js
+++ b/dom/indexedDB/test/unit/test_deleteDatabase_interactions.js
@@ -30,17 +30,17 @@ function testSteps()
 
   is(event.type, "success", "Expect a success event");
   is(event.target, request, "Event has right target");
   ok(event.target.result instanceof IDBDatabase, "Result should be a database");
   is(db.objectStoreNames.length, 1, "Expect an objectStore here");
 
   db.close();
 
-  let request = indexedDB.deleteDatabase(name);
+  request = indexedDB.deleteDatabase(name);
 
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
 
   ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
 
   let openRequest = indexedDB.open(name, 1);
   openRequest.onerror = errorHandler;
--- a/dom/indexedDB/test/unit/test_index_empty_keyPath.js
+++ b/dom/indexedDB/test/unit/test_index_empty_keyPath.js
@@ -42,39 +42,39 @@ function testSteps()
   // Now create the index.
   objectStore.createIndex("set", "", { unique: true });
   yield undefined; // success
 
   let trans = db.transaction("data", "readwrite");
   objectStore = trans.objectStore("data");
   index = objectStore.index("set");
 
-  let request = index.get("bar");
+  request = index.get("bar");
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   
-  let event = yield undefined;
+  event = yield undefined;
 
   is(event.target.result, "bar", "Got correct result");
 
-  let request = objectStore.add("foopy", 4);
+  request = objectStore.add("foopy", 4);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
 
   yield undefined;
 
-  let request = index.get("foopy");
+  request = index.get("foopy");
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   
-  let event = yield undefined;
+  event = yield undefined;
 
   is(event.target.result, "foopy", "Got correct result");
 
-  let request = objectStore.add("foopy", 5);
+  request = objectStore.add("foopy", 5);
   request.addEventListener("error", new ExpectError("ConstraintError", true));
   request.onsuccess = unexpectedSuccessHandler;
 
   trans.oncomplete = grabEventAndContinueHandler;
 
   yield undefined;
   yield undefined;
 
--- a/dom/indexedDB/test/unit/test_indexes.js
+++ b/dom/indexedDB/test/unit/test_indexes.js
@@ -247,17 +247,17 @@ function testSteps()
   }
   yield undefined;
 
   is(keyIndex, 5, "Saw all the expected keys");
 
   ok(true, "Test group 5");
 
   keyIndex = 2;
-  let keyRange = IDBKeyRange.bound("Bob", "Ron", true);
+  keyRange = IDBKeyRange.bound("Bob", "Ron", true);
 
   request = objectStore.index("name").openKeyCursor(keyRange);
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
          "Correct key");
@@ -273,17 +273,17 @@ function testSteps()
   }
   yield undefined;
 
   is(keyIndex, 5, "Saw all the expected keys");
 
   ok(true, "Test group 6");
 
   keyIndex = 1;
-  let keyRange = IDBKeyRange.bound("Bob", "Ron", false, true);
+  keyRange = IDBKeyRange.bound("Bob", "Ron", false, true);
 
   request = objectStore.index("name").openKeyCursor(keyRange);
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
          "Correct key");
--- a/dom/indexedDB/test/unit/test_multientry.js
+++ b/dom/indexedDB/test/unit/test_multientry.js
@@ -138,17 +138,16 @@ function testSteps()
      { put:     { x: 0, id: 8 },
        fail:    true },
     ];
 
   store.deleteIndex("myindex");
   index = store.createIndex("myindex", "x", { multiEntry: true, unique: true });
   is(index.multiEntry, true, "index created with multiEntry");
 
-  let i;
   let indexes;
   for (i = 0; i < tests.length; ++i) {
     let test = tests[i];
     let testName = " for " + JSON.stringify(test);
     let req;
     if (test.add) {
       req = store.add(test.add);
     }
--- a/dom/indexedDB/test/unit/test_names_sorted.js
+++ b/dom/indexedDB/test/unit/test_names_sorted.js
@@ -69,42 +69,42 @@ function testSteps()
     let info = objectStoreInfo[i];
   
     is(trans.objectStoreNames[info.location], info.name,
        "Got objectStore name in the right location");
   }
 
   db.close();
 
-  let request = indexedDB.open(name, 1);
+  request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   request.onupgradeneeded = unexpectedSuccessHandler;
-  let event = yield undefined;
+  event = yield undefined;
 
-  let db = event.target.result;
+  db = event.target.result;
 
-  let objectStoreNames = []
+  objectStoreNames = []
   for (let i = 0; i < objectStoreInfo.length; i++) {
     let info = objectStoreInfo[i];
     objectStoreNames.push(info.name);
 
     is(db.objectStoreNames[info.location], info.name,
        "Got objectStore name in the right location");
 
     let trans = db.transaction(info.name);
     let objectStore = trans.objectStore(info.name);
     for (let j = 0; j < indexInfo.length; j++) {
       let info = indexInfo[j];
       is(objectStore.indexNames[info.location], info.name,
          "Got index name in the right location");
     }
   }
 
-  let trans = db.transaction(objectStoreNames);
+  trans = db.transaction(objectStoreNames);
   for (let i = 0; i < objectStoreInfo.length; i++) {
     let info = objectStoreInfo[i];
   
     is(trans.objectStoreNames[info.location], info.name,
        "Got objectStore name in the right location");
   }
 
   db.close();
--- a/dom/indexedDB/test/unit/test_objectStore_openKeyCursor.js
+++ b/dom/indexedDB/test/unit/test_objectStore_openKeyCursor.js
@@ -322,17 +322,17 @@ function testSteps() {
     } else {
       cursor.continue();
     }
   };
   yield undefined;
 
   is(seenKeys.length, allKeys.length - 9, "Saw the right number of keys");
 
-  let match = true;
+  match = true;
   for (let i = 0, j = 0; i < seenKeys.length; i++) {
     if (seenKeys[i] !== allKeys[i + j]) {
       match = false;
       break;
     }
     if (i == 0) {
       j = 9;
     }
@@ -378,17 +378,17 @@ function testSteps() {
     } else {
       cursor.continue();
     }
   };
   yield undefined;
 
   is(seenKeys.length, allKeys.length - 9, "Saw the right number of keys");
 
-  let match = true;
+  match = true;
   for (let i = 0, j = 0; i < seenKeys.length; i++) {
     if (seenKeys[i] !== allKeys[i + j]) {
       match = false;
       break;
     }
     if (i == 0) {
       j = 9;
     }
--- a/dom/indexedDB/test/unit/test_open_for_principal.js
+++ b/dom/indexedDB/test/unit/test_open_for_principal.js
@@ -51,17 +51,17 @@ function testSteps()
   let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
                      .getService(Components.interfaces.nsIScriptSecurityManager)
                      .getNoAppCodebasePrincipal(uri);
 
   request = indexedDB.openForPrincipal(principal, name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
-  let event = yield undefined;
+  event = yield undefined;
 
   is(event.type, "upgradeneeded", "Got correct event type");
 
   db = event.target.result;
   db.onerror = errorHandler;
 
   objectStore = db.createObjectStore(objectStoreName, { });
 
--- a/dom/indexedDB/test/unit/test_overlapping_transactions.js
+++ b/dom/indexedDB/test/unit/test_overlapping_transactions.js
@@ -17,17 +17,17 @@ function testSteps()
 
   let db = event.target.result;
   is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
   event.target.onsuccess = grabEventAndContinueHandler;
   for (let i in objectStores) {
     db.createObjectStore(objectStores[i], { autoIncrement: true });
   }
-  let event = yield undefined;
+  event = yield undefined;
 
   is(db.objectStoreNames.length, objectStores.length,
      "Correct objectStoreNames list");
 
   for (let i = 0; i < 50; i++) {
     let stepNumber = 0;
 
     request = db.transaction(["foo"], "readwrite")
--- a/dom/indexedDB/test/unit/test_persistenceType.js
+++ b/dom/indexedDB/test/unit/test_persistenceType.js
@@ -59,17 +59,17 @@ function testSteps()
 
   is(event.target.result, data.key, "Got correct key");
 
   request = indexedDB.open(name, { version: version,
                                    storage: "temporary" });
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
-  let event = yield undefined;
+  event = yield undefined;
 
   is(event.type, "success", "Got correct event type");
 
   is(db.name, name, "Correct name");
   is(db.version, version, "Correct version");
   is(db.storage, "persistent", "Correct persistence type");
 
   objectStore = db.transaction([objectStoreName])
--- a/dom/indexedDB/test/unit/test_remove_objectStore.js
+++ b/dom/indexedDB/test/unit/test_remove_objectStore.js
@@ -34,22 +34,22 @@ function testSteps()
   }
   yield undefined;
 
   is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
   is(db.objectStoreNames.item(0), objectStoreName, "Correct name");
 
   db.close();
 
-  let request = indexedDB.open(name, 2);
+  request = indexedDB.open(name, 2);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
-  let event = yield undefined;
+  event = yield undefined;
 
-  let db = event.target.result;
+  db = event.target.result;
   let trans = event.target.transaction;
 
   let oldObjectStore = trans.objectStore(objectStoreName);
   isnot(oldObjectStore, null, "Correct object store prior to deleting");
   db.deleteObjectStore(objectStoreName);
   is(db.objectStoreNames.length, 0, "Correct objectStores list");
   try {
     trans.objectStore(objectStoreName);
@@ -78,22 +78,22 @@ function testSteps()
   db.deleteObjectStore(objectStore.name);
   is(db.objectStoreNames.length, 0, "Correct objectStores list");
 
   continueToNextStep();
   yield undefined;
 
   db.close();
 
-  let request = indexedDB.open(name, 3);
+  request = indexedDB.open(name, 3);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
-  let event = yield undefined;
+  event = yield undefined;
 
-  let db = event.target.result;
+  db = event.target.result;
 
   objectStore = db.createObjectStore(objectStoreName, { keyPath: "foo" });
 
   request = objectStore.add({foo:"bar"});
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
 
   db.deleteObjectStore(objectStoreName);
--- a/dom/indexedDB/test/unit/test_temporary_storage.js
+++ b/dom/indexedDB/test/unit/test_temporary_storage.js
@@ -195,17 +195,17 @@ function testSteps()
   request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name,
                                        { storage: "temporary" });
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield undefined;
 
   is(event.type, "success", "Got correct event type");
 
-  let db = event.target.result;
+  db = event.target.result;
 
   checkUsage(3);
   yield undefined;
 
   info("Stage 4");
 
   let trans = db.transaction(["foo"], "readwrite");
 
--- a/dom/indexedDB/test/unit/test_transaction_error.js
+++ b/dom/indexedDB/test/unit/test_transaction_error.js
@@ -38,17 +38,17 @@ function testSteps() {
   let transaction = db.transaction(objectStoreName, "readwrite");
   transaction.onerror = grabEventAndContinueHandler;
   transaction.oncomplete = grabEventAndContinueHandler;
 
   objectStore = transaction.objectStore(objectStoreName);
 
   info("Adding duplicate entry with preventDefault()");
 
-  let request = objectStore.add(data, dataKey);
+  request = objectStore.add(data, dataKey);
   request.onsuccess = unexpectedSuccessHandler;
   request.onerror = grabEventAndContinueHandler;
   event = yield undefined;
 
   is(event.type, "error", "Got an error event");
   is(event.target, request, "Error event targeted request");
   is(event.currentTarget, request, "Got request error first");
   is(event.currentTarget.error.name, expectedError,
--- a/dom/indexedDB/test/unit/test_transaction_ordering.js
+++ b/dom/indexedDB/test/unit/test_transaction_ordering.js
@@ -31,19 +31,19 @@ function testSteps()
 
   trans1.oncomplete = grabEventAndContinueHandler;
   trans2.oncomplete = grabEventAndContinueHandler;
 
   yield undefined;
   yield undefined;
 
   let trans3 = db.transaction("foo", "readonly");
-  let request = trans3.objectStore("foo").get(42);
+  request = trans3.objectStore("foo").get(42);
   request.onsuccess = grabEventAndContinueHandler;
   request.onerror = errorHandler;
 
-  let event = yield undefined;
+  event = yield undefined;
   is(event.target.result, "2", "Transactions were ordered properly.");
 
   finishTest();
   yield undefined;
 }
 
--- a/dom/mobilemessage/gonk/MobileMessageDB.jsm
+++ b/dom/mobilemessage/gonk/MobileMessageDB.jsm
@@ -1106,17 +1106,17 @@ MobileMessageDB.prototype = {
                 }
                 messageRecord.threadId = threadRecord.id;
                 messageRecord.threadIdIndex = [threadRecord.id, timestamp];
                 messageCursor.update(messageRecord);
                 messageCursor.continue();
                 return;
               }
 
-              let threadRecord = {
+              threadRecord = {
                 participantIds: participantIds,
                 participantAddresses: threadParticipants,
                 lastMessageId: messageRecord.id,
                 lastTimestamp: timestamp,
                 subject: messageRecord.body,
                 unreadCount: messageRecord.read ? 0 : 1,
                 lastMessageType: messageRecord.type
               };
--- a/dom/system/gonk/tests/test_ril_worker_sms_cdma.js
+++ b/dom/system/gonk/tests/test_ril_worker_sms_cdma.js
@@ -149,17 +149,17 @@ function pduToParcelData(cdmaPduHelper, 
   }
 
   // Subaddress
   writeByte(0);
   writeByte(0);
   writeByte(0);
 
   // Bearer Data Length
-  let dataLength = pdu.bearerData.length;
+  dataLength = pdu.bearerData.length;
   writeByte(dataLength);
 
   // Bearer Data
   for (let i = 0; i < dataLength; i++) {
     writeByte(pdu.bearerData[i]);
   }
 
   return data;
--- a/dom/system/gonk/tests/test_ril_worker_stk.js
+++ b/dom/system/gonk/tests/test_ril_worker_stk.js
@@ -935,17 +935,17 @@ add_test(function test_stk_proactive_com
 
   berTlv = berHelper.decode(set_up_menu_2.length);
   ctlvs = berTlv.value;
   tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
   do_check_eq(tlv.value.commandNumber, 0x01);
   do_check_eq(tlv.value.typeOfCommand, STK_CMD_SET_UP_MENU);
   do_check_eq(tlv.value.commandQualifier, 0x00);
 
-  let menu = stkFactory.createParam(tlv.value, ctlvs);
+  menu = stkFactory.createParam(tlv.value, ctlvs);
   do_check_eq(menu.title, "Title");
   do_check_eq(menu.items[0].identifier, 1);
   do_check_eq(menu.items[0].text, "item 1");
   do_check_eq(menu.items[1].identifier, 2);
   do_check_eq(menu.items[1].text, "item 2");
   do_check_eq(menu.items[2].identifier, 3);
   do_check_eq(menu.items[2].text, "item 3");
   do_check_eq(menu.nextActionList[0], STK_NEXT_ACTION_END_PROACTIVE_SESSION);
--- a/dom/system/tests/marionette/test_proximity_init.js
+++ b/dom/system/tests/marionette/test_proximity_init.js
@@ -19,17 +19,17 @@ function testEventInit() {
   if (event.value !== initValue ||
       event.min !== initMin ||
       event.max !== initMax) {
     log("DeviceProximityEvent not initialized correctly.");
   }
 
   // Test UserProximityEvent initialization
   log("Verifying UserProximityEvent constructor.");
-  let event = new UserProximityEvent("userproximity", {near: true});
+  event = new UserProximityEvent("userproximity", {near: true});
   is(event.type, "userproximity", "event type");
   ok(event.near, "Initialization of UserProximityEvent");
   verifyDefaultStatus();
 }
 
 function verifyDefaultStatus() {
   let emulatorDone = false;
 
--- a/dom/tests/mochitest/bugs/test_bug531176.html
+++ b/dom/tests/mochitest/bugs/test_bug531176.html
@@ -16,30 +16,30 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 531176 **/
 
 var errorCount = 0;
 function errorHandler(msg, filename, linenr) {
-  is(msg, "SyntaxError: syntax error", "Wrong error!");
+  is(msg, "SyntaxError: expected expression, got ';'", "Wrong error!");
   is(filename, window.location, "Wrong filename!");
   is(linenr, 1, "Wrong linenr!");
   ++errorCount;
 }
 
 window.onerror = errorHandler;
 document.body.setAttribute("onclick", "var x=;");
 // Force eager compilation
 document.body.onclick;
 is(errorCount, 1, "Error handler should have been called! (1)");
 
 function recursiveHandler(msg, filename, linenr) {
-  is(msg, "SyntaxError: syntax error", "Wrong error!");
+  is(msg, "SyntaxError: expected expression, got ';'", "Wrong error!");
   is(filename, window.location, "Wrong filename!");
   is(linenr, 1, "Wrong linenr!");
   ++errorCount;
   document.body.setAttribute("onclick", "var z=;");
 }
 
 window.onerror = recursiveHandler;
 document.body.setAttribute("onclick", "var y=;");
--- a/dom/tests/mochitest/chrome/queryCaretRectUnix.html
+++ b/dom/tests/mochitest/chrome/queryCaretRectUnix.html
@@ -135,17 +135,17 @@
       max: { left: 25, top: 390 },
     });
 
     cp = document.caretPositionFromPoint(395, 395);
     input = cp.offsetNode;
     offset = cp.offset;
     input.selectionStart = input.selectionEnd = offset;
 
-    let selection = getSelection(text);
+    selection = getSelection(text);
 
     testCaretPosition(domWinUtils, input.selectionStart, {
       min: { left: 390, top: 380 },
       max: { left: 400, top: 390 },
     });
 
     testCaretPosition(domWinUtils, input.selectionEnd, {
       min: { left: 390, top: 380 },
--- a/dom/tests/mochitest/chrome/queryCaretRectWin.html
+++ b/dom/tests/mochitest/chrome/queryCaretRectWin.html
@@ -144,17 +144,17 @@
       max: { left: 25, top: 390 },
     });
 
     cp = document.caretPositionFromPoint(395, 395);
     input = cp.offsetNode;
     offset = cp.offset;
     input.selectionStart = input.selectionEnd = offset;
 
-    let selection = getSelection(text);
+    selection = getSelection(text);
 
     testCaretPosition(domWinUtils, input.selectionStart, {
       min: { left: 390, top: 380 },
       max: { left: 400, top: 390 },
     });
 
     testCaretPosition(domWinUtils, input.selectionEnd, {
       min: { left: 390, top: 380 },
--- a/dom/tests/mochitest/chrome/selectAtPoint.html
+++ b/dom/tests/mochitest/chrome/selectAtPoint.html
@@ -108,69 +108,69 @@
       checkSelection(document, "SELECT_WORD", "ttestselection1");
     } else if (isWindows) {
       checkSelection(document, "SELECT_WORD", "ttestselection1 ");
     }
     setSingle(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_PARAGRAPH);
     checkSelection(document, "SELECT_PARAGRAPH", "ttestselection1 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos. Ei munere officiis assentior pro, nibh decore ius at.");
 
     // Centered on the second character in the sentence div
-    let targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)),
-                        yPos: rect.top + (charDims.height / 2) };
+    targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)),
+                    yPos: rect.top + (charDims.height / 2) };
     setSingle(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
     checkSelection(document, "SELECT_CHARACTER", "te");
     setSingle(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CLUSTER);
     checkSelection(document, "SELECT_CLUSTER", "te");
 
     // Separate character blocks in a word 't(te)s(ts)election1'
-    let targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)),
-                        yPos: rect.top + (charDims.height / 2) };
+    targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)),
+                    yPos: rect.top + (charDims.height / 2) };
     setStart(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
-    let targetPoint = { xPos: rect.left + ((charDims.width * 4) + (charDims.width / 2)),
-                        yPos: rect.top + (charDims.height / 2) };
+    targetPoint = { xPos: rect.left + ((charDims.width * 4) + (charDims.width / 2)),
+                    yPos: rect.top + (charDims.height / 2) };
     setEnd(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
     if (isLinux || isMac) {
       // XXX I think this is a bug, the right hand selection is 4.5 characters over with a
       // monspaced font. what we want: t(te)s(ts)election1 what we get: t(te)st(se)lection1
       checkSelection(document, "split selection", "tese");
     } else if (isWindows) {
       checkSelection(document, "split selection", "tets");
     }
 
     // Trying to select where there's no text, should fail but not throw
     let result = dwu.selectAtPoint(rect.left - 20, rect.top - 20, Ci.nsIDOMWindowUtils.SELECT_CHARACTER, false);
     ok(result == false, "couldn't select?");
 
     // Second div in the main page
 
-    let div = document.getElementById("div2");
-    let rect = div.getBoundingClientRect();
+    div = document.getElementById("div2");
+    rect = div.getBoundingClientRect();
 
     // Centered on the first line, first character in the paragraph div
-    let targetPoint = { xPos: rect.left + (charDims.width / 2),
-                        yPos: rect.top + (charDims.height / 2) };
+    targetPoint = { xPos: rect.left + (charDims.width / 2),
+                    yPos: rect.top + (charDims.height / 2) };
     setSingle(dwu, targetPoint.xPos + 50, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_PARAGRAPH);
     checkSelection(document, "SELECT_PARAGRAPH", "Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos.");
 
     //
     // Inner IFRAME selection tests
     //
 
     let frame = document.getElementById("frame1");
     let dwuFrame = frame.contentDocument
                         .defaultView
                         .QueryInterface(Ci.nsIInterfaceRequestor)
                         .getInterface(Ci.nsIDOMWindowUtils);
 
     frame.contentWindow.scrollTo(0, 0);
 
-    let rect = frame.getBoundingClientRect();
+    rect = frame.getBoundingClientRect();
 
-    let targetPoint = { xPos: charDims.width / 2,
-                        yPos: charDims.height / 2 };
+    targetPoint = { xPos: charDims.width / 2,
+                    yPos: charDims.height / 2 };
     setSingle(dwuFrame, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_WORDNOSPACE);
     checkSelection(frame.contentWindow.document, "SELECT_WORDNOSPACE", "ttestselection2");
     setSingle(dwuFrame, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_WORD);
     if (isLinux || isMac) {
       checkSelection(frame.contentWindow.document, "SELECT_WORD", "ttestselection2");
     } else if (isWindows) {
       checkSelection(frame.contentWindow.document, "SELECT_WORD", "ttestselection2 ");
     }
--- a/dom/tests/mochitest/whatwg/postMessage_structured_clone_helper.js
+++ b/dom/tests/mochitest/whatwg/postMessage_structured_clone_helper.js
@@ -25,39 +25,39 @@ function getTestContent()
   recursiveobj.bar = new Object();
   recursiveobj.bar.foo = "foo";
   recursiveobj.bar.backref = recursiveobj;
   recursiveobj.bar.baz = new Date(1306113544);
   recursiveobj.bar.backref2 = recursiveobj;
   recursiveobj.expando = recursiveobj;
   yield recursiveobj;
 
-  let obj = new Object();
+  obj = new Object();
   obj.expando1 = 1;
   obj.foo = new Object();
   obj.foo.bar = 2;
   obj.bar = new Object();
   obj.bar.foo = obj.foo;
   obj.expando = new Object();
   obj.expando.expando = new Object();
   obj.expando.expando.obj = obj;
   obj.expando2 = 4;
   obj.baz = obj.expando.expando;
   obj.blah = obj.bar;
   obj.foo.baz = obj.blah;
   obj.foo.blah = obj.blah;
   yield obj;
 
   let diamond = new Object();
-  let obj = new Object();
+  obj = new Object();
   obj.foo = "foo";
   obj.bar = 92;
   obj.backref = diamond;
   diamond.ref1 = obj;
   diamond.ref2 = obj;
   yield diamond;
 
   let doubleref = new Object();
-  let obj = new Object();
+  obj = new Object();
   doubleref.ref1 = obj;
   doubleref.ref2 = obj;
   yield doubleref;
 }
--- a/dom/wappush/tests/test_si_pdu_helper.js
+++ b/dom/wappush/tests/test_si_pdu_helper.js
@@ -50,17 +50,17 @@ add_test(function test_si_parse_wbxml_em
   let data = {};
 
   contentType = "application/vnd.wap.sic";
   data.array = new Uint8Array([
                   0x02, 0x05, 0x6A, 0x00, 0x05
                 ]);
   data.offset = 0;
   let result = "<si/>";
-  let msg = SI.PduHelper.parse(data, contentType);
+  msg = SI.PduHelper.parse(data, contentType);
   do_check_eq(msg.content, result);
 
   run_next_test();
 });
 
 /**
  * Empty SI compressed by WBXML, with public ID stored in string table
  */
@@ -74,17 +74,17 @@ add_test(function test_si_parse_wbxml_em
                   0x02, 0x00, 0x00, 0x6A, 0x1C, 0x2D, 0x2F, 0x2F,
                   0x57, 0x41, 0x50, 0x46, 0x4F, 0x52, 0x55, 0x4D,
                   0x2F, 0x2F, 0x44, 0x54, 0x44, 0x20, 0x53, 0x49,
                   0x20, 0x31, 0x2E, 0x30, 0x2F, 0x2F, 0x45, 0x4E,
                   0x00, 0x05
                 ]);
   data.offset = 0;
   let result = "<si/>";
-  let msg = SI.PduHelper.parse(data, contentType);
+  msg = SI.PduHelper.parse(data, contentType);
   do_check_eq(msg.content, result);
 
   run_next_test();
 });
 
 /**
  * SI compressed by WBXML with href attribute
  */
@@ -99,17 +99,17 @@ add_test(function test_si_parse_wbxml_wi
                   0x6F, 0x72, 0x65, 0x69, 0x6C, 0x6C, 0x79, 0x00,
                   0x85, 0x01, 0x03, 0x43, 0x68, 0x65, 0x63, 0x6B,
                   0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x65,
                   0x62, 0x73, 0x69, 0x74, 0x65, 0x00, 0x01, 0x01
                 ]);
   data.offset = 0;
   let result = "<si><indication href=\"http://www.oreilly.com/\">" +
                "Check this website</indication></si>";
-  let msg = SI.PduHelper.parse(data, contentType);
+  msg = SI.PduHelper.parse(data, contentType);
   do_check_eq(msg.content, result);
 
   run_next_test();
 });
 
 /**
  * SI compressed by WBXML with href attribute containing reserved XML character
  */
@@ -126,17 +126,17 @@ add_test(function test_si_parse_wbxml_wi
                   0x72, 0x00, 0x01, 0x03, 0x43, 0x68, 0x65, 0x63,
                   0x6B, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77,
                   0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x00, 0x01,
                   0x01
                 ]);
   data.offset = 0;
   let result = "<si><indication href=\"http://www.oreilly.com/foo&amp;bar\">" +
                "Check this website</indication></si>";
-  let msg = SI.PduHelper.parse(data, contentType);
+  msg = SI.PduHelper.parse(data, contentType);
   do_check_eq(msg.content, result);
 
   run_next_test();
 });
 
 /**
  * SI compressed by WBXML with href and date attribute
  */
@@ -157,17 +157,17 @@ add_test(function test_si_parse_wbxml_wi
                   0x61, 0x76, 0x65, 0x20, 0x34, 0x20, 0x6E, 0x65,
                   0x77, 0x20, 0x65, 0x6D, 0x61, 0x69, 0x6C, 0x73,
                   0x00, 0x01, 0x01
                 ]);
   data.offset = 0;
   let result = "<si><indication href=\"http://www.xyz.com/email/123/abc.wml\"" +
                " created=\"1999-06-25T15:23:15Z\" si-expires=\"1999-06-30T00:00:00Z\">" +
                "You have 4 new emails</indication></si>";
-  let msg = SI.PduHelper.parse(data, contentType);
+  msg = SI.PduHelper.parse(data, contentType);
   do_check_eq(msg.content, result);
 
   run_next_test();
 });
 
 /**
  * SI compressed by WBXML with attributes and string table
  */
@@ -188,13 +188,13 @@ add_test(function test_si_parse_wbxml_wi
                   0xC3, 0x07, 0x19, 0x99, 0x06, 0x25, 0x15, 0x23,
                   0x15, 0x10, 0xC3, 0x04, 0x19, 0x99, 0x06, 0x30,
                   0x01, 0x83, 0x12, 0x01, 0x01
                 ]);
   data.offset = 0;
   let result = "<si><indication href=\"http://www.xyz.com/email/123/abc.wml\"" +
                " created=\"1999-06-25T15:23:15Z\" si-expires=\"1999-06-30T00:00:00Z\">" +
                "You have 4 new emails</indication></si>";
-  let msg = SI.PduHelper.parse(data, contentType);
+  msg = SI.PduHelper.parse(data, contentType);
   do_check_eq(msg.content, result);
 
   run_next_test();
 });
--- a/dom/wappush/tests/test_sl_pdu_helper.js
+++ b/dom/wappush/tests/test_sl_pdu_helper.js
@@ -46,42 +46,42 @@ add_test(function test_sl_parse_wbxml() 
   contentType = "application/vnd.wap.slc";
   data.array = new Uint8Array([
                   0x03, 0x06, 0x6A, 0x00, 0x85, 0x0A, 0x03, 0x6F,
                   0x72, 0x65, 0x69, 0x6C, 0x6C, 0x79, 0x00, 0x85,
                   0x01
                 ]);
   data.offset = 0;
   let result = "<sl href=\"http://www.oreilly.com/\"/>";
-  let msg = SL.PduHelper.parse(data, contentType);
+  msg = SL.PduHelper.parse(data, contentType);
   do_check_eq(msg.content, result);
 
   run_next_test();
 });
 
 /**
  * SL compressed by WBXML, with public ID stored in string table
  */
 add_test(function test_sl_parse_wbxml_public_id_string_table() {
-    let msg = {};
+  let msg = {};
   let contentType = "";
   let data = {};
 
   contentType = "application/vnd.wap.slc";
   data.array = new Uint8Array([
                   0x03, 0x00, 0x00, 0x6A, 0x1C, 0x2D, 0x2F, 0x2F,
                   0x57, 0x41, 0x50, 0x46, 0x4F, 0x52, 0x55, 0x4D,
                   0x2F, 0x2F, 0x44, 0x54, 0x44, 0x20, 0x53, 0x4C,
                   0x20, 0x31, 0x2E, 0x30, 0x2F, 0x2F, 0x45, 0x4E,
                   0x00, 0x85, 0x0A, 0x03, 0x6F, 0x72, 0x65, 0x69,
                   0x6C, 0x6C, 0x79, 0x00, 0x85, 0x01
                 ]);
   data.offset = 0;
   let result = "<sl href=\"http://www.oreilly.com/\"/>";
-  let msg = SL.PduHelper.parse(data, contentType);
+  msg = SL.PduHelper.parse(data, contentType);
   do_check_eq(msg.content, result);
 
   run_next_test();
 });
 
 /**
  * SL compressed by WBXML with string table
  */
@@ -93,13 +93,13 @@ add_test(function test_sl_parse_wbxml_wi
   contentType = "application/vnd.wap.slc";
   data.array = new Uint8Array([
                   0x03, 0x06, 0x6A, 0x08, 0x6F, 0x72, 0x65, 0x69,
                   0x6C, 0x6C, 0x79, 0x00, 0x85, 0x0A, 0x83, 0x00,
                   0x85, 0x01
                 ]);
   data.offset = 0;
   let result = "<sl href=\"http://www.oreilly.com/\"/>";
-  let msg = SL.PduHelper.parse(data, contentType);
+  msg = SL.PduHelper.parse(data, contentType);
   do_check_eq(msg.content, result);
 
   run_next_test();
 });
--- a/dom/workers/test/test_multi_sharedWorker_lifetimes.html
+++ b/dom/workers/test/test_multi_sharedWorker_lifetimes.html
@@ -65,33 +65,33 @@
           event = yield undefined;
           ok(event instanceof MessageEvent, "Got a MessageEvent");
           is(event.source, frame, "Correct window got the event");
           is(event.data.type, "result", "Got a result message");
           is(event.data.data, storedData, "Got stored data");
 
           // Navigate when the bfcache is disabled.
           info("Navigating to about:blank");
-          let frame = document.getElementById("frame");
+          frame = document.getElementById("frame");
           frame.onload = sendToGenerator;
           frame.src = "about:blank";
           frame.contentWindow.document.body.offsetTop;
 
           yield undefined;
 
           info("Navigating to " + frameRelativeURL);
           frame.src = frameRelativeURL;
           frame.contentWindow.document.body.offsetTop;
 
           yield undefined;
 
           frame = frame.contentWindow;
           frame.postMessage({ command: "retrieve" }, "*");
 
-          let event = yield undefined;
+          event = yield undefined;
           ok(event instanceof MessageEvent, "Got a MessageEvent");
           is(event.source, frame, "Correct window got the event");
           is(event.data.type, "result", "Got a result message");
           is(event.data.data, undefined, "No data stored");
 
           frame.postMessage({ command: "store", data: storedData }, "*");
           frame.postMessage({ command: "retrieve" }, "*");
 
@@ -103,17 +103,17 @@
 
           info("Enabling '" + bfCacheEnabledPref + "' pref");
           SpecialPowers.pushPrefEnv({ set: [[bfCacheEnabledPref, true],
                                             [bfCacheDepthPref, bfCacheDepth]] },
                                     sendToGenerator);
           yield undefined;
 
           // Navigate when the bfcache is enabled.
-          let frame = document.getElementById("frame");
+          frame = document.getElementById("frame");
           frame.onload = sendToGenerator;
 
           info("Navigating to about:blank");
           frame.src = "about:blank";
           frame.contentWindow.document.body.offsetTop;
 
           yield undefined;
 
@@ -131,17 +131,17 @@
           frame.src = frameRelativeURL;
           frame.contentWindow.document.body.offsetTop;
 
           yield undefined;
 
           frame = frame.contentWindow;
           frame.postMessage({ command: "retrieve" }, "*");
 
-          let event = yield undefined;
+          event = yield undefined;
           ok(event instanceof MessageEvent, "Got a MessageEvent");
           is(event.source, frame, "Correct window got the event");
           is(event.data.type, "result", "Got a result message");
           is(event.data.data, storedData, "Still have data stored");
 
           info("Resetting '" + bfCacheEnabledPref + "' pref");
           SpecialPowers.popPrefEnv(sendToGenerator);
           yield undefined;
--- a/dom/xbl/test/test_bug591198.html
+++ b/dom/xbl/test/test_bug591198.html
@@ -26,17 +26,17 @@ function runTest() {
   
   iframe.src = "file_bug591198_inner.html";
   let res = (yield);
   is(res.widths[0], res.widths[2], "binding was rendered");
   isnot(res.widths[0], res.widths[1], "binding was rendered");
   is(res.anonChildCount, 2, "correct number of anon children");
 
   iframe.src = "http://noxul.example.com/tests/dom/xbl/test/file_bug591198_inner.html";
-  let res = (yield);
+  res = (yield);
   is(res.widths[0], res.widths[1], "binding was not rendered");
   isnot(res.widths[0], res.widths[2], "binding was not rendered");
   is("anonChildCount" in res, false, "no anon children");
 
   SimpleTest.finish();
   yield undefined;
 }
 
--- a/extensions/cookie/test/unit/test_cookies_async_failure.js
+++ b/extensions/cookie/test/unit/test_cookies_async_failure.js
@@ -347,17 +347,17 @@ function run_test_3(generator)
   new _observer(sub_generator, "cookie-db-rebuilding");
   yield;
   do_execute_soon(function() { do_run_generator(sub_generator); });
   yield;
 
   // Close the profile.
   do_close_profile(sub_generator);
   yield;
-  let db = Services.storage.openDatabase(do_get_cookie_file(profile));
+  db = Services.storage.openDatabase(do_get_cookie_file(profile));
   do_check_eq(do_count_cookies_in_db(db), 0);
   db.close();
 
   // Check that the original database was renamed.
   do_check_true(do_get_backup_file(profile).exists());
   do_check_eq(do_get_backup_file(profile).fileSize, size);
 
   // Clean up.
--- a/extensions/cookie/test/unit/test_domain_eviction.js
+++ b/extensions/cookie/test/unit/test_domain_eviction.js
@@ -72,17 +72,17 @@ function do_run_test()
   do_timeout(2100, continue_test);
   yield;
 
   do_check_eq(countCookies("captchart.com", "captchart.com"), 50);
   Services.cookiemgr.add("captchart.com", "", "test200", "eviction",
     false, false, false, futureExpiry);
   do_check_eq(countCookies("captchart.com", "captchart.com"), 50);
 
-  let enumerator = Services.cookiemgr.getCookiesFromHost("captchart.com");
+  enumerator = Services.cookiemgr.getCookiesFromHost("captchart.com");
   while (enumerator.hasMoreElements()) {
     let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
     do_check_true(cookie.expiry == futureExpiry);
   }
 
   do_finish_generator_test(test_generator);
 }
 
--- a/extensions/cookie/test/unit/test_schema_2_migration.js
+++ b/extensions/cookie/test/unit/test_schema_2_migration.js
@@ -110,17 +110,17 @@ function do_run_test() {
                             futureExpiry, now, now + i, false, false, false);
 
     schema2db.insertCookie(cookie);
   }
 
   // Attempt to add a cookie with the same (name, host, path) values as another
   // cookie. This should succeed since we have a REPLACE clause for conflict on
   // the unique index.
-  let cookie = new Cookie("oh", "hai", "baz.com", "/",
+  cookie = new Cookie("oh", "hai", "baz.com", "/",
                           futureExpiry, now, now + 100, false, false, false);
 
   schema2db.insertCookie(cookie);
 
   // Check that there is, indeed, a singular cookie for baz.com.
   do_check_eq(do_count_cookies_in_db(schema2db.db, "baz.com"), 1);
 
   // Close it.
--- a/extensions/cookie/test/unit/test_schema_3_migration.js
+++ b/extensions/cookie/test/unit/test_schema_3_migration.js
@@ -111,15 +111,15 @@ function do_run_test() {
   schema3db = null;
 
   // Load the database. The cookies added immediately prior will have a NULL
   // creationTime column.
   do_load_profile();
 
   // Test the expected set of cookies.
   do_check_eq(Services.cookiemgr.countCookiesFromHost("cat.com"), 20);
-  let enumerator = Services.cookiemgr.getCookiesFromHost("cat.com");
-  let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
+  enumerator = Services.cookiemgr.getCookiesFromHost("cat.com");
+  cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
   do_check_eq(cookie.creationTime, 0);
 
   finish_test();
 }
 
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -523,30 +523,26 @@ public:
     // AdjustDisplacement() zeroes out the Axis velocity if we're in overscroll.
     // Since we need to hand off the velocity to the tree manager in such a case,
     // we save it here. Would be ScreenVector instead of ScreenPoint if we had
     // vector classes.
     ScreenPoint velocity(mApzc.mX.GetVelocity(), mApzc.mY.GetVelocity());
 
     ScreenPoint offset = velocity * aDelta.ToMilliseconds();
 
-    // Inversely scale the offset by the resolution (when you're zoomed further in,
-    // the same swipe should move you a shorter distance).
-    CSSPoint cssOffset = offset / aFrameMetrics.GetZoom();
-
     // Ordinarily we might need to do a ScheduleComposite if either of
     // the following AdjustDisplacement calls returns true, but this
     // is already running as part of a FlingAnimation, so we'll be compositing
     // per frame of animation anyway.
-    CSSPoint overscroll;
-    CSSPoint adjustedOffset;
-    mApzc.mX.AdjustDisplacement(cssOffset.x, adjustedOffset.x, overscroll.x);
-    mApzc.mY.AdjustDisplacement(cssOffset.y, adjustedOffset.y, overscroll.y);
-
-    aFrameMetrics.ScrollBy(adjustedOffset);
+    ScreenPoint overscroll;
+    ScreenPoint adjustedOffset;
+    mApzc.mX.AdjustDisplacement(offset.x, adjustedOffset.x, overscroll.x);
+    mApzc.mY.AdjustDisplacement(offset.y, adjustedOffset.y, overscroll.y);
+
+    aFrameMetrics.ScrollBy(adjustedOffset / aFrameMetrics.GetZoom());
 
     // The fling may have caused us to reach the end of our scroll range.
     if (!IsZero(overscroll)) {
       if (mAllowOverscroll) {
         // If this is a fling that allows overscroll, then go into overscroll.
 
         mApzc.OverscrollBy(overscroll);
 
@@ -745,28 +741,27 @@ public:
     } else {
       mApzc.mX.SetVelocity(velocity.x);
     }
     if (mYAxisModel.IsFinished()) {
       mApzc.mY.SetVelocity(0);
     } else {
       mApzc.mY.SetVelocity(velocity.y);
     }
-
     // If we overscroll, hand off to a fling animation that will complete the
     // spring back.
-    float displacement_x = position.x - mApzc.mX.GetOrigin();
-    float displacement_y = position.y - mApzc.mY.GetOrigin();
-
-    CSSPoint overscroll;
-    CSSPoint adjustedOffset;
-    mApzc.mX.AdjustDisplacement(displacement_x, adjustedOffset.x, overscroll.x);
-    mApzc.mY.AdjustDisplacement(displacement_y, adjustedOffset.y, overscroll.y);
-
-    aFrameMetrics.ScrollBy(adjustedOffset);
+    CSSToScreenScale zoom = aFrameMetrics.GetZoom();
+    ScreenPoint displacement = (position - aFrameMetrics.GetScrollOffset()) * zoom;
+
+    ScreenPoint overscroll;
+    ScreenPoint adjustedOffset;
+    mApzc.mX.AdjustDisplacement(displacement.x, adjustedOffset.x, overscroll.x);
+    mApzc.mY.AdjustDisplacement(displacement.y, adjustedOffset.y, overscroll.y);
+
+    aFrameMetrics.ScrollBy(adjustedOffset / zoom);
 
     // The smooth scroll may have caused us to reach the end of our scroll range.
     // This can happen if either the layout.css.scroll-behavior.damping-ratio
     // preference is set to less than 1 (underdamped) or if a smooth scroll
     // inherits velocity from a fling gesture.
     if (!IsZero(overscroll)) {
 
       // Hand off a fling with the remaining momentum to the next APZC in the
@@ -1389,27 +1384,23 @@ nsEventStatus AsyncPanZoomController::On
 
   float spanRatio = aEvent.mCurrentSpan / aEvent.mPreviousSpan;
 
   {
     ReentrantMonitorAutoEnter lock(mMonitor);
 
     CSSToParentLayerScale userZoom = mFrameMetrics.GetZoomToParent();
     ParentLayerPoint focusPoint = ToParentLayerCoords(aEvent.mFocusPoint) - mFrameMetrics.mCompositionBounds.TopLeft();
-    CSSPoint cssFocusPoint = focusPoint / userZoom;
+    CSSPoint cssFocusPoint = focusPoint / mFrameMetrics.GetZoomToParent();
 
     CSSPoint focusChange = (mLastZoomFocus - focusPoint) / userZoom;
     // If displacing by the change in focus point will take us off page bounds,
     // then reduce the displacement such that it doesn't.
-    if (mX.DisplacementWillOverscroll(focusChange.x) != Axis::OVERSCROLL_NONE) {
-      focusChange.x -= mX.DisplacementWillOverscrollAmount(focusChange.x);
-    }
-    if (mY.DisplacementWillOverscroll(focusChange.y) != Axis::OVERSCROLL_NONE) {
-      focusChange.y -= mY.DisplacementWillOverscrollAmount(focusChange.y);
-    }
+    focusChange.x -= mX.DisplacementWillOverscrollAmount(focusChange.x);
+    focusChange.y -= mY.DisplacementWillOverscrollAmount(focusChange.y);
     ScrollBy(focusChange);
 
     // When we zoom in with focus, we can zoom too much towards the boundaries
     // that we actually go over them. These are the needed displacements along
     // either axis such that we don't overscroll the boundaries when zooming.
     CSSPoint neededDisplacement;
 
     CSSToParentLayerScale realMinZoom = mZoomConstraints.mMinZoom * mFrameMetrics.mTransformScale;
@@ -1922,37 +1913,28 @@ bool AsyncPanZoomController::AttemptScro
                                            uint32_t aOverscrollHandoffChainIndex) {
 
   // "start - end" rather than "end - start" because e.g. moving your finger
   // down (*positive* direction along y axis) causes the vertical scroll offset
   // to *decrease* as the page follows your finger.
   ScreenPoint displacement = aStartPoint - aEndPoint;
 
   ScreenPoint overscroll;  // will be used outside monitor block
-  CSSPoint cssOverscroll;  // ditto
   {
     ReentrantMonitorAutoEnter lock(mMonitor);
 
-    CSSToScreenScale zoom = mFrameMetrics.GetZoom();
-
-    // Inversely scale the offset by the resolution (when you're zoomed further in,
-    // the same swipe should move you a shorter distance).
-    CSSPoint cssDisplacement = displacement / zoom;
-
-    CSSPoint adjustedDisplacement;
-    bool xChanged = mX.AdjustDisplacement(cssDisplacement.x, adjustedDisplacement.x, cssOverscroll.x);
-    bool yChanged = mY.AdjustDisplacement(cssDisplacement.y, adjustedDisplacement.y, cssOverscroll.y);
+    ScreenPoint adjustedDisplacement;
+    bool xChanged = mX.AdjustDisplacement(displacement.x, adjustedDisplacement.x, overscroll.x);
+    bool yChanged = mY.AdjustDisplacement(displacement.y, adjustedDisplacement.y, overscroll.y);
     if (xChanged || yChanged) {
       ScheduleComposite();
     }
 
-    overscroll = cssOverscroll * zoom;
-
     if (!IsZero(adjustedDisplacement)) {
-      ScrollBy(adjustedDisplacement);
+      ScrollBy(adjustedDisplacement / mFrameMetrics.GetZoom());
       ScheduleCompositeAndMaybeRepaint();
       UpdateSharedCompositorFrameMetrics();
     }
   }
 
   // If we consumed the entire displacement as a normal scroll, great.
   if (IsZero(overscroll)) {
     return true;
@@ -1967,20 +1949,20 @@ bool AsyncPanZoomController::AttemptScro
                          aOverscrollHandoffChain, aOverscrollHandoffChainIndex + 1)) {
     return true;
   }
 
   // If there is no APZC later in the handoff chain that accepted the
   // overscroll, try to accept it ourselves. We only accept it if we
   // are pannable.
   APZC_LOG("%p taking overscroll during panning\n", this);
-  return OverscrollBy(cssOverscroll);
+  return OverscrollBy(overscroll);
 }
 
-bool AsyncPanZoomController::OverscrollBy(const CSSPoint& aOverscroll) {
+bool AsyncPanZoomController::OverscrollBy(const ScreenPoint& aOverscroll) {
   if (!gfxPrefs::APZOverscrollEnabled()) {
     return false;
   }
 
   ReentrantMonitorAutoEnter lock(mMonitor);
   // Do not go into overscroll in a direction in which we have no room to
   // scroll to begin with.
   bool xCanScroll = mX.CanScroll();
@@ -2433,43 +2415,42 @@ void AsyncPanZoomController::GetOverscro
   // scrollable area pinned into place.
 
   // The kStretchFactor parameter determines how much overscroll can stretch the
   // content.
   const float kStretchFactor = gfxPrefs::APZOverscrollStretchFactor();
 
   // Compute the amount of the stretch along each axis. The stretch is
   // proportional to the amount by which we are overscrolled along that axis.
-  CSSSize compositionSize(mX.GetCompositionLength(), mY.GetCompositionLength());
+  ScreenSize compositionSize(mX.GetCompositionLength(), mY.GetCompositionLength());
   float scaleX = 1 + kStretchFactor * fabsf(mX.GetOverscroll()) / mX.GetCompositionLength();
   float scaleY = 1 + kStretchFactor * fabsf(mY.GetOverscroll()) / mY.GetCompositionLength();
 
   // The scale is applied relative to the origin of the composition bounds, i.e.
   // it keeps the top-left corner of the content in place. This is fine if we
   // are overscrolling at the top or on the left, but if we are overscrolling
   // at the bottom or on the right, we want the bottom or right edge of the
   // content to stay in place instead, so we add a translation to compensate.
-  CSSPoint translation;
+  ScreenPoint translation;
   if (mX.IsOverscrolled() && mX.GetOverscroll() > 0) {
     // Overscrolled on the right.
-    CSSCoord overscrolledCompositionWidth = scaleX * compositionSize.width;
-    CSSCoord extraCompositionWidth = overscrolledCompositionWidth - compositionSize.width;
+    ScreenCoord overscrolledCompositionWidth = scaleX * compositionSize.width;
+    ScreenCoord extraCompositionWidth = overscrolledCompositionWidth - compositionSize.width;
     translation.x = -extraCompositionWidth;
   }
   if (mY.IsOverscrolled() && mY.GetOverscroll() > 0) {
     // Overscrolled at the bottomn.
-    CSSCoord overscrolledCompositionHeight = scaleY * compositionSize.height;
-    CSSCoord extraCompositionHeight = overscrolledCompositionHeight - compositionSize.height;
+    ScreenCoord overscrolledCompositionHeight = scaleY * compositionSize.height;
+    ScreenCoord extraCompositionHeight = overscrolledCompositionHeight - compositionSize.height;
     translation.y = -extraCompositionHeight;
   }
 
   // Combine the transformations into a matrix.
-  ScreenPoint screenTranslation = translation * mFrameMetrics.GetZoom();
   *aTransform = Matrix4x4().Scale(scaleX, scaleY, 1)
-                           .PostTranslate(screenTranslation.x, screenTranslation.y, 0);
+                           .PostTranslate(translation.x, translation.y, 0);
 }
 
 bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
 {
   AssertOnCompositorThread();
 
   // Don't send any state-change notifications until the end of the function,
   // because we may go through some intermediate states while we finish
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -1017,17 +1017,17 @@ private:
                           uint32_t aOverscrollHandoffChainIndex);
 
   /**
    * Try to overscroll by 'aOverscroll'.
    * If we are pannable, 'aOverscroll' is added to any existing overscroll,
    * and the function returns true.
    * Otherwise, nothing happens and the function return false.
    */
-  bool OverscrollBy(const CSSPoint& aOverscroll);
+  bool OverscrollBy(const ScreenPoint& aOverscroll);
 
   /**
    * Build the chain of APZCs along which scroll will be handed off when
    * this APZC receives input events.
    *
    * Notes on lifetime and const-correctness:
    *   - The returned handoff chain is |const|, to indicate that it cannot be
    *     changed after being built.
--- a/gfx/layers/apz/src/Axis.cpp
+++ b/gfx/layers/apz/src/Axis.cpp
@@ -67,63 +67,63 @@ void Axis::UpdateWithTouchAtDevicePoint(
 
 void Axis::StartTouch(ScreenCoord aPos, uint32_t aTimestampMs) {
   mStartPos = aPos;
   mPos = aPos;
   mPosTimeMs = aTimestampMs;
   mAxisLocked = false;
 }
 
-bool Axis::AdjustDisplacement(CSSCoord aDisplacement,
-                              /* CSSCoord */ float& aDisplacementOut,
-                              /* CSSCoord */ float& aOverscrollAmountOut)
+bool Axis::AdjustDisplacement(ScreenCoord aDisplacement,
+                              /* ScreenCoord */ float& aDisplacementOut,
+                              /* ScreenCoord */ float& aOverscrollAmountOut)
 {
   if (mAxisLocked) {
     aOverscrollAmountOut = 0;
     aDisplacementOut = 0;
     return false;
   }
 
-  CSSCoord displacement = aDisplacement;
+  ScreenCoord displacement = aDisplacement;
 
   // First consume any overscroll in the opposite direction along this axis.
-  CSSCoord consumedOverscroll = 0;
+  ScreenCoord consumedOverscroll = 0;
   if (mOverscroll > 0 && aDisplacement < 0) {
     consumedOverscroll = std::min(mOverscroll, -aDisplacement);
   } else if (mOverscroll < 0 && aDisplacement > 0) {
     consumedOverscroll = 0.f - std::min(-mOverscroll, aDisplacement);
   }
   mOverscroll -= consumedOverscroll;
   displacement += consumedOverscroll;
 
   // Split the requested displacement into an allowed displacement that does
   // not overscroll, and an overscroll amount.
-  if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) {
+  aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement);
+  if (aOverscrollAmountOut != 0.0f) {
     // No need to have a velocity along this axis anymore; it won't take us
     // anywhere, so we're just spinning needlessly.
     mVelocity = 0.0f;
-    aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement);
     displacement -= aOverscrollAmountOut;
   }
   aDisplacementOut = displacement;
   return fabsf(consumedOverscroll) > EPSILON;
 }
 
-CSSCoord Axis::ApplyResistance(CSSCoord aRequestedOverscroll) const {
+ScreenCoord Axis::ApplyResistance(ScreenCoord aRequestedOverscroll) const {
   // 'resistanceFactor' is a value between 0 and 1, which:
   //   - tends to 1 as the existing overscroll tends to 0
   //   - tends to 0 as the existing overscroll tends to the composition length
   // The actual overscroll is the requested overscroll multiplied by this
   // factor; this should prevent overscrolling by more than the composition
   // length.
   float resistanceFactor = 1 - fabsf(mOverscroll) / GetCompositionLength();
-  return resistanceFactor < 0 ? CSSCoord(0) : aRequestedOverscroll * resistanceFactor;
+  return resistanceFactor < 0 ? ScreenCoord(0) : aRequestedOverscroll * resistanceFactor;
 }
 
-void Axis::OverscrollBy(CSSCoord aOverscroll) {
+void Axis::OverscrollBy(ScreenCoord aOverscroll) {
   MOZ_ASSERT(CanScroll());
   aOverscroll = ApplyResistance(aOverscroll);
   if (aOverscroll > 0) {
 #ifdef DEBUG
     if (!FuzzyEqualsAdditive(GetCompositionEnd().value, GetPageEnd().value, COORDINATE_EPSILON)) {
       nsPrintfCString message("composition end (%f) is not within COORDINATE_EPISLON of page end (%f)\n",
                               GetCompositionEnd().value, GetPageEnd().value);
       NS_ASSERTION(false, message.get());
@@ -140,17 +140,17 @@ void Axis::OverscrollBy(CSSCoord aOversc
       MOZ_CRASH();
     }
 #endif
     MOZ_ASSERT(mOverscroll <= 0);
   }
   mOverscroll += aOverscroll;
 }
 
-CSSCoord Axis::GetOverscroll() const {
+ScreenCoord Axis::GetOverscroll() const {
   return mOverscroll;
 }
 
 bool Axis::SampleSnapBack(const TimeDuration& aDelta) {
   // Apply spring physics to the snap-back as time goes on.
   // Note: this method of sampling isn't perfectly smooth, as it assumes
   // a constant velocity over 'aDelta', instead of an accelerating velocity.
   // (The way we applying friction to flings has the same issue.)
@@ -165,36 +165,35 @@ bool Axis::SampleSnapBack(const TimeDura
   //   v is the velocity of the point at the end of the spring
   // See http://gafferongames.com/game-physics/spring-physics/
   const float kSpringStiffness = gfxPrefs::APZOverscrollSnapBackSpringStiffness();
   const float kSpringFriction = gfxPrefs::APZOverscrollSnapBackSpringFriction();
   const float kMass = gfxPrefs::APZOverscrollSnapBackMass();
   float force = -1 * kSpringStiffness * mOverscroll - kSpringFriction * mVelocity;
   float acceleration = force / kMass;
   mVelocity += acceleration * aDelta.ToMilliseconds();
-  float screenDisplacement = mVelocity * aDelta.ToMilliseconds();
-  float cssDisplacement = screenDisplacement / GetFrameMetrics().GetZoom().scale;
+  float displacement = mVelocity * aDelta.ToMilliseconds();
   if (mOverscroll > 0) {
-    if (cssDisplacement > 0) {
+    if (displacement > 0) {
       NS_WARNING("Overscroll snap-back animation is moving in the wrong direction!");
       return false;
     }
-    mOverscroll = std::max(mOverscroll + cssDisplacement, 0.0f);
+    mOverscroll = std::max(mOverscroll + displacement, 0.0f);
     // Overscroll relieved, do not continue animation.
     if (mOverscroll == 0.f) {
       mVelocity = 0;
       return false;
     }
     return true;
   } else if (mOverscroll < 0) {
-    if (cssDisplacement < 0) {
+    if (displacement < 0) {
       NS_WARNING("Overscroll snap-back animation is moving in the wrong direction!");
       return false;
     }
-    mOverscroll = std::min(mOverscroll + cssDisplacement, 0.0f);
+    mOverscroll = std::min(mOverscroll + displacement, 0.0f);
     // Overscroll relieved, do not continue animation.
     if (mOverscroll == 0.f) {
       mVelocity = 0;
       return false;
     }
     return true;
   }
   // No overscroll on this axis, do not continue animation.
@@ -268,158 +267,156 @@ bool Axis::FlingApplyFrictionOrCancel(co
     mVelocity = 0.0f;
     return false;
   } else {
     mVelocity *= pow(1.0f - aFriction, float(aDelta.ToMilliseconds()));
   }
   return true;
 }
 
-Axis::Overscroll Axis::DisplacementWillOverscroll(CSSCoord aDisplacement) {
+ScreenCoord Axis::DisplacementWillOverscrollAmount(ScreenCoord aDisplacement) const {
+  ScreenCoord newOrigin = GetOrigin() + aDisplacement;
+  ScreenCoord newCompositionEnd = GetCompositionEnd() + aDisplacement;
   // If the current pan plus a displacement takes the window to the left of or
   // above the current page rect.
-  bool minus = GetOrigin() + aDisplacement < GetPageStart();
+  bool minus = newOrigin < GetPageStart();
   // If the current pan plus a displacement takes the window to the right of or
   // below the current page rect.
-  bool plus = GetCompositionEnd() + aDisplacement > GetPageEnd();
+  bool plus = newCompositionEnd > GetPageEnd();
   if (minus && plus) {
-    return OVERSCROLL_BOTH;
+    // Don't handle overscrolled in both directions; a displacement can't cause
+    // this, it must have already been zoomed out too far.
+    return 0;
   }
   if (minus) {
-    return OVERSCROLL_MINUS;
+    return newOrigin - GetPageStart();
   }
   if (plus) {
-    return OVERSCROLL_PLUS;
+    return newCompositionEnd - GetPageEnd();
   }
-  return OVERSCROLL_NONE;
+  return 0;
 }
 
-CSSCoord Axis::DisplacementWillOverscrollAmount(CSSCoord aDisplacement) {
-  switch (DisplacementWillOverscroll(aDisplacement)) {
-  case OVERSCROLL_MINUS: return (GetOrigin() + aDisplacement) - GetPageStart();
-  case OVERSCROLL_PLUS: return (GetCompositionEnd() + aDisplacement) - GetPageEnd();
-  // Don't handle overscrolled in both directions; a displacement can't cause
-  // this, it must have already been zoomed out too far.
-  default: return 0;
-  }
-}
-
-CSSCoord Axis::ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) {
-  CSSCoord originAfterScale = (GetOrigin() + aFocus) - (aFocus / aScale);
+CSSCoord Axis::ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) const {
+  // Internally, do computations in Screen coordinates *before* the scale is
+  // applied.
+  CSSToScreenScale zoom = GetFrameMetrics().GetZoom();
+  ScreenCoord focus = aFocus * zoom;
+  ScreenCoord originAfterScale = (GetOrigin() + focus) - (focus / aScale);
 
   bool both = ScaleWillOverscrollBothSides(aScale);
   bool minus = GetPageStart() - originAfterScale > COORDINATE_EPSILON;
   bool plus = (originAfterScale + (GetCompositionLength() / aScale)) - GetPageEnd() > COORDINATE_EPSILON;
 
   if ((minus && plus) || both) {
     // If we ever reach here it's a bug in the client code.
     MOZ_ASSERT(false, "In an OVERSCROLL_BOTH condition in ScaleWillOverscrollAmount");
     return 0;
   }
   if (minus) {
-    return originAfterScale - GetPageStart();
+    return (originAfterScale - GetPageStart()) / zoom;
   }
   if (plus) {
-    return originAfterScale + (GetCompositionLength() / aScale) - GetPageEnd();
+    return (originAfterScale + (GetCompositionLength() / aScale) - GetPageEnd()) / zoom;
   }
   return 0;
 }
 
 float Axis::GetVelocity() {
   return mAxisLocked ? 0 : mVelocity;
 }
 
 void Axis::SetVelocity(float aVelocity) {
   mVelocity = aVelocity;
 }
 
-CSSCoord Axis::GetCompositionEnd() const {
+ScreenCoord Axis::GetCompositionEnd() const {
   return GetOrigin() + GetCompositionLength();
 }
 
-CSSCoord Axis::GetPageEnd() const {
+ScreenCoord Axis::GetPageEnd() const {
   return GetPageStart() + GetPageLength();
 }
 
-CSSCoord Axis::GetOrigin() const {
-  CSSPoint origin = GetFrameMetrics().GetScrollOffset();
+ScreenCoord Axis::GetOrigin() const {
+  ScreenPoint origin = GetFrameMetrics().GetScrollOffset() * GetFrameMetrics().GetZoom();
   return GetPointOffset(origin);
 }
 
-CSSCoord Axis::GetCompositionLength() const {
-  return GetRectLength(GetFrameMetrics().CalculateCompositedRectInCssPixels());
+ScreenCoord Axis::GetCompositionLength() const {
+  return GetRectLength(GetFrameMetrics().mCompositionBounds / GetFrameMetrics().mTransformScale);
 }
 
-CSSCoord Axis::GetPageStart() const {
-  CSSRect pageRect = GetFrameMetrics().GetExpandedScrollableRect();
+ScreenCoord Axis::GetPageStart() const {
+  ScreenRect pageRect = GetFrameMetrics().GetExpandedScrollableRect() * GetFrameMetrics().GetZoom();
   return GetRectOffset(pageRect);
 }
 
-CSSCoord Axis::GetPageLength() const {
-  CSSRect pageRect = GetFrameMetrics().GetExpandedScrollableRect();
+ScreenCoord Axis::GetPageLength() const {
+  ScreenRect pageRect = GetFrameMetrics().GetExpandedScrollableRect() * GetFrameMetrics().GetZoom();
   return GetRectLength(pageRect);
 }
 
-bool Axis::ScaleWillOverscrollBothSides(float aScale) {
+bool Axis::ScaleWillOverscrollBothSides(float aScale) const {
   const FrameMetrics& metrics = GetFrameMetrics();
 
-  CSSToParentLayerScale scale(metrics.GetZoomToParent().scale * aScale);
-  CSSRect cssCompositionBounds = metrics.mCompositionBounds / scale;
+  ScreenToParentLayerScale scale(metrics.mTransformScale.scale * aScale);
+  ScreenRect screenCompositionBounds = metrics.mCompositionBounds / scale;
 
-  return GetRectLength(cssCompositionBounds) - GetRectLength(metrics.GetExpandedScrollableRect()) > COORDINATE_EPSILON;
+  return GetRectLength(screenCompositionBounds) - GetPageLength() > COORDINATE_EPSILON;
 }
 
 const FrameMetrics& Axis::GetFrameMetrics() const {
   return mAsyncPanZoomController->GetFrameMetrics();
 }
 
 
 AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController)
   : Axis(aAsyncPanZoomController)
 {
 
 }
 
-CSSCoord AxisX::GetPointOffset(const CSSPoint& aPoint) const
+ScreenCoord AxisX::GetPointOffset(const ScreenPoint& aPoint) const
 {
   return aPoint.x;
 }
 
-CSSCoord AxisX::GetRectLength(const CSSRect& aRect) const
+ScreenCoord AxisX::GetRectLength(const ScreenRect& aRect) const
 {
   return aRect.width;
 }
 
-CSSCoord AxisX::GetRectOffset(const CSSRect& aRect) const
+ScreenCoord AxisX::GetRectOffset(const ScreenRect& aRect) const
 {
   return aRect.x;
 }
 
 ScreenPoint AxisX::MakePoint(ScreenCoord aCoord) const
 {
   return ScreenPoint(aCoord, 0);
 }
 
 AxisY::AxisY(AsyncPanZoomController* aAsyncPanZoomController)
   : Axis(aAsyncPanZoomController)
 {
 
 }
 
-CSSCoord AxisY::GetPointOffset(const CSSPoint& aPoint) const
+ScreenCoord AxisY::GetPointOffset(const ScreenPoint& aPoint) const
 {
   return aPoint.y;
 }
 
-CSSCoord AxisY::GetRectLength(const CSSRect& aRect) const
+ScreenCoord AxisY::GetRectLength(const ScreenRect& aRect) const
 {
   return aRect.height;
 }
 
-CSSCoord AxisY::GetRectOffset(const CSSRect& aRect) const
+ScreenCoord AxisY::GetRectOffset(const ScreenRect& aRect) const
 {
   return aRect.y;
 }
 
 ScreenPoint AxisY::MakePoint(ScreenCoord aCoord) const
 {
   return ScreenPoint(0, aCoord);
 }
--- a/gfx/layers/apz/src/Axis.h
+++ b/gfx/layers/apz/src/Axis.h
@@ -3,17 +3,17 @@
 /* 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/. */
 
 #ifndef mozilla_layers_Axis_h
 #define mozilla_layers_Axis_h
 
 #include <sys/types.h>                  // for int32_t
-#include "Units.h"                      // for CSSRect, CSSPoint
+#include "Units.h"
 #include "mozilla/TimeStamp.h"          // for TimeDuration
 #include "nsTArray.h"                   // for nsTArray
 
 namespace mozilla {
 namespace layers {
 
 const float EPSILON = 0.0001f;
 
@@ -32,30 +32,16 @@ class AsyncPanZoomController;
  * Helper class to maintain each axis of movement (X,Y) for panning and zooming.
  * Note that everything here is specific to one axis; that is, the X axis knows
  * nothing about the Y axis and vice versa.
  */
 class Axis {
 public:
   explicit Axis(AsyncPanZoomController* aAsyncPanZoomController);
 
-  enum Overscroll {
-    // Overscroll is not happening at all.
-    OVERSCROLL_NONE = 0,
-    // Overscroll is happening in the negative direction. This means either to
-    // the left or to the top depending on the axis.
-    OVERSCROLL_MINUS,
-    // Overscroll is happening in the positive direction. This means either to
-    // the right or to the bottom depending on the axis.
-    OVERSCROLL_PLUS,
-    // Overscroll is happening both ways. This only means something when the
-    // page is scaled out to a smaller size than the viewport.
-    OVERSCROLL_BOTH
-  };
-
   /**
    * Notify this Axis that a new touch has been received, including a timestamp
    * for when the touch was received. This triggers a recalculation of velocity.
    */
   void UpdateWithTouchAtDevicePoint(ScreenCoord aPos, uint32_t aTimestampMs);
 
   /**
    * Notify this Axis that a touch has begun, i.e. the user has put their finger
@@ -82,30 +68,30 @@ public:
    * to account for overscroll (which might decrease the displacement; this is
    * to prevent the viewport from overscrolling the page rect), and axis locking
    * (which might prevent any displacement from happening). If overscroll
    * ocurred, its amount is written to |aOverscrollAmountOut|.
    * The |aDisplacementOut| parameter is set to the adjusted
    * displacement, and the function returns true iff internal overscroll amounts
    * were changed.
    */
-  bool AdjustDisplacement(CSSCoord aDisplacement,
-                          /* CSSCoord */ float& aDisplacementOut,
-                          /* CSSCoord */ float& aOverscrollAmountOut);
+  bool AdjustDisplacement(ScreenCoord aDisplacement,
+                          /* ScreenCoord */ float& aDisplacementOut,
+                          /* ScreenCoord */ float& aOverscrollAmountOut);
 
   /**
    * Overscrolls this axis by the requested amount in the requested direction.
    * The axis must be at the end of its scroll range in this direction.
    */
-  void OverscrollBy(CSSCoord aOverscroll);
+  void OverscrollBy(ScreenCoord aOverscroll);
 
   /**
-   * Return the amount of overscroll on this axis, in CSS pixels.
+   * Return the amount of overscroll on this axis, in Screen pixels.
    */
-  CSSCoord GetOverscroll() const;
+  ScreenCoord GetOverscroll() const;
 
   /**
    * Sample the snap-back animation to relieve overscroll.
    * |aDelta| is the time since the last sample.
    */
   bool SampleSnapBack(const TimeDuration& aDelta);
 
   /**
@@ -173,103 +159,100 @@ public:
    * another APZC, in which case there are no touch points available to call
    * UpdateWithTouchAtDevicePoint. In other circumstances,
    * UpdateWithTouchAtDevicePoint should be used and the velocity calculated
    * there.
    */
   void SetVelocity(float aVelocity);
 
   /**
-   * Gets the overscroll state of the axis given an additional displacement.
-   * That is to say, if the given displacement is applied, this will tell you
-   * whether or not it will overscroll, and in what direction.
+   * If a displacement will overscroll the axis, this returns the amount and in
+   * what direction.
    */
-  Overscroll DisplacementWillOverscroll(CSSCoord aDisplacement);
-
-  /**
-   * If a displacement will overscroll the axis, this returns the amount and in
-   * what direction. Similar to GetExcess() but takes a displacement to apply.
-   */
-  CSSCoord DisplacementWillOverscrollAmount(CSSCoord aDisplacement);
+  ScreenCoord DisplacementWillOverscrollAmount(ScreenCoord aDisplacement) const;
 
   /**
    * If a scale will overscroll the axis, this returns the amount and in what
-   * direction. Similar to GetExcess() but takes a displacement to apply.
+   * direction.
    *
    * |aFocus| is the point at which the scale is focused at. We will offset the
    * scroll offset in such a way that it remains in the same place on the page
    * relative.
+   *
+   * Note: Unlike most other functions in Axis, this functions operates in
+   *       CSS coordinates so there is no confusion as to whether the Screen
+   *       coordinates it operates in are before or after the scale is applied.
    */
-  CSSCoord ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus);
+  CSSCoord ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) const;
 
   /**
    * Checks if an axis will overscroll in both directions by computing the
    * content rect and checking that its height/width (depending on the axis)
    * does not overextend past the viewport.
    *
    * This gets called by ScaleWillOverscroll().
    */
-  bool ScaleWillOverscrollBothSides(float aScale);
+  bool ScaleWillOverscrollBothSides(float aScale) const;
 
-  CSSCoord GetOrigin() const;
-  CSSCoord GetCompositionLength() const;
-  CSSCoord GetPageStart() const;
-  CSSCoord GetPageLength() const;
-  CSSCoord GetCompositionEnd() const;
-  CSSCoord GetPageEnd() const;
+  ScreenCoord GetOrigin() const;
+  ScreenCoord GetCompositionLength() const;
+  ScreenCoord GetPageStart() const;
+  ScreenCoord GetPageLength() const;
+  ScreenCoord GetCompositionEnd() const;
+  ScreenCoord GetPageEnd() const;
 
   ScreenCoord GetPos() const { return mPos; }
 
-  virtual CSSCoord GetPointOffset(const CSSPoint& aPoint) const = 0;
-  virtual CSSCoord GetRectLength(const CSSRect& aRect) const = 0;
-  virtual CSSCoord GetRectOffset(const CSSRect& aRect) const = 0;
+  virtual ScreenCoord GetPointOffset(const ScreenPoint& aPoint) const = 0;
+  virtual ScreenCoord GetRectLength(const ScreenRect& aRect) const = 0;
+  virtual ScreenCoord GetRectOffset(const ScreenRect& aRect) const = 0;
 
   virtual ScreenPoint MakePoint(ScreenCoord aCoord) const = 0;
 
 protected:
   ScreenCoord mPos;
   uint32_t mPosTimeMs;
   ScreenCoord mStartPos;
-  float mVelocity;
+  float mVelocity;      // Units: ScreenCoords per millisecond
   bool mAxisLocked;     // Whether movement on this axis is locked.
   AsyncPanZoomController* mAsyncPanZoomController;
-  // The amount by which this axis is in overscroll, in CSS coordinates.
+  // The amount by which this axis is in overscroll, in Screen coordinates.
   // If this amount is nonzero, the relevant component of
   // mAsyncPanZoomController->mFrameMetrics.mScrollOffset must be at its
   // extreme allowed value in the relevant direction (that is, it must be at
   // its maximum value if mOverscroll is positive, and at its minimum value
   // if mOverscroll is negative).
-  CSSCoord mOverscroll;
+  ScreenCoord mOverscroll;
   // A queue of (timestamp, velocity) pairs; these are the historical
   // velocities at the given timestamps. Timestamps are in milliseconds,
   // velocities are in screen pixels per ms. This member can only be
   // accessed on the controller/UI thread.
   nsTArray<std::pair<uint32_t, float> > mVelocityQueue;
 
   const FrameMetrics& GetFrameMetrics() const;
 
   // Adjust a requested overscroll amount for resistance, yielding a smaller
   // actual overscroll amount.
-  CSSCoord ApplyResistance(CSSCoord aOverscroll) const;
+  ScreenCoord ApplyResistance(ScreenCoord aOverscroll) const;
 };
 
 class AxisX : public Axis {
 public:
   explicit AxisX(AsyncPanZoomController* mAsyncPanZoomController);
-  virtual CSSCoord GetPointOffset(const CSSPoint& aPoint) const;
-  virtual CSSCoord GetRectLength(const CSSRect& aRect) const;
-  virtual CSSCoord GetRectOffset(const CSSRect& aRect) const;
-  virtual ScreenPoint MakePoint(ScreenCoord aCoord) const;
+  virtual ScreenCoord GetPointOffset(const ScreenPoint& aPoint) const MOZ_OVERRIDE;
+  virtual ScreenCoord GetRectLength(const ScreenRect& aRect) const MOZ_OVERRIDE;
+  virtual ScreenCoord GetRectOffset(const ScreenRect& aRect) const MOZ_OVERRIDE;
+  virtual ScreenPoint MakePoint(ScreenCoord aCoord) const MOZ_OVERRIDE;
 };
 
 class AxisY : public Axis {
 public:
   explicit AxisY(AsyncPanZoomController* mAsyncPanZoomController);
-  virtual CSSCoord GetPointOffset(const CSSPoint& aPoint) const;
-  virtual CSSCoord GetRectLength(const CSSRect& aRect) const;
-  virtual CSSCoord GetRectOffset(const CSSRect& aRect) const;
-  virtual ScreenPoint MakePoint(ScreenCoord aCoord) const;
+  virtual ScreenCoord GetPointOffset(const ScreenPoint& aPoint) const MOZ_OVERRIDE;
+  virtual ScreenCoord GetRectLength(const ScreenRect& aRect) const MOZ_OVERRIDE;
+  virtual ScreenCoord GetRectOffset(const ScreenRect& aRect) const MOZ_OVERRIDE;
+  virtual ScreenPoint MakePoint(ScreenCoord aCoord) const MOZ_OVERRIDE;
 };
 
 }
 }
 
 #endif
--- a/image/test/unit/test_moz_icon_uri.js
+++ b/image/test/unit/test_moz_icon_uri.js
@@ -108,17 +108,17 @@ function run_test() {
     uri = ioService.newURI(currentSpec, null, null);
   } catch (e) {
     exception = true;
   }
   do_check_eq(exception, false);
   exception = false; // reset exception value
 
   iconURI = uri.QueryInterface(Ci.nsIMozIconURI);
-  let fileURL = null;
+  fileURL = null;
   try {
     fileURL = iconURI.iconURL.QueryInterface(Ci.nsIFileURL);
   } catch (e) {
     exception = true;
   }
   do_check_eq(exception, false);
   exception = false; // reset exception value
 
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -237,16 +237,18 @@ typedef enum JSWhyMagic
     JS_OPTIMIZED_ARGUMENTS,      /* optimized-away 'arguments' value */
     JS_IS_CONSTRUCTING,          /* magic value passed to natives to indicate construction */
     JS_OVERWRITTEN_CALLEE,       /* arguments.callee has been overwritten */
     JS_BLOCK_NEEDS_CLONE,        /* value of static block object slot */
     JS_HASH_KEY_EMPTY,           /* see class js::HashableValue */
     JS_ION_ERROR,                /* error while running Ion code */
     JS_ION_BAILOUT,              /* missing recover instruction result */
     JS_OPTIMIZED_OUT,            /* optimized out slot */
+    JS_UNINITIALIZED_LEXICAL,    /* uninitialized lexical bindings that produce ReferenceError
+                                  * on touch. */
     JS_GENERIC_MAGIC             /* for local use */
 } JSWhyMagic;
 
 #if defined(IS_LITTLE_ENDIAN)
 # if defined(JS_NUNBOX32)
 typedef union jsval_layout
 {
     uint64_t asBits;
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -286,17 +286,18 @@ frontend::CompileScript(ExclusiveContext
     // We can specialize a bit for the given scope chain if that scope chain is the global object.
     JSObject *globalScope =
         scopeChain && scopeChain == &scopeChain->global() ? (JSObject*) scopeChain : nullptr;
     JS_ASSERT_IF(globalScope, globalScope->isNative());
     JS_ASSERT_IF(globalScope, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalScope->getClass()));
 
     BytecodeEmitter::EmitterMode emitterMode =
         options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
-    BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script, options.forEval,
+    BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script,
+                        /* lazyScript = */ js::NullPtr(), options.forEval,
                         evalCaller, !!globalScope, options.lineno, emitterMode);
     if (!bce.init())
         return nullptr;
 
     // Syntax parsing may cause us to restart processing of top level
     // statements in the script. Use Maybe<> so that the parse context can be
     // reset when this occurs.
     Maybe<ParseContext<FullParseHandler> > pc;
@@ -431,19 +432,21 @@ frontend::CompileScript(ExclusiveContext
     if (Emit1(cx, &bce, JSOP_RETRVAL) < 0)
         return nullptr;
 
     // Global/eval script bindings are always empty (all names are added to the
     // scope dynamically via JSOP_DEFFUN/VAR).  They may have block-scoped
     // locals, however, which are allocated to the fixed part of the stack
     // frame.
     InternalHandle<Bindings*> bindings(script, &script->bindings);
-    if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, nullptr,
-                                            pc->blockScopeDepth))
+    if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, 0,
+                                            pc->blockScopeDepth, nullptr))
+    {
         return nullptr;
+    }
 
     if (!JSScript::fullyInitFromEmitter(cx, script, &bce))
         return nullptr;
 
     // Note that this marking must happen before we tell Debugger
     // about the new script, in case Debugger delazifies the script's
     // inner functions.
     if (options.forEval)
@@ -504,25 +507,23 @@ frontend::CompileLazyFunction(JSContext 
 
     if (lazy->directlyInsideEval())
         script->setDirectlyInsideEval();
     if (lazy->usesArgumentsAndApply())
         script->setUsesArgumentsAndApply();
     if (lazy->hasBeenCloned())
         script->setHasBeenCloned();
 
-    BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, options.forEval,
-                        /* evalCaller = */ NullPtr(), /* hasGlobalScope = */ true,
-                        options.lineno, BytecodeEmitter::LazyFunction);
+    BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, lazy,
+                        options.forEval, /* evalCaller = */ js::NullPtr(),
+                        /* hasGlobalScope = */ true, options.lineno,
+                        BytecodeEmitter::LazyFunction);
     if (!bce.init())
         return false;
 
-    if (lazy->treatAsRunOnce())
-        bce.lazyRunOnceLambda = true;
-
     return EmitFunctionScript(cx, &bce, pn->pn_body);
 }
 
 // Compile a JS function body, which might appear as the value of an event
 // handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
 static bool
 CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyCompileOptions &options,
                     const AutoNameVector &formals, SourceBufferHolder &srcBuf,
@@ -627,17 +628,18 @@ CompileFunctionBody(JSContext *cx, Mutab
         /*
          * The reason for checking fun->environment() below is that certain
          * consumers of JS::CompileFunction, namely
          * EventListenerManager::CompileEventHandlerInternal, passes in a
          * nullptr environment. This compiled function is never used, but
          * instead is cloned immediately onto the right scope chain.
          */
         BytecodeEmitter funbce(/* parent = */ nullptr, &parser, fn->pn_funbox, script,
-                               /* insideEval = */ false, /* evalCaller = */ js::NullPtr(),
+                               /* lazyScript = */ js::NullPtr(), /* insideEval = */ false,
+                               /* evalCaller = */ js::NullPtr(),
                                fun->environment() && fun->environment()->is<GlobalObject>(),
                                options.lineno);
         if (!funbce.init())
             return false;
 
         if (!EmitFunctionScript(cx, &funbce, fn->pn_body))
             return false;
     } else {
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -26,16 +26,17 @@
 #include "jsscript.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "asmjs/AsmJSLink.h"
 #include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 #include "vm/Debugger.h"
+#include "vm/Stack.h"
 
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "frontend/ParseMaps-inl.h"
 #include "frontend/ParseNode-inl.h"
 #include "vm/ScopeObject-inl.h"
@@ -105,21 +106,23 @@ struct LoopStmtInfo : public StmtInfoBCE
         return static_cast<LoopStmtInfo*>(stmt);
     }
 };
 
 } // anonymous namespace
 
 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
                                  Parser<FullParseHandler> *parser, SharedContext *sc,
-                                 HandleScript script, bool insideEval, HandleScript evalCaller,
+                                 HandleScript script, Handle<LazyScript *> lazyScript,
+                                 bool insideEval, HandleScript evalCaller,
                                  bool hasGlobalScope, uint32_t lineNum, EmitterMode emitterMode)
   : sc(sc),
     parent(parent),
     script(sc->context, script),
+    lazyScript(sc->context, lazyScript),
     prolog(sc->context, lineNum),
     main(sc->context, lineNum),
     current(&main),
     parser(parser),
     evalCaller(evalCaller),
     topStmt(nullptr),
     topScopeStmt(nullptr),
     staticScope(sc->context),
@@ -130,22 +133,22 @@ BytecodeEmitter::BytecodeEmitter(Bytecod
     emitLevel(0),
     constList(sc->context),
     tryNoteList(sc->context),
     blockScopeList(sc->context),
     typesetCount(0),
     hasSingletons(false),
     emittingForInit(false),
     emittingRunOnceLambda(false),
-    lazyRunOnceLambda(false),
     insideEval(insideEval),
     hasGlobalScope(hasGlobalScope),
     emitterMode(emitterMode)
 {
     JS_ASSERT_IF(evalCaller, insideEval);
+    JS_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
 }
 
 bool
 BytecodeEmitter::init()
 {
     return atomIndices.ensureMap(sc->context);
 }
 
@@ -218,17 +221,17 @@ frontend::Emit2(ExclusiveContext *cx, By
     code[0] = jsbytecode(op);
     code[1] = op1;
     UpdateDepth(cx, bce, offset);
     return offset;
 }
 
 ptrdiff_t
 frontend::Emit3(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1,
-                    jsbytecode op2)
+                jsbytecode op2)
 {
     /* These should filter through EmitVarOp. */
     JS_ASSERT(!IsArgOp(op));
     JS_ASSERT(!IsLocalOp(op));
 
     ptrdiff_t offset = EmitCheck(cx, bce, 3);
     if (offset < 0)
         return -1;
@@ -794,32 +797,32 @@ EmitInternedObjectOp(ExclusiveContext *c
 
 // In a function, block-scoped locals go after the vars, and form part of the
 // fixed part of a stack frame.  Outside a function, there are no fixed vars,
 // but block-scoped locals still form part of the fixed part of a stack frame
 // and are thus addressable via GETLOCAL and friends.
 static void
 ComputeLocalOffset(ExclusiveContext *cx, BytecodeEmitter *bce, Handle<StaticBlockObject *> blockObj)
 {
-    unsigned nfixedvars = bce->sc->isFunctionBox() ? bce->script->bindings.numVars() : 0;
-    unsigned localOffset = nfixedvars;
+    unsigned nbodyfixed = bce->sc->isFunctionBox() ? bce->script->bindings.numBodyLevelLocals() : 0;
+    unsigned localOffset = nbodyfixed;
 
     if (bce->staticScope) {
         Rooted<NestedScopeObject *> outer(cx, bce->staticScope);
         for (; outer; outer = outer->enclosingNestedScope()) {
             if (outer->is<StaticBlockObject>()) {
                 StaticBlockObject &outerBlock = outer->as<StaticBlockObject>();
                 localOffset = outerBlock.localOffset() + outerBlock.numVariables();
                 break;
             }
         }
     }
 
     JS_ASSERT(localOffset + blockObj->numVariables()
-              <= nfixedvars + bce->script->bindings.numBlockScoped());
+              <= nbodyfixed + bce->script->bindings.numBlockScoped());
 
     blockObj->setLocalOffset(localOffset);
 }
 
 // ~ Nested Scopes ~
 //
 // A nested scope is a region of a compilation unit (function, script, or eval
 // code) with an additional node on the scope chain.  This node may either be a
@@ -1056,40 +1059,56 @@ EmitRegExp(ExclusiveContext *cx, uint32_
 /*
  * To catch accidental misuse, EMIT_UINT16_IMM_OP/Emit3 assert that they are
  * not used to unconditionally emit JSOP_GETLOCAL. Variable access should
  * instead be emitted using EmitVarOp. In special cases, when the caller
  * definitely knows that a given local slot is unaliased, this function may be
  * used as a non-asserting version of EMIT_UINT16_IMM_OP.
  */
 static bool
-EmitUnaliasedVarOp(ExclusiveContext *cx, JSOp op, uint32_t slot, BytecodeEmitter *bce)
+EmitLocalOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, uint32_t slot)
+{
+    JS_ASSERT(JOF_OPTYPE(op) != JOF_SCOPECOORD);
+    JS_ASSERT(IsLocalOp(op));
+
+    ptrdiff_t off = EmitN(cx, bce, op, LOCALNO_LEN);
+    if (off < 0)
+        return false;
+
+    SET_LOCALNO(bce->code(off), slot);
+    return true;
+}
+
+static bool
+EmitUnaliasedVarOp(ExclusiveContext *cx, JSOp op, uint32_t slot, MaybeCheckLexical checkLexical,
+                   BytecodeEmitter *bce)
 {
     JS_ASSERT(JOF_OPTYPE(op) != JOF_SCOPECOORD);
 
     if (IsLocalOp(op)) {
-        ptrdiff_t off = EmitN(cx, bce, op, LOCALNO_LEN);
-        if (off < 0)
-            return false;
-
-        SET_LOCALNO(bce->code(off), slot);
-        return true;
+        if (checkLexical) {
+            MOZ_ASSERT(op != JSOP_INITLEXICAL);
+            if (!EmitLocalOp(cx, bce, JSOP_CHECKLEXICAL, slot))
+                return false;
+        }
+
+        return EmitLocalOp(cx, bce, op, slot);
     }
 
     JS_ASSERT(IsArgOp(op));
     ptrdiff_t off = EmitN(cx, bce, op, ARGNO_LEN);
     if (off < 0)
         return false;
 
     SET_ARGNO(bce->code(off), slot);
     return true;
 }
 
 static bool
-EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmitter *bce)
+EmitScopeCoordOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, ScopeCoordinate sc)
 {
     JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD);
 
     unsigned n = SCOPECOORD_HOPS_LEN + SCOPECOORD_SLOT_LEN;
     JS_ASSERT(int(n) + 1 /* op */ == js_CodeSpec[op].length);
 
     ptrdiff_t off = EmitN(cx, bce, op, n);
     if (off < 0)
@@ -1099,55 +1118,98 @@ EmitAliasedVarOp(ExclusiveContext *cx, J
     SET_SCOPECOORD_HOPS(pc, sc.hops());
     pc += SCOPECOORD_HOPS_LEN;
     SET_SCOPECOORD_SLOT(pc, sc.slot());
     pc += SCOPECOORD_SLOT_LEN;
     CheckTypeSet(cx, bce, op);
     return true;
 }
 
+static bool
+EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, MaybeCheckLexical checkLexical,
+                 BytecodeEmitter *bce)
+{
+    if (checkLexical) {
+        MOZ_ASSERT(op != JSOP_INITALIASEDLEXICAL);
+        if (!EmitScopeCoordOp(cx, bce, JSOP_CHECKALIASEDLEXICAL, sc))
+            return false;
+    }
+
+    return EmitScopeCoordOp(cx, bce, op, sc);
+}
+
 // Compute the number of nested scope objects that will actually be on the scope
 // chain at runtime, given the BCE's current staticScope.
 static unsigned
 DynamicNestedScopeDepth(BytecodeEmitter *bce)
 {
     unsigned depth = 0;
     for (NestedScopeObject *b = bce->staticScope; b; b = b->enclosingNestedScope()) {
         if (!b->is<StaticBlockObject>() || b->as<StaticBlockObject>().needsClone())
             ++depth;
     }
 
     return depth;
 }
 
 static bool
-LookupAliasedName(HandleScript script, PropertyName *name, uint32_t *pslot)
-{
+LookupAliasedName(BytecodeEmitter *bce, HandleScript script, PropertyName *name, uint32_t *pslot,
+                  ParseNode *pn = nullptr)
+{
+    LazyScript::FreeVariable *freeVariables = nullptr;
+    uint32_t lexicalBegin = 0;
+    uint32_t numFreeVariables = 0;
+    if (bce->emitterMode == BytecodeEmitter::LazyFunction) {
+        freeVariables = bce->lazyScript->freeVariables();
+        lexicalBegin = script->bindings.lexicalBegin();
+        numFreeVariables = bce->lazyScript->numFreeVariables();
+    }
+
     /*
      * Beware: BindingIter may contain more than one Binding for a given name
      * (in the case of |function f(x,x) {}|) but only one will be aliased.
      */
+    uint32_t bindingIndex = 0;
     uint32_t slot = CallObject::RESERVED_SLOTS;
     for (BindingIter bi(script); !bi.done(); bi++) {
         if (bi->aliased()) {
             if (bi->name() == name) {
+                // Check if the free variable from a lazy script was marked as
+                // a possible hoisted use and is a lexical binding. If so,
+                // mark it as such so we emit a dead zone check.
+                if (freeVariables) {
+                    for (uint32_t i = 0; i < numFreeVariables; i++) {
+                        if (freeVariables[i].atom() == name) {
+                            if (freeVariables[i].isHoistedUse() && bindingIndex >= lexicalBegin) {
+                                MOZ_ASSERT(pn);
+                                MOZ_ASSERT(pn->isUsed());
+                                pn->pn_dflags |= PND_LET;
+                            }
+
+                            break;
+                        }
+                    }
+                }
+
                 *pslot = slot;
                 return true;
             }
             slot++;
         }
+        bindingIndex++;
     }
     return false;
 }
 
 static bool
-LookupAliasedNameSlot(HandleScript script, PropertyName *name, ScopeCoordinate *sc)
+LookupAliasedNameSlot(BytecodeEmitter *bce, HandleScript script, PropertyName *name,
+                      ScopeCoordinate *sc)
 {
     uint32_t slot;
-    if (!LookupAliasedName(script, name, &slot))
+    if (!LookupAliasedName(bce, script, name, &slot))
         return false;
 
     sc->setSlot(slot);
     return true;
 }
 
 /*
  * Use this function instead of assigning directly to 'hops' to guard for
@@ -1160,16 +1222,22 @@ AssignHops(BytecodeEmitter *bce, ParseNo
         bce->reportError(pn, JSMSG_TOO_DEEP, js_function_str);
         return false;
     }
 
     dst->setHops(src);
     return true;
 }
 
+static inline MaybeCheckLexical
+NodeNeedsCheckLexical(ParseNode *pn)
+{
+    return pn->isHoistedLetUse() ? CheckLexical : DontCheckLexical;
+}
+
 static bool
 EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce)
 {
     /*
      * While pn->pn_cookie tells us how many function scopes are between the use and the def this
      * is not the same as how many hops up the dynamic scope chain are needed. In particular:
      *  - a lexical function scope only contributes a hop if it is "heavyweight" (has a dynamic
      *    scope object).
@@ -1206,67 +1274,68 @@ EmitAliasedVarOp(ExclusiveContext *cx, J
      * and so includes the full DynamicNestedScopeDepth. A let/catch-binding
      * requires a search of the block chain to see how many (dynamic) block
      * objects to skip.
      */
     ScopeCoordinate sc;
     if (IsArgOp(pn->getOp())) {
         if (!AssignHops(bce, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc))
             return false;
-        JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef->script, pn->name(), &sc));
+        JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef, bceOfDef->script, pn->name(), &sc));
     } else {
         JS_ASSERT(IsLocalOp(pn->getOp()) || pn->isKind(PNK_FUNCTION));
         uint32_t local = pn->pn_cookie.slot();
-        if (local < bceOfDef->script->bindings.numVars()) {
+        if (local < bceOfDef->script->bindings.numBodyLevelLocals()) {
             if (!AssignHops(bce, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc))
                 return false;
-            JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef->script, pn->name(), &sc));
+            JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef, bceOfDef->script, pn->name(), &sc));
         } else {
             JS_ASSERT_IF(bce->sc->isFunctionBox(), local <= bceOfDef->script->bindings.numLocals());
             JS_ASSERT(bceOfDef->staticScope->is<StaticBlockObject>());
             Rooted<StaticBlockObject*> b(cx, &bceOfDef->staticScope->as<StaticBlockObject>());
             while (local < b->localOffset()) {
                 if (b->needsClone())
                     skippedScopes++;
                 b = &b->enclosingNestedScope()->as<StaticBlockObject>();
             }
             if (!AssignHops(bce, pn, skippedScopes, &sc))
                 return false;
             sc.setSlot(b->localIndexToSlot(local));
         }
     }
 
-    return EmitAliasedVarOp(cx, op, sc, bce);
+    return EmitAliasedVarOp(cx, op, sc, NodeNeedsCheckLexical(pn), bce);
 }
 
 static bool
 EmitVarOp(ExclusiveContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
 {
     JS_ASSERT(pn->isKind(PNK_FUNCTION) || pn->isKind(PNK_NAME));
     JS_ASSERT(!pn->pn_cookie.isFree());
 
     if (IsAliasedVarOp(op)) {
         ScopeCoordinate sc;
         sc.setHops(pn->pn_cookie.level());
         sc.setSlot(pn->pn_cookie.slot());
-        return EmitAliasedVarOp(cx, op, sc, bce);
+        return EmitAliasedVarOp(cx, op, sc, NodeNeedsCheckLexical(pn), bce);
     }
 
     JS_ASSERT_IF(pn->isKind(PNK_NAME), IsArgOp(op) || IsLocalOp(op));
 
     if (!bce->isAliasedName(pn)) {
         JS_ASSERT(pn->isUsed() || pn->isDefn());
         JS_ASSERT_IF(pn->isUsed(), pn->pn_cookie.level() == 0);
         JS_ASSERT_IF(pn->isDefn(), pn->pn_cookie.level() == bce->script->staticLevel());
-        return EmitUnaliasedVarOp(cx, op, pn->pn_cookie.slot(), bce);
+        return EmitUnaliasedVarOp(cx, op, pn->pn_cookie.slot(), NodeNeedsCheckLexical(pn), bce);
     }
 
     switch (op) {
       case JSOP_GETARG: case JSOP_GETLOCAL: op = JSOP_GETALIASEDVAR; break;
       case JSOP_SETARG: case JSOP_SETLOCAL: op = JSOP_SETALIASEDVAR; break;
+      case JSOP_INITLEXICAL: op = JSOP_INITALIASEDLEXICAL; break;
       default: MOZ_CRASH("unexpected var op");
     }
 
     return EmitAliasedVarOp(cx, op, pn, bce);
 }
 
 static JSOp
 GetIncDecInfo(ParseNodeKind kind, bool *post)
@@ -1430,23 +1499,24 @@ TryConvertFreeName(BytecodeEmitter *bce,
                     hops++;
                 continue;
             }
             RootedScript script(bce->sc->context, ssi.funScript());
             if (script->functionNonDelazifying()->atom() == pn->pn_atom)
                 return false;
             if (ssi.hasDynamicScopeObject()) {
                 uint32_t slot;
-                if (LookupAliasedName(script, pn->pn_atom->asPropertyName(), &slot)) {
+                if (LookupAliasedName(bce, script, pn->pn_atom->asPropertyName(), &slot, pn)) {
                     JSOp op;
                     switch (pn->getOp()) {
-                      case JSOP_NAME:     op = JSOP_GETALIASEDVAR; break;
-                      case JSOP_SETNAME:  op = JSOP_SETALIASEDVAR; break;
+                      case JSOP_NAME:    op = JSOP_GETALIASEDVAR; break;
+                      case JSOP_SETNAME: op = JSOP_SETALIASEDVAR; break;
                       default: return false;
                     }
+
                     pn->setOp(op);
                     JS_ALWAYS_TRUE(pn->pn_cookie.set(bce->parser->tokenStream, hops, slot));
                     return true;
                 }
                 hops++;
             }
 
             if (script->funHasExtensibleScope() || script->directlyInsideEval())
@@ -2459,54 +2529,58 @@ EmitNumberOp(ExclusiveContext *cx, doubl
 
 static inline void
 SetJumpOffsetAt(BytecodeEmitter *bce, ptrdiff_t off)
 {
     SET_JUMP_OFFSET(bce->code(off), bce->offset() - off);
 }
 
 static bool
-PushUndefinedValues(ExclusiveContext *cx, BytecodeEmitter *bce, unsigned n)
-{
+PushInitialConstants(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, unsigned n)
+{
+    MOZ_ASSERT(op == JSOP_UNDEFINED || op == JSOP_UNINITIALIZED);
     for (unsigned i = 0; i < n; ++i) {
-        if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
+        if (Emit1(cx, bce, op) < 0)
             return false;
     }
     return true;
 }
 
 static bool
 InitializeBlockScopedLocalsFromStack(ExclusiveContext *cx, BytecodeEmitter *bce,
                                      Handle<StaticBlockObject *> blockObj)
 {
     for (unsigned i = blockObj->numVariables(); i > 0; --i) {
         if (blockObj->isAliased(i - 1)) {
             ScopeCoordinate sc;
             sc.setHops(0);
             sc.setSlot(BlockObject::RESERVED_SLOTS + i - 1);
-            if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce))
+            if (!EmitAliasedVarOp(cx, JSOP_INITALIASEDLEXICAL, sc, DontCheckLexical, bce))
                 return false;
         } else {
             unsigned local = blockObj->blockIndexToLocalIndex(i - 1);
-            if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, local, bce))
+            if (!EmitUnaliasedVarOp(cx, JSOP_INITLEXICAL, local, DontCheckLexical, bce))
                 return false;
         }
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
     }
     return true;
 }
 
 static bool
 EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmtInfo,
-                ObjectBox *objbox, unsigned alreadyPushed = 0)
-{
-    // Initial values for block-scoped locals.
+                ObjectBox *objbox, JSOp initialValueOp, unsigned alreadyPushed = 0)
+{
+    // Initial values for block-scoped locals. Whether it is undefined or the
+    // JS_UNINITIALIZED_LEXICAL magic value depends on the context. The
+    // current way we emit for-in and for-of heads means its let bindings will
+    // always be initialized, so we can initialize them to undefined.
     Rooted<StaticBlockObject *> blockObj(cx, &objbox->object->as<StaticBlockObject>());
-    if (!PushUndefinedValues(cx, bce, blockObj->numVariables() - alreadyPushed))
+    if (!PushInitialConstants(cx, bce, initialValueOp, blockObj->numVariables() - alreadyPushed))
         return false;
 
     if (!EnterNestedScope(cx, bce, stmtInfo, objbox, STMT_BLOCK))
         return false;
 
     if (!InitializeBlockScopedLocalsFromStack(cx, bce, blockObj))
         return false;
 
@@ -2539,17 +2613,17 @@ EmitSwitch(ExclusiveContext *cx, Bytecod
     JS_ASSERT(pn2->isKind(PNK_LEXICALSCOPE) || pn2->isKind(PNK_STATEMENTLIST));
 
     /* Push the discriminant. */
     if (!EmitTree(cx, bce, pn->pn_left))
         return false;
 
     StmtInfoBCE stmtInfo(cx);
     if (pn2->isKind(PNK_LEXICALSCOPE)) {
-        if (!EnterBlockScope(cx, bce, &stmtInfo, pn2->pn_objbox, 0))
+        if (!EnterBlockScope(cx, bce, &stmtInfo, pn2->pn_objbox, JSOP_UNINITIALIZED, 0))
             return false;
 
         stmtInfo.type = STMT_SWITCH;
         stmtInfo.update = top = bce->offset();
         /* Advance pn2 to refer to the switch case list. */
         pn2 = pn2->expr();
     } else {
         JS_ASSERT(pn2->isKind(PNK_STATEMENTLIST));
@@ -2842,18 +2916,21 @@ EmitSwitch(ExclusiveContext *cx, Bytecod
 
 bool
 BytecodeEmitter::isRunOnceLambda()
 {
     // The run once lambda flags set by the parser are approximate, and we look
     // at properties of the function itself before deciding to emit a function
     // as a run once lambda.
 
-    if (!(parent && parent->emittingRunOnceLambda) && !lazyRunOnceLambda)
-        return false;
+    if (!(parent && parent->emittingRunOnceLambda) &&
+        (emitterMode != LazyFunction || !lazyScript->treatAsRunOnce()))
+    {
+        return false;
+    }
 
     FunctionBox *funbox = sc->asFunctionBox();
     return !funbox->argumentsHasLocalBinding() &&
            !funbox->isGenerator() &&
            !funbox->function()->name();
 }
 
 bool
@@ -2872,21 +2949,21 @@ frontend::EmitFunctionScript(ExclusiveCo
         bce->switchToProlog();
         if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
             return false;
         InternalBindingsHandle bindings(bce->script, &bce->script->bindings);
         uint32_t varIndex = Bindings::argumentsVarIndex(cx, bindings);
         if (bce->script->varIsAliased(varIndex)) {
             ScopeCoordinate sc;
             sc.setHops(0);
-            JS_ALWAYS_TRUE(LookupAliasedNameSlot(bce->script, cx->names().arguments, &sc));
-            if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce))
+            JS_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().arguments, &sc));
+            if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, DontCheckLexical, bce))
                 return false;
         } else {
-            if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, varIndex, bce))
+            if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, varIndex, DontCheckLexical, bce))
                 return false;
         }
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
         bce->switchToMain();
     }
 
     if (funbox->isGenerator()) {
@@ -3002,63 +3079,97 @@ enum VarEmitOption
     DefineVars        = 0,
     PushInitialValues = 1,
     InitializeVars    = 2
 };
 
 typedef bool
 (*DestructuringDeclEmitter)(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn);
 
+template <DestructuringDeclEmitter EmitName>
 static bool
-EmitDestructuringDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
-{
-    JS_ASSERT(pn->isKind(PNK_NAME));
-    if (!BindNameToSlot(cx, bce, pn))
-        return false;
-
-    JS_ASSERT(!pn->isOp(JSOP_CALLEE));
-    return MaybeEmitVarDecl(cx, bce, prologOp, pn, nullptr);
-}
-
-static bool
-EmitDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
-                       ParseNode *pattern)
+EmitDestructuringDeclsWithEmitter(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
+                                  ParseNode *pattern)
 {
     if (pattern->isKind(PNK_ARRAY)) {
         for (ParseNode *element = pattern->pn_head; element; element = element->pn_next) {
             if (element->isKind(PNK_ELISION))
                 continue;
             ParseNode *target = element;
             if (element->isKind(PNK_SPREAD)) {
                 JS_ASSERT(element->pn_kid->isKind(PNK_NAME));
                 target = element->pn_kid;
             }
-            DestructuringDeclEmitter emitter =
-                target->isKind(PNK_NAME) ? EmitDestructuringDecl : EmitDestructuringDecls;
-            if (!emitter(cx, bce, prologOp, target))
-                return false;
+            if (target->isKind(PNK_NAME)) {
+                if (!EmitName(cx, bce, prologOp, target))
+                    return false;
+            } else {
+                if (!EmitDestructuringDeclsWithEmitter<EmitName>(cx, bce, prologOp, target))
+                    return false;
+            }
         }
         return true;
     }
 
     MOZ_ASSERT(pattern->isKind(PNK_OBJECT));
     for (ParseNode *member = pattern->pn_head; member; member = member->pn_next) {
         MOZ_ASSERT(member->isKind(PNK_MUTATEPROTO) ||
                    member->isKind(PNK_COLON) ||
                    member->isKind(PNK_SHORTHAND));
 
         ParseNode *target = member->isKind(PNK_MUTATEPROTO) ? member->pn_kid : member->pn_right;
-        DestructuringDeclEmitter emitter =
-            target->isKind(PNK_NAME) ? EmitDestructuringDecl : EmitDestructuringDecls;
-        if (!emitter(cx, bce, prologOp, target))
-            return false;
+
+        if (target->isKind(PNK_NAME)) {
+            if (!EmitName(cx, bce, prologOp, target))
+                return false;
+        } else {
+            if (!EmitDestructuringDeclsWithEmitter<EmitName>(cx, bce, prologOp, target))
+                return false;
+        }
     }
     return true;
 }
 
+bool
+EmitDestructuringDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
+{
+    JS_ASSERT(pn->isKind(PNK_NAME));
+    if (!BindNameToSlot(cx, bce, pn))
+        return false;
+
+    JS_ASSERT(!pn->isOp(JSOP_CALLEE));
+    return MaybeEmitVarDecl(cx, bce, prologOp, pn, nullptr);
+}
+
+static inline bool
+EmitDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
+                       ParseNode *pattern)
+{
+    return EmitDestructuringDeclsWithEmitter<EmitDestructuringDecl>(cx, bce, prologOp, pattern);
+}
+
+bool
+EmitInitializeDestructuringDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
+                                ParseNode *pn)
+{
+    MOZ_ASSERT(pn->isKind(PNK_NAME));
+    MOZ_ASSERT(pn->isBound());
+    return EmitVarOp(cx, pn, pn->getOp(), bce);
+}
+
+// Emit code to initialize all destructured names to the value on the top of
+// the stack.
+static inline bool
+EmitInitializeDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
+                                 ParseNode *pattern)
+{
+    return EmitDestructuringDeclsWithEmitter<EmitInitializeDestructuringDecl>(cx, bce,
+                                                                              prologOp, pattern);
+}
+
 static bool
 EmitDestructuringOpsHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pattern,
                            VarEmitOption emitOption);
 
 /*
  * EmitDestructuringLHS assumes the to-be-destructured value has been pushed on
  * the stack and emits code to destructure a single lhs expression (either a
  * name or a compound []/{} expression).
@@ -3088,17 +3199,17 @@ EmitDestructuringLHS(ExclusiveContext *c
             // Per its post-condition, EmitDestructuringOpsHelper has left the
             // to-be-destructured value on top of the stack.
             if (Emit1(cx, bce, JSOP_POP) < 0)
                 return false;
         }
     } else if (emitOption == PushInitialValues) {
         // The lhs is a simple name so the to-be-destructured value is
         // its initial value and there is nothing to do.
-        JS_ASSERT(pn->getOp() == JSOP_SETLOCAL);
+        JS_ASSERT(pn->getOp() == JSOP_SETLOCAL || pn->getOp() == JSOP_INITLEXICAL);
         JS_ASSERT(pn->pn_dflags & PND_BOUND);
     } else {
         switch (pn->getKind()) {
           case PNK_NAME:
             if (!BindNameToSlot(cx, bce, pn))
                 return false;
 
             // Allow 'const [x,y] = o', make 'const x,y; [x,y] = o' a nop.
@@ -3133,16 +3244,17 @@ EmitDestructuringLHS(ExclusiveContext *c
 
                 if (!EmitIndexOp(cx, pn->getOp(), atomIndex, bce))
                     return false;
                 break;
               }
 
               case JSOP_SETLOCAL:
               case JSOP_SETARG:
+              case JSOP_INITLEXICAL:
                 if (!EmitVarOp(cx, pn, pn->getOp(), bce))
                     return false;
                 break;
 
               default:
                 MOZ_CRASH("EmitDestructuringLHS: bad name op");
             }
             break;
@@ -3529,42 +3641,59 @@ EmitTemplateString(ExclusiveContext *cx,
         }
 
     }
     return true;
 }
 
 static bool
 EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption,
-              bool isLet = false)
+              bool isLetExpr = false)
 {
     JS_ASSERT(pn->isArity(PN_LIST));
-    JS_ASSERT(isLet == (emitOption == PushInitialValues));
+    JS_ASSERT(isLetExpr == (emitOption == PushInitialValues));
 
     ParseNode *next;
     for (ParseNode *pn2 = pn->pn_head; ; pn2 = next) {
         if (!UpdateSourceCoordNotes(cx, bce, pn2->pn_pos.begin))
             return false;
         next = pn2->pn_next;
 
         ParseNode *pn3;
         if (!pn2->isKind(PNK_NAME)) {
             if (pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT)) {
-                /*
-                 * Emit variable binding ops, but not destructuring ops.  The
-                 * parser (see Parser::variables) has ensured that our caller
-                 * will be the PNK_FOR/PNK_FORIN/PNK_FOROF case in EmitTree, and
-                 * that case will emit the destructuring code only after
-                 * emitting an enumerating opcode and a branch that tests
-                 * whether the enumeration ended.
-                 */
-                JS_ASSERT(emitOption == DefineVars);
+                // If the emit option is DefineVars, emit variable binding
+                // ops, but not destructuring ops.  The parser (see
+                // Parser::variables) has ensured that our caller will be the
+                // PNK_FOR/PNK_FORIN/PNK_FOROF case in EmitTree (we don't have
+                // to worry about this being a variable declaration, as
+                // destructuring declarations without initializers, e.g., |var
+                // [x]|, are not legal syntax), and that case will emit the
+                // destructuring code only after emitting an enumerating
+                // opcode and a branch that tests whether the enumeration
+                // ended. Thus, each iteration's assignment is responsible for
+                // initializing, and nothing needs to be done here.
+                //
+                // Otherwise this is emitting destructuring let binding
+                // initialization for a legacy comprehension expression. See
+                // EmitForInOrOfVariables.
                 JS_ASSERT(pn->pn_count == 1);
-                if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn2))
-                    return false;
+                if (emitOption == DefineVars) {
+                    if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn2))
+                        return false;
+                } else {
+                    // Lexical bindings cannot be used before they are
+                    // initialized. Similar to the JSOP_INITLEXICAL case below.
+                    MOZ_ASSERT(emitOption != DefineVars);
+                    MOZ_ASSERT_IF(emitOption == InitializeVars, pn->pn_xflags & PNX_POPVAR);
+                    if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
+                        return false;
+                    if (!EmitInitializeDestructuringDecls(cx, bce, pn->getOp(), pn2))
+                        return false;
+                }
                 break;
             }
 
             /*
              * A destructuring initialiser assignment preceded by var will
              * never occur to the left of 'in' in a for-in loop.  As with 'for
              * (var x = i in o)...', this will cause the entire 'var [a, b] =
              * i' to be hoisted out of the loop.
@@ -3586,17 +3715,17 @@ EmitVariables(ExclusiveContext *cx, Byte
 
             pn3 = pn2->pn_left;
             if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn3))
                 return false;
 
             if (!EmitTree(cx, bce, pn2->pn_right))
                 return false;
 
-            if (!EmitDestructuringOps(cx, bce, pn3, isLet))
+            if (!EmitDestructuringOps(cx, bce, pn3, isLetExpr))
                 return false;
 
             /* If we are not initializing, nothing to pop. */
             if (emitOption != InitializeVars) {
                 if (next)
                     continue;
                 break;
             }
@@ -3640,23 +3769,27 @@ EmitVariables(ExclusiveContext *cx, Byte
                     return false;
             }
 
             bool oldEmittingForInit = bce->emittingForInit;
             bce->emittingForInit = false;
             if (!EmitTree(cx, bce, pn3))
                 return false;
             bce->emittingForInit = oldEmittingForInit;
-        } else if (isLet) {
-            /* JSOP_ENTERLETx expects at least 1 slot to have been pushed. */
+        } else if (op == JSOP_INITLEXICAL || isLetExpr) {
+            // 'let' bindings cannot be used before they are
+            // initialized. JSOP_INITLEXICAL distinguishes the binding site.
+            MOZ_ASSERT(emitOption != DefineVars);
+            MOZ_ASSERT_IF(emitOption == InitializeVars, pn->pn_xflags & PNX_POPVAR);
             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
                 return false;
         }
 
-        /* If we are not initializing, nothing to pop. */
+        // If we are not initializing, nothing to pop. If we are initializing
+        // lets, we must emit the pops.
         if (emitOption != InitializeVars) {
             if (next)
                 continue;
             break;
         }
 
         JS_ASSERT_IF(pn2->isDefn(), pn3 == pn2->pn_expr);
         if (!pn2->pn_cookie.isFree()) {
@@ -4104,17 +4237,17 @@ EmitCatch(ExclusiveContext *cx, Bytecode
             return false;
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
         break;
 
       case PNK_NAME:
         /* Inline and specialize BindNameToSlot for pn2. */
         JS_ASSERT(!pn2->pn_cookie.isFree());
-        if (!EmitVarOp(cx, pn2, JSOP_SETLOCAL, bce))
+        if (!EmitVarOp(cx, pn2, JSOP_INITLEXICAL, bce))
             return false;
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
         break;
 
       default:
         JS_ASSERT(0);
     }
@@ -4458,19 +4591,19 @@ EmitLet(ExclusiveContext *cx, BytecodeEm
     JS_ASSERT(letBody->isLet() && letBody->isKind(PNK_LEXICALSCOPE));
 
     int letHeadDepth = bce->stackDepth;
 
     if (!EmitVariables(cx, bce, varList, PushInitialValues, true))
         return false;
 
     /* Push storage for hoisted let decls (e.g. 'let (x) { let y }'). */
-    uint32_t alreadyPushed = bce->stackDepth - letHeadDepth;
+    uint32_t valuesPushed = bce->stackDepth - letHeadDepth;
     StmtInfoBCE stmtInfo(cx);
-    if (!EnterBlockScope(cx, bce, &stmtInfo, letBody->pn_objbox, alreadyPushed))
+    if (!EnterBlockScope(cx, bce, &stmtInfo, letBody->pn_objbox, JSOP_UNINITIALIZED, valuesPushed))
         return false;
 
     if (!EmitTree(cx, bce, letBody->pn_expr))
         return false;
 
     if (!LeaveNestedScope(cx, bce, &stmtInfo))
         return false;
 
@@ -4482,17 +4615,17 @@ EmitLet(ExclusiveContext *cx, BytecodeEm
  * the comment on EmitSwitch.
  */
 MOZ_NEVER_INLINE static bool
 EmitLexicalScope(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
 
     StmtInfoBCE stmtInfo(cx);
-    if (!EnterBlockScope(cx, bce, &stmtInfo, pn->pn_objbox, 0))
+    if (!EnterBlockScope(cx, bce, &stmtInfo, pn->pn_objbox, JSOP_UNINITIALIZED, 0))
         return false;
 
     if (!EmitTree(cx, bce, pn->pn_expr))
         return false;
 
     if (!LeaveNestedScope(cx, bce, &stmtInfo))
         return false;
 
@@ -4529,16 +4662,49 @@ EmitIterator(ExclusiveContext *cx, Bytec
     if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // @@ITERATOR OBJ
         return false;
     if (EmitCall(cx, bce, JSOP_CALL, 0) < 0)                   // ITER
         return false;
     CheckTypeSet(cx, bce, JSOP_CALL);
     return true;
 }
 
+static bool
+EmitForInOrOfVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool *letDecl)
+{
+    *letDecl = pn->isKind(PNK_LEXICALSCOPE);
+    MOZ_ASSERT_IF(*letDecl, pn->isLet());
+
+    // If the left part is 'var x', emit code to define x if necessary using a
+    // prolog opcode, but do not emit a pop. If it is 'let x', EnterBlockScope
+    // will initialize let bindings in EmitForOf and EmitForIn with
+    // undefineds.
+    //
+    // Due to the horror of legacy comprehensions, there is a third case where
+    // we have PNK_LET without a lexical scope, because those expressions are
+    // parsed with single lexical scope for the entire comprehension. In this
+    // case we must initialize the lets to not trigger dead zone checks via
+    // InitializeVars.
+    if (!*letDecl) {
+        bce->emittingForInit = true;
+        if (pn->isKind(PNK_VAR)) {
+            if (!EmitVariables(cx, bce, pn, DefineVars))
+                return false;
+        } else {
+            MOZ_ASSERT(pn->isKind(PNK_LET));
+            if (!EmitVariables(cx, bce, pn, InitializeVars))
+                return false;
+        }
+        bce->emittingForInit = false;
+    }
+
+    return true;
+}
+
+
 /**
  * If type is STMT_FOR_OF_LOOP, it emits bytecode for for-of loop.
  * pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
  *
  * If type is STMT_SPREAD, it emits bytecode for spread operator.
  * pn should be nullptr.
  * Please refer the comment above EmitSpread for additional information about
  * stack convention.
@@ -4549,29 +4715,19 @@ EmitForOf(ExclusiveContext *cx, Bytecode
     JS_ASSERT(type == STMT_FOR_OF_LOOP || type == STMT_SPREAD);
     JS_ASSERT_IF(type == STMT_FOR_OF_LOOP, pn && pn->pn_left->isKind(PNK_FOROF));
     JS_ASSERT_IF(type == STMT_SPREAD, !pn);
 
     ParseNode *forHead = pn ? pn->pn_left : nullptr;
     ParseNode *forBody = pn ? pn->pn_right : nullptr;
 
     ParseNode *pn1 = forHead ? forHead->pn_kid1 : nullptr;
-    bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
-    JS_ASSERT_IF(letDecl, pn1->isLet());
-
-    // If the left part is 'var x', emit code to define x if necessary using a
-    // prolog opcode, but do not emit a pop.
-    if (pn1) {
-        ParseNode *decl = letDecl ? pn1->pn_expr : pn1;
-        JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET));
-        bce->emittingForInit = true;
-        if (!EmitVariables(cx, bce, decl, DefineVars))
-            return false;
-        bce->emittingForInit = false;
-    }
+    bool letDecl = false;
+    if (pn1 && !EmitForInOrOfVariables(cx, bce, pn1, &letDecl))
+        return false;
 
     if (type == STMT_FOR_OF_LOOP) {
         // For-of loops run with two values on the stack: the iterator and the
         // current result object.
 
         // Compile the object expression to the right of 'of'.
         if (!EmitTree(cx, bce, forHead->pn_kid3))
             return false;
@@ -4579,19 +4735,21 @@ EmitForOf(ExclusiveContext *cx, Bytecode
             return false;
 
         // Push a dummy result so that we properly enter iteration midstream.
         if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)                // ITER RESULT
             return false;
     }
 
     // Enter the block before the loop body, after evaluating the obj.
+    // Initialize let bindings with undefined when entering, as the name
+    // assigned to is a plain assignment.
     StmtInfoBCE letStmt(cx);
     if (letDecl) {
-        if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, 0))
+        if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, JSOP_UNDEFINED, 0))
             return false;
     }
 
     LoopStmtInfo stmtInfo(cx);
     PushLoopStatement(bce, &stmtInfo, type, top);
 
     // Jump down to the loop condition to minimize overhead assuming at least
     // one iteration, as the other loop forms do.  Annotate so IonMonkey can
@@ -4703,51 +4861,39 @@ EmitForOf(ExclusiveContext *cx, Bytecode
 
 static bool
 EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
     ParseNode *forHead = pn->pn_left;
     ParseNode *forBody = pn->pn_right;
 
     ParseNode *pn1 = forHead->pn_kid1;
-    bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
-    JS_ASSERT_IF(letDecl, pn1->isLet());
-
-    /*
-     * If the left part is 'var x', emit code to define x if necessary
-     * using a prolog opcode, but do not emit a pop. If the left part was
-     * originally 'var x = i', the parser will have rewritten it; see
-     * Parser::forStatement. 'for (let x = i in o)' is mercifully banned.
-     */
-    if (pn1) {
-        ParseNode *decl = letDecl ? pn1->pn_expr : pn1;
-        JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET));
-        bce->emittingForInit = true;
-        if (!EmitVariables(cx, bce, decl, DefineVars))
-            return false;
-        bce->emittingForInit = false;
-    }
+    bool letDecl = false;
+    if (pn1 && !EmitForInOrOfVariables(cx, bce, pn1, &letDecl))
+        return false;
 
     /* Compile the object expression to the right of 'in'. */
     if (!EmitTree(cx, bce, forHead->pn_kid3))
         return false;
 
     /*
      * Emit a bytecode to convert top of stack value to the iterator
      * object depending on the loop variant (for-in, for-each-in, or
      * destructuring for-in).
      */
     JS_ASSERT(pn->isOp(JSOP_ITER));
     if (Emit2(cx, bce, JSOP_ITER, (uint8_t) pn->pn_iflags) < 0)
         return false;
 
-    /* Enter the block before the loop body, after evaluating the obj. */
+    // Enter the block before the loop body, after evaluating the obj.
+    // Initialize let bindings with undefined when entering, as the name
+    // assigned to is a plain assignment.
     StmtInfoBCE letStmt(cx);
     if (letDecl) {
-        if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, 0))
+        if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, JSOP_UNDEFINED, 0))
             return false;
     }
 
     LoopStmtInfo stmtInfo(cx);
     PushLoopStatement(bce, &stmtInfo, STMT_FOR_IN_LOOP, top);
 
     /* Annotate so IonMonkey can find the loop-closing jump. */
     int noteIndex = NewSrcNote(cx, bce, SRC_FOR_IN);
@@ -5037,18 +5183,18 @@ EmitFunc(ExclusiveContext *cx, BytecodeE
                                                           sourceObject,
                                                           funbox->bufStart, funbox->bufEnd));
             if (!script)
                 return false;
 
             script->bindings = funbox->bindings;
 
             uint32_t lineNum = bce->parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin);
-            BytecodeEmitter bce2(bce, bce->parser, funbox, script, bce->insideEval,
-                                 bce->evalCaller, bce->hasGlobalScope, lineNum,
+            BytecodeEmitter bce2(bce, bce->parser, funbox, script, /* lazyScript = */ js::NullPtr(),
+                                 bce->insideEval, bce->evalCaller, bce->hasGlobalScope, lineNum,
                                  bce->emitterMode);
             if (!bce2.init())
                 return false;
 
             /* We measured the max scope depth when we parsed the function. */
             if (!EmitFunctionScript(cx, &bce2, pn->pn_body))
                 return false;
 
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -81,16 +81,19 @@ struct BytecodeEmitter
     typedef StmtInfoBCE StmtInfo;
 
     SharedContext   *const sc;      /* context shared between parsing and bytecode generation */
 
     BytecodeEmitter *const parent;  /* enclosing function or global context */
 
     Rooted<JSScript*> script;       /* the JSScript we're ultimately producing */
 
+    Rooted<LazyScript *> lazyScript; /* the lazy script if mode is LazyFunction,
+                                        nullptr otherwise. */
+
     struct EmitSection {
         BytecodeVector code;        /* bytecode */
         SrcNotesVector notes;       /* source notes, see below */
         ptrdiff_t   lastNoteOffset; /* code offset for last source note */
         uint32_t    currentLine;    /* line number for tree-based srcnote gen */
         uint32_t    lastColumn;     /* zero-based column index on currentLine of
                                        last SRC_COLSPAN-annotated opcode */
 
@@ -131,18 +134,16 @@ struct BytecodeEmitter
     uint16_t        typesetCount;   /* Number of JOF_TYPESET opcodes generated */
 
     bool            hasSingletons:1;    /* script contains singleton initializer JSOP_OBJECT */
 
     bool            emittingForInit:1;  /* true while emitting init expr of for; exclude 'in' */
 
     bool            emittingRunOnceLambda:1; /* true while emitting a lambda which is only
                                                 expected to run once. */
-    bool            lazyRunOnceLambda:1; /* true while lazily emitting a script for
-                                          * a lambda which is only expected to run once. */
 
     bool isRunOnceLambda();
 
     bool            insideEval:1;       /* True if compiling an eval-expression or a function
                                            nested inside an eval. */
 
     const bool      hasGlobalScope:1;   /* frontend::CompileScript's scope chain is the
                                            global object */
@@ -168,18 +169,19 @@ struct BytecodeEmitter
 
     /*
      * Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
      * space above their tempMark points. This means that you cannot alloc from
      * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
      * destruction.
      */
     BytecodeEmitter(BytecodeEmitter *parent, Parser<FullParseHandler> *parser, SharedContext *sc,
-                    HandleScript script, bool insideEval, HandleScript evalCaller,
-                    bool hasGlobalScope, uint32_t lineNum, EmitterMode emitterMode = Normal);
+                    HandleScript script, Handle<LazyScript *> lazyScript,
+                    bool insideEval, HandleScript evalCaller, bool hasGlobalScope,
+                    uint32_t lineNum, EmitterMode emitterMode = Normal);
     bool init();
 
     bool isAliasedName(ParseNode *pn);
 
     MOZ_ALWAYS_INLINE
     bool makeAtomIndex(JSAtom *atom, jsatomid *indexp) {
         AtomIndexAddPtr p = atomIndices->lookupForAdd(atom);
         if (p) {
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -592,16 +592,19 @@ class FullParseHandler
     inline ParseNode *makeAssignment(ParseNode *pn, ParseNode *rhs);
 
     static Definition *getDefinitionNode(Definition *dn) {
         return dn;
     }
     static Definition::Kind getDefinitionKind(Definition *dn) {
         return dn->kind();
     }
+    static bool isPlaceholderDefinition(Definition *dn) {
+        return dn->isPlaceholder();
+    }
     void linkUseToDef(ParseNode *pn, Definition *dn)
     {
         JS_ASSERT(!pn->isUsed());
         JS_ASSERT(!pn->isDefn());
         JS_ASSERT(pn != dn->dn_uses);
         JS_ASSERT(dn->isDefn());
         pn->pn_link = dn->dn_uses;
         dn->dn_uses = pn;
@@ -619,16 +622,23 @@ class FullParseHandler
             JS_ASSERT(!pnu->isDefn());
             if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end)
                 pnu->pn_dflags |= PND_DEOPTIMIZED;
         }
     }
     bool dependencyCovered(ParseNode *pn, unsigned blockid, bool functionScope) {
         return pn->pn_blockid >= blockid;
     }
+    void markMaybeUninitializedLexicalUseInSwitch(ParseNode *pn, Definition *dn,
+                                                  uint16_t firstDominatingLexicalSlot)
+    {
+        MOZ_ASSERT(pn->isUsed());
+        if (dn->isLet() && dn->pn_cookie.slot() < firstDominatingLexicalSlot)
+            pn->pn_dflags |= PND_LET;
+    }
 
     static uintptr_t definitionToBits(Definition *dn) {
         return uintptr_t(dn);
     }
     static Definition *definitionFromBits(uintptr_t bits) {
         return (Definition *) bits;
     }
     static Definition *nullDefinition() {
@@ -706,21 +716,24 @@ FullParseHandler::finishInitializerAssig
     if (pn->isUsed()) {
         pn = makeAssignment(pn, init);
         if (!pn)
             return false;
     } else {
         pn->pn_expr = init;
     }
 
-    pn->setOp((pn->pn_dflags & PND_BOUND)
-              ? JSOP_SETLOCAL
-              : (op == JSOP_DEFCONST)
-              ? JSOP_SETCONST
-              : JSOP_SETNAME);
+    if (op == JSOP_INITLEXICAL)
+        pn->setOp(op);
+    else if (pn->pn_dflags & PND_BOUND)
+        pn->setOp(JSOP_SETLOCAL);
+    else if (op == JSOP_DEFCONST)
+        pn->setOp(JSOP_SETCONST);
+    else
+        pn->setOp(JSOP_SETNAME);
 
     pn->markAsAssigned();
 
     /* The declarator's position must include the initializer. */
     pn->pn_pos.end = init->pn_pos.end;
     return true;
 }
 
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -402,16 +402,17 @@ Parser<FullParseHandler>::cloneParseTree
         if (opn->isUsed()) {
             /*
              * The old name is a use of its pn_lexdef. Make the clone also be a
              * use of that definition.
              */
             Definition *dn = pn->pn_lexdef;
 
             pn->pn_link = dn->dn_uses;
+            pn->pn_dflags = opn->pn_dflags;
             dn->dn_uses = pn;
         } else if (opn->pn_expr) {
             NULLCHECK(pn->pn_expr = cloneParseTree(opn->pn_expr));
 
             /*
              * If the old name is a definition, the new one has pn_defn set.
              * Make the old name a use of the new node.
              */
@@ -508,17 +509,17 @@ Parser<FullParseHandler>::cloneLeftHandS
 
         pn->pn_link = dn->dn_uses;
         dn->dn_uses = pn;
     } else {
         pn->pn_expr = nullptr;
         if (opn->isDefn()) {
             /* We copied some definition-specific state into pn. Clear it out. */
             pn->pn_cookie.makeFree();
-            pn->pn_dflags &= ~PND_BOUND;
+            pn->pn_dflags &= ~(PND_LET | PND_BOUND);
             pn->setDefn(false);
 
             handler.linkUseToDef(pn, (Definition *) opn);
         }
     }
     return pn;
 }
 
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -659,17 +659,17 @@ class ParseNode
     }
 
     ParseNode  *maybeExpr()   { return pn_used ? nullptr : expr(); }
     Definition *maybeLexDef() { return pn_used ? lexdef() : nullptr; }
 
     Definition *resolve();
 
 /* PN_CODE and PN_NAME pn_dflags bits. */
-#define PND_LET                 0x01    /* let (block-scoped) binding */
+#define PND_LET                 0x01    /* let (block-scoped) binding or use of a hoisted let */
 #define PND_CONST               0x02    /* const binding (orthogonal to let) */
 #define PND_ASSIGNED            0x04    /* set if ever LHS of assignment */
 #define PND_PLACEHOLDER         0x08    /* placeholder definition for lexdep */
 #define PND_BOUND               0x10    /* bound to a stack or global slot */
 #define PND_DEOPTIMIZED         0x20    /* former pn_used name node, pn_lexdef
                                            still valid, but this use no longer
                                            optimizable via an upvar opcode */
 #define PND_CLOSED              0x40    /* variable is closed over */
@@ -741,24 +741,25 @@ class ParseNode
             if (kid && kid->getKind() == PNK_STRING && !kid->pn_parens)
                 return kid->pn_atom;
         }
         return nullptr;
     }
 
     inline bool test(unsigned flag) const;
 
-    bool isLet() const          { return test(PND_LET); }
+    bool isLet() const          { return test(PND_LET) && !isUsed(); }
     bool isConst() const        { return test(PND_CONST); }
     bool isPlaceholder() const  { return test(PND_PLACEHOLDER); }
     bool isDeoptimized() const  { return test(PND_DEOPTIMIZED); }
     bool isAssigned() const     { return test(PND_ASSIGNED); }
     bool isClosed() const       { return test(PND_CLOSED); }
     bool isBound() const        { return test(PND_BOUND); }
     bool isImplicitArguments() const { return test(PND_IMPLICITARGUMENTS); }
+    bool isHoistedLetUse() const { return test(PND_LET) && isUsed(); }
 
     /* True if pn is a parsenode representing a literal constant. */
     bool isLiteral() const {
         return isKind(PNK_NUMBER) ||
                isKind(PNK_STRING) ||
                isKind(PNK_TRUE) ||
                isKind(PNK_FALSE) ||
                isKind(PNK_NULL);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -91,16 +91,75 @@ GenerateBlockId(TokenStream &ts, ParseCo
 template <typename ParseHandler>
 static void
 PushStatementPC(ParseContext<ParseHandler> *pc, StmtInfoPC *stmt, StmtType type)
 {
     stmt->blockid = pc->blockid();
     PushStatement(pc, stmt, type);
 }
 
+template <>
+bool
+ParseContext<FullParseHandler>::checkLocalsOverflow(TokenStream &ts)
+{
+    if (vars_.length() + bodyLevelLexicals_.length() >= LOCALNO_LIMIT) {
+        ts.reportError(JSMSG_TOO_MANY_LOCALS);
+        return false;
+    }
+    return true;
+}
+
+static void
+MarkUsesAsHoistedLexical(ParseNode *pn)
+{
+    MOZ_ASSERT(pn->isDefn());
+
+    Definition *dn = (Definition *)pn;
+    ParseNode **pnup = &dn->dn_uses;
+    ParseNode *pnu;
+    unsigned start = pn->pn_blockid;
+
+    // In ES6, lexical bindings cannot be accessed until initialized.
+    // Distinguish hoisted uses as a different JSOp for easier compilation.
+    while ((pnu = *pnup) != nullptr && pnu->pn_blockid >= start) {
+        MOZ_ASSERT(pnu->isUsed());
+
+        // JavaScript is parsed in dominator order. This condition says to
+        // mark uses which either:
+        //
+        // 1) Is at the same dominator level.
+        //
+        //    This covers the case where the right hand side of declarations
+        //    cannot refer to the binding itself. e.g, |let x = x| is a
+        //    ReferenceError. Note that the use of 'x' follows the definition
+        //    node 'let x' in the program text.
+        //
+        // 2) Precedes the definition in the program text.
+        //
+        //    This covers all hoisted uses.
+        //
+        // The uses that are not covered by these two conditions are uses of
+        // the binding as free variables in function definitions on the right
+        // hand side of the binding node. e.g.,
+        //
+        //     let x = function () { x(); }
+        //
+        // does not mark the upvar use of 'x' inside the lambda as needing a
+        // TDZ check.
+        //
+        // N.B. This function expects to be called at the point of defining
+        // the lexical binding, and should not be called afterwards, as it
+        // would erroneously unmark hoisted function definitions and needing
+        // TDZ checks, which is currently handled in leaveFunction.
+        if (pnu->pn_blockid == start || pnu->pn_pos < pn->pn_pos)
+            pnu->pn_dflags |= PND_LET;
+        pnup = &pnu->pn_link;
+    }
+}
+
 // See comment on member function declaration.
 template <>
 bool
 ParseContext<FullParseHandler>::define(TokenStream &ts,
                                        HandlePropertyName name, ParseNode *pn, Definition::Kind kind)
 {
     JS_ASSERT(!pn->isUsed());
     JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
@@ -145,16 +204,17 @@ ParseContext<FullParseHandler>::define(T
     if (kind == Definition::CONST)
         pn->pn_dflags |= PND_CONST;
 
     Definition *dn = (Definition *)pn;
     switch (kind) {
       case Definition::ARG:
         JS_ASSERT(sc->isFunctionBox());
         dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETARG : JSOP_GETARG);
+        dn->pn_blockid = bodyid;
         dn->pn_dflags |= PND_BOUND;
         if (!dn->pn_cookie.set(ts, staticLevel, args_.length()))
             return false;
         if (!args_.append(dn))
             return false;
         if (args_.length() >= ARGNO_LIMIT) {
             ts.reportError(JSMSG_TOO_MANY_FUN_ARGS);
             return false;
@@ -164,47 +224,65 @@ ParseContext<FullParseHandler>::define(T
         if (!decls_.addUnique(name, dn))
             return false;
         break;
 
       case Definition::CONST:
       case Definition::VAR:
         if (sc->isFunctionBox()) {
             dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL);
+            dn->pn_blockid = bodyid;
             dn->pn_dflags |= PND_BOUND;
             if (!dn->pn_cookie.set(ts, staticLevel, vars_.length()))
                 return false;
             if (!vars_.append(dn))
                 return false;
-            if (vars_.length() >= LOCALNO_LIMIT) {
-                ts.reportError(JSMSG_TOO_MANY_LOCALS);
+            if (!checkLocalsOverflow(ts))
                 return false;
-            }
         }
         if (!decls_.addUnique(name, dn))
             return false;
         break;
 
       case Definition::LET:
-        dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL);
+        dn->setOp(JSOP_INITLEXICAL);
         dn->pn_dflags |= (PND_LET | PND_BOUND);
         JS_ASSERT(dn->pn_cookie.level() == staticLevel); /* see bindLet */
+        if (atBodyLevel()) {
+            if (!bodyLevelLexicals_.append(dn))
+                return false;
+            if (!checkLocalsOverflow(ts))
+                return false;
+        }
+
+        // In ES6, lexical bindings cannot be accessed until initialized. If
+        // the definition has existing uses, they need to be marked so that we
+        // emit dead zone checks.
+        MarkUsesAsHoistedLexical(pn);
+
         if (!decls_.addShadow(name, dn))
             return false;
         break;
 
       default:
         MOZ_CRASH("unexpected kind");
     }
 
     return true;
 }
 
 template <>
 bool
+ParseContext<SyntaxParseHandler>::checkLocalsOverflow(TokenStream &ts)
+{
+    return true;
+}
+
+template <>
+bool
 ParseContext<SyntaxParseHandler>::define(TokenStream &ts, HandlePropertyName name, Node pn,
                                          Definition::Kind kind)
 {
     JS_ASSERT(!decls_.lookupFirst(name));
 
     if (lexdeps.lookupDefn<SyntaxParseHandler>(name))
         lexdeps->remove(name);
 
@@ -273,16 +351,21 @@ static void
 AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec, Binding *dst)
 {
     for (size_t i = 0; i < vec.length(); ++i, ++dst) {
         Definition *dn = vec[i];
         PropertyName *name = dn->name();
 
         Binding::Kind kind;
         switch (dn->kind()) {
+          case Definition::LET:
+            // Treat body-level let declarations as var bindings by falling
+            // through. The fact that the binding is in fact a let declaration
+            // is reflected in the slot. All body-level lets go after the
+            // vars.
           case Definition::VAR:
             kind = Binding::VARIABLE;
             break;
           case Definition::CONST:
             kind = Binding::CONSTANT;
             break;
           case Definition::ARG:
             kind = Binding::ARGUMENT;
@@ -308,37 +391,48 @@ AppendPackedBindings(const ParseContext<
 template <typename ParseHandler>
 bool
 ParseContext<ParseHandler>::generateFunctionBindings(ExclusiveContext *cx, TokenStream &ts,
                                                      LifoAlloc &alloc,
                                                      InternalHandle<Bindings*> bindings) const
 {
     JS_ASSERT(sc->isFunctionBox());
     JS_ASSERT(args_.length() < ARGNO_LIMIT);
-    JS_ASSERT(vars_.length() < LOCALNO_LIMIT);
+    JS_ASSERT(vars_.length() + bodyLevelLexicals_.length() < LOCALNO_LIMIT);
 
     /*
      * Avoid pathological edge cases by explicitly limiting the total number of
      * bindings to what will fit in a uint32_t.
      */
-    if (UINT32_MAX - args_.length() <= vars_.length())
+    if (UINT32_MAX - args_.length() <= vars_.length() + bodyLevelLexicals_.length())
         return ts.reportError(JSMSG_TOO_MANY_LOCALS);
 
-    uint32_t count = args_.length() + vars_.length();
+    // Fix up the slots of body-level lets to come after the vars now that we
+    // know how many vars there are.
+    for (size_t i = 0; i < bodyLevelLexicals_.length(); i++) {
+        Definition *dn = bodyLevelLexicals_[i];
+        if (!dn->pn_cookie.set(ts, dn->pn_cookie.level(), vars_.length() + i))
+            return false;
+    }
+
+    uint32_t count = args_.length() + vars_.length() + bodyLevelLexicals_.length();
     Binding *packedBindings = alloc.newArrayUninitialized<Binding>(count);
     if (!packedBindings) {
         js_ReportOutOfMemory(cx);
         return false;
     }
 
     AppendPackedBindings(this, args_, packedBindings);
     AppendPackedBindings(this, vars_, packedBindings + args_.length());
+    AppendPackedBindings(this, bodyLevelLexicals_,
+                         packedBindings + args_.length() + vars_.length());
 
     return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
-                                              packedBindings, blockScopeDepth);
+                                              bodyLevelLexicals_.length(), blockScopeDepth,
+                                              packedBindings);
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
                                    unsigned errorNumber, va_list args)
 {
     bool result = false;
@@ -628,17 +722,18 @@ Parser<ParseHandler>::parse(JSObject *ch
                                         /* staticLevel = */ 0, /* bodyid = */ 0,
                                         /* blockScopeDepth = */ 0);
     if (!globalpc.init(tokenStream))
         return null();
 
     Node pn = statements();
     if (pn) {
         if (!tokenStream.matchToken(TOK_EOF)) {
-            report(ParseError, false, null(), JSMSG_SYNTAX_ERROR);
+            report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
+                   "script", TokenKindToDesc(tokenStream.peekToken()));
             return null();
         }
         if (foldConstants) {
             if (!FoldConstants(context, &pn, this))
                 return null();
         }
     }
     return pn;
@@ -746,17 +841,18 @@ Parser<FullParseHandler>::standaloneFunc
             return null();
     }
 
     ParseNode *pn = functionBody(Statement, StatementListBody);
     if (!pn)
         return null();
 
     if (!tokenStream.matchToken(TOK_EOF)) {
-        report(ParseError, false, null(), JSMSG_SYNTAX_ERROR);
+        report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
+               "function body", TokenKindToDesc(tokenStream.peekToken()));
         return null();
     }
 
     if (!FoldConstants(context, &pn, this))
         return null();
 
     InternalHandle<Bindings*> funboxBindings =
         InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
@@ -806,17 +902,20 @@ Parser<FullParseHandler>::checkFunctionA
     }
 
     /*
      * Report error if both rest parameters and 'arguments' are used. Do this
      * check before adding artificial 'arguments' below.
      */
     Definition *maybeArgDef = pc->decls().lookupFirst(arguments);
     bool argumentsHasBinding = !!maybeArgDef;
-    bool argumentsHasLocalBinding = maybeArgDef && maybeArgDef->kind() != Definition::ARG;
+    // ES6 9.2.13.17 says that a lexical binding of 'arguments' shadows the
+    // arguments object.
+    bool argumentsHasLocalBinding = maybeArgDef && (maybeArgDef->kind() != Definition::ARG &&
+                                                    maybeArgDef->kind() != Definition::LET);
     bool hasRest = pc->sc->asFunctionBox()->function()->hasRest();
     if (hasRest && argumentsHasLocalBinding) {
         report(ParseError, false, nullptr, JSMSG_ARGUMENTS_AND_REST);
         return false;
     }
 
     /*
      * Even if 'arguments' isn't explicitly mentioned, dynamic name lookup
@@ -970,18 +1069,22 @@ Parser<ParseHandler>::functionBody(Funct
         return null();
 
     return pn;
 }
 
 /* See comment for use in Parser::functionDef. */
 template <>
 bool
-Parser<FullParseHandler>::makeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom)
-{
+Parser<FullParseHandler>::makeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom,
+                                         bool *pbodyLevelHoistedUse)
+{
+    // See comment in addFreeVariablesFromLazyFunction.
+    *pbodyLevelHoistedUse = !!dn->dn_uses;
+
     /* Turn pn into a definition. */
     pc->updateDecl(atom, pn);
 
     /* Change all uses of dn to be uses of pn. */
     for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
         JS_ASSERT(pnu->isUsed());
         JS_ASSERT(!pnu->isDefn());
         pnu->pn_lexdef = (Definition *) pn;
@@ -1067,22 +1170,22 @@ struct BindData
 
     struct LetData {
         explicit LetData(ExclusiveContext *cx) : blockObj(cx) {}
         VarContext varContext;
         RootedStaticBlockObject blockObj;
         unsigned   overflow;
     } let;
 
-    void initLet(VarContext varContext, StaticBlockObject &blockObj, unsigned overflow) {
+    void initLet(VarContext varContext, StaticBlockObject *blockObj, unsigned overflow) {
         this->pn = ParseHandler::null();
-        this->op = JSOP_NOP;
+        this->op = JSOP_INITLEXICAL;
         this->binder = Parser<ParseHandler>::bindLet;
         this->let.varContext = varContext;
-        this->let.blockObj = &blockObj;
+        this->let.blockObj = blockObj;
         this->let.overflow = overflow;
     }
 
     void initVarOrConst(JSOp op) {
         this->op = op;
         this->binder = Parser<ParseHandler>::bindVarOrConst;
     }
 };
@@ -1184,17 +1287,17 @@ ConvertDefinitionToNamedLambdaUse(TokenS
  * Beware: this function is called for functions nested in other functions or
  * global scripts but not for functions compiled through the Function
  * constructor or JSAPI. To always execute code when a function has finished
  * parsing, use Parser::functionBody.
  */
 template <>
 bool
 Parser<FullParseHandler>::leaveFunction(ParseNode *fn, ParseContext<FullParseHandler> *outerpc,
-                                        FunctionSyntaxKind kind)
+                                        bool bodyLevelHoistedUse, FunctionSyntaxKind kind)
 {
     outerpc->blockidGen = pc->blockidGen;
 
     FunctionBox *funbox = fn->pn_funbox;
     JS_ASSERT(funbox == pc->sc->asFunctionBox());
 
     /* Propagate unresolved lexical names up to outerpc->lexdeps. */
     if (pc->lexdeps->count()) {
@@ -1256,16 +1359,39 @@ Parser<FullParseHandler>::leaveFunction(
              * when leaving the inner function.
              *
              * The dn == outer_dn case arises with generator expressions
              * (see LegacyCompExprTransplanter::transplant, the PN_CODE/PN_NAME
              * case), and nowhere else, currently.
              */
             if (dn != outer_dn) {
                 if (ParseNode *pnu = dn->dn_uses) {
+                    // In ES6, lexical bindings cannot be accessed until
+                    // initialized. If we are parsing a function with a
+                    // hoisted body-level use, all free variables that get
+                    // linked to an outer 'let' binding need to be marked as
+                    // needing dead zone checks. e.g.,
+                    //
+                    // function outer() {
+                    //   inner();
+                    //   function inner() { use(x); }
+                    //   let x;
+                    // }
+                    //
+                    // The use of 'x' inside 'inner' needs to be marked.
+                    if (bodyLevelHoistedUse && outer_dn->isLet()) {
+                        while (true) {
+                            pnu->pn_dflags |= PND_LET;
+                            if (!pnu->pn_link)
+                                break;
+                            pnu = pnu->pn_link;
+                        }
+                        pnu = dn->dn_uses;
+                    }
+
                     while (true) {
                         pnu->pn_lexdef = outer_dn;
                         if (!pnu->pn_link)
                             break;
                         pnu = pnu->pn_link;
                     }
                     pnu->pn_link = outer_dn->dn_uses;
                     outer_dn->dn_uses = dn->dn_uses;
@@ -1283,22 +1409,22 @@ Parser<FullParseHandler>::leaveFunction(
     InternalHandle<Bindings*> bindings =
         InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
     return pc->generateFunctionBindings(context, tokenStream, alloc, bindings);
 }
 
 template <>
 bool
 Parser<SyntaxParseHandler>::leaveFunction(Node fn, ParseContext<SyntaxParseHandler> *outerpc,
-                                          FunctionSyntaxKind kind)
+                                          bool bodyLevelHoistedUse, FunctionSyntaxKind kind)
 {
     outerpc->blockidGen = pc->blockidGen;
 
     FunctionBox *funbox = pc->sc->asFunctionBox();
-    return addFreeVariablesFromLazyFunction(funbox->function(), outerpc);
+    return addFreeVariablesFromLazyFunction(funbox->function(), outerpc, bodyLevelHoistedUse);
 }
 
 /*
  * defineArg is called for both the arguments of a regular function definition
  * and the arguments specified by the Function constructor.
  *
  * The 'disallowDuplicateArgs' bool indicates whether the use of another
  * feature (destructuring or default arguments) disables duplicate arguments.
@@ -1559,38 +1685,42 @@ Parser<ParseHandler>::functionArguments(
 
     return true;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
                                                   ParseNode **pn_, FunctionSyntaxKind kind,
-                                                  bool *pbodyProcessed)
+                                                  bool *pbodyProcessed,
+                                                  bool *pbodyLevelHoistedUse)
 {
     ParseNode *&pn = *pn_;
     *pbodyProcessed = false;
+    *pbodyLevelHoistedUse = false;
 
     /* Function statements add a binding to the enclosing scope. */
     bool bodyLevel = pc->atBodyLevel();
 
     if (kind == Statement) {
         /*
          * Handle redeclaration and optimize cases where we can statically bind the
          * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
          */
         if (Definition *dn = pc->decls().lookupFirst(funName)) {
             JS_ASSERT(!dn->isUsed());
             JS_ASSERT(dn->isDefn());
 
-            if (options().extraWarningsOption || dn->kind() == Definition::CONST) {
+            bool throwRedeclarationError = dn->kind() == Definition::CONST ||
+                                           dn->kind() == Definition::LET;
+            if (options().extraWarningsOption || throwRedeclarationError) {
                 JSAutoByteString name;
-                ParseReportKind reporter = (dn->kind() != Definition::CONST)
-                                           ? ParseExtraWarning
-                                           : ParseError;
+                ParseReportKind reporter = throwRedeclarationError
+                                           ? ParseError
+                                           : ParseExtraWarning;
                 if (!AtomToPrintableString(context, funName, &name) ||
                     !report(reporter, false, nullptr, JSMSG_REDECLARED_VAR,
                             Definition::kindString(dn->kind()), name.ptr()))
                 {
                     return false;
                 }
             }
 
@@ -1609,17 +1739,17 @@ Parser<FullParseHandler>::checkFunctionD
                     // remains a definition. But change the function node pn so
                     // that it knows where the argument is located.
                     pn->setOp(JSOP_GETARG);
                     pn->setDefn(true);
                     pn->pn_cookie = dn->pn_cookie;
                     pn->pn_dflags |= PND_BOUND;
                     dn->markAsAssigned();
                 } else {
-                    if (!makeDefIntoUse(dn, pn, funName))
+                    if (!makeDefIntoUse(dn, pn, funName, pbodyLevelHoistedUse))
                         return false;
                 }
             }
         } else if (bodyLevel) {
             /*
              * If this function was used before it was defined, claim the
              * pre-created definition node for this function that primaryExpr
              * put in pc->lexdeps on first forward reference, and recycle pn.
@@ -1632,16 +1762,18 @@ Parser<FullParseHandler>::checkFunctionD
                 fn->pn_pos.end = pn->pn_pos.end;
 
                 fn->pn_body = nullptr;
                 fn->pn_cookie.makeFree();
 
                 pc->lexdeps->remove(funName);
                 handler.freeTree(pn);
                 pn = fn;
+
+                *pbodyLevelHoistedUse = true;
             }
 
             if (!pc->define(tokenStream, funName, pn, Definition::VAR))
                 return false;
         }
 
         if (bodyLevel) {
             JS_ASSERT(pn->functionIsHoisted());
@@ -1700,17 +1832,17 @@ Parser<FullParseHandler>::checkFunctionD
     if (LazyScript *lazyOuter = handler.lazyOuterFunction()) {
         JSFunction *fun = handler.nextLazyInnerFunction();
         JS_ASSERT(!fun->isLegacyGenerator());
         FunctionBox *funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false),
                                              fun->generatorKind());
         if (!funbox)
             return false;
 
-        if (!addFreeVariablesFromLazyFunction(fun, pc))
+        if (!addFreeVariablesFromLazyFunction(fun, pc, *pbodyLevelHoistedUse))
             return false;
 
         // The position passed to tokenStream.advance() is relative to
         // userbuf.base() while LazyScript::{begin,end} offsets are relative to
         // the outermost script source. N.B: userbuf.base() is initialized
         // (in TokenStream()) to begin() - column() so that column numbers in
         // the lazily parsed script are correct.
         uint32_t userbufBase = lazyOuter->begin() - lazyOuter->column();
@@ -1731,53 +1863,69 @@ PropagateTransitiveParseFlags(const T *i
      outer->setBindingsAccessedDynamically();
    if (inner->hasDebuggerStatement())
      outer->setHasDebuggerStatement();
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::addFreeVariablesFromLazyFunction(JSFunction *fun,
-                                                       ParseContext<ParseHandler> *pc)
-{
+                                                       ParseContext<ParseHandler> *pc,
+                                                       bool bodyLevelHoistedUse)
+{
+    MOZ_ASSERT_IF(bodyLevelHoistedUse, fun->displayAtom() && pc->atBodyLevel());
+
     // Update any definition nodes in this context according to free variables
     // in a lazily parsed inner function.
 
     LazyScript *lazy = fun->lazyScript();
-    HeapPtrAtom *freeVariables = lazy->freeVariables();
+    LazyScript::FreeVariable *freeVariables = lazy->freeVariables();
     for (size_t i = 0; i < lazy->numFreeVariables(); i++) {
-        JSAtom *atom = freeVariables[i];
+        JSAtom *atom = freeVariables[i].atom();
 
         // 'arguments' will be implicitly bound within the inner function.
         if (atom == context->names().arguments)
             continue;
 
         DefinitionNode dn = pc->decls().lookupFirst(atom);
 
         if (!dn) {
             dn = getOrCreateLexicalDependency(pc, atom);
             if (!dn)
                 return false;
         }
 
+        // In ES6, lexical bindings are unaccessible before initialization. If
+        // the inner function closes over a placeholder definition, we need to
+        // mark the variable as maybe needing a dead zone check when we emit
+        // bytecode.
+        //
+        // Note that body-level function declaration statements are always
+        // hoisted to the top, so all accesses to free let variables need the
+        // dead zone check.
+        if (handler.isPlaceholderDefinition(dn) || bodyLevelHoistedUse)
+            freeVariables[i].setIsHoistedUse();
+
         /* Mark the outer dn as escaping. */
         handler.setFlag(handler.getDefinitionNode(dn), PND_CLOSED);
     }
 
     PropagateTransitiveParseFlags(lazy, pc->sc);
     return true;
 }
 
 template <>
 bool
 Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
                                                     Node *pn, FunctionSyntaxKind kind,
-                                                    bool *pbodyProcessed)
+                                                    bool *pbodyProcessed,
+                                                    bool *pbodyLevelHoistedUse)
 {
     *pbodyProcessed = false;
+    *pbodyLevelHoistedUse = false;
 
     /* Function statements add a binding to the enclosing scope. */
     bool bodyLevel = pc->atBodyLevel();
 
     if (kind == Statement) {
         /*
          * Handle redeclaration and optimize cases where we can statically bind the
          * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
@@ -1788,18 +1936,20 @@ Parser<SyntaxParseHandler>::checkFunctio
                 if (!AtomToPrintableString(context, funName, &name) ||
                     !report(ParseError, false, null(), JSMSG_REDECLARED_VAR,
                             Definition::kindString(dn), name.ptr()))
                 {
                     return false;
                 }
             }
         } else if (bodyLevel) {
-            if (pc->lexdeps.lookupDefn<SyntaxParseHandler>(funName))
+            if (pc->lexdeps.lookupDefn<SyntaxParseHandler>(funName)) {
+                *pbodyLevelHoistedUse = true;
                 pc->lexdeps->remove(funName);
+            }
 
             if (!pc->define(tokenStream, funName, *pn, Definition::VAR))
                 return false;
         }
 
         if (!bodyLevel && funName == context->names().arguments)
             pc->sc->setBindingsAccessedDynamically();
     }
@@ -1888,17 +2038,18 @@ Parser<ParseHandler>::functionDef(Handle
     JS_ASSERT_IF(kind == Statement, funName);
 
     /* Make a TOK_FUNCTION node. */
     Node pn = handler.newFunctionDefinition();
     if (!pn)
         return null();
 
     bool bodyProcessed;
-    if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed))
+    bool bodyLevelHoistedUse;
+    if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed, &bodyLevelHoistedUse))
         return null();
 
     if (bodyProcessed)
         return pn;
 
     RootedObject proto(context);
     if (generatorKind == StarGenerator) {
         // If we are off the main thread, the generator meta-objects have
@@ -1916,17 +2067,18 @@ Parser<ParseHandler>::functionDef(Handle
     // Speculatively parse using the directives of the parent parsing context.
     // If a directive is encountered (e.g., "use strict") that changes how the
     // function should have been parsed, we backup and reparse with the new set
     // of directives.
     Directives directives(pc);
     Directives newDirectives = directives;
 
     while (true) {
-        if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives))
+        if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives,
+                                bodyLevelHoistedUse))
             break;
         if (tokenStream.hadError() || directives == newDirectives)
             return null();
 
         // Assignment must be monotonic to prevent reparsing iloops
         JS_ASSERT_IF(directives.strict(), newDirectives.strict());
         JS_ASSERT_IF(directives.asmJS(), newDirectives.asmJS());
         directives = newDirectives;
@@ -2007,20 +2159,20 @@ Parser<SyntaxParseHandler>::finishFuncti
 
     RootedFunction fun(context, funbox->function());
     LazyScript *lazy = LazyScript::CreateRaw(context, fun, numFreeVariables, numInnerFunctions,
                                              versionNumber(), funbox->bufStart, funbox->bufEnd,
                                              funbox->startLine, funbox->startColumn);
     if (!lazy)
         return false;
 
-    HeapPtrAtom *freeVariables = lazy->freeVariables();
+    LazyScript::FreeVariable *freeVariables = lazy->freeVariables();
     size_t i = 0;
     for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront())
-        freeVariables[i++].init(r.front().key());
+        freeVariables[i++] = LazyScript::FreeVariable(r.front().key());
     JS_ASSERT(i == numFreeVariables);
 
     HeapPtrFunction *innerFunctions = lazy->innerFunctions();
     for (size_t i = 0; i < numInnerFunctions; i++)
         innerFunctions[i].init(pc->innerFunctions[i]);
 
     if (pc->sc->strict)
         lazy->setStrict();
@@ -2034,17 +2186,18 @@ Parser<SyntaxParseHandler>::finishFuncti
 }
 
 template <>
 bool
 Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
                                               FunctionType type, FunctionSyntaxKind kind,
                                               GeneratorKind generatorKind,
                                               Directives inheritedDirectives,
-                                              Directives *newDirectives)
+                                              Directives *newDirectives,
+                                              bool bodyLevelHoistedUse)
 {
     ParseContext<FullParseHandler> *outerpc = pc;
 
     // Create box for fun->object early to protect against last-ditch GC.
     FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
     if (!funbox)
         return false;
 
@@ -2058,18 +2211,17 @@ Parser<FullParseHandler>::functionArgsAn
             // Move the syntax parser to the current position in the stream.
             TokenStream::Position position(keepAtoms);
             tokenStream.tell(&position);
             if (!parser->tokenStream.seek(position, tokenStream))
                 return false;
 
             ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(), funbox,
                                                    newDirectives, outerpc->staticLevel + 1,
-                                                   outerpc->blockidGen,
-