Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 07 Jun 2013 11:10:54 -0400
changeset 145852 6f32011a27ef12dd162731471d05e8eaea412c0c
parent 145764 c41a3e24a574377f2d443a7783c4a2011c413f1b (current diff)
parent 145851 0261df8a6a8eea809d5b065a11fbb35d33ddbfd4 (diff)
child 145853 6cafe68983ca4945a7d50bda6b345b3522c4c5d3
child 145856 47aba2f7bd778f111b1f7a3540e767b54de849dc
child 145869 18e3ca7c212bce0533a6a9c1d87de4e6aef01d84
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone24.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 inbound to m-c.
b2g/config/panda-gaia-central/README
b2g/config/panda-gaia-central/config.json
b2g/config/panda-gaia-central/releng-pandaboard.tt
js/src/jsprobes.cpp
js/src/jsprobes.h
layout/reftests/flexbox/flexbox-align-self-baseline-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-baseline-horiz-1.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-1-block.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-1-table.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-2-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-2.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-3-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-3.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-4-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-4.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-5-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-horiz-5.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-1-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-1.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-2-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-2.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-3-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-3.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-4-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-4.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-rtl-1-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-rtl-1.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-rtl-2-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-rtl-2.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-rtl-3-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-rtl-3.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-rtl-4-ref.xhtml
layout/reftests/flexbox/flexbox-align-self-vert-rtl-4.xhtml
layout/reftests/flexbox/flexbox-baseline-align-self-baseline-horiz-1-ref.html
layout/reftests/flexbox/flexbox-baseline-align-self-baseline-horiz-1.html
layout/reftests/flexbox/flexbox-baseline-align-self-baseline-vert-1-ref.html
layout/reftests/flexbox/flexbox-baseline-align-self-baseline-vert-1.html
layout/reftests/flexbox/flexbox-baseline-empty-1-ref.html
layout/reftests/flexbox/flexbox-baseline-empty-1a.html
layout/reftests/flexbox/flexbox-baseline-empty-1b.html
layout/reftests/flexbox/flexbox-baseline-multi-item-horiz-1-ref.html
layout/reftests/flexbox/flexbox-baseline-multi-item-horiz-1.html
layout/reftests/flexbox/flexbox-baseline-multi-item-vert-1-ref.html
layout/reftests/flexbox/flexbox-baseline-multi-item-vert-1.html
layout/reftests/flexbox/flexbox-baseline-single-item-1-ref.html
layout/reftests/flexbox/flexbox-baseline-single-item-1a.html
layout/reftests/flexbox/flexbox-baseline-single-item-1b.html
layout/reftests/flexbox/flexbox-basic-block-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-block-horiz-1.xhtml
layout/reftests/flexbox/flexbox-basic-block-vert-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-block-vert-1.xhtml
layout/reftests/flexbox/flexbox-basic-canvas-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-canvas-horiz-1.xhtml
layout/reftests/flexbox/flexbox-basic-canvas-vert-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-canvas-vert-1.xhtml
layout/reftests/flexbox/flexbox-basic-fieldset-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-fieldset-horiz-1.xhtml
layout/reftests/flexbox/flexbox-basic-fieldset-vert-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-fieldset-vert-1.xhtml
layout/reftests/flexbox/flexbox-basic-iframe-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-iframe-horiz-1.xhtml
layout/reftests/flexbox/flexbox-basic-iframe-vert-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-iframe-vert-1.xhtml
layout/reftests/flexbox/flexbox-basic-img-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-img-horiz-1.xhtml
layout/reftests/flexbox/flexbox-basic-img-vert-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-img-vert-1.xhtml
layout/reftests/flexbox/flexbox-basic-textarea-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-textarea-horiz-1.xhtml
layout/reftests/flexbox/flexbox-basic-textarea-vert-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-textarea-vert-1.xhtml
layout/reftests/flexbox/flexbox-basic-video-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-video-horiz-1.xhtml
layout/reftests/flexbox/flexbox-basic-video-vert-1-ref.xhtml
layout/reftests/flexbox/flexbox-basic-video-vert-1.xhtml
layout/reftests/flexbox/flexbox-items-as-stacking-contexts-1-ref.xhtml
layout/reftests/flexbox/flexbox-items-as-stacking-contexts-1.xhtml
layout/reftests/flexbox/flexbox-items-as-stacking-contexts-2-ref.html
layout/reftests/flexbox/flexbox-items-as-stacking-contexts-2.html
layout/reftests/flexbox/flexbox-items-as-stacking-contexts-3-ref.html
layout/reftests/flexbox/flexbox-items-as-stacking-contexts-3.html
layout/reftests/flexbox/flexbox-justify-content-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-justify-content-horiz-1.xhtml
layout/reftests/flexbox/flexbox-justify-content-horiz-2-ref.xhtml
layout/reftests/flexbox/flexbox-justify-content-horiz-2.xhtml
layout/reftests/flexbox/flexbox-justify-content-horiz-3-ref.xhtml
layout/reftests/flexbox/flexbox-justify-content-horiz-3.xhtml
layout/reftests/flexbox/flexbox-justify-content-horiz-4-ref.xhtml
layout/reftests/flexbox/flexbox-justify-content-horiz-4.xhtml
layout/reftests/flexbox/flexbox-justify-content-horiz-5-ref.xhtml
layout/reftests/flexbox/flexbox-justify-content-horiz-5.xhtml
layout/reftests/flexbox/flexbox-justify-content-vert-1-ref.xhtml
layout/reftests/flexbox/flexbox-justify-content-vert-1.xhtml
layout/reftests/flexbox/flexbox-justify-content-vert-2-ref.xhtml
layout/reftests/flexbox/flexbox-justify-content-vert-2.xhtml
layout/reftests/flexbox/flexbox-justify-content-vert-3-ref.xhtml
layout/reftests/flexbox/flexbox-justify-content-vert-3.xhtml
layout/reftests/flexbox/flexbox-justify-content-vert-4-ref.xhtml
layout/reftests/flexbox/flexbox-justify-content-vert-4.xhtml
layout/reftests/flexbox/flexbox-justify-content-vert-5-ref.xhtml
layout/reftests/flexbox/flexbox-justify-content-vert-5.xhtml
layout/reftests/flexbox/flexbox-margin-auto-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-margin-auto-horiz-1.xhtml
layout/reftests/flexbox/flexbox-margin-auto-horiz-2-ref.xhtml
layout/reftests/flexbox/flexbox-margin-auto-horiz-2.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-1-reverse-ref.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-1-reverse.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-1-rtl-reverse.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-1-rtl.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-1.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-2-ref.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-2a.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-2b.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-3-ref.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-3-reverse-ref.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-3-reverse.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-3.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-4-ref.xhtml
layout/reftests/flexbox/flexbox-mbp-horiz-4.xhtml
layout/reftests/flexbox/flexbox-overflow-horiz-1-ref.html
layout/reftests/flexbox/flexbox-overflow-horiz-1.html
layout/reftests/flexbox/flexbox-overflow-horiz-2-ref.html
layout/reftests/flexbox/flexbox-overflow-horiz-2.html
layout/reftests/flexbox/flexbox-overflow-horiz-3-ref.html
layout/reftests/flexbox/flexbox-overflow-horiz-3.html
layout/reftests/flexbox/flexbox-overflow-vert-1-ref.html
layout/reftests/flexbox/flexbox-overflow-vert-1.html
layout/reftests/flexbox/flexbox-overflow-vert-2-ref.html
layout/reftests/flexbox/flexbox-overflow-vert-2.html
layout/reftests/flexbox/flexbox-overflow-vert-3-ref.html
layout/reftests/flexbox/flexbox-overflow-vert-3.html
layout/reftests/flexbox/flexbox-paint-ordering-1-ref.xhtml
layout/reftests/flexbox/flexbox-paint-ordering-1.xhtml
layout/reftests/flexbox/flexbox-paint-ordering-2-ref.xhtml
layout/reftests/flexbox/flexbox-paint-ordering-2.xhtml
layout/reftests/flexbox/flexbox-sizing-horiz-1-ref.xhtml
layout/reftests/flexbox/flexbox-sizing-horiz-1.xhtml
layout/reftests/flexbox/flexbox-sizing-horiz-2-ref.xhtml
layout/reftests/flexbox/flexbox-sizing-horiz-2.xhtml
layout/reftests/flexbox/flexbox-sizing-vert-1-ref.xhtml
layout/reftests/flexbox/flexbox-sizing-vert-1.xhtml
layout/reftests/flexbox/flexbox-sizing-vert-2-ref.xhtml
layout/reftests/flexbox/flexbox-sizing-vert-2.xhtml
layout/reftests/flexbox/flexbox-table-fixup-1-ref.xhtml
layout/reftests/flexbox/flexbox-table-fixup-1a.xhtml
layout/reftests/flexbox/flexbox-table-fixup-1b.xhtml
layout/reftests/flexbox/flexbox-whitespace-handling-1-ref.xhtml
layout/reftests/flexbox/flexbox-whitespace-handling-1a.xhtml
layout/reftests/flexbox/flexbox-whitespace-handling-1b.xhtml
layout/reftests/flexbox/flexbox-whitespace-handling-2-ref.xhtml
layout/reftests/flexbox/flexbox-whitespace-handling-2.xhtml
layout/reftests/flexbox/flexbox-with-pseudo-elements-1-ref.html
layout/reftests/flexbox/flexbox-with-pseudo-elements-1.html
layout/reftests/flexbox/flexbox-with-pseudo-elements-2-ref.html
layout/reftests/flexbox/flexbox-with-pseudo-elements-2.html
layout/reftests/flexbox/flexbox-with-pseudo-elements-3-ref.html
layout/reftests/flexbox/flexbox-with-pseudo-elements-3.html
testing/marionette/marionette-actors.js
--- a/CLOBBER
+++ b/CLOBBER
@@ -12,9 +12,9 @@
 #          O               O
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
-Bug 875929 removed a file from js/src/moz.build and apparently the build system didn't notice.
+Bug 879831 needed to clobber for the removal of jsprobes.cpp
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -548,20 +548,17 @@ pref("javascript.options.mem.log", false
 pref("javascript.options.mem.gc_incremental_slice_ms", 30);
 
 pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 150);
 pref("javascript.options.mem.gc_high_frequency_heap_growth_min", 120);
 pref("javascript.options.mem.gc_high_frequency_high_limit_mb", 40);
 pref("javascript.options.mem.gc_high_frequency_low_limit_mb", 10);
 pref("javascript.options.mem.gc_low_frequency_heap_growth", 120);
 pref("javascript.options.mem.high_water_mark", 6);
-pref("javascript.options.mem.gc_allocation_threshold_mb", 3);
-
-// Allocation Threshold for workers
-pref("dom.workers.mem.gc_allocation_threshold_mb", 3);
+pref("javascript.options.mem.gc_allocation_threshold_mb", 1);
 
 // Show/Hide scrollbars when active/inactive
 pref("ui.showHideScrollbars", 1);
 
 // Enable the ProcessPriorityManager, and give processes with no visible
 // documents a 1s grace period before they're eligible to be marked as
 // background.
 pref("dom.ipc.processPriorityManager.enabled", true);
deleted file mode 120000
--- a/b2g/config/panda-gaia-central/README
+++ /dev/null
@@ -1,1 +0,0 @@
-../panda/README
\ No newline at end of file
deleted file mode 100644
--- a/b2g/config/panda-gaia-central/config.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-    "config_version": 1,
-    "tooltool_manifest": "releng-pandaboard.tt",
-    "mock_target": "mozilla-centos6-i386",
-    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel"],
-    "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
-    "build_targets": ["boottarball", "systemtarball", "userdatatarball", "package-tests"],
-    "upload_files": [
-        "{workdir}/out/target/product/panda/*.tar.bz2",
-        "{workdir}/out/target/product/panda/tests/*.zip",
-        "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
-        "{srcdir}/b2g/config/panda/README",
-        "{workdir}/sources.xml"
-    ],
-    "gecko_l10n_root": "http://hg.mozilla.org/l10n-central",
-    "gaia": {
-        "vcs": "hgtool",
-        "repo": "http://hg.mozilla.org/integration/gaia-central",
-        "l10n": {
-            "vcs": "hgtool",
-            "root": "http://hg.mozilla.org/gaia-l10n"
-        }
-    },
-    "upload_platform": "panda_gaia_central"
-}
deleted file mode 120000
--- a/b2g/config/panda-gaia-central/releng-pandaboard.tt
+++ /dev/null
@@ -1,1 +0,0 @@
-../panda/releng-pandaboard.tt
\ No newline at end of file
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -388,17 +388,21 @@ pref("browser.link.open_newwindow", 3);
 // 1-3: see browser.link.open_newwindow for interpretation
 pref("browser.link.open_newwindow.override.external", -1);
 
 // 0: no restrictions - divert everything
 // 1: don't divert window.open at all
 // 2: don't divert window.open with features
 pref("browser.link.open_newwindow.restriction", 2);
 
-// Disable opening a new window via window.open if browser is in fullscreen mode
+// If true, this pref causes windows opened by window.open to be forced into new
+// tabs (rather than potentially opening separate windows, depending on
+// window.open arguments) when the browser is in fullscreen mode.
+// We set this differently on Mac because the fullscreen implementation there is
+// different.
 #ifdef XP_MACOSX
 pref("browser.link.open_newwindow.disabled_in_fullscreen", true);
 #else
 pref("browser.link.open_newwindow.disabled_in_fullscreen", false);
 #endif
 
 // Tabbed browser
 pref("browser.tabs.closeWindowWithLastTab", true);
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -427,24 +427,32 @@ var FullZoom = {
    * captured state is no longer current, then the zoom should not be changed.
    * Doing so would either change the zoom of the wrong tab or clobber an
    * earlier zoom change that occurred after the operation started.
    *
    * @param browser  The browser associated with the state.  If not given, the
    *                 currently selected browser is used.
    */
   _getState: function FullZoom__getState(browser) {
-    let browser = browser || gBrowser.selectedBrowser;
-    return { uri: browser.currentURI, token: this._zoomChangeToken };
+    browser = browser || gBrowser.selectedBrowser;
+    return {
+      // Due to async content pref service callbacks, this method can get called
+      // after the window has closed, so gBrowser.selectedBrowser may be null.
+      uri: browser ? browser.currentURI : null,
+      token: this._zoomChangeToken,
+     };
   },
 
   /**
    * Returns true if the given state is current.
    */
   _isStateCurrent: function FullZoom__isStateCurrent(state) {
+    // If either state has no URI, then the given state can't be current.
+    // currState.uri will be null when this method is called after the window
+    // has closed, which can happen due to async content pref service callbacks.
     let currState = this._getState();
     return currState.token === state.token &&
            currState.uri && state.uri &&
            this._cps2.extractDomain(currState.uri.spec) ==
              this._cps2.extractDomain(state.uri.spec);
   },
 
   _ensureValid: function FullZoom__ensureValid(aValue) {
--- a/browser/metro/base/content/contenthandlers/FindHandler.js
+++ b/browser/metro/base/content/contenthandlers/FindHandler.js
@@ -35,16 +35,19 @@ var FindHandler = {
         break;
     }
 
     if (findResult == Ci.nsITypeAheadFind.FIND_NOTFOUND) {
       sendAsyncMessage("FindAssist:Show", { rect: null , result: findResult });
       return;
     }
 
+    if (!this._fastFind.currentWindow)
+      return;
+
     let selection = this._fastFind.currentWindow.getSelection();
     if (!selection.rangeCount || selection.isCollapsed) {
       // The selection can be into an input or a textarea element
       let nodes = content.document.querySelectorAll("input[type='text'], textarea");
       for (let i = 0; i < nodes.length; i++) {
         let node = nodes[i];
         if (node instanceof Ci.nsIDOMNSEditableElement && node.editor) {
           selection = node.editor.selectionController.getSelection(Ci.nsISelectionController.SELECTION_NORMAL);
--- a/browser/metro/base/content/helperui/FindHelperUI.js
+++ b/browser/metro/base/content/helperui/FindHelperUI.js
@@ -1,13 +1,17 @@
 // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
 /* 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/. */
 
+/* We don't support zooming yet, disable Animated zoom by clamping it to the default zoom. */
+const kBrowserFindZoomLevelMin = 1;
+const kBrowserFindZoomLevelMax = 1;
+
 var FindHelperUI = {
   type: "find",
   commands: {
     next: "cmd_findNext",
     previous: "cmd_findPrevious",
     close: "cmd_findClose"
   },
 
@@ -170,18 +174,18 @@ var FindHelperUI = {
     if (!aElementRect || !autozoomEnabled)
       return;
 
     if (Browser.selectedTab.allowZoom) {
       let zoomLevel = Browser._getZoomLevelForRect(aElementRect);
 
       // Clamp the zoom level relatively to the default zoom level of the page
       let defaultZoomLevel = Browser.selectedTab.getDefaultZoomLevel();
-      zoomLevel = Util.clamp(zoomLevel, (defaultZoomLevel * kBrowserFormZoomLevelMin),
-                                        (defaultZoomLevel * kBrowserFormZoomLevelMax));
+      zoomLevel = Util.clamp(zoomLevel, (defaultZoomLevel * kBrowserFindZoomLevelMin),
+                                        (defaultZoomLevel * kBrowserFindZoomLevelMax));
       zoomLevel = Browser.selectedTab.clampZoomLevel(zoomLevel);
 
       let zoomRect = Browser._getZoomRectForPoint(aElementRect.center().x, aElementRect.y, zoomLevel);
       AnimatedZoom.animateTo(zoomRect);
     } else {
       // Even if zooming is disabled we could need to reposition the view in
       // order to keep the element on-screen
       let zoomRect = Browser._getZoomRectForPoint(aElementRect.center().x, aElementRect.y, getBrowser().scale);
--- a/browser/metro/base/content/helperui/FormHelperUI.js
+++ b/browser/metro/base/content/helperui/FormHelperUI.js
@@ -3,19 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * Responsible for filling in form information.
  *  - displays select popups
  *  - Provides autocomplete box for input fields.
  */
 
-const kBrowserFormZoomLevelMin = 0.8;
-const kBrowserFormZoomLevelMax = 2.0;
-
 var FormHelperUI = {
   _debugEvents: false,
   _currentBrowser: null,
   _currentElement: null,
   _currentCaretRect: null,
   _currentElementRect: null,
   _open: false,
 
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -657,16 +657,21 @@ nsRange::ContentRemoved(nsIDocument* aDo
     if (aIndexInContainer < mEndOffset) {
       --mEndOffset;
     }
   }
   else if (nsContentUtils::ContentIsDescendantOf(mEndParent, aChild)) {
     gravitateEnd = true;
   }
 
+  if (!mEnableGravitationOnElementRemoval) {
+    // Do not gravitate.
+    return;
+  }
+
   if (gravitateStart || gravitateEnd) {
     DoSetRange(gravitateStart ? container : mStartParent.get(),
                gravitateStart ? aIndexInContainer : mStartOffset,
                gravitateEnd ? container : mEndParent.get(),
                gravitateEnd ? aIndexInContainer : mEndOffset,
                mRoot);
   }
   if (container->IsSelectionDescendant() &&
--- a/content/base/src/nsRange.h
+++ b/content/base/src/nsRange.h
@@ -43,16 +43,17 @@ public:
     , mStartOffset(0)
     , mEndOffset(0)
     , mIsPositioned(false)
     , mIsDetached(false)
     , mMaySpanAnonymousSubtrees(false)
     , mInSelection(false)
     , mStartOffsetWasIncremented(false)
     , mEndOffsetWasIncremented(false)
+    , mEnableGravitationOnElementRemoval(true)
 #ifdef DEBUG
     , mAssertNextInsertOrAppendIndex(-1)
     , mAssertNextInsertOrAppendNode(nullptr)
 #endif
   {
     SetIsDOMBinding();
     MOZ_ASSERT(aNode, "range isn't in a document!");
     mOwner = aNode->OwnerDoc();
@@ -67,16 +68,30 @@ public:
                               nsIDOMRange** aRange);
   static nsresult CreateRange(nsINode* aStartParent, int32_t aStartOffset,
                               nsINode* aEndParent, int32_t aEndOffset,
                               nsRange** aRange);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsRange, nsIDOMRange)
 
+  /**
+   * The DOM Range spec requires that when a node is removed from its parent,
+   * and the node's subtree contains the start or end point of a range, that
+   * start or end point is moved up to where the node was removed from its
+   * parent.
+   * For some internal uses of Ranges it's useful to disable that behavior,
+   * so that a range of children within a single parent is preserved even if
+   * that parent is removed from the document tree.
+   */
+  void SetEnableGravitationOnElementRemoval(bool aEnable)
+  {
+    mEnableGravitationOnElementRemoval = aEnable;
+  }
+
   // nsIDOMRange interface
   NS_DECL_NSIDOMRANGE
   
   nsINode* GetRoot() const
   {
     return mRoot;
   }
 
@@ -294,16 +309,17 @@ protected:
   int32_t mEndOffset;
 
   bool mIsPositioned;
   bool mIsDetached;
   bool mMaySpanAnonymousSubtrees;
   bool mInSelection;
   bool mStartOffsetWasIncremented;
   bool mEndOffsetWasIncremented;
+  bool mEnableGravitationOnElementRemoval;
 #ifdef DEBUG
   int32_t  mAssertNextInsertOrAppendIndex;
   nsINode* mAssertNextInsertOrAppendNode;
 #endif
 };
 
 inline nsISupports*
 ToCanonicalSupports(nsRange* aRange)
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -616,16 +616,17 @@ WebGLContext::Render(gfxContext *ctx, gf
     if (!gl)
         return NS_OK;
 
     nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
                                                          gfxASurface::ImageFormatARGB32);
     if (surf->CairoStatus() != 0)
         return NS_ERROR_FAILURE;
 
+    gl->MakeCurrent();
     gl->ReadScreenIntoImageSurface(surf);
 
     bool srcPremultAlpha = mOptions.premultipliedAlpha;
     bool dstPremultAlpha = aFlags & RenderFlagPremultAlpha;
 
     if (!srcPremultAlpha && dstPremultAlpha) {
         gfxUtils::PremultiplyImageSurface(surf);
     } else if (srcPremultAlpha && !dstPremultAlpha) {
--- a/content/html/content/public/HTMLMediaElement.h
+++ b/content/html/content/public/HTMLMediaElement.h
@@ -39,16 +39,17 @@ typedef uint16_t nsMediaNetworkState;
 typedef uint16_t nsMediaReadyState;
 
 namespace mozilla {
 class MediaResource;
 class MediaDecoder;
 }
 
 class nsITimer;
+class nsRange;
 
 namespace mozilla {
 namespace dom {
 
 class MediaError;
 
 class HTMLMediaElement : public nsGenericHTMLElement,
                          public nsIObserver,
@@ -877,17 +878,17 @@ protected:
 
   // The current media load ID. This is incremented every time we start a
   // new load. Async events note the ID when they're first sent, and only fire
   // if the ID is unchanged when they come to fire.
   uint32_t mCurrentLoadID;
 
   // Points to the child source elements, used to iterate through the children
   // when selecting a resource to load.
-  nsCOMPtr<nsIDOMRange> mSourcePointer;
+  nsRefPtr<nsRange> mSourcePointer;
 
   // Points to the document whose load we're blocking. This is the document
   // we're bound to when loading starts.
   nsCOMPtr<nsIDocument> mLoadBlockedDoc;
 
   // Contains names of events that have been raised while in the bfcache.
   // These events get re-dispatched when the bfcache is exited.
   nsTArray<nsString> mPendingEvents;
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -3354,16 +3354,19 @@ nsIContent* HTMLMediaElement::GetNextSou
   nsCOMPtr<nsIDOMNode> thisDomNode = do_QueryObject(this);
 
   mSourceLoadCandidate = nullptr;
 
   nsresult rv = NS_OK;
   if (!mSourcePointer) {
     // First time this has been run, create a selection to cover children.
     mSourcePointer = new nsRange(this);
+    // If this media element is removed from the DOM, don't gravitate the
+    // range up to its ancestor, leave it attached to the media element.
+    mSourcePointer->SetEnableGravitationOnElementRemoval(false);
 
     rv = mSourcePointer->SelectNodeContents(thisDomNode);
     if (NS_FAILED(rv)) return nullptr;
 
     rv = mSourcePointer->Collapse(true);
     if (NS_FAILED(rv)) return nullptr;
   }
 
--- a/content/media/AudioNodeEngine.cpp
+++ b/content/media/AudioNodeEngine.cpp
@@ -108,19 +108,19 @@ AudioBlockPanStereoToStereo(const float 
                             float aGainL, float aGainR, bool aIsOnTheLeft,
                             float aOutputL[WEBAUDIO_BLOCK_SIZE],
                             float aOutputR[WEBAUDIO_BLOCK_SIZE])
 {
   uint32_t i;
 
   if (aIsOnTheLeft) {
     for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
-      *aOutputL++ = *aInputL++ + *aInputR++ * aGainL;
+      *aOutputL++ = *aInputL++ + *aInputR * aGainL;
       *aOutputR++ = *aInputR++ * aGainR;
     }
   } else {
     for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
-      *aOutputL++ = *aInputL++ * aGainL;
+      *aOutputL++ = *aInputL * aGainL;
       *aOutputR++ = *aInputR++ + *aInputL++ * aGainR;
     }
   }
 }
 }
--- a/content/media/omx/MPAPI.h
+++ b/content/media/omx/MPAPI.h
@@ -7,16 +7,25 @@
 #define MPAPI_h_
 
 #include <stdint.h>
 #include "GonkIOSurfaceImage.h"
 
 namespace MPAPI {
 
 struct VideoPlane {
+  VideoPlane() :
+    mData(nullptr),
+    mStride(0),
+    mWidth(0),
+    mHeight(0),
+    mOffset(0),
+    mSkip(0)
+  {}
+
   void *mData;
   int32_t mStride;
   int32_t mWidth;
   int32_t mHeight;
   int32_t mOffset;
   int32_t mSkip;
 };
 
@@ -29,16 +38,27 @@ struct VideoFrame {
   int32_t mStride;
   int32_t mSliceHeight;
   int32_t mRotation;
   VideoPlane Y;
   VideoPlane Cb;
   VideoPlane Cr;
   nsRefPtr<mozilla::layers::GraphicBufferLocked> mGraphicBuffer;
 
+  VideoFrame() :
+    mTimeUs(0),
+    mKeyFrame(false),
+    mShouldSkip(false),
+    mData(nullptr),
+    mSize(0),
+    mStride(0),
+    mSliceHeight(0),
+    mRotation(0)
+  {}
+
   void Set(int64_t aTimeUs, bool aKeyFrame,
            void *aData, size_t aSize, int32_t aStride, int32_t aSliceHeight, int32_t aRotation,
            void *aYData, int32_t aYStride, int32_t aYWidth, int32_t aYHeight, int32_t aYOffset, int32_t aYSkip,
            void *aCbData, int32_t aCbStride, int32_t aCbWidth, int32_t aCbHeight, int32_t aCbOffset, int32_t aCbSkip,
            void *aCrData, int32_t aCrStride, int32_t aCrWidth, int32_t aCrHeight, int32_t aCrOffset, int32_t aCrSkip)
   {
     mTimeUs = aTimeUs;
     mKeyFrame = aKeyFrame;
--- a/content/media/omx/MediaOmxReader.cpp
+++ b/content/media/omx/MediaOmxReader.cpp
@@ -135,16 +135,21 @@ bool MediaOmxReader::DecodeVideoFrame(bo
     MPAPI::VideoFrame frame;
     frame.mGraphicBuffer = nullptr;
     frame.mShouldSkip = false;
     if (!mOmxDecoder->ReadVideo(&frame, aTimeThreshold, aKeyframeSkip, doSeek)) {
       mVideoQueue.Finish();
       return false;
     }
 
+    // Ignore empty buffer which stagefright media read will sporadically return
+    if (frame.mSize == 0 && !frame.mGraphicBuffer) {
+      return true;
+    }
+
     parsed++;
     if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) {
       mSkipCount++;
       return true;
     }
 
     mSkipCount = 0;
 
--- a/content/media/omx/OmxDecoder.cpp
+++ b/content/media/omx/OmxDecoder.cpp
@@ -556,21 +556,25 @@ bool OmxDecoder::ReadVideo(VideoFrame *a
     MediaSource::ReadOptions options;
     options.setSeekTo(aTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
     err = mVideoSource->read(&mVideoBuffer, &options);
     {
       Mutex::Autolock autoLock(mSeekLock);
       mIsVideoSeeking = false;
       ReleaseAllPendingVideoBuffersLocked();
     }
+
+    aDoSeek = false;
   } else {
     err = mVideoSource->read(&mVideoBuffer);
   }
 
-  if (err == OK && mVideoBuffer->range_length() > 0) {
+  aFrame->mSize = 0;
+
+  if (err == OK) {
     int64_t timeUs;
     int32_t unreadable;
     int32_t keyFrame;
 
     if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs) ) {
       NS_WARNING("OMX decoder did not return frame time");
       return false;
     }
@@ -597,51 +601,52 @@ bool OmxDecoder::ReadVideo(VideoFrame *a
 
       mozilla::layers::SurfaceDescriptor descWrapper(newDescriptor);
       aFrame->mGraphicBuffer = new mozilla::layers::VideoGraphicBuffer(this, mVideoBuffer, descWrapper);
       aFrame->mRotation = mVideoRotation;
       aFrame->mTimeUs = timeUs;
       aFrame->mKeyFrame = keyFrame;
       aFrame->Y.mWidth = mVideoWidth;
       aFrame->Y.mHeight = mVideoHeight;
-    } else {
+    } else if (mVideoBuffer->range_length() > 0) {
       char *data = static_cast<char *>(mVideoBuffer->data()) + mVideoBuffer->range_offset();
       size_t length = mVideoBuffer->range_length();
 
       if (unreadable) {
         LOG(PR_LOG_DEBUG, "video frame is unreadable");
       }
 
       if (!ToVideoFrame(aFrame, timeUs, data, length, keyFrame)) {
         return false;
       }
     }
 
     if (aKeyframeSkip && timeUs < aTimeUs) {
       aFrame->mShouldSkip = true;
     }
-
   }
   else if (err == INFO_FORMAT_CHANGED) {
     // If the format changed, update our cached info.
     if (!SetVideoFormat()) {
       return false;
     } else {
       return ReadVideo(aFrame, aTimeUs, aKeyframeSkip, aDoSeek);
     }
   }
   else if (err == ERROR_END_OF_STREAM) {
     return false;
   }
-  else if (err == UNKNOWN_ERROR) {
-    // This sometimes is used to mean "out of memory", but regardless,
-    // don't keep trying to decode if the decoder doesn't want to.
-    return false;
+  else if (err == -ETIMEDOUT) {
+    LOG(PR_LOG_DEBUG, "OmxDecoder::ReadVideo timed out, will retry");
+    return true;
   }
-  else if (err != OK && err != -ETIMEDOUT) {
+  else {
+    // UNKNOWN_ERROR is sometimes is used to mean "out of memory", but
+    // regardless, don't keep trying to decode if the decoder doesn't want to.
+    LOG(PR_LOG_DEBUG, "OmxDecoder::ReadVideo failed, err=%d", err);
     return false;
   }
 
   return true;
 }
 
 bool OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs)
 {
@@ -659,16 +664,17 @@ bool OmxDecoder::ReadAudio(AudioFrame *a
       err = mAudioSource->read(&mAudioBuffer, &options);
     } else {
       err = mAudioSource->read(&mAudioBuffer);
     }
   }
   mAudioMetadataRead = false;
 
   aSeekTimeUs = -1;
+  aFrame->mSize = 0;
 
   if (err == OK && mAudioBuffer && mAudioBuffer->range_length() != 0) {
     int64_t timeUs;
     if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs))
       return false;
 
     return ToAudioFrame(aFrame, timeUs,
                         mAudioBuffer->data(),
@@ -684,20 +690,22 @@ bool OmxDecoder::ReadAudio(AudioFrame *a
       return ReadAudio(aFrame, aSeekTimeUs);
     }
   }
   else if (err == ERROR_END_OF_STREAM) {
     if (aFrame->mSize == 0) {
       return false;
     }
   }
-  else if (err == UNKNOWN_ERROR) {
-    return false;
+  else if (err == -ETIMEDOUT) {
+    LOG(PR_LOG_DEBUG, "OmxDecoder::ReadAudio timed out, will retry");
+    return true;
   }
-  else if (err != OK && err != -ETIMEDOUT) {
+  else if (err != OK) {
+    LOG(PR_LOG_DEBUG, "OmxDecoder::ReadAudio failed, err=%d", err);
     return false;
   }
 
   return true;
 }
 
 nsresult OmxDecoder::Play() {
   if (!mPaused) {
--- a/content/media/plugins/MPAPI.h
+++ b/content/media/plugins/MPAPI.h
@@ -21,16 +21,25 @@ enum ColorFormat {
  */
 class BufferCallback {
 public:
   virtual void *operator()(size_t aWidth, size_t aHeight,
                            ColorFormat aColorFormat) = 0;
 };
 
 struct VideoPlane {
+  VideoPlane() :
+    mData(0),
+    mStride(0),
+    mWidth(0),
+    mHeight(0),
+    mOffset(0),
+    mSkip(0)
+  {}
+
   void *mData;
   int32_t mStride;
   int32_t mWidth;
   int32_t mHeight;
   int32_t mOffset;
   int32_t mSkip;
 };
 
@@ -41,16 +50,26 @@ struct VideoFrame {
   size_t mSize;
   int32_t mStride;
   int32_t mSliceHeight;
   int32_t mRotation;
   VideoPlane Y;
   VideoPlane Cb;
   VideoPlane Cr;
 
+  VideoFrame() :
+    mTimeUs(0),
+    mKeyFrame(false),
+    mData(0),
+    mSize(0),
+    mStride(0),
+    mSliceHeight(0),
+    mRotation(0)
+  {}
+
   void Set(int64_t aTimeUs, bool aKeyFrame,
            void *aData, size_t aSize, int32_t aStride, int32_t aSliceHeight, int32_t aRotation,
            void *aYData, int32_t aYStride, int32_t aYWidth, int32_t aYHeight, int32_t aYOffset, int32_t aYSkip,
            void *aCbData, int32_t aCbStride, int32_t aCbWidth, int32_t aCbHeight, int32_t aCbOffset, int32_t aCbSkip,
            void *aCrData, int32_t aCrStride, int32_t aCrWidth, int32_t aCrHeight, int32_t aCrOffset, int32_t aCrSkip)
   {
     mTimeUs = aTimeUs;
     mKeyFrame = aKeyFrame;
new file mode 100644
--- /dev/null
+++ b/content/media/test/crashtests/865537-1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<body onload="doTest()">
+<base href="../unknown">
+<div id="test3"></div>
+<video id="test4"><source src="white.webm"></video>
+<script>
+function doTest() {
+  test3.appendChild(test4);
+}
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/test/crashtests/880129.html
@@ -0,0 +1,9 @@
+<script>
+try { o1 = new window.AudioContext(3, 2, 44100); } catch(e) { }
+try { o6 = o1.createBufferSource(); } catch(e) { }
+try { o15 = o1.createAnalyser(); } catch(e) { }
+try { o15.fftSize = 32; } catch(e) { }
+try { o6.connect(o15,0,0) } catch(e) { }
+try { o27 = o1.createPanner(); } catch(e) { }
+try { o6.buffer = function(){var buffer = o1.createBuffer(2, 1148, o1.sampleRate);for(var c=0; c<2; c++) {for(var i=0; i<1148; i++) {buffer.getChannelData(c)[i] = 0;}}return buffer;}() } catch(e) { }
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/content/media/test/crashtests/880202.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var Context0= new window.OfflineAudioContext(15,12119,44100)
+var BufferSource1=Context0.createBufferSource();
+var Gain0=Context0.createGain();
+var Panner0=Context0.createPanner();
+Context0.listener.setPosition(29,135,158);
+
+BufferSource1.connect(Gain0);
+
+BufferSource1.buffer=function(){
+	var channels=3; 
+	var length=53325;
+	var Buffer=Context0.createBuffer(channels,length,Context0.sampleRate);
+	for(var y=0;y<channels;y++){
+		var bufferData= Buffer.getChannelData(y);
+		for (var i = 0; i < length; ++i) { 
+			bufferData[i] = i*(270);
+		}
+	};
+	return Buffer;
+}();
+
+Gain0.connect(Panner0);
+Panner0.panningModel=0;
+
+
+setTimeout(function(){
+document.documentElement.removeAttribute("class");
+},500)
+
+</script>
--- a/content/media/test/crashtests/crashtests.list
+++ b/content/media/test/crashtests/crashtests.list
@@ -10,16 +10,17 @@ load 492286-1.xhtml
 load 576612-1.html
 skip-if(Android||B2G) load 691096-1.html # Android sound API can't handle playing large number of sounds at once, bug 852821 for B2G
 load 752784-1.html
 skip-if(Android||B2G) HTTP load 795892-1.html # load failed, bug 833371 for B2G
 skip-if(Android||B2G) load 789075-1.html # load failed, bug 833371 for B2G
 load 844563.html
 load 846612.html
 load 852838.html
+load 865537-1.html
 load 868504.html
 load 874869.html
 load 874915.html
 load 874934.html
 load 874952.html
 load 875144.html
 load 875596.html
 load 875911.html
@@ -32,8 +33,10 @@ load 876249.html
 load 876252.html
 load 876834.html
 load 877820.html
 load 878014.html
 load 878328.html
 load 878407.html
 load 878478.html
 load 877527.html
+load 880129.html
+skip-if(B2G) load 880202.html # load failed, bug 833371 for B2G
--- a/content/media/webaudio/AnalyserNode.cpp
+++ b/content/media/webaudio/AnalyserNode.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/AnalyserNode.h"
 #include "mozilla/dom/AnalyserNodeBinding.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "mozilla/Mutex.h"
+#include "mozilla/PodOperations.h"
 #include "kiss_fft/kiss_fftr.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS_INHERITED0(AnalyserNode, AudioNode)
 
 class AnalyserNodeEngine : public AudioNodeEngine
@@ -270,31 +271,36 @@ AnalyserNode::AllocateBuffer()
   return result;
 }
 
 void
 AnalyserNode::AppendChunk(const AudioChunk& aChunk)
 {
   const uint32_t bufferSize = mBuffer.Length();
   const uint32_t channelCount = aChunk.mChannelData.Length();
-  const uint32_t chunkCount = aChunk.mDuration;
+  uint32_t chunkDuration = aChunk.mDuration;
   MOZ_ASSERT((bufferSize & (bufferSize - 1)) == 0); // Must be a power of two!
   MOZ_ASSERT(channelCount > 0);
-  MOZ_ASSERT(chunkCount == WEBAUDIO_BLOCK_SIZE);
+  MOZ_ASSERT(chunkDuration == WEBAUDIO_BLOCK_SIZE);
 
-  memcpy(mBuffer.Elements() + mWriteIndex, aChunk.mChannelData[0], sizeof(float) * chunkCount);
+  if (chunkDuration > bufferSize) {
+    // Copy a maximum bufferSize samples.
+    chunkDuration = bufferSize;
+  }
+
+  PodCopy(mBuffer.Elements() + mWriteIndex, static_cast<const float*>(aChunk.mChannelData[0]), chunkDuration);
   for (uint32_t i = 1; i < channelCount; ++i) {
     AudioBlockAddChannelWithScale(static_cast<const float*>(aChunk.mChannelData[i]), 1.0f,
                                   mBuffer.Elements() + mWriteIndex);
   }
   if (channelCount > 1) {
     AudioBlockInPlaceScale(mBuffer.Elements() + mWriteIndex, 1,
                            1.0f / aChunk.mChannelData.Length());
   }
-  mWriteIndex += chunkCount;
+  mWriteIndex += chunkDuration;
   MOZ_ASSERT(mWriteIndex <= bufferSize);
   if (mWriteIndex >= bufferSize) {
     mWriteIndex = 0;
   }
 }
 
 }
 }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1452,19 +1452,21 @@ nsGlobalWindow::FreeInnerObjects()
 
   // Make sure that this is called before we null out the document and
   // other members that the window destroyed observers could
   // re-create.
   NotifyDOMWindowDestroyed(this);
 
   // Kill all of the workers for this window.
   // We push a cx so that exceptions get reported in the right DOM Window.
-  nsIScriptContext *scx = GetContextInternal();
-  AutoPushJSContext cx(scx ? scx->GetNativeContext() : nsContentUtils::GetSafeJSContext());
-  mozilla::dom::workers::CancelWorkersForWindow(cx, this);
+  {
+    nsIScriptContext *scx = GetContextInternal();
+    AutoPushJSContext cx(scx ? scx->GetNativeContext() : nsContentUtils::GetSafeJSContext());
+    mozilla::dom::workers::CancelWorkersForWindow(cx, this);
+  }
 
   // Close all offline storages for this window.
   quota::QuotaManager* quotaManager = quota::QuotaManager::Get();
   if (quotaManager) {
     quotaManager->AbortCloseStoragesForWindow(this);
   }
 
   ClearAllTimeouts();
@@ -10934,20 +10936,22 @@ nsGlobalWindow::SuspendTimeouts(uint32_t
     nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
     if (ac) {
       for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
         ac->RemoveWindowListener(mEnabledSensors[i], this);
     }
     DisableGamepadUpdates();
 
     // Suspend all of the workers for this window.
-  // We push a cx so that exceptions get reported in the right DOM Window.
-    nsIScriptContext *scx = GetContextInternal();
-    AutoPushJSContext cx(scx ? scx->GetNativeContext() : nsContentUtils::GetSafeJSContext());
-    mozilla::dom::workers::SuspendWorkersForWindow(cx, this);
+    // We push a cx so that exceptions get reported in the right DOM Window.
+    {
+      nsIScriptContext *scx = GetContextInternal();
+      AutoPushJSContext cx(scx ? scx->GetNativeContext() : nsContentUtils::GetSafeJSContext());
+      mozilla::dom::workers::SuspendWorkersForWindow(cx, this);
+    }
 
     TimeStamp now = TimeStamp::Now();
     for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
       // Set mTimeRemaining to be the time remaining for this timer.
       if (t->mWhen > now)
         t->mTimeRemaining = t->mWhen - now;
       else
         t->mTimeRemaining = TimeDuration(0);
@@ -11029,17 +11033,17 @@ nsGlobalWindow::ResumeTimeouts(bool aTha
     for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
       mAudioContexts[i]->Resume();
     }
 
     // Resume all of the workers for this window.
     // We push a cx so that exceptions get reported in the right DOM Window.
     nsIScriptContext *scx = GetContextInternal();
     AutoPushJSContext cx(scx ? scx->GetNativeContext() : nsContentUtils::GetSafeJSContext());
-    mozilla::dom::workers::ResumeWorkersForWindow(cx, this);
+    mozilla::dom::workers::ResumeWorkersForWindow(scx, this);
 
     // Restore all of the timeouts, using the stored time remaining
     // (stored in timeout->mTimeRemaining).
 
     TimeStamp now = TimeStamp::Now();
 
 #ifdef DEBUG
     bool _seenDummyTimeout = false;
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -30,18 +30,18 @@ bool
 DefineStaticJSVals(JSContext* cx)
 {
   return InternJSString(cx, s_length_id, "length");
 }
 
 
 int HandlerFamily;
 
-js::ListBaseShadowsResult
-DOMListShadows(JSContext* cx, JSHandleObject proxy, JSHandleId id)
+js::DOMProxyShadowsResult
+DOMProxyShadows(JSContext* cx, JSHandleObject proxy, JSHandleId id)
 {
   JS::Value v = js::GetProxyExtra(proxy, JSPROXYSLOT_EXPANDO);
   if (v.isObject()) {
     JSBool hasOwn;
     if (!JS_AlreadyHasOwnPropertyById(cx, &v.toObject(), id, &hasOwn))
       return js::ShadowCheckFailed;
 
     return hasOwn ? js::Shadows : js::DoesntShadow;
@@ -54,25 +54,25 @@ DOMListShadows(JSContext* cx, JSHandleOb
   bool hasOwn;
   if (!GetProxyHandler(proxy)->hasOwn(cx, proxy, id, &hasOwn))
     return js::ShadowCheckFailed;
 
   return hasOwn ? js::Shadows : js::DoesntShadowUnique;
 }
 
 // Store the information for the specialized ICs.
-struct SetListBaseInformation
+struct SetDOMProxyInformation
 {
-  SetListBaseInformation() {
-    js::SetListBaseInformation((void*) &HandlerFamily,
-                               js::JSSLOT_PROXY_EXTRA + JSPROXYSLOT_EXPANDO, DOMListShadows);
+  SetDOMProxyInformation() {
+    js::SetDOMProxyInformation((void*) &HandlerFamily,
+                               js::JSSLOT_PROXY_EXTRA + JSPROXYSLOT_EXPANDO, DOMProxyShadow);
   }
 };
 
-SetListBaseInformation gSetListBaseInformation;
+SetDOMProxyInformation gSetDOMProxyInformation;
 
 // static
 JSObject*
 DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj)
 {
   MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
   JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
   if (v.isUndefined()) {
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -760,20 +760,39 @@ RTCPeerConnection.prototype = {
     let sdp = this._getPC().remoteDescription;
     if (sdp.length == 0) {
       return null;
     }
     return new this._win.mozRTCSessionDescription({ type: this._remoteType,
                                                     sdp: sdp });
   },
 
-  get signalingState()     { return "stable"; }, // not yet implemented
   get iceGatheringState()  { return this._iceGatheringState; },
   get iceConnectionState() { return this._iceConnectionState; },
 
+  // Corresponds to constants in IPeerConnection.idl
+  _signalingStateMap: [
+    'invalid',
+    'stable',
+    'have-local-offer',
+    'have-remote-offer',
+    'have-local-pranswer',
+    'have-remote-pranswer',
+    'closed'
+  ],
+
+  get signalingState() {
+    // checking for our local pc closed indication
+    // before invoking the pc methods.
+    if(this._closed) {
+      return "closed";
+    }
+    return this._signalingStateMap[this._getPC().signalingState];
+  },
+
   changeIceGatheringState: function(state) {
     this._iceGatheringState = state;
   },
 
   changeIceConnectionState: function(state) {
     this._iceConnectionState = state;
     this.dispatchEvent(new this._win.Event("iceconnectionstatechange"));
   },
@@ -985,24 +1004,20 @@ PeerConnectionObserver.prototype = {
   },
 
   onAddIceCandidateError: function(code, message) {
     this._dompc._pendingType = null;
     this.callCB(this._dompc._onAddIceCandidateError, new RTCError(code, message));
     this._dompc._executeNext();
   },
 
-  onStateChange: function(state) {
-    if (state != Ci.IPeerConnectionObserver.kIceState) {
-      return;
-    }
-
-    switch (this._dompc._pc.iceState) {
+  handleIceStateChanges: function(iceState) {
+    switch (iceState) {
       case Ci.IPeerConnection.kIceWaiting:
-        this._dompc.changeIceConnectionState("completed");
+        this._dompc.changeIceConnectionState("new");
         this.callCB(this._dompc.ongatheringchange, "complete");
         this.callCB(this._onicechange, "starting");
         // Now that the PC is ready to go, execute any pending operations.
         this._dompc._executeNext();
         break;
       case Ci.IPeerConnection.kIceChecking:
         this._dompc.changeIceConnectionState("checking");
         this.callCB(this._onicechange, "checking");
@@ -1016,17 +1031,43 @@ PeerConnectionObserver.prototype = {
         this._dompc.changeIceConnectionState("connected");
         this.callCB(this._onicechange, "connected");
         break;
       case Ci.IPeerConnection.kIceFailed:
         this._dompc.changeIceConnectionState("failed");
         this.callCB(this._onicechange, "failed");
         break;
       default:
-        // Unknown state!
+        // Unknown ICE state!
+        this._dompc.reportWarning("Unhandled ice state: " + iceState, null, 0);
+        break;
+    }
+  },
+
+  onStateChange: function(state) {
+    switch (state) {
+      case Ci.IPeerConnectionObserver.kSignalingState:
+        this.callCB(this._dompc.onsignalingstatechange,
+                    this._dompc.signalingState);
+        break;
+
+      case Ci.IPeerConnectionObserver.kIceState:
+        this.handleIceStateChanges(this._dompc._pc.iceState);
+        break;
+
+      case Ci.IPeerConnectionObserver.kSdpState:
+        // No-op
+        break;
+
+      case Ci.IPeerConnectionObserver.kSipccState:
+        // No-op
+        break;
+
+      default:
+        this._dompc.reportWarning("Unhandled state type: " + state, null, 0);
         break;
     }
   },
 
   onAddStream: function(stream) {
     this.dispatchEvent(new this._dompc._win.MediaStreamEvent("addstream",
                                                              { stream: stream }));
   },
--- a/dom/media/bridge/IPeerConnection.idl
+++ b/dom/media/bridge/IPeerConnection.idl
@@ -27,16 +27,17 @@ interface IPeerConnectionManager : nsISu
 [scriptable, uuid(85ba28da-53d0-401d-afed-9cad69f727ff)]
 interface IPeerConnectionObserver : nsISupports
 {
   /* Constants */
   const long kReadyState = 0x1;
   const long kIceState = 0x2;
   const long kSdpState = 0x3;
   const long kSipccState = 0x4;
+  const long kSignalingState = 0x5;
 
   /* JSEP callbacks */
   void onCreateOfferSuccess(in string offer);
   void onCreateOfferError(in unsigned long name, in string message);
   void onCreateAnswerSuccess(in string answer);
   void onCreateAnswerError(in unsigned long name, in string message);
   void onSetLocalDescriptionSuccess();
   void onSetRemoteDescriptionSuccess();
@@ -86,16 +87,25 @@ interface IPeerConnection : nsISupports
 
   /* for readyState on Peer Connection */
   const long kNew = 0;
   const long kNegotiating = 1;
   const long kActive = 2;
   const long kClosing = 3;
   const long kClosed = 4;
 
+  /* RTCSignalingState from WebRTC spec */
+  const long kSignalingInvalid            = 0;
+  const long kSignalingStable             = 1;
+  const long kSignalingHaveLocalOffer     = 2;
+  const long kSignalingHaveRemoteOffer    = 3;
+  const long kSignalingHaveLocalPranswer  = 4;
+  const long kSignalingHaveRemotePranswer = 5;
+  const long kSignalingClosed             = 6;
+
   /* for 'type' in DataChannelInit dictionary */
   const unsigned short kDataChannelReliable = 0;
   const unsigned short kDataChannelPartialReliableRexmit = 1;
   const unsigned short kDataChannelPartialReliableTimed = 2;
 
   /* Constants for 'name' in error callbacks */
   const unsigned long kNoError                          = 0; // Test driver only
   const unsigned long kInvalidConstraintsType           = 1;
@@ -139,16 +149,17 @@ interface IPeerConnection : nsISupports
   void close();
 
   /* Attributes */
   readonly attribute string localDescription;
   readonly attribute string remoteDescription;
 
   readonly attribute unsigned long iceState;
   readonly attribute unsigned long readyState;
+  readonly attribute unsigned long signalingState;
   readonly attribute unsigned long sipccState;
 
   /* Data channels */
   nsIDOMDataChannel createDataChannel(in ACString label, in ACString protocol,
     in unsigned short type, in boolean outOfOrderAllowed,
     in unsigned short maxTime, in unsigned short maxNum,
     in boolean externalNegotiated, in unsigned short stream);
   void connectDataConnection(in unsigned short localport,
--- a/dom/media/tests/mochitest/Makefile.in
+++ b/dom/media/tests/mochitest/Makefile.in
@@ -30,16 +30,23 @@ MOCHITEST_FILES = \
   test_peerConnection_basicAudioVideo.html \
   test_peerConnection_basicAudioVideoCombined.html \
   test_peerConnection_basicVideo.html \
   test_peerConnection_errorCallbacks.html \
   test_peerConnection_offerRequiresReceiveAudio.html \
   test_peerConnection_offerRequiresReceiveVideo.html \
   test_peerConnection_offerRequiresReceiveVideoAudio.html \
   test_peerConnection_throwInCallbacks.html \
+  test_peerConnection_setLocalAnswerInStable.html \
+  test_peerConnection_setRemoteAnswerInStable.html \
+  test_peerConnection_setLocalAnswerInHaveLocalOffer.html \
+  test_peerConnection_setRemoteOfferInHaveLocalOffer.html \
+  test_peerConnection_setLocalOfferInHaveRemoteOffer.html \
+  test_peerConnection_setRemoteAnswerInHaveRemoteOffer.html \
+  test_peerConnection_addCandidateInHaveLocalOffer.html \
   test_peerConnection_bug822674.html \
   test_peerConnection_bug825703.html \
   test_peerConnection_bug827843.html \
   test_peerConnection_bug834153.html \
   test_peerConnection_bug835370.html \
   head.js \
   mediaStreamPlayback.js \
   pc.js \
--- a/dom/media/tests/mochitest/head.js
+++ b/dom/media/tests/mochitest/head.js
@@ -177,16 +177,28 @@ function checkMediaStreamTracks(constrai
 function unexpectedCallbackAndFinish(error) {
   /**
    * @param {object} aObj
    *        The object fired back from the callback
    */
   return function(aObj) {
     var where = error.fileName + ":" + error.lineNumber;
     if (aObj && aObj.name && aObj.message) {
-      ok(false, "Unexpected error callback from " + where + " with name = '" +
+      ok(false, "Unexpected callback/event from " + where + " with name = '" +
                 aObj.name + "', message = '" + aObj.message + "'");
     } else {
-      ok(false, "Unexpected error callback from " + where + " with " + aObj);
+      ok(false, "Unexpected callback/event from " + where + " with " + aObj);
     }
     SimpleTest.finish();
   }
 }
+
+/**
+ * Generates a callback function suitable for putting int a success
+ * callback in circumstances where success is unexpected. The callback,
+ * if activated, will kill off the test gracefully.
+ */
+
+function unexpectedSuccessCallbackAndFinish(error, reason) {
+  return function() {
+    unexpectedCallbackAndFinish(error)(message);
+  }
+}
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -242,61 +242,71 @@ var commandsPeerConnection = [
     'PC_REMOTE_GUM',
     function (test) {
       test.pcRemote.getAllUserMedia(function () {
         test.next();
       });
     }
   ],
   [
+    'PC_CHECK_INITIAL_SIGNALINGSTATE',
+    function (test) {
+      is(test.pcLocal.signalingState,"stable", "Initial local signalingState is stable");
+      is(test.pcRemote.signalingState,"stable", "Initial remote signalingState is stable");
+      test.next();
+    }
+  ],
+  [
     'PC_LOCAL_CREATE_OFFER',
     function (test) {
       test.pcLocal.createOffer(function () {
+        is(test.pcLocal.signalingState, "stable", "Local create offer does not change signaling state");
         test.next();
       });
     }
   ],
   [
     'PC_LOCAL_SET_LOCAL_DESCRIPTION',
     function (test) {
-      test.pcLocal.setLocalDescription(test.pcLocal._last_offer, function () {
-        test.next();
-      });
+      test.expectStateChange(test.pcLocal, "have-local-offer", test);
+      test.pcLocal.setLocalDescription(test.pcLocal._last_offer,
+        test.checkStateInCallback(test.pcLocal, "have-local-offer", test));
     }
   ],
   [
     'PC_REMOTE_SET_REMOTE_DESCRIPTION',
     function (test) {
-      test.pcRemote.setRemoteDescription(test.pcLocal._last_offer, function () {
-        test.next();
-      });
+      test.expectStateChange(test.pcRemote, "have-remote-offer", test);
+      test.pcRemote.setRemoteDescription(test.pcLocal._last_offer,
+        test.checkStateInCallback(test.pcRemote, "have-remote-offer", test));
     }
   ],
   [
     'PC_REMOTE_CREATE_ANSWER',
     function (test) {
       test.pcRemote.createAnswer(function () {
+        is(test.pcRemote.signalingState, "have-remote-offer", "Remote create offer does not change signaling state");
         test.next();
       });
     }
   ],
   [
     'PC_LOCAL_SET_REMOTE_DESCRIPTION',
     function (test) {
-      test.pcLocal.setRemoteDescription(test.pcRemote._last_answer, function () {
-        test.next();
-      });
+      test.expectStateChange(test.pcLocal, "stable", test);
+      test.pcLocal.setRemoteDescription(test.pcRemote._last_answer,
+        test.checkStateInCallback(test.pcLocal, "stable", test));
     }
   ],
   [
     'PC_REMOTE_SET_LOCAL_DESCRIPTION',
     function (test) {
-      test.pcRemote.setLocalDescription(test.pcRemote._last_answer, function () {
-        test.next();
-      });
+      test.expectStateChange(test.pcRemote, "stable", test);
+      test.pcRemote.setLocalDescription(test.pcRemote._last_answer,
+        test.checkStateInCallback(test.pcRemote, "stable", test));
     }
   ],
   [
     'PC_LOCAL_CHECK_MEDIA',
     function (test) {
       test.pcLocal.checkMedia(test.pcRemote.constraints);
       test.next();
     }
@@ -389,16 +399,74 @@ PeerConnectionTest.prototype.teardown = 
     this.pcRemote.close();
     this.pcRemote = null;
   }
 
   info("Test finished");
   SimpleTest.finish();
 };
 
+/**
+ * Sets up the "onsignalingstatechange" handler for the indicated peerconnection
+ * as a one-shot test. If the test.commandSuccess flag is set when the event
+ * happens, then the next test in the command chain is triggered. After
+ * running, this sets the event handler so that it will fail the test if
+ * it fires again before we expect it. This is intended to be used in
+ * conjunction with checkStateInCallback, below.
+ *
+ * @param {pcw} PeerConnectionWrapper
+ *        The peer connection to expect a state change on
+ * @param {state} string
+ *        The state that we expect to change to
+ * @param {test} PeerConnectionTest
+ *        The test strucure currently in use.
+ */
+PeerConnectionTest.prototype.expectStateChange =
+function PCT_expectStateChange(pcw, state, test) {
+  pcw.signalingChangeEvent = false;
+  pcw._pc.onsignalingstatechange = function() {
+    pcw._pc.onsignalingstatechange = unexpectedCallbackAndFinish(new Error);
+    is(pcw._pc.signalingState, state, pcw.label + ": State is " + state + " in onsignalingstatechange");
+    pcw.signalingChangeEvent = true;
+    if (pcw.commandSuccess) {
+      test.next();
+    } else {
+      info("Waiting for success callback...");
+    }
+  };
+}
+
+/**
+ * Returns a function, suitable for use as a success callback, that
+ * checks the signaling state of the PC; and, if the signalingstatechange
+ * event has already fired, moves on to the next test case. This is
+ * intended to be used in conjunction with expectStateChange, above.
+ *
+ * @param {pcw} PeerConnectionWrapper
+ *        The peer connection to expect a state change on
+ * @param {state} string
+ *        The state that we expect to change to
+ * @param {test} PeerConnectionTest
+ *        The test strucure currently in use.
+ */
+
+PeerConnectionTest.prototype.checkStateInCallback =
+function PCT_checkStateInCallback(pcw, state, test) {
+  pcw.commandSuccess = false;
+  return function() {
+    pcw.commandSuccess = true;
+    is(pcw.signalingState, state, pcw.label + ": State is " + state + " in success callback");
+    if (pcw.signalingChangeEvent) {
+      test.next();
+    } else {
+      info("Waiting for signalingstatechange event...");
+    }
+  };
+}
+
 
 /**
  * This class handles acts as a wrapper around a PeerConnection instance.
  *
  * @constructor
  * @param {string} label
  *        Description for the peer connection instance
  * @param {object} configuration
@@ -415,16 +483,19 @@ function PeerConnectionWrapper(label, co
   info("Creating new PeerConnectionWrapper: " + this.label);
   this._pc = new mozRTCPeerConnection(this.configuration);
 
   var self = this;
   this._pc.onaddstream = function (event) {
     // Bug 834835: Assume type is video until we get get{Audio,Video}Tracks.
     self.attachMedia(event.stream, 'video', 'remote');
   };
+
+  // Make sure no signaling state changes are fired until we expect them to
+  this._pc.onsignalingstatechange = unexpectedCallbackAndFinish(new Error);
 }
 
 PeerConnectionWrapper.prototype = {
 
   /**
    * Returns the local description.
    *
    * @returns {object} The local description
@@ -458,16 +529,25 @@ PeerConnectionWrapper.prototype = {
    * @param {object} desc
    *        The new remote description
    */
   set remoteDescription(desc) {
     this._pc.remoteDescription = desc;
   },
 
   /**
+   * Returns the remote signaling state.
+   *
+   * @returns {object} The local description
+   */
+  get signalingState() {
+    return this._pc.signalingState;
+  },
+
+  /**
    * Callback when we get media from either side. Also an appropriate
    * HTML media element will be created.
    *
    * @param {MediaStream} stream
    *        Media stream to handle
    * @param {string} type
    *        The type of media stream ('audio' or 'video')
    * @param {string} side
@@ -567,32 +647,107 @@ PeerConnectionWrapper.prototype = {
     var self = this;
     this._pc.setLocalDescription(desc, function () {
       info("Successfully set the local description for " + self.label);
       onSuccess();
     }, unexpectedCallbackAndFinish(new Error));
   },
 
   /**
+   * Tries to set the local description and expect failure. Automatically
+   * causes the test case to fail if the call succeeds.
+   *
+   * @param {object} desc
+   *        mozRTCSessionDescription for the local description request
+   * @param {function} onFailure
+   *        Callback to execute if the call fails.
+   */
+  setLocalDescriptionAndFail : function PCW_setLocalDescriptionAndFail(desc, onFailure) {
+    var self = this;
+    this._pc.setLocalDescription(desc,
+      unexpectedSuccessCallbackAndFinish(new Error, "setLocalDescription should have failed."),
+      function (err) {
+        info("As expected, failed to set the local description for " + self.label);
+        onFailure(err);
+    });
+  },
+
+  /**
    * Sets the remote description and automatically handles the failure case.
    *
    * @param {object} desc
    *        mozRTCSessionDescription for the remote description request
    * @param {function} onSuccess
    *        Callback to execute if the remote description was set successfully
    */
   setRemoteDescription : function PCW_setRemoteDescription(desc, onSuccess) {
     var self = this;
     this._pc.setRemoteDescription(desc, function () {
       info("Successfully set remote description for " + self.label);
       onSuccess();
     }, unexpectedCallbackAndFinish(new Error));
   },
 
   /**
+   * Tries to set the remote description and expect failure. Automatically
+   * causes the test case to fail if the call succeeds.
+   *
+   * @param {object} desc
+   *        mozRTCSessionDescription for the remote description request
+   * @param {function} onFailure
+   *        Callback to execute if the call fails.
+   */
+  setRemoteDescriptionAndFail : function PCW_setRemoteDescriptionAndFail(desc, onFailure) {
+    var self = this;
+    this._pc.setRemoteDescription(desc,
+      unexpectedSuccessCallbackAndFinish(new Error, "setRemoteDescription should have failed."),
+      function (err) {
+        info("As expected, failed to set the remote description for " + self.label);
+        onFailure(err);
+    });
+  },
+
+  /**
+   * Adds an ICE candidate and automatically handles the failure case.
+   *
+   * @param {object} candidate
+   *        SDP candidate
+   * @param {function} onSuccess
+   *        Callback to execute if the local description was set successfully
+   */
+  addIceCandidate : function PCW_addIceCandidate(candidate, onSuccess) {
+    var self = this;
+
+    this._pc.addIceCandidate(candidate, function () {
+      info("Successfully added an ICE candidate to " + self.label);
+      onSuccess();
+    }, unexpectedCallbackAndFinish(new Error));
+  },
+
+  /**
+   * Tries to add an ICE candidate and expects failure. Automatically
+   * causes the test case to fail if the call succeeds.
+   *
+   * @param {object} candidate
+   *        SDP candidate
+   * @param {function} onFailure
+   *        Callback to execute if the call fails.
+   */
+  addIceCandidateAndFail : function PCW_addIceCandidateAndFail(candidate, onFailure) {
+    var self = this;
+
+    this._pc.addIceCandidate(candidate,
+      unexpectedSuccessCallbackAndFinish(new Error, "addIceCandidate should have failed."),
+      function (err) {
+        info("As expected, failed to add an ICE candidate to " + self.label);
+        onFailure(err);
+    }) ;
+  },
+
+  /**
    * Checks that we are getting the media we expect.
    *
    * @param {object} constraintsRemote
    *        The media constraints of the remote peer connection object
    */
   checkMedia : function PCW_checkMedia(constraintsRemote) {
     is(this._pc.localStreams.length, this.constraints.length,
        this.label + ' has ' + this.constraints.length + ' local streams');
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_addCandidateInHaveLocalOffer.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="head.js"></script>
+  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
+  <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+  createHTML({
+    bug: "784519",
+    title: "addCandidate (answer) in 'have-local-offer'"
+  });
+
+  var test;
+  runTest(function () {
+    test = new PeerConnectionTest();
+    test.setMediaConstraints([{audio: true}], [{audio: true}]);
+    test.chain.removeAfter("PC_LOCAL_SET_LOCAL_DESCRIPTION");
+
+    test.chain.append([[
+      "PC_LOCAL_ADD_CANDIDATE",
+      function (test) {
+        test.pcLocal.addIceCandidateAndFail(
+          mozRTCIceCandidate(
+            {candidate:"1 1 UDP 2130706431 192.168.2.1 50005 typ host",
+             sdpMLineIndex: 1}),
+          function(err) {
+            is(err.name, "INVALID_STATE", "Error is INVALID_STATE");
+            test.next();
+          } );
+      }
+    ]]);
+
+    test.run();
+  });
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/tests/mochitest/test_peerConnection_bug825703.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug825703.html
@@ -49,17 +49,17 @@
     makePC({ iceServers: [{ url:"" }] }, false);
 
     makePC({ iceServers: [{ url:"http:0.0.0.0" }] }, false);
 
     makePC({ iceServers: [
                 { url:"stun:0.0.0.0" },
                 { url:"stuns:x.net", foo:"" },
                 { url:"turn:[::192.9.5.5]:42", username:"p", credential:"p" },
-                { url:"turns:x.org:42", username:"p", credential:"p" }
+                { url:"turns:x.org:42?transport=udp", username:"p", credential:"p" }
                 ]}, true);
 
     pcs = null;
     SimpleTest.finish();
   });
 </script>
 </pre>
 </body>
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_setLocalAnswerInHaveLocalOffer.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="head.js"></script>
+  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
+  <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+  createHTML({
+    bug: "784519",
+    title: "setLocalDescription (answer) in 'have-local-offer'"
+  });
+
+  var test;
+  runTest(function () {
+    test = new PeerConnectionTest();
+    test.setMediaConstraints([{audio: true}], [{audio: true}]);
+    test.chain.removeAfter("PC_LOCAL_SET_LOCAL_DESCRIPTION");
+
+    test.chain.append([[
+      "PC_LOCAL_SET_LOCAL_ANSWER",
+      function (test) {
+        test.pcLocal._last_offer.type="answer";
+        test.pcLocal.setLocalDescriptionAndFail(test.pcLocal._last_offer,
+          function(err) {
+            is(err.name, "INVALID_STATE", "Error is INVALID_STATE");
+            test.next();
+          } );
+      }
+    ]]);
+
+    test.run();
+  });
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_setLocalAnswerInStable.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="head.js"></script>
+  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
+  <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+  createHTML({
+    bug: "784519",
+    title: "setLocalDescription (answer) in 'stable'"
+  });
+
+  var test;
+  runTest(function () {
+    test = new PeerConnectionTest();
+    test.setMediaConstraints([{audio: true}], [{audio: true}]);
+    test.chain.removeAfter("PC_LOCAL_CREATE_OFFER");
+
+    test.chain.append([[
+      "PC_LOCAL_SET_LOCAL_ANSWER",
+      function (test) {
+        test.pcLocal._last_offer.type="answer";
+        test.pcLocal.setLocalDescriptionAndFail(test.pcLocal._last_offer,
+          function(err) {
+            is(err.name, "INVALID_STATE", "Error is INVALID_STATE");
+            test.next();
+          } );
+      }
+    ]]);
+
+    test.run();
+  });
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_setLocalOfferInHaveRemoteOffer.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="head.js"></script>
+  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
+  <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+  createHTML({
+    bug: "784519",
+    title: "setLocalDescription (offer) in 'have-remote-offer'"
+  });
+
+  var test;
+  runTest(function () {
+    test = new PeerConnectionTest();
+    test.setMediaConstraints([{audio: true}], [{audio: true}]);
+    test.chain.removeAfter("PC_REMOTE_SET_REMOTE_DESCRIPTION");
+
+    test.chain.append([[
+      "PC_REMOTE_SET_LOCAL_OFFER",
+      function (test) {
+        test.pcRemote.setLocalDescriptionAndFail(test.pcLocal._last_offer,
+          function(err) {
+            is(err.name, "INVALID_STATE", "Error is INVALID_STATE");
+            test.next();
+          } );
+      }
+    ]]);
+
+    test.run();
+  });
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_setRemoteAnswerInHaveRemoteOffer.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="head.js"></script>
+  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
+  <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+  createHTML({
+    bug: "784519",
+    title: "setRemoteDescription (answer) in 'have-remote-offer'"
+  });
+
+  var test;
+  runTest(function () {
+    test = new PeerConnectionTest();
+    test.setMediaConstraints([{audio: true}], [{audio: true}]);
+    test.chain.removeAfter("PC_REMOTE_SET_REMOTE_DESCRIPTION");
+
+    test.chain.append([[
+      "PC_REMOTE_SET_REMOTE_ANSWER",
+      function (test) {
+        test.pcLocal._last_offer.type="answer";
+        test.pcRemote.setRemoteDescriptionAndFail(test.pcLocal._last_offer,
+          function(err) {
+            is(err.name, "INVALID_STATE", "Error is INVALID_STATE");
+            test.next();
+          } );
+      }
+    ]]);
+
+    test.run();
+  });
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_setRemoteAnswerInStable.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="head.js"></script>
+  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
+  <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+  createHTML({
+    bug: "784519",
+    title: "setRemoteDescription (answer) in 'stable'"
+  });
+
+  var test;
+  runTest(function () {
+    test = new PeerConnectionTest();
+    test.setMediaConstraints([{audio: true}], [{audio: true}]);
+    test.chain.removeAfter("PC_LOCAL_CREATE_OFFER");
+
+    test.chain.append([[
+      "PC_LOCAL_SET_REMOTE_ANSWER",
+      function (test) {
+        test.pcLocal._last_offer.type="answer";
+        test.pcLocal.setRemoteDescriptionAndFail(test.pcLocal._last_offer,
+          function(err) {
+            is(err.name, "INVALID_STATE", "Error is INVALID_STATE");
+            test.next();
+          } );
+      }
+    ]]);
+
+    test.run();
+  });
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_setRemoteOfferInHaveLocalOffer.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="head.js"></script>
+  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
+  <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+  createHTML({
+    bug: "784519",
+    title: "setRemoteDescription (offer) in 'have-local-offer'"
+  });
+
+  var test;
+  runTest(function () {
+    test = new PeerConnectionTest();
+    test.setMediaConstraints([{audio: true}], [{audio: true}]);
+    test.chain.removeAfter("PC_LOCAL_SET_LOCAL_DESCRIPTION");
+
+    test.chain.append([[
+      "PC_LOCAL_SET_REMOTE_OFFER",
+      function (test) {
+        test.pcLocal.setRemoteDescriptionAndFail(test.pcLocal._last_offer,
+          function(err) {
+            is(err.name, "INVALID_STATE", "Error is INVALID_STATE");
+            test.next();
+          } );
+      }
+    ]]);
+
+    test.run();
+  });
+</script>
+</pre>
+</body>
+</html>
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -1,54 +1,52 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/Util.h"
-
 #include "RuntimeService.h"
 
 #include "nsIContentSecurityPolicy.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIObserverService.h"
 #include "nsIPlatformCharset.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISupportsPriority.h"
 #include "nsITimer.h"
 #include "nsPIDOMWindow.h"
-#include "nsLayoutStatics.h"
 
+#include <algorithm>
+#include "GeckoProfiler.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
+#include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/EventTargetBinding.h"
+#include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/Util.h"
+#include <Navigator.h>
 #include "nsContentUtils.h"
-#include "nsCxPusher.h"
 #include "nsDOMJSUtils.h"
-#include <Navigator.h>
+#include "nsLayoutStatics.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
+#include "OSFileConstants.h"
 #include "xpcpublic.h"
 
 #include "Events.h"
 #include "Worker.h"
 #include "WorkerPrivate.h"
 
-#include "OSFileConstants.h"
-#include <algorithm>
-
-#include "GeckoProfiler.h"
-
 using namespace mozilla;
 using namespace mozilla::dom;
 
 USING_WORKERS_NAMESPACE
 
 using mozilla::MutexAutoLock;
 using mozilla::MutexAutoUnlock;
 using mozilla::Preferences;
@@ -67,29 +65,32 @@ using mozilla::Preferences;
 #define WORKER_CONTEXT_NATIVE_STACK_LIMIT 128 * sizeof(size_t) * 1024
 
 // The maximum number of threads to use for workers, overridable via pref.
 #define MAX_WORKERS_PER_DOMAIN 10
 
 MOZ_STATIC_ASSERT(MAX_WORKERS_PER_DOMAIN >= 1,
                   "We should allow at least one worker per domain.");
 
-// The default number of seconds that close handlers will be allowed to run.
+// The default number of seconds that close handlers will be allowed to run for
+// content workers.
 #define MAX_SCRIPT_RUN_TIME_SEC 10
 
 // The number of seconds that idle threads can hang around before being killed.
 #define IDLE_THREAD_TIMEOUT_SEC 30
 
 // The maximum number of threads that can be idle at one time.
 #define MAX_IDLE_THREADS 20
 
-#define PREF_WORKERS_ENABLED "dom.workers.enabled"
-#define PREF_WORKERS_MAX_PER_DOMAIN "dom.workers.maxPerDomain"
-#define PREF_WORKERS_GCZEAL "dom.workers.gczeal"
-#define PREF_MAX_SCRIPT_RUN_TIME "dom.max_script_run_time"
+#define PREF_WORKERS_PREFIX "dom.workers."
+#define PREF_WORKERS_ENABLED PREF_WORKERS_PREFIX "enabled"
+#define PREF_WORKERS_MAX_PER_DOMAIN PREF_WORKERS_PREFIX "maxPerDomain"
+
+#define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
+#define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
 
 #define GC_REQUEST_OBSERVER_TOPIC "child-gc-request"
 #define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
 
 #define BROADCAST_ALL_WORKERS(_func, ...)                                      \
   PR_BEGIN_MACRO                                                               \
     AssertIsOnMainThread();                                                    \
                                                                                \
@@ -104,28 +105,38 @@ MOZ_STATIC_ASSERT(MAX_WORKERS_PER_DOMAIN
       AutoSafeJSContext cx;                                                    \
       JSAutoRequest ar(cx);                                                    \
       for (uint32_t index = 0; index < workers.Length(); index++) {            \
         workers[index]-> _func (cx, __VA_ARGS__);                              \
       }                                                                        \
     }                                                                          \
   PR_END_MACRO
 
+// Prefixes for observing preference changes.
+#define PREF_JS_OPTIONS_PREFIX "javascript.options."
+#define PREF_WORKERS_OPTIONS_PREFIX PREF_WORKERS_PREFIX "options."
+#define PREF_MEM_OPTIONS_PREFIX "mem."
+#define PREF_JIT_HARDENING "jit_hardening"
+#define PREF_GCZEAL "gcZeal"
+
 namespace {
 
 const uint32_t kNoIndex = uint32_t(-1);
 
 const uint32_t kRequiredJSContextOptions =
   JSOPTION_DONT_REPORT_UNCAUGHT | JSOPTION_NO_SCRIPT_RVAL;
 
 uint32_t gMaxWorkersPerDomain = MAX_WORKERS_PER_DOMAIN;
 
 // Does not hold an owning reference.
 RuntimeService* gRuntimeService = nullptr;
 
+// Only non-null during the call to Init.
+RuntimeService* gRuntimeServiceDuringInit = nullptr;
+
 enum {
   ID_Worker = 0,
   ID_ChromeWorker,
   ID_Event,
   ID_MessageEvent,
   ID_ErrorEvent,
 
   ID_COUNT
@@ -143,110 +154,438 @@ const char* gStringChars[] = {
 
   // XXX Don't care about ProgressEvent since it should never leak to the main
   // thread.
 };
 
 MOZ_STATIC_ASSERT(NS_ARRAY_LENGTH(gStringChars) == ID_COUNT,
                   "gStringChars should have the right length.");
 
-enum {
-  PREF_strict = 0,
-  PREF_werror,
-  PREF_typeinference,
-  PREF_jit_hardening,
-  PREF_mem_max,
-  PREF_baselinejit,
-  PREF_ion,
-  PREF_asmjs,
-  PREF_mem_gc_allocation_threshold_mb,
+class LiteralRebindingCString : public nsDependentCString
+{
+public:
+  template<int N>
+  void RebindLiteral(const char (&aStr)[N])
+  {
+    Rebind(aStr, N-1);
+  }
+};
+
+template <typename T>
+struct PrefTraits;
+
+template <>
+struct PrefTraits<bool>
+{
+  typedef bool PrefValueType;
+
+  static const PrefValueType kDefaultValue = false;
+
+  static inline PrefValueType
+  Get(const char* aPref)
+  {
+    AssertIsOnMainThread();
+    return Preferences::GetBool(aPref);
+  }
 
-#ifdef JS_GC_ZEAL
-  PREF_gczeal,
-#endif
+  static inline bool
+  Exists(const char* aPref)
+  {
+    AssertIsOnMainThread();
+    return Preferences::GetType(aPref) == nsIPrefBranch::PREF_BOOL;
+  }
+};
+
+template <>
+struct PrefTraits<int32_t>
+{
+  typedef int32_t PrefValueType;
 
-  PREF_COUNT
+  static const PrefValueType kDefaultValue = 0;
+
+  static inline PrefValueType
+  Get(const char* aPref)
+  {
+    AssertIsOnMainThread();
+    return Preferences::GetInt(aPref);
+  }
+
+  static inline bool
+  Exists(const char* aPref)
+  {
+    AssertIsOnMainThread();
+    return Preferences::GetType(aPref) == nsIPrefBranch::PREF_INT;
+  }
 };
 
-#define JS_OPTIONS_DOT_STR "javascript.options."
+template <typename T>
+T
+GetWorkerPref(const nsACString& aPref,
+              const T aDefault = PrefTraits<T>::kDefaultValue)
+{
+  AssertIsOnMainThread();
+
+  typedef PrefTraits<T> PrefHelper;
+
+  T result;
+
+  nsAutoCString prefName;
+  prefName.AssignLiteral(PREF_WORKERS_OPTIONS_PREFIX);
+  prefName.Append(aPref);
+
+  if (PrefHelper::Exists(prefName.get())) {
+    result = PrefHelper::Get(prefName.get());
+  }
+  else {
+    prefName.AssignLiteral(PREF_JS_OPTIONS_PREFIX);
+    prefName.Append(aPref);
 
-const char* gPrefsToWatch[] = {
-  JS_OPTIONS_DOT_STR "strict",
-  JS_OPTIONS_DOT_STR "werror",
-  JS_OPTIONS_DOT_STR "typeinference",
-  JS_OPTIONS_DOT_STR "jit_hardening",
-  JS_OPTIONS_DOT_STR "mem.max",
-  JS_OPTIONS_DOT_STR "baselinejit.content",
-  JS_OPTIONS_DOT_STR "ion.content",
-  JS_OPTIONS_DOT_STR "asmjs",
-  "dom.workers.mem.gc_allocation_threshold_mb"
+    if (PrefHelper::Exists(prefName.get())) {
+      result = PrefHelper::Get(prefName.get());
+    }
+    else {
+      result = aDefault;
+    }
+  }
+
+  return result;
+}
+
+int
+LoadJSContextOptions(const char* aPrefName, void* /* aClosure */)
+{
+  AssertIsOnMainThread();
+
+  RuntimeService* rts = RuntimeService::GetService();
+  if (!rts && !gRuntimeServiceDuringInit) {
+    // May be shutting down, just bail.
+    return 0;
+  }
+
+  const nsDependentCString prefName(aPrefName);
+
+  // Several other pref branches will get included here so bail out if there is
+  // another callback that will handle this change.
+  if (StringBeginsWith(prefName,
+                       NS_LITERAL_CSTRING(PREF_JS_OPTIONS_PREFIX
+                                          PREF_MEM_OPTIONS_PREFIX)) ||
+      StringBeginsWith(prefName,
+                       NS_LITERAL_CSTRING(PREF_WORKERS_OPTIONS_PREFIX
+                                          PREF_MEM_OPTIONS_PREFIX)) ||
+      prefName.EqualsLiteral(PREF_JS_OPTIONS_PREFIX PREF_JIT_HARDENING) ||
+      prefName.EqualsLiteral(PREF_WORKERS_OPTIONS_PREFIX PREF_JIT_HARDENING)) {
+    return 0;
+  }
 
 #ifdef JS_GC_ZEAL
-  , PREF_WORKERS_GCZEAL
+  if (prefName.EqualsLiteral(PREF_JS_OPTIONS_PREFIX PREF_GCZEAL) ||
+      prefName.EqualsLiteral(PREF_WORKERS_OPTIONS_PREFIX PREF_GCZEAL)) {
+    return 0;
+  }
 #endif
-};
+
+  // Common options.
+  uint32_t commonOptions = kRequiredJSContextOptions;
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("strict"))) {
+    commonOptions |= JSOPTION_STRICT;
+  }
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("werror"))) {
+    commonOptions |= JSOPTION_WERROR;
+  }
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("typeinference"))) {
+    commonOptions |= JSOPTION_TYPE_INFERENCE;
+  }
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("asmjs"))) {
+    commonOptions |= JSOPTION_ASMJS;
+  }
 
-MOZ_STATIC_ASSERT(NS_ARRAY_LENGTH(gPrefsToWatch) == PREF_COUNT,
-                  "gPrefsToWatch should have the right length.");
+  // Content options.
+  uint32_t contentOptions = commonOptions;
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("pccounts.content"))) {
+    contentOptions |= JSOPTION_PCCOUNT;
+  }
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("baselinejit.content"))) {
+    contentOptions |= JSOPTION_BASELINE;
+  }
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("ion.content"))) {
+    contentOptions |= JSOPTION_ION;
+  }
 
+  // Chrome options.
+  uint32_t chromeOptions = commonOptions;
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("pccounts.chrome"))) {
+    chromeOptions |= JSOPTION_PCCOUNT;
+  }
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("baselinejit.chrome"))) {
+    chromeOptions |= JSOPTION_BASELINE;
+  }
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("ion.chrome"))) {
+    chromeOptions |= JSOPTION_ION;
+  }
+#ifdef DEBUG
+  if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("strict.debug"))) {
+    chromeOptions |= JSOPTION_STRICT;
+  }
+#endif
+
+  RuntimeService::SetDefaultJSContextOptions(contentOptions, chromeOptions);
+
+  if (rts) {
+    rts->UpdateAllWorkerJSContextOptions();
+  }
+
+  return 0;
+}
+
+#ifdef JS_GC_ZEAL
 int
-PrefCallback(const char* aPrefName, void* aClosure)
+LoadGCZealOptions(const char* /* aPrefName */, void* /* aClosure */)
 {
   AssertIsOnMainThread();
 
-  RuntimeService* rts = static_cast<RuntimeService*>(aClosure);
-  NS_ASSERTION(rts, "This should never be null!");
+  RuntimeService* rts = RuntimeService::GetService();
+  if (!rts && !gRuntimeServiceDuringInit) {
+    // May be shutting down, just bail.
+    return 0;
+  }
+
+  int32_t gczeal = GetWorkerPref<int32_t>(NS_LITERAL_CSTRING(PREF_GCZEAL), -1);
+  if (gczeal < 0) {
+    gczeal = 0;
+  }
+
+  int32_t frequency =
+    GetWorkerPref<int32_t>(NS_LITERAL_CSTRING("gcZeal.frequency"), -1);
+  if (frequency < 0) {
+    frequency = JS_DEFAULT_ZEAL_FREQ;
+  }
+
+  RuntimeService::SetDefaultGCZeal(uint8_t(gczeal), uint32_t(frequency));
+
+  if (rts) {
+    rts->UpdateAllWorkerGCZeal();
+  }
 
-  NS_NAMED_LITERAL_CSTRING(jsOptionStr, JS_OPTIONS_DOT_STR);
+  return 0;
+}
+#endif
+
+void
+UpdateCommonJSGCMemoryOption(RuntimeService* aRuntimeService,
+                             const nsACString& aPrefName, JSGCParamKey aKey)
+{
+  AssertIsOnMainThread();
+  NS_ASSERTION(!aPrefName.IsEmpty(), "Empty pref name!");
+
+  int32_t prefValue = GetWorkerPref(aPrefName, -1);
+  uint32_t value =
+    (prefValue <= 0 || prefValue >= 10000) ? 0 : uint32_t(prefValue);
+
+  RuntimeService::SetDefaultJSGCSettings(aKey, value);
+
+  if (aRuntimeService) {
+    aRuntimeService->UpdateAllWorkerMemoryParameter(aKey, value);
+  }
+}
+
+void
+UpdatOtherJSGCMemoryOption(RuntimeService* aRuntimeService,
+                           JSGCParamKey aKey, uint32_t aValue)
+{
+  AssertIsOnMainThread();
+
+  RuntimeService::SetDefaultJSGCSettings(aKey, aValue);
 
-  if (!strcmp(aPrefName, gPrefsToWatch[PREF_mem_max])) {
-    int32_t pref = Preferences::GetInt(aPrefName, -1);
-    uint32_t maxBytes = (pref <= 0 || pref >= 0x1000) ?
-                        uint32_t(-1) :
-                        uint32_t(pref) * 1024 * 1024;
-    RuntimeService::SetDefaultJSWorkerMemoryParameter(JSGC_MAX_BYTES, maxBytes);
-    rts->UpdateAllWorkerMemoryParameter(JSGC_MAX_BYTES);
-  } else if (!strcmp(aPrefName, gPrefsToWatch[PREF_mem_gc_allocation_threshold_mb])) {
-    int32_t pref = Preferences::GetInt(aPrefName, 30);
-    uint32_t threshold = (pref <= 0 || pref >= 0x1000) ?
-                          uint32_t(30) :
-                          uint32_t(pref);
-    RuntimeService::SetDefaultJSWorkerMemoryParameter(JSGC_ALLOCATION_THRESHOLD, threshold);
-    rts->UpdateAllWorkerMemoryParameter(JSGC_ALLOCATION_THRESHOLD);
-  } else if (StringBeginsWith(nsDependentCString(aPrefName), jsOptionStr)) {
-    uint32_t newOptions = kRequiredJSContextOptions;
-    if (Preferences::GetBool(gPrefsToWatch[PREF_strict])) {
-      newOptions |= JSOPTION_STRICT;
-    }
-    if (Preferences::GetBool(gPrefsToWatch[PREF_werror])) {
-      newOptions |= JSOPTION_WERROR;
-    }
-    if (Preferences::GetBool(gPrefsToWatch[PREF_typeinference])) {
-      newOptions |= JSOPTION_TYPE_INFERENCE;
-    }
-    if (Preferences::GetBool(gPrefsToWatch[PREF_baselinejit])) {
-      newOptions |= JSOPTION_BASELINE;
-    }
-    if (Preferences::GetBool(gPrefsToWatch[PREF_ion])) {
-      newOptions |= JSOPTION_ION;
-    }
-    if (Preferences::GetBool(gPrefsToWatch[PREF_asmjs])) {
-      newOptions |= JSOPTION_ASMJS;
+  if (aRuntimeService) {
+    aRuntimeService->UpdateAllWorkerMemoryParameter(aKey, aValue);
+  }
+}
+
+
+int
+LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
+{
+  AssertIsOnMainThread();
+
+  RuntimeService* rts = RuntimeService::GetService();
+
+  if (!rts && !gRuntimeServiceDuringInit) {
+    // May be shutting down, just bail.
+    return 0;
+  }
+
+  NS_NAMED_LITERAL_CSTRING(jsPrefix, PREF_JS_OPTIONS_PREFIX);
+  NS_NAMED_LITERAL_CSTRING(workersPrefix, PREF_WORKERS_OPTIONS_PREFIX);
+
+  const nsDependentCString fullPrefName(aPrefName);
+
+  // Pull out the string that actually distinguishes the parameter we need to
+  // change.
+  nsDependentCSubstring memPrefName;
+  if (StringBeginsWith(fullPrefName, jsPrefix)) {
+    memPrefName.Rebind(fullPrefName, jsPrefix.Length());
+  }
+  else if (StringBeginsWith(fullPrefName, workersPrefix)) {
+    memPrefName.Rebind(fullPrefName, workersPrefix.Length());
+  }
+  else {
+    NS_ERROR("Unknown pref name!");
+    return 0;
+  }
+
+#ifdef DEBUG
+  // During Init() we get called back with a branch string here, so there should
+  // be no just a "mem." pref here.
+  if (!rts) {
+    NS_ASSERTION(memPrefName.EqualsLiteral(PREF_MEM_OPTIONS_PREFIX), "Huh?!");
+  }
+#endif
+
+  // If we're running in Init() then do this for every pref we care about.
+  // Otherwise we just want to update the parameter that changed.
+  for (uint32_t index = rts ? JSSettings::kGCSettingsArraySize - 1 : 0;
+       index < JSSettings::kGCSettingsArraySize;
+       index++) {
+    LiteralRebindingCString matchName;
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "max");
+    if (memPrefName == matchName || (!rts && index == 0)) {
+      int32_t prefValue = GetWorkerPref(matchName, -1);
+      uint32_t value = (prefValue <= 0 || prefValue >= 0x1000) ?
+                       uint32_t(-1) :
+                       uint32_t(prefValue) * 1024 * 1024;
+      UpdatOtherJSGCMemoryOption(rts, JSGC_MAX_BYTES, value);
+      continue;
     }
 
-    RuntimeService::SetDefaultJSContextOptions(newOptions);
-    rts->UpdateAllWorkerJSContextOptions();
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "high_water_mark");
+    if (memPrefName == matchName || (!rts && index == 1)) {
+      int32_t prefValue = GetWorkerPref(matchName, 128);
+      UpdatOtherJSGCMemoryOption(rts, JSGC_MAX_MALLOC_BYTES,
+                                 uint32_t(prefValue) * 1024 * 1024);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX 
+                            "gc_high_frequency_time_limit_ms");
+    if (memPrefName == matchName || (!rts && index == 2)) {
+      UpdateCommonJSGCMemoryOption(rts, matchName,
+                                   JSGC_HIGH_FREQUENCY_TIME_LIMIT);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
+                            "gc_low_frequency_heap_growth");
+    if (memPrefName == matchName || (!rts && index == 3)) {
+      UpdateCommonJSGCMemoryOption(rts, matchName,
+                                   JSGC_LOW_FREQUENCY_HEAP_GROWTH);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
+                            "gc_high_frequency_heap_growth_min");
+    if (memPrefName == matchName || (!rts && index == 4)) {
+      UpdateCommonJSGCMemoryOption(rts, matchName,
+                                   JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
+                            "gc_high_frequency_heap_growth_max");
+    if (memPrefName == matchName || (!rts && index == 5)) {
+      UpdateCommonJSGCMemoryOption(rts, matchName,
+                                   JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
+                            "gc_high_frequency_low_limit_mb");
+    if (memPrefName == matchName || (!rts && index == 6)) {
+      UpdateCommonJSGCMemoryOption(rts, matchName,
+                                   JSGC_HIGH_FREQUENCY_LOW_LIMIT);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
+                            "gc_high_frequency_high_limit_mb");
+    if (memPrefName == matchName || (!rts && index == 7)) {
+      UpdateCommonJSGCMemoryOption(rts, matchName,
+                                   JSGC_HIGH_FREQUENCY_HIGH_LIMIT);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "analysis_purge_mb");
+    if (memPrefName == matchName || (!rts && index == 8)) {
+      UpdateCommonJSGCMemoryOption(rts, matchName, JSGC_ANALYSIS_PURGE_TRIGGER);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
+                            "gc_allocation_threshold_mb");
+    if (memPrefName == matchName || (!rts && index == 9)) {
+      UpdateCommonJSGCMemoryOption(rts, matchName, JSGC_ALLOCATION_THRESHOLD);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "gc_incremental_slice_ms");
+    if (memPrefName == matchName || (!rts && index == 10)) {
+      int32_t prefValue = GetWorkerPref(matchName, -1);
+      uint32_t value =
+        (prefValue <= 0 || prefValue >= 100000) ? 0 : uint32_t(prefValue);
+      UpdatOtherJSGCMemoryOption(rts, JSGC_SLICE_TIME_BUDGET, value);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "gc_dynamic_heap_growth");
+    if (memPrefName == matchName || (!rts && index == 11)) {
+      bool prefValue = GetWorkerPref(matchName, false);
+      UpdatOtherJSGCMemoryOption(rts, JSGC_DYNAMIC_HEAP_GROWTH,
+                                 prefValue ? 0 : 1);
+      continue;
+    }
+
+    matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "gc_dynamic_mark_slice");
+    if (memPrefName == matchName || (!rts && index == 12)) {
+      bool prefValue = GetWorkerPref(matchName, false);
+      UpdatOtherJSGCMemoryOption(rts, JSGC_DYNAMIC_MARK_SLICE,
+                                 prefValue ? 0 : 1);
+      continue;
+    }
+
+#ifdef DEBUG
+    nsAutoCString message("Workers don't support the 'mem.");
+    message.Append(memPrefName);
+    message.AppendLiteral("' preference!");
+    NS_WARNING(message.get());
+#endif
   }
-#ifdef JS_GC_ZEAL
-  else if (!strcmp(aPrefName, gPrefsToWatch[PREF_gczeal])) {
-    int32_t gczeal = Preferences::GetInt(gPrefsToWatch[PREF_gczeal]);
-    RuntimeService::SetDefaultGCZeal(uint8_t(clamped(gczeal, 0, 3)));
-    rts->UpdateAllWorkerGCZeal();
+
+  return 0;
+}
+
+int
+LoadJITHardeningOption(const char* /* aPrefName */, void* /* aClosure */)
+{
+  AssertIsOnMainThread();
+
+  RuntimeService* rts = RuntimeService::GetService();
+
+  if (!rts && !gRuntimeServiceDuringInit) {
+    // May be shutting down, just bail.
+    return 0;
   }
-#endif
+
+  bool value = GetWorkerPref(NS_LITERAL_CSTRING(PREF_JIT_HARDENING), false);
+
+  RuntimeService::SetDefaultJITHardening(value);
+
+  if (rts) {
+    rts->UpdateAllWorkerJITHardening(value);
+  }
+
   return 0;
 }
 
 void
 ErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aReport)
 {
   WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
   return worker->ReportError(aCx, aMessage, aReport);
@@ -417,27 +756,43 @@ CTypesActivityCallback(JSContext* aCx,
 JSContext*
 CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate)
 {
   aWorkerPrivate->AssertIsOnWorkerThread();
   NS_ASSERTION(!aWorkerPrivate->GetJSContext(), "Already has a context!");
 
   // The number passed here doesn't matter, we're about to change it in the call
   // to JS_SetGCParameter.
-  JSRuntime* runtime = JS_NewRuntime(WORKER_DEFAULT_RUNTIME_HEAPSIZE, JS_NO_HELPER_THREADS);
+  JSRuntime* runtime =
+    JS_NewRuntime(WORKER_DEFAULT_RUNTIME_HEAPSIZE, JS_NO_HELPER_THREADS);
   if (!runtime) {
     NS_WARNING("Could not create new runtime!");
     return nullptr;
   }
 
+  JSSettings settings;
+  aWorkerPrivate->CopyJSSettings(settings);
+
+  NS_ASSERTION((settings.chrome.options & kRequiredJSContextOptions) ==
+               kRequiredJSContextOptions,
+               "Somehow we lost our required chrome options!");
+  NS_ASSERTION((settings.content.options & kRequiredJSContextOptions) ==
+               kRequiredJSContextOptions,
+               "Somehow we lost our required content options!");
+
+  JSSettings::JSGCSettingsArray& gcSettings = settings.gcSettings;
+
   // This is the real place where we set the max memory for the runtime.
-  JS_SetGCParameter(runtime, JSGC_MAX_BYTES,
-                    aWorkerPrivate->GetJSRuntimeHeapSize());
-  JS_SetGCParameter(runtime, JSGC_ALLOCATION_THRESHOLD,
-                    aWorkerPrivate->GetJSWorkerAllocationThreshold());
+  for (uint32_t index = 0; index < ArrayLength(gcSettings); index++) {
+    const JSSettings::JSGCSetting& setting = gcSettings[index];
+    if (setting.IsSet()) {
+      NS_ASSERTION(setting.value, "Can't handle 0 values!");
+      JS_SetGCParameter(runtime, setting.key, setting.value);
+    }
+  }
 
   JS_SetNativeStackQuota(runtime, WORKER_CONTEXT_NATIVE_STACK_LIMIT);
 
   // Security policy:
   static JSSecurityCallbacks securityCallbacks = {
     NULL,
     ContentSecurityPolicyAllows
   };
@@ -459,29 +814,24 @@ CreateJSContextForWorker(WorkerPrivate* 
   JS_SetRuntimePrivate(runtime, aWorkerPrivate);
 
   JS_SetErrorReporter(workerCx, ErrorReporter);
 
   JS_SetOperationCallback(workerCx, OperationCallback);
 
   js::SetCTypesActivityCallback(runtime, CTypesActivityCallback);
 
-  NS_ASSERTION((aWorkerPrivate->GetJSContextOptions() &
-                kRequiredJSContextOptions) == kRequiredJSContextOptions,
-               "Somehow we lost our required options!");
-  JS_SetOptions(workerCx, aWorkerPrivate->GetJSContextOptions());
+  JS_SetOptions(workerCx,
+                aWorkerPrivate->IsChromeWorker() ? settings.chrome.options :
+                                                   settings.content.options);
+
+  JS_SetJitHardening(runtime, settings.jitHardening);
 
 #ifdef JS_GC_ZEAL
-  {
-    uint8_t zeal = aWorkerPrivate->GetGCZeal();
-    NS_ASSERTION(zeal <= 3, "Bad zeal value!");
-
-    uint32_t frequency = zeal <= 2 ? JS_DEFAULT_ZEAL_FREQ : 1;
-    JS_SetGCZeal(workerCx, zeal, frequency);
-  }
+  JS_SetGCZeal(workerCx, settings.gcZeal, settings.gcZealFrequency);
 #endif
 
   if (aWorkerPrivate->IsChromeWorker()) {
     JS_SetVersion(workerCx, JSVERSION_LATEST);
   }
 
   return workerCx;
 }
@@ -645,17 +995,17 @@ SuspendWorkersForWindow(JSContext* aCx, 
   AssertIsOnMainThread();
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->SuspendWorkersForWindow(aCx, aWindow);
   }
 }
 
 void
-ResumeWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow)
+ResumeWorkersForWindow(nsIScriptContext* aCx, nsPIDOMWindow* aWindow)
 {
   AssertIsOnMainThread();
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->ResumeWorkersForWindow(aCx, aWindow);
   }
 }
 
@@ -702,29 +1052,18 @@ WorkerCrossThreadDispatcher::PostTask(Wo
 
   nsRefPtr<WorkerTaskRunnable> runnable = new WorkerTaskRunnable(mPrivate, aTask);
   runnable->Dispatch(nullptr);
   return true;
 }
 
 END_WORKERS_NAMESPACE
 
-uint32_t RuntimeService::sDefaultJSContextOptions = kRequiredJSContextOptions;
-
-uint32_t RuntimeService::sDefaultJSRuntimeHeapSize =
-  WORKER_DEFAULT_RUNTIME_HEAPSIZE;
-
-uint32_t RuntimeService::sDefaultJSAllocationThreshold =
-  WORKER_DEFAULT_ALLOCATION_THRESHOLD;
-
-int32_t RuntimeService::sCloseHandlerTimeoutSeconds = MAX_SCRIPT_RUN_TIME_SEC;
-
-#ifdef JS_GC_ZEAL
-uint8_t RuntimeService::sDefaultGCZeal = 0;
-#endif
+// This is only touched on the main thread. Initialized in Init() below.
+JSSettings RuntimeService::sDefaultJSSettings;
 
 RuntimeService::RuntimeService()
 : mMutex("RuntimeService::mMutex"), mObserved(false),
   mShuttingDown(false), mNavigatorStringsLoaded(false)
 {
   AssertIsOnMainThread();
   NS_ASSERTION(!gRuntimeService, "More than one service!");
 }
@@ -967,22 +1306,25 @@ RuntimeService::ScheduleWorker(JSContext
   if (!thread) {
     if (NS_FAILED(NS_NewNamedThread("DOM Worker",
                                     getter_AddRefs(thread), nullptr,
                                     WORKER_STACK_SIZE))) {
       UnregisterWorker(aCx, aWorkerPrivate);
       JS_ReportError(aCx, "Could not create new thread!");
       return false;
     }
+  }
 
-    nsCOMPtr<nsISupportsPriority> priority = do_QueryInterface(thread);
-    if (!priority ||
-        NS_FAILED(priority->SetPriority(nsISupportsPriority::PRIORITY_LOW))) {
-      NS_WARNING("Could not lower the new thread's priority!");
-    }
+  int32_t priority = aWorkerPrivate->IsChromeWorker() ?
+                     nsISupportsPriority::PRIORITY_NORMAL :
+                     nsISupportsPriority::PRIORITY_LOW;
+
+  nsCOMPtr<nsISupportsPriority> threadPriority = do_QueryInterface(thread);
+  if (!threadPriority || NS_FAILED(threadPriority->SetPriority(priority))) {
+    NS_WARNING("Could not set the thread's priority!");
   }
 
 #ifdef DEBUG
   aWorkerPrivate->SetThread(thread);
 #endif
 
   nsCOMPtr<nsIRunnable> runnable = new WorkerThreadRunnable(aWorkerPrivate);
   if (NS_FAILED(thread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
@@ -1053,18 +1395,34 @@ RuntimeService::ShutdownIdleThreads(nsIT
     }
   }
 }
 
 nsresult
 RuntimeService::Init()
 {
   AssertIsOnMainThread();
+
   nsLayoutStatics::AddRef();
 
+  // Initialize JSSettings.
+  if (!sDefaultJSSettings.gcSettings[0].IsSet()) {
+    sDefaultJSSettings.chrome.options = kRequiredJSContextOptions;
+    sDefaultJSSettings.chrome.maxScriptRuntime = -1;
+    sDefaultJSSettings.content.options = kRequiredJSContextOptions;
+    sDefaultJSSettings.content.maxScriptRuntime = MAX_SCRIPT_RUN_TIME_SEC;
+#ifdef JS_GC_ZEAL
+    sDefaultJSSettings.gcZealFrequency = JS_DEFAULT_ZEAL_FREQ;
+    sDefaultJSSettings.gcZeal = 0;
+#endif
+    SetDefaultJSGCSettings(JSGC_MAX_BYTES, WORKER_DEFAULT_RUNTIME_HEAPSIZE);
+    SetDefaultJSGCSettings(JSGC_ALLOCATION_THRESHOLD,
+                           WORKER_DEFAULT_ALLOCATION_THRESHOLD);
+  }
+
   mIdleThreadTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
   NS_ENSURE_STATE(mIdleThreadTimer);
 
   mDomainMap.Init();
   mWindowMap.Init();
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
@@ -1079,31 +1437,69 @@ RuntimeService::Init()
     NS_WARNING("Failed to register for GC request notifications!");
   }
 
   if (NS_FAILED(obs->AddObserver(this, MEMORY_PRESSURE_OBSERVER_TOPIC,
                                  false))) {
     NS_WARNING("Failed to register for memory pressure notifications!");
   }
 
-  for (uint32_t index = 0; index < ArrayLength(gPrefsToWatch); index++) {
-    if (NS_FAILED(Preferences::RegisterCallback(PrefCallback,
-                                                gPrefsToWatch[index], this))) {
-      NS_WARNING("Failed to register pref callback?!");
-    }
-    PrefCallback(gPrefsToWatch[index], this);
+  NS_ASSERTION(!gRuntimeServiceDuringInit, "This should be null!");
+  gRuntimeServiceDuringInit = this;
+
+  if (NS_FAILED(Preferences::RegisterCallback(
+                                 LoadJSGCMemoryOptions,
+                                 PREF_JS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX,
+                                 nullptr)) ||
+      NS_FAILED(Preferences::RegisterCallbackAndCall(
+                            LoadJSGCMemoryOptions,
+                            PREF_WORKERS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX,
+                            nullptr)) ||
+      NS_FAILED(Preferences::RegisterCallback(
+                                      LoadJITHardeningOption,
+                                      PREF_JS_OPTIONS_PREFIX PREF_JIT_HARDENING,
+                                      nullptr)) ||
+      NS_FAILED(Preferences::RegisterCallbackAndCall(
+                                 LoadJITHardeningOption,
+                                 PREF_WORKERS_OPTIONS_PREFIX PREF_JIT_HARDENING,
+                                 nullptr)) ||
+#ifdef JS_GC_ZEAL
+      NS_FAILED(Preferences::RegisterCallback(
+                                             LoadGCZealOptions,
+                                             PREF_JS_OPTIONS_PREFIX PREF_GCZEAL,
+                                             nullptr)) ||
+      NS_FAILED(Preferences::RegisterCallbackAndCall(
+                                        LoadGCZealOptions,
+                                        PREF_WORKERS_OPTIONS_PREFIX PREF_GCZEAL,
+                                        nullptr)) ||
+#endif
+      NS_FAILED(Preferences::RegisterCallback(LoadJSContextOptions,
+                                              PREF_JS_OPTIONS_PREFIX,
+                                              nullptr)) ||
+      NS_FAILED(Preferences::RegisterCallbackAndCall(
+                                                    LoadJSContextOptions,
+                                                    PREF_WORKERS_OPTIONS_PREFIX,
+                                                    nullptr))) {
+    NS_WARNING("Failed to register pref callbacks!");
   }
 
+  NS_ASSERTION(gRuntimeServiceDuringInit == this, "Should be 'this'!");
+  gRuntimeServiceDuringInit = nullptr;
+
   // We assume atomic 32bit reads/writes. If this assumption doesn't hold on
   // some wacky platform then the worst that could happen is that the close
   // handler will run for a slightly different amount of time.
-  if (NS_FAILED(Preferences::AddIntVarCache(&sCloseHandlerTimeoutSeconds,
-                                            PREF_MAX_SCRIPT_RUN_TIME,
-                                            MAX_SCRIPT_RUN_TIME_SEC))) {
-      NS_WARNING("Failed to register timeout cache?!");
+  if (NS_FAILED(Preferences::AddIntVarCache(
+                                   &sDefaultJSSettings.content.maxScriptRuntime,
+                                   PREF_MAX_SCRIPT_RUN_TIME_CONTENT,
+                                   MAX_SCRIPT_RUN_TIME_SEC)) ||
+      NS_FAILED(Preferences::AddIntVarCache(
+                                    &sDefaultJSSettings.chrome.maxScriptRuntime,
+                                    PREF_MAX_SCRIPT_RUN_TIME_CHROME, -1))) {
+    NS_WARNING("Failed to register timeout cache!");
   }
 
   int32_t maxPerDomain = Preferences::GetInt(PREF_WORKERS_MAX_PER_DOMAIN,
                                              MAX_WORKERS_PER_DOMAIN);
   gMaxWorkersPerDomain = std::max(0, maxPerDomain);
 
   mDetectorName = Preferences::GetLocalizedCString("intl.charset.detector");
 
@@ -1210,18 +1606,49 @@ RuntimeService::Cleanup()
     }
   }
 
   if (mWindowMap.IsInitialized()) {
     NS_ASSERTION(!mWindowMap.Count(), "All windows should have been released!");
   }
 
   if (mObserved) {
-    for (uint32_t index = 0; index < ArrayLength(gPrefsToWatch); index++) {
-      Preferences::UnregisterCallback(PrefCallback, gPrefsToWatch[index], this);
+    if (NS_FAILED(Preferences::UnregisterCallback(LoadJSContextOptions,
+                                                  PREF_JS_OPTIONS_PREFIX,
+                                                  nullptr)) ||
+        NS_FAILED(Preferences::UnregisterCallback(LoadJSContextOptions,
+                                                  PREF_WORKERS_OPTIONS_PREFIX,
+                                                  nullptr)) ||
+#ifdef JS_GC_ZEAL
+        NS_FAILED(Preferences::UnregisterCallback(
+                                             LoadGCZealOptions,
+                                             PREF_JS_OPTIONS_PREFIX PREF_GCZEAL,
+                                             nullptr)) ||
+        NS_FAILED(Preferences::UnregisterCallback(
+                                        LoadGCZealOptions,
+                                        PREF_WORKERS_OPTIONS_PREFIX PREF_GCZEAL,
+                                        nullptr)) ||
+#endif
+        NS_FAILED(Preferences::UnregisterCallback(
+                                 LoadJSGCMemoryOptions,
+                                 PREF_JS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX,
+                                 nullptr)) ||
+        NS_FAILED(Preferences::UnregisterCallback(
+                            LoadJSGCMemoryOptions,
+                            PREF_WORKERS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX,
+                            nullptr)) ||
+        NS_FAILED(Preferences::UnregisterCallback(
+                                      LoadJITHardeningOption,
+                                      PREF_JS_OPTIONS_PREFIX PREF_JIT_HARDENING,
+                                      nullptr)) ||
+        NS_FAILED(Preferences::UnregisterCallback(
+                                 LoadJITHardeningOption,
+                                 PREF_WORKERS_OPTIONS_PREFIX PREF_JIT_HARDENING,
+                                 nullptr))) {
+      NS_WARNING("Failed to unregister pref callbacks!");
     }
 
     if (obs) {
       if (NS_FAILED(obs->RemoveObserver(this, GC_REQUEST_OBSERVER_TOPIC))) {
         NS_WARNING("Failed to unregister for GC request notifications!");
       }
 
       if (NS_FAILED(obs->RemoveObserver(this,
@@ -1316,27 +1743,27 @@ RuntimeService::SuspendWorkersForWindow(
       if (!workers[index]->Suspend(aCx)) {
         NS_WARNING("Failed to cancel worker!");
       }
     }
   }
 }
 
 void
-RuntimeService::ResumeWorkersForWindow(JSContext* aCx,
+RuntimeService::ResumeWorkersForWindow(nsIScriptContext* aCx,
                                        nsPIDOMWindow* aWindow)
 {
   AssertIsOnMainThread();
 
   nsAutoTArray<WorkerPrivate*, 100> workers;
   GetWorkersForWindow(aWindow, workers);
 
   if (!workers.IsEmpty()) {
     for (uint32_t index = 0; index < workers.Length(); index++) {
-      if (!workers[index]->Resume(aCx)) {
+      if (!workers[index]->SynchronizeAndResume(aCx)) {
         NS_WARNING("Failed to cancel worker!");
       }
     }
   }
 }
 
 void
 RuntimeService::NoteIdleThread(nsIThread* aThread)
@@ -1382,36 +1809,44 @@ RuntimeService::NoteIdleThread(nsIThread
                                        nsITimer::TYPE_ONE_SHOT))) {
     NS_ERROR("Can't schedule timer!");
   }
 }
 
 void
 RuntimeService::UpdateAllWorkerJSContextOptions()
 {
-  BROADCAST_ALL_WORKERS(UpdateJSContextOptions, GetDefaultJSContextOptions());
+  BROADCAST_ALL_WORKERS(UpdateJSContextOptions,
+                        sDefaultJSSettings.content.options,
+                        sDefaultJSSettings.chrome.options);
 }
 
 void
-RuntimeService::UpdateAllWorkerMemoryParameter(JSGCParamKey key)
+RuntimeService::UpdateAllWorkerMemoryParameter(JSGCParamKey aKey,
+                                               uint32_t aValue)
 {
-  BROADCAST_ALL_WORKERS(UpdateJSWorkerMemoryParameter,
-                        key,
-                        GetDefaultJSWorkerMemoryParameter(key));
+  BROADCAST_ALL_WORKERS(UpdateJSWorkerMemoryParameter, aKey, aValue);
 }
 
 #ifdef JS_GC_ZEAL
 void
 RuntimeService::UpdateAllWorkerGCZeal()
 {
-  BROADCAST_ALL_WORKERS(UpdateGCZeal, GetDefaultGCZeal());
+  BROADCAST_ALL_WORKERS(UpdateGCZeal, sDefaultJSSettings.gcZeal,
+                        sDefaultJSSettings.gcZealFrequency);
 }
 #endif
 
 void
+RuntimeService::UpdateAllWorkerJITHardening(bool aJITHardening)
+{
+  BROADCAST_ALL_WORKERS(UpdateJITHardening, aJITHardening);
+}
+
+void
 RuntimeService::GarbageCollectAllWorkers(bool aShrinking)
 {
   BROADCAST_ALL_WORKERS(GarbageCollect, aShrinking);
 }
 
 // nsISupports
 NS_IMPL_ISUPPORTS1(RuntimeService, nsIObserver)
 
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -7,25 +7,25 @@
 #ifndef mozilla_dom_workers_runtimeservice_h__
 #define mozilla_dom_workers_runtimeservice_h__
 
 #include "Workers.h"
 
 #include "nsIObserver.h"
 
 #include "jsapi.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/TimeStamp.h"
 #include "nsAutoPtr.h"
 #include "nsClassHashtable.h"
 #include "nsCOMPtr.h"
 #include "nsHashKeys.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
-#include "mozilla/Attributes.h"
 
 class nsIThread;
 class nsITimer;
 class nsPIDOMWindow;
 
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerPrivate;
@@ -66,24 +66,17 @@ class RuntimeService MOZ_FINAL : public 
   nsClassHashtable<nsPtrHashKey<nsPIDOMWindow>, nsTArray<WorkerPrivate*> > mWindowMap;
 
   // Only used on the main thread.
   nsCOMPtr<nsITimer> mIdleThreadTimer;
 
   nsCString mDetectorName;
   nsCString mSystemCharset;
 
-  static uint32_t sDefaultJSContextOptions;
-  static uint32_t sDefaultJSRuntimeHeapSize;
-  static uint32_t sDefaultJSAllocationThreshold;
-  static int32_t sCloseHandlerTimeoutSeconds;
-
-#ifdef JS_GC_ZEAL
-  static uint8_t sDefaultGCZeal;
-#endif
+  static JSSettings sDefaultJSSettings;
 
 public:
   struct NavigatorStrings
   {
     nsString mAppName;
     nsString mAppVersion;
     nsString mPlatform;
     nsString mUserAgent;
@@ -115,17 +108,17 @@ public:
 
   void
   CancelWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
 
   void
   SuspendWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
 
   void
-  ResumeWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
+  ResumeWorkersForWindow(nsIScriptContext* aCx, nsPIDOMWindow* aWindow);
 
   const nsACString&
   GetDetectorName() const
   {
     return mDetectorName;
   }
 
   const nsACString&
@@ -138,91 +131,79 @@ public:
   GetNavigatorStrings() const
   {
     return mNavigatorStrings;
   }
 
   void
   NoteIdleThread(nsIThread* aThread);
 
-  static uint32_t
-  GetDefaultJSContextOptions()
+  static void
+  GetDefaultJSSettings(JSSettings& aSettings)
   {
     AssertIsOnMainThread();
-    return sDefaultJSContextOptions;
+    aSettings = sDefaultJSSettings;
   }
 
   static void
-  SetDefaultJSContextOptions(uint32_t aOptions)
+  SetDefaultJSContextOptions(uint32_t aContentOptions, uint32_t aChromeOptions)
   {
     AssertIsOnMainThread();
-    sDefaultJSContextOptions = aOptions;
+    sDefaultJSSettings.content.options = aContentOptions;
+    sDefaultJSSettings.chrome.options = aChromeOptions;
   }
 
   void
   UpdateAllWorkerJSContextOptions();
 
-  static uint32_t
-  GetDefaultJSWorkerMemoryParameter(JSGCParamKey aKey)
+  static void
+  SetDefaultJSGCSettings(JSGCParamKey aKey, uint32_t aValue)
   {
     AssertIsOnMainThread();
-    switch (aKey) {
-      case JSGC_ALLOCATION_THRESHOLD:
-        return sDefaultJSAllocationThreshold;
-      case JSGC_MAX_BYTES:
-        return sDefaultJSRuntimeHeapSize;
-      default:
-        MOZ_NOT_REACHED("Unknown Worker Memory Parameter.");
-    }
-  }
-
-  static void
-  SetDefaultJSWorkerMemoryParameter(JSGCParamKey aKey, uint32_t aValue)
-  {
-    AssertIsOnMainThread();
-    switch(aKey) {
-      case JSGC_ALLOCATION_THRESHOLD:
-        sDefaultJSAllocationThreshold = aValue;
-        break;
-      case JSGC_MAX_BYTES:
-        sDefaultJSRuntimeHeapSize = aValue;
-        break;
-      default:
-        MOZ_NOT_REACHED("Unknown Worker Memory Parameter.");
-    }
+    sDefaultJSSettings.ApplyGCSetting(aKey, aValue);
   }
 
   void
-  UpdateAllWorkerMemoryParameter(JSGCParamKey aKey);
+  UpdateAllWorkerMemoryParameter(JSGCParamKey aKey, uint32_t aValue);
 
   static uint32_t
-  GetCloseHandlerTimeoutSeconds()
+  GetContentCloseHandlerTimeoutSeconds()
   {
-    return sCloseHandlerTimeoutSeconds > 0 ? sCloseHandlerTimeoutSeconds : 0;
+    return sDefaultJSSettings.content.maxScriptRuntime;
+  }
+
+  static uint32_t
+  GetChromeCloseHandlerTimeoutSeconds()
+  {
+    return sDefaultJSSettings.chrome.maxScriptRuntime;
   }
 
 #ifdef JS_GC_ZEAL
-  static uint8_t
-  GetDefaultGCZeal()
+  static void
+  SetDefaultGCZeal(uint8_t aGCZeal, uint32_t aFrequency)
   {
     AssertIsOnMainThread();
-    return sDefaultGCZeal;
-  }
-
-  static void
-  SetDefaultGCZeal(uint8_t aGCZeal)
-  {
-    AssertIsOnMainThread();
-    sDefaultGCZeal = aGCZeal;
+    sDefaultJSSettings.gcZeal = aGCZeal;
+    sDefaultJSSettings.gcZealFrequency = aFrequency;
   }
 
   void
   UpdateAllWorkerGCZeal();
 #endif
 
+  static void
+  SetDefaultJITHardening(bool aJITHardening)
+  {
+    AssertIsOnMainThread();
+    sDefaultJSSettings.jitHardening = aJITHardening;
+  }
+
+  void
+  UpdateAllWorkerJITHardening(bool aJITHardening);
+
   void
   GarbageCollectAllWorkers(bool aShrinking);
 
 private:
   RuntimeService();
   ~RuntimeService();
 
   nsresult
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -21,67 +21,64 @@
 #include "nsITextToSubURI.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsIXPConnect.h"
 #include "nsIXPCScriptNotify.h"
 #include "nsPrintfCString.h"
 
+#include <algorithm>
 #include "jsfriendapi.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
 #include "jsprf.h"
 #include "js/MemoryMetrics.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Likely.h"
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsError.h"
 #include "nsDOMJSUtils.h"
 #include "nsGUIEvent.h"
 #include "nsJSEnvironment.h"
 #include "nsJSUtils.h"
 #include "nsNetUtil.h"
 #include "nsProxyRelease.h"
 #include "nsSandboxFlags.h"
 #include "nsThreadUtils.h"
 #include "xpcpublic.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/Likely.h"
-#include <algorithm>
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 #include "Events.h"
 #include "Exceptions.h"
 #include "File.h"
 #include "ImageData.h"
 #include "Principal.h"
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "Worker.h"
 #include "WorkerFeature.h"
 #include "WorkerScope.h"
 
-#if 0 // Define to run GC more often.
-#define EXTRA_GC
-#endif
-
 // GC will run once every thirty seconds during normal execution.
 #define NORMAL_GC_TIMER_DELAY_MS 30000
 
 // GC will run five seconds after the last event is processed.
 #define IDLE_GC_TIMER_DELAY_MS 5000
 
 using mozilla::MutexAutoLock;
 using mozilla::TimeDuration;
 using mozilla::TimeStamp;
 using mozilla::dom::workers::exceptions::ThrowDOMExceptionForNSResult;
+using mozilla::AutoPushJSContext;
 using mozilla::AutoSafeJSContext;
 
 USING_WORKERS_NAMESPACE
 using namespace mozilla::dom::workers::events;
 using namespace mozilla::dom;
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsWorkerMallocSizeOf)
 
@@ -1302,29 +1299,32 @@ public:
     }
 
     return true;
   }
 };
 
 class UpdateJSContextOptionsRunnable : public WorkerControlRunnable
 {
-  uint32_t mOptions;
+  uint32_t mContentOptions;
+  uint32_t mChromeOptions;
 
 public:
   UpdateJSContextOptionsRunnable(WorkerPrivate* aWorkerPrivate,
-                                 uint32_t aOptions)
+                                 uint32_t aContentOptions,
+                                 uint32_t aChromeOptions)
   : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
-    mOptions(aOptions)
+    mContentOptions(aContentOptions), mChromeOptions(aChromeOptions)
   { }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
-    aWorkerPrivate->UpdateJSContextOptionsInternal(aCx, mOptions);
+    aWorkerPrivate->UpdateJSContextOptionsInternal(aCx, mContentOptions,
+                                                   mChromeOptions);
     return true;
   }
 };
 
 class UpdateJSWorkerMemoryParameterRunnable : public WorkerControlRunnable
 {
   uint32_t mValue;
   JSGCParamKey mKey;
@@ -1344,33 +1344,53 @@ public:
     return true;
   }
 };
 
 #ifdef JS_GC_ZEAL
 class UpdateGCZealRunnable : public WorkerControlRunnable
 {
   uint8_t mGCZeal;
+  uint32_t mFrequency;
 
 public:
   UpdateGCZealRunnable(WorkerPrivate* aWorkerPrivate,
-                       uint8_t aGCZeal)
+                       uint8_t aGCZeal,
+                       uint32_t aFrequency)
   : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
-    mGCZeal(aGCZeal)
+    mGCZeal(aGCZeal), mFrequency(aFrequency)
   { }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
-    aWorkerPrivate->UpdateGCZealInternal(aCx, mGCZeal);
+    aWorkerPrivate->UpdateGCZealInternal(aCx, mGCZeal, mFrequency);
     return true;
   }
 };
 #endif
 
+class UpdateJITHardeningRunnable : public WorkerControlRunnable
+{
+  bool mJITHardening;
+
+public:
+  UpdateJITHardeningRunnable(WorkerPrivate* aWorkerPrivate, bool aJITHardening)
+  : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
+    mJITHardening(aJITHardening)
+  { }
+
+  bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+  {
+    aWorkerPrivate->UpdateJITHardeningInternal(aCx, mJITHardening);
+    return true;
+  }
+};
+
 class GarbageCollectRunnable : public WorkerControlRunnable
 {
 protected:
   bool mShrinking;
   bool mCollectChildren;
 
 public:
   GarbageCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aShrinking,
@@ -1398,16 +1418,43 @@ public:
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     aWorkerPrivate->GarbageCollectInternal(aCx, mShrinking, mCollectChildren);
     return true;
   }
 };
 
+class SynchronizeAndResumeRunnable : public nsRunnable
+{
+protected:
+  WorkerPrivate* mWorkerPrivate;
+  nsCOMPtr<nsIScriptContext> mCx;
+
+public:
+  SynchronizeAndResumeRunnable(WorkerPrivate* aWorkerPrivate,
+                               nsIScriptContext* aCx)
+  : mWorkerPrivate(aWorkerPrivate), mCx(aCx)
+  {
+    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  }
+
+  NS_IMETHOD Run()
+  {
+    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+    AutoPushJSContext cx(mCx ? mCx->GetNativeContext() :
+                         nsContentUtils::GetSafeJSContext());
+    JSAutoRequest ar(cx);
+    mWorkerPrivate->Resume(cx);
+
+    return NS_OK;
+  }
+};
+
 class WorkerJSRuntimeStats : public JS::RuntimeStats
 {
   const nsACString& mRtPath;
 
 public:
   WorkerJSRuntimeStats(const nsACString& aRtPath)
   : JS::RuntimeStats(JsWorkerMallocSizeOf), mRtPath(aRtPath)
   { }
@@ -1807,19 +1854,17 @@ WorkerPrivateParent<Derived>::WorkerPriv
                                      nsCOMPtr<nsIContentSecurityPolicy>& aCSP,
                                      bool aEvalAllowed,
                                      bool aReportCSPViolations)
 : EventTarget(aParent ? aCx : NULL), mMutex("WorkerPrivateParent Mutex"),
   mCondVar(mMutex, "WorkerPrivateParent CondVar"),
   mMemoryReportCondVar(mMutex, "WorkerPrivateParent Memory Report CondVar"),
   mJSObject(aObject), mParent(aParent), mParentJSContext(aParentJSContext),
   mScriptURL(aScriptURL), mDomain(aDomain), mBusyCount(0),
-  mParentStatus(Pending), mJSContextOptions(0),
-  mJSRuntimeHeapSize(0), mJSWorkerAllocationThreshold(3),
-  mGCZeal(0), mJSObjectRooted(false), mParentSuspended(false),
+  mParentStatus(Pending), mJSObjectRooted(false), mParentSuspended(false),
   mIsChromeWorker(aIsChromeWorker), mPrincipalIsSystem(false),
   mMainThreadObjectsForgotten(false), mEvalAllowed(aEvalAllowed),
   mReportCSPViolations(aReportCSPViolations)
 {
   MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerPrivateParent);
 
   if (aWindow) {
     NS_ASSERTION(aWindow->IsInnerWindow(), "Should have inner window here!");
@@ -1831,42 +1876,27 @@ WorkerPrivateParent<Derived>::WorkerPriv
   mBaseURI.swap(aBaseURI);
   mPrincipal.swap(aPrincipal);
   mChannel.swap(aChannel);
   mCSP.swap(aCSP);
 
   if (aParent) {
     aParent->AssertIsOnWorkerThread();
 
-    NS_ASSERTION(JS_GetOptions(aCx) == aParent->GetJSContextOptions(),
+    aParent->CopyJSSettings(mJSSettings);
+
+    NS_ASSERTION(JS_GetOptions(aCx) == (aParent->IsChromeWorker() ?
+                                        mJSSettings.chrome.options :
+                                        mJSSettings.content.options),
                  "Options mismatch!");
-    mJSContextOptions = aParent->GetJSContextOptions();
-
-    NS_ASSERTION(JS_GetGCParameter(JS_GetRuntime(aCx), JSGC_MAX_BYTES) ==
-                 aParent->GetJSRuntimeHeapSize(),
-                 "Runtime heap size mismatch!");
-    mJSRuntimeHeapSize = aParent->GetJSRuntimeHeapSize();
-
-    mJSWorkerAllocationThreshold = aParent->GetJSWorkerAllocationThreshold();
-
-#ifdef JS_GC_ZEAL
-    mGCZeal = aParent->GetGCZeal();
-#endif
   }
   else {
     AssertIsOnMainThread();
 
-    mJSContextOptions = RuntimeService::GetDefaultJSContextOptions();
-    mJSRuntimeHeapSize =
-      RuntimeService::GetDefaultJSWorkerMemoryParameter(JSGC_MAX_BYTES);
-    mJSWorkerAllocationThreshold =
-      RuntimeService::GetDefaultJSWorkerMemoryParameter(JSGC_ALLOCATION_THRESHOLD);
-#ifdef JS_GC_ZEAL
-    mGCZeal = RuntimeService::GetDefaultGCZeal();
-#endif
+    RuntimeService::GetDefaultJSSettings(mJSSettings);
   }
 }
 
 template <class Derived>
 WorkerPrivateParent<Derived>::~WorkerPrivateParent()
 {
   MOZ_COUNT_DTOR(mozilla::dom::workers::WorkerPrivateParent);
 }
@@ -1954,55 +1984,67 @@ WorkerPrivateParent<Derived>::Suspend(JS
   }
 
   nsRefPtr<SuspendRunnable> runnable =
     new SuspendRunnable(ParentAsWorkerPrivate());
   return runnable->Dispatch(aCx);
 }
 
 template <class Derived>
-bool
+void
 WorkerPrivateParent<Derived>::Resume(JSContext* aCx)
 {
   AssertIsOnParentThread();
   NS_ASSERTION(mParentSuspended, "Not yet suspended!");
 
   mParentSuspended = false;
 
   {
     MutexAutoLock lock(mMutex);
 
     if (mParentStatus >= Terminating) {
-      return true;
+      return;
     }
   }
 
-  // Dispatch queued runnables before waking up the worker, otherwise the worker
+  // Execute queued runnables before waking up the worker, otherwise the worker
   // could post new messages before we run those that have been queued.
   if (!mQueuedRunnables.IsEmpty()) {
     AssertIsOnMainThread();
 
     nsTArray<nsRefPtr<WorkerRunnable> > runnables;
     mQueuedRunnables.SwapElements(runnables);
 
     for (uint32_t index = 0; index < runnables.Length(); index++) {
       nsRefPtr<WorkerRunnable>& runnable = runnables[index];
-      if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
-        NS_WARNING("Failed to dispatch queued runnable!");
-      }
+      runnable->Run();
     }
   }
 
   nsRefPtr<ResumeRunnable> runnable =
     new ResumeRunnable(ParentAsWorkerPrivate());
-  if (!runnable->Dispatch(aCx)) {
-    return false;
-  }
-
-  return true;
+  runnable->Dispatch(aCx);
+}
+
+template <class Derived>
+bool
+WorkerPrivateParent<Derived>::SynchronizeAndResume(nsIScriptContext* aCx)
+{
+  AssertIsOnParentThread();
+  NS_ASSERTION(mParentSuspended, "Not yet suspended!");
+
+  // NB: There may be pending unqueued messages.  If we resume here we will
+  // execute those messages out of order.  Instead we post an event to the
+  // end of the event queue, allowing all of the outstanding messages to be
+  // queued up in order on the worker.  Then and only then we execute all of
+  // the messages.
+
+  nsRefPtr<SynchronizeAndResumeRunnable> runnable =
+    new SynchronizeAndResumeRunnable(ParentAsWorkerPrivate(), aCx);
+  return NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable));
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::_trace(JSTracer* aTrc)
 {
   // This should only happen on the parent thread but we can't assert that
   // because it can also happen on the cycle collector thread when this is a
@@ -2205,78 +2247,107 @@ WorkerPrivateParent<Derived>::GetInnerWi
   AssertIsOnMainThread();
   NS_ASSERTION(!mWindow || mWindow->IsInnerWindow(), "Outer window?");
   return mWindow ? mWindow->WindowID() : 0;
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::UpdateJSContextOptions(JSContext* aCx,
-                                                     uint32_t aOptions)
+                                                     uint32_t aContentOptions,
+                                                     uint32_t aChromeOptions)
 {
   AssertIsOnParentThread();
 
-  mJSContextOptions = aOptions;
+  {
+    MutexAutoLock lock(mMutex);
+    mJSSettings.content.options = aContentOptions;
+    mJSSettings.chrome.options = aChromeOptions;
+  }
 
   nsRefPtr<UpdateJSContextOptionsRunnable> runnable =
-    new UpdateJSContextOptionsRunnable(ParentAsWorkerPrivate(), aOptions);
+    new UpdateJSContextOptionsRunnable(ParentAsWorkerPrivate(), aContentOptions,
+                                       aChromeOptions);
   if (!runnable->Dispatch(aCx)) {
     NS_WARNING("Failed to update worker context options!");
     JS_ClearPendingException(aCx);
   }
 }
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::UpdateJSWorkerMemoryParameter(JSContext* aCx,
                                                             JSGCParamKey aKey,
                                                             uint32_t aValue)
 {
   AssertIsOnParentThread();
-  switch(aKey) {
-    case JSGC_ALLOCATION_THRESHOLD:
-      mJSWorkerAllocationThreshold = aValue;
-      break;
-    case JSGC_MAX_BYTES:
-      mJSRuntimeHeapSize = aValue;
-      break;
-    default:
-      break;
+
+  bool found = false;
+
+  {
+    MutexAutoLock lock(mMutex);
+    found = mJSSettings.ApplyGCSetting(aKey, aValue);
   }
 
-  nsRefPtr<UpdateJSWorkerMemoryParameterRunnable> runnable =
-    new UpdateJSWorkerMemoryParameterRunnable(ParentAsWorkerPrivate(),
-                                              aKey,
-                                              aValue);
-  if (!runnable->Dispatch(aCx)) {
-    NS_WARNING("Failed to update memory parameter!");
-    JS_ClearPendingException(aCx);
+  if (found) {
+    nsRefPtr<UpdateJSWorkerMemoryParameterRunnable> runnable =
+      new UpdateJSWorkerMemoryParameterRunnable(ParentAsWorkerPrivate(), aKey,
+                                                aValue);
+    if (!runnable->Dispatch(aCx)) {
+      NS_WARNING("Failed to update memory parameter!");
+      JS_ClearPendingException(aCx);
+    }
   }
 }
 
 #ifdef JS_GC_ZEAL
 template <class Derived>
 void
-WorkerPrivateParent<Derived>::UpdateGCZeal(JSContext* aCx, uint8_t aGCZeal)
+WorkerPrivateParent<Derived>::UpdateGCZeal(JSContext* aCx, uint8_t aGCZeal,
+                                           uint32_t aFrequency)
 {
   AssertIsOnParentThread();
 
-  mGCZeal = aGCZeal;
+  {
+    MutexAutoLock lock(mMutex);
+    mJSSettings.gcZeal = aGCZeal;
+    mJSSettings.gcZealFrequency = aFrequency;
+  }
 
   nsRefPtr<UpdateGCZealRunnable> runnable =
-    new UpdateGCZealRunnable(ParentAsWorkerPrivate(), aGCZeal);
+    new UpdateGCZealRunnable(ParentAsWorkerPrivate(), aGCZeal, aFrequency);
   if (!runnable->Dispatch(aCx)) {
     NS_WARNING("Failed to update worker gczeal!");
     JS_ClearPendingException(aCx);
   }
 }
 #endif
 
 template <class Derived>
 void
+WorkerPrivateParent<Derived>::UpdateJITHardening(JSContext* aCx,
+                                                 bool aJITHardening)
+{
+  AssertIsOnParentThread();
+
+  {
+    MutexAutoLock lock(mMutex);
+    mJSSettings.jitHardening = aJITHardening;
+  }
+
+  nsRefPtr<UpdateJITHardeningRunnable> runnable =
+    new UpdateJITHardeningRunnable(ParentAsWorkerPrivate(), aJITHardening);
+  if (!runnable->Dispatch(aCx)) {
+    NS_WARNING("Failed to update worker jit hardening!");
+    JS_ClearPendingException(aCx);
+  }
+}
+
+template <class Derived>
+void
 WorkerPrivateParent<Derived>::GarbageCollect(JSContext* aCx, bool aShrinking)
 {
   nsRefPtr<GarbageCollectRunnable> runnable =
     new GarbageCollectRunnable(ParentAsWorkerPrivate(), aShrinking, true);
   if (!runnable->Dispatch(aCx)) {
     NS_WARNING("Failed to update worker heap size!");
     JS_ClearPendingException(aCx);
   }
@@ -2747,63 +2818,60 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
                                              nsITimer::TYPE_REPEATING_SLACK))) {
             normalGCTimerRunning = true;
           }
           else {
             JS_ReportError(aCx, "Failed to start normal GC timer!");
           }
         }
 
-#ifdef EXTRA_GC
-        // Find GC bugs...
-        JS_GC(aCx);
-#endif
-
         // Keep track of whether or not this is the idle GC event.
         eventIsNotIdleGCEvent = event != idleGCEvent;
 
         static_cast<nsIRunnable*>(event)->Run();
         NS_RELEASE(event);
       }
 
       currentStatus = mStatus;
       scheduleIdleGC = mControlQueue.IsEmpty() &&
                        mQueue.IsEmpty() &&
-                       eventIsNotIdleGCEvent;
+                       eventIsNotIdleGCEvent &&
+                       JS_GetGlobalForScopeChain(aCx);
     }
 
     // Take care of the GC timer. If we're starting the close sequence then we
     // kill the timer once and for all. Otherwise we schedule the idle timeout
     // if there are no more events.
     if (currentStatus > Terminating || scheduleIdleGC) {
       if (NS_SUCCEEDED(gcTimer->Cancel())) {
         normalGCTimerRunning = false;
       }
       else {
         NS_WARNING("Failed to cancel GC timer!");
       }
     }
 
     if (scheduleIdleGC) {
+      NS_ASSERTION(JS_GetGlobalForScopeChain(aCx), "Should have global here!");
+
+      // Now *might* be a good time to GC. Let the JS engine make the decision.
+      JSAutoCompartment ac(aCx, JS_GetGlobalForScopeChain(aCx));
+      JS_MaybeGC(aCx);
+
       if (NS_SUCCEEDED(gcTimer->SetTarget(idleGCEventTarget)) &&
           NS_SUCCEEDED(gcTimer->InitWithFuncCallback(
                                                     DummyCallback, nullptr,
                                                     IDLE_GC_TIMER_DELAY_MS,
                                                     nsITimer::TYPE_ONE_SHOT))) {
       }
       else {
         JS_ReportError(aCx, "Failed to start idle GC timer!");
       }
     }
 
-#ifdef EXTRA_GC
-    // Find GC bugs...
-    JS_GC(aCx);
-#endif
-
     if (currentStatus != Running && !HasActiveFeatures()) {
       // If the close handler has finished and all features are done then we can
       // kill this thread.
       if (mCloseHandlerFinished && currentStatus != Killing) {
         if (!NotifyInternal(aCx, Killing)) {
           JS_ReportPendingException(aCx);
         }
 #ifdef DEBUG
@@ -3457,29 +3525,19 @@ WorkerPrivate::RunSyncLoop(JSContext* aC
     {
       MutexAutoLock lock(mMutex);
 
       while (!mControlQueue.Pop(event) && !syncQueue->mQueue.Pop(event)) {
         WaitForWorkerEvents();
       }
     }
 
-#ifdef EXTRA_GC
-    // Find GC bugs...
-    JS_GC(mJSContext);
-#endif
-
     static_cast<nsIRunnable*>(event)->Run();
     NS_RELEASE(event);
 
-#ifdef EXTRA_GC
-    // Find GC bugs...
-    JS_GC(mJSContext);
-#endif
-
     if (syncQueue->mComplete) {
       NS_ASSERTION(mSyncQueues.Length() - 1 == aSyncLoopKey,
                    "Mismatched calls!");
       NS_ASSERTION(syncQueue->mQueue.IsEmpty(), "Unprocessed sync events!");
 
       bool result = syncQueue->mResult;
       DestroySyncLoop(aSyncLoopKey);
 
@@ -3641,17 +3699,20 @@ WorkerPrivate::NotifyInternal(JSContext*
   }
 
   if (aStatus == Canceling) {
     // We need to enforce a timeout on the close handler.
     NS_ASSERTION(previousStatus == Running || previousStatus == Closing ||
                  previousStatus == Terminating,
                  "Bad previous status!");
 
-    uint32_t killSeconds = RuntimeService::GetCloseHandlerTimeoutSeconds();
+    uint32_t killSeconds = IsChromeWorker() ?
+      RuntimeService::GetChromeCloseHandlerTimeoutSeconds() :
+      RuntimeService::GetContentCloseHandlerTimeoutSeconds();
+
     if (killSeconds) {
       mKillTime = TimeStamp::Now() + TimeDuration::FromSeconds(killSeconds);
 
       if (!mCloseHandlerFinished && !ScheduleKillCloseEventRunnable(aCx)) {
         return false;
       }
     }
 
@@ -4056,68 +4117,99 @@ WorkerPrivate::RescheduleTimeoutTimer(JS
     JS_ReportError(aCx, "Failed to start timer!");
     return false;
   }
 
   return true;
 }
 
 void
-WorkerPrivate::UpdateJSContextOptionsInternal(JSContext* aCx, uint32_t aOptions)
+WorkerPrivate::UpdateJSContextOptionsInternal(JSContext* aCx,
+                                              uint32_t aContentOptions,
+                                              uint32_t aChromeOptions)
 {
   AssertIsOnWorkerThread();
 
-  JS_SetOptions(aCx, aOptions);
+  JS_SetOptions(aCx, IsChromeWorker() ? aChromeOptions : aContentOptions);
 
   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
-    mChildWorkers[index]->UpdateJSContextOptions(aCx, aOptions);
+    mChildWorkers[index]->UpdateJSContextOptions(aCx, aContentOptions,
+                                                 aChromeOptions);
   }
 }
 
 void
 WorkerPrivate::UpdateJSWorkerMemoryParameterInternal(JSContext* aCx,
                                                      JSGCParamKey aKey,
                                                      uint32_t aValue)
 {
   AssertIsOnWorkerThread();
-  JS_SetGCParameter(JS_GetRuntime(aCx), aKey, aValue);
+
+  // XXX aValue might be 0 here (telling us to unset a previous value for child
+  // workers). Calling JS_SetGCParameter with a value of 0 isn't actually
+  // supported though. We really need some way to revert to a default value
+  // here.
+  if (aValue) {
+    JS_SetGCParameter(JS_GetRuntime(aCx), aKey, aValue);
+  }
 
   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
     mChildWorkers[index]->UpdateJSWorkerMemoryParameter(aCx, aKey, aValue);
   }
 }
 
 #ifdef JS_GC_ZEAL
 void
-WorkerPrivate::UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal)
+WorkerPrivate::UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal,
+                                    uint32_t aFrequency)
 {
   AssertIsOnWorkerThread();
 
-  uint32_t frequency = aGCZeal <= 2 ? JS_DEFAULT_ZEAL_FREQ : 1;
-  JS_SetGCZeal(aCx, aGCZeal, frequency);
+  JS_SetGCZeal(aCx, aGCZeal, aFrequency);
 
   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
-    mChildWorkers[index]->UpdateGCZeal(aCx, aGCZeal);
+    mChildWorkers[index]->UpdateGCZeal(aCx, aGCZeal, aFrequency);
   }
 }
 #endif
 
 void
+WorkerPrivate::UpdateJITHardeningInternal(JSContext* aCx, bool aJITHardening)
+{
+  AssertIsOnWorkerThread();
+
+  JS_SetJitHardening(JS_GetRuntime(aCx), aJITHardening);
+
+  for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
+    mChildWorkers[index]->UpdateJITHardening(aCx, aJITHardening);
+  }
+}
+
+void
 WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking,
                                       bool aCollectChildren)
 {
   AssertIsOnWorkerThread();
 
-  JSRuntime *rt = JS_GetRuntime(aCx);
-  JS::PrepareForFullGC(rt);
-  if (aShrinking) {
-    JS::ShrinkingGC(rt, JS::gcreason::DOM_WORKER);
+  if (aCollectChildren) {
+    JSRuntime* rt = JS_GetRuntime(aCx);
+    JS::PrepareForFullGC(rt);
+    if (aShrinking) {
+      JS::ShrinkingGC(rt, JS::gcreason::DOM_WORKER);
+    }
+    else {
+      JS::GCForReason(rt, JS::gcreason::DOM_WORKER);
+    }
   }
   else {
-    JS::GCForReason(rt, JS::gcreason::DOM_WORKER);
+    // If aCollectChildren is false then it means this collection request was
+    // not generated by the main thread. At the moment only the periodic GC
+    // timer can end up here, so rather than force a collection let the JS
+    // engine decide if we need one.
+    JS_MaybeGC(aCx);
   }
 
   if (aCollectChildren) {
     for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
       mChildWorkers[index]->GarbageCollect(aCx, aShrinking);
     }
   }
 }
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -37,17 +37,20 @@ class nsIChannel;
 class nsIDocument;
 class nsIMemoryMultiReporter;
 class nsIPrincipal;
 class nsIScriptContext;
 class nsIURI;
 class nsPIDOMWindow;
 class nsITimer;
 class nsIXPCScriptNotify;
-namespace JS { struct RuntimeStats; }
+
+namespace JS {
+class RuntimeStats;
+}
 
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerPrivate;
 
 class WorkerRunnable : public nsIRunnable
 {
 public:
@@ -104,17 +107,17 @@ protected:
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
 
   virtual void
   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
 
   void NotifyScriptExecutedIfNeeded() const;
 
-private:
+public:
   NS_DECL_NSIRUNNABLE
 };
 
 class WorkerSyncRunnable : public WorkerRunnable
 {
 protected:
   uint32_t mSyncQueueKey;
   bool mBypassSyncQueue;
@@ -269,22 +272,21 @@ private:
   nsCOMPtr<nsIURI> mScriptURI;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIChannel> mChannel;
   nsCOMPtr<nsIContentSecurityPolicy> mCSP;
 
   // Only used for top level workers.
   nsTArray<nsRefPtr<WorkerRunnable> > mQueuedRunnables;
 
+  // Protected by mMutex.
+  JSSettings mJSSettings;
+
   uint64_t mBusyCount;
   Status mParentStatus;
-  uint32_t mJSContextOptions;
-  uint32_t mJSRuntimeHeapSize;
-  uint32_t mJSWorkerAllocationThreshold;
-  uint8_t mGCZeal;
   bool mJSObjectRooted;
   bool mParentSuspended;
   bool mIsChromeWorker;
   bool mPrincipalIsSystem;
   bool mMainThreadObjectsForgotten;
   bool mEvalAllowed;
   bool mReportCSPViolations;
 
@@ -343,18 +345,21 @@ public:
   Kill(JSContext* aCx)
   {
     return Notify(aCx, Killing);
   }
 
   bool
   Suspend(JSContext* aCx);
 
+  void
+  Resume(JSContext* aCx);
+
   bool
-  Resume(JSContext* aCx);
+  SynchronizeAndResume(nsIScriptContext* aCx);
 
   virtual void
   _trace(JSTracer* aTrc) MOZ_OVERRIDE;
 
   virtual void
   _finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
 
   void
@@ -386,27 +391,32 @@ public:
   bool
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
               JS::Handle<JS::Value> aTransferable);
 
   uint64_t
   GetInnerWindowId();
 
   void
-  UpdateJSContextOptions(JSContext* aCx, uint32_t aOptions);
+  UpdateJSContextOptions(JSContext* aCx, uint32_t aChromeOptions,
+                         uint32_t aContentOptions);
 
   void
-  UpdateJSWorkerMemoryParameter(JSContext* aCx, JSGCParamKey key, uint32_t value);
+  UpdateJSWorkerMemoryParameter(JSContext* aCx, JSGCParamKey key,
+                                uint32_t value);
 
 #ifdef JS_GC_ZEAL
   void
-  UpdateGCZeal(JSContext* aCx, uint8_t aGCZeal);
+  UpdateGCZeal(JSContext* aCx, uint8_t aGCZeal, uint32_t aFrequency);
 #endif
 
   void
+  UpdateJITHardening(JSContext* aCx, bool aJITHardening);
+
+  void
   GarbageCollect(JSContext* aCx, bool aShrinking);
 
   void
   QueueRunnable(WorkerRunnable* aRunnable)
   {
     AssertIsOnMainThread();
     mQueuedRunnables.AppendElement(aRunnable);
   }
@@ -572,42 +582,23 @@ public:
   }
 
   LocationInfo&
   GetLocationInfo()
   {
     return mLocationInfo;
   }
 
-  uint32_t
-  GetJSContextOptions() const
+  void
+  CopyJSSettings(JSSettings& aSettings)
   {
-    return mJSContextOptions;
-  }
-
-  uint32_t
-  GetJSRuntimeHeapSize() const
-  {
-    return mJSRuntimeHeapSize;
+    mozilla::MutexAutoLock lock(mMutex);
+    aSettings = mJSSettings;
   }
 
-  uint32_t
-  GetJSWorkerAllocationThreshold() const
-  {
-    return mJSWorkerAllocationThreshold;
-  }
-
-#ifdef JS_GC_ZEAL
-  uint8_t
-  GetGCZeal() const
-  {
-    return mGCZeal;
-  }
-#endif
-
   bool
   IsChromeWorker() const
   {
     return mIsChromeWorker;
   }
 
 #ifdef DEBUG
   void
@@ -810,17 +801,18 @@ public:
   void
   CloseHandlerFinished()
   {
     AssertIsOnWorkerThread();
     mCloseHandlerFinished = true;
   }
 
   void
-  UpdateJSContextOptionsInternal(JSContext* aCx, uint32_t aOptions);
+  UpdateJSContextOptionsInternal(JSContext* aCx, uint32_t aContentOptions,
+                                 uint32_t aChromeOptions);
 
   void
   UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, uint32_t aValue);
 
   void
   ScheduleDeletion(bool aWasPending);
 
   bool
@@ -835,20 +827,23 @@ public:
   void
   SetXHRParamsAllowed(bool aAllowed)
   {
     mXHRParamsAllowed = aAllowed;
   }
 
 #ifdef JS_GC_ZEAL
   void
-  UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal);
+  UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal, uint32_t aFrequency);
 #endif
 
   void
+  UpdateJITHardeningInternal(JSContext* aCx, bool aJITHardening);
+
+  void
   GarbageCollectInternal(JSContext* aCx, bool aShrinking,
                          bool aCollectChildren);
 
   JSContext*
   GetJSContext() const
   {
     AssertIsOnWorkerThread();
     return mJSContext;
--- a/dom/workers/Workers.h
+++ b/dom/workers/Workers.h
@@ -19,16 +19,17 @@
   namespace mozilla { namespace dom { namespace workers {
 #define END_WORKERS_NAMESPACE \
   } /* namespace workers */ } /* namespace dom */ } /* namespace mozilla */
 #define USING_WORKERS_NAMESPACE \
   using namespace mozilla::dom::workers;
 
 #define WORKERS_SHUTDOWN_TOPIC "web-workers-shutdown"
 
+class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerPrivate;
 
 struct PrivatizableBase
 { };
@@ -37,29 +38,149 @@ struct PrivatizableBase
 void
 AssertIsOnMainThread();
 #else
 inline void
 AssertIsOnMainThread()
 { }
 #endif
 
+struct JSSettings
+{
+  enum {
+    // All the GC parameters that we support.
+    JSSettings_JSGC_MAX_BYTES = 0,
+    JSSettings_JSGC_MAX_MALLOC_BYTES,
+    JSSettings_JSGC_HIGH_FREQUENCY_TIME_LIMIT,
+    JSSettings_JSGC_LOW_FREQUENCY_HEAP_GROWTH,
+    JSSettings_JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN,
+    JSSettings_JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX,
+    JSSettings_JSGC_HIGH_FREQUENCY_LOW_LIMIT,
+    JSSettings_JSGC_HIGH_FREQUENCY_HIGH_LIMIT,
+    JSSettings_JSGC_ANALYSIS_PURGE_TRIGGER,
+    JSSettings_JSGC_ALLOCATION_THRESHOLD,
+    JSSettings_JSGC_SLICE_TIME_BUDGET,
+    JSSettings_JSGC_DYNAMIC_HEAP_GROWTH,
+    JSSettings_JSGC_DYNAMIC_MARK_SLICE,
+    // JSGC_MODE not supported
+
+    // This must be last so that we get an accurate count.
+    kGCSettingsArraySize
+  };
+
+  struct JSGCSetting
+  {
+    JSGCParamKey key;
+    uint32_t value;
+
+    JSGCSetting()
+    : key(static_cast<JSGCParamKey>(-1)), value(0)
+    { }
+
+    bool
+    IsSet() const
+    {
+      return key != static_cast<JSGCParamKey>(-1);
+    }
+
+    void
+    Unset()
+    {
+      key = static_cast<JSGCParamKey>(-1);
+      value = 0;
+    }
+  };
+
+  // There are several settings that we know we need so it makes sense to
+  // preallocate here.
+  typedef JSGCSetting JSGCSettingsArray[kGCSettingsArraySize];
+
+  // Settings that change based on chrome/content context.
+  struct JSContentChromeSettings
+  {
+    uint32_t options;
+    int32_t maxScriptRuntime;
+
+    JSContentChromeSettings()
+    : options(0), maxScriptRuntime(0)
+    { }
+  };
+
+  JSContentChromeSettings chrome;
+  JSContentChromeSettings content;
+  JSGCSettingsArray gcSettings;
+  bool jitHardening;
+#ifdef JS_GC_ZEAL
+  uint8_t gcZeal;
+  uint32_t gcZealFrequency;
+#endif
+
+  JSSettings()
+  : jitHardening(false)
+#ifdef JS_GC_ZEAL
+  , gcZeal(0), gcZealFrequency(0)
+#endif
+  {
+    for (uint32_t index = 0; index < ArrayLength(gcSettings); index++) {
+      new (gcSettings + index) JSGCSetting();
+    }
+  }
+
+  bool
+  ApplyGCSetting(JSGCParamKey aKey, uint32_t aValue)
+  {
+    JSSettings::JSGCSetting* firstEmptySetting = nullptr;
+    JSSettings::JSGCSetting* foundSetting = nullptr;
+
+    for (uint32_t index = 0; index < ArrayLength(gcSettings); index++) {
+      JSSettings::JSGCSetting& setting = gcSettings[index];
+      if (setting.key == aKey) {
+        foundSetting = &setting;
+        break;
+      }
+      if (!firstEmptySetting && !setting.IsSet()) {
+        firstEmptySetting = &setting;
+      }
+    }
+
+    if (aValue) {
+      if (!foundSetting) {
+        foundSetting = firstEmptySetting;
+        if (!foundSetting) {
+          NS_ERROR("Not enough space for this value!");
+          return false;
+        }
+      }
+      foundSetting->key = aKey;
+      foundSetting->value = aValue;
+      return true;
+    }
+
+    if (foundSetting) {
+      foundSetting->Unset();
+      return true;
+    }
+
+    return false;
+  }
+};
+
 // All of these are implemented in RuntimeService.cpp
 JSBool
-ResolveWorkerClasses(JSContext* aCx, JSHandleObject aObj, JSHandleId aId, unsigned aFlags,
-                     JS::MutableHandle<JSObject*> aObjp);
+ResolveWorkerClasses(JSContext* aCx, JSHandleObject aObj, JSHandleId aId,
+                     unsigned aFlags, JS::MutableHandle<JSObject*> aObjp);
 
 void
 CancelWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
 
 void
 SuspendWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
 
 void
-ResumeWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
+ResumeWorkersForWindow(nsIScriptContext* aCx, nsPIDOMWindow* aWindow);
 
 class WorkerTask {
 public:
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerTask)
 
     virtual ~WorkerTask() { }
 
     virtual bool RunTask(JSContext* aCx) = 0;
--- a/extensions/cookie/nsPermission.cpp
+++ b/extensions/cookie/nsPermission.cpp
@@ -1,18 +1,20 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "nsPermission.h"
+#include "nsIClassInfoImpl.h"
 
 // nsPermission Implementation
 
-NS_IMPL_ISUPPORTS1(nsPermission, nsIPermission)
+NS_IMPL_CLASSINFO(nsPermission, nullptr, 0, {0})
+NS_IMPL_ISUPPORTS1_CI(nsPermission, nsIPermission)
 
 nsPermission::nsPermission(const nsACString &aHost,
                            uint32_t aAppId,
                            bool aIsInBrowserElement,
                            const nsACString &aType,
                            uint32_t         aCapability,
                            uint32_t         aExpireType,
                            int64_t          aExpireTime)
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -613,18 +613,20 @@ nsPermissionManager::AddFromPrincipal(ns
   ENSURE_NOT_CHILD_PROCESS;
   NS_ENSURE_ARG_POINTER(aPrincipal);
   NS_ENSURE_ARG_POINTER(aType);
   NS_ENSURE_TRUE(aExpireType == nsIPermissionManager::EXPIRE_NEVER ||
                  aExpireType == nsIPermissionManager::EXPIRE_TIME ||
                  aExpireType == nsIPermissionManager::EXPIRE_SESSION,
                  NS_ERROR_INVALID_ARG);
 
-  // Skip addition if the permission is already expired.
-  if (aExpireType == nsIPermissionManager::EXPIRE_TIME &&
+  // Skip addition if the permission is already expired. Note that EXPIRE_SESSION only
+  // honors expireTime if it is nonzero.
+  if ((aExpireType == nsIPermissionManager::EXPIRE_TIME ||
+       (aExpireType == nsIPermissionManager::EXPIRE_SESSION && aExpireTime != 0)) &&
       aExpireTime <= (PR_Now() / 1000)) {
     return NS_OK;
   }
 
   // We don't add the system principal because it actually has no URI and we
   // always allow action for them.
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     return NS_OK;
@@ -697,17 +699,17 @@ nsPermissionManager::AddInternal(nsIPrin
 
     // remove the permission if the permission is UNKNOWN, update the
     // permission if its value or expire type have changed OR if the time has
     // changed and the expire type is time, otherwise, don't modify.  There's
     // no need to modify a permission that doesn't expire with time when the
     // only thing changed is the expire time.
     if (aPermission == oldPermissionEntry.mPermission &&
         aExpireType == oldPermissionEntry.mExpireType &&
-        (aExpireType != nsIPermissionManager::EXPIRE_TIME ||
+        (aExpireType == nsIPermissionManager::EXPIRE_NEVER ||
          aExpireTime == oldPermissionEntry.mExpireTime))
       op = eOperationNone;
     else if (aPermission == nsIPermissionManager::UNKNOWN_ACTION)
       op = eOperationRemoving;
     else
       op = eOperationChanging;
   }
 
@@ -796,24 +798,26 @@ nsPermissionManager::AddInternal(nsIPrin
 
       // If the new expireType is EXPIRE_SESSION, then we have to keep a
       // copy of the previous permission/expireType values. This cached value will be
       // used when restoring the permissions of an app.
       if (entry->GetPermissions()[index].mExpireType != nsIPermissionManager::EXPIRE_SESSION &&
           aExpireType == nsIPermissionManager::EXPIRE_SESSION) {
         entry->GetPermissions()[index].mNonSessionPermission = entry->GetPermissions()[index].mPermission;
         entry->GetPermissions()[index].mNonSessionExpireType = entry->GetPermissions()[index].mExpireType;
+        entry->GetPermissions()[index].mNonSessionExpireTime = entry->GetPermissions()[index].mExpireTime;
       } else if (aExpireType != nsIPermissionManager::EXPIRE_SESSION) {
         entry->GetPermissions()[index].mNonSessionPermission = aPermission;
         entry->GetPermissions()[index].mNonSessionExpireType = aExpireType;
-        entry->GetPermissions()[index].mExpireTime = aExpireTime;
+        entry->GetPermissions()[index].mNonSessionExpireTime = aExpireTime;
       }
 
       entry->GetPermissions()[index].mPermission = aPermission;
       entry->GetPermissions()[index].mExpireType = aExpireType;
+      entry->GetPermissions()[index].mExpireTime = aExpireTime;
 
       if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION)
         // We care only about the id, the permission and expireType/expireTime here.
         // We pass dummy values for all other parameters.
         UpdateDB(op, mStmtUpdate, id, EmptyCString(), EmptyCString(),
                  aPermission, aExpireType, aExpireTime, 0, false);
 
       if (aNotifyOperation == eNotify) {
@@ -1013,16 +1017,73 @@ nsPermissionManager::TestPermissionFromP
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     *aPermission = nsIPermissionManager::ALLOW_ACTION;
     return NS_OK;
   }
 
   return CommonTestPermission(aPrincipal, aType, aPermission, false, true);
 }
 
+NS_IMETHODIMP
+nsPermissionManager::GetPermissionObject(nsIPrincipal* aPrincipal,
+                                         const char* aType,
+                                         bool aExactHostMatch,
+                                         nsIPermission** aResult)
+{
+  NS_ENSURE_ARG_POINTER(aPrincipal);
+  NS_ENSURE_ARG_POINTER(aType);
+
+  *aResult = nullptr;
+
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    return NS_OK;
+  }
+
+  nsAutoCString host;
+  nsresult rv = GetHostForPrincipal(aPrincipal, host);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  int32_t typeIndex = GetTypeIndex(aType, false);
+  // If type == -1, the type isn't known,
+  // so just return NS_OK
+  if (typeIndex == -1) return NS_OK;
+
+  uint32_t appId;
+  rv = aPrincipal->GetAppId(&appId);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool isInBrowserElement;
+  rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PermissionHashKey* entry = GetPermissionHashKey(host, appId, isInBrowserElement,
+                                                  typeIndex, aExactHostMatch);
+  if (!entry) {
+    return NS_OK;
+  }
+
+  // We don't call GetPermission(typeIndex) because that returns a fake
+  // UNKNOWN_ACTION entry if there is no match.
+  int32_t idx = entry->GetPermissionIndex(typeIndex);
+  if (-1 == idx) {
+    return NS_OK;
+  }
+
+  PermissionEntry& perm = entry->GetPermissions()[idx];
+  nsCOMPtr<nsIPermission> r = new nsPermission(entry->GetKey()->mHost,
+                                               entry->GetKey()->mAppId,
+                                               entry->GetKey()->mIsInBrowserElement,
+                                               mTypeArray.ElementAt(perm.mType),
+                                               perm.mPermission,
+                                               perm.mExpireType,
+                                               perm.mExpireTime);
+  r.forget(aResult);
+  return NS_OK;
+}
+
 nsresult
 nsPermissionManager::CommonTestPermission(nsIPrincipal* aPrincipal,
                                           const char *aType,
                                           uint32_t   *aPermission,
                                           bool        aExactHostMatch,
                                           bool        aIncludingSession)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
@@ -1081,17 +1142,20 @@ nsPermissionManager::GetPermissionHashKe
 
   nsRefPtr<PermissionKey> key = new PermissionKey(aHost, aAppId, aIsInBrowserElement);
   entry = mPermissionTable.GetEntry(key);
 
   if (entry) {
     PermissionEntry permEntry = entry->GetPermission(aType);
 
     // if the entry is expired, remove and keep looking for others.
-    if (permEntry.mExpireType == nsIPermissionManager::EXPIRE_TIME &&
+    // Note that EXPIRE_SESSION only honors expireTime if it is nonzero.
+    if ((permEntry.mExpireType == nsIPermissionManager::EXPIRE_TIME ||
+         (permEntry.mExpireType == nsIPermissionManager::EXPIRE_SESSION &&
+          permEntry.mExpireTime != 0)) &&
         permEntry.mExpireTime <= (PR_Now() / 1000)) {
       nsCOMPtr<nsIPrincipal> principal;
       if (NS_FAILED(GetPrincipal(aHost, aAppId, aIsInBrowserElement, getter_AddRefs(principal)))) {
         return nullptr;
       }
 
       entry = nullptr;
       RemoveFromPrincipal(principal, mTypeArray[aType].get());
@@ -1313,16 +1377,17 @@ nsPermissionManager::RemoveExpiredPermis
                                                         oldPermissionEntry.mExpireTime,
                                                         NS_LITERAL_STRING("deleted").get());
       --i;
       continue;
     }
 
     permEntry.mPermission = permEntry.mNonSessionPermission;
     permEntry.mExpireType = permEntry.mNonSessionExpireType;
+    permEntry.mExpireTime = permEntry.mNonSessionExpireTime;
 
     gPermissionManager->NotifyObserversWithPermission(entry->GetKey()->mHost,
                                                       entry->GetKey()->mAppId,
                                                       entry->GetKey()->mIsInBrowserElement,
                                                       gPermissionManager->mTypeArray.ElementAt(permEntry.mType),
                                                       permEntry.mPermission,
                                                       permEntry.mExpireType,
                                                       permEntry.mExpireTime,
--- a/extensions/cookie/nsPermissionManager.h
+++ b/extensions/cookie/nsPermissionManager.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 nsPermissionManager_h__
 #define nsPermissionManager_h__
 
 #include "nsIPermissionManager.h"
@@ -40,25 +40,27 @@ public:
                     uint32_t aExpireType, int64_t aExpireTime)
      : mID(aID)
      , mType(aType)
      , mPermission(aPermission)
      , mExpireType(aExpireType)
      , mExpireTime(aExpireTime)
      , mNonSessionPermission(aPermission)
      , mNonSessionExpireType(aExpireType)
+     , mNonSessionExpireTime(aExpireTime)
     {}
 
     int64_t  mID;
     uint32_t mType;
     uint32_t mPermission;
     uint32_t mExpireType;
     int64_t  mExpireTime;
     uint32_t mNonSessionPermission;
     uint32_t mNonSessionExpireType;
+    uint32_t mNonSessionExpireTime;
   };
 
   /**
    * PermissionKey is the key used by PermissionHashKey hash table.
    *
    * NOTE: It could be implementing nsIHashable but there is no reason to worry
    * with XPCOM interfaces while we don't need to.
    */
--- a/extensions/cookie/test/unit/test_permmanager_expiration.js
+++ b/extensions/cookie/test/unit/test_permmanager_expiration.js
@@ -22,35 +22,47 @@ function do_run_test() {
   let pm = Services.permissions;
   let permURI = NetUtil.newURI("http://example.com");
   let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(permURI);
 
   let now = Number(Date.now());
 
   // add a permission with *now* expiration
   pm.addFromPrincipal(principal, "test/expiration-perm-exp", 1, pm.EXPIRE_TIME, now);
+  pm.addFromPrincipal(principal, "test/expiration-session-exp", 1, pm.EXPIRE_SESSION, now);
 
   // add a permission with future expiration (100 milliseconds)
   pm.addFromPrincipal(principal, "test/expiration-perm-exp2", 1, pm.EXPIRE_TIME, now + 100);
+  pm.addFromPrincipal(principal, "test/expiration-session-exp2", 1, pm.EXPIRE_SESSION, now + 100);
 
   // add a permission with future expiration (1000 seconds)
   pm.addFromPrincipal(principal, "test/expiration-perm-exp3", 1, pm.EXPIRE_TIME, now + 1e6);
+  pm.addFromPrincipal(principal, "test/expiration-session-exp3", 1, pm.EXPIRE_SESSION, now + 1e6);
 
   // add a permission without expiration
   pm.addFromPrincipal(principal, "test/expiration-perm-nexp", 1, pm.EXPIRE_NEVER, 0);
 
   // check that the second two haven't expired yet
   do_check_eq(1, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp3"));
+  do_check_eq(1, pm.testPermissionFromPrincipal(principal, "test/expiration-session-exp3"));
   do_check_eq(1, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-nexp"));
 
   // ... and the first one has
   do_timeout(10, continue_test);
   yield;
   do_check_eq(0, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp"));
+  do_check_eq(0, pm.testPermissionFromPrincipal(principal, "test/expiration-session-exp"));
 
   // ... and that the short-term one will
   do_timeout(200, continue_test);
   yield;
-  do_check_eq(0, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp2")); 
+  do_check_eq(0, pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp2"));
+  do_check_eq(0, pm.testPermissionFromPrincipal(principal, "test/expiration-session-exp2"));
+
+  // Check that .getPermission returns a matching result
+  do_check_null(pm.getPermissionObject(principal, "test/expiration-perm-exp", false));
+  do_check_null(pm.getPermissionObject(principal, "test/expiration-session-exp", false));
+  do_check_null(pm.getPermissionObject(principal, "test/expiration-perm-exp2", false));
+  do_check_null(pm.getPermissionObject(principal, "test/expiration-session-exp2", false));
 
   do_finish_generator_test(test_generator);
 }
 
new file mode 100644
--- /dev/null
+++ b/extensions/cookie/test/unit/test_permmanager_getPermissionObject.js
@@ -0,0 +1,94 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function getPrincipalFromURI(uri) {
+  return Cc["@mozilla.org/scriptsecuritymanager;1"]
+           .getService(Ci.nsIScriptSecurityManager)
+           .getNoAppCodebasePrincipal(NetUtil.newURI(uri));
+}
+
+function getSystemPrincipal() {
+  return Cc["@mozilla.org/scriptsecuritymanager;1"]
+           .getService(Ci.nsIScriptSecurityManager)
+           .getSystemPrincipal();
+}
+
+function run_test() {
+  var pm = Cc["@mozilla.org/permissionmanager;1"].
+           getService(Ci.nsIPermissionManager);
+
+  do_check_null(pm.getPermissionObject(getSystemPrincipal(), "test/pobject", false));
+
+  let principal = getPrincipalFromURI("http://example.com");
+  let subPrincipal = getPrincipalFromURI("http://sub.example.com");
+  let subSubPrincipal = getPrincipalFromURI("http://sub.sub.example.com");
+
+  do_check_null(pm.getPermissionObject(principal, "test/pobject", false));
+  do_check_null(pm.getPermissionObject(principal, "test/pobject", true));
+
+  pm.addFromPrincipal(principal, "test/pobject", pm.ALLOW_ACTION);
+  var rootPerm = pm.getPermissionObject(principal, "test/pobject", false);
+  do_check_true(rootPerm != null);
+  do_check_eq(rootPerm.host, "example.com");
+  do_check_eq(rootPerm.type, "test/pobject");
+  do_check_eq(rootPerm.capability, pm.ALLOW_ACTION);
+  do_check_eq(rootPerm.expireType, pm.EXPIRE_NEVER);
+
+  var rootPerm2 = pm.getPermissionObject(principal, "test/pobject", true);
+  do_check_true(rootPerm != null);
+  do_check_eq(rootPerm.host, "example.com");
+
+  var subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", true);
+  do_check_null(subPerm);
+  subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false);
+  do_check_true(subPerm != null);
+  do_check_eq(subPerm.host, "example.com");
+  do_check_eq(subPerm.type, "test/pobject");
+  do_check_eq(subPerm.capability, pm.ALLOW_ACTION);
+
+  subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", true);
+  do_check_null(subPerm);
+  subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", false);
+  do_check_true(subPerm != null);
+  do_check_eq(subPerm.host, "example.com");
+
+  pm.addFromPrincipal(principal, "test/pobject", pm.DENY_ACTION, pm.EXPIRE_SESSION);
+
+  // make sure permission objects are not dynamic
+  do_check_eq(rootPerm.capability, pm.ALLOW_ACTION);
+
+  // but do update on change
+  rootPerm = pm.getPermissionObject(principal, "test/pobject", true);
+  do_check_eq(rootPerm.capability, pm.DENY_ACTION);
+  do_check_eq(rootPerm.expireType, pm.EXPIRE_SESSION);
+
+  subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false);
+  do_check_eq(subPerm.host, "example.com");
+  do_check_eq(subPerm.capability, pm.DENY_ACTION);
+  do_check_eq(subPerm.expireType, pm.EXPIRE_SESSION);
+
+  pm.addFromPrincipal(subPrincipal, "test/pobject", pm.PROMPT_ACTION);
+  rootPerm = pm.getPermissionObject(principal, "test/pobject", true);
+  do_check_eq(rootPerm.host, "example.com");
+  do_check_eq(rootPerm.capability, pm.DENY_ACTION);
+
+  subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", true);
+  do_check_eq(subPerm.host, "sub.example.com");
+  do_check_eq(subPerm.capability, pm.PROMPT_ACTION);
+
+  subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false);
+  do_check_eq(subPerm.host, "sub.example.com");
+  do_check_eq(subPerm.capability, pm.PROMPT_ACTION);
+
+  subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", true);
+  do_check_null(subPerm);
+
+  subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", false);
+  do_check_eq(subPerm.host, "sub.example.com");
+  do_check_eq(subPerm.capability, pm.PROMPT_ACTION);
+
+  pm.removeFromPrincipal(principal, "test/pobject");
+
+  rootPerm = pm.getPermissionObject(principal, "test/pobject", true);
+  do_check_null(rootPerm);
+}
--- a/extensions/cookie/test/unit/xpcshell.ini
+++ b/extensions/cookie/test/unit/xpcshell.ini
@@ -11,16 +11,17 @@ tail =
 [test_cookies_profile_close.js]
 [test_cookies_read.js]
 [test_cookies_sync_failure.js]
 [test_cookies_thirdparty.js]
 [test_cookies_thirdparty_session.js]
 [test_domain_eviction.js]
 [test_eviction.js]
 [test_permmanager_expiration.js]
+[test_permmanager_getPermissionObject.js]
 [test_permmanager_notifications.js]
 [test_permmanager_removeall.js]
 [test_permmanager_load_invalid_entries.js]
 skip-if = debug == true
 [test_permmanager_idn.js]
 [test_permmanager_subdomains.js]
 [test_permmanager_local_files.js]
 [test_permmanager_cleardata.js]
--- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
+++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
@@ -9192,392 +9192,394 @@ 17800a23606
 18151d23956
 < convenor/S
 18206c24011
 < cookie/M
 ---
 > cookie/SM
 18467a24273
 > could've
-19246c25052
+19035a24842
+> cul-de-sac
+19246c25053
 < cysteine
 ---
 > cysteine/M
-20196,20197c26002,26003
+20196,20197c26003,26004
 < dialog/SM
 < dialogue/SM
 ---
 > dialog/SMGD
 > dialogue/SMRGD
-20481a26288
+20481a26289
 > disclose/DSG
-20830c26637
+20830c26638
 < dogie/M
 ---
 > dogie/SM
-20895a26703
+20895a26704
 > donator/MS
-21820a27629
+21820a27630
 > elicitor/MS
-22071a27881
+22071a27882
 > encyclopaedia
-22556a28367
+22556a28368
 > estoppel
-22638c28449
+22638c28450
 < euthanize
 ---
 > euthanize/DSG
-22719a28531
+22719a28532
 > exabyte/MS
-22947a28760
+22947a28761
 > experimentalism
-23207,23208d29019
+23207,23208d29020
 < faecal
 < faeces/M
-23215c29026
+23215c29027
 < faggoting's
 ---
 > faggot/SMG
-23701a29513
+23701a29514
 > filesystem/MS
-24155c29967
+24155c29968
 < fluidized
 ---
 > fluidize/DSG
-24216a30029
+24216a30030
 > foci
-24736d30548
+24736d30549
 < frier/M
-24855,24856c30667,30668
+24855,24856c30668,30669
 < fucker/M!
 < fuckhead/S!
 ---
 > fucker/SM!
 > fuckhead/SM!
-24953d30764
+24953d30765
 < furore/MS
-25125c30936
+25125c30937
 < gaolbird/S
 ---
 > gaolbirds
-25180d30990
+25180d30991
 < gasolene/M
-25190a31001
+25190a31002
 > gastroenterologist/M
-25262c31073
+25262c31074
 < geezer/M
 ---
 > geezer/MS
-25327c31138
+25327c31139
 < genomic
 ---
 > genomic/S
-25462a31274
+25462a31275
 > gigabit/MS
-25464a31277,31279
+25464a31278,31280
 > gigajoule/MS
 > gigapixel/MS
 > gigawatt/MS
-25560d31374
+25560d31375
 < glamourize/DSG
-25674c31488
+25674c31489
 < glycerine's
 ---
 > glycerine/M
-25905c31719
+25905c31720
 < gram/MS
 ---
 > gram/KMS
-25909d31722
+25909d31723
 < gramme/SM
-26063c31876,31877
+26063c31877,31878
 < greybeard
 ---
 > grey/MDRTGSP
 > greybeard/SM
-26066c31880
+26066c31881
 < greyness
 ---
 > greyness/M
-26246,26247d32059
+26246,26247d32060
 < guerilla's
 < guerillas
-26432,26436d32243
+26432,26436d32244
 < haemoglobin's
 < haemophilia/M
 < haemorrhage/DSMG
 < haemorrhoid/S
 < haemorrhoids/M
-27167c32974
+27167c32975
 < hexane
 ---
 > hexane/SM
-27273a33081
+27273a33082
 > hippopotami
-27875d33682
+27875d33683
 < hyaena/SM
-28017c33824
+28017c33825
 < iPod/M
 ---
 > iPod/MS
-28105a33913
+28105a33914
 > idolator/SM
-28513c34321
+28513c34322
 < inbound
 ---
 > inbound/s
-28650a34459
+28650a34460
 > indices
-28812d34620
+28812d34621
 < inflexion/SM
-29216a35025
+29216a35026
 > intern/GDL
-29272a35082,35085
+29272a35083,35086
 > intersex
 > intersexual/MS
 > intersexualism
 > intersexuality
-29724c35537
+29724c35538
 < jewellery's
 ---
 > jewellery/M
-29870a35684
+29870a35685
 > judgement/MS
-30066c35880
+30066c35881
 < kiddie/M
 ---
 > kiddie/SM
-30262,30263c36076
+30262,30263c36077
 < kraut's
 < kraut/S!
 ---
 > kraut/MS!
-30665a36479
+30665a36480
 > lector/MS
-31031c36845
+31031c36846
 < linguini's
 ---
 > linguini/M
-31151,31152c36965
+31151,31152c36966
 < liver's
 < liver/S
 ---
 > liver/MS
-32230c38043
+32230c38044
 < meanie/M
 ---
 > meanie/MS
-32317,32318c38130
+32317,32318c38131
 < megadeath/M
 < megadeaths
 ---
 > megadeath/SM
-32320c38132
+32320c38133
 < megajoules
 ---
 > megajoule/SM
-32329c38141
+32329c38142
 < megapixel/S
 ---
 > megapixel/MS
-32708a38521
+32708a38522
 > might've
-32777d38589
+32777d38590
 < millionnaire/M
-32934a38747
+32934a38748
 > miscommunication/S
-32991a38805
+32991a38806
 > misjudgement/MS
-33784a39599
+33784a39600
 > must've
-33963c39778
+33963c39779
 < native/MS
 ---
 > native/MSY
-34169,34171c39984,39985
+34169,34171c39985,39986
 < neurone/S
 < neurophysiology
 < neuroscience
 ---
 > neurophysiology/M
 > neuroscience/MS
-34275c40089
+34275c40090
 < nightie/M
 ---
 > nightie/SM
-35104a40919
+35104a40920
 > octopi
-35219d41033
+35219d41034
 < oleomargarin/M
-35226a41041
+35226a41042
 > oligo
-35913c41728
+35913c41729
 < oversize/D
 ---
 > oversize
-36056,36059d41870
+36056,36059d41871
 < paederast/S
 < paediatrician's
 < paediatricians
 < paediatrics/M
-36291a42103
+36291a42104
 > paralyses
-36403d42214
+36403d42215
 < parrakeet/MS
-36449d42259
+36449d42260
 < partizan/SM
-37093a42904
+37093a42905
 > petabyte/MS
-37102c42913
+37102c42914
 < petitioner/M
 ---
 > petitioner/MS
-37264a43076
+37264a43077
 > phosphorylate/DSGN
-37316d43127
+37316d43128
 < phrenetic
-37796a43608
+37796a43609
 > plugin/MS
-37987c43799
+37987c43800
 < polypeptide/S
 ---
 > polypeptide/MS
-38291d44102
+38291d44103
 < practise's
-38451a44263
+38451a44264
 > prejudgement/MS
-38891a44704,44705
+38891a44705,44706
 > pronate/DSGN
 > pronator/MS
-38951c44765
+38951c44766
 < proprietorship/M
 ---
 > proprietorship/MS
-39039a44854
+39039a44855
 > provender/M
-39564a45380
+39564a45381
 > quinoa
-40036a45853
+40036a45854
 > recency
-40141a45959
+40141a45960
 > recuse/DGS
-40208a46027
+40208a46028
 > refactor/SMDG
-40244d46062
+40244d46063
 < reflexion/SM
-40829c46647
+40829c46648
 < reverie/M
 ---
 > reverie/MS
-41415a47234
+41415a47235
 > sabre/MS
-41914c47733
+41914c47734
 < schnaps's
 ---
 > schnaps/M
-41949c47768
+41949c47769
 < schrod's
 ---
 > schrod/SM
-41998a47818
+41998a47819
 > scot-free
-42883,42885c48703
+42883,42885c48704
 < shit's
 < shit/S!
 < shite/S!
 ---
 > shit/MS!
-42887,42888c48705,48706
+42887,42888c48706,48707
 < shithead/S!
 < shitload/!
 ---
 > shithead/MS!
 > shitload/MS!
-42891c48709
+42891c48710
 < shitty/RT!
 ---
 > shitty/TR!
-42976a48795
+42976a48796
 > should've
-43008c48827
+43008c48828
 < showtime
 ---
 > showtime/MS
-43724,43726c49543
+43724,43726c49544
 < smoulder's
 < smouldered
 < smoulders
 ---
 > smoulder/GSMD
-44062c49879
+44062c49880
 < sonofabitch
 ---
 > sonofabitch/!
-44346a50164
+44346a50165
 > spelled
-44348a50167
+44348a50168
 > spelt
-44371a50191
+44371a50192
 > spick/S!
-44383c50203
+44383c50204
 < spik/S
 ---
 > spik/S!
-46106a51927
+46106a51928
 > syllabi
-46160c51981
+46160c51982
 < synch/GMD
 ---
 > synch/GMDS
-46167d51987
+46167d51988
 < synchs
-46203,46204c52023,52024
+46203,46204c52024,52025
 < sysadmin/S
 < sysop/S
 ---
 > sysadmin/MS
 > sysop/MS
-46752a52573
+46752a52574
 > terabit/MS
-46753a52575,52576
+46753a52576,52577
 > terahertz/M
 > terapixel/MS
-46817a52641
+46817a52642
 > testcase/MS
-46831a52656
+46831a52657
 > testsuite/MS
-46925a52751
+46925a52752
 > theremin/MS
-47755a53582
+47755a53583
 > transfect/DSMG
-47774a53602,53603
+47774a53603,53604
 > transgenderism
 > transgene/MS
-47951c53780
+47951c53781
 < triage/M
 ---
 > triage/MG
-48869a54699
+48869a54700
 > unlikeable
-49211c55041
+49211c55042
 < vagina/M
 ---
 > vagina/MS
-49368,49369c55198
+49368,49369c55199
 < velour's
 < velours's
 ---
 > velour/MS
-49478a55308
+49478a55309
 > vertices
-50148a55979
+50148a55980
 > weaponize/DSG
-50260,50261d56090
+50260,50261d56091
 < werwolf/M
 < werwolves
-50728c56557
+50728c56558
 < women
 ---
 > women/M
-50794c56623
+50794c56624
 < wop/S!
 ---
 > wop/MS!
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-57445
+57446
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -25101,16 +25101,17 @@ cucumber/SM
 cud/SM
 cuddle/DSMG
 cuddly/TRP
 cudgel/SGMDJ
 cue/DSMG
 cuff/MDGS
 cufflink/SM
 cuisine/SM
+cul-de-sac
 culinary
 cull/MDGS
 cullender/MS
 culminate/DSXGN
 culmination/M
 culotte/SM
 culpability/M
 culpable/I
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -380,28 +380,24 @@ GLScreenBuffer::Attach(SharedSurface* su
     }
 }
 
 bool
 GLScreenBuffer::Swap(const gfxIntSize& size)
 {
     SharedSurface* nextSurf = mStream->SwapProducer(mFactory, size);
     if (!nextSurf) {
-        SurfaceFactory_GL* basicFactory =
-            new SurfaceFactory_Basic(mGL, mFactory->Caps());
-        nextSurf = mStream->SwapProducer(basicFactory, size);
-        if (!nextSurf) {
-            delete basicFactory;
-            return false;
-        }
+        SurfaceFactory_Basic basicFactory(mGL, mFactory->Caps());
+        nextSurf = mStream->SwapProducer(&basicFactory, size);
+        if (!nextSurf)
+          return false;
 
-        // Swap out the apparently defective old factory.
-        delete mFactory;
-        mFactory = basicFactory;
+        NS_WARNING("SwapProd failed for sophisticated Factory type, fell back to Basic.");
     }
+    MOZ_ASSERT(nextSurf);
 
     Attach(nextSurf, size);
 
     return true;
 }
 
 bool
 GLScreenBuffer::PublishFrame(const gfxIntSize& size)
--- a/gfx/gl/SharedSurfaceANGLE.cpp
+++ b/gfx/gl/SharedSurfaceANGLE.cpp
@@ -227,32 +227,35 @@ SharedSurface_ANGLEShareHandle::Create(G
     {
         NS_ERROR("Failed to grab ShareHandle for PBuffer!");
         goto CleanUpIfFailed;
     }
 
     // Ok, we have a valid PBuffer with ShareHandle.
     // Let's attach it to D3D.
     hr = d3d->OpenSharedResource(shareHandle,
-                                         __uuidof(ID3D10Texture2D),
-                                         getter_AddRefs(texture));
-    if (FAILED(hr))
+                                 __uuidof(ID3D10Texture2D),
+                                 getter_AddRefs(texture));
+    if (FAILED(hr)) {
+        NS_ERROR("Failed to open shared resource!");
         goto CleanUpIfFailed;
+    }
 
     hr = d3d->CreateShaderResourceView(texture, nullptr, getter_AddRefs(srv));
-    if (FAILED(hr))
+    if (FAILED(hr)) {
+        NS_ERROR("Failed to create SRV!");
         goto CleanUpIfFailed;
+    }
 
     failed = false;
 
 CleanUpIfFailed:
     if (failed) {
         NS_WARNING("CleanUpIfFailed");
         egl->fDestroySurface(egl->Display(), pbuffer);
-        MOZ_CRASH();
         return nullptr;
     }
 
     return new SharedSurface_ANGLEShareHandle(gl, egl,
                                               size, hasAlpha,
                                               context, pbuffer,
                                               texture, srv);
 }
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -74,17 +74,19 @@ protected:
   IntSize mSize;
 };
 
 TemporaryRef<TextureHost>
 CreateBasicTextureHost(SurfaceDescriptorType aDescriptorType,
                        uint32_t aTextureHostFlags,
                        uint32_t aTextureFlags)
 {
-  MOZ_ASSERT(aDescriptorType == SurfaceDescriptor::TShmem, "We can only support Shmem currently");
+  MOZ_ASSERT(aDescriptorType == SurfaceDescriptor::TShmem ||
+             aDescriptorType == SurfaceDescriptor::TMemoryImage,
+             "We can only support Shmem currently");
   return new TextureSourceBasic();
 }
 
 BasicCompositor::BasicCompositor(nsIWidget *aWidget)
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
 {
   MOZ_COUNT_CTOR(BasicCompositor);
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -40,20 +40,22 @@ ContentClient::CreateContentClient(Compo
   {
     useDoubleBuffering = LayerManagerComposite::SupportsDirectTexturing();
   }
 
   if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) {
     return new ContentClientDoubleBuffered(aForwarder);
   }
 #ifdef XP_MACOSX
-  return new ContentClientIncremental(aForwarder);
-#else
+  if (aForwarder->GetCompositorBackendType() == LAYERS_OPENGL) {
+    return new ContentClientIncremental(aForwarder);
+  }
+#endif
   return new ContentClientSingleBuffered(aForwarder);
-#endif
+
 }
 
 ContentClientBasic::ContentClientBasic(CompositableForwarder* aForwarder,
                                        BasicLayerManager* aManager)
 : ContentClient(aForwarder), ThebesLayerBuffer(ContainsVisibleBounds), mManager(aManager)
 {}
 
 already_AddRefed<gfxASurface>
--- a/gfx/layers/composite/ContentHost.cpp
+++ b/gfx/layers/composite/ContentHost.cpp
@@ -366,16 +366,17 @@ ContentHostDoubleBuffered::EnsureTexture
   if (aTextureId == TextureBack) {
     mBackHost = newHost;
     mBufferRect = nsIntRect();
     mBufferRotation = nsIntPoint();
     return;
   }
   if (aTextureId == TextureOnWhiteBack) {
     mBackHostOnWhite = newHost;
+    return;
   }
 
   NS_ERROR("Bad texture identifier");
 }
 
 void
 ContentHostDoubleBuffered::DestroyTextures()
 {
--- a/image/test/mochitest/Makefile.in
+++ b/image/test/mochitest/Makefile.in
@@ -106,11 +106,12 @@ MOCHITEST_CHROME_FILES = imgutils.js \
                 invalid.jpg \
                 bad.jpg \
                 rillybad.jpg \
                 red.png \
                 lime100x100.svg \
                 test_synchronized_animation.html \
                 animated1.gif \
                 animated2.gif \
+                test_staticClone.html \
                 $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_staticClone.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=878037
+-->
+<head>
+  <title>Test for Bug 878037</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=878037">Mozilla Bug 878037</a>
+<p id="display"></p>
+<div>
+  <!-- transparent-animation.gif from the gif reftests. -->
+  <img id="animated" src="data:image/gif;base64,R0lGODlhZABkAIABAP8AAP///yH5BAkBAAEALAAAAABLAGQAAAK8jI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8YhMKpchgPMJjUqnVOipis1ir9qul+sNV8HistVkTj/JajG7/UXDy+95tm4fy/NdPF/q93dWIqgVWAhwWKgoyPjnyAeZJ2lHOWcJh9mmqcaZ5mkGSreHOCXqRloadRrGGkeoapoa6+TaN0tra4gbq3vHq+q7BVwqrMeEnKy8zNzs/AwdLT1NXW19jZ1tUgAAIfkECQEAAQAsAAAAADQAZAAAArCMj6nL7Q+jnLTai7PevPsPhuJIluaJpurKtu4Lx/JM1/aN5/rO9/7vAAiHxKLxiCRCkswmc+mMSqHSapJqzSof2u4Q67WCw1MuOTs+N9Pqq7kdZcON8vk2aF+/88g6358HaCc4Rwhn2IaopnjGSOYYBukl2UWpZYm2x0enuXnX4NnXGQqAKTYaalqlWoZH+snwWsQah+pJ64Sr5ypbCvQLHCw8TFxsfIycrLzM3PxQAAAh+QQJAQABACwAAAAAGwBkAAACUIyPqcvtD6OctNqLs968+w+G4kiW5omm6sq27gTE8kzX9o3n+s73/g8MCofEovGITCqXzKbzCY1Kp9Sq9YrNarfcrvdrfYnH5LL5jE6r16sCADs=">
+</div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 878037**/
+
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function() {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var img = document.getElementById("animated");
+  var content =  img.QueryInterface(Components.interfaces.nsIImageLoadingContent);
+
+  var request = content.getRequest(Components.interfaces.nsIImageLoadingContent.CURRENT_REQUEST);
+
+  var staticReq = request.getStaticRequest();
+  var clone = staticReq.clone(null);
+
+  ok(true, "hooray, we didn't crash!");
+
+  SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/image/test/reftest/bmp/bmp-1bpp/reftest.list
+++ b/image/test/reftest/bmp/bmp-1bpp/reftest.list
@@ -1,12 +1,12 @@
 # BMP 1BPP tests
 
 # Images of various sizes
-fails-if(B2G) == bmp-size-1x1-1bpp.bmp   bmp-size-1x1-1bpp.png
+== bmp-size-1x1-1bpp.bmp   bmp-size-1x1-1bpp.png
 == bmp-size-2x2-1bpp.bmp   bmp-size-2x2-1bpp.png
 == bmp-size-3x3-1bpp.bmp   bmp-size-3x3-1bpp.png
 == bmp-size-4x4-1bpp.bmp   bmp-size-4x4-1bpp.png
 == bmp-size-5x5-1bpp.bmp   bmp-size-5x5-1bpp.png
 == bmp-size-6x6-1bpp.bmp   bmp-size-6x6-1bpp.png
 == bmp-size-7x7-1bpp.bmp   bmp-size-7x7-1bpp.png
 == bmp-size-8x8-1bpp.bmp   bmp-size-8x8-1bpp.png
 == bmp-size-9x9-1bpp.bmp   bmp-size-9x9-1bpp.png
--- a/ipc/glue/SharedMemory.cpp
+++ b/ipc/glue/SharedMemory.cpp
@@ -5,51 +5,49 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <math.h>
 
 #include "nsString.h"
 #include "nsIMemoryReporter.h"
 #include "mozilla/ipc/SharedMemory.h"
+#include "mozilla/Atomics.h"
 
 namespace mozilla {
 namespace ipc {
 
-static int64_t gShmemAllocated;
-static int64_t gShmemMapped;
-static int64_t GetShmemAllocated() { return gShmemAllocated; }
-static int64_t GetShmemMapped() { return gShmemMapped; }
+static Atomic<size_t> gShmemAllocated;
+static Atomic<size_t> gShmemMapped;
+static size_t GetShmemAllocated() { return gShmemAllocated; }
+static size_t GetShmemMapped() { return gShmemMapped; }
 
-NS_MEMORY_REPORTER_IMPLEMENT(ShmemAllocated,
+NS_THREADSAFE_MEMORY_REPORTER_IMPLEMENT(ShmemAllocated,
   "shmem-allocated",
   KIND_OTHER,
   UNITS_BYTES,
   GetShmemAllocated,
   "Memory shared with other processes that is accessible (but not "
   "necessarily mapped).")
 
-NS_MEMORY_REPORTER_IMPLEMENT(ShmemMapped,
+NS_THREADSAFE_MEMORY_REPORTER_IMPLEMENT(ShmemMapped,
   "shmem-mapped",
   KIND_OTHER,
   UNITS_BYTES,
   GetShmemMapped,
   "Memory shared with other processes that is mapped into the address space.")
 
 SharedMemory::SharedMemory()
   : mAllocSize(0)
   , mMappedSize(0)
 {
-  // NB: SharedMemory is main-thread-only at the moment, but that may
-  // change soon
-  static bool registered;
-  if (!registered) {
+  static Atomic<uint32_t> registered;
+  if (registered.compareExchange(0, 1)) {
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(ShmemAllocated));
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(ShmemMapped));
-    registered = true;
   }
 }
 
 /*static*/ size_t
 SharedMemory::PageAlignedSize(size_t aSize)
 {
   size_t pageSize = SystemPageSize();
   size_t nPagesNeeded = size_t(ceil(double(aSize) / double(pageSize)));
@@ -68,25 +66,25 @@ SharedMemory::Mapped(size_t aNBytes)
 {
   mMappedSize = aNBytes;
   gShmemMapped += mMappedSize;
 }
 
 void
 SharedMemory::Unmapped()
 {
-  NS_ABORT_IF_FALSE(gShmemMapped >= int64_t(mMappedSize),
+  NS_ABORT_IF_FALSE(gShmemMapped >= mMappedSize,
                     "Can't unmap more than mapped");
   gShmemMapped -= mMappedSize;
   mMappedSize = 0;
 }
 
 /*static*/ void
 SharedMemory::Destroyed()
 {
-  NS_ABORT_IF_FALSE(gShmemAllocated >= int64_t(mAllocSize),
+  NS_ABORT_IF_FALSE(gShmemAllocated >= mAllocSize,
                     "Can't destroy more than allocated");
   gShmemAllocated -= mAllocSize;
   mAllocSize = 0;
 }
 
 } // namespace ipc
 } // namespace mozilla
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -603,17 +603,17 @@ host_jsoplengen.$(OBJ_SUFFIX): jsopcode.
 
 # Force auto-header generation before compiling any source that may use them
 $(patsubst %.cc,%.$(OBJ_SUFFIX),$(CPPSRCS:%.cpp=%.$(OBJ_SUFFIX))): $(CURDIR)/jsautokw.h $(CURDIR)/jsautooplen.h
 
 ifdef MOZ_ETW
 ETWProvider.h ETWProvider.rc ETWProvider.mof: ETWProvider.man
 	$(MC) -um -mof $^
 
-jsprobes.$(OBJ_SUFFIX): ETWProvider.h
+Probes.$(OBJ_SUFFIX): ETWProvider.h
 
 ETWProvider.res: ETWProvider.rc
 	$(RC) -r -i "$(SDKDIR)Include" $^
 
 export:: ETWProvider.res
 
 install:: ETWProvider.mof ETWProvider.man
 	$(SYSINSTALL) $^ $(DESTDIR)$(bindir)
@@ -624,17 +624,17 @@ ifdef HAVE_DTRACE
 $(CURDIR)/javascript-trace.h: $(srcdir)/devtools/javascript-trace.d
 	dtrace -h -s $(srcdir)/devtools/javascript-trace.d -o javascript-trace.h.in
 	sed -e 's/if _DTRACE_VERSION/ifdef INCLUDE_MOZILLA_DTRACE/' \
 	    -e '/const/!s/char \*/const char */g' \
 	    javascript-trace.h.in > javascript-trace.h
 
 # We can't automatically generate dependencies on auto-generated headers;
 # we have to list them explicitly.
-$(addsuffix .$(OBJ_SUFFIX),jsprobes jsinterp jsobj): $(CURDIR)/javascript-trace.h
+$(addsuffix .$(OBJ_SUFFIX),Probes jsinterp jsobj): $(CURDIR)/javascript-trace.h
 endif
 
 ifdef HAVE_LINUX_PERF_EVENT_H
 pm_linux.$(OBJ_SUFFIX): CXXFLAGS += $(LINUX_HEADERS_INCLUDES)
 endif
 
 # Prepare self-hosted JS code for embedding
 export:: selfhosting
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -1036,18 +1036,16 @@ const JSPropertySpec MapObject::properti
 
 const JSFunctionSpec MapObject::methods[] = {
     JS_FN("get", get, 1, 0),
     JS_FN("has", has, 1, 0),
     JS_FN("set", set, 2, 0),
     JS_FN("delete", delete_, 1, 0),
     JS_FN("keys", keys, 0, 0),
     JS_FN("values", values, 0, 0),
-    JS_FN("entries", entries, 0, 0),
-    JS_FN("iterator", entries, 0, 0),
     JS_FN("clear", clear, 0, 0),
     JS_FS_END
 };
 
 static JSObject *
 InitClass(JSContext *cx, Handle<GlobalObject*> global, Class *clasp, JSProtoKey key, Native construct,
           const JSPropertySpec *properties, const JSFunctionSpec *methods)
 {
@@ -1066,17 +1064,30 @@ InitClass(JSContext *cx, Handle<GlobalOb
     }
     return proto;
 }
 
 JSObject *
 MapObject::initClass(JSContext *cx, JSObject *obj)
 {
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
-    return InitClass(cx, global, &class_, JSProto_Map, construct, properties, methods);
+    RootedObject proto(cx,
+        InitClass(cx, global, &class_, JSProto_Map, construct, properties, methods));
+    if (proto) {
+        // Define the "entries" method.
+        JSFunction *fun = JS_DefineFunction(cx, proto, "entries", entries, 0, 0);
+        if (!fun)
+            return NULL;
+
+        // Define its alias.
+        RootedValue funval(cx, ObjectValue(*fun));
+        if (!JS_DefineProperty(cx, proto, "iterator", funval, NULL, NULL, 0))
+            return NULL;
+    }
+    return proto;
 }
 
 template <class Range>
 static void
 MarkKey(Range &r, const HashableValue &key, JSTracer *trc)
 {
     HashableValue newKey = key.mark(trc);
 
@@ -1417,24 +1428,26 @@ js_InitMapClass(JSContext *cx, HandleObj
 }
 
 
 /*** SetIterator *********************************************************************************/
 
 class js::SetIteratorObject : public JSObject
 {
   public:
-    enum { TargetSlot, RangeSlot, SlotCount };
+    enum { TargetSlot, KindSlot, RangeSlot, SlotCount };
     static const JSFunctionSpec methods[];
-    static SetIteratorObject *create(JSContext *cx, HandleObject setobj, ValueSet *data);
+    static SetIteratorObject *create(JSContext *cx, HandleObject setobj, ValueSet *data,
+                                     SetObject::IteratorKind kind);
     static void finalize(FreeOp *fop, JSObject *obj);
 
   private:
     static inline bool is(const Value &v);
     inline ValueSet::Range *range();
+    inline SetObject::IteratorKind kind() const;
     static bool next_impl(JSContext *cx, CallArgs args);
     static JSBool next(JSContext *cx, unsigned argc, Value *vp);
 };
 
 inline js::SetIteratorObject &
 JSObject::asSetIterator()
 {
     JS_ASSERT(isSetIterator());
@@ -1461,16 +1474,24 @@ const JSFunctionSpec SetIteratorObject::
 };
 
 inline ValueSet::Range *
 SetIteratorObject::range()
 {
     return static_cast<ValueSet::Range *>(getSlot(RangeSlot).toPrivate());
 }
 
+inline SetObject::IteratorKind
+SetIteratorObject::kind() const
+{
+    int32_t i = getSlot(KindSlot).toInt32();
+    JS_ASSERT(i == SetObject::Values || i == SetObject::Entries);
+    return SetObject::IteratorKind(i);
+}
+
 bool
 GlobalObject::initSetIteratorProto(JSContext *cx, Handle<GlobalObject*> global)
 {
     JSObject *base = global->getOrCreateIteratorPrototype(cx);
     if (!base)
         return false;
     RootedObject proto(cx, NewObjectWithGivenProto(cx, &SetIteratorClass, base, global));
     if (!proto)
@@ -1478,33 +1499,35 @@ GlobalObject::initSetIteratorProto(JSCon
     proto->setSlot(SetIteratorObject::RangeSlot, PrivateValue(NULL));
     if (!JS_DefineFunctions(cx, proto, SetIteratorObject::methods))
         return false;
     global->setReservedSlot(SET_ITERATOR_PROTO, ObjectValue(*proto));
     return true;
 }
 
 SetIteratorObject *
-SetIteratorObject::create(JSContext *cx, HandleObject setobj, ValueSet *data)
+SetIteratorObject::create(JSContext *cx, HandleObject setobj, ValueSet *data,
+                          SetObject::IteratorKind kind)
 {
     Rooted<GlobalObject *> global(cx, &setobj->global());
     Rooted<JSObject*> proto(cx, global->getOrCreateSetIteratorPrototype(cx));
     if (!proto)
         return NULL;
 
     ValueSet::Range *range = cx->new_<ValueSet::Range>(data->all());
     if (!range)
         return NULL;
 
     JSObject *iterobj = NewObjectWithGivenProto(cx, &SetIteratorClass, proto, global);
     if (!iterobj) {
         js_delete(range);
         return NULL;
     }
     iterobj->setSlot(TargetSlot, ObjectValue(*setobj));
+    iterobj->setSlot(KindSlot, Int32Value(int32_t(kind)));
     iterobj->setSlot(RangeSlot, PrivateValue(range));
     return static_cast<SetIteratorObject *>(iterobj);
 }
 
 void
 SetIteratorObject::finalize(FreeOp *fop, JSObject *obj)
 {
     fop->delete_(obj->asSetIterator().range());
@@ -1524,17 +1547,33 @@ SetIteratorObject::next_impl(JSContext *
     if (!range)
         return js_ThrowStopIteration(cx);
     if (range->empty()) {
         js_delete(range);
         thisobj.setReservedSlot(RangeSlot, PrivateValue(NULL));
         return js_ThrowStopIteration(cx);
     }
 
-    args.rval().set(range->front().get());
+    switch (thisobj.kind()) {
+      case SetObject::Values:
+        args.rval().set(range->front().get());
+        break;
+
+      case SetObject::Entries: {
+        Value pair[2] = { range->front().get(), range->front().get() };
+        AutoValueArray root(cx, pair, 2);
+
+        JSObject *pairobj = NewDenseCopiedArray(cx, 2, pair);
+        if (!pairobj)
+          return false;
+        args.rval().setObject(*pairobj);
+        break;
+      }
+    }
+
     range->popFront();
     return true;
 }
 
 JSBool
 SetIteratorObject::next(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1574,26 +1613,41 @@ const JSPropertySpec SetObject::properti
     JS_PSG("size", size, 0),
     JS_PS_END
 };
 
 const JSFunctionSpec SetObject::methods[] = {
     JS_FN("has", has, 1, 0),
     JS_FN("add", add, 1, 0),
     JS_FN("delete", delete_, 1, 0),
-    JS_FN("iterator", iterator, 0, 0),
+    JS_FN("entries", entries, 0, 0),
     JS_FN("clear", clear, 0, 0),
     JS_FS_END
 };
 
 JSObject *
 SetObject::initClass(JSContext *cx, JSObject *obj)
 {
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
-    return InitClass(cx, global, &class_, JSProto_Set, construct, properties, methods);
+    RootedObject proto(cx,
+        InitClass(cx, global, &class_, JSProto_Set, construct, properties, methods));
+    if (proto) {
+        // Define the "values" method.
+        JSFunction *fun = JS_DefineFunction(cx, proto, "values", values, 0, 0);
+        if (!fun)
+            return NULL;
+
+        // Define its aliases.
+        RootedValue funval(cx, ObjectValue(*fun));
+        if (!JS_DefineProperty(cx, proto, "keys", funval, NULL, NULL, 0))
+            return NULL;
+        if (!JS_DefineProperty(cx, proto, "iterator", funval, NULL, NULL, 0))
+            return NULL;
+    }
+    return proto;
 }
 
 void
 SetObject::mark(JSTracer *trc, JSObject *obj)
 {
     SetObject *setobj = static_cast<SetObject *>(obj);
     if (ValueSet *set = setobj->getData()) {
         for (ValueSet::Range r = set->all(); !r.empty(); r.popFront())
@@ -1738,32 +1792,51 @@ SetObject::delete_impl(JSContext *cx, Ca
 JSBool
 SetObject::delete_(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<SetObject::is, SetObject::delete_impl>(cx, args);
 }
 
 bool
-SetObject::iterator_impl(JSContext *cx, CallArgs args)
+SetObject::iterator_impl(JSContext *cx, CallArgs args, IteratorKind kind)
 {
     Rooted<SetObject*> setobj(cx, &args.thisv().toObject().asSet());
     ValueSet &set = *setobj->getData();
-    Rooted<JSObject*> iterobj(cx, SetIteratorObject::create(cx, setobj, &set));
+    Rooted<JSObject*> iterobj(cx, SetIteratorObject::create(cx, setobj, &set, kind));
     if (!iterobj)
         return false;
     args.rval().setObject(*iterobj);
     return true;
 }
 
+bool
+SetObject::values_impl(JSContext *cx, CallArgs args)
+{
+    return iterator_impl(cx, args, Values);
+}
+
 JSBool
-SetObject::iterator(JSContext *cx, unsigned argc, Value *vp)
+SetObject::values(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod(cx, is, iterator_impl, args);
+    return CallNonGenericMethod(cx, is, values_impl, args);
+}
+
+bool
+SetObject::entries_impl(JSContext *cx, CallArgs args)
+{
+    return iterator_impl(cx, args, Entries);
+}
+
+JSBool
+SetObject::entries(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod(cx, is, entries_impl, args);
 }
 
 bool
 SetObject::clear_impl(JSContext *cx, CallArgs args)
 {
     Rooted<SetObject*> setobj(cx, &args.thisv().toObject().asSet());
     if (!setobj->getData()->clear()) {
         js_ReportOutOfMemory(cx);
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -122,39 +122,44 @@ class MapObject : public JSObject {
     static bool entries_impl(JSContext *cx, CallArgs args);
     static JSBool entries(JSContext *cx, unsigned argc, Value *vp);
     static bool clear_impl(JSContext *cx, CallArgs args);
     static JSBool clear(JSContext *cx, unsigned argc, Value *vp);
 };
 
 class SetObject : public JSObject {
   public:
+    enum IteratorKind { Values, Entries };
     static JSObject *initClass(JSContext *cx, JSObject *obj);
     static Class class_;
   private:
     static const JSPropertySpec properties[];
     static const JSFunctionSpec methods[];
     ValueSet *getData() { return static_cast<ValueSet *>(getPrivate()); }
     static ValueSet & extract(CallReceiver call);
     static void mark(JSTracer *trc, JSObject *obj);
     static void finalize(FreeOp *fop, JSObject *obj);
     static JSBool construct(JSContext *cx, unsigned argc, Value *vp);
 
     static bool is(const Value &v);
 
+    static bool iterator_impl(JSContext *cx, CallArgs args, IteratorKind kind);
+
     static bool size_impl(JSContext *cx, CallArgs args);
     static JSBool size(JSContext *cx, unsigned argc, Value *vp);
     static bool has_impl(JSContext *cx, CallArgs args);
     static JSBool has(JSContext *cx, unsigned argc, Value *vp);
     static bool add_impl(JSContext *cx, CallArgs args);
     static JSBool add(JSContext *cx, unsigned argc, Value *vp);
     static bool delete_impl(JSContext *cx, CallArgs args);
     static JSBool delete_(JSContext *cx, unsigned argc, Value *vp);
-    static bool iterator_impl(JSContext *cx, CallArgs args);
-    static JSBool iterator(JSContext *cx, unsigned argc, Value *vp);
+    static bool values_impl(JSContext *cx, CallArgs args);
+    static JSBool values(JSContext *cx, unsigned argc, Value *vp);
+    static bool entries_impl(JSContext *cx, CallArgs args);
+    static JSBool entries(JSContext *cx, unsigned argc, Value *vp);
     static bool clear_impl(JSContext *cx, CallArgs args);
     static JSBool clear(JSContext *cx, unsigned argc, Value *vp);
 };
 
 } /* namespace js */
 
 extern JSObject *
 js_InitMapClass(JSContext *cx, js::HandleObject obj);
--- a/js/src/builtin/Module.h
+++ b/js/src/builtin/Module.h
@@ -28,16 +28,9 @@ class Module : public JSObject {
     inline void setScript(JSScript *script);
 
     static const uint32_t ATOM_SLOT = 0;
     static const uint32_t SCRIPT_SLOT = 1;
 };
 
 } // namespace js
 
-inline js::Module &
-JSObject::asModule()
-{
-    JS_ASSERT(isModule());
-    return *static_cast<js::Module *>(this);
-}
-
 #endif // Module_h___
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "jscntxt.h"
 #include "jsobj.h"
 
 #include "builtin/Object.h"
-#include "frontend/Parser.h"
+#include "frontend/BytecodeCompiler.h"
 #include "vm/StringBuffer.h"
 
 #include "jsfuninlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::types;
 
--- a/js/src/builtin/Profilers.cpp
+++ b/js/src/builtin/Profilers.cpp
@@ -6,19 +6,19 @@
 
 /* Profiling-related API */
 
 #include <stdarg.h>
 
 #include "Profilers.h"
 #include "jsapi.h"
 #include "jscntxt.h"
-#include "jsprobes.h"
 
 #include "jscntxtinlines.h"
+#include "vm/Probes-inl.h"
 #include "vm/Stack-inl.h"
 
 #ifdef MOZ_CALLGRIND
 #include <valgrind/callgrind.h>
 #endif
 
 #ifdef __APPLE__
 #include "devtools/sharkctl.h"
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -1,31 +1,29 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 #include "frontend/BytecodeCompiler.h"
 
-#include "jsprobes.h"
 #include "jsscript.h"
-
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/NameFunctions.h"
 #include "ion/AsmJS.h"
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
-
 #include "frontend/ParseMaps-inl.h"
 #include "frontend/ParseNode-inl.h"
 #include "frontend/Parser-inl.h"
 #include "frontend/SharedContext-inl.h"
+#include "vm/Probes-inl.h"
 
 using namespace js;
 using namespace js::frontend;
 using mozilla::Maybe;
 
 static bool
 CheckLength(JSContext *cx, size_t length)
 {
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -23,12 +23,32 @@ bool
 CompileLazyFunction(JSContext *cx, HandleFunction fun, LazyScript *lazy,
                     const jschar *chars, size_t length);
 
 bool
 CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
                     const AutoNameVector &formals, const jschar *chars, size_t length,
                     bool isAsmJSRecompile = false);
 
+/*
+ * True if str consists of an IdentifierStart character, followed by one or
+ * more IdentifierPart characters, i.e. it matches the IdentifierName production
+ * in the language spec.
+ *
+ * This returns true even if str is a keyword like "if".
+ *
+ * Defined in TokenStream.cpp.
+ */
+bool
+IsIdentifier(JSLinearString *str);
+
+/* True if str is a keyword. Defined in TokenStream.cpp. */
+bool
+IsKeyword(JSLinearString *str);
+
+/* GC marking. Defined in Parser.cpp. */
+void
+MarkParser(JSTracer *trc, AutoGCRooter *parser);
+
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* BytecodeCompiler_h__ */
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BytecodeEmitter-inl.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 BytecodeEmitter_inl_h__
+#define BytecodeEmitter_inl_h__
+
+#include "frontend/BytecodeEmitter.h"
+#include "frontend/Parser.h"
+
+namespace js {
+namespace frontend {
+
+inline TokenStream *
+BytecodeEmitter::tokenStream()
+{
+    return &parser->tokenStream;
+}
+
+} // namespace frontend
+} // namespace js
+
+#endif // BytecodeEmitter_inl_h__
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3,16 +3,18 @@
  * 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/. */
 
 /*
  * JS bytecode generation.
  */
 
+#include "frontend/BytecodeEmitter-inl.h"
+
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/PodOperations.h"
 
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
 #endif
 #include <string.h>
@@ -26,17 +28,16 @@
 #include "jsversion.h"
 #include "jsfun.h"
 #include "jsnum.h"
 #include "jsopcode.h"
 #include "jsscript.h"
 #include "jsautooplen.h"        // generated headers last
 
 #include "ds/LifoAlloc.h"
-#include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 #include "ion/AsmJS.h"
 #include "vm/Debugger.h"
 #include "vm/RegExpObject.h"
 #include "vm/Shape.h"
 
 #include "jsatominlines.h"
@@ -6022,16 +6023,21 @@ frontend::EmitTree(JSContext *cx, Byteco
         if (Emit1(cx, bce, JSOP_DEBUGGER) < 0)
             return false;
         break;
 
       case PNK_NOP:
         JS_ASSERT(pn->getArity() == PN_NULLARY);
         break;
 
+      case PNK_MODULE:
+        // TODO: Add emitter support for modules
+        bce->reportError(NULL, JSMSG_SYNTAX_ERROR);
+        return false;
+
       default:
         JS_ASSERT(0);
     }
 
     /* bce->emitLevel == 1 means we're last on the stack, so finish up. */
     if (ok && bce->emitLevel == 1) {
         if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.end))
             return false;
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -10,18 +10,16 @@
 /*
  * JS bytecode generation.
  */
 #include "jsatom.h"
 #include "jsopcode.h"
 #include "jsscript.h"
 #include "jspubtd.h"
 
-#include "frontend/BytecodeCompiler.h"
-#include "frontend/Parser.h"
 #include "frontend/ParseMaps.h"
 #include "frontend/SharedContext.h"
 #include "frontend/SourceNotes.h"
 
 #include "vm/ScopeObject.h"
 
 namespace js {
 namespace frontend {
@@ -179,17 +177,17 @@ struct BytecodeEmitter
 
     bool isInLoop();
     bool checkSingletonContext();
 
     bool needsImplicitThis();
 
     void tellDebuggerAboutCompiledScript(JSContext *cx);
 
-    TokenStream *tokenStream() { return &parser->tokenStream; }
+    inline TokenStream *tokenStream();
 
     BytecodeVector &code() const { return current->code; }
     jsbytecode *code(ptrdiff_t offset) const { return current->code.begin() + offset; }
     ptrdiff_t offset() const { return current->code.end() - current->code.begin(); }
     ptrdiff_t prologOffset() const { return prolog.code.end() - prolog.code.begin(); }
     void switchToMain() { current = &main; }
     void switchToProlog() { current = &prolog; }
 
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -106,17 +106,17 @@ FoldType(JSContext *cx, ParseNode *pn, P
 
 /*
  * Fold two numeric constants.  Beware that pn1 and pn2 are recycled, unless
  * one of them aliases pn, so you can't safely fetch pn2->pn_next, e.g., after
  * a successful call to this function.
  */
 static bool
 FoldBinaryNumeric(JSContext *cx, JSOp op, ParseNode *pn1, ParseNode *pn2,
-                  ParseNode *pn, Parser<FullParseHandler> *parser)
+                  ParseNode *pn)
 {
     double d, d2;
     int32_t i, j;
 
     JS_ASSERT(pn1->isKind(PNK_NUMBER) && pn2->isKind(PNK_NUMBER));
     d = pn1->pn_dval;
     d2 = pn2->pn_dval;
     switch (op) {
@@ -198,49 +198,30 @@ ReplaceNode(ParseNode **pnp, ParseNode *
     *pnp = pn;
 }
 
 enum Truthiness { Truthy, Falsy, Unknown };
 
 static Truthiness
 Boolish(ParseNode *pn)
 {
-    switch (pn->getOp()) {
-      case JSOP_DOUBLE:
+    switch (pn->getKind()) {
+      case PNK_NUMBER:
         return (pn->pn_dval != 0 && !IsNaN(pn->pn_dval)) ? Truthy : Falsy;
 
-      case JSOP_STRING:
+      case PNK_STRING:
         return (pn->pn_atom->length() > 0) ? Truthy : Falsy;
 
-#if JS_HAS_GENERATOR_EXPRS
-      case JSOP_CALL:
-      {
-        /*
-         * A generator expression as an if or loop condition has no effects, it
-         * simply results in a truthy object reference. This condition folding
-         * is needed for the decompiler. See bug 442342 and bug 443074.
-         */
-        if (pn->pn_count != 1)
-            return Unknown;
-        ParseNode *pn2 = pn->pn_head;
-        if (!pn2->isKind(PNK_FUNCTION))
-            return Unknown;
-        if (!(pn2->pn_funbox->inGenexpLambda))
-            return Unknown;
-        return Truthy;
-      }
-#endif
-
-      case JSOP_DEFFUN:
-      case JSOP_LAMBDA:
-      case JSOP_TRUE:
+      case PNK_TRUE:
+      case PNK_FUNCTION:
+      case PNK_GENEXP:
         return Truthy;
 
-      case JSOP_NULL:
-      case JSOP_FALSE:
+      case PNK_FALSE:
+      case PNK_NULL:
         return Falsy;
 
       default:
         return Unknown;
     }
 }
 
 namespace js {
@@ -261,18 +242,21 @@ FoldConstants<FullParseHandler>(JSContex
     // constant-folding will misrepresent the source text for the purpose
     // of type checking. (Also guard against entering a function containing
     // "use asm", see PN_FUNC case below.)
     if (parser->pc->useAsmOrInsideUseAsm() && cx->hasOption(JSOPTION_ASMJS))
         return true;
 
     switch (pn->getArity()) {
       case PN_CODE:
-        if (pn->pn_funbox->useAsmOrInsideUseAsm() && cx->hasOption(JSOPTION_ASMJS))
+        if (pn->isKind(PNK_FUNCTION) &&
+            pn->pn_funbox->useAsmOrInsideUseAsm() && cx->hasOption(JSOPTION_ASMJS))
+        {
             return true;
+        }
         if (pn->getKind() == PNK_MODULE) {
             if (!FoldConstants(cx, &pn->pn_body, parser))
                 return false;
         } else {
             // Note: pn_body is NULL for functions which are being lazily parsed.
             JS_ASSERT(pn->getKind() == PNK_FUNCTION);
             if (pn->pn_body) {
                 if (!FoldConstants(cx, &pn->pn_body, parser, pn->pn_funbox->inGenexpLambda))
@@ -634,61 +618,61 @@ FoldConstants<FullParseHandler>(JSContex
                 if (!pn2->isKind(PNK_NUMBER))
                     break;
             }
             if (!pn2) {
                 JSOp op = pn->getOp();
 
                 pn2 = pn1->pn_next;
                 pn3 = pn2->pn_next;
-                if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn, parser))
+                if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn))
                     return false;
                 while ((pn2 = pn3) != NULL) {
                     pn3 = pn2->pn_next;
-                    if (!FoldBinaryNumeric(cx, op, pn, pn2, pn, parser))
+                    if (!FoldBinaryNumeric(cx, op, pn, pn2, pn))
                         return false;
                 }
             }
         } else {
             JS_ASSERT(pn->isArity(PN_BINARY));
             if (!FoldType(cx, pn1, PNK_NUMBER) ||
                 !FoldType(cx, pn2, PNK_NUMBER)) {
                 return false;
             }
             if (pn1->isKind(PNK_NUMBER) && pn2->isKind(PNK_NUMBER)) {
-                if (!FoldBinaryNumeric(cx, pn->getOp(), pn1, pn2, pn, parser))
+                if (!FoldBinaryNumeric(cx, pn->getOp(), pn1, pn2, pn))
                     return false;
             }
         }
         break;
 
       case PNK_TYPEOF:
       case PNK_VOID:
       case PNK_NOT:
       case PNK_BITNOT:
       case PNK_POS:
       case PNK_NEG:
         if (pn1->isKind(PNK_NUMBER)) {
             double d;
 
             /* Operate on one numeric constant. */
             d = pn1->pn_dval;
-            switch (pn->getOp()) {
-              case JSOP_BITNOT:
+            switch (pn->getKind()) {
+              case PNK_BITNOT:
                 d = ~ToInt32(d);
                 break;
 
-              case JSOP_NEG:
+              case PNK_NEG:
                 d = -d;
                 break;
 
-              case JSOP_POS:
+              case PNK_POS:
                 break;
 
-              case JSOP_NOT:
+              case PNK_NOT:
                 if (d == 0 || IsNaN(d)) {
                     pn->setKind(PNK_TRUE);
                     pn->setOp(JSOP_TRUE);
                 } else {
                     pn->setKind(PNK_FALSE);
                     pn->setOp(JSOP_FALSE);
                 }
                 pn->setArity(PN_NULLARY);
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -1,20 +1,21 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 #include "frontend/NameFunctions.h"
-#include "frontend/ParseNode.h"
-#include "frontend/SharedContext.h"
 
 #include "jsfun.h"
 #include "jsprf.h"
+#include "frontend/BytecodeCompiler.h"
+#include "frontend/ParseNode.h"
+#include "frontend/SharedContext.h"
 
 #include "vm/String-inl.h"
 #include "vm/StringBuffer.h"
 
 using namespace js;
 using namespace js::frontend;
 
 class NameResolver
@@ -311,17 +312,17 @@ class NameResolver
                 resolve(cur->pn_right, prefix);
             break;
           case PN_TERNARY:
             resolve(cur->pn_kid1, prefix);
             resolve(cur->pn_kid2, prefix);
             resolve(cur->pn_kid3, prefix);
             break;
           case PN_CODE:
-            JS_ASSERT(cur->isKind(PNK_FUNCTION));
+            JS_ASSERT(cur->isKind(PNK_MODULE) || cur->isKind(PNK_FUNCTION));
             resolve(cur->pn_body, prefix);
             break;
           case PN_LIST:
             for (ParseNode *nxt = cur->pn_head; nxt; nxt = nxt->pn_next)
                 resolve(nxt, prefix);
             break;
         }
         nparents--;
--- a/js/src/frontend/ParseNode-inl.h
+++ b/js/src/frontend/ParseNode-inl.h
@@ -2,18 +2,18 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 ParseNode_inl_h__
 #define ParseNode_inl_h__
 
-#include "frontend/Parser.h"
 #include "frontend/ParseNode.h"
+#include "frontend/SharedContext.h"
 
 namespace js {
 namespace frontend {
 
 inline bool
 UpvarCookie::set(JSContext *cx, unsigned newLevel, uint16_t newSlot)
 {
     // This is an unsigned-to-uint16_t conversion, test for too-high values.
@@ -39,23 +39,12 @@ ParseNode::name() const
 
 inline JSAtom *
 ParseNode::atom() const
 {
     JS_ASSERT(isKind(PNK_MODULE) || isKind(PNK_STRING));
     return isKind(PNK_MODULE) ? pn_modulebox->module()->atom() : pn_atom;
 }
 
-inline void
-NameNode::initCommon(ParseContext<FullParseHandler> *pc)
-{
-    pn_expr = NULL;
-    pn_cookie.makeFree();
-    pn_dflags = (!pc->topStmt || pc->topStmt->type == STMT_BLOCK)
-                ? PND_BLOCKCHILD
-                : 0;
-    pn_blockid = pc->blockid();
-}
-
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* ParseNode_inl_h__ */
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -341,16 +341,27 @@ ParseNode::newBinaryOrAppend(ParseNodeKi
         left->pn_pos.end = right->pn_pos.end;
         handler->freeTree(right);
         return left;
     }
 
     return handler->new_<BinaryNode>(kind, op, left, right);
 }
 
+inline void
+NameNode::initCommon(ParseContext<FullParseHandler> *pc)
+{
+    pn_expr = NULL;
+    pn_cookie.makeFree();
+    pn_dflags = (!pc->topStmt || pc->topStmt->type == STMT_BLOCK)
+                ? PND_BLOCKCHILD
+                : 0;
+    pn_blockid = pc->blockid();
+}
+
 // Note: the parse context passed into this may not equal the associated
 // parser's current context.
 NameNode *
 NameNode::create(ParseNodeKind kind, JSAtom *atom, FullParseHandler *handler,
                  ParseContext<FullParseHandler> *pc)
 {
     ParseNode *pn = ParseNode::create(kind, PN_NAME, handler);
     if (pn) {
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -240,17 +240,17 @@ enum ParseNodeKind {
  *                          pn_val: constant value if lookup or table switch
  * PNK_WHILE    binary      pn_left: cond, pn_right: body
  * PNK_DOWHILE  binary      pn_left: body, pn_right: cond
  * PNK_FOR      binary      pn_left: either PNK_FORIN (for-in statement) or
  *                            PNK_FORHEAD (for(;;) statement)
  *                          pn_right: body
  * PNK_FORIN    ternary     pn_kid1:  PNK_VAR to left of 'in', or NULL
  *                            its pn_xflags may have PNX_POPVAR
- *                            and PNX_FORINVAR bits set
+ *                            bit set
  *                          pn_kid2: PNK_NAME or destructuring expr
  *                            to left of 'in'; if pn_kid1, then this
  *                            is a clone of pn_kid1->pn_head
  *                          pn_kid3: object expr to right of 'in'
  * PNK_FORHEAD  ternary     pn_kid1:  init expr before first ';' or NULL
  *                          pn_kid2:  cond expr before second ';' or NULL
  *                          pn_kid3:  update expr after second ';' or NULL
  * PNK_THROW    unary       pn_op: JSOP_THROW, pn_kid: exception
@@ -637,31 +637,29 @@ struct ParseNode {
 /* Flags to propagate from uses to definition. */
 #define PND_USE2DEF_FLAGS (PND_ASSIGNED | PND_CLOSED)
 
 /* PN_LIST pn_xflags bits. */
 #define PNX_STRCAT      0x01            /* PNK_ADD list has string term */
 #define PNX_CANTFOLD    0x02            /* PNK_ADD list has unfoldable term */
 #define PNX_POPVAR      0x04            /* PNK_VAR or PNK_CONST last result
                                            needs popping */
-#define PNX_FORINVAR    0x08            /* PNK_VAR is left kid of PNK_FORIN node
-                                           which is left kid of PNK_FOR */
-#define PNX_GROUPINIT   0x10            /* var [a, b] = [c, d]; unit list */
-#define PNX_FUNCDEFS    0x20            /* contains top-level function statements */
-#define PNX_SETCALL     0x40            /* call expression in lvalue context */
-#define PNX_DESTRUCT    0x80            /* destructuring special cases:
+#define PNX_GROUPINIT   0x08            /* var [a, b] = [c, d]; unit list */
+#define PNX_FUNCDEFS    0x10            /* contains top-level function statements */
+#define PNX_SETCALL     0x20            /* call expression in lvalue context */
+#define PNX_DESTRUCT    0x40            /* destructuring special cases:
                                            1. shorthand syntax used, at present
                                               object destructuring ({x,y}) only;
                                            2. code evaluating destructuring
                                               arguments occurs before function
                                               body */
-#define PNX_SPECIALARRAYINIT 0x100      /* one or more of
+#define PNX_SPECIALARRAYINIT 0x80       /* one or more of
                                            1. array initialiser has holes
                                            2. array initializer has spread node */
-#define PNX_NONCONST   0x200            /* initialiser has non-constants */
+#define PNX_NONCONST   0x100            /* initialiser has non-constants */
 
     unsigned frameLevel() const {
         JS_ASSERT(pn_arity == PN_CODE || pn_arity == PN_NAME);
         return pn_cookie.level();
     }
 
     unsigned frameSlot() const {
         JS_ASSERT(pn_arity == PN_CODE || pn_arity == PN_NAME);
--- a/js/src/frontend/Parser-inl.h
+++ b/js/src/frontend/Parser-inl.h
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 Parser_inl_h__
 #define Parser_inl_h__
 
+#include "frontend/BytecodeCompiler.h"
 #include "frontend/Parser.h"
 
 #include "frontend/SharedContext-inl.h"
 
 namespace js {
 namespace frontend {
 
 template <typename ParseHandler>
@@ -99,20 +100,17 @@ ParseContext<ParseHandler>::~ParseContex
 template <typename ParseHandler>
 static bool
 CheckStrictBinding(JSContext *cx, ParseHandler *handler, ParseContext<ParseHandler> *pc,
                    HandlePropertyName name, ParseNode *pn)
 {
     if (!pc->sc->needStrictChecks())
         return true;
 
-    if (name == cx->names().eval ||
-        name == cx->names().arguments ||
-        FindKeyword(name->charsZ(), name->length()))
-    {
+    if (name == cx->names().eval || name == cx->names().arguments || IsKeyword(name)) {
         JSAutoByteString bytes;
         if (!js_AtomToPrintableString(cx, name, &bytes))
             return false;
         return handler->report(ParseStrictError, pn, JSMSG_BAD_BINDING, bytes.ptr());
     }
 
     return true;
 }
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -34,19 +34,19 @@
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
+#include "frontend/BytecodeCompiler.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/ParseMaps.h"
-#include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 #include "gc/Marking.h"
 #include "vm/Interpreter.h"
 #include "vm/Shape.h"
 
 #include "jsatominlines.h"
 #include "jsscriptinlines.h"
 
@@ -592,16 +592,22 @@ Parser<FullParseHandler>::newModuleBox(M
 
 template <typename ParseHandler>
 void
 Parser<ParseHandler>::trace(JSTracer *trc)
 {
     traceListHead->trace(trc);
 }
 
+void
+MarkParser(JSTracer *trc, AutoGCRooter *parser)
+{
+    static_cast<Parser<FullParseHandler> *>(parser)->trace(trc);
+}
+
 /*
  * Parse a top-level JS script.
  */
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::parse(JSObject *chain)
 {
     /*
@@ -825,20 +831,17 @@ Parser<ParseHandler>::checkStrictAssignm
  */
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::checkStrictBinding(HandlePropertyName name, Node pn)
 {
     if (!pc->sc->needStrictChecks())
         return true;
 
-    if (name == context->names().eval ||
-        name == context->names().arguments ||
-        FindKeyword(name->charsZ(), name->length()))
-    {
+    if (name == context->names().eval || name == context->names().arguments || IsKeyword(name)) {
         JSAutoByteString bytes;
         if (!js_AtomToPrintableString(context, name, &bytes))
             return false;
         return report(ParseStrictError, pc->sc->strict, pn,
                       JSMSG_BAD_BINDING, bytes.ptr());
     }
 
     return true;
@@ -3816,21 +3819,17 @@ Parser<FullParseHandler>::forStatement()
         }
 
         /*
          * After the following if-else, pn2 will point to the name or
          * destructuring pattern on in's left. pn1 will point to the decl, if
          * any, else NULL. Note that the "declaration with initializer" case
          * rewrites the loop-head, moving the decl and setting pn1 to NULL.
          */
-        pn2 = NULL;
         if (forDecl) {
-            /* Tell EmitVariables that pn1 is part of a for/in. */
-            pn1->pn_xflags |= PNX_FORINVAR;
-
             pn2 = pn1->pn_head;
             if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr())
 #if JS_HAS_DESTRUCTURING
                 || pn2->isKind(PNK_ASSIGN)
 #endif
                 )
             {
                 /*
@@ -3847,24 +3846,22 @@ Parser<FullParseHandler>::forStatement()
                 }
 #endif /* JS_HAS_BLOCK_SCOPE */
 
                 ParseNode *pnseq = handler.newList(PNK_SEQ, pn1);
                 if (!pnseq)
                     return null();
 
                 /*
-                 * All of 'var x = i' is hoisted above 'for (x in o)',
-                 * so clear PNX_FORINVAR.
+                 * All of 'var x = i' is hoisted above 'for (x in o)'.
                  *
                  * Request JSOP_POP here since the var is for a simple
                  * name (it is not a destructuring binding's left-hand
                  * side) and it has an initializer.
                  */
-                pn1->pn_xflags &= ~PNX_FORINVAR;
                 pn1->pn_xflags |= PNX_POPVAR;
                 pn1 = NULL;
 
 #if JS_HAS_DESTRUCTURING
                 if (pn2->isKind(PNK_ASSIGN)) {
                     pn2 = pn2->pn_left;
                     JS_ASSERT(pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT) ||
                               pn2->isKind(PNK_NAME));
@@ -6056,17 +6053,16 @@ Parser<FullParseHandler>::comprehensionT
          */
         ParseNode *vars = ListNode::create(PNK_VAR, &handler);
         if (!vars)
             return null();
         vars->setOp(JSOP_NOP);
         vars->pn_pos = pn3->pn_pos;
         vars->makeEmpty();
         vars->append(pn3);
-        vars->pn_xflags |= PNX_FORINVAR;
 
         /* Definitions can't be passed directly to EmitAssignment as lhs. */
         pn3 = cloneLeftHandSide(pn3);
         if (!pn3)
             return null();
 
         pn2->pn_left = handler.newTernary(PNK_FORIN, vars, pn3, pn4);
         if (!pn2->pn_left)
@@ -6536,23 +6532,16 @@ Parser<FullParseHandler>::newRegExp(cons
     if (context->hasfp())
         reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream);
     else
         reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream);
 
     if (!reobj)
         return NULL;
 
-    if (!compileAndGo) {
-        if (!JSObject::clearParent(context, reobj))
-            return NULL;
-        if (!JSObject::clearType(context, reobj))
-            return NULL;
-    }
-
     pn->pn_objbox = newObjectBox(reobj);
     if (!pn->pn_objbox)
         return NULL;
 
     pn->setOp(JSOP_REGEXP);
     return pn;
 }
 
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -12,17 +12,17 @@
  */
 #include "jsversion.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsatom.h"
 #include "jsscript.h"
 #include "jswin.h"
 
-#include "frontend/FoldConstants.h"
+#include "frontend/BytecodeCompiler.h"
 #include "frontend/FullParseHandler.h"
 #include "frontend/ParseMaps.h"
 #include "frontend/ParseNode.h"
 #include "frontend/SharedContext.h"
 #include "frontend/SyntaxParseHandler.h"
 
 namespace js {
 namespace frontend {
@@ -324,17 +324,17 @@ struct Parser : private AutoGCRooter, pu
                           ...);
 
     Parser(JSContext *cx, const CompileOptions &options,
            const jschar *chars, size_t length, bool foldConstants,
            Parser<SyntaxParseHandler> *syntaxParser,
            LazyScript *lazyOuterFunction);
     ~Parser();
 
-    friend void AutoGCRooter::trace(JSTracer *trc);
+    friend void js::frontend::MarkParser(JSTracer *trc, AutoGCRooter *parser);
 
     const char *getFilename() const { return tokenStream.getFilename(); }
     JSVersion versionNumber() const { return tokenStream.versionNumber(); }
 
     /*
      * Parse a top-level JS script.
      */
     Node parse(JSObject *chain);
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -27,16 +27,17 @@
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsexn.h"
 #include "jsnum.h"
 #include "jsopcode.h"
 #include "jsscript.h"
 
+#include "frontend/BytecodeCompiler.h"
 #include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 #include "js/CharacterEncoding.h"
 #include "vm/Keywords.h"
 #include "vm/RegExpObject.h"
 #include "vm/StringBuffer.h"
 
 #include "jsscriptinlines.h"
@@ -44,30 +45,41 @@
 using namespace js;
 using namespace js::frontend;
 using namespace js::unicode;
 
 using mozilla::PodAssign;
 using mozilla::PodCopy;
 using mozilla::PodZero;
 
+struct KeywordInfo {
+    const char  *chars;         /* C string with keyword text */
+    TokenKind   tokentype;
+    JSOp        op;             /* JSOp */
+    JSVersion   version;        /* JSVersion */
+};
+
 static const KeywordInfo keywords[] = {
 #define KEYWORD_INFO(keyword, name, type, op, version) \
     {js_##keyword##_str, type, op, version},
     FOR_EACH_JAVASCRIPT_KEYWORD(KEYWORD_INFO)
 #undef KEYWORD_INFO
 };
 
-const KeywordInfo *
-frontend::FindKeyword(const jschar *s, size_t length)
+/*
+ * Returns a KeywordInfo for the specified characters, or NULL if the string is
+ * not a keyword.
+ */
+static const KeywordInfo *
+FindKeyword(const jschar *s, size_t length)
 {
     JS_ASSERT(length != 0);
 
     register size_t i;
-    const struct KeywordInfo *kw;
+    const KeywordInfo *kw;
     const char *chars;
 
 #define JSKW_LENGTH()           length
 #define JSKW_AT(column)         s[column]
 #define JSKW_GOT_MATCH(index)   i = (index); goto got_match;
 #define JSKW_TEST_GUESS(index)  i = (index); goto test_guess;
 #define JSKW_NO_MATCH()         goto no_match;
 #include "jsautokw.h"
@@ -108,16 +120,22 @@ frontend::IsIdentifier(JSLinearString *s
     while (++chars != end) {
         c = *chars;
         if (!IsIdentifierPart(c))
             return false;
     }
     return true;
 }
 
+bool
+frontend::IsKeyword(JSLinearString *str)
+{
+    return FindKeyword(str->chars(), str->length()) != NULL;
+}
+
 TokenStream::SourceCoords::SourceCoords(JSContext *cx, uint32_t ln)
   : lineStartOffsets_(cx), initialLineNum_(ln), lastLineIndex_(0)
 {
     // This is actually necessary!  Removing it causes compile errors on
     // GCC and clang.  You could try declaring this:
     //
     //   const uint32_t TokenStream::SourceCoords::MAX_PTR;
     //
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -934,37 +934,16 @@ class MOZ_STACK_CLASS TokenStream
      */
     SkipRoot            tokenSkip;
 
     // Bug 846011
     SkipRoot            linebaseSkip;
     SkipRoot            prevLinebaseSkip;
 };
 
-struct KeywordInfo {
-    const char  *chars;         /* C string with keyword text */
-    TokenKind   tokentype;
-    JSOp        op;             /* JSOp */
-    JSVersion   version;        /* JSVersion */
-};
-
-/*
- * Returns a KeywordInfo for the specified characters, or NULL if the string is
- * not a keyword.
- */
-const KeywordInfo *
-FindKeyword(const jschar *s, size_t length);
-
-/*
- * Check that str forms a valid JS identifier name. The function does not
- * check if str is a JS keyword.
- */
-bool
-IsIdentifier(JSLinearString *str);
-
 /*
  * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error
  * message have const jschar* type, not const char*.
  */
 #define JSREPORT_UC 0x100
 
 } /* namespace frontend */
 } /* namespace js */
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -11,17 +11,17 @@
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsgc.h"
 #include "jsonparser.h"
 #include "jsprf.h"
 #include "jswatchpoint.h"
 
 #include "builtin/MapObject.h"
-#include "frontend/Parser.h"
+#include "frontend/BytecodeCompiler.h"
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 #ifdef JS_ION
 # include "ion/IonMacroAssembler.h"
 # include "ion/IonFrameIterator.h"
 #endif
 #include "js/HashTable.h"
 #include "vm/Debugger.h"
@@ -383,17 +383,17 @@ JS::AutoIdArray::trace(JSTracer *trc)
     gc::MarkIdRange(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray");
 }
 
 inline void
 AutoGCRooter::trace(JSTracer *trc)
 {
     switch (tag_) {
       case PARSER:
-        static_cast<frontend::Parser<frontend::FullParseHandler> *>(this)->trace(trc);
+        frontend::MarkParser(trc, this);
         return;
 
       case IDARRAY: {
         JSIdArray *ida = static_cast<AutoIdArray *>(this)->idArray;
         MarkIdRange(trc, ida->length, ida->vector, "JS::AutoIdArray.idArray");
         return;
       }
 
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -1,32 +1,33 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
+#include "gc/Statistics.h"
+
 #include <stdio.h>
 #include <stdarg.h>
 
 #include "mozilla/PodOperations.h"
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jscrashformat.h"
 #include "jscrashreport.h"
 #include "jsprf.h"
-#include "jsprobes.h"
 #include "jsutil.h"
 #include "prmjtime.h"
+#include "gc/Memory.h"
 
-#include "gc/Memory.h"
-#include "gc/Statistics.h"
-
+#include "jscntxtinlines.h"
 #include "gc/Barrier-inl.h"
+#include "vm/Probes-inl.h"
 
 using namespace js;
 using namespace js::gcstats;
 
 using mozilla::PodArrayZero;
 
 /* Except for the first and last, slices of less than 42ms are not reported. */
 static const int64_t SLICE_MIN_REPORT_TIME = 42 * PRMJ_USEC_PER_MSEC;
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsgc.h"
 #include "jsprf.h"
 
+#include "vm/Debugger.h"
 #include "js/HashTable.h"
 #include "gc/GCInternals.h"
 
 #ifdef JS_ION
 #include "ion/BaselineJIT.h"
 #include "ion/IonCompartment.h"
 #include "ion/Ion.h"
 #endif
@@ -138,20 +139,54 @@ Zone::sweep(FreeOp *fop, bool releaseTyp
     if (active)
         releaseTypes = false;
 
     if (!isPreservingCode()) {
         gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
         types.sweep(fop, releaseTypes);
     }
 
+    if (!rt->debuggerList.isEmpty())
+        sweepBreakpoints(fop);
+
     active = false;
 }
 
 void
+Zone::sweepBreakpoints(FreeOp *fop)
+{
+    /*
+     * Sweep all compartments in a zone at the same time, since there is no way
+     * to iterate over the scripts belonging to a single compartment in a zone.
+     */
+
+    gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_SWEEP_TABLES);
+    gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TABLES_BREAKPOINT);
+
+    for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
+        JSScript *script = i.get<JSScript>();
+        if (!script->hasAnyBreakpointsOrStepMode())
+            continue;
+        bool scriptGone = IsScriptAboutToBeFinalized(&script);
+        JS_ASSERT(script == i.get<JSScript>());
+        for (unsigned i = 0; i < script->length; i++) {
+            BreakpointSite *site = script->getBreakpointSite(script->code + i);
+            if (!site)
+                continue;
+            Breakpoint *nextbp;
+            for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
+                nextbp = bp->nextInSite();
+                if (scriptGone || IsObjectAboutToBeFinalized(&bp->debugger->toJSObjectRef()))
+                    bp->destroy(fop);
+            }
+        }
+    }
+}
+
+void
 Zone::discardJitCode(FreeOp *fop, bool discardConstraints)
 {
 #ifdef JS_ION
     if (isPreservingCode()) {
         PurgeJITCaches(this);
     } else {
 
 # ifdef DEBUG
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -306,16 +306,19 @@ struct Zone : private JS::shadow::Zone, 
 
     void onTooMuchMalloc();
 
     void markTypes(JSTracer *trc);
 
     js::types::TypeZone types;
 
     void sweep(js::FreeOp *fop, bool releaseTypes);
+
+  private:
+    void sweepBreakpoints(js::FreeOp *fop);
 };
 
 } /* namespace JS */
 
 namespace js {
 
 class ZonesIter {
   private:
--- a/js/src/ion/AsmJSModule.h
+++ b/js/src/ion/AsmJSModule.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
-#if !defined(jsion_asmjsmodule_h__)
+#if !defined(jsion_asmjsmodule_h__) && defined(JS_ION)
 #define jsion_asmjsmodule_h__
 
 #include "gc/Marking.h"
 #include "ion/RegisterSets.h"
 
 #include "jsscript.h"
 #include "jstypedarrayinlines.h"
 
--- a/js/src/ion/BaselineIC.cpp
+++ b/js/src/ion/BaselineIC.cpp
@@ -297,35 +297,35 @@ ICStub::trace(JSTracer *trc)
       }
       case ICStub::GetProp_NativePrototype: {
         ICGetProp_NativePrototype *propStub = toGetProp_NativePrototype();
         MarkShape(trc, &propStub->shape(), "baseline-getpropnativeproto-stub-shape");
         MarkObject(trc, &propStub->holder(), "baseline-getpropnativeproto-stub-holder");
         MarkShape(trc, &propStub->holderShape(), "baseline-getpropnativeproto-stub-holdershape");
         break;
       }
-      case ICStub::GetProp_CallListBaseNative:
-      case ICStub::GetProp_CallListBaseWithGenerationNative: {
-        ICGetPropCallListBaseNativeStub *propStub;
-        if (kind() ==  ICStub::GetProp_CallListBaseNative)
-            propStub = toGetProp_CallListBaseNative();
+      case ICStub::GetProp_CallDOMProxyNative:
+      case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
+        ICGetPropCallDOMProxyNativeStub *propStub;
+        if (kind() ==  ICStub::GetProp_CallDOMProxyNative)
+            propStub = toGetProp_CallDOMProxyNative();
         else
-            propStub = toGetProp_CallListBaseWithGenerationNative();
+            propStub = toGetProp_CallDOMProxyWithGenerationNative();
         MarkShape(trc, &propStub->shape(), "baseline-getproplistbasenative-stub-shape");
         if (propStub->expandoShape()) {
             MarkShape(trc, &propStub->expandoShape(),
                       "baseline-getproplistbasenative-stub-expandoshape");
         }
         MarkObject(trc, &propStub->holder(), "baseline-getproplistbasenative-stub-holder");
         MarkShape(trc, &propStub->holderShape(), "baseline-getproplistbasenative-stub-holdershape");
         MarkObject(trc, &propStub->getter(), "baseline-getproplistbasenative-stub-getter");
         break;
       }
-      case ICStub::GetProp_ListBaseShadowed: {
-        ICGetProp_ListBaseShadowed *propStub = toGetProp_ListBaseShadowed();
+      case ICStub::GetProp_DOMProxyShadowed: {
+        ICGetProp_DOMProxyShadowed *propStub = toGetProp_DOMProxyShadowed();
         MarkShape(trc, &propStub->shape(), "baseline-getproplistbaseshadowed-stub-shape");
         MarkString(trc, &propStub->name(), "baseline-getproplistbaseshadowed-stub-name");
         break;
       }
       case ICStub::GetProp_CallScripted: {
         ICGetProp_CallScripted *callStub = toGetProp_CallScripted();
         MarkShape(trc, &callStub->shape(), "baseline-getpropcallscripted-stub-shape");
         MarkObject(trc, &callStub->holder(), "baseline-getpropcallscripted-stub-holder");
@@ -613,20 +613,20 @@ ICStubCompiler::leaveStubFrame(MacroAsse
 }
 
 void
 ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip)
 {
     // This should only be called from the following stubs.
     JS_ASSERT(kind == ICStub::Call_Scripted      || kind == ICStub::Call_AnyScripted     ||
               kind == ICStub::Call_Native        || kind == ICStub::GetProp_CallScripted ||
-              kind == ICStub::GetProp_CallNative || kind == ICStub::GetProp_CallListBaseNative ||
+              kind == ICStub::GetProp_CallNative || kind == ICStub::GetProp_CallDOMProxyNative ||
               kind == ICStub::Call_ScriptedApplyArguments ||
-              kind == ICStub::GetProp_CallListBaseWithGenerationNative ||
-              kind == ICStub::GetProp_ListBaseShadowed ||
+              kind == ICStub::GetProp_CallDOMProxyWithGenerationNative ||
+              kind == ICStub::GetProp_DOMProxyShadowed ||
               kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative);
 
     // Guard on bit in frame that indicates if the SPS frame was pushed in the first
     // place.  This code is expected to be called from within a stub that has already
     // entered a stub frame.
     JS_ASSERT(entersStubFrame_);
     masm.loadPtr(Address(BaselineFrameReg, 0), scratch);
     masm.branchTest32(Assembler::Zero,
@@ -3053,227 +3053,227 @@ static void GetFixedOrDynamicSlotOffset(
     JS_ASSERT(isFixed);
     JS_ASSERT(offset);
     *isFixed = obj->isFixedSlot(slot);
     *offset = *isFixed ? JSObject::getFixedSlotOffset(slot)
                        : obj->dynamicSlotIndex(slot) * sizeof(Value);
 }
 
 static bool
-IsCacheableListBase(JSObject *obj)
+IsCacheableDOMProxy(JSObject *obj)
 {
     if (!obj->isProxy())
         return false;
 
     BaseProxyHandler *handler = GetProxyHandler(obj);
 
-    if (handler->family() != GetListBaseHandlerFamily())
+    if (handler->family() != GetDOMProxyHandlerFamily())
         return false;
 
-    if (obj->numFixedSlots() <= GetListBaseExpandoSlot())
+    if (obj->numFixedSlots() <= GetDOMProxyExpandoSlot())
         return false;
 
     return true;
 }
 
 static JSObject *
-GetListBaseProto(JSObject *obj)
-{
-    JS_ASSERT(IsCacheableListBase(obj));
+GetDOMProxyProto(JSObject *obj)
+{
+    JS_ASSERT(IsCacheableDOMProxy(obj));
     return obj->getTaggedProto().toObjectOrNull();
 }
 
 static void
-GenerateListBaseChecks(JSContext *cx, MacroAssembler &masm, Register object,
+GenerateDOMProxyChecks(JSContext *cx, MacroAssembler &masm, Register object,
                        Address checkProxyHandlerAddr,
                        Address *checkExpandoShapeAddr,
                        Address *expandoAndGenerationAddr,
                        Address *generationAddr,
                        Register scratch,
-                       GeneralRegisterSet &listBaseRegSet,
+                       GeneralRegisterSet &domProxyRegSet,
                        Label *checkFailed)
 {
     // Guard the following:
-    //      1. The object is a ListBase.
+    //      1. The object is a DOMProxy.
     //      2. The object does not have expando properties, or has an expando
     //          which is known to not have the desired property.
     Address handlerAddr(object, JSObject::getFixedSlotOffset(JSSLOT_PROXY_HANDLER));
-    Address expandoAddr(object, JSObject::getFixedSlotOffset(GetListBaseExpandoSlot()));
-
-    // Check that object is a ListBase.
+    Address expandoAddr(object, JSObject::getFixedSlotOffset(GetDOMProxyExpandoSlot()));
+
+    // Check that object is a DOMProxy.
     masm.loadPtr(checkProxyHandlerAddr, scratch);
     masm.branchPrivatePtr(Assembler::NotEqual, handlerAddr, scratch, checkFailed);
 
     // At this point, if not checking for an expando object, just return.
     if (!checkExpandoShapeAddr)
         return;
 
     // For the remaining code, we need to reserve some registers to load a value.
     // This is ugly, but unavoidable.
-    ValueOperand tempVal = listBaseRegSet.takeAnyValue();
+    ValueOperand tempVal = domProxyRegSet.takeAnyValue();
     masm.pushValue(tempVal);
 
-    Label failListBaseCheck;
-    Label listBaseOk;
+    Label failDOMProxyCheck;
+    Label domProxyOk;
 
     if (expandoAndGenerationAddr) {
         JS_ASSERT(generationAddr);
 
         masm.loadPtr(*expandoAndGenerationAddr, tempVal.scratchReg());
         masm.branchPrivatePtr(Assembler::NotEqual, expandoAddr, tempVal.scratchReg(),
-                              &failListBaseCheck);
+                              &failDOMProxyCheck);
 
         masm.load32(*generationAddr, scratch);
         masm.branch32(Assembler::NotEqual,
                       Address(tempVal.scratchReg(), offsetof(ExpandoAndGeneration, expando)),
-                      scratch, &failListBaseCheck);
+                      scratch, &failDOMProxyCheck);
 
         masm.loadValue(Address(tempVal.scratchReg(), 0), tempVal);
     } else {
         masm.loadValue(expandoAddr, tempVal);
     }
 
     // If the incoming object does not have an expando object then we're sure we're not
     // shadowing.
-    masm.branchTestUndefined(Assembler::Equal, tempVal, &listBaseOk);
+    masm.branchTestUndefined(Assembler::Equal, tempVal, &domProxyOk);
 
     // The reference object used to generate this check may not have had an
     // expando object at all, in which case the presence of a non-undefined
     // expando value in the incoming object is automatically a failure.
     masm.loadPtr(*checkExpandoShapeAddr, scratch);
-    masm.branchPtr(Assembler::Equal, scratch, ImmWord((void*)NULL), &failListBaseCheck);
+    masm.branchPtr(Assembler::Equal, scratch, ImmWord((void*)NULL), &failDOMProxyCheck);
 
     // Otherwise, ensure that the incoming object has an object for its expando value and that
     // the shape matches.
-    masm.branchTestObject(Assembler::NotEqual, tempVal, &failListBaseCheck);
+    masm.branchTestObject(Assembler::NotEqual, tempVal, &failDOMProxyCheck);
     Register objReg = masm.extractObject(tempVal, tempVal.scratchReg());
-    masm.branchTestObjShape(Assembler::Equal, objReg, scratch, &listBaseOk);
+    masm.branchTestObjShape(Assembler::Equal, objReg, scratch, &domProxyOk);
 
     // Failure case: restore the tempVal registers and jump to failures.
-    masm.bind(&failListBaseCheck);
+    masm.bind(&failDOMProxyCheck);
     masm.popValue(tempVal);
     masm.jump(checkFailed);
 
     // Success case: restore the tempval and proceed.
-    masm.bind(&listBaseOk);
+    masm.bind(&domProxyOk);
     masm.popValue(tempVal);
 }
 
 // Look up a property's shape on an object, being careful never to do any effectful
 // operations.  This procedure not yielding a shape should not be taken as a lack of
 // existence of the property on the object.
 static bool
 EffectlesslyLookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                            MutableHandleObject holder, MutableHandleShape shape,
-                           bool *checkListBase=NULL,
-                           ListBaseShadowsResult *shadowsResult=NULL,
-                           bool *listBaseHasGeneration=NULL)
+                           bool *checkDOMProxy=NULL,
+                           DOMProxyShadowsResult *shadowsResult=NULL,
+                           bool *domProxyHasGeneration=NULL)
 {
     shape.set(NULL);
     holder.set(NULL);
 
-    bool isListBase = false;
-    if (checkListBase)
-        *checkListBase = false;
+    bool isDOMProxy = false;
+    if (checkDOMProxy)
+        *checkDOMProxy = false;
 
     // Check for list base if asked to.
     RootedObject checkObj(cx, obj);
-    if (checkListBase && IsCacheableListBase(obj)) {
-        JS_ASSERT(listBaseHasGeneration);
+    if (checkDOMProxy && IsCacheableDOMProxy(obj)) {
+        JS_ASSERT(domProxyHasGeneration);
         JS_ASSERT(shadowsResult);
 
-        *checkListBase = isListBase = true;
+        *checkDOMProxy = isDOMProxy = true;
         if (obj->hasUncacheableProto())
             return true;
 
         RootedId id(cx, NameToId(name));
-        *shadowsResult = GetListBaseShadowsCheck()(cx, obj, id);
+        *shadowsResult = GetDOMProxyShadowsCheck()(cx, obj, id);
         if (*shadowsResult == ShadowCheckFailed)
             return false;
 
         if (*shadowsResult == Shadows) {
             holder.set(obj);
             return true;
         }
 
-        *listBaseHasGeneration = (*shadowsResult == DoesntShadowUnique);
-
-        checkObj = GetListBaseProto(obj);
-    }
-
-    if (!isListBase && !obj->isNative())
+        *domProxyHasGeneration = (*shadowsResult == DoesntShadowUnique);
+
+        checkObj = GetDOMProxyProto(obj);
+    }
+
+    if (!isDOMProxy && !obj->isNative())
         return true;
 
     if (checkObj->hasIdempotentProtoChain()) {
         if (!JSObject::lookupProperty(cx, checkObj, name, holder, shape))
             return false;
     } else if (checkObj->isNative()) {
         shape.set(checkObj->nativeLookup(cx, NameToId(name)));
         if (shape)
             holder.set(checkObj);
     }
     return true;
 }
 
 static bool
-IsCacheableProtoChain(JSObject *obj, JSObject *holder, bool isListBase=false)
-{
-    JS_ASSERT_IF(isListBase, IsCacheableListBase(obj));
-    JS_ASSERT_IF(!isListBase, obj->isNative());
+IsCacheableProtoChain(JSObject *obj, JSObject *holder, bool isDOMProxy=false)
+{
+    JS_ASSERT_IF(isDOMProxy, IsCacheableDOMProxy(obj));
+    JS_ASSERT_IF(!isDOMProxy, obj->isNative());
 
     // Don't handle objects which require a prototype guard. This should
     // be uncommon so handling it is likely not worth the complexity.
     if (obj->hasUncacheableProto())
         return false;
 
     JSObject *cur = obj;
     while (cur != holder) {
         // We cannot assume that we find the holder object on the prototype
         // chain and must check for null proto. The prototype chain can be
         // altered during the lookupProperty call.
         JSObject *proto;
-        if (isListBase && cur == obj)
+        if (isDOMProxy && cur == obj)
             proto = cur->getTaggedProto().toObjectOrNull();
         else
             proto = cur->getProto();
 
         if (!proto || !proto->isNative())
             return false;
 
         if (proto->hasUncacheableProto())
             return false;
 
         cur = proto;
     }
     return true;
 }
 
 static bool
-IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, Shape *shape, bool isListBase=false)
-{
-    if (!shape || !IsCacheableProtoChain(obj, holder, isListBase))
+IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, Shape *shape, bool isDOMProxy=false)
+{
+    if (!shape || !IsCacheableProtoChain(obj, holder, isDOMProxy))
         return false;
 
     if (!shape->hasSlot() || !shape->hasDefaultGetter())
         return false;
 
     return true;
 }
 
 static bool
 IsCacheableGetPropCall(JSObject *obj, JSObject *holder, Shape *shape, bool *isScripted,
-                       bool isListBase=false)
+                       bool isDOMProxy=false)
 {
     JS_ASSERT(isScripted);
 
     // Currently we only optimize getter calls for getters bound on prototypes.
     if (obj == holder)
         return false;
 
-    if (!shape || !IsCacheableProtoChain(obj, holder, isListBase))
+    if (!shape || !IsCacheableProtoChain(obj, holder, isDOMProxy))
         return false;
 
     if (shape->hasSlot() || shape->hasDefaultGetter())
         return false;
 
     if (!shape->hasGetterValue())
         return false;
 
@@ -5202,26 +5202,26 @@ TryAttachLengthStub(JSContext *cx, Handl
         stub->addNewStub(newStub);
         return true;
     }
 
     return true;
 }
 
 static bool
-UpdateExistingGenerationalListBaseStub(ICGetProp_Fallback *stub,
+UpdateExistingGenerationalDOMProxyStub(ICGetProp_Fallback *stub,
                                        HandleObject obj)
 {
-    Value expandoSlot = obj->getFixedSlot(GetListBaseExpandoSlot());
+    Value expandoSlot = obj->getFixedSlot(GetDOMProxyExpandoSlot());
     JS_ASSERT(!expandoSlot.isObject() && !expandoSlot.isUndefined());
     ExpandoAndGeneration *expandoAndGeneration = (ExpandoAndGeneration*)expandoSlot.toPrivate();
     for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
-        if (iter->isGetProp_CallListBaseWithGenerationNative()) {
-            ICGetProp_CallListBaseWithGenerationNative* updateStub =
-                iter->toGetProp_CallListBaseWithGenerationNative();
+        if (iter->isGetProp_CallDOMProxyWithGenerationNative()) {
+            ICGetProp_CallDOMProxyWithGenerationNative* updateStub =
+                iter->toGetProp_CallDOMProxyWithGenerationNative();
             if (updateStub->expandoAndGeneration() == expandoAndGeneration) {
                 // Update generation
                 uint32_t generation = expandoAndGeneration->generation;
                 IonSpew(IonSpew_BaselineIC,
                         "  Updating existing stub with generation, old value: %i, "
                         "new value: %i", updateStub->generation(),
                         generation);
                 updateStub->setGeneration(generation);
@@ -5239,57 +5239,57 @@ TryAttachNativeGetPropStub(JSContext *cx
 {
     JS_ASSERT(!*attached);
 
     if (!val.isObject())
         return true;
 
     RootedObject obj(cx, &val.toObject());
 
-    bool isListBase;
-    bool listBaseHasGeneration;
-    ListBaseShadowsResult listBaseShadowsResult;
+    bool isDOMProxy;
+    bool domProxyHasGeneration;
+    DOMProxyShadowsResult domProxyShadowsResult;
     RootedShape shape(cx);
     RootedObject holder(cx);
-    if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape, &isListBase,
-                                    &listBaseShadowsResult, &listBaseHasGeneration))
+    if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape, &isDOMProxy,
+                                    &domProxyShadowsResult, &domProxyHasGeneration))
     {
         return false;
     }
 
-    if (!isListBase && !obj->isNative())
+    if (!isDOMProxy && !obj->isNative())
         return true;
 
     ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
-    if (!isListBase && IsCacheableGetPropReadSlot(obj, holder, shape)) {
+    if (!isDOMProxy && IsCacheableGetPropReadSlot(obj, holder, shape)) {
         bool isFixedSlot;
         uint32_t offset;
         GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
 
         ICStub::Kind kind = (obj == holder) ? ICStub::GetProp_Native
                                             : ICStub::GetProp_NativePrototype;
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(%s %s) stub",
-                    isListBase ? "ListBase" : "Native",
+                    isDOMProxy ? "DOMProxy" : "Native",
                     (obj == holder) ? "direct" : "prototype");
         ICGetPropNativeCompiler compiler(cx, kind, monitorStub, obj, holder, isFixedSlot, offset);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     bool isScripted = false;
-    bool cacheableCall = IsCacheableGetPropCall(obj, holder, shape, &isScripted, isListBase);
+    bool cacheableCall = IsCacheableGetPropCall(obj, holder, shape, &isScripted, isDOMProxy);
 
     // Try handling scripted getters.
-    if (cacheableCall && isScripted && !isListBase) {
+    if (cacheableCall && isScripted && !isDOMProxy) {
         RootedFunction callee(cx, shape->getterObject()->toFunction());
         JS_ASSERT(obj != holder);
         JS_ASSERT(callee->hasScript());
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(NativeObj/ScriptedGetter %s:%d) stub",
                     callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno);
 
         ICGetProp_CallScripted::Compiler compiler(cx, monitorStub, obj, holder, callee,
@@ -5305,53 +5305,53 @@ TryAttachNativeGetPropStub(JSContext *cx
 
     // Try handling JSNative getters.
     if (cacheableCall && !isScripted) {
         RootedFunction callee(cx, shape->getterObject()->toFunction());
         JS_ASSERT(obj != holder);
         JS_ASSERT(callee->isNative());
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(%s%s/NativeGetter %p) stub",
-                isListBase ? "ListBaseObj" : "NativeObj",
-                isListBase && listBaseHasGeneration ? "WithGeneration" : "",
+                isDOMProxy ? "DOMProxyObj" : "NativeObj",
+                isDOMProxy && domProxyHasGeneration ? "WithGeneration" : "",
                 callee->native());
 
         ICStub *newStub = NULL;
-        if (isListBase) {
+        if (isDOMProxy) {
             ICStub::Kind kind;
-            if (listBaseHasGeneration) {
-                if (UpdateExistingGenerationalListBaseStub(stub, obj)) {
+            if (domProxyHasGeneration) {
+                if (UpdateExistingGenerationalDOMProxyStub(stub, obj)) {
                     *attached = true;
                     return true;
                 }
-                kind = ICStub::GetProp_CallListBaseWithGenerationNative;
+                kind = ICStub::GetProp_CallDOMProxyWithGenerationNative;
             } else {
-                kind = ICStub::GetProp_CallListBaseNative;
+                kind = ICStub::GetProp_CallDOMProxyNative;
             }
-            ICGetPropCallListBaseNativeCompiler compiler(cx, kind, monitorStub, obj, holder, callee,
+            ICGetPropCallDOMProxyNativeCompiler compiler(cx, kind, monitorStub, obj, holder, callee,
                                                             pc - script->code);
             newStub = compiler.getStub(compiler.getStubSpace(script));
         } else {
             ICGetProp_CallNative::Compiler compiler(cx, monitorStub, obj, holder, callee,
                                                     pc - script->code);
             newStub = compiler.getStub(compiler.getStubSpace(script));
         }
         if (!newStub)
             return false;
         stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     // If it's a shadowed listbase proxy property, attach stub to call Proxy::get instead.
-    if (isListBase && listBaseShadowsResult == Shadows) {
+    if (isDOMProxy && domProxyShadowsResult == Shadows) {
         JS_ASSERT(obj == holder);
 
-        IonSpew(IonSpew_BaselineIC, "  Generating GetProp(ListBaseProxy) stub");
-        ICGetProp_ListBaseShadowed::Compiler compiler(cx, monitorStub, obj, name,
+        IonSpew(IonSpew_BaselineIC, "  Generating GetProp(DOMProxyProxy) stub");
+        ICGetProp_DOMProxyShadowed::Compiler compiler(cx, monitorStub, obj, name,
                                                       pc - script->code);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
         stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
@@ -5844,64 +5844,64 @@ ICGetProp_CallNative::Compiler::generate
 
     // Failure case - jump to next stub
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
 bool
-ICGetPropCallListBaseNativeCompiler::generateStubCode(MacroAssembler &masm,
+ICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler &masm,
                                                       Address* expandoAndGenerationAddr,
                                                       Address* generationAddr)
 {
     Label failure;
     GeneralRegisterSet regs(availableGeneralRegs(1));
     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
 
     // Guard input is an object.
     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
 
     // Unbox.
     Register objReg = masm.extractObject(R0, ExtractTemp0);
 
     // Shape guard.
-    masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallListBaseNative::offsetOfShape()), scratch);
+    masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfShape()), scratch);
     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
 
     // Guard for ListObject.
     {
-        GeneralRegisterSet listBaseRegSet(GeneralRegisterSet::All());
-        listBaseRegSet.take(BaselineStubReg);
-        listBaseRegSet.take(objReg);
-        listBaseRegSet.take(scratch);
-        Address expandoShapeAddr(BaselineStubReg, ICGetProp_CallListBaseNative::offsetOfExpandoShape());
-        GenerateListBaseChecks(
+        GeneralRegisterSet domProxyRegSet(GeneralRegisterSet::All());
+        domProxyRegSet.take(BaselineStubReg);
+        domProxyRegSet.take(objReg);
+        domProxyRegSet.take(scratch);
+        Address expandoShapeAddr(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfExpandoShape());
+        GenerateDOMProxyChecks(
                 cx, masm, objReg,
-                Address(BaselineStubReg, ICGetProp_CallListBaseNative::offsetOfProxyHandler()),
+                Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfProxyHandler()),
                 &expandoShapeAddr, expandoAndGenerationAddr, generationAddr,
                 scratch,
-                listBaseRegSet,
+                domProxyRegSet,
                 &failure);
     }
 
     Register holderReg = regs.takeAny();
-    masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallListBaseNative::offsetOfHolder()),
+    masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfHolder()),
                  holderReg);
-    masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallListBaseNative::offsetOfHolderShape()),
+    masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfHolderShape()),
                  scratch);
     masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure);
     regs.add(holderReg);
 
     // Push a stub frame so that we can perform a non-tail call.
     enterStubFrame(masm, scratch);
 
     // Load callee function.
     Register callee = regs.takeAny();
-    masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallListBaseNative::offsetOfGetter()), callee);
+    masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfGetter()), callee);
 
     // Push args for vm call.
     masm.push(objReg);
     masm.push(callee);
 
     // Don't have to preserve R0 anymore.
     regs.add(R0);
 
@@ -5910,17 +5910,17 @@ ICGetPropCallListBaseNativeCompiler::gen
         Label skipProfilerUpdate;
         Register scratch = regs.takeAny();
         Register pcIdx = regs.takeAny();
 
         // Check if profiling is enabled.
         guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
 
         // Update profiling entry before leaving function.
-        masm.load32(Address(BaselineStubReg, ICGetProp_CallListBaseNative::offsetOfPCOffset()),
+        masm.load32(Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfPCOffset()),
                     pcIdx);
         masm.spsUpdatePCIdx(&cx->runtime->spsProfiler, pcIdx, scratch);
 
         masm.bind(&skipProfilerUpdate);
         regs.add(scratch);
         regs.add(pcIdx);
     }
     if (!callVM(DoCallNativeGetterInfo, masm))
@@ -5932,143 +5932,143 @@ ICGetPropCallListBaseNativeCompiler::gen
 
     // Failure case - jump to next stub
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
 bool
-ICGetPropCallListBaseNativeCompiler::generateStubCode(MacroAssembler &masm)
-{
-    if (kind == ICStub::GetProp_CallListBaseNative)
+ICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler &masm)
+{
+    if (kind == ICStub::GetProp_CallDOMProxyNative)
         return generateStubCode(masm, NULL, NULL);
 
     Address internalStructAddress(BaselineStubReg,
-        ICGetProp_CallListBaseWithGenerationNative::offsetOfInternalStruct());
+        ICGetProp_CallDOMProxyWithGenerationNative::offsetOfInternalStruct());
     Address generationAddress(BaselineStubReg,
-        ICGetProp_CallListBaseWithGenerationNative::offsetOfGeneration());
+        ICGetProp_CallDOMProxyWithGenerationNative::offsetOfGeneration());
     return generateStubCode(masm, &internalStructAddress, &generationAddress);
 }
 
 ICStub *
-ICGetPropCallListBaseNativeCompiler::getStub(ICStubSpace *space)
+ICGetPropCallDOMProxyNativeCompiler::getStub(ICStubSpace *space)
 {
     RootedShape shape(cx, obj_->lastProperty());
     RootedShape holderShape(cx, holder_->lastProperty());
 
-    Value expandoSlot = obj_->getFixedSlot(GetListBaseExpandoSlot());
+    Value expandoSlot = obj_->getFixedSlot(GetDOMProxyExpandoSlot());
     RootedShape expandoShape(cx, NULL);
     ExpandoAndGeneration *expandoAndGeneration;
     int32_t generation;
     Value expandoVal;
-    if (kind == ICStub::GetProp_CallListBaseNative) {
+    if (kind == ICStub::GetProp_CallDOMProxyNative) {
         expandoVal = expandoSlot;
     } else {
-        JS_ASSERT(kind == ICStub::GetProp_CallListBaseWithGenerationNative);
+        JS_ASSERT(kind == ICStub::GetProp_CallDOMProxyWithGenerationNative);
         JS_ASSERT(!expandoSlot.isObject() && !expandoSlot.isUndefined());
         expandoAndGeneration = (ExpandoAndGeneration*)expandoSlot.toPrivate();
         expandoVal = expandoAndGeneration->expando;
         generation = expandoAndGeneration->generation;
     }
 
     if (expandoVal.isObject())
         expandoShape = expandoVal.toObject().lastProperty();
 
-    if (kind == ICStub::GetProp_CallListBaseNative) {
-        return ICGetProp_CallListBaseNative::New(
+    if (kind == ICStub::GetProp_CallDOMProxyNative) {
+        return ICGetProp_CallDOMProxyNative::New(
             space, getStubCode(), firstMonitorStub_, shape, GetProxyHandler(obj_),
             expandoShape, holder_, holderShape, getter_, pcOffset_);
     }
 
-    return ICGetProp_CallListBaseWithGenerationNative::New(
+    return ICGetProp_CallDOMProxyWithGenerationNative::New(
         space, getStubCode(), firstMonitorStub_, shape, GetProxyHandler(obj_),
         expandoAndGeneration, generation, expandoShape, holder_, holderShape, getter_,
         pcOffset_);
 }
 
 ICStub *
-ICGetProp_ListBaseShadowed::Compiler::getStub(ICStubSpace *space)
+ICGetProp_DOMProxyShadowed::Compiler::getStub(ICStubSpace *space)
 {
     RootedShape shape(cx, obj_->lastProperty());
-    return ICGetProp_ListBaseShadowed::New(space, getStubCode(), firstMonitorStub_,
+    return ICGetProp_DOMProxyShadowed::New(space, getStubCode(), firstMonitorStub_,
                                            shape, GetProxyHandler(obj_), name_, pcOffset_);
 }
 
 static bool
 ProxyGet(JSContext *cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp)
 {
     RootedId id(cx, NameToId(name));
     return Proxy::get(cx, proxy, proxy, id, vp);
 }
 
 typedef bool (*ProxyGetFn)(JSContext *cx, HandleObject proxy, HandlePropertyName name,
                            MutableHandleValue vp);
 static const VMFunction ProxyGetInfo = FunctionInfo<ProxyGetFn>(ProxyGet);
 
 bool
-ICGetProp_ListBaseShadowed::Compiler::generateStubCode(MacroAssembler &masm)
+ICGetProp_DOMProxyShadowed::Compiler::generateStubCode(MacroAssembler &masm)
 {
     Label failure;
 
     GeneralRegisterSet regs(availableGeneralRegs(1));
     // Need to reserve a scratch register, but the scratch register should not be
     // BaselineTailCallReg, because it's used for |enterStubFrame| which needs a
     // non-BaselineTailCallReg scratch reg.
     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
 
     // Guard input is an object.
     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
 
     // Unbox.
     Register objReg = masm.extractObject(R0, ExtractTemp0);
 
     // Shape guard.
-    masm.loadPtr(Address(BaselineStubReg, ICGetProp_ListBaseShadowed::offsetOfShape()), scratch);
+    masm.loadPtr(Address(BaselineStubReg, ICGetProp_DOMProxyShadowed::offsetOfShape()), scratch);
     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
 
     // Guard for ListObject.
     {
-        GeneralRegisterSet listBaseRegSet(GeneralRegisterSet::All());
-        listBaseRegSet.take(BaselineStubReg);
-        listBaseRegSet.take(objReg);
-        listBaseRegSet.take(scratch);
-        GenerateListBaseChecks(
+        GeneralRegisterSet domProxyRegSet(GeneralRegisterSet::All());
+        domProxyRegSet.take(BaselineStubReg);
+        domProxyRegSet.take(objReg);
+        domProxyRegSet.take(scratch);
+        GenerateDOMProxyChecks(
                 cx, masm, objReg,
-                Address(BaselineStubReg, ICGetProp_ListBaseShadowed::offsetOfProxyHandler()),
+                Address(BaselineStubReg, ICGetProp_DOMProxyShadowed::offsetOfProxyHandler()),
                 /*expandoShapeAddr=*/NULL, /*expandoAndGenerationAddr=*/NULL, /*generationAddr=*/NULL,
                 scratch,
-                listBaseRegSet,
+                domProxyRegSet,
                 &failure);
     }
 
     // Call ProxyGet(JSContext *cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp);
 
     // Push a stub frame so that we can perform a non-tail call.
     enterStubFrame(masm, scratch);
 
     // Push property name and proxy object.
-    masm.loadPtr(Address(BaselineStubReg, ICGetProp_ListBaseShadowed::offsetOfName()), scratch);
+    masm.loadPtr(Address(BaselineStubReg, ICGetProp_DOMProxyShadowed::offsetOfName()), scratch);
     masm.push(scratch);
     masm.push(objReg);
 
     // Don't have to preserve R0 anymore.
     regs.add(R0);
 
     // If needed, update SPS Profiler frame entry.
     {
         Label skipProfilerUpdate;
         Register scratch = regs.takeAny();
         Register pcIdx = regs.takeAny();
 
         // Check if profiling is enabled.
         guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
 
         // Update profiling entry before leaving function.
-        masm.load32(Address(BaselineStubReg, ICGetProp_ListBaseShadowed::offsetOfPCOffset()), pcIdx);
+        masm.load32(Address(BaselineStubReg, ICGetProp_DOMProxyShadowed::offsetOfPCOffset()), pcIdx);
         masm.spsUpdatePCIdx(&cx->runtime->spsProfiler, pcIdx, scratch);
 
         masm.bind(&skipProfilerUpdate);
         regs.add(scratch);
         regs.add(pcIdx);
     }
     if (!callVM(ProxyGetInfo, masm))
         return false;
@@ -8423,17 +8423,17 @@ ICCall_Scripted::ICCall_Scripted(IonCode
 
 ICCall_Native::ICCall_Native(IonCode *stubCode, ICStub *firstMonitorStub, HandleFunction callee,
                              uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Native, stubCode, firstMonitorStub),
     callee_(callee),
     pcOffset_(pcOffset)
 { }
 
-ICGetPropCallListBaseNativeStub::ICGetPropCallListBaseNativeStub(Kind kind, IonCode *stubCode,
+ICGetPropCallDOMProxyNativeStub::ICGetPropCallDOMProxyNativeStub(Kind kind, IonCode *stubCode,
                                                                  ICStub *firstMonitorStub,
                                                                  HandleShape shape,
                                                                  BaseProxyHandler *proxyHandler,
                                                                  HandleShape expandoShape,
                                                                  HandleObject holder,
                                                                  HandleShape holderShape,
                                                                  HandleFunction getter,
                                                                  uint32_t pcOffset)
@@ -8442,43 +8442,43 @@ ICGetPropCallListBaseNativeStub::ICGetPr
     proxyHandler_(proxyHandler),
     expandoShape_(expandoShape),
     holder_(holder),
     holderShape_(holderShape),
     getter_(getter),
     pcOffset_(pcOffset)
 { }
 
-ICGetPropCallListBaseNativeCompiler::ICGetPropCallListBaseNativeCompiler(JSContext *cx,
+ICGetPropCallDOMProxyNativeCompiler::ICGetPropCallDOMProxyNativeCompiler(JSContext *cx,
                                                                          ICStub::Kind kind,
                                                                          ICStub *firstMonitorStub,
                                                                          HandleObject obj,
                                                                          HandleObject holder,
                                                                          HandleFunction getter,
                                                                          uint32_t pcOffset)
   : ICStubCompiler(cx, kind),
     firstMonitorStub_(firstMonitorStub),
     obj_(cx, obj),
     holder_(cx, holder),
     getter_(cx, getter),
     pcOffset_(pcOffset)
 {
-    JS_ASSERT(kind == ICStub::GetProp_CallListBaseNative ||
-              kind == ICStub::GetProp_CallListBaseWithGenerationNative);
+    JS_ASSERT(kind == ICStub::GetProp_CallDOMProxyNative ||
+              kind == ICStub::GetProp_CallDOMProxyWithGenerationNative);
     JS_ASSERT(obj_->isProxy());
-    JS_ASSERT(GetProxyHandler(obj_)->family() == GetListBaseHandlerFamily());
-}
-
-ICGetProp_ListBaseShadowed::ICGetProp_ListBaseShadowed(IonCode *stubCode,
+    JS_ASSERT(GetProxyHandler(obj_)->family() == GetDOMProxyHandlerFamily());
+}
+
+ICGetProp_DOMProxyShadowed::ICGetProp_DOMProxyShadowed(IonCode *stubCode,
                                                        ICStub *firstMonitorStub,
                                                        HandleShape shape,
                                                        BaseProxyHandler *proxyHandler,
                                                        HandlePropertyName name,
                                                        uint32_t pcOffset)
-  : ICMonitoredStub(ICStub::GetProp_ListBaseShadowed, stubCode, firstMonitorStub),
+  : ICMonitoredStub(ICStub::GetProp_DOMProxyShadowed, stubCode, firstMonitorStub),
     shape_(shape),
     proxyHandler_(proxyHandler),
     name_(name),
     pcOffset_(pcOffset)
 { }
 
 } // namespace ion
 } // namespace js
--- a/js/src/ion/BaselineIC.h
+++ b/js/src/ion/BaselineIC.h
@@ -360,19 +360,19 @@ class ICEntry
     _(GetProp_ArrayLength)      \
     _(GetProp_TypedArrayLength) \
     _(GetProp_String)           \
     _(GetProp_StringLength)     \
     _(GetProp_Native)           \
     _(GetProp_NativePrototype)  \
     _(GetProp_CallScripted)     \
     _(GetProp_CallNative)       \
-    _(GetProp_CallListBaseNative)\
-    _(GetProp_CallListBaseWithGenerationNative)\
-    _(GetProp_ListBaseShadowed) \
+    _(GetProp_CallDOMProxyNative)\
+    _(GetProp_CallDOMProxyWithGenerationNative)\
+    _(GetProp_DOMProxyShadowed) \
     _(GetProp_ArgumentsLength)  \
                                 \
     _(SetProp_Fallback)         \
     _(SetProp_Native)           \
     _(SetProp_NativeAdd)        \
     _(SetProp_CallScripted)     \
     _(SetProp_CallNative)       \
                                 \
@@ -728,19 +728,19 @@ class ICStub
           case Call_Fallback:
           case Call_Scripted:
           case Call_AnyScripted:
           case Call_Native:
           case Call_ScriptedApplyArguments:
           case UseCount_Fallback:
           case GetProp_CallScripted:
           case GetProp_CallNative:
-          case GetProp_CallListBaseNative:
-          case GetProp_CallListBaseWithGenerationNative:
-          case GetProp_ListBaseShadowed:
+          case GetProp_CallDOMProxyNative:
+          case GetProp_CallDOMProxyWithGenerationNative:
+          case GetProp_DOMProxyShadowed:
           case SetProp_CallScripted:
           case SetProp_CallNative:
             return true;
           default:
             return false;
         }
     }
 
@@ -4187,21 +4187,21 @@ class ICGetProp_CallNative : public ICGe
             RootedShape shape(cx, obj_->lastProperty());
             RootedShape holderShape(cx, holder_->lastProperty());
             return ICGetProp_CallNative::New(space, getStubCode(), firstMonitorStub_, shape,
                                                holder_, holderShape, getter_, pcOffset_);
         }
     };
 };
 
-class ICGetPropCallListBaseNativeStub : public ICMonitoredStub
+class ICGetPropCallDOMProxyNativeStub : public ICMonitoredStub
 {
   friend class ICStubSpace;
   protected:
-    // Shape of the ListBase proxy
+    // Shape of the DOMProxy
     HeapPtrShape shape_;
 
     // Proxy handler to check against.
     BaseProxyHandler *proxyHandler_;
 
     // Object shape of expected expando object. (NULL if no expando object should be there)
     HeapPtrShape expandoShape_;
 
@@ -4210,17 +4210,17 @@ class ICGetPropCallListBaseNativeStub : 
     HeapPtrShape holderShape_;
 
     // Function to call.
     HeapPtrFunction getter_;
 
     // PC offset of call
     uint32_t pcOffset_;
 
-    ICGetPropCallListBaseNativeStub(ICStub::Kind kind, IonCode *stubCode,
+    ICGetPropCallDOMProxyNativeStub(ICStub::Kind kind, IonCode *stubCode,
                                     ICStub *firstMonitorStub, HandleShape shape,
                                     BaseProxyHandler *proxyHandler, HandleShape expandoShape,
                                     HandleObject holder, HandleShape holderShape,
                                     HandleFunction getter, uint32_t pcOffset);
 
   public:
     HeapPtrShape &shape() {
         return shape_;
@@ -4237,96 +4237,96 @@ class ICGetPropCallListBaseNativeStub : 
     HeapPtrFunction &getter() {
         return getter_;
     }
     uint32_t pcOffset() const {
         return pcOffset_;
     }
 
     static size_t offsetOfShape() {
-        return offsetof(ICGetPropCallListBaseNativeStub, shape_);
+        return offsetof(ICGetPropCallDOMProxyNativeStub, shape_);
     }
     static size_t offsetOfProxyHandler() {
-        return offsetof(ICGetPropCallListBaseNativeStub, proxyHandler_);
+        return offsetof(ICGetPropCallDOMProxyNativeStub, proxyHandler_);
     }
     static size_t offsetOfExpandoShape() {
-        return offsetof(ICGetPropCallListBaseNativeStub, expandoShape_);
+        return offsetof(ICGetPropCallDOMProxyNativeStub, expandoShape_);
     }
     static size_t offsetOfHolder() {
-        return offsetof(ICGetPropCallListBaseNativeStub, holder_);
+        return offsetof(ICGetPropCallDOMProxyNativeStub, holder_);
     }
     static size_t offsetOfHolderShape() {
-        return offsetof(ICGetPropCallListBaseNativeStub, holderShape_);
+        return offsetof(ICGetPropCallDOMProxyNativeStub, holderShape_);
     }
     static size_t offsetOfGetter() {
-        return offsetof(ICGetPropCallListBaseNativeStub, getter_);
+        return offsetof(ICGetPropCallDOMProxyNativeStub, getter_);
     }
     static size_t offsetOfPCOffset() {
-        return offsetof(ICGetPropCallListBaseNativeStub, pcOffset_);
+        return offsetof(ICGetPropCallDOMProxyNativeStub, pcOffset_);
     }
 };
 
-class ICGetProp_CallListBaseNative : public ICGetPropCallListBaseNativeStub
+class ICGetProp_CallDOMProxyNative : public ICGetPropCallDOMProxyNativeStub
 {
     friend class ICStubSpace;
-    ICGetProp_CallListBaseNative(IonCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
+    ICGetProp_CallDOMProxyNative(IonCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
                                  BaseProxyHandler *proxyHandler, HandleShape expandoShape,
                                  HandleObject holder, HandleShape holderShape,
                                  HandleFunction getter, uint32_t pcOffset)
-      : ICGetPropCallListBaseNativeStub(ICStub::GetProp_CallListBaseNative, stubCode,
+      : ICGetPropCallDOMProxyNativeStub(ICStub::GetProp_CallDOMProxyNative, stubCode,
                                         firstMonitorStub, shape, proxyHandler, expandoShape,
                                         holder, holderShape, getter, pcOffset)
     {}
 
   public:
-    static inline ICGetProp_CallListBaseNative *New(
+    static inline ICGetProp_CallDOMProxyNative *New(
             ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
             HandleShape shape, BaseProxyHandler *proxyHandler,
             HandleShape expandoShape, HandleObject holder, HandleShape holderShape,
             HandleFunction getter, uint32_t pcOffset)
     {
         if (!code)
             return NULL;
-        return space->allocate<ICGetProp_CallListBaseNative>(code, firstMonitorStub, shape,
+        return space->allocate<ICGetProp_CallDOMProxyNative>(code, firstMonitorStub, shape,
                                                    proxyHandler, expandoShape, holder,
                                                    holderShape, getter, pcOffset);
     }
 };
 
-class ICGetProp_CallListBaseWithGenerationNative : public ICGetPropCallListBaseNativeStub
+class ICGetProp_CallDOMProxyWithGenerationNative : public ICGetPropCallDOMProxyNativeStub
 {
   protected:
     ExpandoAndGeneration *expandoAndGeneration_;
     uint32_t generation_;
 
   public:
-    ICGetProp_CallListBaseWithGenerationNative(IonCode *stubCode, ICStub *firstMonitorStub,
+    ICGetProp_CallDOMProxyWithGenerationNative(IonCode *stubCode, ICStub *firstMonitorStub,
                                                HandleShape shape, BaseProxyHandler *proxyHandler,
                                                ExpandoAndGeneration *expandoAndGeneration,
                                                uint32_t generation, HandleShape expandoShape,
                                                HandleObject holder, HandleShape holderShape,
                                                HandleFunction getter, uint32_t pcOffset)
-      : ICGetPropCallListBaseNativeStub(ICStub::GetProp_CallListBaseWithGenerationNative,
+      : ICGetPropCallDOMProxyNativeStub(ICStub::GetProp_CallDOMProxyWithGenerationNative,
                                         stubCode, firstMonitorStub, shape, proxyHandler,
                                         expandoShape, holder, holderShape, getter, pcOffset),
         expandoAndGeneration_(expandoAndGeneration),
         generation_(generation)
     {
     }
 
-    static inline ICGetProp_CallListBaseWithGenerationNative *New(
+    static inline ICGetProp_CallDOMProxyWithGenerationNative *New(
             ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
             HandleShape shape, BaseProxyHandler *proxyHandler,
             ExpandoAndGeneration *expandoAndGeneration, uint32_t generation,
             HandleShape expandoShape, HandleObject holder, HandleShape holderShape,
             HandleFunction getter, uint32_t pcOffset)
     {
         if (!code)
             return NULL;
-        return space->allocate<ICGetProp_CallListBaseWithGenerationNative>(code, firstMonitorStub,
+        return space->allocate<ICGetProp_CallDOMProxyWithGenerationNative>(code, firstMonitorStub,
                                                    shape, proxyHandler, expandoAndGeneration,
                                                    generation, expandoShape, holder, holderShape,
                                                    getter, pcOffset);
     }
 
     void *expandoAndGeneration() const {
         return expandoAndGeneration_;
     }
@@ -4334,86 +4334,86 @@ class ICGetProp_CallListBaseWithGenerati
         return generation_;
     }
 
     void setGeneration(uint32_t value) {
         generation_ = value;
     }
 
     static size_t offsetOfInternalStruct() {
-        return offsetof(ICGetProp_CallListBaseWithGenerationNative, expandoAndGeneration_);
+        return offsetof(ICGetProp_CallDOMProxyWithGenerationNative, expandoAndGeneration_);
     }
     static size_t offsetOfGeneration() {
-        return offsetof(ICGetProp_CallListBaseWithGenerationNative, generation_);
+        return offsetof(ICGetProp_CallDOMProxyWithGenerationNative, generation_);
     }
 };
 
-class ICGetPropCallListBaseNativeCompiler : public ICStubCompiler {
+class ICGetPropCallDOMProxyNativeCompiler : public ICStubCompiler {
     ICStub *firstMonitorStub_;
     RootedObject obj_;
     RootedObject holder_;
     RootedFunction getter_;
     uint32_t pcOffset_;
 
     bool generateStubCode(MacroAssembler &masm, Address* internalStructAddr,
                           Address* generationAddr);
     bool generateStubCode(MacroAssembler &masm);
 
   public:
-    ICGetPropCallListBaseNativeCompiler(JSContext *cx, ICStub::Kind kind,
+    ICGetPropCallDOMProxyNativeCompiler(JSContext *cx, ICStub::Kind kind,
                                         ICStub *firstMonitorStub, HandleObject obj,
                                         HandleObject holder, HandleFunction getter,
                                         uint32_t pcOffset);
 
     ICStub *getStub(ICStubSpace *space);
 };
 
-class ICGetProp_ListBaseShadowed : public ICMonitoredStub
+class ICGetProp_DOMProxyShadowed : public ICMonitoredStub
 {
   friend class ICStubSpace;
   protected:
     HeapPtrShape shape_;
     BaseProxyHandler *proxyHandler_;
     HeapPtrPropertyName name_;
     uint32_t pcOffset_;
 
-    ICGetProp_ListBaseShadowed(IonCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
+    ICGetProp_DOMProxyShadowed(IonCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
                                BaseProxyHandler *proxyHandler, HandlePropertyName name,
                                uint32_t pcOffset);
 
   public:
-    static inline ICGetProp_ListBaseShadowed *New(ICStubSpace *space, IonCode *code,
+    static inline ICGetProp_DOMProxyShadowed *New(ICStubSpace *space, IonCode *code,
                                                   ICStub *firstMonitorStub, HandleShape shape,
                                                   BaseProxyHandler *proxyHandler,
                                                   HandlePropertyName name, uint32_t pcOffset)
     {
         if (!code)
             return NULL;
-        return space->allocate<ICGetProp_ListBaseShadowed>(code, firstMonitorStub, shape,
+        return space->allocate<ICGetProp_DOMProxyShadowed>(code, firstMonitorStub, shape,
                                                            proxyHandler, name, pcOffset);
     }
 
     HeapPtrShape &shape() {
         return shape_;
     }
     HeapPtrPropertyName &name() {
         return name_;
     }
 
     static size_t offsetOfShape() {
-        return offsetof(ICGetProp_ListBaseShadowed, shape_);
+        return offsetof(ICGetProp_DOMProxyShadowed, shape_);
     }
     static size_t offsetOfProxyHandler() {
-        return offsetof(ICGetProp_ListBaseShadowed, proxyHandler_);
+        return offsetof(ICGetProp_DOMProxyShadowed, proxyHandler_);
     }
     static size_t offsetOfName() {
-        return offsetof(ICGetProp_ListBaseShadowed, name_);
+        return offsetof(ICGetProp_DOMProxyShadowed, name_);
     }
     static size_t offsetOfPCOffset() {
-        return offsetof(ICGetProp_ListBaseShadowed, pcOffset_);
+        return offsetof(ICGetProp_DOMProxyShadowed, pcOffset_);
     }
 
     class Compiler : public ICStubCompiler {
         ICStub *firstMonitorStub_;
         RootedObject obj_;
         RootedPropertyName name_;
         uint32_t pcOffset_;
 
--- a/js/src/ion/ExecutionModeInlines.h
+++ b/js/src/ion/ExecutionModeInlines.h
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jsion_compilemode_h__
-#define jsion_compilemode_h__
+#if !defined(jsion_executionmodeinlines_h__) && defined(JS_ION)
+#define jsion_executionmodeinlines_h__
 
 namespace js {
 namespace ion {
 
 static inline bool
 HasIonScript(JSScript *script, ExecutionMode cmode)
 {
     switch (cmode) {
@@ -100,9 +100,9 @@ CompilerOutputKind(ExecutionMode cmode)
     }
     JS_NOT_REACHED("No such execution mode");
     return types::CompilerOutput::Ion;
 }
 
 }
 }
 
-#endif
+#endif  // jsion_executionmodeinlines_h__
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -1,26 +1,27 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
+#include "ion/IonBuilder.h"
+
 #include "mozilla/DebugOnly.h"
 
-#include "IonAnalysis.h"
-#include "IonBuilder.h"
-#include "Lowering.h"
-#include "MIRGraph.h"
-#include "Ion.h"
-#include "IonAnalysis.h"
-#include "IonSpewer.h"
-#include "BaselineInspector.h"
 #include "builtin/Eval.h"
-#include "frontend/BytecodeEmitter.h"
+#include "frontend/SourceNotes.h"
+#include "ion/BaselineInspector.h"
+#include "ion/Ion.h"
+#include "ion/IonAnalysis.h"
+#include "ion/IonAnalysis.h"
+#include "ion/IonSpewer.h"
+#include "ion/Lowering.h"
+#include "ion/MIRGraph.h"
 
 #include "CompileInfo-inl.h"
 #include "ExecutionModeInlines.h"
 #include "jsanalyzeinlines.h"
 #include "jsscriptinlines.h"
 #include "jstypedarrayinlines.h"
 
 #ifdef JS_THREADSAFE
@@ -4128,17 +4129,17 @@ IonBuilder::inlineCalls(CallInfo &callIn
             return false;
 
         // Natives may veto inlining.
         if (status == InliningStatus_NotInlined) {
             JS_ASSERT(target->isNative());
             JS_ASSERT(current == inlineBlock);
             // Undo operations
             inlineInfo.unwrapArgs();
-            inlineBlock->entryResumePoint()->replaceOperand(funIndex, callInfo.fun());
+            inlineBlock->entryResumePoint()->discardOperand(funIndex);
             inlineBlock->rewriteSlot(funIndex, callInfo.fun());
             inlineBlock->discard(funcDef);
             graph().removeBlock(inlineBlock);
             choiceSet[i] = false;
             continue;
         }
 
         // inlineSingleCall() changed |current| to the inline return block.
@@ -5249,44 +5250,46 @@ IonBuilder::jsop_initelem_array()
 
     if (!resumeAfter(initLength))
         return false;
 
    return true;
 }
 
 static bool
-CanEffectlesslyCallLookupGenericOnObject(JSObject *obj)
+CanEffectlesslyCallLookupGenericOnObject(JSContext *cx, JSObject *obj, jsid id)
 {
     while (obj) {
         if (!obj->isNative())
             return false;
-        if (obj->getClass()->ops.lookupProperty)
+        if (obj->getClass()->ops.lookupGeneric)
             return false;
+        if (obj->nativeLookup(cx, id))
+            return true;
         if (obj->getClass()->resolve != JS_ResolveStub)
             return false;
         obj = obj->getProto();
     }
     return true;
 }
 
 bool
 IonBuilder::jsop_initprop(HandlePropertyName name)
 {
     MDefinition *value = current->pop();
     MDefinition *obj = current->peek(-1);
 
     RootedObject templateObject(cx, obj->toNewObject()->templateObject());
 
-    if (!CanEffectlesslyCallLookupGenericOnObject(templateObject))
-        return abort("INITPROP template object is special");
-
     RootedObject holder(cx);
     RootedShape shape(cx);
     RootedId id(cx, NameToId(name));
+    if (!CanEffectlesslyCallLookupGenericOnObject(cx, templateObject, id))
+        return abort("INITPROP template object is special");
+
     bool res = LookupPropertyWithFlags(cx, templateObject, id,
                                        0, &holder, &shape);
     if (!res)
         return false;
 
     if (!shape || holder != templateObject ||
         PropertyWriteNeedsTypeBarrier(cx, current, &obj, name, &value))
     {
@@ -5662,17 +5665,17 @@ TestSingletonProperty(JSContext *cx, Han
     // and the only way it can become missing in the future is if it is deleted.
     // Deletion causes type properties to be explicitly marked with undefined.
 
     *isKnownConstant = false;
 
     if (id != types::IdToTypeId(id))
         return true;
 
-    if (!CanEffectlesslyCallLookupGenericOnObject(obj))
+    if (!CanEffectlesslyCallLookupGenericOnObject(cx, obj, id))
         return true;
 
     RootedObject holder(cx);
     RootedShape shape(cx);
     if (!JSObject::lookupGeneric(cx, obj, id, &holder, &shape))
         return false;
     if (!shape)
         return true;
@@ -7140,17 +7143,17 @@ IonBuilder::TestCommonPropFunc(JSContext
             // on an own property can be protected with the prototype
             // shapeguard, though.
             if (!isGetter && curObj->watched())
                 return true;
         }
 
         // Turns out that we need to check for a property lookup op, else we
         // will end up calling it mid-compilation.
-        if (!CanEffectlesslyCallLookupGenericOnObject(curObj))
+        if (!CanEffectlesslyCallLookupGenericOnObject(cx, curObj, id))
             return true;
 
         RootedObject proto(cx);
         RootedShape shape(cx);
         if (!JSObject::lookupGeneric(cx, curObj, id, &proto, &shape))
             return false;
 
         if (!shape)
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jsion_bytecode_analyzer_h__
+#if !defined(jsion_bytecode_analyzer_h__) && defined(JS_ION)
 #define jsion_bytecode_analyzer_h__
 
 // This file declares the data structures for building a MIRGraph from a
 // JSScript.
 
 #include "MIR.h"
 #include "MIRGraph.h"
 
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -417,27 +417,27 @@ IonCache::updateBaseAddress(IonCode *cod
 }
 
 void
 IonCache::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
 {
 }
 
 static bool
-IsCacheableListBase(JSObject *obj)
+IsCacheableDOMProxy(JSObject *obj)
 {
     if (!obj->isProxy())
         return false;
 
     BaseProxyHandler *handler = GetProxyHandler(obj);
 
-    if (handler->family() != GetListBaseHandlerFamily())
+    if (handler->family() != GetDOMProxyHandlerFamily())
         return false;
 
-    if (obj->numFixedSlots() <= GetListBaseExpandoSlot())
+    if (obj->numFixedSlots() <= GetDOMProxyExpandoSlot())
         return false;
 
     return true;
 }
 
 static void
 GeneratePrototypeGuards(JSContext *cx, MacroAssembler &masm, JSObject *obj, JSObject *holder,
                         Register objectReg, Register scratchReg, Label *failures)
@@ -447,17 +447,17 @@ GeneratePrototypeGuards(JSContext *cx, M
     if (obj->hasUncacheableProto()) {
         // Note: objectReg and scratchReg may be the same register, so we cannot
         // use objectReg in the rest of this function.
         masm.loadPtr(Address(objectReg, JSObject::offsetOfType()), scratchReg);
         Address proto(scratchReg, offsetof(types::TypeObject, proto));
         masm.branchPtr(Assembler::NotEqual, proto, ImmGCPtr(obj->getProto()), failures);
     }
 
-    JSObject *pobj = IsCacheableListBase(obj)
+    JSObject *pobj = IsCacheableDOMProxy(obj)
                      ? obj->getTaggedProto().toObjectOrNull()
                      : obj->getProto();
     if (!pobj)
         return;
     while (pobj != holder) {
         if (pobj->hasUncacheableProto()) {
             JS_ASSERT(!pobj->hasSingletonType());
             masm.movePtr(ImmGCPtr(pobj), scratchReg);
@@ -472,17 +472,17 @@ static bool
 IsCacheableProtoChain(JSObject *obj, JSObject *holder)
 {
     while (obj != holder) {
         /*
          * We cannot assume that we find the holder object on the prototype
          * chain and must check for null proto. The prototype chain can be
          * altered during the lookupProperty call.
          */
-        JSObject *proto = IsCacheableListBase(obj)
+        JSObject *proto = IsCacheableDOMProxy(obj)
                      ? obj->getTaggedProto().toObjectOrNull()
                      : obj->getProto();
         if (!proto || !proto->isNative())
             return false;
         obj = proto;
     }
     return true;
 }
@@ -509,17 +509,17 @@ IsCacheableNoProperty(JSObject *obj, JSO
     JS_ASSERT(!holder);
 
     // Just because we didn't find the property on the object doesn't mean it
     // won't magically appear through various engine hacks:
     if (obj->getClass()->getProperty && obj->getClass()->getProperty != JS_PropertyStub)
         return false;
 
     // Don't generate missing property ICs if we skipped a non-native object, as
-    // lookups may extend beyond the prototype chain (e.g.  for ListBase
+    // lookups may extend beyond the prototype chain (e.g.  for DOMProxy
     // proxies).
     JSObject *obj2 = obj;
     while (obj2) {
         if (!obj2->isNative())
             return false;
         obj2 = obj2->getProto();
     }
 
@@ -620,86 +620,86 @@ EmitLoadSlot(MacroAssembler &masm, JSObj
         masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), scratchReg);
 
         Address addr(scratchReg, holder->dynamicSlotIndex(shape->slot()) * sizeof(Value));
         masm.loadTypedOrValue(addr, output);
     }
 }
 
 static void
-GenerateListBaseChecks(JSContext *cx, MacroAssembler &masm, JSObject *obj,
+GenerateDOMProxyChecks(JSContext *cx, MacroAssembler &masm, JSObject *obj,
                        PropertyName *name, Register object, Label *stubFailure,
                        bool skipExpandoCheck = false)
 {
-    MOZ_ASSERT(IsCacheableListBase(obj));
+    MOZ_ASSERT(IsCacheableDOMProxy(obj));
 
     // Guard the following:
-    //      1. The object is a ListBase.
+    //      1. The object is a DOMProxy.
     //      2. The object does not have expando properties, or has an expando
     //          which is known to not have the desired property.
     Address handlerAddr(object, JSObject::getFixedSlotOffset(JSSLOT_PROXY_HANDLER));
-    Address expandoSlotAddr(object, JSObject::getFixedSlotOffset(GetListBaseExpandoSlot()));
-
-    // Check that object is a ListBase.
+    Address expandoSlotAddr(object, JSObject::getFixedSlotOffset(GetDOMProxyExpandoSlot()));
+
+    // Check that object is a DOMProxy.
     masm.branchPrivatePtr(Assembler::NotEqual, handlerAddr, ImmWord(GetProxyHandler(obj)), stubFailure);
 
     if (skipExpandoCheck)
         return;
 
     // For the remaining code, we need to reserve some registers to load a value.
     // This is ugly, but unvaoidable.
-    RegisterSet listBaseRegSet(RegisterSet::All());
-    listBaseRegSet.take(AnyRegister(object));
-    ValueOperand tempVal = listBaseRegSet.takeValueOperand();
+    RegisterSet domProxyRegSet(RegisterSet::All());
+    domProxyRegSet.take(AnyRegister(object));
+    ValueOperand tempVal = domProxyRegSet.takeValueOperand();
     masm.pushValue(tempVal);
 
-    Label failListBaseCheck;
-    Label listBaseOk;
-
-    Value expandoVal = obj->getFixedSlot(GetListBaseExpandoSlot());
+    Label failDOMProxyCheck;
+    Label domProxyOk;
+
+    Value expandoVal = obj->getFixedSlot(GetDOMProxyExpandoSlot());
     masm.loadValue(expandoSlotAddr, tempVal);
 
     if (!expandoVal.isObject() && !expandoVal.isUndefined()) {
-        masm.branchTestValue(Assembler::NotEqual, tempVal, expandoVal, &failListBaseCheck);
+        masm.branchTestValue(Assembler::NotEqual, tempVal, expandoVal, &failDOMProxyCheck);
 
         ExpandoAndGeneration *expandoAndGeneration = (ExpandoAndGeneration*)expandoVal.toPrivate();
         masm.movePtr(ImmWord(expandoAndGeneration), tempVal.scratchReg());
 
         masm.branch32(Assembler::NotEqual, Address(tempVal.scratchReg(), sizeof(Value)),
                                                    Imm32(expandoAndGeneration->generation),
-                                                   &failListBaseCheck);
+                                                   &failDOMProxyCheck);
 
         expandoVal = expandoAndGeneration->expando;
         masm.loadValue(Address(tempVal.scratchReg(), 0), tempVal);
     }
 
     // If the incoming object does not have an expando object then we're sure we're not
     // shadowing.
-    masm.branchTestUndefined(Assembler::Equal, tempVal, &listBaseOk);
+    masm.branchTestUndefined(Assembler::Equal, tempVal, &domProxyOk);
 
     if (expandoVal.isObject()) {
         JS_ASSERT(!expandoVal.toObject().nativeContains(cx, name));
 
         // Reference object has an expando object that doesn't define the name. Check that
         // the incoming object has an expando object with the same shape.
-        masm.branchTestObject(Assembler::NotEqual, tempVal, &failListBaseCheck);
+        masm.branchTestObject(Assembler::NotEqual, tempVal, &failDOMProxyCheck);
         masm.extractObject(tempVal, tempVal.scratchReg());
         masm.branchPtr(Assembler::Equal,
                        Address(tempVal.scratchReg(), JSObject::offsetOfShape()),
                        ImmGCPtr(expandoVal.toObject().lastProperty()),
-                       &listBaseOk);
+                       &domProxyOk);
     }
 
     // Failure case: restore the tempVal registers and jump to failures.
-    masm.bind(&failListBaseCheck);
+    masm.bind(&failDOMProxyCheck);
     masm.popValue(tempVal);
     masm.jump(stubFailure);
 
     // Success case: restore the tempval and proceed.
-    masm.bind(&listBaseOk);
+    masm.bind(&domProxyOk);
     masm.popValue(tempVal);
 }
 
 static void
 GenerateReadSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
                  JSObject *obj, PropertyName *name, JSObject *holder, Shape *shape,
                  Register object, TypedOrValueRegister output, Label *failures = NULL)
 {
@@ -715,21 +715,21 @@ GenerateReadSlot(JSContext *cx, MacroAss
         failures = &failures_;
 
     // Guard on the shape of the object.
     attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
                                    Address(object, JSObject::offsetOfShape()),
                                    ImmGCPtr(obj->lastProperty()),
                                    failures);
 
-    bool isCacheableListBase = IsCacheableListBase(obj);
-    Label listBaseFailures;
-    if (isCacheableListBase) {
+    bool isCacheableDOMProxy = IsCacheableDOMProxy(obj);
+    Label domProxyFailures;
+    if (isCacheableDOMProxy) {
         JS_ASSERT(multipleFailureJumps);
-        GenerateListBaseChecks(cx, masm, obj, name, object, &listBaseFailures);
+        GenerateDOMProxyChecks(cx, masm, obj, name, object, &domProxyFailures);
     }
 
     // If we need a scratch register, use either an output register or the
     // object register. After this point, we cannot jump directly to
     // |failures| since we may still have to pop the object register.
     bool restoreScratch = false;
     Register scratchReg = Register::FromCode(0); // Quell compiler warning.
 
@@ -810,18 +810,18 @@ GenerateReadSlot(JSContext *cx, MacroAss
         masm.pop(scratchReg);
 
     attacher.jumpRejoin(masm);
 
     if (multipleFailureJumps) {
         masm.bind(&prototypeFailures);
         if (restoreScratch)
             masm.pop(scratchReg);
-        if (isCacheableListBase)
-            masm.bind(&listBaseFailures);
+        if (isCacheableDOMProxy)
+            masm.bind(&domProxyFailures);
         masm.bind(failures);
     }
 
     attacher.jumpNextStub(masm);
 
     if (restoreScratch)
         masm.pop(scratchReg);
 }
@@ -832,18 +832,18 @@ GenerateCallGetter(JSContext *cx, MacroA
                    RegisterSet &liveRegs, Register object, TypedOrValueRegister output,
                    void *returnAddr, jsbytecode *pc)
 {
     // Initial shape check.
     Label stubFailure;
     masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfShape()),
                    ImmGCPtr(obj->lastProperty()), &stubFailure);
 
-    if (IsCacheableListBase(obj))
-        GenerateListBaseChecks(cx, masm, obj, name, object, &stubFailure);
+    if (IsCacheableDOMProxy(obj))
+        GenerateDOMProxyChecks(cx, masm, obj, name, object, &stubFailure);
 
     JS_ASSERT(output.hasValue());
     Register scratchReg = output.valueReg().scratchReg();
 
     // Note: this may clobber the object register if it's used as scratch.
     if (obj != holder)
         GeneratePrototypeGuards(cx, masm, obj, holder, object, scratchReg, &stubFailure);
 
@@ -1016,37 +1016,37 @@ GetPropertyIC::attachReadSlot(JSContext 
     GenerateReadSlot(cx, masm, attacher, obj, name(), holder, shape, object(), output());
     const char *attachKind = "non idempotent reading";
     if (idempotent())
         attachKind = "idempotent reading";
     return linkAndAttachStub(cx, masm, attacher, ion, attachKind);
 }
 
 bool
-GetPropertyIC::attachListBaseShadowed(JSContext *cx, IonScript *ion, JSObject *obj,
+GetPropertyIC::attachDOMProxyShadowed(JSContext *cx, IonScript *ion, JSObject *obj,
                                       void *returnAddr)
 {
     JS_ASSERT(!idempotent());
-    JS_ASSERT(IsCacheableListBase(obj));
+    JS_ASSERT(IsCacheableDOMProxy(obj));
     JS_ASSERT(output().hasValue());
 
     Label failures;
     MacroAssembler masm(cx);
     RepatchStubAppender attacher(*this);
 
     masm.setFramePushed(ion->frameSize());
 
     // Guard on the shape of the object.
     attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
                                    Address(object(), JSObject::offsetOfShape()),
                                    ImmGCPtr(obj->lastProperty()),
                                    &failures);
 
-    // Make sure object is a ListBase proxy
-    GenerateListBaseChecks(cx, masm, obj, name(), object(), &failures,
+    // Make sure object is a DOMProxy proxy
+    GenerateDOMProxyChecks(cx, masm, obj, name(), object(), &failures,
                            /*skipExpandoCheck=*/true);
 
     // saveLive()
     masm.PushRegsInMask(liveRegs_);
 
     DebugOnly<uint32_t> initialStack = masm.framePushed();
 
     // Remaining registers should be free, but we need to use |object| still
@@ -1374,26 +1374,26 @@ TryAttachNativeGetPropStub(JSContext *cx
                            HandlePropertyName name,
                            const SafepointIndex *safepointIndex,
                            void *returnAddr, bool *isCacheable)
 {
     JS_ASSERT(!*isCacheable);
     JS_ASSERT(cache.canAttachStub());
 
     RootedObject checkObj(cx, obj);
-    if (IsCacheableListBase(obj)) {
+    if (IsCacheableDOMProxy(obj)) {
         RootedId id(cx, NameToId(name));
-        ListBaseShadowsResult shadows = GetListBaseShadowsCheck()(cx, obj, id);
+        DOMProxyShadowsResult shadows = GetDOMProxyShadowsCheck()(cx, obj, id);
         if (shadows == ShadowCheckFailed)
             return false;
         if (shadows == Shadows) {
             if (cache.idempotent() || !cache.output().hasValue())
                 return true;
             *isCacheable = true;
-            return cache.attachListBaseShadowed(cx, ion, obj, returnAddr);
+            return cache.attachDOMProxyShadowed(cx, ion, obj, returnAddr);
         }
         if (shadows == DoesntShadowUnique)
             // We reset the cache to clear out an existing IC for this object
             // (if there is one). The generation is a constant in the generated
             // code and we will not have the same generation again for this
             // object, so the generation check in the existing IC would always
             // fail anyway.
             cache.reset();
--- a/js/src/ion/IonCaches.h
+++ b/js/src/ion/IonCaches.h
@@ -540,17 +540,17 @@ class GetPropertyIC : public RepatchIonC
         return hasTypedArrayLengthStub_;
     }
     bool hasArgumentsLengthStub(bool strict) const {
         return strict ? hasStrictArgumentsLengthStub_ : hasNormalArgumentsLengthStub_;
     }
 
     bool attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
                         HandleShape shape);
-    bool attachListBaseShadowed(JSContext *cx, IonScript *ion, JSObject *obj, void *returnAddr);
+    bool attachDOMProxyShadowed(JSContext *cx, IonScript *ion, JSObject *obj, void *returnAddr);
     bool attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
                           HandleShape shape,
                           const SafepointIndex *safepointIndex, void *returnAddr);
     bool attachArrayLength(JSContext *cx, IonScript *ion, JSObject *obj);
     bool attachTypedArrayLength(JSContext *cx, IonScript *ion, JSObject *obj);
     bool attachArgumentsLength(JSContext *cx, IonScript *ion, JSObject *obj);
 
     static bool update(JSContext *cx, size_t cacheIndex, HandleObject obj, MutableHandleValue vp);
--- a/js/src/ion/IonCompartment.h
+++ b/js/src/ion/IonCompartment.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jsion_ion_compartment_h__
+#if !defined(jsion_ion_compartment_h__) && defined(JS_ION)
 #define jsion_ion_compartment_h__
 
 #include "IonCode.h"
 #include "jsweakcache.h"
 #include "js/Value.h"
 #include "vm/Stack.h"
 #include "IonFrames.h"
 #include "CompileInfo.h"
--- a/js/src/ion/IonFrameIterator-inl.h
+++ b/js/src/ion/IonFrameIterator-inl.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jsion_frame_iterator_inl_h__
+#if !defined(jsion_frame_iterator_inl_h__) && defined(JS_ION)
 #define jsion_frame_iterator_inl_h__
 
 #include "ion/BaselineFrame.h"
 #include "ion/IonFrameIterator.h"
 #include "ion/Bailouts.h"
 #include "ion/Ion.h"
 
 namespace js {
--- a/js/src/ion/IonFrameIterator.h
+++ b/js/src/ion/IonFrameIterator.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jsion_frame_iterator_h__
+#if !defined(jsion_frame_iterator_h__) && defined(JS_ION)
 #define jsion_frame_iterator_h__
 
 #include "jstypes.h"
 #include "IonCode.h"
 #include "SnapshotReader.h"
 
 class JSFunction;
 class JSScript;
--- a/js/src/ion/IonFrames-inl.h
+++ b/js/src/ion/IonFrames-inl.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jsion_frames_inl_h__
+#if !defined(jsion_frames_inl_h__) && defined(JS_ION)
 #define jsion_frames_inl_h__
 
 #include "ion/IonFrames.h"
 #include "ion/IonFrameIterator.h"
 #include "ion/LIR.h"
 
 namespace js {
 namespace ion {
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -1,34 +1,36 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
-#include "Ion.h"
 #include "IonFrames.h"
+
 #include "jsobj.h"
 #include "jsscript.h"
 #include "jsfun.h"
-#include "BaselineFrame.h"
-#include "BaselineIC.h"
-#include "BaselineJIT.h"
-#include "IonCompartment.h"
-#include "IonFrames-inl.h"
-#include "IonFrameIterator-inl.h"
-#include "Safepoints.h"
-#include "IonSpewer.h"
-#include "IonMacroAssembler.h"
-#include "PcScriptCache.h"
-#include "PcScriptCache-inl.h"
 #include "gc/Marking.h"
-#include "SnapshotReader.h"
-#include "Safepoints.h"
-#include "VMFunctions.h"
+#include "ion/BaselineFrame.h"
+#include "ion/BaselineIC.h"
+#include "ion/BaselineJIT.h"
+#include "ion/Ion.h"
+#include "ion/IonCompartment.h"
+#include "ion/IonMacroAssembler.h"
+#include "ion/IonSpewer.h"
+#include "ion/PcScriptCache.h"
+#include "ion/Safepoints.h"
+#include "ion/SnapshotReader.h"
+#include "ion/VMFunctions.h"
+
+#include "ion/IonFrameIterator-inl.h"
+#include "ion/IonFrames-inl.h"
+#include "ion/PcScriptCache-inl.h"
+#include "vm/Probes-inl.h"
 
 namespace js {
 namespace ion {
 
 IonFrameIterator::IonFrameIterator(const IonActivationIterator &activations)
     : current_(activations.top()),
       type_(IonFrame_Exit),
       returnAddressToFp_(NULL),
--- a/js/src/ion/IonFrames.h
+++ b/js/src/ion/IonFrames.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jsion_frames_h__
+#if !defined(jsion_frames_h__) && defined(JS_ION)
 #define jsion_frames_h__
 
 #include "mozilla/DebugOnly.h"
 
 #include "jsfun.h"
 #include "jstypes.h"
 #include "jsutil.h"
 #include "Registers.h"
--- a/js/src/ion/IonMacroAssembler.h
+++ b/js/src/ion/IonMacroAssembler.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jsion_macro_assembler_h__
+#if !defined(jsion_macro_assembler_h__) && defined(JS_ION)
 #define jsion_macro_assembler_h__
 
 #if defined(JS_CPU_X86)
 # include "ion/x86/MacroAssembler-x86.h"
 #elif defined(JS_CPU_X64)
 # include "ion/x64/MacroAssembler-x64.h"
 #elif defined(JS_CPU_ARM)
 # include "ion/arm/MacroAssembler-arm.h"
--- a/js/src/ion/MIRGraph.cpp
+++ b/js/src/ion/MIRGraph.cpp
@@ -4,17 +4,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Ion.h"
 #include "IonSpewer.h"
 #include "MIR.h"
 #include "MIRGraph.h"
 #include "IonBuilder.h"
-#include "frontend/BytecodeEmitter.h"
 #include "jsscriptinlines.h"
 
 using namespace js;
 using namespace js::ion;
 
 MIRGenerator::MIRGenerator(JSCompartment *compartment,
                            TempAllocator *temp, MIRGraph *graph, CompileInfo *info)
   : compartment(compartment),
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -11,17 +11,17 @@
 #include "ion/IonFrames.h"
 
 #include "vm/Debugger.h"
 #include "vm/Interpreter.h"
 #include "vm/StringObject-inl.h"
 
 #include "builtin/ParallelArray.h"
 
-#include "frontend/TokenStream.h"
+#include "frontend/BytecodeCompiler.h"
 
 #include "jsboolinlines.h"
 
 #include "ion/IonFrames-inl.h" // for GetTopIonJSScript
 
 #include "vm/Interpreter-inl.h"
 #include "vm/StringObject-inl.h"
 
@@ -531,17 +531,17 @@ GetDynamicName(JSContext *cx, JSObject *
     } else {
         atom = AtomizeString<NoGC>(cx, str);
         if (!atom) {
             vp->setUndefined();
             return;
         }
     }
 
-    if (!frontend::IsIdentifier(atom) || frontend::FindKeyword(atom->chars(), atom->length())) {
+    if (!frontend::IsIdentifier(atom) || frontend::IsKeyword(atom)) {
         vp->setUndefined();
         return;
     }
 
     Shape *shape = NULL;
     JSObject *scope = NULL, *pobj = NULL;
     if (LookupNameNoGC(cx, atom->asPropertyName(), scopeChain, &scope, &pobj, &shape)) {
         if (FetchNameNoGC(pobj, shape, MutableHandleValue::fromMarkedLocation(vp)))
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/testBug878520.js
@@ -0,0 +1,9 @@
+function surprise(depth) {
+    arguments.callee.caller(depth);
+}
+
+(function(depth) {
+    function foo() { function asmModule() { 'use asm'; return {} } };
+    if (depth)
+        surprise(depth - 1);
+})(2);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Array-iterator-surfaces.js
@@ -0,0 +1,4 @@
+// Array.prototype.iterator is the same function object as .values.
+
+assertEq(Array.prototype.values, Array.prototype.iterator);
+assertEq(Array.prototype.iterator.name, "values");
--- a/js/src/jit-test/tests/collections/Map-surfaces-1.js
+++ b/js/src/jit-test/tests/collections/Map-surfaces-1.js
@@ -26,16 +26,22 @@ function checkMethod(name, arity) {
     assertEq(desc.value.name, name);
     assertEq(desc.value.length, arity);
 }
 
 checkMethod("get", 1);
 checkMethod("has", 1);
 checkMethod("set", 2);
 checkMethod("delete", 1);
+checkMethod("keys", 0);
+checkMethod("values", 0);
+checkMethod("entries", 0);
 
 var desc = Object.getOwnPropertyDescriptor(Map.prototype, "size");
 assertEq(desc.enumerable, false);
 assertEq(desc.configurable, true);
 assertEq(typeof desc.get, 'function');
 assertEq(desc.get.length, 0);
 assertEq(desc.set, undefined);
 checkMethod("clear", 0);
+
+// Map.prototype.iterator and .entries are the same function object.
+assertEq(Map.prototype.iterator, Map.prototype.entries);
--- a/js/src/jit-test/tests/collections/Map-surfaces-2.js
+++ b/js/src/jit-test/tests/collections/Map-surfaces-2.js
@@ -11,16 +11,19 @@ function testcase(obj, fn) {
 var Map_size_getter = Object.getOwnPropertyDescriptor(Map.prototype, "size").get;
 
 function test(obj) {
     testcase(obj, Map.prototype.get, "x");
     testcase(obj, Map.prototype.has, "x");
     testcase(obj, Map.prototype.set, "x", 1);
     testcase(obj, Map.prototype.delete, "x");
     testcase(obj, Map.prototype.clear);
+    testcase(obj, Map.prototype.keys);
+    testcase(obj, Map.prototype.values);
+    testcase(obj, Map.prototype.entries);
     testcase(obj, Map_size_getter);
 }
 
 test(Map.prototype);
 test(Object.create(new Map));
 test(new Set());
 test({});
 test(null);
--- a/js/src/jit-test/tests/collections/Set-surfaces-1.js
+++ b/js/src/jit-test/tests/collections/Set-surfaces-1.js
@@ -25,16 +25,22 @@ function checkMethod(name, arity) {
     assertEq(typeof desc.value, 'function');
     assertEq(desc.value.name, name);
     assertEq(desc.value.length, arity);
 }
 
 checkMethod("has", 1);
 checkMethod("add", 1);
 checkMethod("delete", 1);
+checkMethod("values", 0);
+checkMethod("entries", 0);
 
 var desc = Object.getOwnPropertyDescriptor(Set.prototype, "size");
 assertEq(desc.enumerable, false);
 assertEq(desc.configurable, true);
 assertEq(typeof desc.get, 'function');
 assertEq(desc.get.length, 0);
 assertEq(desc.set, undefined);
 checkMethod("clear", 0);
+
+// Set.prototype.keys, .values, and .iterator are the same function object
+assertEq(Set.prototype.keys, Set.prototype.values);
+assertEq(Set.prototype.iterator, Set.prototype.values);
--- a/js/src/jit-test/tests/collections/Set-surfaces-2.js
+++ b/js/src/jit-test/tests/collections/Set-surfaces-2.js
@@ -10,16 +10,19 @@ function testcase(obj, fn) {
 
 var Set_size_getter = Object.getOwnPropertyDescriptor(Set.prototype, "size").get;
 
 function test(obj) {
     testcase(obj, Set.prototype.has, 12);
     testcase(obj, Set.prototype.add, 12);
     testcase(obj, Set.prototype.delete, 12);
     testcase(obj, Set.prototype.clear);
+    testcase(obj, Set.prototype.keys);
+    testcase(obj, Set.prototype.values);
+    testcase(obj, Set.prototype.entries);
     testcase(obj, Set_size_getter);
 }
 
 test(Set.prototype);
 test(Object.create(new Set));
 test(new Map());
 test({});
 test(null);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Set-values-1.js
@@ -0,0 +1,14 @@
+// set.keys(), .values(), and .entries() on an empty set produce empty iterators
+
+var s = Set();
+var ki = s.keys(), vi = s.values(), ei = s.entries();
+var p = Object.getPrototypeOf(ki);
+assertEq(Object.getPrototypeOf(vi), p);
+assertEq(Object.getPrototypeOf(ei), p);
+
+for (let k of ki)
+	throw "FAIL";
+for (let v of vi)
+	throw "FAIL";
+for (let [k, v] of ei)
+	throw "FAIL";
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Set-values-2.js
@@ -0,0 +1,18 @@
+// set.keys() and set.values() return iterators over the elements
+// and set.entries() returns an iterator that yields pairs [e, e].
+
+load(libdir + "asserts.js");
+
+var data = [1, 2, 3, 4];
+var s = Set(data);
+
+var ki = s.keys();
+assertEq(ki.next(), 1);
+assertEq(ki.next(), 2);
+assertEq(ki.next(), 3);
+assertEq(ki.next(), 4);
+assertThrowsValue(function () { ki.next(); }, StopIteration);
+
+assertEq([...s.keys()].toSource(), data.toSource());
+assertEq([...s.values()].toSource(), data.toSource());
+assertEq([...s.entries()].toSource(), [[1, 1], [2, 2], [3, 3], [4, 4]].toSource());
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug858586.js
@@ -0,0 +1,23 @@
+function A(a) { this.a = a; }
+A.prototype.foo = function (x) {};
+function B(b) { this.b = b; }
+B.prototype.foo = function (x) {};
+function C(c) {}
+function makeArray(n) {
+    var classes = [A, B, C];
+    var arr = [];
+    for (var i = 0; i < n; i++) {
+        arr.push(new classes[i % 3](i % 3));
+    }
+    return arr;
+}
+function runner(arr, resultArray, len) {
+    for (var i = 0; i < len; i++) {
+        var obj = arr[i];
+        resultArray[0] += obj.foo(i);
+    }
+}
+var resultArray = [0];
+var arr = makeArray(30000);
+C.prototype.foo = Uint8ClampedArray;
+runner(arr, resultArray, 30000);
--- a/js/src/jsapi-tests/testXDR.cpp
+++ b/js/src/jsapi-tests/testXDR.cpp
@@ -1,23 +1,19 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
 
-
 #include "tests.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsfriendapi.h"
 
-#include "jsscriptinlines.h"
-
 static JSScript *
 CompileScriptForPrincipalsVersionOrigin(JSContext *cx, JS::HandleObject obj,
                                         JSPrincipals *principals, JSPrincipals *originPrincipals,
                                         const char *bytes, size_t nbytes,
                                         const char *filename, unsigned lineno,
                                         JSVersion version)
 {
     size_t nchars;
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2666,17 +2666,17 @@ array_filter(JSContext *cx, unsigned arg
             ag.setThis(thisv);
             ag[0] = kValue;
             ag[1] = NumberValue(k);
             ag[2] = ObjectValue(*obj);
             if (!fig.invoke(cx))
                 return false;
 
             if (ToBoolean(ag.rval())) {
-                if(!SetArrayElement(cx, arr, to, kValue))
+                if (!SetArrayElement(cx, arr, to, kValue))
                     return false;
                 to++;
             }
         }
 
         /* Step d. */
         k++;
     }
@@ -2723,17 +2723,16 @@ static const JSFunctionSpec array_method
          {"forEach",            {NULL, NULL},       1,0, "ArrayForEach"},
          {"map",                {NULL, NULL},       1,0, "ArrayMap"},
          {"reduce",             {NULL, NULL},       1,0, "ArrayReduce"},
          {"reduceRight",        {NULL, NULL},       1,0, "ArrayReduceRight"},
     JS_FN("filter",             array_filter,       1,JSFUN_GENERIC_NATIVE),
          {"some",               {NULL, NULL},       1,0, "ArraySome"},
          {"every",              {NULL, NULL},       1,0, "ArrayEvery"},
 
-    JS_FN("iterator",           JS_ArrayIterator,   0,0),
     JS_FS_END
 };
 
 static const JSFunctionSpec array_static_methods[] = {
     JS_FN("isArray",            array_isArray,      1,0),
          {"lastIndexOf",        {NULL, NULL},       2,0, "ArrayStaticLastIndexOf"},
          {"indexOf",            {NULL, NULL},       2,0, "ArrayStaticIndexOf"},
          {"forEach",            {NULL, NULL},       2,0, "ArrayStaticForEach"},
@@ -2842,16 +2841,24 @@ js_InitArrayClass(JSContext *cx, HandleO
         !DefinePropertiesAndBrand(cx, ctor, NULL, array_static_methods))
     {
         return NULL;
     }
 
     if (!DefineConstructorAndPrototype(cx, global, JSProto_Array, ctor, arrayProto))
         return NULL;
 
+    JSFunction *fun = JS_DefineFunction(cx, arrayProto, "values", JS_ArrayIterator, 0, 0);
+    if (!fun)
+        return NULL;
+
+    RootedValue funval(cx, ObjectValue(*fun));
+    if (!JS_DefineProperty(cx, arrayProto, "iterator", funval, NULL, NULL, 0))
+        return NULL;
+
     return arrayProto;
 }
 
 /*
  * Array allocation functions.
  */
 
 static inline bool
--- a/js/src/jsatominlines.h
+++ b/js/src/jsatominlines.h
@@ -9,17 +9,16 @@
 
 #include "mozilla/PodOperations.h"
 #include "mozilla/RangedPtr.h"
 
 #include "jsatom.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsstr.h"
-
 #include "gc/Barrier.h"
 #include "vm/String.h"
 
 inline JSAtom *
 js::AtomStateEntry::asPtr() const
 {
     JS_ASSERT(bits != 0);
     JSAtom *atom = reinterpret_cast<JSAtom *>(bits & NO_TAG_MASK);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1523,17 +1523,17 @@ struct JSContext : js::ContextFriendFiel
     /* Exception state -- the exception member is a GC root by definition. */
     bool                throwing;            /* is there a pending exception? */
     js::Value           exception;           /* most-recently-thrown exception */
 
     /* Per-context options. */
     unsigned            options_;            /* see jsapi.h for JSOPTION_* */
 
   public:
-    int32_t             reportGranularity;  /* see jsprobes.h */
+    int32_t             reportGranularity;  /* see vm/Probes.h */
 
     js::AutoResolving   *resolvingList;
 
     /* True if generating an error, to prevent runaway recursion. */
     bool                generatingError;
 
     inline void setCompartment(JSCompartment *comp);
 
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -3,24 +3,24 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jscntxtinlines_h___
 #define jscntxtinlines_h___
 
 #include "jscntxt.h"
+
 #include "jscompartment.h"
 #include "jsfriendapi.h"
-#include "jsprobes.h"
 #include "jsgc.h"
-
 #include "builtin/Object.h" // For js::obj_construct
 #include "frontend/ParseMaps.h"
 #include "vm/Interpreter.h"
+#include "vm/Probes.h"
 #include "vm/RegExpObject.h"
 
 #include "jsgcinlines.h"
 
 namespace js {
 
 inline void
 NewObjectCache::staticAsserts()
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -16,17 +16,16 @@
 #include "jswatchpoint.h"
 #include "jswrapper.h"
 
 #include "gc/Marking.h"
 #ifdef JS_ION
 #include "ion/IonCompartment.h"
 #endif
 #include "js/RootingAPI.h"
-#include "vm/Debugger.h"
 
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::DebugOnly;
@@ -512,17 +511,16 @@ JSCompartment::sweep(FreeOp *fop, bool r
         gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_TABLES);
 
         /* Remove dead references held weakly by the compartment. */
 
         sweepBaseShapeTable();
         sweepInitialShapeTable();
         sweepNewTypeObjectTable(newTypeObjects);
         sweepNewTypeObjectTable(lazyTypeObjects);
-        sweepBreakpoints(fop);
         sweepCallsiteClones();
 
         if (global_ && IsObjectAboutToBeFinalized(global_.unsafeGet()))
             global_ = NULL;
 
 #ifdef JS_ION
         if (ionCompartment_)
             ionCompartment_->sweep(fop);
@@ -752,46 +750,16 @@ JSCompartment::clearTraps(FreeOp *fop)
     for (gc::CellIter i(zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
         JSScript *script = i.get<JSScript>();
         if (script->compartment() == this && script->hasAnyBreakpointsOrStepMode())
             script->clearTraps(fop);
     }
 }
 
 void
-JSCompartment::sweepBreakpoints(FreeOp *fop)
-{
-    gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_TABLES_BREAKPOINT);
-
-    if (rt->debuggerList.isEmpty())
-        return;
-
-    for (CellIterUnderGC i(zone(), FINALIZE_SCRIPT); !i.done(); i.next()) {
-        JSScript *script = i.get<JSScript>();
-        if (script->compartment() != this || !script->hasAnyBreakpointsOrStepMode())
-            continue;
-        bool scriptGone = IsScriptAboutToBeFinalized(&script);
-        JS_ASSERT(script == i.get<JSScript>());
-        for (unsigned i = 0; i < script->length; i++) {
-            BreakpointSite *site = script->getBreakpointSite(script->code + i);
-            if (!site)
-                continue;
-            // nextbp is necessary here to avoid possibly reading *bp after
-            // destroying it.
-            Breakpoint *nextbp;
-            for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
-                nextbp = bp->nextInSite();
-                if (scriptGone || IsObjectAboutToBeFinalized(&bp->debugger->toJSObjectRef()))
-                    bp->destroy(fop);
-            }
-        }
-    }
-}
-
-void
 JSCompartment::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *compartmentObject,
                                    JS::TypeInferenceSizes *tiSizes, size_t *shapesCompartmentTables,
                                    size_t *crossCompartmentWrappersArg, size_t *regexpCompartment,
                                    size_t *debuggeesSet, size_t *baselineStubsOptimized)
 {
     *compartmentObject = mallocSizeOf(this);
     sizeOfTypeInferenceData(tiSizes, mallocSizeOf);
     *shapesCompartmentTables = baseShapes.sizeOfExcludingThis(mallocSizeOf)
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -33,16 +33,17 @@
 #include "ion/AsmJSModule.h"
 #endif
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
+#include "vm/Debugger-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::PodZero;
 
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1003,45 +1003,45 @@ js::SetDOMCallbacks(JSRuntime *rt, const
 }
 
 JS_FRIEND_API(const DOMCallbacks *)
 js::GetDOMCallbacks(JSRuntime *rt)
 {
     return rt->DOMcallbacks;
 }
 
-static void *gListBaseHandlerFamily = NULL;
-static uint32_t gListBaseExpandoSlot = 0;
-static ListBaseShadowsCheck gListBaseShadowsCheck;
+static void *gDOMProxyHandlerFamily = NULL;
+static uint32_t gDOMProxyExpandoSlot = 0;
+static DOMProxyShadowsCheck gDOMProxyShadowsCheck;
 
 JS_FRIEND_API(void)
-js::SetListBaseInformation(void *listBaseHandlerFamily, uint32_t listBaseExpandoSlot,
-                           ListBaseShadowsCheck listBaseShadowsCheck)
+js::SetDOMProxyInformation(void *domProxyHandlerFamily, uint32_t domProxyExpandoSlot,
+                           DOMProxyShadowsCheck domProxyShadowsCheck)
 {
-    gListBaseHandlerFamily = listBaseHandlerFamily;
-    gListBaseExpandoSlot = listBaseExpandoSlot;
-    gListBaseShadowsCheck = listBaseShadowsCheck;
+    gDOMProxyHandlerFamily = domProxyHandlerFamily;
+    gDOMProxyExpandoSlot = domProxyExpandoSlot;
+    gDOMProxyShadowsCheck = domProxyShadowsCheck;
 }
 
 void *
-js::GetListBaseHandlerFamily()
+js::GetDOMProxyHandlerFamily()
 {
-    return gListBaseHandlerFamily;
+    return gDOMProxyHandlerFamily;
 }
 
 uint32_t
-js::GetListBaseExpandoSlot()
+js::GetDOMProxyExpandoSlot()
 {
-    return gListBaseExpandoSlot;
+    return gDOMProxyExpandoSlot;
 }
 
-ListBaseShadowsCheck
-js::GetListBaseShadowsCheck()
+DOMProxyShadowsCheck
+js::GetDOMProxyShadowsCheck()
 {
-    return gListBaseShadowsCheck;
+    return gDOMProxyShadowsCheck;
 }
 
 JS_FRIEND_API(void)
 js::SetCTypesActivityCallback(JSRuntime *rt, CTypesActivityCallback cb)
 {
     rt->ctypesActivityCallback = cb;
 }
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -854,20 +854,20 @@ struct CompartmentsWithPrincipals : publ
 };
 
 extern JS_FRIEND_API(JSBool)
 NukeCrossCompartmentWrappers(JSContext* cx,
                              const CompartmentFilter& sourceFilter,
                              const CompartmentFilter& targetFilter,
                              NukeReferencesToWindow nukeReferencesToWindow);
 
-/* Specify information about ListBase proxies in the DOM, for use by ICs. */
+/* Specify information about DOMProxy proxies in the DOM, for use by ICs. */
 
 /*
- * The ListBaseShadowsCheck function will be called to check if the property for
+ * The DOMProxyShadowsCheck function will be called to check if the property for
  * id should be gotten from the prototype, or if there is an own property that
  * shadows it.
  * If DoesntShadow is returned then the slot at listBaseExpandoSlot should
  * either be undefined or point to an expando object that would contain the own
  * property.
  * If DoesntShadowUnique is returned then the slot at listBaseExpandoSlot should
  * contain a private pointer to a ExpandoAndGeneration, which contains a
  * JS::Value that should either be undefined or point to an expando object, and
@@ -880,31 +880,31 @@ struct ExpandoAndGeneration {
     : expando(UndefinedValue()),
       generation(0)
   {}
 
   Value expando;
   uint32_t generation;
 };
 
-typedef enum ListBaseShadowsResult {
+typedef enum DOMProxyShadowsResult {
   ShadowCheckFailed,
   Shadows,
   DoesntShadow,
   DoesntShadowUnique
-} ListBaseShadowsResult;
-typedef ListBaseShadowsResult
-(* ListBaseShadowsCheck)(JSContext* cx, JSHandleObject object, JSHandleId id);
+} DOMProxyShadowsResult;
+typedef DOMProxyShadowsResult
+(* DOMProxyShadowsCheck)(JSContext* cx, JSHandleObject object, JSHandleId id);
 JS_FRIEND_API(void)
-SetListBaseInformation(void *listBaseHandlerFamily, uint32_t listBaseExpandoSlot,
-                       ListBaseShadowsCheck listBaseShadowsCheck);
+SetDOMProxyInformation(void *domProxyHandlerFamily, uint32_t domProxyExpandoSlot,
+                       DOMProxyShadowsCheck domProxyShadowsCheck);
 
-void *GetListBaseHandlerFamily();
-uint32_t GetListBaseExpandoSlot();
-ListBaseShadowsCheck GetListBaseShadowsCheck();
+void *GetDOMProxyHandlerFamily();
+uint32_t GetDOMProxyExpandoSlot();
+DOMProxyShadowsCheck GetDOMProxyShadowsCheck();
 
 } /* namespace js */
 
 /* Implemented in jsdate.cpp. */
 
 /*
  * Detect whether the internal date value is NaN.  (Because failure is
  * out-of-band for js_DateGet*)
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -12,19 +12,17 @@
 #include "jsanalyze.h"
 #include "jscompartment.h"
 #include "jsinfer.h"
 #include "jsprf.h"
 #include "jsproxy.h"
 #include "jstypedarray.h"
 
 #include "builtin/ParallelArray.h"
-#ifdef JS_ION
 #include "ion/IonFrames.h"
-#endif
 #include "js/RootingAPI.h"
 #include "vm/GlobalObject.h"
 
 #include "jsanalyzeinlines.h"
 #include "vm/Stack-inl.h"
 
 #ifndef jsinferinlines_h___
 #define jsinferinlines_h___
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2,17 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 /*
  * JS object implementation.
  */
-#include "jsobj.h"
+#include "jsobjinlines.h"
 
 #include <stdlib.h>
 #include <string.h>
 
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
 #include "jsutil.h"
@@ -21,43 +21,41 @@
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsiter.h"
 #include "jsnum.h"
 #include "jsopcode.h"
-#include "jsprobes.h"
 #include "jsprototypes.h"
 #include "jsproxy.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsdbgapi.h"
 #include "jswatchpoint.h"
 #include "jswrapper.h"
-
-#include "frontend/TokenStream.h"
+#include "frontend/BytecodeCompiler.h"
 #include "gc/Marking.h"
 #include "ion/BaselineJIT.h"
 #include "js/MemoryMetrics.h"
 #include "vm/Interpreter.h"
 #include "vm/Shape.h"
 
 #include "jsatominlines.h"
 #include "jsboolinlines.h"
 #include "jscntxtinlines.h"
 #include "jscompartmentinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 #include "jstypedarrayinlines.h"
-
 #include "builtin/Iterator-inl.h"
 #include "vm/BooleanObject-inl.h"
 #include "vm/NumberObject-inl.h"
+#include "vm/Probes-inl.h"
 #include "vm/RegExpStatics-inl.h"
 #include "vm/Shape-inl.h"
 #include "vm/StringObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
@@ -3575,16 +3573,21 @@ template <AllowGC allowGC>
 static JS_ALWAYS_INLINE bool
 LookupPropertyWithFlagsInline(JSContext *cx,
                               typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
                               typename MaybeRooted<jsid, allowGC>::HandleType id,
                               unsigned flags,
                               typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
                               typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
 {
+    /* NB: The logic of this procedure is implicitly reflected in IonBuilder.cpp's
+     *     |CanEffectlesslyCallLookupGenericOnObject| logic.
+     *     If this changes, please remember to update the logic there as well.
+     */
+
     /* Search scopes starting with obj and following the prototype link. */
     typename MaybeRooted<JSObject*, allowGC>::RootType current(cx, obj);
 
     while (true) {
         /* Search for a native dense element or property. */
         {
             if (JSID_IS_INT(id) && current->containsDenseElement(JSID_TO_INT(id))) {
                 objp.set(current);
@@ -3652,16 +3655,20 @@ LookupPropertyWithFlagsInline(JSContext 
 template <AllowGC allowGC>
 JSBool
 baseops::LookupProperty(JSContext *cx,
                         typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
                         typename MaybeRooted<jsid, allowGC>::HandleType id,
                         typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
                         typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
 {
+    /* NB: The logic of this procedure is implicitly reflected in IonBuilder.cpp's
+     *     |CanEffectlesslyCallLookupGenericOnObject| logic.
+     *     If this changes, please remember to update the logic there as well.
+     */
     return LookupPropertyWithFlagsInline<allowGC>(cx, obj, id, cx->resolveFlags, objp, propp);
 }
 
 template JSBool
 baseops::LookupProperty<CanGC>(JSContext *cx, HandleObject obj, HandleId id,
                                MutableHandleObject objp, MutableHandleShape propp);
 
 template JSBool
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -2,53 +2,52 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 jsobjinlines_h___
 #define jsobjinlines_h___
 
+#include "jsobj.h"
+
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
-#include "jsobj.h"
-#include "jsprobes.h"
 #include "jspropertytree.h"
 #include "jsproxy.h"
 #include "jsstr.h"
 #include "jstypedarray.h"
 #include "jswrapper.h"
 
+#include "builtin/Module.h"
 #include "gc/Barrier.h"
 #include "gc/Marking.h"
 #include "js/MemoryMetrics.h"
 #include "js/RootingAPI.h"
 #include "js/TemplateLib.h"
 #include "vm/BooleanObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/Shape.h"
 #include "vm/NumberObject.h"
+#include "vm/Probes.h"
 #include "vm/RegExpStatics.h"
 #include "vm/StringObject.h"
 
 #include "jsatominlines.h"
 #include "jscompartmentinlines.h"
 #include "jsfuninlines.h"
 #include "jsgcinlines.h"
 #include "jsinferinlines.h"
-#include "jsscriptinlines.h"
-
 #include "gc/Barrier-inl.h"
-
 #include "vm/ObjectImpl-inl.h"