Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Fri, 22 Jun 2012 14:26:15 -0700
changeset 112662 b09dce38ad34d43515a53a184e5e3ef27a361e89
parent 112661 618b5cc186a9a48261f70b26975d025eaf0d84a9 (current diff)
parent 102187 93439ef249799a7bcb7dcfe6c4e2de45108c8fd5 (diff)
child 112663 05a756967f2578dd49aae675ae18046feb3b1daa
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone16.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 from mozilla-central.
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
config/autoconf.mk.in
config/system-headers
configure.in
content/base/public/nsIContent.h
content/base/public/nsINode.h
content/base/src/nsFrameLoader.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsGenericElement.h
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLProtoImplField.cpp
content/xbl/src/nsXBLProtoImplField.h
docshell/base/nsDocShell.cpp
docshell/base/nsDocShellLoadTypes.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/indexedDB/IndexedDatabaseManager.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/plugins/base/nsNPAPIPlugin.cpp
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/base/nsPluginNativeWindowGtk2.cpp
dom/plugins/ipc/PluginInstanceChild.cpp
dom/plugins/ipc/PluginInstanceParent.cpp
dom/plugins/ipc/PluginModuleChild.cpp
dom/plugins/ipc/PluginModuleChild.h
dom/plugins/ipc/PluginModuleParent.cpp
js/src/config/system-headers
js/src/configure.in
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SemanticAnalysis.cpp
js/src/gc/Root.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfun.cpp
js/src/jsfuninlines.h
js/src/jsgc.cpp
js/src/jsinfer.cpp
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jswrapper.cpp
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/ScopeObject.cpp
js/xpconnect/idl/nsIXPConnect.idl
js/xpconnect/src/Makefile.in
js/xpconnect/src/XPCCallContext.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCInlines.h
js/xpconnect/src/XPCJSContextStack.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCThreadContext.cpp
js/xpconnect/src/XPCThrower.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/wrappers/XrayWrapper.cpp
layout/base/nsBidiPresUtils.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresShell.cpp
layout/generic/nsBulletFrame.cpp
layout/generic/nsBulletFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/style/nsAnimationManager.cpp
layout/style/nsCSSProps.cpp
layout/style/nsCSSRules.cpp
layout/style/test/Makefile.in
layout/style/test/property_database.js
layout/svg/base/src/nsSVGIntegrationUtils.cpp
layout/svg/base/src/nsSVGIntegrationUtils.h
layout/svg/base/src/nsSVGUtils.cpp
mobile/android/base/GeckoAppShell.java
modules/libpref/src/init/all.js
mozglue/android/APKOpen.cpp
netwerk/cache/nsCacheService.cpp
netwerk/protocol/http/SpdySession2.cpp
netwerk/protocol/http/SpdySession3.cpp
netwerk/protocol/http/nsAHttpTransaction.h
netwerk/protocol/http/nsHttpChannel.cpp
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/components/telemetry/TelemetryPing.js
toolkit/content/license.html
toolkit/mozapps/update/nsUpdateService.js
toolkit/profile/nsToolkitProfileService.cpp
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaUtils.mm
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
widget/xpwidgets/nsBaseWidget.cpp
widget/xpwidgets/nsBaseWidget.h
xpfe/appshell/src/nsContentTreeOwner.cpp
--- a/accessible/src/base/Logging.cpp
+++ b/accessible/src/base/Logging.cpp
@@ -275,16 +275,19 @@ LogShellLoadType(nsIDocShell* aDocShell)
       printf("stop content; ");
       break;
     case LOAD_STOP_CONTENT_AND_REPLACE:
       printf("stop content and replace; ");
       break;
     case LOAD_PUSHSTATE:
       printf("load pushstate; ");
       break;
+    case LOAD_REPLACE_BYPASS_CACHE:
+      printf("replace bypass cache; ");
+      break;
     case LOAD_ERROR_PAGE:
       printf("error page;");
       break;
     default:
       printf("unknown");
   }
 }
 
--- a/b2g/components/DirectoryProvider.js
+++ b/b2g/components/DirectoryProvider.js
@@ -17,24 +17,23 @@ function DirectoryProvider() {
 
 DirectoryProvider.prototype = {
   classID: Components.ID("{9181eb7c-6f87-11e1-90b1-4f59d80dd2e5}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]),
 
   getFile: function dp_getFile(prop, persistent) {
 #ifdef MOZ_WIDGET_GONK
-    let localProps = ["cachePDir", "webappsDir", "PrefD"];
+    let localProps = ["cachePDir", "webappsDir", "PrefD", "indexedDBPDir"];
     if (localProps.indexOf(prop) != -1) {
       prop.persistent = true;
       let file = Cc["@mozilla.org/file/local;1"]
                    .createInstance(Ci.nsILocalFile)
       file.initWithPath(LOCAL_DIR);
       return file;
     }
 #endif
 
     return null;
   }
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([DirectoryProvider]);
-
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -579,14 +579,14 @@ vbox[anonid=browserContainer][responsive
 }
 
 stack[anonid=browserStack][responsivemode] {
   -moz-transition-duration: 200ms;
   -moz-transition-timing-function: linear;
 }
 
 stack[anonid=browserStack][responsivemode] {
-  -moz-transition-properties: min-width, max-width, min-height, max-height;
+  -moz-transition-property: min-width, max-width, min-height, max-height;
 }
 
 stack[anonid=browserStack][responsivemode][notransition] {
   -moz-transition: none;
 }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1395,17 +1395,17 @@ var gBrowserInit = {
       document.getElementById("menu_devToolbar").hidden = false;
       document.getElementById("Tools:DevToolbar").removeAttribute("disabled");
 #ifdef MENUBAR_CAN_AUTOHIDE
       document.getElementById("appmenu_devToolbar").hidden = false;
 #endif
 
       // Show the toolbar if it was previously visible
       if (gPrefService.getBoolPref("devtools.toolbar.visible")) {
-        this.DeveloperToolbar.show();
+        DeveloperToolbar.show();
       }
     }
 
     // Enable Inspector?
     let enabled = gPrefService.getBoolPref("devtools.inspector.enabled");
     if (enabled) {
       document.getElementById("menu_pageinspect").hidden = false;
       document.getElementById("Tools:Inspect").removeAttribute("disabled");
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3046,23 +3046,23 @@
         <body><![CDATA[
           var numPinned = this.tabbrowser._numPinnedTabs;
           var doPosition = this.getAttribute("overflow") == "true" &&
                            numPinned > 0;
 
           if (doPosition) {
             this.setAttribute("positionpinnedtabs", "true");
 
-            let scrollButtonWidth = this.mTabstrip._scrollButtonDown.scrollWidth;
+            let scrollButtonWidth = this.mTabstrip._scrollButtonDown.getBoundingClientRect().width;
             let paddingStart = this.mTabstrip.scrollboxPaddingStart;
             let width = 0;
 
             for (let i = numPinned - 1; i >= 0; i--) {
               let tab = this.childNodes[i];
-              width += tab.scrollWidth;
+              width += tab.getBoundingClientRect().width;
               tab.style.MozMarginStart = - (width + scrollButtonWidth + paddingStart) + "px";
             }
 
             this.style.MozMarginStart = width + paddingStart + "px";
 
           } else {
             this.removeAttribute("positionpinnedtabs");
 
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -972,38 +972,26 @@ PropertiesView.prototype = {
     element.addProperties = this._addProperties.bind(this, element);
 
     // Setup the additional elements specific for a variable node.
     element.refresh(function() {
       let separatorLabel = document.createElement("label");
       let valueLabel = document.createElement("label");
       let title = element.getElementsByClassName("title")[0];
 
+      // Use attribute flags to specify the element type and tooltip text.
+      this._setAttributes(element, aName, aFlags);
+
       // Separator between the variable name and its value.
       separatorLabel.className = "plain";
       separatorLabel.setAttribute("value", ":");
 
       // The variable information (type, class and/or value).
       valueLabel.className = "value plain";
 
-      if (aFlags) {
-        // Use attribute flags to specify the element type and tooltip text.
-        let tooltip = [];
-
-        !aFlags.configurable ? element.setAttribute("non-configurable", "")
-                             : tooltip.push("configurable");
-        !aFlags.enumerable   ? element.setAttribute("non-enumerable", "")
-                             : tooltip.push("enumerable");
-        !aFlags.writable     ? element.setAttribute("non-writable", "")
-                             : tooltip.push("writable");
-
-        element.setAttribute("tooltiptext", tooltip.join(", "));
-      }
-      if (aName === "this") { element.setAttribute("self", ""); }
-
       // Handle the click event when pressing the element value label.
       valueLabel.addEventListener("click", this._activateElementInputMode.bind({
         scope: this,
         element: element,
         valueLabel: valueLabel
       }));
 
       // Maintain the symbolic name of the variable.
@@ -1025,16 +1013,46 @@ PropertiesView.prototype = {
       });
     }.bind(this));
 
     // Return the element for later use if necessary.
     return element;
   },
 
   /**
+   * Sets a variable's configurable, enumerable or writable attributes.
+   *
+   * @param object aVar
+   *        The object to set the attributes on.
+   * @param object aName
+   *        The varialbe name.
+   * @param object aFlags
+   *        Contains configurable, enumerable or writable flags.
+   */
+  _setAttributes: function DVP_setAttributes(aVar, aName, aFlags) {
+    if (aFlags) {
+      if (!aFlags.configurable) {
+        aVar.setAttribute("non-configurable", "");
+      }
+      if (!aFlags.enumerable) {
+        aVar.setAttribute("non-enumerable", "");
+      }
+      if (!aFlags.writable) {
+        aVar.setAttribute("non-writable", "");
+      }
+    }
+    if (aName === "this") {
+      aVar.setAttribute("self", "");
+    }
+    if (aName === "__proto__ ") {
+      aVar.setAttribute("proto", "");
+    }
+  },
+
+  /**
    * Sets the specific grip for a variable.
    * The grip should contain the value or the type & class, as defined in the
    * remote debugger protocol. For convenience, undefined and null are
    * both considered types.
    *
    * @param object aVar
    *        The parent variable element.
    * @param object aGrip
@@ -1204,16 +1222,19 @@ PropertiesView.prototype = {
 
     // Setup the additional elements specific for a variable node.
     element.refresh(function(pKey, pGrip) {
       let title = element.getElementsByClassName("title")[0];
       let nameLabel = title.getElementsByClassName("name")[0];
       let separatorLabel = document.createElement("label");
       let valueLabel = document.createElement("label");
 
+      // Use attribute flags to specify the element type and tooltip text.
+      this._setAttributes(element, pKey, aFlags);
+
       if ("undefined" !== typeof pKey) {
         // Use a key element to specify the property name.
         nameLabel.className = "key plain";
         nameLabel.setAttribute("value", pKey.trim());
         title.appendChild(nameLabel);
       }
       if ("undefined" !== typeof pGrip) {
         // Separator between the variable name and its value.
@@ -1223,31 +1244,16 @@ PropertiesView.prototype = {
         // Use a value element to specify the property value.
         valueLabel.className = "value plain";
         this._applyGrip(valueLabel, pGrip);
 
         title.appendChild(separatorLabel);
         title.appendChild(valueLabel);
       }
 
-      if (aFlags) {
-        // Use attribute flags to specify the element type and tooltip text.
-        let tooltip = [];
-
-        !aFlags.configurable ? element.setAttribute("non-configurable", "")
-                             : tooltip.push("configurable");
-        !aFlags.enumerable   ? element.setAttribute("non-enumerable", "")
-                             : tooltip.push("enumerable");
-        !aFlags.writable     ? element.setAttribute("non-writable", "")
-                             : tooltip.push("writable");
-
-        element.setAttribute("tooltiptext", tooltip.join(", "));
-      }
-      if (pKey === "__proto__ ") { element.setAttribute("proto", ""); }
-
       // Handle the click event when pressing the element value label.
       valueLabel.addEventListener("click", this._activateElementInputMode.bind({
         scope: this,
         element: element,
         valueLabel: valueLabel
       }));
 
       // Maintain the symbolic name of the property.
@@ -1493,16 +1499,17 @@ PropertiesView.prototype = {
     details.className = "details";
 
     // Add the click event handler for the title, or arrow and name.
     if (aClass === "scope") {
       title.addEventListener("click", function() { element.toggle(); }, false);
     } else {
       arrow.addEventListener("click", function() { element.toggle(); }, false);
       name.addEventListener("click", function() { element.toggle(); }, false);
+      name.addEventListener("mouseover", function() { element.updateTooltip(name); }, false);
     }
 
     title.appendChild(arrow);
     title.appendChild(name);
 
     element.appendChild(title);
     element.appendChild(details);
 
@@ -1724,16 +1731,62 @@ PropertiesView.prototype = {
           element.showArrow();
         } else {
           element.hideArrow();
         }
       }
     });
 
     /**
+     * Creates a tooltip for the element displaying certain attributes.
+     *
+     * @param object aAnchor
+     *        The element which will anchor the tooltip.
+     */
+    element.updateTooltip = function DVP_element_updateTooltip(aAnchor) {
+      let tooltip = document.getElementById("element-tooltip");
+      if (tooltip) {
+        document.documentElement.removeChild(tooltip);
+      }
+
+      tooltip = document.createElement("tooltip");
+      tooltip.id = "element-tooltip";
+
+      let configurableLabel = document.createElement("label");
+      configurableLabel.id = "configurableLabel";
+      configurableLabel.setAttribute("value", "configurable");
+
+      let enumerableLabel = document.createElement("label");
+      enumerableLabel.id = "enumerableLabel";
+      enumerableLabel.setAttribute("value", "enumerable");
+
+      let writableLabel = document.createElement("label");
+      writableLabel.id = "writableLabel";
+      writableLabel.setAttribute("value", "writable");
+
+      tooltip.setAttribute("orient", "horizontal")
+      tooltip.appendChild(configurableLabel);
+      tooltip.appendChild(enumerableLabel);
+      tooltip.appendChild(writableLabel);
+
+      if (element.hasAttribute("non-configurable")) {
+        configurableLabel.setAttribute("non-configurable", "");
+      }
+      if (element.hasAttribute("non-enumerable")) {
+        enumerableLabel.setAttribute("non-enumerable", "");
+      }
+      if (element.hasAttribute("non-writable")) {
+        writableLabel.setAttribute("non-writable", "");
+      }
+
+      document.documentElement.appendChild(tooltip);
+      aAnchor.setAttribute("tooltip", tooltip.id);
+    };
+
+    /**
      * Generic function refreshing the internal state of the element when
      * it's modified (e.g. a child detail, variable, property is added).
      *
      * @param function aFunction
      *        The function logic used to modify the internal state.
      * @param array aArguments
      *        Optional arguments array to be applied to aFunction.
      */
--- a/browser/devtools/layoutview/LayoutView.jsm
+++ b/browser/devtools/layoutview/LayoutView.jsm
@@ -289,17 +289,22 @@ LayoutView.prototype = {
     if (!node || !this.documentReady) return;
 
     // First, we update the first part of the layout view, with
     // the size of the element.
 
     let clientRect = node.getBoundingClientRect();
     let width = Math.round(clientRect.width);
     let height = Math.round(clientRect.height);
-    this.doc.querySelector("#element-size").textContent =  width + "x" + height;
+
+    let elt = this.doc.querySelector("#element-size");
+    let newLabel = width + "x" + height;
+    if (elt.textContent != newLabel) {
+      elt.textContent = newLabel;
+    }
 
     // If the view is closed, no need to do anything more.
     if (!this.isOpen) return;
 
     // We compute and update the values of margins & co.
     let style = this.browser.contentWindow.getComputedStyle(node);;
 
     for (let i in this.map) {
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -23,20 +23,20 @@ let ResponsiveUIManager = {
    * Check if the a tab is in a responsive mode.
    * Leave the responsive mode if active,
    * active the responsive mode if not active.
    *
    * @param aWindow the main window.
    * @param aTab the tab targeted.
    */
   toggle: function(aWindow, aTab) {
-    if (aTab.responsiveUI) {
-      aTab.responsiveUI.close();
+    if (aTab.__responsiveUI) {
+      aTab.__responsiveUI.close();
     } else {
-      aTab.responsiveUI = new ResponsiveUI(aWindow, aTab);
+      aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
     }
   },
 }
 
 let presets = [
   // Phones
   {key: "320x480", width: 320, height: 480},    // iPhone, B2G, with <meta viewport>
   {key: "360x640", width: 360, height: 640},    // Android 4, phones, with <meta viewport>
@@ -164,17 +164,17 @@ ResponsiveUI.prototype = {
     this.container.removeChild(this.toolbar);
     this.stack.removeChild(this.resizer);
     this.stack.removeChild(this.resizeBar);
 
     // Unset the responsive mode.
     this.container.removeAttribute("responsivemode");
     this.stack.removeAttribute("responsivemode");
 
-    delete this.tab.responsiveUI;
+    delete this.tab.__responsiveUI;
   },
 
   /**
    * Retrieve a preset from its key.
    *
    * @param aKey preset's key.
    * @returns the index of the preset, -1 if not found.
    */
--- a/browser/devtools/responsivedesign/test/browser_responsivecomputedview.js
+++ b/browser/devtools/responsivedesign/test/browser_responsivecomputedview.js
@@ -37,17 +37,17 @@ function test() {
   }
 
   function startTest() {
     document.getElementById("Tools:ResponsiveUI").doCommand();
     executeSoon(onUIOpen);
   }
 
   function onUIOpen() {
-    instance = gBrowser.selectedTab.responsiveUI;
+    instance = gBrowser.selectedTab.__responsiveUI;
     ok(instance, "instance of the module is attached to the tab.");
 
     instance.stack.setAttribute("notransition", "true");
     registerCleanupFunction(function() {
       instance.stack.removeAttribute("notransition");
     });
 
     instance.setSize(500, 500);
--- a/browser/devtools/responsivedesign/test/browser_responsiveruleview.js
+++ b/browser/devtools/responsivedesign/test/browser_responsiveruleview.js
@@ -32,17 +32,17 @@ function test() {
   }
 
   function startTest() {
     document.getElementById("Tools:ResponsiveUI").doCommand();
     executeSoon(onUIOpen);
   }
 
   function onUIOpen() {
-    instance = gBrowser.selectedTab.responsiveUI;
+    instance = gBrowser.selectedTab.__responsiveUI;
     ok(instance, "instance of the module is attached to the tab.");
 
     instance.stack.setAttribute("notransition", "true");
     registerCleanupFunction(function() {
       instance.stack.removeAttribute("notransition");
     });
 
     instance.setSize(500, 500);
--- a/browser/devtools/responsivedesign/test/browser_responsiveui.js
+++ b/browser/devtools/responsivedesign/test/browser_responsiveui.js
@@ -23,17 +23,17 @@ function test() {
   function onUIOpen() {
     // Is it open?
     let container = gBrowser.getBrowserContainer();
     is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
 
     // Menus are correctly updated?
     is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "true", "menus checked");
 
-    instance = gBrowser.selectedTab.responsiveUI;
+    instance = gBrowser.selectedTab.__responsiveUI;
     ok(instance, "instance of the module is attached to the tab.");
 
     instance.transitionsEnabled = false;
 
     testPresets();
   }
 
   function testPresets() {
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -678,9 +678,10 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 @BINPATH@/webapprt/chrome/webapprt.manifest
 @BINPATH@/webapprt/components/CommandLineHandler.js
 @BINPATH@/webapprt/components/ContentPermission.js
 @BINPATH@/webapprt/components/ContentPolicy.js
 @BINPATH@/webapprt/components/DirectoryProvider.js
 @BINPATH@/webapprt/components/components.manifest
 @BINPATH@/webapprt/defaults/preferences/prefs.js
 @BINPATH@/webapprt/modules/WebappRT.jsm
+@BINPATH@/webapprt/modules/WebappsHandler.jsm
 #endif
--- a/browser/locales/en-US/webapprt/webapp.properties
+++ b/browser/locales/en-US/webapprt/webapp.properties
@@ -18,8 +18,17 @@ hideApplicationCmdMac.label=Hide %S
 
 # LOCALIZATION NOTE (geolocation.title): %S will be replaced with the name of
 # the webapp.
 geolocation.title=%S - Share Location
 geolocation.description=Do you want to share your location?
 geolocation.sharelocation=Share Location
 geolocation.dontshare=Don't Share
 geolocation.remember=Remember my choice
+
+# LOCALIZATION NOTE (webapps.install.title): %S will be replaced with the name
+# of the webapp being installed.
+webapps.install.title=Install %S
+# LOCALIZATION NOTE (webapps.install.description): %S will be replaced with the
+# name of the webapp being installed.
+webapps.install.description=Do you want to install %S?
+webapps.install.install=Install App
+webapps.install.dontinstall=Don't Install
--- a/browser/modules/WebappsInstaller.jsm
+++ b/browser/modules/WebappsInstaller.jsm
@@ -111,17 +111,17 @@ function NativeApp(aData) {
 
   this.profileFolder = Services.dirsvc.get("ProfD", Ci.nsIFile);
 
   this.webappJson = {
     "registryDir": this.profileFolder.path,
     "app": app
   };
 
-  this.processFolder = Services.dirsvc.get("CurProcD", Ci.nsIFile);
+  this.runtimeFolder = Services.dirsvc.get("GreD", Ci.nsIFile);
 }
 
 #ifdef XP_WIN
 /*************************************
  * Windows app installer
  *
  * The Windows installation process will generate the following files:
  *
@@ -279,21 +279,21 @@ WinNativeApp.prototype = {
     this.installDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
     this.uninstallDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
   },
 
   /**
    * Copy the pre-built files into their destination folders.
    */
   _copyPrebuiltFiles: function() {
-    let webapprt = this.processFolder.clone();
+    let webapprt = this.runtimeFolder.clone();
     webapprt.append("webapprt-stub.exe");
     webapprt.copyTo(this.installDir, this.appNameAsFilename + ".exe");
 
-    let uninstaller = this.processFolder.clone();
+    let uninstaller = this.runtimeFolder.clone();
     uninstaller.append("webapp-uninstaller.exe");
     uninstaller.copyTo(this.uninstallDir, this.uninstallerFile.leafName);
   },
 
   /**
    * Creates the configuration files into their destination folders.
    */
   _createConfigFiles: function() {
@@ -308,17 +308,17 @@ WinNativeApp.prototype = {
 
     let factory = Cc["@mozilla.org/xpcom/ini-processor-factory;1"]
                     .getService(Ci.nsIINIParserFactory);
 
     let writer = factory.createINIParser(webappINI).QueryInterface(Ci.nsIINIParserWriter);
     writer.setString("Webapp", "Name", this.appName);
     writer.setString("Webapp", "Profile", this.installDir.leafName);
     writer.setString("Webapp", "Executable", this.appNameAsFilename);
-    writer.setString("WebappRT", "InstallDir", this.processFolder.path);
+    writer.setString("WebappRT", "InstallDir", this.runtimeFolder.path);
     writer.writeFile(null, Ci.nsIINIParserWriter.WRITE_UTF16);
 
     // ${UninstallDir}/shortcuts_log.ini
     let shortcutLogsINI = this.uninstallDir.clone().QueryInterface(Ci.nsILocalFile);
     shortcutLogsINI.append("shortcuts_log.ini");
 
     writer = factory.createINIParser(shortcutLogsINI).QueryInterface(Ci.nsIINIParserWriter);
     writer.setString("STARTMENU", "Shortcut0", this.appNameAsFilename + ".lnk");
@@ -529,17 +529,17 @@ MacNativeApp.prototype = {
       this.appProfileDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
 
     this.contentsDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
     this.macOSDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
     this.resourcesDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
   },
 
   _copyPrebuiltFiles: function() {
-    let webapprt = this.processFolder.clone();
+    let webapprt = this.runtimeFolder.clone();
     webapprt.append("webapprt-stub");
     webapprt.copyTo(this.macOSDir, "webapprt");
   },
 
   _createConfigFiles: function() {
     // ${ProfileDir}/webapp.json
     let configJson = this.appProfileDir.clone();
     configJson.append("webapp.json");
@@ -714,17 +714,17 @@ LinuxNativeApp.prototype = {
     }
   },
 
   _createDirectoryStructure: function() {
     this.installDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
   },
 
   _copyPrebuiltFiles: function() {
-    let webapprtPre = this.processFolder.clone();
+    let webapprtPre = this.runtimeFolder.clone();
     webapprtPre.append(this.webapprt.leafName);
     webapprtPre.copyTo(this.installDir, this.webapprt.leafName);
   },
 
   _createConfigFiles: function() {
     // ${InstallDir}/webapp.json
     let configJson = this.installDir.clone();
     configJson.append("webapp.json");
@@ -735,17 +735,17 @@ LinuxNativeApp.prototype = {
     webappINI.append("webapp.ini");
 
     let factory = Cc["@mozilla.org/xpcom/ini-processor-factory;1"]
                     .getService(Ci.nsIINIParserFactory);
 
     let writer = factory.createINIParser(webappINI).QueryInterface(Ci.nsIINIParserWriter);
     writer.setString("Webapp", "Name", this.appName);
     writer.setString("Webapp", "Profile", this.uniqueName);
-    writer.setString("WebappRT", "InstallDir", this.processFolder.path);
+    writer.setString("WebappRT", "InstallDir", this.runtimeFolder.path);
     writer.writeFile();
 
     // $XDG_DATA_HOME/applications/owa-<webappuniquename>.desktop
     this.desktopINI.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0755);
 
     writer = factory.createINIParser(this.desktopINI).QueryInterface(Ci.nsIINIParserWriter);
     writer.setString("Desktop Entry", "Name", this.appName);
     writer.setString("Desktop Entry", "Comment", this.shortDescription);
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -163,16 +163,26 @@
   content: " ";
   display: inline-block;
   width: 16px;
   height: 16px;
   background: url("chrome://browser/skin/identity-icons-https.png") no-repeat;
   opacity: 0.5;
 }
 
+#element-tooltip > label {
+  margin: 0 2px 0 2px;
+}
+
+#element-tooltip > label[non-enumerable],
+#element-tooltip > label[non-configurable],
+#element-tooltip > label[non-writable]{
+  text-decoration: line-through;
+}
+
 /**
  * Property values colors
  */
 
 .token-undefined {
   -moz-padding-start: 6px;
   color: #bbb;
 }
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -165,16 +165,26 @@
   content: " ";
   display: inline-block;
   width: 16px;
   height: 16px;
   background: url("chrome://browser/skin/identity-icons-https.png") no-repeat;
   opacity: 0.5;
 }
 
+#element-tooltip > label {
+  margin: 0 2px 0 2px;
+}
+
+#element-tooltip > label[non-enumerable],
+#element-tooltip > label[non-configurable],
+#element-tooltip > label[non-writable]{
+  text-decoration: line-through;
+}
+
 /**
  * Property values colors
  */
 
 .token-undefined {
   -moz-padding-start: 6px;
   color: #bbb;
 }
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -163,16 +163,26 @@
   content: " ";
   display: inline-block;
   width: 16px;
   height: 16px;
   background: url("chrome://browser/skin/identity-icons-https.png") no-repeat;
   opacity: 0.5;
 }
 
+#element-tooltip > label {
+  margin: 0 2px 0 2px;
+}
+
+#element-tooltip > label[non-enumerable],
+#element-tooltip > label[non-configurable],
+#element-tooltip > label[non-writable]{
+  text-decoration: line-through;
+}
+
 /**
  * Property values colors
  */
 
 .token-undefined {
   -moz-padding-start: 6px;
   color: #bbb;
 }
old mode 100644
new mode 100755
--- a/build/unix/build-clang/build-clang.py
+++ b/build/unix/build-clang/build-clang.py
@@ -8,16 +8,17 @@ moz_version = "moz0"
 
 ##############################################
 
 import os
 import os.path
 import shutil
 import tarfile
 import subprocess
+import platform
 
 def check_run(args):
     r = subprocess.call(args)
     assert r == 0
 
 def run_in(path, args):
     d = os.getcwd()
     os.chdir(path)
@@ -41,18 +42,17 @@ def with_env(env, f):
     old_env = os.environ.copy()
     os.environ.update(env)
     f()
     os.environ.clear()
     os.environ.update(old_env)
 
 def build_tar_package(tar, name, base, directory):
     name = os.path.realpath(name)
-    run_in(base, [tar, "-cjf", name, "--mtime=2012-01-01", "--owner=root",
-                  directory])
+    run_in(base, [tar, "-cjf", name, directory])
 
 def svn_co(url, directory, revision):
     check_run(["svn", "co", "-r", revision, url, directory])
 
 # The directories end up in the debug info, so the easy way of getting
 # a reproducible build is to run it in a know absolute directory.
 # We use a directory in /builds/slave because the mozilla infrastructure
 # cleans it up automatically.
@@ -69,47 +69,68 @@ def build_one_stage(env, stage_dir, is_s
     def f():
         build_one_stage_aux(stage_dir, is_stage_one)
     with_env(env, f)
 
 def build_one_stage_aux(stage_dir, is_stage_one):
     os.mkdir(stage_dir)
 
     build_dir = stage_dir + "/build"
-    inst_dir = stage_dir + "/inst"
+    inst_dir = stage_dir + "/clang"
 
     configure_opts = ["--enable-optimized",
                       "--prefix=%s" % inst_dir,
                       "--with-gcc-toolchain=/tools/gcc-4.5-0moz3"]
     if is_stage_one:
         configure_opts.append("--with-optimize-option=-O0")
 
     build_package(llvm_source_dir, build_dir, configure_opts)
 
+isDarwin = platform.system() == "Darwin"
+
 if not os.path.exists(source_dir):
     os.makedirs(source_dir)
     svn_co("http://llvm.org/svn/llvm-project/llvm/trunk",
            llvm_source_dir, llvm_revision)
     svn_co("http://llvm.org/svn/llvm-project/cfe/trunk",
            clang_source_dir, llvm_revision)
     svn_co("http://llvm.org/svn/llvm-project/compiler-rt/trunk",
            compiler_rt_source_dir, llvm_revision)
     os.symlink("../../clang", llvm_source_dir + "/tools/clang")
     os.symlink("../../compiler-rt", llvm_source_dir + "/projects/compiler-rt")
-    patch("old-ld-hack.patch", 1, llvm_source_dir)
-    patch("compiler-rt-gnu89-inline.patch", 0, compiler_rt_source_dir)
+    if isDarwin:
+        patch("clang-no-ios.patch", 0, clang_source_dir)
+        patch("compiler-rt-no-ios.patch", 0, compiler_rt_source_dir)
+    else:
+        patch("old-ld-hack.patch", 1, llvm_source_dir)
+        patch("compiler-rt-gnu89-inline.patch", 0, compiler_rt_source_dir)
 
 if os.path.exists(build_dir):
     shutil.rmtree(build_dir)
 os.makedirs(build_dir)
 
 stage1_dir = build_dir + '/stage1'
 stage1_inst_dir = stage1_dir + '/clang'
-build_one_stage({"CC"  : "/tools/gcc-4.5-0moz3/bin/gcc -static-libgcc",
-                 "CXX" : "/tools/gcc-4.5-0moz3/bin/g++ -static-libgcc -static-libstdc++"},
+
+if isDarwin:
+    extra_cflags = ""
+    extra_cxxflags = ""
+    cc = "/usr/bin/clang"
+    cxx = "/usr/bin/clang++"
+else:
+    extra_cflags = "-static-libgcc"
+    extra_cxxflags = "-static-libgcc -static-libstdc++"
+    cc = "/tools/gcc-4.5-0moz3/bin/gcc %s" % extra_cflags
+    cxx = "/tools/gcc-4.5-0moz3/bin/g++ %s" % extra_cxxflags
+
+build_one_stage({"CC"  : cc,
+                 "CXX" : cxx },
                 stage1_dir, True)
 
+if not isDarwin:
+    extra_cflags += " -fgnu89-inline"
+
 stage2_dir = build_dir + '/stage2'
-build_one_stage({"CC"  : stage1_inst_dir + "/bin/clang -static-libgcc -fgnu89-inline",
-                 "CXX" : stage1_inst_dir + "/bin/clang++ -static-libgcc -static-libstdc++"},
+build_one_stage({"CC"  : stage1_inst_dir + "/bin/clang %s" % extra_cflags,
+                 "CXX" : stage1_inst_dir + "/bin/clang++ %s" % extra_cxxflags},
                 stage2_dir, False)
 
-build_tar_package("/bin/tar", "clang.tar.bz2", stage3_dir, "clang")
+build_tar_package("tar", "clang.tar.bz2", stage2_dir, "clang")
new file mode 100644
--- /dev/null
+++ b/build/unix/build-clang/clang-no-ios.patch
@@ -0,0 +1,15 @@
+Index: runtime/compiler-rt/Makefile
+===================================================================
+--- runtime/compiler-rt/Makefile	(revision 157958)
++++ runtime/compiler-rt/Makefile	(working copy)
+@@ -74,8 +74,8 @@
+ ifeq ($(OS),Darwin)
+ RuntimeDirs += darwin
+ RuntimeLibrary.darwin.Configs := \
+-	eprintf 10.4 osx ios cc_kext \
+-	asan_osx profile_osx profile_ios
++	eprintf 10.4 osx  \
++	asan_osx profile_osx
+ endif
+ 
+ # On Linux, include a library which has all the runtime functions.
new file mode 100644
--- /dev/null
+++ b/build/unix/build-clang/compiler-rt-no-ios.patch
@@ -0,0 +1,29 @@
+Index: make/platform/clang_darwin.mk
+===================================================================
+--- make/platform/clang_darwin.mk	(revision 157958)
++++ make/platform/clang_darwin.mk	(working copy)
+@@ -47,7 +47,7 @@
+ # Configuration for targetting iOS, for some ARMv6 functions, which must be
+ # in the same linkage unit, and for a couple of other functions that didn't
+ # make it into libSystem.
+-Configs += ios
++#Configs += ios
+ UniversalArchs.ios := $(call CheckArches,i386 x86_64 armv6 armv7,ios)
+ 
+ # Configuration for targetting OSX. These functions may not be in libSystem
+@@ -56,13 +56,13 @@
+ UniversalArchs.osx := $(call CheckArches,i386 x86_64,osx)
+ 
+ # Configuration for use with kernel/kexts.
+-Configs += cc_kext
++#Configs += cc_kext
+ UniversalArchs.cc_kext := $(call CheckArches,armv6 armv7 i386 x86_64,cc_kext)
+ 
+ # Configurations which define the profiling support functions.
+ Configs += profile_osx
+ UniversalArchs.profile_osx := $(call CheckArches,i386 x86_64,profile_osx)
+-Configs += profile_ios
++#Configs += profile_ios
+ UniversalArchs.profile_ios := $(call CheckArches,i386 x86_64 armv6 armv7,profile_ios)
+ 
+ # Configurations which define the ASAN support functions.
new file mode 100644
--- /dev/null
+++ b/build/unix/build-clang/setup.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+rm -rf clang
+tar -xjf clang.tar.bz2
--- a/build/unix/stdc++compat/stdc++compat.cpp
+++ b/build/unix/stdc++compat/stdc++compat.cpp
@@ -21,32 +21,37 @@
 namespace std {
 #if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 9)
     /* Instantiate these templates to avoid GLIBCXX_3.4.9 symbol versions */
     template ostream& ostream::_M_insert(double);
     template ostream& ostream::_M_insert(long);
     template ostream& ostream::_M_insert(unsigned long);
     template ostream& ostream::_M_insert(long long);
     template ostream& ostream::_M_insert(unsigned long long);
+    template ostream& ostream::_M_insert(bool);
     template ostream& ostream::_M_insert(const void*);
     template ostream& __ostream_insert(ostream&, const char*, streamsize);
     template istream& istream::_M_extract(double&);
+    template istream& istream::_M_extract(float&);
+    template istream& istream::_M_extract(unsigned int&);
+    template istream& istream::_M_extract(unsigned long&);
 #endif
 #if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14)
     /* Instantiate these templates to avoid GLIBCXX_3.4.14 symbol versions
      * depending on optimization level */
     template char *string::_S_construct_aux_2(size_type, char, allocator<char> const&);
 #ifdef _GLIBCXX_USE_WCHAR_T
     template wchar_t *wstring::_S_construct_aux_2(size_type, wchar_t, allocator<wchar_t> const&);
 #endif /* _GLIBCXX_USE_WCHAR_T */
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
     template string::basic_string(string&&);
     template string& string::operator=(string&&);
     template wstring::basic_string(wstring&&);
     template wstring& wstring::operator=(wstring&&);
+    template string& string::assign(string&&);
     template wstring& wstring::assign(wstring&&);
 #endif /* __GXX_EXPERIMENTAL_CXX0X__ */
 #endif /* (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5) */
 }
 
 namespace std __attribute__((visibility("default"))) {
 #if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14)
     /* Hack to avoid GLIBCXX_3.4.14 symbol versions */
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -132,16 +132,17 @@ MOZ_MEDIA = @MOZ_MEDIA@
 MOZ_VORBIS = @MOZ_VORBIS@
 MOZ_TREMOR = @MOZ_TREMOR@
 MOZ_NO_THEORA_ASM = @MOZ_NO_THEORA_ASM@
 MOZ_OPUS = @MOZ_OPUS@
 MOZ_WEBM = @MOZ_WEBM@
 MOZ_MEDIA_PLUGINS = @MOZ_MEDIA_PLUGINS@
 MOZ_OMX_PLUGIN = @MOZ_OMX_PLUGIN@
 MOZ_GSTREAMER = @MOZ_GSTREAMER@
+MOZ_VP8 = @MOZ_VP8@
 MOZ_VP8_ERROR_CONCEALMENT = @MOZ_VP8_ERROR_CONCEALMENT@
 MOZ_VP8_ENCODER = @MOZ_VP8_ENCODER@
 VPX_AS = @VPX_AS@
 VPX_ASFLAGS = @VPX_ASFLAGS@
 VPX_DASH_C_FLAG = @VPX_DASH_C_FLAG@
 VPX_AS_CONVERSION = @VPX_AS_CONVERSION@
 VPX_ASM_SUFFIX = @VPX_ASM_SUFFIX@
 VPX_X86_ASM = @VPX_X86_ASM@
@@ -165,16 +166,17 @@ MOZ_DIRECTX_SDK_PATH = @MOZ_DIRECTX_SDK_
 MOZ_DIRECTX_SDK_CPU_SUFFIX = @MOZ_DIRECTX_SDK_CPU_SUFFIX@
 MOZ_D3DX9_VERSION = @MOZ_D3DX9_VERSION@
 MOZ_D3DX9_CAB = @MOZ_D3DX9_CAB@
 MOZ_D3DCOMPILER_CAB = @MOZ_D3DCOMPILER_CAB@
 MOZ_D3DX9_DLL = @MOZ_D3DX9_DLL@
 MOZ_D3DCOMPILER_DLL = @MOZ_D3DCOMPILER_DLL@
 MOZ_GL_PROVIDER = @MOZ_GL_PROVIDER@
 MOZ_GL_DEFAULT_PROVIDER = @MOZ_GL_DEFAULT_PROVIDER@
+MOZ_WEBRTC = @MOZ_WEBRTC@
 
 
 JAVA=@JAVA@
 JAVAC=@JAVAC@
 JAR=@JAR@
 
 TAR=@TAR@
 
--- a/config/config.mk
+++ b/config/config.mk
@@ -51,16 +51,18 @@ check-variable = $(if $(filter-out 0 1,$
 core_abspath = $(if $(findstring :,$(1)),$(1),$(if $(filter /%,$(1)),$(1),$(CURDIR)/$(1)))
 core_realpath = $(if $(realpath $(1)),$(realpath $(1)),$(call core_abspath,$(1)))
 
 nullstr :=
 space :=$(nullstr) # EOL
 
 core_winabspath = $(firstword $(subst /, ,$(call core_abspath,$(1)))):$(subst $(space),,$(patsubst %,\\%,$(wordlist 2,$(words $(subst /, ,$(call core_abspath,$(1)))), $(strip $(subst /, ,$(call core_abspath,$(1)))))))
 
+RM = rm -f
+
 # LIBXUL_DIST is not defined under js/src, thus we make it mean DIST there.
 LIBXUL_DIST ?= $(DIST)
 
 # FINAL_TARGET specifies the location into which we copy end-user-shipped
 # build products (typelibs, components, chrome).
 #
 # If XPI_NAME is set, the files will be shipped to $(DIST)/xpi-stage/$(XPI_NAME)
 # If DIST_SUBDIR is set, the files will be shipped to $(DIST)/$(DIST_SUBDIR)
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -628,17 +628,20 @@ include $(topsrcdir)/config/makefiles/ta
 
 ifneq (,$(filter-out %.$(LIB_SUFFIX),$(SHARED_LIBRARY_LIBS)))
 $(error SHARED_LIBRARY_LIBS must contain .$(LIB_SUFFIX) files only)
 endif
 
 HOST_LIBS_DEPS = $(filter %.$(LIB_SUFFIX),$(HOST_LIBS))
 
 # Dependencies which, if modified, should cause everything to rebuild
-GLOBAL_DEPS += Makefile Makefile.in $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk
+GLOBAL_DEPS += Makefile $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk
+ifndef NO_MAKEFILE_RULE
+GLOBAL_DEPS += Makefile.in
+endif
 
 ##############################################
 include $(topsrcdir)/config/makefiles/target_libs.mk
 
 ##############################################
 ifndef NO_PROFILE_GUIDED_OPTIMIZE
 ifdef MOZ_PROFILE_USE
 ifeq ($(OS_ARCH)_$(GNU_CC), WINNT_)
@@ -1142,26 +1145,30 @@ endif
 	$(JAR) cf $@ -C $(_JAVA_DIR) .
 
 GARBAGE_DIRS += $(_JAVA_DIR)
 
 ###############################################################################
 # Update Makefiles
 ###############################################################################
 
+ifndef NO_MAKEFILE_RULE
 # Note: Passing depth to make-makefile is optional.
 #       It saves the script some work, though.
 Makefile: Makefile.in
 	@$(PERL) $(AUTOCONF_TOOLS)/make-makefile -t $(topsrcdir) -d $(DEPTH)
+endif
 
+ifndef NO_SUBMAKEFILES_RULE
 ifdef SUBMAKEFILES
 # VPATH does not work on some machines in this case, so add $(srcdir)
 $(SUBMAKEFILES): % : $(srcdir)/%.in
 	$(PERL) $(AUTOCONF_TOOLS)/make-makefile -t $(topsrcdir) -d $(DEPTH) $@
 endif
+endif
 
 ifdef AUTOUPDATE_CONFIGURE
 $(topsrcdir)/configure: $(topsrcdir)/configure.in
 	(cd $(topsrcdir) && $(AUTOCONF)) && (cd $(DEPTH) && ./config.status --recheck)
 endif
 
 $(DEPTH)/config/autoconf.mk: $(topsrcdir)/config/autoconf.mk.in
 	cd $(DEPTH) && CONFIG_HEADERS= CONFIG_FILES=config/autoconf.mk ./config.status
--- a/config/system-headers
+++ b/config/system-headers
@@ -1054,8 +1054,10 @@ ogg/ogg.h
 ogg/os_types.h
 nestegg/nestegg.h
 cubeb/cubeb.h
 #endif
 gst/gst.h
 gst/app/gstappsink.h
 gst/app/gstappsrc.h
 gst/video/video.h
+sys/msg.h
+sys/ipc.h
--- a/configure.in
+++ b/configure.in
@@ -490,17 +490,17 @@ case "$target" in
 
         AC_LANG_CPLUSPLUS
         AC_TRY_COMPILE([#include <new.h>],
             [ unsigned *test = new unsigned(42); ],,
             AC_MSG_ERROR([\$(CXX) test failed.  You must have MS VC++ in your path to build.]) )
         AC_LANG_RESTORE
 
         changequote(,)
-        _MSVC_VER_FILTER='s|.* ([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?).*|\1|p'
+        _MSVC_VER_FILTER='s|.*[^!-~]([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?).*|\1|p'
         changequote([,])
 
         # Determine compiler version
         CC_VERSION=`"${CC}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"`
         _CC_MAJOR_VERSION=`echo ${CC_VERSION} | $AWK -F\. '{ print $1 }'`
         _CC_MINOR_VERSION=`echo ${CC_VERSION} | $AWK -F\. '{ print $2 }'`
         _CC_RELEASE=`echo ${CC_VERSION} | $AWK -F\. '{ print $3 }'`
         _CC_BUILD=`echo ${CC_VERSION} | $AWK -F\. '{ print $4 }'`
@@ -517,28 +517,32 @@ case "$target" in
             dnl Require VC8SP1 or newer.
             dnl VC8 is 14.00.50727.42, VC8SP1 is 14.00.50727.762.
             if test "$_CC_RELEASE" -lt 50727 -o \
                     \( "$_CC_RELEASE" -eq 50727 -a "$_CC_BUILD" -lt 762 \); then
               AC_MSG_ERROR([This version ($CC_VERSION) of the MSVC compiler is unsupported. You probably need to install Service Pack 1 of Visual Studio 2005. See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
             fi
 
             _CC_SUITE=8
+            _MSVS_VERSION=2005
             AC_DEFINE(_CRT_SECURE_NO_DEPRECATE)
             AC_DEFINE(_CRT_NONSTDC_NO_DEPRECATE)
         elif test "$_CC_MAJOR_VERSION" = "15"; then
             _CC_SUITE=9
+            _MSVS_VERSION=2008
             AC_DEFINE(_CRT_SECURE_NO_WARNINGS)
             AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
         elif test "$_CC_MAJOR_VERSION" = "16"; then
             _CC_SUITE=10
+            _MSVS_VERSION=2010
             AC_DEFINE(_CRT_SECURE_NO_WARNINGS)
             AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
         elif test "$_CC_MAJOR_VERSION" = "17"; then
             _CC_SUITE=11
+            _MSVS_VERSION=2011
             AC_DEFINE(_CRT_SECURE_NO_WARNINGS)
             AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
         else
             AC_MSG_ERROR([This version ($CC_VERSION) of the MSVC compiler is unsupported. See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
         fi
 
         AC_DEFINE(HAVE_SEH_EXCEPTIONS)
 
@@ -562,17 +566,17 @@ case "$target" in
         dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool',
         dnl not something else like "magnetic tape manipulation utility".
         MSMT_TOOL=`mt 2>&1|grep 'Microsoft (R) Manifest Tool'`
         if test -z "$MSMT_TOOL"; then
           AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.])
         fi
 
         changequote(,)
-        _MSMT_VER_FILTER='s|.* \([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p'
+        _MSMT_VER_FILTER='s|.*[^!-~]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p'
         changequote([,])
         MSMANIFEST_TOOL_VERSION=`echo ${MSMT_TOOL}|sed -ne "$_MSMT_VER_FILTER"`
         if test -z "$MSMANIFEST_TOOL_VERSION"; then
           AC_MSG_WARN([Unknown version of the Microsoft (R) Manifest Tool.])
         fi
 
         MSMANIFEST_TOOL=1
         unset MSMT_TOOL
@@ -4245,19 +4249,22 @@ MOZ_SYDNEYAUDIO=
 MOZ_SPEEX_RESAMPLER=1
 MOZ_CUBEB=
 MOZ_VORBIS=
 MOZ_TREMOR=
 MOZ_WAVE=1
 MOZ_MEDIA=
 MOZ_OPUS=1
 MOZ_WEBM=1
+MOZ_WEBRTC=
+MOZ_WEBRTC_SIGNALING=
 MOZ_MEDIA_PLUGINS=
 MOZ_MEDIA_NAVIGATOR=
 MOZ_OMX_PLUGIN=
+MOZ_VP8=
 MOZ_VP8_ERROR_CONCEALMENT=
 MOZ_VP8_ENCODER=
 VPX_AS=
 VPX_ASFLAGS=
 VPX_AS_DASH_C_FLAG=
 VPX_AS_CONVERSION=
 VPX_ASM_SUFFIX=
 VPX_X86_ASM=
@@ -5267,16 +5274,35 @@ MOZ_ARG_DISABLE_BOOL(printing,
     NS_PRINTING=1)
 
 if test "$NS_PRINTING"; then
     AC_DEFINE(NS_PRINTING)
     AC_DEFINE(NS_PRINT_PREVIEW)
 fi
 
 dnl ========================================================
+dnl = Enable WebRTC code
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(webrtc,
+[  --enable-webrtc        Enable support for WebRTC],
+    MOZ_WEBRTC=1,
+    MOZ_WEBRTC=)
+
+if test -n "$MOZ_WEBRTC"; then
+    AC_DEFINE(MOZ_WEBRTC)
+    MOZ_MEDIA=1
+    MOZ_RAW=1
+    MOZ_VP8=1
+    MOZ_VP8_ENCODER=1
+    MOZ_VP8_ERROR_CONCEALMENT=1
+fi
+
+AC_SUBST(MOZ_WEBRTC)
+
+dnl ========================================================
 dnl = Enable Raw Codecs
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(raw,
 [  --enable-raw           Enable support for RAW media],
     MOZ_RAW=1,
     MOZ_RAW=)
 
 if test -n "$MOZ_RAW"; then
@@ -5341,16 +5367,21 @@ MOZ_ARG_DISABLE_BOOL(opus,
 dnl ========================================================
 dnl = Disable VP8 decoder support
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(webm,
 [  --disable-webm          Disable support for WebM media (VP8 video and Vorbis audio)],
     MOZ_WEBM=,
     MOZ_WEBM=1)
 
+if test -n "$MOZ_WEBM"; then
+    AC_DEFINE(MOZ_WEBM)
+    MOZ_VP8=1
+fi;
+
 dnl ========================================================
 dnl = Disable media plugin support
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(media-plugins,
 [  --enable-media-plugins  Enable support for media plugins],
     MOZ_MEDIA_PLUGINS=1,
     MOZ_MEDIA_PLUGINS=)
 
@@ -5392,18 +5423,18 @@ dnl system libvpx Support
 dnl ========================================================
 MOZ_ARG_WITH_BOOL(system-libvpx,
 [  --with-system-libvpx    Use system libvpx (located with pkgconfig)],
     MOZ_NATIVE_LIBVPX=1)
 
 MOZ_LIBVPX_INCLUDES=
 MOZ_LIBVPX_LIBS=
 
-if test -n "$MOZ_WEBM"; then
-    AC_DEFINE(MOZ_WEBM)
+if test -n "$MOZ_VP8"; then
+    AC_DEFINE(MOZ_VP8)
     if test -n "$MOZ_VP8_ERROR_CONCEALMENT" ; then
         AC_DEFINE(MOZ_VP8_ERROR_CONCEALMENT)
     fi
     if test -n "$MOZ_VP8_ENCODER" ; then
         AC_DEFINE(MOZ_VP8_ENCODER)
     fi
 
     if test -n "$MOZ_NATIVE_LIBVPX"; then
@@ -5420,29 +5451,31 @@ if test -n "$MOZ_WEBM"; then
          [AC_MSG_ERROR([--with-system-libvpx requested but symbol vpx_codec_dec_init_ver not found])])
     fi
 fi
 
 AC_SUBST(MOZ_NATIVE_LIBVPX)
 AC_SUBST(MOZ_LIBVPX_INCLUDES)
 AC_SUBST(MOZ_LIBVPX_LIBS)
 
-if test -n "$MOZ_WEBM" -a -z "$MOZ_NATIVE_LIBVPX"; then
+if test "$MOZ_WEBM"; then
     MOZ_SYDNEYAUDIO=1
     MOZ_CUBEB=1
     MOZ_MEDIA=1
     case "$target_cpu" in
     arm*)
         MOZ_TREMOR=1
     ;;
     *)
         MOZ_VORBIS=1
     ;;
     esac
-
+fi
+
+if test -n "$MOZ_VP8" -a -z "$MOZ_NATIVE_LIBVPX"; then
 
     dnl Detect if we can use an assembler to compile optimized assembly for libvpx.
     dnl We currently require yasm on all x86 platforms and require yasm 1.1.0 on Win32.
     dnl We currently require gcc on all arm platforms.
     VPX_AS=$YASM
     VPX_ASM_SUFFIX=asm
     VPX_NEED_OBJ_INT_EXTRACT=
 
@@ -8583,16 +8616,17 @@ AC_SUBST(MOZ_WAVE)
 AC_SUBST(MOZ_VORBIS)
 AC_SUBST(MOZ_TREMOR)
 AC_SUBST(MOZ_OPUS)
 AC_SUBST(MOZ_WEBM)
 AC_SUBST(MOZ_MEDIA_PLUGINS)
 AC_SUBST(MOZ_OMX_PLUGIN)
 AC_SUBST(MOZ_VP8_ERROR_CONCEALMENT)
 AC_SUBST(MOZ_VP8_ENCODER)
+AC_SUBST(MOZ_VP8)
 AC_SUBST(MOZ_OGG)
 AC_SUBST(MOZ_ALSA_LIBS)
 AC_SUBST(MOZ_ALSA_CFLAGS)
 AC_SUBST(VPX_AS)
 AC_SUBST(VPX_ASFLAGS)
 AC_SUBST(VPX_DASH_C_FLAG)
 AC_SUBST(VPX_AS_CONVERSION)
 AC_SUBST(VPX_ASM_SUFFIX)
@@ -8860,16 +8894,62 @@ fi
 rm conftest.sh
 
 echo $MAKEFILES > unallmakefiles
 
 mv -f config/autoconf.mk config/autoconf.mk.orig 2> /dev/null
 
 AC_OUTPUT($MAKEFILES)
 
+# Generate Makefiles for WebRTC directly from .gyp files
+if test "${OS_TARGET}" = "WINNT"; then
+   if test "$HAVE_64BIT_OS"; then
+      OS_BITS=64
+   else
+      OS_BITS=32
+   fi
+   EXTRA_GYP_DEFINES="-D MSVS_VERSION=${_MSVS_VERSION} -D MSVS_OS_BITS=${OS_BITS}"
+fi
+
+if test -n "$MOZ_WEBRTC"; then
+   AC_MSG_RESULT("generating WebRTC Makefiles...")
+
+   GYP_WEBRTC_OPTIONS="--format=mozmake -D build_with_mozilla=1 -D enable_protobuf=0 -D include_internal_video_render=0 ${EXTRA_GYP_DEFINES} --depth=${srcdir}/media/webrtc/trunk --toplevel-dir=${srcdir} -G OBJDIR=${_objdir}"
+
+   $PYTHON ${srcdir}/media/webrtc/trunk/build/gyp_chromium \
+     $GYP_WEBRTC_OPTIONS \
+     --generator-output=${_objdir}/media/webrtc/trunk \
+     ${srcdir}/media/webrtc/trunk/peerconnection.gyp
+   if test "$?" != 0; then
+      AC_MSG_ERROR([failed to generate WebRTC Makefiles])
+   fi
+
+   # XXX disable until we land the tranche with signaling
+   if test -n "$MOZ_WEBRTC_SIGNALING"; then
+     AC_MSG_RESULT("generating WebRTC/Signaling Makefiles...")
+     $PYTHON ${srcdir}/media/webrtc/trunk/build/gyp_chromium \
+       $GYP_WEBRTC_OPTIONS \
+       --generator-output=${_objdir}/media/webrtc/signaling \
+       ${srcdir}/media/webrtc/signaling/signaling.gyp
+     if test "$?" != 0; then
+        AC_MSG_ERROR([failed to generate WebRTC/Signaling Makefiles])
+     fi
+   fi
+
+   AC_MSG_RESULT("generating gtest Makefiles...")
+   # Ok to pass some extra -D's that are ignored here
+   $PYTHON ${srcdir}/media/webrtc/trunk/build/gyp_chromium \
+     $GYP_WEBRTC_OPTIONS \
+     --generator-output=${_objdir}/media/webrtc/trunk/testing/ \
+     ${srcdir}/media/webrtc/trunk/testing/gtest.gyp
+   if test "$?" != 0; then
+      AC_MSG_ERROR([failed to generate gtest Makefiles])
+   fi
+fi
+
 # Populate the virtualenv
 AC_MSG_RESULT([Populating Python virtualenv])
 $MAKE -C build/virtualenv MACOSX_DEPLOYMENT_TARGET=  || exit 1
 
 # Generate a JSON config file for unittest harnesses etc to read
 # build configuration details from in a standardized way.
 OS_TARGET=${OS_TARGET} TARGET_CPU=${TARGET_CPU} MOZ_DEBUG=${MOZ_DEBUG} \
 MOZ_WIDGET_TOOLKIT=${MOZ_WIDGET_TOOLKIT} UNIVERSAL_BINARY=${UNIVERSAL_BINARY} \
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -246,16 +246,74 @@ public:
    * the term, i.e. not in an XHTML/XML document).
    */
   inline bool IsInHTMLDocument() const
   {
     return OwnerDoc()->IsHTML();
   }
 
   /**
+   * Get the namespace that this element's tag is defined in
+   * @return the namespace
+   */
+  inline PRInt32 GetNameSpaceID() const
+  {
+    return mNodeInfo->NamespaceID();
+  }
+
+  /**
+   * Get the NodeInfo for this element
+   * @return the nodes node info
+   */
+  inline nsINodeInfo* NodeInfo() const
+  {
+    return mNodeInfo;
+  }
+
+  inline bool IsInNamespace(PRInt32 aNamespace) const
+  {
+    return mNodeInfo->NamespaceID() == aNamespace;
+  }
+
+  inline bool IsHTML() const
+  {
+    return IsInNamespace(kNameSpaceID_XHTML);
+  }
+
+  inline bool IsHTML(nsIAtom* aTag) const
+  {
+    return mNodeInfo->Equals(aTag, kNameSpaceID_XHTML);
+  }
+
+  inline bool IsSVG() const
+  {
+    return IsInNamespace(kNameSpaceID_SVG);
+  }
+
+  inline bool IsSVG(nsIAtom* aTag) const
+  {
+    return mNodeInfo->Equals(aTag, kNameSpaceID_SVG);
+  }
+
+  inline bool IsXUL() const
+  {
+    return IsInNamespace(kNameSpaceID_XUL);
+  }
+
+  inline bool IsMathML() const
+  {
+    return IsInNamespace(kNameSpaceID_MathML);
+  }
+
+  inline bool IsMathML(nsIAtom* aTag) const
+  {
+    return mNodeInfo->Equals(aTag, kNameSpaceID_MathML);
+  }
+
+  /**
    * Returns an atom holding the name of the attribute of type ID on
    * this content node (if applicable).  Returns null for non-element
    * content nodes.
    */
   virtual nsIAtom *GetIDAttributeName() const = 0;
 
   /**
    * Normalizes an attribute name and returns it as a nodeinfo if an attribute
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -472,84 +472,26 @@ public:
     return mNodeInfo->NodeName();
   }
   const nsString& LocalName() const
   {
     return mNodeInfo->LocalName();
   }
 
   /**
-   * Get the namespace that this element's tag is defined in
-   * @return the namespace
-   */
-  PRInt32 GetNameSpaceID() const
-  {
-    return mNodeInfo->NamespaceID();
-  }
-
-  /**
    * Get the tag for this element. This will always return a non-null atom
    * pointer (as implied by the naming of the method).  For elements this is
    * the non-namespaced tag, and for other nodes it's something like "#text",
    * "#comment", "#document", etc.
    */
   nsIAtom* Tag() const
   {
     return mNodeInfo->NameAtom();
   }
 
-  /**
-   * Get the NodeInfo for this element
-   * @return the nodes node info
-   */
-  nsINodeInfo* NodeInfo() const
-  {
-    return mNodeInfo;
-  }
-
-  bool IsInNamespace(PRInt32 aNamespace) const
-  {
-    return mNodeInfo->NamespaceID() == aNamespace;
-  }
-
-  bool IsHTML() const
-  {
-    return IsInNamespace(kNameSpaceID_XHTML);
-  }
-
-  bool IsHTML(nsIAtom* aTag) const
-  {
-    return mNodeInfo->Equals(aTag, kNameSpaceID_XHTML);
-  }
-
-  bool IsSVG() const
-  {
-    return IsInNamespace(kNameSpaceID_SVG);
-  }
-
-  bool IsSVG(nsIAtom* aTag) const
-  {
-    return mNodeInfo->Equals(aTag, kNameSpaceID_SVG);
-  }
-
-  bool IsXUL() const
-  {
-    return IsInNamespace(kNameSpaceID_XUL);
-  }
-
-  bool IsMathML() const
-  {
-    return IsInNamespace(kNameSpaceID_MathML);
-  }
-
-  bool IsMathML(nsIAtom* aTag) const
-  {
-    return mNodeInfo->Equals(aTag, kNameSpaceID_MathML);
-  }
-
   nsINode*
   InsertBefore(nsINode *aNewChild, nsINode *aRefChild, nsresult *aReturn)
   {
     return ReplaceOrInsertBefore(false, aNewChild, aRefChild, aReturn);
   }
   nsINode*
   ReplaceChild(nsINode *aNewChild, nsINode *aOldChild, nsresult *aReturn)
   {
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -1500,23 +1500,16 @@ nsFrameLoader::MaybeCreateDocShell()
       // handler from it and use that for our shell as well.
 
       parentShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
     }
 
     mDocShell->SetChromeEventHandler(chromeEventHandler);
   }
 
-  nsCOMPtr<nsIObserverService> os = services::GetObserverService();
-  if (OwnerIsBrowserFrame() && os) {
-    mDocShell->SetIsBrowserFrame(true);
-    os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
-                        "in-process-browser-frame-shown", NULL);
-  }
-
   // This is nasty, this code (the do_GetInterface(mDocShell) below)
   // *must* come *after* the above call to
   // mDocShell->SetChromeEventHandler() for the global window to get
   // the right chrome event handler.
 
   // Tell the window about the frame that hosts it.
   nsCOMPtr<nsIDOMElement> frame_element(do_QueryInterface(mOwnerContent));
   NS_ASSERTION(frame_element, "frame loader owner element not a DOM element!");
@@ -1533,16 +1526,32 @@ nsFrameLoader::MaybeCreateDocShell()
   if (NS_FAILED(base_win->Create()) || !win_private) {
     // Do not call Destroy() here. See bug 472312.
     NS_WARNING("Something wrong when creating the docshell for a frameloader!");
     return NS_ERROR_FAILURE;
   }
 
   EnsureMessageManager();
 
+  if (OwnerIsBrowserFrame()) {
+    mDocShell->SetIsBrowserFrame(true);
+
+    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+    if (os) {
+      os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
+                          "in-process-browser-frame-shown", NULL);
+    }
+
+    if (mMessageManager) {
+      mMessageManager->LoadFrameScript(
+        NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"),
+        /* allowDelayedLoad = */ true);
+    }
+  }
+
   return NS_OK;
 }
 
 void
 nsFrameLoader::GetURL(nsString& aURI)
 {
   aURI.Truncate();
 
@@ -1894,17 +1903,18 @@ nsFrameLoader::TryRemoteBrowser()
     return false;
   }
   if (NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
     return false;
   }
 
   ContentParent* parent = ContentParent::GetNewOrUsed();
   NS_ASSERTION(parent->IsAlive(), "Process parent should be alive; something is very wrong!");
-  mRemoteBrowser = parent->CreateTab(chromeFlags);
+  mRemoteBrowser = parent->CreateTab(chromeFlags,
+                                     /* aIsBrowserFrame = */ OwnerIsBrowserFrame());
   if (mRemoteBrowser) {
     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
     mRemoteBrowser->SetOwnerElement(element);
 
     nsCOMPtr<nsIDocShellTreeItem> rootItem;
     parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
     nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
     nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -2028,16 +2028,30 @@ nsGenericElement::GetOffsetRect(nsRect& 
   // we only care about the size. Using 'parent' might make things
   // a bit faster by speeding up the internal GetOffsetTo operations.
   nsIFrame* parent = frame->GetParent() ? frame->GetParent() : frame;
   nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, parent);
   aRect.width = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width);
   aRect.height = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height);
 }
 
+nsIntSize
+nsGenericElement::GetPaddingRectSize()
+{
+  nsIFrame* frame = GetStyledFrame();
+  if (!frame) {
+    return nsIntSize(0, 0);
+  }
+
+  NS_ASSERTION(frame->GetParent(), "Styled frame has no parent");
+  nsRect rcFrame = nsLayoutUtils::GetAllInFlowPaddingRectsUnion(frame, frame->GetParent());
+  return nsIntSize(nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width),
+                   nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height));
+}
+
 nsIScrollableFrame*
 nsGenericElement::GetScrollFrame(nsIFrame **aStyledFrame)
 {
   // it isn't clear what to return for SVG nodes, so just return nothing
   if (IsSVG()) {
     if (aStyledFrame) {
       *aStyledFrame = nsnull;
     }
@@ -2140,20 +2154,17 @@ nsGenericElement::SetScrollLeft(PRInt32 
 PRInt32
 nsGenericElement::GetScrollHeight()
 {
   if (IsSVG())
     return 0;
 
   nsIScrollableFrame* sf = GetScrollFrame();
   if (!sf) {
-    nsRect rcFrame;
-    nsCOMPtr<nsIContent> parent;
-    GetOffsetRect(rcFrame, getter_AddRefs(parent));
-    return rcFrame.height;
+    return GetPaddingRectSize().height;
   }
 
   nscoord height = sf->GetScrollRange().height + sf->GetScrollPortRect().height;
   return nsPresContext::AppUnitsToIntCSSPixels(height);
 }
 
 NS_IMETHODIMP
 nsGenericElement::GetScrollHeight(PRInt32* aScrollHeight)
@@ -2166,20 +2177,17 @@ nsGenericElement::GetScrollHeight(PRInt3
 PRInt32
 nsGenericElement::GetScrollWidth()
 {
   if (IsSVG())
     return 0;
 
   nsIScrollableFrame* sf = GetScrollFrame();
   if (!sf) {
-    nsRect rcFrame;
-    nsCOMPtr<nsIContent> parent;
-    GetOffsetRect(rcFrame, getter_AddRefs(parent));
-    return rcFrame.width;
+    return GetPaddingRectSize().width;
   }
 
   nscoord width = sf->GetScrollRange().width + sf->GetScrollPortRect().width;
   return nsPresContext::AppUnitsToIntCSSPixels(width);
 }
 
 NS_IMETHODIMP
 nsGenericElement::GetScrollWidth(PRInt32 *aScrollWidth)
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -772,16 +772,23 @@ protected:
    * Retrieve the rectangle for the offsetX properties, which
    * are coordinates relative to the returned aOffsetParent.
    *
    * @param aRect offset rectangle
    * @param aOffsetParent offset parent
    */
   virtual void GetOffsetRect(nsRect& aRect, nsIContent** aOffsetParent);
 
+  /**
+   * Retrieve the size of the padding rect of this element.
+   *
+   * @param aSize the size of the padding rect
+   */
+  nsIntSize GetPaddingRectSize();
+
   nsIFrame* GetStyledFrame();
 
   virtual mozilla::dom::Element* GetNameSpaceElement()
   {
     return this;
   }
 
   nsresult GetAttributeNodeNSInternal(const nsAString& aNamespaceURI,
--- a/content/base/test/test_bug320799.html
+++ b/content/base/test/test_bug320799.html
@@ -6,17 +6,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <head>
   <title>Test for Bug 320799</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=320799">Mozilla Bug 320799</a>
 <p id="display">
-  <select id="s" style="width: 100px">
+  <select id="s" style="width: 100px; -moz-box-sizing: padding-box">
     <option>This is a test, it really is a test I tell you</option>
   </select>
   <select id="s2">
     <option>x</option>
     <option>x</option>
     <option>x</option>
     <option>x</option>
     <option>x</option>
--- a/content/html/content/test/test_bug375003-1.html
+++ b/content/html/content/test/test_bug375003-1.html
@@ -36,53 +36,53 @@ function t3(id,c,o,s,pid) {
   test(id,'offset',o);
   test(id,'scroll',s);
   var p = document.getElementById(id).offsetParent; 
   is(p.id, pid, id+".offsetParent");
 }
 
 function run_test() {
    t3('span1',[0,0,20,20],[12,12,20,20],[0,0,20,20],'td1');
-   t3('td1'  ,[1,1,69,44],[16,16,71,46],[0,0,71,46],'table1');
+   t3('td1'  ,[1,1,69,44],[16,16,71,46],[0,0,69,46],'table1');
    t3('tr1'  ,[0,0,71,46],[16,16,71,46],[0,0,71,44],'table1');
-   t3('span2',[10,0,20,20],[27,12,30,20],[0,0,30,20],'td2');
-   t3('table1',[9,9,85,113],[10,10,103,131],[0,0,103,50],'body');
+   t3('span2',[10,0,20,20],[27,12,30,20],[0,0,20,20],'td2');
+   t3('table1',[9,9,85,113],[10,10,103,131],[0,0,85,50],'body');
    t3('div1',[10,10,-1,131],[0,0,-1,151],[0,0,-1,85],'body');
 
-   t3('span2b',[10,0,20,20],[25,-1,30,20],[0,0,30,20],'body');
+   t3('span2b',[10,0,20,20],[25,-1,30,20],[0,0,20,20],'body');
    // XXX not sure how to make reliable cross-platform tests for replaced-inline, inline
    // t3('span2c',[10,2,18,2],[25,-1,30,6],[0,0,30,20],'body');
    // t3('span2d',[0,0,0,0],[25,-1,10,19],[0,0,10,20],'body');
 
    t3('span3' ,[0,0,20,20],[15,0,20,20],[0,0,20,20],'td3');
    t3('td3'   ,[0,0,35,20],[0,0,35,20],[0,0,35,20],'table3');
    t3('tr3'  ,[0,0,35,20],[0,0,35,20],[0,0,35,22],'table3');
    t3('span4' ,[0,0,20,20],[0,0,20,20],[0,0,20,20],'td4');
    t3('table3',[0,0,35,40],[0,0,35,40],[0,0,35,50],'div3');
    t3('div3',[10,10,-1,40],[0,151,-1,60],[0,0,-1,70],'body');
 
    t3('span5' ,[0,0,20,20],[1,1,20,20],[0,0,20,20],'td5');
-   t3('td5'   ,[7,7,22,22],[2,2,36,36],[0,0,36,36],'table5');
+   t3('td5'   ,[7,7,22,22],[2,2,36,36],[0,0,22,36],'table5');
    t3('tr5'  ,[0,0,36,36],[2,2,36,36],[0,0,36,22],'table5');
    t3('span6' ,[0,0,20,20],[20,58,20,20],[0,0,20,20],'div5');
    t3('table5',[0,0,40,78],[0,0,40,78],[0,0,40,78],'div5');
    t3('div5',[10,10,-1,78],[0,211,-1,98],[0,0,-1,70],'body');
 
    t3('span7' ,[0,0,20,20],[1,1,20,20],[0,0,20,20],'td7');
-   t3('td7'   ,[1,1,37,22],[9,9,39,24],[0,0,39,22],'table7');
+   t3('td7'   ,[1,1,37,22],[9,9,39,24],[0,0,37,22],'table7');
    t3('tr7'  ,[0,0,39,24],[9,9,39,24],[0,0,39,22],'table7');
    t3('span8' ,[0,0,20,20],[26,37,20,20],[0,0,20,20],'table7');
-   t3('table7',[7,7,43,54],[10,319,57,68],[0,0,57,50],'body');
+   t3('table7',[7,7,43,54],[10,319,57,68],[0,0,43,50],'body');
    t3('div7',[10,10,-1,68],[0,309,-1,88],[0,0,-1,70],'body');
 
    t3('span9' ,[0,0,20,20],[1,1,20,20],[0,0,20,20],'td9');
-   t3('td9'   ,[1,1,22,22],[15,15,24,24],[0,0,24,24],'table9');
+   t3('td9'   ,[1,1,22,22],[15,15,24,24],[0,0,22,24],'table9');
    t3('tr9'  ,[0,0,24,24],[15,15,24,24],[0,0,24,22],'table9');
    t3('span10' ,[0,0,20,20],[17,43,20,20],[0,0,20,20],'table9');
-   t3('table9',[13,13,28,34],[10,407,54,60],[0,0,54,50],'body');
+   t3('table9',[13,13,28,34],[10,407,54,60],[0,0,28,50],'body');
    t3('div9',[10,10,-1,0],[0,397,-1,20],[0,0,-1,70],'body');
 
    t3('span11' ,[0,0,20,20],[1,1,20,20],[0,0,20,20],'td11');
    t3('td11'   ,[0,0,22,22],[2,2,22,22],[0,0,22,22],'table11');
    t3('tr11'  ,[0,0,22,22],[2,2,22,22],[0,0,22,22],'table11');
    t3('span12' ,[0,0,20,20],[28,454,20,20],[0,0,20,20],'body');
    t3('table11',[0,0,26,30],[10,427,26,30],[0,0,26,50],'body');
    t3('div11',[10,10,-1,30],[0,417,-1,50],[0,0,-1,70],'body');
--- a/content/html/content/test/test_bug375003-2.html
+++ b/content/html/content/test/test_bug375003-2.html
@@ -63,19 +63,19 @@ function t3(id,c,o,s,pid) {
   is(p.id, pid, id+".offsetParent");
 }
 
 function run_test() {
    // XXX how test clientWidth/clientHeight (the -1 below) in cross-platform manner
    // without hard-coding the scrollbar width?
    t3('div1',[20,20,-1,-1],[10,10,200,160],[0,0,230,20],'body');
    t3('abs1',[20,20,-1,-1],[500,170,200,160],[0,0,230,20],'body');
-   t3('table1',[20,20,266,266],[10,170,306,306],[0,0,306,20],'body');
+   t3('table1',[20,20,266,266],[10,170,306,306],[0,0,266,20],'body');
    t3('table2',[0,0,206,206],[0,0,206,206],[0,0,206,20],'table2parent');
-   t3('table3',[10,10,208,208],[0,0,228,228],[0,0,228,228],'table3parent');
+   t3('table3',[10,10,208,208],[0,0,228,228],[0,0,208,228],'table3parent');
    t3('table3parent',[0,0,228,228],[300,100,228,228],[0,0,228,228],'body');
 }
 </script>
 
 </head>
 <body id="body">
 <div id="content">
 <div id="div1parent">
@@ -101,9 +101,9 @@ function run_test() {
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 run_test();
 </script>
 </pre>
 
 </body>
-</html>
\ No newline at end of file
+</html>
--- a/content/media/gstreamer/nsGStreamerReader.cpp
+++ b/content/media/gstreamer/nsGStreamerReader.cpp
@@ -186,17 +186,17 @@ nsresult nsGStreamerReader::ReadMetadata
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
   nsresult ret = NS_OK;
 
   /* We do 3 attempts here: decoding audio and video, decoding video only,
    * decoding audio only. This allows us to play streams that have one broken
    * stream but that are otherwise decodeable.
    */
   guint flags[3] = {GST_PLAY_FLAG_VIDEO|GST_PLAY_FLAG_AUDIO,
-    ~GST_PLAY_FLAG_AUDIO, ~GST_PLAY_FLAG_VIDEO};
+    static_cast<guint>(~GST_PLAY_FLAG_AUDIO), static_cast<guint>(~GST_PLAY_FLAG_VIDEO)};
   guint default_flags, current_flags;
   g_object_get(mPlayBin, "flags", &default_flags, NULL);
 
   GstMessage *message = NULL;
   for (int i=0; i < G_N_ELEMENTS(flags); i++) {
     current_flags = default_flags & flags[i];
     g_object_set(G_OBJECT(mPlayBin), "flags", current_flags, NULL);
 
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -73,123 +73,352 @@ XBLFinalize(JSFreeOp *fop, JSObject *obj
   nsXBLDocumentInfo* docInfo =
     static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(obj));
   NS_RELEASE(docInfo);
   
   nsXBLJSClass* c = static_cast<nsXBLJSClass*>(::JS_GetClass(obj));
   c->Drop();
 }
 
+// XBL fields are represented on elements inheriting that field a bit trickily.
+// Initially the element itself won't have a property for the field.  When an
+// attempt is made to access the field, the element's resolve hook won't find
+// it.  But the XBL prototype object, in the prototype chain of the element,
+// will resolve an accessor property for the field on the XBL prototype object.
+// That accessor, when used, will then (via InstallXBLField below) reify a
+// property for the field onto the actual XBL-backed element.
+//
+// The accessor property is a plain old property backed by a getter function and
+// a setter function.  These properties are backed by the FieldGetter and
+// FieldSetter natives; they're created by XBLResolve.  The precise field to be
+// reified is identified using two extra slots on the getter/setter functions.
+// XBLPROTO_SLOT stores the XBL prototype object that provides the field.
+// FIELD_SLOT stores the name of the field, i.e. its JavaScript property name.
+//
+// This two-step field installation process -- reify an accessor on the
+// prototype, then have that reify an own property on the actual element -- is
+// admittedly convoluted.  Better would be for XBL-backed elements to be proxies
+// that could resolve fields onto themselves.  But given that XBL bindings are
+// associated with elements mutably -- you can add/remove/change -moz-binding
+// whenever you want, alas -- doing so would require all elements to be proxies,
+// which isn't performant now.  So we do this two-step instead.
+static const uint32_t XBLPROTO_SLOT = 0;
+static const uint32_t FIELD_SLOT = 1;
+
+static bool
+ObjectHasISupportsPrivate(JS::Handle<JSObject*> obj)
+{
+  JSClass* clasp = ::JS_GetClass(obj);
+  const uint32_t HAS_PRIVATE_NSISUPPORTS =
+    JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS;
+  return (clasp->flags & HAS_PRIVATE_NSISUPPORTS) == HAS_PRIVATE_NSISUPPORTS;
+}
+
+// Define a shadowing property on |this| for the XBL field defined by the
+// contents of the callee's reserved slots.  If the property was defined,
+// *installed will be true, and idp will be set to the property name that was
+// defined.
+static JSBool
+InstallXBLField(JSContext* cx,
+                JS::Handle<JSObject*> callee, JS::Handle<JSObject*> thisObj,
+                jsid* idp, bool* installed)
+{
+  *installed = false;
+
+  // First ensure |this| is a reasonable XBL bound node.
+  //
+  // FieldAccessorGuard already determined whether |thisObj| was acceptable as
+  // |this| in terms of not throwing a TypeError.  Assert this for good measure.
+  MOZ_ASSERT(ObjectHasISupportsPrivate(thisObj));
+
+  // But there are some cases where we must accept |thisObj| but not install a
+  // property on it, or otherwise touch it.  Hence this split of |this|-vetting
+  // duties.
+  nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
+    do_QueryInterface(static_cast<nsISupports*>(::JS_GetPrivate(thisObj)));
+  if (!xpcWrapper) {
+    // Looks like whatever |thisObj| is it's not our nsIContent.  It might well
+    // be the proto our binding installed, however, where the private is the
+    // nsXBLDocumentInfo, so just baul out quietly.  Do NOT throw an exception
+    // here.
+    //
+    // We could make this stricter by checking the class maybe, but whatever.
+    return true;
+  }
+
+  nsCOMPtr<nsIContent> xblNode = do_QueryWrappedNative(xpcWrapper);
+  if (!xblNode) {
+    xpc::Throw(cx, NS_ERROR_UNEXPECTED);
+    return false;
+  }
+
+  // Now that |this| is okay, actually install the field.  Some of this
+  // installation work could have been done in XBLResolve, but this splitting
+  // of work seems simplest to implement and friendliest regarding lifetimes
+  // and potential cycles.
+
+  // Because of the possibility (due to XBL binding inheritance, because each
+  // XBL binding lives in its own global object) that |this| might be in a
+  // different compartment from the callee (not to mention that this method can
+  // be called with an arbitrary |this| regardless of how insane XBL is), and
+  // because in this method we've entered |this|'s compartment (see in
+  // Field[GS]etter where we attempt a cross-compartment call), we must enter
+  // the callee's compartment to access its reserved slots.
+  nsXBLPrototypeBinding* protoBinding;
+  nsDependentJSString fieldName;
+  {
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(cx, callee)) {
+      return false;
+    }
+
+    JS::Rooted<JSObject*> xblProto(cx);
+    xblProto = &js::GetFunctionNativeReserved(callee, XBLPROTO_SLOT).toObject();
+
+    JS::Value name = js::GetFunctionNativeReserved(callee, FIELD_SLOT);
+    JSFlatString* fieldStr = JS_ASSERT_STRING_IS_FLAT(name.toString());
+    fieldName.init(fieldStr);
+
+    MOZ_ALWAYS_TRUE(JS_ValueToId(cx, name, idp));
+
+    JS::Value slotVal = ::JS_GetReservedSlot(xblProto, 0);
+    protoBinding = static_cast<nsXBLPrototypeBinding*>(slotVal.toPrivate());
+    MOZ_ASSERT(protoBinding);
+  }
+
+  nsXBLProtoImplField* field = protoBinding->FindField(fieldName);
+  MOZ_ASSERT(field);
+
+  // This mirrors code in nsXBLProtoImpl::InstallImplementation
+  nsIScriptGlobalObject* global = xblNode->OwnerDoc()->GetScriptGlobalObject();
+  if (!global) {
+    return true;
+  }
+
+  nsCOMPtr<nsIScriptContext> context = global->GetContext();
+  if (!context) {
+    return true;
+  }
+
+  nsresult rv = field->InstallField(context, thisObj, xblNode->NodePrincipal(),
+                                    protoBinding->DocURI(), installed);
+  if (NS_SUCCEEDED(rv)) {
+    return true;
+  }
+
+  if (!::JS_IsExceptionPending(cx)) {
+    xpc::Throw(cx, rv);
+  }
+  return false;
+}
+
+// Determine whether the |this| passed to this method is valid for an XBL field
+// access (which is to say, an object with an nsISupports private), taking into
+// account proxies and/or wrappers around |this|.  There are three possible
+// outcomes from calling this method:
+//
+//   1. An error was hit, and this method returned false.  In this case, the
+//      caller should propagate it.
+//   2. The |this| passed in was directly acceptable for XBL field access.  This
+//      method returned true and set *thisObj to a |this| that can be used for
+//      field definition (i.e. that passes ObjectHasISupportsPrivate).  In this
+//      case, the caller should install the field on *thisObj.
+//   3. The |this| passed in was a proxy/wrapper around an object usable for
+//      XBL field access.  The method recursively (and successfully) invoked the
+//      native on the unwrapped |this|, then it returned true and set *thisObj
+//      to null.  In this case, the caller should itself return true.
+//
+// Thus this method implements the JS_CallNonGenericMethodOnProxy idiom in
+// jsapi.h.
+//
+// Note that a |this| valid for field access is *not* necessarily one on which
+// the field value will be installed.  It's just one where calling the specified
+// method on it won't unconditionally throw a TypeError.  Confusing?  Perhaps,
+// but it's compatible with what we did before we implemented XBL fields using
+// this technique.
+inline bool
+FieldAccessorGuard(JSContext *cx, unsigned argc, JS::Value *vp, JSNative native, JSObject **thisObj)
+{
+  JS::Rooted<JSObject*> obj(cx, JS_THIS_OBJECT(cx, vp));
+  if (!obj) {
+    xpc::Throw(cx, NS_ERROR_UNEXPECTED);
+    return false;
+  }
+
+  if (ObjectHasISupportsPrivate(obj)) {
+    *thisObj = obj;
+    return true;
+  }
+
+  // |this| wasn't an unwrapped object passing the has-private-nsISupports test.
+  // So try to unwrap |this| and recursively call the native on it.
+  //
+  // This |protoClass| gunk is needed for the JS engine to report an error if an
+  // object of the wrong class was passed as |this|, so that it can complain
+  // that it expected an object of type |protoClass|.  It would be better if the
+  // error didn't try to specify the expected class of objects -- particularly
+  // because there's no one class of objects -- but it's what the API wants, so
+  // pass a class that's marginally correct as an answer.
+  JSClass* protoClass;
+  {
+    JS::Rooted<JSObject*> callee(cx, &JS_CALLEE(cx, vp).toObject());
+    JS::Rooted<JSObject*> xblProto(cx);
+    xblProto = &js::GetFunctionNativeReserved(callee, XBLPROTO_SLOT).toObject();
+
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(cx, xblProto)) {
+      return false;
+    }
+
+    protoClass = ::JS_GetClass(xblProto);
+  }
+
+  *thisObj = NULL;
+  return JS_CallNonGenericMethodOnProxy(cx, argc, vp, native, protoClass);
+}
+
+static JSBool
+FieldGetter(JSContext *cx, unsigned argc, JS::Value *vp)
+{
+  JS::Rooted<JSObject*> thisObj(cx);
+  if (!FieldAccessorGuard(cx, argc, vp, FieldGetter, thisObj.address())) {
+    return false;
+  }
+  if (!thisObj) {
+    return true; // FieldGetter was recursively invoked on an unwrapped |this|
+  }
+
+  bool installed = false;
+  JS::Rooted<JSObject*> callee(cx, &JS_CALLEE(cx, vp).toObject());
+  JS::Rooted<jsid> id(cx);
+  if (!InstallXBLField(cx, callee, thisObj, id.address(), &installed)) {
+    return false;
+  }
+
+  if (!installed) {
+    JS_SET_RVAL(cx, vp, JS::UndefinedValue());
+    return true;
+  }
+
+  JS::Rooted<JS::Value> v(cx);
+  if (!JS_GetPropertyById(cx, thisObj, id, v.address())) {
+    return false;
+  }
+  JS_SET_RVAL(cx, vp, v);
+  return true;
+}
+
+static JSBool
+FieldSetter(JSContext *cx, unsigned argc, JS::Value *vp)
+{
+  JS::Rooted<JSObject*> thisObj(cx);
+  if (!FieldAccessorGuard(cx, argc, vp, FieldSetter, thisObj.address())) {
+    return false;
+  }
+  if (!thisObj) {
+    return true; // FieldSetter was recursively invoked on an unwrapped |this|
+  }
+
+  bool installed = false;
+  JS::Rooted<JSObject*> callee(cx, &JS_CALLEE(cx, vp).toObject());
+  JS::Rooted<jsid> id(cx);
+  if (!InstallXBLField(cx, callee, thisObj, id.address(), &installed)) {
+    return false;
+  }
+
+  JS::Rooted<JS::Value> v(cx,
+                          argc > 0 ? JS_ARGV(cx, vp)[0] : JS::UndefinedValue());
+  return JS_SetPropertyById(cx, thisObj, id, v.address());
+}
+
 static JSBool
 XBLResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
            JSObject **objp)
 {
-  // Note: if we get here, that means that the implementation for some binding
-  // was installed, which means that AllowScripts() tested true.  Hence no need
-  // to do checks like that here.
-  
-  // Default to not resolving things.
-  NS_ASSERTION(*objp, "Must have starting object");
-
-  JSObject* origObj = *objp;
   *objp = NULL;
 
   if (!JSID_IS_STRING(id)) {
-    return JS_TRUE;
+    return true;
   }
 
-  nsDependentJSString fieldName(id);
+  nsXBLPrototypeBinding* protoBinding =
+    static_cast<nsXBLPrototypeBinding*>(::JS_GetReservedSlot(obj, 0).toPrivate());
+  MOZ_ASSERT(protoBinding);
 
-  jsval slotVal = ::JS_GetReservedSlot(obj, 0);
-  NS_ASSERTION(!JSVAL_IS_VOID(slotVal), "How did that happen?");
-    
-  nsXBLPrototypeBinding* protoBinding =
-    static_cast<nsXBLPrototypeBinding*>(JSVAL_TO_PRIVATE(slotVal));
-  NS_ASSERTION(protoBinding, "Must have prototype binding!");
-
+  // If the field's not present, don't resolve it.  Also don't resolve it if the
+  // field is empty; see also nsXBLProtoImplField::InstallField which also must
+  // implement the not-empty requirement.
+  nsDependentJSString fieldName(id);
   nsXBLProtoImplField* field = protoBinding->FindField(fieldName);
-  if (!field) {
-    return JS_TRUE;
-  }
-
-  // We have this field.  Time to install it.  Get our node.
-  JSClass* nodeClass = ::JS_GetClass(origObj);
-  if (!nodeClass) {
-    return JS_FALSE;
-  }
-  
-  if (~nodeClass->flags &
-      (JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS)) {
-    xpc::Throw(cx, NS_ERROR_UNEXPECTED);
-    return JS_FALSE;
+  if (!field || field->IsEmpty()) {
+    return true;
   }
 
-  nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
-    do_QueryInterface(static_cast<nsISupports*>(::JS_GetPrivate(origObj)));
-  if (!xpcWrapper) {
-    // Looks like whatever |origObj| is it's not our nsIContent.  It might well
-    // be the proto our binding installed, however, where the private is the
-    // nsXBLDocumentInfo, so just baul out quietly.  Do NOT throw an exception
-    // here.
-    // We could make this stricter by checking the class maybe, but whatever
-    return JS_TRUE;
+  // We have a field: now install a getter/setter pair which will resolve the
+  // field onto the actual object, when invoked.
+  JS::Rooted<JSObject*> global(cx, JS_GetGlobalForObject(cx, obj));
+
+  JS::Rooted<JSObject*> get(cx);
+  get = ::JS_GetFunctionObject(js::NewFunctionByIdWithReserved(cx, FieldGetter,
+                                                               0, 0, global,
+                                                               id));
+  if (!get) {
+    return false;
   }
+  js::SetFunctionNativeReserved(get, XBLPROTO_SLOT, JS::ObjectValue(*obj));
+  js::SetFunctionNativeReserved(get, FIELD_SLOT,
+                                JS::StringValue(JSID_TO_STRING(id)));
 
-  nsCOMPtr<nsIContent> content = do_QueryWrappedNative(xpcWrapper);
-  if (!content) {
-    xpc::Throw(cx, NS_ERROR_UNEXPECTED);
-    return JS_FALSE;
+  JS::Rooted<JSObject*> set(cx);
+  set = ::JS_GetFunctionObject(js::NewFunctionByIdWithReserved(cx, FieldSetter,
+                                                               1, 0, global,
+                                                               id));
+  if (!set) {
+    return false;
+  }
+  js::SetFunctionNativeReserved(set, XBLPROTO_SLOT, JS::ObjectValue(*obj));
+  js::SetFunctionNativeReserved(set, FIELD_SLOT,
+                                JS::StringValue(JSID_TO_STRING(id)));
+
+  if (!::JS_DefinePropertyById(cx, obj, id, JS::UndefinedValue(),
+                               JS_DATA_TO_FUNC_PTR(JSPropertyOp,
+                                                   get.reference()),
+                               JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp,
+                                                   set.reference()),
+                               field->AccessorAttributes())) {
+    return false;
   }
 
-  // This mirrors code in nsXBLProtoImpl::InstallImplementation
-  nsIDocument* doc = content->OwnerDoc();
-
-  nsIScriptGlobalObject* global = doc->GetScriptGlobalObject();
-  if (!global) {
-    return JS_TRUE;
-  }
-
-  nsCOMPtr<nsIScriptContext> context = global->GetContext();
-  if (!context) {
-    return JS_TRUE;
-  }
-
+  *objp = obj;
+  return true;
+}
 
-  // Now we either resolve or fail
-  bool didInstall;
-  nsresult rv = field->InstallField(context, origObj,
-                                    content->NodePrincipal(),
-                                    protoBinding->DocURI(),
-                                    &didInstall);
-  if (NS_FAILED(rv)) {
-    xpc::Throw(cx, rv);
-    return JS_FALSE;
-  }
+static JSBool
+XBLEnumerate(JSContext *cx, JS::Handle<JSObject*> obj)
+{
+  nsXBLPrototypeBinding* protoBinding =
+    static_cast<nsXBLPrototypeBinding*>(::JS_GetReservedSlot(obj, 0).toPrivate());
+  MOZ_ASSERT(protoBinding);
 
-  if (didInstall) {
-    *objp = origObj;
-  }
-  // else we didn't resolve this field after all
-
-  return JS_TRUE;
+  return protoBinding->ResolveAllFields(cx, obj);
 }
 
 nsXBLJSClass::nsXBLJSClass(const nsAFlatCString& aClassName)
 {
   memset(this, 0, sizeof(nsXBLJSClass));
   next = prev = static_cast<JSCList*>(this);
   name = ToNewCString(aClassName);
   flags =
     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
-    JSCLASS_NEW_RESOLVE | JSCLASS_NEW_RESOLVE_GETS_START |
+    JSCLASS_NEW_RESOLVE |
     // Our one reserved slot holds the relevant nsXBLPrototypeBinding
     JSCLASS_HAS_RESERVED_SLOTS(1);
   addProperty = delProperty = getProperty = ::JS_PropertyStub;
   setProperty = ::JS_StrictPropertyStub;
-  enumerate = ::JS_EnumerateStub;
+  enumerate = XBLEnumerate;
   resolve = (JSResolveOp)XBLResolve;
   convert = ::JS_ConvertStub;
   finalize = XBLFinalize;
 }
 
 nsrefcnt
 nsXBLJSClass::Destroy()
 {
--- a/content/xbl/src/nsXBLProtoImplField.cpp
+++ b/content/xbl/src/nsXBLProtoImplField.cpp
@@ -83,17 +83,18 @@ nsXBLProtoImplField::InstallField(nsIScr
 {
   NS_TIME_FUNCTION_MIN(5);
   NS_PRECONDITION(aBoundNode,
                   "uh-oh, bound node should NOT be null or bad things will "
                   "happen");
 
   *aDidInstall = false;
 
-  if (mFieldTextLength == 0) {
+  // Empty fields are treated as not actually present.
+  if (IsEmpty()) {
     return NS_OK;
   }
 
   nsAutoMicroTask mt;
 
   // EvaluateStringWithValue and JS_DefineUCProperty can both trigger GC, so
   // protect |result| here.
   nsresult rv;
--- a/content/xbl/src/nsXBLProtoImplField.h
+++ b/content/xbl/src/nsXBLProtoImplField.h
@@ -36,16 +36,23 @@ public:
                         nsIURI* aBindingDocURI,
                         bool* aDidInstall) const;
 
   nsresult Read(nsIScriptContext* aContext, nsIObjectInputStream* aStream);
   nsresult Write(nsIScriptContext* aContext, nsIObjectOutputStream* aStream);
 
   const PRUnichar* GetName() const { return mName; }
 
+  unsigned AccessorAttributes() const {
+    return JSPROP_SHARED | JSPROP_GETTER | JSPROP_SETTER |
+           (mJSAttributes & (JSPROP_ENUMERATE | JSPROP_PERMANENT));
+  }
+
+  bool IsEmpty() const { return mFieldTextLength == 0; }
+
 protected:
   nsXBLProtoImplField* mNext;
   PRUnichar* mName;
   PRUnichar* mFieldText;
   PRUint32 mFieldTextLength;
   PRUint32 mLineNumber;
   unsigned mJSAttributes;
 };
--- a/content/xbl/test/test_bug372769.xhtml
+++ b/content/xbl/test/test_bug372769.xhtml
@@ -111,18 +111,19 @@ addLoadEvent(function() {
     if (prop == "seven") {
       found = true;
       break;
     }
   }
   is(found, true, "Enumeration is broken");
 
   is(d.four, 9, "Shouldn't have rerun field six");
+  is(d.five, 11, "Shouldn't have run field 7");
+  is(d.seven, 7, "Should be 7")
   is(d.five, 5, "Should have run field 7");
-  is(d.seven, 7, "Should be 7")
 
   d = $("display2");
   is(typeof(d.eight), "undefined", "Recursive resolve should bail out");
   is(typeof(d.nine), "undefined", "Recursive double resolve should bail out");
   is(typeof(d.ten), "undefined",
      "This recursive double resolve should bail out too");
 
   // Get .eleven so it's resolved now
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -643,16 +643,17 @@ ConvertLoadTypeToNavigationType(PRUint32
     case LOAD_NORMAL:
     case LOAD_NORMAL_EXTERNAL:
     case LOAD_NORMAL_BYPASS_CACHE:
     case LOAD_NORMAL_BYPASS_PROXY:
     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
     case LOAD_NORMAL_REPLACE:
     case LOAD_LINK:
     case LOAD_STOP_CONTENT:
+    case LOAD_REPLACE_BYPASS_CACHE:
         result = nsIDOMPerformanceNavigation::TYPE_NAVIGATE;
         break;
     case LOAD_HISTORY:
         result = nsIDOMPerformanceNavigation::TYPE_BACK_FORWARD;
         break;
     case LOAD_RELOAD_NORMAL:
     case LOAD_RELOAD_CHARSET_CHANGE:
     case LOAD_RELOAD_BYPASS_CACHE:
@@ -1136,16 +1137,19 @@ ConvertDocShellLoadInfoToLoadType(nsDocS
         loadType = LOAD_STOP_CONTENT;
         break;
     case nsIDocShellLoadInfo::loadStopContentAndReplace:
         loadType = LOAD_STOP_CONTENT_AND_REPLACE;
         break;
     case nsIDocShellLoadInfo::loadPushState:
         loadType = LOAD_PUSHSTATE;
         break;
+    case nsIDocShellLoadInfo::loadReplaceBypassCache:
+        loadType = LOAD_REPLACE_BYPASS_CACHE;
+        break;
     default:
         NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
     }
 
     return loadType;
 }
 
 
@@ -1204,16 +1208,19 @@ nsDocShell::ConvertLoadTypeToDocShellLoa
         docShellLoadType = nsIDocShellLoadInfo::loadStopContent;
         break;
     case LOAD_STOP_CONTENT_AND_REPLACE:
         docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace;
         break;
     case LOAD_PUSHSTATE:
         docShellLoadType = nsIDocShellLoadInfo::loadPushState;
         break;
+    case LOAD_REPLACE_BYPASS_CACHE:
+        docShellLoadType = nsIDocShellLoadInfo::loadReplaceBypassCache;
+        break;
     default:
         NS_NOTREACHED("Unexpected load type value");
     }
 
     return docShellLoadType;
 }                                                                               
 
 //*****************************************************************************
@@ -5918,16 +5925,17 @@ nsDocShell::Embed(nsIContentViewer * aCo
 
     // Determine if this type of load should update history
     switch (mLoadType) {
     case LOAD_NORMAL_REPLACE:
     case LOAD_STOP_CONTENT_AND_REPLACE:
     case LOAD_RELOAD_BYPASS_CACHE:
     case LOAD_RELOAD_BYPASS_PROXY:
     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
+    case LOAD_REPLACE_BYPASS_CACHE:
         updateHistory = false;
         break;
     default:
         break;
     }
 
     if (!updateHistory)
         SetLayoutHistoryState(nsnull);
@@ -9221,16 +9229,17 @@ nsresult nsDocShell::DoChannelLoad(nsICh
         break;
 
     case LOAD_NORMAL_BYPASS_CACHE:
     case LOAD_NORMAL_BYPASS_PROXY:
     case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
     case LOAD_RELOAD_BYPASS_CACHE:
     case LOAD_RELOAD_BYPASS_PROXY:
     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
+    case LOAD_REPLACE_BYPASS_CACHE:
         loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
                      nsIRequest::LOAD_FRESH_CONNECTION;
         break;
 
     case LOAD_NORMAL:
     case LOAD_LINK:
         // Set cache checking flags
         switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
--- a/docshell/base/nsDocShellLoadTypes.h
+++ b/docshell/base/nsDocShellLoadTypes.h
@@ -55,16 +55,17 @@ enum LoadType {
     LOAD_RELOAD_BYPASS_PROXY_AND_CACHE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY),
     LOAD_LINK = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_IS_LINK),
     LOAD_REFRESH = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_IS_REFRESH),
     LOAD_RELOAD_CHARSET_CHANGE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD, nsIWebNavigation::LOAD_FLAGS_CHARSET_CHANGE),
     LOAD_BYPASS_HISTORY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_HISTORY),
     LOAD_STOP_CONTENT = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT),
     LOAD_STOP_CONTENT_AND_REPLACE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT | nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY),
     LOAD_PUSHSTATE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_PUSHSTATE, nsIWebNavigation::LOAD_FLAGS_NONE),
+    LOAD_REPLACE_BYPASS_CACHE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY | nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE),
     /**
      * Load type for an error page. These loads are never triggered by users of
      * Docshell. Instead, Docshell triggers the load itself when a
      * consumer-triggered load failed.
      */
     LOAD_ERROR_PAGE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, LOAD_FLAGS_ERROR_PAGE)
 
     // NOTE: Adding a new value? Remember to update IsValidLoadType!
@@ -86,16 +87,17 @@ static inline bool IsValidLoadType(PRUin
     case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
     case LOAD_LINK:
     case LOAD_REFRESH:
     case LOAD_RELOAD_CHARSET_CHANGE:
     case LOAD_BYPASS_HISTORY:
     case LOAD_STOP_CONTENT:
     case LOAD_STOP_CONTENT_AND_REPLACE:
     case LOAD_PUSHSTATE:
+    case LOAD_REPLACE_BYPASS_CACHE:
     case LOAD_ERROR_PAGE:
         return true;
     }
     return false;
 }
 
 #endif // MOZILLA_INTERNAL_API
 #endif 
--- a/docshell/base/nsIDocShellLoadInfo.idl
+++ b/docshell/base/nsIDocShellLoadInfo.idl
@@ -55,16 +55,17 @@ interface nsIDocShellLoadInfo : nsISuppo
     const long loadBypassHistory = 10;
     const long loadStopContent = 11;
     const long loadStopContentAndReplace = 12;
     const long loadNormalExternal = 13;
     const long loadNormalBypassCache = 14;
     const long loadNormalBypassProxy = 15;
     const long loadNormalBypassProxyAndCache = 16;
     const long loadPushState = 17;                 // history.pushState or replaceState
+    const long loadReplaceBypassCache = 18;
 
     /** Contains a load type as specified by the load* constants */
     attribute nsDocShellInfoLoadType loadType;
 
     /** SHEntry for this page */
     attribute nsISHEntry SHEntry;
 
     /** Target for load, like _content, _blank etc. */
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -32,28 +32,34 @@ function wrapObjectIn(aObject, aCtxt) {
   Cu.makeObjectPropsNormal(res);
   return res;
 };
 
 function convertAppsArray(aApps, aWindow) {
   let apps = Cu.createArrayIn(aWindow);
   for (let i = 0; i < aApps.length; i++) {
     let app = aApps[i];
-    apps.push(new WebappsApplication(aWindow, app.origin, app.manifest, app.manifestURL, 
-                                     app.receipts, app.installOrigin, app.installTime));
+    apps.push(createApplicationObject(aWindow, app.origin, app.manifest, app.manifestURL, 
+                                      app.receipts, app.installOrigin, app.installTime));
   }
 
   return apps;
 }
 
 function WebappsRegistry() {
 }
 
 WebappsRegistry.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
+  __exposedProps__: {
+                      install: 'r',
+                      getSelf: 'r',
+                      getInstalled: 'r',
+                      mgmt: 'r'
+                     },
 
   /** from https://developer.mozilla.org/en/OpenWebApps/The_Manifest
    * only the name property is mandatory
    */
   checkManifest: function(aManifest, aInstallOrigin) {
     // TODO : check for install_allowed_from
     if (aManifest.name == undefined)
       return false;
@@ -71,27 +77,27 @@ WebappsRegistry.prototype = {
     if (msg.oid != this._id)
       return
     let req = this.getRequest(msg.requestID);
     if (!req)
       return;
     let app = msg.app;
     switch (aMessage.name) {
       case "Webapps:Install:Return:OK":
-        Services.DOMRequest.fireSuccess(req, new WebappsApplication(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
-                                                app.installOrigin, app.installTime));
+        Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
+                                                                     app.installOrigin, app.installTime));
         break;
       case "Webapps:Install:Return:KO":
         Services.DOMRequest.fireError(req, "DENIED");
         break;
       case "Webapps:GetSelf:Return:OK":
         if (msg.apps.length) {
           app = msg.apps[0];
-          Services.DOMRequest.fireSuccess(req, new WebappsApplication(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
-                                                  app.installOrigin, app.installTime));
+          Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
+                                                                       app.installOrigin, app.installTime));
         } else {
           Services.DOMRequest.fireSuccess(req, null);
         }
         break;
       case "Webapps:GetInstalled:Return:OK":
         Services.DOMRequest.fireSuccess(req, convertAppsArray(msg.apps, this._window));
         break;
       case "Webapps:GetSelf:Return:KO":
@@ -195,101 +201,108 @@ WebappsRegistry.prototype = {
                                     interfaces: [Ci.mozIDOMApplicationRegistry],
                                     flags: Ci.nsIClassInfo.DOM_OBJECT,
                                     classDescription: "Webapps Registry"})
 }
 
 /**
   * mozIDOMApplication object
   */
-function WebappsApplication(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
-  this._origin = aOrigin;
-  this._manifestURL = aManifestURL;
-  this._manifest = wrapObjectIn(aManifest, aWindow);
-  this._receipts = aReceipts;
-  this._installOrigin = aInstallOrigin;
-  this._installTime = aInstallTime;
 
-  this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Return:KO"]);
+function createApplicationObject(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
+  let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication);
+  app.wrappedJSObject.init(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime);
+  return app;
+}
+
+function WebappsApplication() {
+  this.wrappedJSObject = this;
 }
 
 WebappsApplication.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
-  _origin: null,
-  _manifest: null,
-  _manifestURL: null,
-  _receipts: [],
-  _installOrigin: null,
-  _installTime: 0,
   __exposedProps__: {
                       origin: 'r',
                       manifest: 'r',
                       manifestURL: 'r',
                       installOrigin: 'r',
                       installTime: 'r',
+                      status: 'r',
+                      progress: 'r',
+                      onprogress: 'rw',
                       launch: 'r',
                       receipts: 'r',
                       uninstall: 'r'
                      },
 
-  get origin() {
-    return this._origin;
-  },
-
-  get manifest() {
-    return this._manifest;
+  init: function(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
+    this.origin = aOrigin;
+    this.manifest = wrapObjectIn(aManifest, aWindow);
+    this.manifestURL = aManifestURL;
+    this.receipts = aReceipts;
+    this.installOrigin = aInstallOrigin;
+    this.installTime = aInstallTime;
+    this.status = "installed";
+    this.progress = NaN;
+    this._onprogress = null;
+    this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Return:KO", "Webapps:OfflineCache"]);
   },
 
-  get manifestURL() {
-    return this._manifestURL;
+  set onprogress(aCallback) {
+    this._onprogress = aCallback;
   },
 
-  get receipts() {
-    return this._receipts;
-  },
-
-  get installOrigin() {
-    return this._installOrigin;
-  },
-  
-  get installTime() {
-    return this._installTime;
+  get onprogress() {
+    return this._onprogress;
   },
 
   launch: function(aStartPoint) {
     let request = this.createRequest();
-    cpmm.sendAsyncMessage("Webapps:Launch", { origin: this._origin,
+    cpmm.sendAsyncMessage("Webapps:Launch", { origin: this.origin,
                                               startPoint: aStartPoint || "",
                                               oid: this._id,
                                               requestID: this.getRequestId(request) });
     return request;
   },
 
   uninstall: function() {
     let request = this.createRequest();
-    cpmm.sendAsyncMessage("Webapps:Uninstall", { origin: this._origin,
+    cpmm.sendAsyncMessage("Webapps:Uninstall", { origin: this.origin,
                                                  oid: this._id,
                                                  requestID: this.getRequestId(request) });
     return request;
   },
 
+  uninit: function() {
+    this._onprogress = null;
+  },
+
   receiveMessage: function(aMessage) {
     var msg = aMessage.json;
-    let req = this.getRequest(msg.requestID);
-    if (msg.oid != this._id || !req)
+    let req = this.takeRequest(msg.requestID);
+    if ((msg.oid != this._id || !req) && aMessage.name !== "Webapps:OfflineCache")
       return;
     switch (aMessage.name) {
       case "Webapps:Uninstall:Return:OK":
         Services.DOMRequest.fireSuccess(req, msg.origin);
         break;
       case "Webapps:Uninstall:Return:KO":
         Services.DOMRequest.fireError(req, "NOT_INSTALLED");
         break;
+      case "Webapps:OfflineCache":
+        if (msg.manifest != this.manifestURL)
+          return;
+        
+        this.status = msg.status;
+        if (this._onprogress) {
+          let event = new this._window.MozApplicationEvent("applicationinstall", { application: this });
+          this._onprogress.handleEvent(event);
+        }
+        break;
     }
-    this.removeRequest(msg.requestID);
   },
 
   classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplication]),
 
   classInfo: XPCOMUtils.generateCI({classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
                                     contractID: "@mozilla.org/webapps/application;1",
@@ -316,16 +329,21 @@ function WebappsApplicationMgmt(aWindow)
                             "Webapps:Install:Return:OK", "Webapps:Uninstall:Return:OK"]);
 
   this._oninstall = null;
   this._onuninstall = null;
 }
 
 WebappsApplicationMgmt.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
+  __exposedProps__: {
+                      getAll: 'r',
+                      oninstall: 'rw',
+                      onuninstall: 'rw'
+                     },
 
   uninit: function() {
     this._oninstall = null;
     this._onuninstall = null;
   },
 
   getAll: function() {
     let request = this.createRequest();
@@ -371,25 +389,25 @@ WebappsApplicationMgmt.prototype = {
         break;
       case "Webapps:GetAll:Return:KO":
         Services.DOMRequest.fireError(req, "DENIED");
         break;
       case "Webapps:Install:Return:OK":
         if (this._oninstall) {
           let app = msg.app;
           let event = new this._window.MozApplicationEvent("applicationinstall", 
-                           { application : new WebappsApplication(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
+                           { application : createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
                                                                   app.installOrigin, app.installTime) });
           this._oninstall.handleEvent(event);
         }
         break;
       case "Webapps:Uninstall:Return:OK":
         if (this._onuninstall) {
           let event = new this._window.MozApplicationEvent("applicationuninstall", 
-                           { application : new WebappsApplication(this._window, msg.origin, null, null, null, null, 0) });
+                           { application : createApplicationObject(this._window, msg.origin, null, null, null, null, 0) });
           this._onuninstall.handleEvent(event);
         }
         break;
     }
     this.removeRequest(msg.requestID);
   },
 
   classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"),
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -151,26 +151,28 @@ let DOMApplicationRegistry = {
 
   // clones a app object, without the manifest
   _cloneAppObject: function(aApp) {
     let clone = {
       installOrigin: aApp.installOrigin,
       origin: aApp.origin,
       receipts: aApp.receipts,
       installTime: aApp.installTime,
-      manifestURL: aApp.manifestURL
+      manifestURL: aApp.manifestURL,
+      progress: aApp.progress || 0.0,
+      status: aApp.status || "installed"
     };
     return clone;
   },
 
   denyInstall: function(aData) {
     ppmm.sendAsyncMessage("Webapps:Install:Return:KO", aData);
   },
 
-  confirmInstall: function(aData, aFromSync) {
+  confirmInstall: function(aData, aFromSync, aProfileDir, aOfflineCacheObserver) {
     let app = aData.app;
     let id = app.syncId || this._appId(app.origin);
 
     // install an application again is considered as an update
     if (id) {
       let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
       try {
         dir.remove(true);
@@ -186,21 +188,39 @@ let DOMApplicationRegistry = {
     appNote.id = id;
 
     let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
     let manFile = dir.clone();
     manFile.append("manifest.webapp");
     this._writeFile(manFile, JSON.stringify(app.manifest));
     this.webapps[id] = appObject;
 
+    appObject.status = "installed";
+    
+    let manifest = new DOMApplicationManifest(app.manifest, app.origin);
+
     if (!aFromSync)
       this._saveApps((function() {
         ppmm.sendAsyncMessage("Webapps:Install:Return:OK", aData);
         Services.obs.notifyObservers(this, "webapps-sync-install", appNote);
       }).bind(this));
+
+    // if the manifest has an appcache_path property, use it to populate the appcache
+    if (manifest.appcache_path) {
+      let appcacheURI = Services.io.newURI(manifest.fullAppcachePath(), null, null);
+      let updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]
+                            .getService(Ci.nsIOfflineCacheUpdateService);
+      let docURI = Services.io.newURI(manifest.fullLaunchPath(), null, null);
+      let cacheUpdate = aProfileDir ? updateService.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
+                                    : updateService.scheduleUpdate(appcacheURI, docURI, null);
+      cacheUpdate.addObserver(new AppcacheObserver(appObject), false);
+      if (aOfflineCacheObserver) {
+        cacheUpdate.addObserver(aOfflineCacheObserver, false);
+      }
+    }
   },
 
   _appId: function(aURI) {
     for (let id in this.webapps) {
       if (this.webapps[id].origin == aURI)
         return id;
     }
     return null;
@@ -424,16 +444,63 @@ let DOMApplicationRegistry = {
       } catch (e) {
       }
     }
     this._saveApps(aCallback);
   }
 };
 
 /**
+ * Appcache download observer
+ */
+AppcacheObserver = function(aApp) {
+  this.app = aApp;
+};
+
+AppcacheObserver.prototype = {
+  // nsIOfflineCacheUpdateObserver implementation
+  updateStateChanged: function appObs_Update(aUpdate, aState) {
+    let mustSave = false;
+    let app = this.app;
+
+    let setStatus = function appObs_setStatus(aStatus) {
+      mustSave = (app.status != aStatus);
+      app.status = aStatus;
+      ppmm.sendAsyncMessage("Webapps:OfflineCache", { manifest: app.manifestURL, status: aStatus });
+    }
+
+    switch (aState) {
+      case Ci.nsIOfflineCacheUpdateObserver.STATE_ERROR:
+        aUpdate.removeObserver(this);
+        setStatus("cache-error");
+        break;
+      case Ci.nsIOfflineCacheUpdateObserver.STATE_NOUPDATE:
+      case Ci.nsIOfflineCacheUpdateObserver.STATE_FINISHED:
+        aUpdate.removeObserver(this);
+        setStatus("cached");
+        break;
+      case Ci.nsIOfflineCacheUpdateObserver.STATE_DOWNLOADING:
+      case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
+      case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS:
+        setStatus("downloading")
+        break;
+    }
+
+    // Status changed, update the stored version.
+    if (mustSave) {
+      DOMApplicationRegistry._saveApps();
+    }
+  },
+
+  applicationCacheAvailable: function appObs_CacheAvail(aApplicationCache) {
+    // Nothing to do.
+  }
+};
+
+/**
  * Helper object to access manifest information with locale support
  */
 DOMApplicationManifest = function(aManifest, aOrigin) {
   this._origin = Services.io.newURI(aOrigin, null, null);
   this._manifest = aManifest;
   let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry)
                                                           .QueryInterface(Ci.nsIToolkitChromeRegistry);
   let locale = chrome.getSelectedLocale("browser").toLowerCase();
@@ -476,16 +543,20 @@ DOMApplicationManifest.prototype = {
   get developer() {
     return this._localeProp("developer");
   },
 
   get icons() {
     return this._localeProp("icons");
   },
 
+  get appcache_path() {
+    return this._localeProp("appcache_path");
+  },
+
   iconURLForSize: function(aSize) {
     let icons = this._localeProp("icons");
     if (!icons)
       return null;
     let dist = 100000;
     let icon = null;
     for (let size in icons) {
       let iSize = parseInt(size);
@@ -496,12 +567,17 @@ DOMApplicationManifest.prototype = {
     }
     return icon;
   },
 
   fullLaunchPath: function(aStartPoint) {
     let startPoint = aStartPoint || "";
     let launchPath = this._localeProp("launch_path") || "";
     return this._origin.resolve(launchPath + startPoint);
+  },
+
+  fullAppcachePath: function() {
+    let appcachePath = this._localeProp("appcache_path");
+    return this._origin.resolve(appcachePath ? appcachePath : "");
   }
 };
 
 DOMApplicationRegistry.init();
--- a/dom/apps/src/Webapps.manifest
+++ b/dom/apps/src/Webapps.manifest
@@ -1,4 +1,7 @@
 # Webapps.js
 component {fff440b3-fae2-45c1-bf03-3b5a2e432270} Webapps.js
 contract @mozilla.org/webapps;1 {fff440b3-fae2-45c1-bf03-3b5a2e432270}
 category JavaScript-navigator-property mozApps @mozilla.org/webapps;1
+
+component {723ed303-7757-4fb0-b261-4f78b1f6bd22} Webapps.js
+contract @mozilla.org/webapps/application;1 {723ed303-7757-4fb0-b261-4f78b1f6bd22}
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -569,18 +569,17 @@ static const char kDOMStringBundleURL[] 
 
 // We need to let JavaScript QI elements to interfaces that are not in
 // the classinfo since XBL can be used to dynamically implement new
 // unknown interfaces on elements, accessibility relies on this being
 // possible.
 
 #define ELEMENT_SCRIPTABLE_FLAGS                                              \
   ((NODE_SCRIPTABLE_FLAGS & ~nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY) |   \
-   nsIXPCScriptable::WANT_POSTCREATE |                                        \
-   nsIXPCScriptable::WANT_ENUMERATE)
+   nsIXPCScriptable::WANT_POSTCREATE)
 
 #define EXTERNAL_OBJ_SCRIPTABLE_FLAGS                                         \
   ((ELEMENT_SCRIPTABLE_FLAGS &                                                \
     ~nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY) |                          \
    nsIXPCScriptable::WANT_POSTCREATE |                                        \
    nsIXPCScriptable::WANT_GETPROPERTY |                                       \
    nsIXPCScriptable::WANT_SETPROPERTY |                                       \
    nsIXPCScriptable::WANT_CALL)
@@ -8183,37 +8182,16 @@ nsElementSH::PostCreate(nsIXPConnectWrap
       nsContentUtils::AddScriptRunner(
         NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
     }
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsElementSH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
-                       JSObject *obj, bool *_retval)
-{
-  // Make sure to not call the superclass here!
-  nsCOMPtr<nsIContent> content(do_QueryWrappedNative(wrapper, obj));
-  NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
-
-  nsIDocument* doc = content->OwnerDoc();
-
-  nsRefPtr<nsXBLBinding> binding = doc->BindingManager()->GetBinding(content);
-  if (!binding) {
-    // Nothing else to do here
-    return NS_OK;
-  }
-
-  *_retval = binding->ResolveAllFields(cx, obj);
-  
-  return NS_OK;
-}
-  
 
 // Generic array scriptable helper.
 
 NS_IMETHODIMP
 nsGenericArraySH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                              JSObject *obj, jsid id, PRUint32 flags,
                              JSObject **objp, bool *_retval)
 {
@@ -8552,31 +8530,19 @@ nsDOMStringMapSH::Enumerate(nsIXPConnect
 NS_IMETHODIMP
 nsDOMStringMapSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
                             JSObject *globalObj, JSObject **parentObj)
 {
   *parentObj = globalObj;
 
   nsDOMStringMap* dataset = static_cast<nsDOMStringMap*>(nativeObj);
 
-  nsIDocument* document = dataset->GetElement()->OwnerDoc();
-
-  nsCOMPtr<nsIScriptGlobalObject> sgo =
-      do_GetInterface(document->GetScopeObject());
-
-  if (sgo) {
-    JSObject *global = sgo->GetGlobalJSObject();
-
-    if (global) {
-      *parentObj = global;
-      return NS_OK;
-    }
-  }
-
-  return NS_OK;
+  // Parent the string map to its element.
+  nsINode* element = dataset->GetElement();
+  return WrapNativeParent(cx, globalObj, element, element, parentObj);
 }
 
 NS_IMETHODIMP
 nsDOMStringMapSH::DelProperty(nsIXPConnectWrappedNative *wrapper,
                               JSContext *cx, JSObject *obj, jsid id,
                               jsval *vp, bool *_retval)
 {
   nsCOMPtr<nsIDOMDOMStringMap> dataset(do_QueryWrappedNative(wrapper, obj));
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -557,18 +557,16 @@ protected:
   {
   }
 
 public:
   NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
                        JSObject *globalObj, JSObject **parentObj);
   NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj);
-  NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
-                       JSObject *obj, bool *_retval);
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsElementSH(aData);
   }
 };
 
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -487,16 +487,17 @@ NS_IMETHODIMP
 nsDOMWindowUtils::SendMouseEventToWindow(const nsAString& aType,
                                          float aX,
                                          float aY,
                                          PRInt32 aButton,
                                          PRInt32 aClickCount,
                                          PRInt32 aModifiers,
                                          bool aIgnoreRootScrollFrame)
 {
+  SAMPLE_LABEL("nsDOMWindowUtils", "SendMouseEventToWindow");
   return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers,
                               aIgnoreRootScrollFrame, true);
 }
 
 static nsIntPoint
 ToWidgetPoint(float aX, float aY, const nsPoint& aOffset,
               nsPresContext* aPresContext)
 {
@@ -1820,23 +1821,23 @@ nsDOMWindowUtils::GetParent(const JS::Va
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // First argument must be an object.
   if (JSVAL_IS_PRIMITIVE(aObject)) {
     return NS_ERROR_XPC_BAD_CONVERT_JS;
   }
 
-  JSObject* parent = JS_GetParent(JSVAL_TO_OBJECT(aObject));
+  JS::Rooted<JSObject*> parent(aCx, JS_GetParent(JSVAL_TO_OBJECT(aObject)));
   *aParent = OBJECT_TO_JSVAL(parent);
 
   // Outerize if necessary.
   if (parent) {
     if (JSObjectOp outerize = js::GetObjectClass(parent)->ext.outerObject) {
-      *aParent = OBJECT_TO_JSVAL(outerize(aCx, JS::RootedObject(aCx, parent)));
+      *aParent = OBJECT_TO_JSVAL(outerize(aCx, parent));
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetOuterWindowID(PRUint64 *aWindowID)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1085,16 +1085,17 @@ nsGlobalWindow::FreeInnerObjects()
 
   if (mNavigator) {
     mNavigator->OnNavigation();
     mNavigator->Invalidate();
     mNavigator = nsnull;
   }
 
   if (mScreen) {
+    mScreen->Reset();
     mScreen = nsnull;
   }
 
   if (mDocument) {
     NS_ASSERTION(mDoc, "Why is mDoc null?");
 
     // Remember the document's principal.
     mDocumentPrincipal = mDoc->NodePrincipal();
--- a/dom/base/nsScreen.cpp
+++ b/dom/base/nsScreen.cpp
@@ -58,18 +58,35 @@ nsScreen::Create(nsPIDOMWindow* aWindow)
   return screen.forget();
 }
 
 nsScreen::nsScreen()
   : mEventListener(nsnull)
 {
 }
 
+void
+nsScreen::Reset()
+{
+  hal::UnlockScreenOrientation();
+
+  if (mEventListener) {
+    nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
+    if (target) {
+      target->RemoveSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"),
+                                        mEventListener, true);
+    }
+
+    mEventListener = nsnull;
+  }
+}
+
 nsScreen::~nsScreen()
 {
+  Reset();
   hal::UnregisterScreenConfigurationObserver(this);
 }
 
 
 DOMCI_DATA(Screen, nsScreen)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsScreen)
 
@@ -313,61 +330,56 @@ nsScreen::GetMozOrientation(nsAString& a
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScreen::MozLockOrientation(const nsAString& aOrientation, bool* aReturn)
 {
   ScreenOrientation orientation;
+  *aReturn = false;
 
   if (aOrientation.EqualsLiteral("portrait")) {
     orientation = eScreenOrientation_Portrait;
   } else if (aOrientation.EqualsLiteral("portrait-primary")) {
     orientation = eScreenOrientation_PortraitPrimary;
   } else if (aOrientation.EqualsLiteral("portrait-secondary")) {
     orientation = eScreenOrientation_PortraitSecondary;
   } else if (aOrientation.EqualsLiteral("landscape")) {
     orientation = eScreenOrientation_Landscape;
   } else if (aOrientation.EqualsLiteral("landscape-primary")) {
     orientation = eScreenOrientation_LandscapePrimary;
   } else if (aOrientation.EqualsLiteral("landscape-secondary")) {
     orientation = eScreenOrientation_LandscapeSecondary;
   } else {
-    *aReturn = false;
     return NS_OK;
   }
 
   if (!GetOwner()) {
-    *aReturn = false;
     return NS_OK;
   }
 
-  if (!IsChromeType(GetOwner()->GetDocShell())) {
+  // Chrome code and apps can always lock the screen orientation.
+  if (!IsChromeType(GetOwner()->GetDocShell()) &&
+      !static_cast<nsGlobalWindow*>(GetOwner())->IsPartOfApp()) {
     nsCOMPtr<nsIDOMDocument> doc;
     GetOwner()->GetDocument(getter_AddRefs(doc));
     if (!doc) {
-      *aReturn = false;
       return NS_OK;
     }
 
-    // Apps and frames contained in apps can lock orientation.
-    // But non-apps can lock orientation only if they're fullscreen.
-    if (!static_cast<nsGlobalWindow*>(GetOwner())->IsPartOfApp()) {
-      bool fullscreen;
-      doc->GetMozFullScreen(&fullscreen);
-      if (!fullscreen) {
-        *aReturn = false;
-        return NS_OK;
-      }
+    // Non-apps content can lock orientation only if fullscreen.
+    bool fullscreen;
+    doc->GetMozFullScreen(&fullscreen);
+    if (!fullscreen) {
+      return NS_OK;
     }
 
     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
     if (!target) {
-      *aReturn = false;
       return NS_OK;
     }
 
     if (!mEventListener) {
       mEventListener = new FullScreenEventListener();
     }
 
     target->AddSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"),
--- a/dom/base/nsScreen.h
+++ b/dom/base/nsScreen.h
@@ -21,17 +21,17 @@ struct nsRect;
 // Script "screen" object
 class nsScreen : public nsDOMEventTargetHelper
                , public nsIDOMScreen
                , public mozilla::hal::ScreenConfigurationObserver
 {
 public:
   static already_AddRefed<nsScreen> Create(nsPIDOMWindow* aWindow);
 
-  void Invalidate();
+  void Reset();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMSCREEN
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsScreen,
                                            nsDOMEventTargetHelper)
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2113,17 +2113,18 @@ for (uint32_t i = 0; i < length; ++i) {
 JSString* %(resultStr)s = JS_NewStringCopyN(cx, %(strings)s[uint32_t(%(result)s)].value, %(strings)s[uint32_t(%(result)s)].length);
 if (!%(resultStr)s) {
   return false;
 }
 """ % { "result" : result,
         "resultStr" : result + "_str",
         "strings" : type.inner.identifier.name + "Values::strings" } + setValue("JS::StringValue(%s_str)" % result)
 
-    if type.isCallback() and not type.isInterface():
+    if type.isCallback():
+        assert not type.isInterface()
         # XXXbz we're going to assume that callback types are always
         # nullable and always have [TreatNonCallableAsNull] for now.
         # See comments in WrapNewBindingObject explaining why we need
         # to wrap here.
         return setValue("JS::ObjectOrNullValue(%s)" % result, True)
 
     if type.tag() == IDLType.Tags.any:
         # See comments in WrapNewBindingObject explaining why we need
@@ -2617,18 +2618,17 @@ class CGMethodCall(CGThing):
                                lambda s: s[1][distinguishingIndex].type.nullable())
 
             # Now check for distinguishingArg being an object that implements a
             # non-callback interface.  That includes typed arrays and
             # arraybuffers.
             interfacesSigs = [
                 s for s in possibleSignatures
                 if (s[1][distinguishingIndex].type.isObject() or
-                    (s[1][distinguishingIndex].type.isInterface() and
-                     not s[1][distinguishingIndex].type.isCallback())) ]
+                    s[1][distinguishingIndex].type.isNonCallbackInterface()) ]
             # There might be more than one of these; we need to check
             # which ones we unwrap to.
             
             if len(interfacesSigs) > 0:
                 # The spec says that we should check for "platform objects
                 # implementing an interface", but it's enough to guard on these
                 # being an object.  The code for unwrapping non-callback
                 # interfaces and typed arrays will just bail out and move on to
@@ -2687,16 +2687,17 @@ class CGMethodCall(CGThing):
                                lambda s: (s[1][distinguishingIndex].type.isDate() or
                                           s[1][distinguishingIndex].type.isObject()))
 
             # Check for vanilla JS objects
             # XXXbz Do we need to worry about security wrappers?
             pickFirstSignature("%s.isObject() && !IsPlatformObject(cx, &%s.toObject())" %
                                (distinguishingArg, distinguishingArg),
                                lambda s: (s[1][distinguishingIndex].type.isCallback() or
+                                          s[1][distinguishingIndex].type.isCallbackInterface() or
                                           s[1][distinguishingIndex].type.isDictionary() or
                                           s[1][distinguishingIndex].type.isObject()))
 
             # The remaining cases are mutually exclusive.  The
             # pickFirstSignature calls are what change caseBody
             # Check for strings or enums
             if pickFirstSignature(None,
                                   lambda s: (s[1][distinguishingIndex].type.isString() or
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -421,16 +421,23 @@ class IDLInterface(IDLObjectWithScope):
             # anything that has consequential interfaces.
             if self.isCallback():
                 assert(self.parent.isCallback())
                 assert(len(self.parent.getConsequentialInterfaces()) == 0)
 
         for iface in self.implementedInterfaces:
             iface.finish(scope)
 
+        cycleInGraph = self.findInterfaceLoopPoint(self)
+        if cycleInGraph:
+            raise WebIDLError("Interface %s has itself as ancestor or "
+                              "implemented interface" % self.identifier.name,
+                              self.location,
+                              extraLocation=cycleInGraph.location)
+
         # Now resolve() and finish() our members before importing the
         # ones from our implemented interfaces.
 
         # resolve() will modify self.members, so we need to iterate
         # over a copy of the member list here.
         for member in list(self.members):
             member.resolve(self)
 
@@ -589,16 +596,36 @@ class IDLInterface(IDLObjectWithScope):
 
         # And now collect up the consequential interfaces of all of those
         temp = set()
         for iface in consequentialInterfaces:
             temp |= iface.getConsequentialInterfaces()
 
         return consequentialInterfaces | temp
 
+    def findInterfaceLoopPoint(self, otherInterface):
+        """
+        Finds an interface, amongst our ancestors and consequential interfaces,
+        that inherits from otherInterface or implements otherInterface
+        directly.  If there is no such interface, returns None.
+        """
+        if self.parent:
+            if self.parent == otherInterface:
+                return self
+            loopPoint = self.parent.findInterfaceLoopPoint(otherInterface)
+            if loopPoint:
+                return loopPoint
+        if otherInterface in self.implementedInterfaces:
+            return self
+        for iface in self.implementedInterfaces:
+            loopPoint = iface.findInterfaceLoopPoint(otherInterface)
+            if loopPoint:
+                return loopPoint
+        return None
+
 class IDLDictionary(IDLObjectWithScope):
     def __init__(self, location, parentScope, name, parent, members):
         assert isinstance(parentScope, IDLScope)
         assert isinstance(name, IDLUnresolvedIdentifier)
         assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
 
         self.parent = parent
         self._finished = False
@@ -756,16 +783,22 @@ class IDLType(IDLObject):
         return False
 
     def isArrayBufferView(self):
         return False
 
     def isTypedArray(self):
         return False
 
+    def isCallbackInterface(self):
+        return False
+
+    def isNonCallbackInterface(self):
+        return False
+
     def isGeckoInterface(self):
         """ Returns a boolean indicating whether this type is an 'interface'
             type that is implemented in Gecko. At the moment, this returns
             true for all interface types that are not types from the TypedArray
             spec."""
         return self.isInterface() and not self.isSpiderMonkeyInterface()
 
     def isSpiderMonkeyInterface(self):
@@ -903,16 +936,22 @@ class IDLNullableType(IDLType):
         return self.inner.isTypedArray()
 
     def isDictionary(self):
         return self.inner.isDictionary()
 
     def isInterface(self):
         return self.inner.isInterface()
 
+    def isCallbackInterface(self):
+        return self.inner.isCallbackInterface()
+
+    def isNonCallbackInterface(self):
+        return self.inner.isNonCallbackInterface()
+
     def isEnum(self):
         return self.inner.isEnum()
 
     def tag(self):
         return self.inner.tag()
 
     def resolveType(self, parentScope):
         assert isinstance(parentScope, IDLScope)
@@ -993,17 +1032,17 @@ class IDLSequenceType(IDLType):
         return self
 
     def unroll(self):
         return self.inner.unroll()
 
     def isDistinguishableFrom(self, other):
         return (other.isPrimitive() or other.isString() or other.isEnum() or
                 other.isDictionary() or other.isDate() or
-                (other.isInterface() and not other.isCallback()))
+                other.isNonCallbackInterface())
 
 class IDLArrayType(IDLType):
     def __init__(self, location, parameterType):
         assert not parameterType.isVoid()
         if parameterType.isSequence():
             raise WebIDLError("Array type cannot parameterize over a sequence type",
                               location)
         if parameterType.isDictionary():
@@ -1066,17 +1105,17 @@ class IDLArrayType(IDLType):
         return self
 
     def unroll(self):
         return self.inner.unroll()
 
     def isDistinguishableFrom(self, other):
         return (other.isPrimitive() or other.isString() or other.isEnum() or
                 other.isDictionary() or other.isDate() or
-                (other.isInterface() and not other.isCallback()))
+                other.isNonCallbackInterface())
 
 class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
     def __init__(self, location, innerType, name):
         IDLType.__init__(self, location, innerType.name)
 
         identifier = IDLUnresolvedIdentifier(location, name)
 
         IDLObjectWithIdentifier.__init__(self, location, None, identifier)
@@ -1119,16 +1158,22 @@ class IDLTypedefType(IDLType, IDLObjectW
         return self.inner.isArrayBufferView()
 
     def isTypedArray(self):
         return self.inner.isTypedArray()
 
     def isInterface(self):
         return self.inner.isInterface()
 
+    def isCallbackInterface(self):
+        return self.inner.isCallbackInterface()
+
+    def isNonCallbackInterface(self):
+        return self.inner.isNonCallbackInterface()
+
     def resolve(self, parentScope):
         assert isinstance(parentScope, IDLScope)
         IDLObjectWithIdentifier.resolve(self, parentScope)
 
     def tag(self):
         return self.inner.tag()
 
     def unroll(self):
@@ -1172,16 +1217,22 @@ class IDLWrapperType(IDLType):
 
     def isDictionary(self):
         return isinstance(self.inner, IDLDictionary)
 
     def isInterface(self):
         return isinstance(self.inner, IDLInterface) or \
                isinstance(self.inner, IDLExternalInterface)
 
+    def isCallbackInterface(self):
+        return self.isInterface() and self.inner.isCallback()
+
+    def isNonCallbackInterface(self):
+        return self.isInterface() and not self.inner.isCallback()
+
     def isEnum(self):
         return isinstance(self.inner, IDLEnum)
 
     def resolveType(self, parentScope):
         assert isinstance(parentScope, IDLScope)
         self.inner.resolve(parentScope)
 
     def isComplete(self):
@@ -1193,33 +1244,38 @@ class IDLWrapperType(IDLType):
         elif self.isEnum():
             return IDLType.Tags.enum
         elif self.isDictionary():
             return IDLType.Tags.dictionary
         else:
             assert False
 
     def isDistinguishableFrom(self, other):
-        assert self.isInterface() or self.isEnum()
+        assert self.isInterface() or self.isEnum() or self.isDictionary()
         if self.isEnum():
             return (other.isInterface() or other.isObject() or
                     other.isCallback() or other.isDictionary() or
                     other.isSequence() or other.isArray() or
                     other.isDate())
         if other.isPrimitive() or other.isString() or other.isEnum():
             return True
+        if self.isDictionary():
+            return (other.isNonCallbackInterface() or other.isSequence() or
+                    other.isArray() or other.isDate())
+
+        assert self.isInterface()
         # XXXbz need to check that the interfaces can't be implemented
         # by the same object
         if other.isInterface():
             return (self != other and
-                    (not self.isCallback() or not other.isCallback()))
-        if other.isDictionary() or other.isCallback():
-            return not self.isCallback()
-        if other.isSequence() or other.isArray():
-            return not self.isCallback()
+                    (self.isNonCallbackInterface() or
+                     other.isNonCallbackInterface()))
+        if (other.isDictionary() or other.isCallback() or
+            other.isSequence() or other.isArray()):
+            return self.isNonCallbackInterface()
 
 class IDLBuiltinType(IDLType):
 
     Types = enum(
         # The integer types
         'byte',
         'octet',
         'short',
@@ -1309,16 +1365,20 @@ class IDLBuiltinType(IDLType):
     def isInterface(self):
         # TypedArray things are interface types per the TypedArray spec,
         # but we handle them as builtins because SpiderMonkey implements
         # all of it internally.
         return self.isArrayBuffer() or \
                self.isArrayBufferView() or \
                self.isTypedArray()
 
+    def isNonCallbackInterface(self):
+        # All the interfaces we can be are non-callback
+        return self.isInterface()
+
     def isFloat(self):
         return self._typeTag == IDLBuiltinType.Types.float or \
                self._typeTag == IDLBuiltinType.Types.double
 
     def tag(self):
         return IDLBuiltinType.TagLookup[self._typeTag]
 
     def isDistinguishableFrom(self, other):
@@ -1342,17 +1402,17 @@ class IDLBuiltinType(IDLType):
         # Not much else we could be!
         assert self.isSpiderMonkeyInterface()
         # Like interfaces, but we know we're not a callback
         return (other.isPrimitive() or other.isString() or other.isEnum() or
                 other.isCallback() or other.isDictionary() or
                 other.isSequence() or other.isArray() or other.isDate() or
                 (other.isInterface() and (
                  # ArrayBuffer is distinguishable from everything
-                 # that's not an ArrayBuffer
+                 # that's not an ArrayBuffer or a callback interface
                  (self.isArrayBuffer() and not other.isArrayBuffer()) or
                  # ArrayBufferView is distinguishable from everything
                  # that's not an ArrayBufferView or typed array.
                  (self.isArrayBufferView() and not other.isArrayBufferView() and
                   not other.isTypedArray()) or
                  # Typed arrays are distinguishable from everything
                  # except ArrayBufferView and the same type of typed
                  # array
@@ -1676,18 +1736,17 @@ class IDLCallbackType(IDLType, IDLObject
             type = argument.type.complete(scope)
 
             assert not isinstance(type, IDLUnresolvedType)
             assert not isinstance(type.name, IDLUnresolvedIdentifier)
             argument.type = type
 
     def isDistinguishableFrom(self, other):
         return (other.isPrimitive() or other.isString() or other.isEnum() or
-                (other.isInterface() and not other.isCallback()) or
-                other.isDate())
+                other.isNonCallbackInterface() or other.isDate())
 
 class IDLMethod(IDLInterfaceMember, IDLScope):
 
     Special = enum(
         'None',
         'Getter',
         'Setter',
         'Creator',
--- a/dom/bindings/parser/tests/test_dictionary.py
+++ b/dom/bindings/parser/tests/test_dictionary.py
@@ -1,10 +1,8 @@
-import WebIDL
-
 def WebIDLTest(parser, harness):
     parser.parse("""
       dictionary Dict2 : Dict1 {
         long child = 5;
         Dict1 aaandAnother;
       };
       dictionary Dict1 {
         long parent;
@@ -24,33 +22,33 @@ def WebIDLTest(parser, harness):
     harness.check(dict1.members[1].identifier.name, "parent",
                   "'o' really comes before 'p'")
     harness.check(dict2.members[0].identifier.name, "aaandAnother",
                   "'a' comes before 'c'")
     harness.check(dict2.members[1].identifier.name, "child",
                   "'a' really comes before 'c'")
 
     # Now reset our parser
-    parser = WebIDL.Parser()
+    parser = parser.reset()
     threw = False
     try:
         parser.parse("""
           dictionary Dict {
             long prop = 5;
             long prop;
           };
         """)
         results = parser.finish()
     except:
         threw = True
 
     harness.ok(threw, "Should not allow name duplication in a dictionary")
 
     # Now reset our parser again
-    parser = WebIDL.Parser()
+    parser = parser.reset()
     threw = False
     try:
         parser.parse("""
           dictionary Dict1 : Dict2 {
             long prop = 5;
           };
           dictionary Dict2 : Dict3 {
             long prop2;
@@ -62,33 +60,33 @@ def WebIDLTest(parser, harness):
         results = parser.finish()
     except:
         threw = True
 
     harness.ok(threw, "Should not allow name duplication in a dictionary and "
                "its ancestor")
 
     # More reset
-    parser = WebIDL.Parser()
+    parser = parser.reset()
     threw = False
     try:
         parser.parse("""
           interface Iface {};
           dictionary Dict : Iface {
             long prop;
           };
         """)
         results = parser.finish()
     except:
         threw = True
 
     harness.ok(threw, "Should not allow non-dictionary parents for dictionaries")
 
     # Even more reset
-    parser = WebIDL.Parser()
+    parser = parser.reset()
     threw = False
     try:
         parser.parse("""
             dictionary A : B {};
             dictionary B : A {};
         """)
         results = parser.finish()
     except:
new file mode 100644
--- /dev/null
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -0,0 +1,33 @@
+def WebIDLTest(parser, harness):
+    parser.parse("""
+      dictionary Dict {
+      };
+      callback interface Foo {
+      };
+      interface Bar {
+        // Bit of a pain to get things that have dictionary types
+        void passDict(Dict arg);
+        void passFoo(Foo arg);
+      };
+    """)
+    results = parser.finish()
+
+    iface = results[2]
+    harness.ok(iface.isInterface(), "Should have interface")
+    dictMethod = iface.members[0]
+    ifaceMethod = iface.members[1]
+
+    def firstArgType(method):
+        return method.signatures()[0][1][0].type
+
+    dictType = firstArgType(dictMethod)
+    ifaceType = firstArgType(ifaceMethod)
+
+    harness.ok(dictType.isDictionary(), "Should have dictionary type");
+    harness.ok(ifaceType.isInterface(), "Should have interface type");
+    harness.ok(ifaceType.isCallbackInterface(), "Should have callback interface type");
+
+    harness.ok(not dictType.isDistinguishableFrom(ifaceType),
+               "Dictionary not distinguishable from callback interface")
+    harness.ok(not ifaceType.isDistinguishableFrom(dictType),
+               "Callback interface not distinguishable from dictionary")
--- a/dom/bindings/parser/tests/test_interface.py
+++ b/dom/bindings/parser/tests/test_interface.py
@@ -47,8 +47,129 @@ def WebIDLTest(parser, harness):
     base = results[0]
     derived = results[1]
     harness.check(base.members[0].identifier.QName(), "::QNameBase::foo",
                   "Member has the right QName")
     harness.check(derived.members[0].identifier.QName(), "::QNameDerived::foo",
                   "Member has the right QName")
     harness.check(derived.members[1].identifier.QName(), "::QNameDerived::bar",
                   "Member has the right QName")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            interface A : B {};
+            interface B : A {};
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Should not allow cycles in interface inheritance chains")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            interface A : C {};
+            interface C : B {};
+            interface B : A {};
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Should not allow indirect cycles in interface inheritance chains")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            interface A {};
+            interface B {};
+            A implements B;
+            B implements A;
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Should not allow cycles via implements")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            interface A {};
+            interface C {};
+            interface B {};
+            A implements C;
+            C implements B;
+            B implements A;
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Should not allow indirect cycles via implements")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            interface A : B {};
+            interface B {};
+            B implements A;
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Should not allow inheriting from an interface that implements us")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            interface A : B {};
+            interface B {};
+            interface C {};
+            B implements C;
+            C implements A;
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Should not allow inheriting from an interface that indirectly implements us")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            interface A : B {};
+            interface B : C {};
+            interface C {};
+            C implements A;
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Should not allow indirectly inheriting from an interface that implements us")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            interface A : B {};
+            interface B : C {};
+            interface C {};
+            interface D {};
+            C implements D;
+            D implements A;
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Should not allow indirectly inheriting from an interface that indirectly implements us")
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -292,16 +292,17 @@ interface DiamondBranch2B : DiamondImple
 TestInterface implements DiamondBranch1A;
 TestInterface implements DiamondBranch1B;
 TestInterface implements DiamondBranch2A;
 TestInterface implements DiamondBranch2B;
 DiamondBranch1A implements DiamondImplements;
 DiamondBranch1B implements DiamondImplements;
 
 dictionary Dict : ParentDict {
+  TestEnum someEnum;
   long x;
   long a;
   long b = 8;
   long z = 9;
   DOMString str;
 };
 
 dictionary ParentDict : GrandparentDict {
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -106,16 +106,20 @@ BrowserElementChild.prototype = {
 
     var self = this;
     function addMsgListener(msg, handler) {
       addMessageListener('browser-element-api:' + msg, handler.bind(self));
     }
 
     addMsgListener("get-screenshot", this._recvGetScreenshot);
     addMsgListener("set-visible", this._recvSetVisible);
+    addMsgListener("get-can-go-back", this._recvCanGoBack);
+    addMsgListener("get-can-go-forward", this._recvCanGoForward);
+    addMsgListener("go-back", this._recvGoBack);
+    addMsgListener("go-forward", this._recvGoForward);
     addMsgListener("unblock-modal-prompt", this._recvStopWaiting);
 
     let els = Cc["@mozilla.org/eventlistenerservice;1"]
                 .getService(Ci.nsIEventListenerService);
 
     // We are using the system group for those events so if something in the
     // content called .stopPropagation() this will still be called.
     els.addSystemEventListener(global, 'keydown',
@@ -315,27 +319,59 @@ BrowserElementChild.prototype = {
     var ctx = canvas.getContext("2d");
     canvas.mozOpaque = true;
     canvas.height = content.innerHeight;
     canvas.width = content.innerWidth;
     ctx.drawWindow(content, 0, 0, content.innerWidth,
                    content.innerHeight, "rgb(255,255,255)");
     sendAsyncMsg('got-screenshot', {
       id: data.json.id,
-      screenshot: canvas.toDataURL("image/png")
+      rv: canvas.toDataURL("image/png")
     });
   },
 
   _recvSetVisible: function(data) {
     debug("Received setVisible message: (" + data.json.visible + ")");
     if (docShell.isActive !== data.json.visible) {
       docShell.isActive = data.json.visible;
     }
   },
 
+  _recvCanGoBack: function(data) {
+    var webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
+    sendAsyncMsg('got-can-go-back', {
+      id: data.json.id,
+      rv: webNav.canGoBack
+    });
+  },
+
+  _recvCanGoForward: function(data) {
+    var webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
+    sendAsyncMsg('got-can-go-forward', {
+      id: data.json.id,
+      rv: webNav.canGoForward
+    });
+  },
+
+  _recvGoBack: function(data) {
+    try {
+      docShell.QueryInterface(Ci.nsIWebNavigation).goBack();
+    } catch(e) {
+      // Silently swallow errors; these happen when we can't go back.
+    }
+  },
+
+  _recvGoForward: function(data) {
+    try {
+      docShell.QueryInterface(Ci.nsIWebNavigation).goForward();
+    } catch(e) {
+      // Silently swallow errors; these happen when we can't go forward.
+    }
+  },
+
   _keyEventHandler: function(e) {
     if (whitelistedEvents.indexOf(e.keyCode) != -1 && !e.defaultPrevented) {
       sendAsyncMsg('keyevent', {
         type: e.type,
         keyCode: e.keyCode,
         charCode: e.charCode,
       });
     }
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -115,18 +115,18 @@ BrowserElementParentFactory.prototype = 
       this._observeContentGlobalCreated(subject);
       break;
     }
   },
 };
 
 function BrowserElementParent(frameLoader) {
   debug("Creating new BrowserElementParent object for " + frameLoader);
-  this._screenshotListeners = {};
-  this._screenshotReqCounter = 0;
+  this._domRequestCounter = 0;
+  this._pendingDOMRequests = {};
 
   this._frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
   if (!this._frameElement) {
     debug("No frame element?");
     return;
   }
 
   this._mm = frameLoader.messageManager;
@@ -145,28 +145,35 @@ function BrowserElementParent(frameLoade
   addMessageListener("loadend", this._fireEventFromMsg);
   addMessageListener("titlechange", this._fireEventFromMsg);
   addMessageListener("iconchange", this._fireEventFromMsg);
   addMessageListener("close", this._fireEventFromMsg);
   addMessageListener("securitychange", this._fireEventFromMsg);
   addMessageListener("get-mozapp-manifest-url", this._sendMozAppManifestURL);
   addMessageListener("keyevent", this._fireKeyEvent);
   addMessageListener("showmodalprompt", this._handleShowModalPrompt);
-  addMessageListener('got-screenshot', this._recvGotScreenshot);
+  addMessageListener('got-screenshot', this._gotDOMRequestResult);
+  addMessageListener('got-can-go-back', this._gotDOMRequestResult);
+  addMessageListener('got-can-go-forward', this._gotDOMRequestResult);
 
   function defineMethod(name, fn) {
     XPCNativeWrapper.unwrap(self._frameElement)[name] = fn.bind(self);
   }
 
+  function defineDOMRequestMethod(domName, msgName) {
+    XPCNativeWrapper.unwrap(self._frameElement)[domName] = self._sendDOMRequest.bind(self, msgName);
+  }
+
   // Define methods on the frame element.
-  defineMethod('getScreenshot', this._getScreenshot);
   defineMethod('setVisible', this._setVisible);
-
-  this._mm.loadFrameScript("chrome://global/content/BrowserElementChild.js",
-                           /* allowDelayedLoad = */ true);
+  defineMethod('goBack', this._goBack);
+  defineMethod('goForward', this._goForward);
+  defineDOMRequestMethod('getScreenshot', 'get-screenshot');
+  defineDOMRequestMethod('getCanGoBack', 'get-can-go-back');
+  defineDOMRequestMethod('getCanGoForward', 'get-can-go-forward');
 }
 
 BrowserElementParent.prototype = {
   get _window() {
     return this._frameElement.ownerDocument.defaultView;
   },
 
   _sendAsyncMsg: function(msg, data) {
@@ -260,35 +267,59 @@ BrowserElementParent.prototype = {
                                   { bubbles: true,
                                     cancelable: cancelable });
   },
 
   _sendMozAppManifestURL: function(data) {
     return this._frameElement.getAttribute('mozapp');
   },
 
-
-  _getScreenshot: function() {
-    let id = 'req_' + this._screenshotReqCounter++;
+  /**
+   * Kick off a DOMRequest in the child process.
+   *
+   * We'll fire an event called |msgName| on the child process, passing along
+   * an object with a single field, id, containing the ID of this request.
+   *
+   * We expect the child to pass the ID back to us upon completion of the
+   * request; see _gotDOMRequestResult.
+   */
+  _sendDOMRequest: function(msgName) {
+    let id = 'req_' + this._domRequestCounter++;
     let req = Services.DOMRequest.createRequest(this._window);
-    this._screenshotListeners[id] = req;
-    this._sendAsyncMsg('get-screenshot', {id: id});
+    this._pendingDOMRequests[id] = req;
+    this._sendAsyncMsg(msgName, {id: id});
     return req;
   },
 
-  _recvGotScreenshot: function(data) {
-    var req = this._screenshotListeners[data.json.id];
-    delete this._screenshotListeners[data.json.id];
-    Services.DOMRequest.fireSuccess(req, data.json.screenshot);
+  /**
+   * Called when the child process finishes handling a DOMRequest.  We expect
+   * data.json to have two fields:
+   *
+   *  - id: the ID of the DOM request (see _sendDOMRequest), and
+   *  - rv: the request's return value.
+   *
+   */
+  _gotDOMRequestResult: function(data) {
+    let req = this._pendingDOMRequests[data.json.id];
+    delete this._pendingDOMRequests[data.json.id];
+    Services.DOMRequest.fireSuccess(req, data.json.rv);
   },
 
   _setVisible: function(visible) {
     this._sendAsyncMsg('set-visible', {visible: visible});
   },
 
+  _goBack: function() {
+    this._sendAsyncMsg('go-back');
+  },
+
+  _goForward: function() {
+    this._sendAsyncMsg('go-forward');
+  },
+
   _fireKeyEvent: function(data) {
     let evt = this._window.document.createEvent("KeyboardEvent");
     evt.initKeyEvent(data.json.type, true, true, this._window,
                      false, false, false, false, // modifiers
                      data.json.keyCode,
                      data.json.charCode);
 
     this._frameElement.dispatchEvent(evt);
--- a/dom/browser-element/mochitest/Makefile.in
+++ b/dom/browser-element/mochitest/Makefile.in
@@ -53,19 +53,22 @@ include $(topsrcdir)/config/rules.mk
 		file_browserElement_Open1.html \
 		file_browserElement_Open2.html \
 		browserElement_OpenWindowRejected.js \
 		test_browserElement_inproc_OpenWindowRejected.html \
 		file_browserElement_OpenWindowRejected.html \
 		browserElement_SecurityChange.js \
 		test_browserElement_inproc_SecurityChange.html \
 		file_browserElement_SecurityChange.html \
+		browserElement_BackForward.js \
 		$(NULL)
 
 # OOP tests don't work on Windows (bug 763081).
+#
+# Note that there's no inproc equivalent of BackForward; that's intentional.
 ifneq ($(OS_ARCH),WINNT)
 _TEST_FILES += \
 		test_browserElement_oop_LoadEvents.html \
 		test_browserElement_oop_DataURI.html \
 		test_browserElement_oop_Titlechange.html \
 		test_browserElement_oop_TopBarrier.html \
 		test_browserElement_oop_Iconchange.html \
 		test_browserElement_oop_GetScreenshot.html \
@@ -73,14 +76,15 @@ ifneq ($(OS_ARCH),WINNT)
 		test_browserElement_oop_KeyEvents.html \
 		test_browserElement_oop_Alert.html \
 		test_browserElement_oop_PromptCheck.html \
 		test_browserElement_oop_PromptConfirm.html \
 		test_browserElement_oop_Close.html \
 		test_browserElement_oop_OpenWindow.html \
 		test_browserElement_oop_OpenWindowRejected.html \
 		test_browserElement_oop_SecurityChange.html \
+		test_browserElement_oop_BackForward.html \
 		$(NULL)
 endif
 
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/dom/browser-element/mochitest/browserElementTestHelpers.js
+++ b/dom/browser-element/mochitest/browserElementTestHelpers.js
@@ -96,23 +96,26 @@ const browserElementTestHelpers = {
   },
 
   'origEnabledPref': null,
   'origWhitelistPref': null,
   'origOOPDisabledPref': null,
   'origOOPByDefaultPref': null,
   'origPageThumbsEnabledPref': null,
 
-  // Two basically-empty pages from two different domains you can load.
+  // Some basically-empty pages from different domains you can load.
   'emptyPage1': 'http://example.com' +
                 window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) +
                 '/file_empty.html',
   'emptyPage2': 'http://example.org' +
                 window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) +
                 '/file_empty.html',
+  'emptyPage3': 'http://test1.example.org' +
+                window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) +
+                '/file_empty.html',
   'focusPage': 'http://example.org' +
                 window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) +
                 '/file_focus.html',
 };
 
 browserElementTestHelpers.origEnabledPref = browserElementTestHelpers.getEnabledPref();
 browserElementTestHelpers.origWhitelistPref = browserElementTestHelpers.getWhitelistPref();
 browserElementTestHelpers.origOOPDisabledPref = browserElementTestHelpers.getOOPDisabledPref();
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_BackForward.js
@@ -0,0 +1,112 @@
+/* Any copyright is dedicated to the public domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 741755 - Test that canGo{Back,Forward} and go{Forward,Back} work with
+// <iframe mozbrowser>.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+
+var iframe;
+function addOneShotIframeEventListener(event, fn) {
+  function wrapper(e) {
+    iframe.removeEventListener(event, wrapper);
+    fn(e);
+  };
+
+  iframe.addEventListener(event, wrapper);
+}
+
+function runTest() {
+  // At the moment, this isn't going to work unless we're actually out of
+  // process.
+  //
+  // With in-process mozbrowser, the root SHistory for an <iframe mozbrowser>
+  // crosses the mozbrowser boundary.  It's like the mozbrowser wasn't there;
+  // canGoBack reflects whether the top-level frame can go back, not whether the
+  // iframe itself can go back.
+  if (!browserElementTestHelpers.getOOPByDefaultPref()) {
+    ok(false, "This test only works OOP.");
+    return;
+  }
+
+  browserElementTestHelpers.setEnabledPref(true);
+  browserElementTestHelpers.addToWhitelist();
+
+  iframe = document.createElement('iframe');
+  iframe.mozbrowser = true;
+
+  addOneShotIframeEventListener('mozbrowserloadend', function() {
+    SimpleTest.executeSoon(test2);
+  });
+
+  iframe.src = browserElementTestHelpers.emptyPage1;
+  document.body.appendChild(iframe);
+}
+
+function checkCanGoBackAndForward(canGoBack, canGoForward, nextTest) {
+  var seenCanGoBackResult = false;
+  iframe.getCanGoBack().onsuccess = function(e) {
+    is(seenCanGoBackResult, false, "onsuccess handler shouldn't be called twice.");
+    seenCanGoBackResult = true;
+    is(e.target.result, canGoBack);
+    maybeRunNextTest();
+  };
+
+  var seenCanGoForwardResult = false;
+  iframe.getCanGoForward().onsuccess = function(e) {
+    is(seenCanGoForwardResult, false, "onsuccess handler shouldn't be called twice.");
+    seenCanGoForwardResult = true;
+    is(e.target.result, canGoForward);
+    maybeRunNextTest();
+  };
+
+  function maybeRunNextTest() {
+    if (seenCanGoBackResult && seenCanGoForwardResult) {
+      nextTest();
+    }
+  }
+}
+
+function test2() {
+  checkCanGoBackAndForward(false, false, test3);
+}
+
+function test3() {
+  addOneShotIframeEventListener('mozbrowserloadend', function() {
+    checkCanGoBackAndForward(true, false, test4);
+  });
+
+  SimpleTest.executeSoon(function() {
+    iframe.src = browserElementTestHelpers.emptyPage2;
+  });
+}
+
+function test4() {
+  addOneShotIframeEventListener('mozbrowserlocationchange', function(e) {
+    is(e.detail, browserElementTestHelpers.emptyPage3);
+    checkCanGoBackAndForward(true, false, test5);
+  });
+
+  SimpleTest.executeSoon(function() {
+    iframe.src = browserElementTestHelpers.emptyPage3;
+  });
+}
+
+function test5() {
+  addOneShotIframeEventListener('mozbrowserlocationchange', function(e) {
+    is(e.detail, browserElementTestHelpers.emptyPage2);
+    checkCanGoBackAndForward(true, true, test6);
+  });
+  iframe.goBack();
+}
+
+function test6() {
+  addOneShotIframeEventListener('mozbrowserlocationchange', function(e) {
+    is(e.detail, browserElementTestHelpers.emptyPage1);
+    checkCanGoBackAndForward(false, true, SimpleTest.finish);
+  });
+  iframe.goBack();
+}
+
+runTest();
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_BackForward.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test of browser element.</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_BackForward.js">
+</script>
+</body>
+</html>
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -209,18 +209,20 @@ IndexedDatabaseManager::GetOrCreate()
       instance->mCurrentWindowIndex = BAD_TLS_INDEX;
       return nsnull;
     }
 
     nsresult rv;
 
     if (sIsMainProcess) {
       nsCOMPtr<nsIFile> dbBaseDirectory;
-      rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
-                                  getter_AddRefs(dbBaseDirectory));
+      rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR, getter_AddRefs(dbBaseDirectory));
+      if (NS_FAILED(rv)) {
+          rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(dbBaseDirectory));
+      }
       NS_ENSURE_SUCCESS(rv, nsnull);
 
       rv = dbBaseDirectory->Append(NS_LITERAL_STRING("indexedDB"));
       NS_ENSURE_SUCCESS(rv, nsnull);
 
       rv = dbBaseDirectory->GetPath(instance->mDatabaseBasePath);
       NS_ENSURE_SUCCESS(rv, nsnull);
 
--- a/dom/interfaces/apps/nsIDOMApplicationRegistry.idl
+++ b/dom/interfaces/apps/nsIDOMApplicationRegistry.idl
@@ -4,25 +4,44 @@
 
 #include "domstubs.idl"
 #include "nsIDOMEvent.idl"
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMDOMRequest;
 interface nsIArray;
 
-[scriptable, uuid(b70b84f1-7ac9-4a92-bc32-8b6a7eb7879e)]
+[scriptable, uuid(9583b825-46b1-4e8f-bb48-9fed660a95e6)]
 interface mozIDOMApplication  : nsISupports
 {
   readonly attribute jsval manifest;
   readonly attribute DOMString manifestURL;
-  readonly attribute nsIArray receipts; /* an array of strings */
+  readonly attribute jsval receipts; /* an array of strings */
   readonly attribute DOMString origin;
   readonly attribute DOMString installOrigin;
-  readonly attribute unsigned long installTime;
+  readonly attribute unsigned long long installTime;
+
+  /* 
+   * The current progress when downloading an offline cache.
+   */
+  readonly attribute double progress;
+
+  /*
+   * The application status :
+   * "installed"   : The app is in the registry, but we have no offline cache.
+   * "downlading"  : We are downloading the offline cache.
+   * "cached"      : We are done with the offline cache download.
+   * "cache-error" : An error occured while downloading the offline-cache.
+   */
+  readonly attribute DOMString status;
+
+  /*
+   * fires a nsIDOMApplicationEvent when a change in appcache download or status happens
+   */
+  attribute nsIDOMEventListener onprogress;
 
   /* startPoint will be used when several launch_path exists for an app */
   nsIDOMDOMRequest launch([optional] in DOMString startPoint);
   nsIDOMDOMRequest uninstall();
 };
 
 [scriptable, builtinclass, uuid(8f2bfba8-f10e-4f63-a5e0-7a7056e1dbe6)]
 interface nsIDOMMozApplicationEvent : nsIDOMEvent
--- a/dom/interfaces/css/nsIDOMCSSRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSRule.idl
@@ -21,16 +21,17 @@ interface nsIDOMCSSRule : nsISupports
   const unsigned short      STYLE_RULE                     = 1;
   const unsigned short      CHARSET_RULE                   = 2;
   const unsigned short      IMPORT_RULE                    = 3;
   const unsigned short      MEDIA_RULE                     = 4;
   const unsigned short      FONT_FACE_RULE                 = 5;
   const unsigned short      PAGE_RULE                      = 6;
   const unsigned short      MOZ_KEYFRAMES_RULE             = 7;
   const unsigned short      MOZ_KEYFRAME_RULE              = 8;
+  const unsigned short      NAMESPACE_RULE                 = 10;
 
   readonly attribute unsigned short      type;
            attribute DOMString           cssText;
                                         // raises(DOMException) on setting
 
   readonly attribute nsIDOMCSSStyleSheet parentStyleSheet;
   readonly attribute nsIDOMCSSRule       parentRule;
 };
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -377,19 +377,19 @@ ContentChild::RecvPMemoryReportRequestCo
 bool
 ContentChild::DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor)
 {
     delete actor;
     return true;
 }
 
 PBrowserChild*
-ContentChild::AllocPBrowser(const PRUint32& aChromeFlags)
+ContentChild::AllocPBrowser(const PRUint32& aChromeFlags, const bool& aIsBrowserFrame)
 {
-    nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags);
+    nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags, aIsBrowserFrame);
     return NS_SUCCEEDED(iframe->Init()) ? iframe.forget().get() : NULL;
 }
 
 bool
 ContentChild::DeallocPBrowser(PBrowserChild* iframe)
 {
     TabChild* child = static_cast<TabChild*>(iframe);
     NS_RELEASE(child);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -50,17 +50,18 @@ public:
 
     const AppInfo& GetAppInfo() {
         return mAppInfo;
     }
 
     /* if you remove this, please talk to cjones or dougt */
     virtual bool RecvDummy(Shmem& foo) { return true; }
 
-    virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags);
+    virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags,
+                                         const bool& aIsBrowserFrame);
     virtual bool DeallocPBrowser(PBrowserChild*);
 
     virtual PCrashReporterChild*
     AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
                         const PRUint32& processType);
     virtual bool
     DeallocPCrashReporter(PCrashReporterChild*);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -351,19 +351,19 @@ ContentParent::ActorDestroy(ActorDestroy
     // all hell breaks loose.
     //
     // This runnable ensures that a reference to |this| lives on at
     // least until after the current task finishes running.
     NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
 }
 
 TabParent*
-ContentParent::CreateTab(PRUint32 aChromeFlags)
+ContentParent::CreateTab(PRUint32 aChromeFlags, bool aIsBrowserFrame)
 {
-  return static_cast<TabParent*>(SendPBrowserConstructor(aChromeFlags));
+  return static_cast<TabParent*>(SendPBrowserConstructor(aChromeFlags, aIsBrowserFrame));
 }
 
 TestShellParent*
 ContentParent::CreateTestShell()
 {
   return static_cast<TestShellParent*>(SendPTestShellConstructor());
 }
 
@@ -693,17 +693,17 @@ ContentParent::Observe(nsISupports* aSub
         unused << SendActivateA11y();
     }
 #endif
 
     return NS_OK;
 }
 
 PBrowserParent*
-ContentParent::AllocPBrowser(const PRUint32& aChromeFlags)
+ContentParent::AllocPBrowser(const PRUint32& aChromeFlags, const bool& aIsBrowserFrame)
 {
   TabParent* parent = new TabParent();
   if (parent){
     NS_ADDREF(parent);
   }
   return parent;
 }
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -46,17 +46,23 @@ public:
     static ContentParent* GetNewOrUsed();
     static void GetAll(nsTArray<ContentParent*>& aArray);
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSITHREADOBSERVER
     NS_DECL_NSIDOMGEOPOSITIONCALLBACK
 
-    TabParent* CreateTab(PRUint32 aChromeFlags);
+    /**
+     * Create a new tab.
+     *
+     * |aIsBrowserFrame| indicates whether this tab is part of an
+     * <iframe mozbrowser>.
+     */
+    TabParent* CreateTab(PRUint32 aChromeFlags, bool aIsBrowserFrame);
 
     TestShellParent* CreateTestShell();
     bool DestroyTestShell(TestShellParent* aTestShell);
     TestShellParent* GetTestShellSingleton();
 
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
@@ -85,17 +91,17 @@ private:
     using PContentParent::SendPBrowserConstructor;
     using PContentParent::SendPTestShellConstructor;
 
     ContentParent();
     virtual ~ContentParent();
 
     void Init();
 
-    virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags);
+    virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags, const bool& aIsBrowserFrame);
     virtual bool DeallocPBrowser(PBrowserParent* frame);
 
     virtual PCrashReporterParent* AllocPCrashReporter(const NativeThreadId& tid,
                                                       const PRUint32& processType);
     virtual bool DeallocPCrashReporter(PCrashReporterParent* crashreporter);
     virtual bool RecvPCrashReporterConstructor(PCrashReporterParent* actor,
                                                const NativeThreadId& tid,
                                                const PRUint32& processType);
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -79,17 +79,17 @@ rpc protocol PContent
 
 both:
     // Depending on exactly how the new browser is being created, it might be
     // created from either the child or parent process!
     //
     // The child creates the PBrowser as part of
     // TabChild::BrowserFrameProvideWindow, and the parent creates the PBrowser
     // as part of ContentParent::CreateTab.
-    async PBrowser(PRUint32 chromeFlags);
+    async PBrowser(PRUint32 chromeFlags, bool isBrowserFrame);
 
 child:
     PMemoryReportRequest();
 
     PTestShell();
 
     RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources,
                    OverrideMapping[] overrides, nsCString locale);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -82,23 +82,24 @@ ContentListener::HandleEvent(nsIDOMEvent
 class ContentDialogChild : public PContentDialogChild
 {
 public:
   virtual bool Recv__delete__(const InfallibleTArray<int>& aIntParams,
                               const InfallibleTArray<nsString>& aStringParams);
 };
 
 
-TabChild::TabChild(PRUint32 aChromeFlags)
+TabChild::TabChild(PRUint32 aChromeFlags, bool aIsBrowserFrame)
   : mRemoteFrame(nsnull)
   , mTabChildGlobal(nsnull)
   , mChromeFlags(aChromeFlags)
   , mOuterRect(0, 0, 0, 0)
   , mLastBackgroundColor(NS_RGB(255, 255, 255))
   , mDidFakeShow(false)
+  , mIsBrowserFrame(aIsBrowserFrame)
 {
     printf("creating %d!\n", NS_IsMainThread());
 }
 
 nsresult
 TabChild::Init()
 {
   nsCOMPtr<nsIWebBrowser> webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
@@ -372,17 +373,19 @@ TabChild::BrowserFrameProvideWindow(nsID
                                     const nsAString& aName,
                                     const nsACString& aFeatures,
                                     bool* aWindowIsNew,
                                     nsIDOMWindow** aReturn)
 {
   *aReturn = nsnull;
 
   nsRefPtr<TabChild> newChild =
-    static_cast<TabChild*>(Manager()->SendPBrowserConstructor(0));
+    static_cast<TabChild*>(Manager()->SendPBrowserConstructor(
+      /* aChromeFlags = */ 0,
+      /* aIsBrowserFrame = */ true));
 
   nsCAutoString spec;
   aURI->GetSpec(spec);
 
   NS_ConvertUTF8toUTF16 url(spec);
   nsString name(aName);
   NS_ConvertUTF8toUTF16 features(aFeatures);
   newChild->SendBrowserFrameOpenWindow(this, url, name,
@@ -943,16 +946,23 @@ TabChild::InitTabChildGlobal()
   
   NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports), false); 
 
   scope->Init();
 
   nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
   NS_ENSURE_TRUE(root, false);
   root->SetParentTarget(scope);
+
+  // Initialize the child side of the browser element machinery, if appropriate.
+  if (mIsBrowserFrame) {
+    RecvLoadRemoteScript(
+      NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"));
+  }
+
   return true;
 }
 
 bool
 TabChild::InitWidget(const nsIntSize& size)
 {
     NS_ABORT_IF_FALSE(!mWidget && !mRemoteFrame, "CreateWidget twice?");
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -135,17 +135,23 @@ class TabChild : public PBrowserChild,
                  public nsIWindowProvider,
                  public nsSupportsWeakReference,
                  public nsIDialogCreator,
                  public nsITabChild
 {
     typedef mozilla::layout::RenderFrameChild RenderFrameChild;
 
 public:
-    TabChild(PRUint32 aChromeFlags);
+    /**
+     * Create a new TabChild object.
+     *
+     * |aIsBrowserFrame| indicates whether the TabChild is inside an
+     * <iframe mozbrowser>.
+     */
+    TabChild(PRUint32 aChromeFlags, bool aIsBrowserFrame);
     virtual ~TabChild();
     nsresult Init();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIEMBEDDINGSITEWINDOW
     NS_DECL_NSIWEBBROWSERCHROMEFOCUS
@@ -261,16 +267,17 @@ private:
     nsCOMPtr<nsIWebNavigation> mWebNav;
     nsCOMPtr<nsIWidget> mWidget;
     RenderFrameChild* mRemoteFrame;
     nsRefPtr<TabChildGlobal> mTabChildGlobal;
     PRUint32 mChromeFlags;
     nsIntRect mOuterRect;
     nscolor mLastBackgroundColor;
     bool mDidFakeShow;
+    bool mIsBrowserFrame;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 inline TabChild*
 GetTabChildFrom(nsIDocShell* aDocShell)
 {
     nsCOMPtr<nsITabChild> tc = do_GetInterface(aDocShell);
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -173,17 +173,17 @@ PluginModuleParent::TimeoutChanged(const
       unused << static_cast<PluginModuleParent*>(aModule)->SendSetParentHangTimeout(timeoutSecs);
     }
     return 0;
 }
 
 void
 PluginModuleParent::CleanupFromTimeout()
 {
-    if (!mShutdown)
+    if (!mShutdown && OkToCleanup())
         Close();
 }
 
 bool
 PluginModuleParent::ShouldContinueFromReplyTimeout()
 {
 #ifdef MOZ_CRASHREPORTER
     CrashReporterParent* crashReporter = CrashReporter();
--- a/dom/system/OSFileConstants.cpp
+++ b/dom/system/OSFileConstants.cpp
@@ -15,16 +15,24 @@
 
 #if defined(XP_WIN)
 #include <windows.h>
 #endif // defined(XP_WIN)
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "BindingUtils.h"
+
+// Used to provide information on the OS
+
+#include "nsIXULRuntime.h"
+#include "nsXPCOMCIDInternal.h"
+#include "nsServiceManagerUtils.h"
+#include "nsString.h"
+
 #include "OSFileConstants.h"
 
 /**
  * This module defines the basic libc constants (error numbers, open modes,
  * etc.) used by OS.File and possibly other OS-bound JavaScript libraries.
  */
 
 namespace mozilla {
@@ -315,13 +323,35 @@ bool DefineOSFileConstants(JSContext *cx
   JSObject *objWin;
   if (!(objWin = GetOrCreateObjectProperty(cx, objConstants, "Win"))) {
     return false;
   }
   if (!dom::DefineConstants(cx, objWin, gWinProperties)) {
     return false;
   }
 #endif // defined(XP_WIN)
+  JSObject *objSys;
+  if (!(objSys = GetOrCreateObjectProperty(cx, objConstants, "Sys"))) {
+    return false;
+  }
+
+  nsCOMPtr<nsIXULRuntime> runtime = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
+  if (runtime) {
+    nsCAutoString os;
+    nsresult rv = runtime->GetOS(os);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+    JSString* strVersion = JS_NewStringCopyZ(cx, os.get());
+    if (!strVersion) {
+      return false;
+    }
+
+    jsval valVersion = STRING_TO_JSVAL(strVersion);
+    if (!JS_SetProperty(cx, objSys, "Version", &valVersion)) {
+      return false;
+    }
+  }
+
   return true;
 }
 
 } // namespace mozilla
 
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -12,18 +12,16 @@ Cu.import("resource://gre/modules/Servic
 var RIL = {};
 Cu.import("resource://gre/modules/ril_consts.js", RIL);
 
 // set to true in ril_consts.js to see debug messages
 const DEBUG = RIL.DEBUG_RIL;
 
 const RADIOINTERFACELAYER_CID =
   Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
-const DATACALLINFO_CID =
-  Components.ID("{ef474cd9-94f7-4c05-a31b-29b9de8a10d2}");
 
 const nsIAudioManager = Ci.nsIAudioManager;
 const nsIRadioInterfaceLayer = Ci.nsIRadioInterfaceLayer;
 
 const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
 const kSmsReceivedObserverTopic          = "sms-received";
 const kSmsDeliveredObserverTopic         = "sms-delivered";
 const kMozSettingsChangedObserverTopic   = "mozsettings-changed";
@@ -126,30 +124,16 @@ XPCOMUtils.defineLazyGetter(this, "gAudi
   } catch (ex) {
     //TODO on the phone this should not fall back as silently.
     debug("Using fake audio manager.");
     return FakeAudioManager;
   }
 });
 
 
-function DataCallInfo(state, cid, apn) {
-  this.callState = state;
-  this.cid = cid;
-  this.apn = apn;
-}
-DataCallInfo.protoptype = {
-  classID:      DATACALLINFO_CID,
-  classInfo:    XPCOMUtils.generateCI({classID: DATACALLINFO_CID,
-                                       classDescription: "DataCallInfo",
-                                       interfaces: [Ci.nsIDataCallInfo]}),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInfo]),
-};
-
-
 function RadioInterfaceLayer() {
   debug("Starting RIL Worker");
   this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
   this.worker.onerror = this.onerror.bind(this);
   this.worker.onmessage = this.onmessage.bind(this);
 
   this.rilContext = {
     radioState:     RIL.GECKO_RADIOSTATE_UNAVAILABLE,
@@ -480,18 +464,17 @@ RadioInterfaceLayer.prototype = {
     if (!state || regState == RIL.NETWORK_CREG_STATE_UNKNOWN) {
       voiceInfo.connected = false;
       voiceInfo.emergencyCallsOnly = false;
       voiceInfo.roaming = false;
       voiceInfo.network = null;
       voiceInfo.type = null;
       voiceInfo.signalStrength = null;
       voiceInfo.relSignalStrength = null;
-      ppmm.sendAsyncMessage("RIL:VoiceThis.RadioState.VoiceChanged",
-                            voiceInfo);
+      ppmm.sendAsyncMessage("RIL:VoiceInfoChanged", voiceInfo);
       return;
     }
 
     let isRoaming = regState == RIL.NETWORK_CREG_STATE_REGISTERED_ROAMING;
     let isHome = regState == RIL.NETWORK_CREG_STATE_REGISTERED_HOME;
     let isConnected = isRoaming || isHome;
     let radioTech = RIL.GECKO_RADIO_TECH[state.radioTech] || null;
 
@@ -527,35 +510,49 @@ RadioInterfaceLayer.prototype = {
     try {
       return Services.prefs.getBoolPref("ril.data.roaming.enabled");
     } catch(ex) {
       return false;
     }
   },
 
   updateDataConnection: function updateDataConnection(state) {
+    let data = this.rilContext.data;
+    if (!state || state.regState == RIL.NETWORK_CREG_STATE_UNKNOWN) {
+      data.connected = false;
+      data.emergencyCallsOnly = false;
+      data.roaming = false;
+      data.network = null;
+      data.type = null;
+      data.signalStrength = null;
+      data.relSignalStrength = null;
+      ppmm.sendAsyncMessage("RIL:DataInfoChanged", data);
+      return;
+    }
+    data.roaming =
+      (state.regState == RIL.NETWORK_CREG_STATE_REGISTERED_ROAMING);
+    data.type = RIL.GECKO_RADIO_TECH[state.radioTech] || null;
+    ppmm.sendAsyncMessage("RIL:DataInfoChanged", data);
+
     if (!this._isDataEnabled()) {
       return false;
     }
 
     let isRegistered =
       state.regState == RIL.NETWORK_CREG_STATE_REGISTERED_HOME ||
         (this._isDataRoamingEnabled() &&
          state.regState == RIL.NETWORK_CREG_STATE_REGISTERED_ROAMING);
     let haveDataConnection =
       state.radioTech != RIL.NETWORK_CREG_TECH_UNKNOWN;
 
     if (isRegistered && haveDataConnection) {
       debug("Radio is ready for data connection.");
       // RILNetworkInterface will ignore this if it's already connected.
       RILNetworkInterface.connect();
     }
-    //TODO need to keep track of some of the state information, and then
-    // notify the content when state changes (connected, technology
-    // changes, etc.). This should be done in RILNetworkInterface.
     return false;
   },
 
   handleSignalStrengthChange: function handleSignalStrengthChange(message) {
     // TODO CDMA, EVDO, LTE, etc. (see bug 726098)
     this.rilContext.voice.signalStrength = message.gsmDBM;
     this.rilContext.voice.relSignalStrength = message.gsmRelative;
     ppmm.sendAsyncMessage("RIL:VoiceInfoChanged", this.rilContext.voice);
@@ -871,32 +868,33 @@ RadioInterfaceLayer.prototype = {
 
     gSmsRequestManager.notifySmsSendFailed(options.requestId, error);
   },
 
   /**
    * Handle data call state changes.
    */
   handleDataCallState: function handleDataCallState(datacall) {
+    let data = this.rilContext.data;
+
+    if (datacall.ifname) {
+      data.connected = (datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED);
+      ppmm.sendAsyncMessage("RIL:DataInfoChanged", data);    
+    }
+
     this._deliverDataCallCallback("dataCallStateChanged",
-                                  [datacall.cid, datacall.ifname, datacall.state]);
+                                  [datacall]);
   },
 
   /**
    * Handle data call list.
    */
   handleDataCallList: function handleDataCallList(message) {
-    let datacalls = [];
-    for each (let datacall in message.datacalls) {
-      datacalls.push(new DataCallInfo(datacall.state,
-                                      datacall.cid,
-                                      datacall.apn));
-    }
     this._deliverDataCallCallback("receiveDataCallList",
-                                  [datacalls, datacalls.length]);
+                                  [message.datacalls, message.datacalls.length]);
   },
 
   /**
    * Handle setting changes.
    */
   handleMozSettingsChanged: function handleMozSettingsChanged(setting) {
     switch (setting.key) {
       case "ril.radio.disabled":
@@ -1690,39 +1688,39 @@ let RILNetworkInterface = {
   type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
 
   name: null,
 
   dhcp: false,
 
   // nsIRILDataCallback
 
-  dataCallStateChanged: function dataCallStateChanged(cid, interfaceName, callState) {
-    debug("Data call ID: " + cid + ", interface name: " + interfaceName);
+  dataCallStateChanged: function dataCallStateChanged(datacall) {
+    debug("Data call ID: " + datacall.cid + ", interface name: " + datacall.ifname);
     if (this.connecting &&
-        (callState == RIL.GECKO_NETWORK_STATE_CONNECTING ||
-         callState == RIL.GECKO_NETWORK_STATE_CONNECTED)) {
+        (datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTING ||
+         datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED)) {
       this.connecting = false;
-      this.cid = cid;
-      this.name = interfaceName;
+      this.cid = datacall.cid;
+      this.name = datacall.ifname;
       if (!this.registeredAsNetworkInterface) {
         let networkManager = Cc["@mozilla.org/network/manager;1"]
                                .getService(Ci.nsINetworkManager);
         networkManager.registerNetworkInterface(this);
         this.registeredAsNetworkInterface = true;
       }
     }
-    if (this.cid != cid) {
+    if (this.cid != datacall.cid) {
       return;
     }
-    if (this.state == callState) {
+    if (this.state == datacall.state) {
       return;
     }
 
-    this.state = callState;
+    this.state = datacall.state;
     Services.obs.notifyObservers(this,
                                  kNetworkInterfaceStateChangedTopic,
                                  null);
   },
 
   receiveDataCallList: function receiveDataCallList(dataCalls, length) {
   },
 
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -57,40 +57,35 @@ interface nsIRILTelephonyCallback : nsIS
    *        Call identifier assigned by the RIL. -1 if no connection
    * @param error
    *        Error from RIL.
    */
   void notifyError(in long callIndex,
                    in AString error);
 };
 
-[scriptable, uuid(66a55943-e63b-4731-aece-9c04bfc14019)]
+[scriptable, uuid(8a711703-1ee5-4675-9d9a-0b188e944cfe)]
 interface nsIRILDataCallInfo : nsISupports
 {
-  readonly attribute unsigned long callState;
+  readonly attribute unsigned long state;
   readonly attribute AString cid;
   readonly attribute AString apn;
+  readonly attribute AString ifname;
 };
 
-[scriptable, uuid(cea91bcb-3cfb-42bb-8638-dae89e8870fc)]
+[scriptable, uuid(5bcac053-c245-46f0-bb45-d0039bfb89f5)]
 interface nsIRILDataCallback : nsISupports
 {
   /**
    * Notified when a data call changes state.
    *
-   * @param cid
-   *        The CID of the data call.
-   * @param interfaceName
-   *        Name of the associated network interface.
-   * @param dataState
-   *        One of the nsIRadioInterfaceLayer::DATACALL_STATE_* values.
+   * @param dataCall
+   *        A nsIRILDataCallInfo object.
    */
-  void dataCallStateChanged(in AString cid,
-                            in AString interfaceName,
-                            in unsigned short callState);
+  void dataCallStateChanged(in nsIRILDataCallInfo dataCall);
 
   /**
    * Called when nsIRadioInterfaceLayer is asked to enumerate the current
    * data call state.
    *
    * @param datacalls
    *        Array of nsIRILDataCallInfo objects.
    * @param length
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -684,16 +684,22 @@ let RIL = {
     let ril_impl = libcutils.property_get("gsm.version.ril-impl");
     if (DEBUG) debug("Detected RIL implementation " + ril_impl);
     switch (ril_impl) {
       case "Samsung RIL(IPC) v2.0":
         // The Samsung Galaxy S2 I-9100 radio sends an extra Uint32 in the
         // call state.
         let model_id = libcutils.property_get("ril.model_id");
         if (DEBUG) debug("Detected RIL model " + model_id);
+        if (!model_id) {
+          // On some RIL models, the RIL has to be "warmed up" for us to read this property.
+          // It apparently isn't warmed up yet, going to try again later.
+          if (DEBUG) debug("Could not detect correct model_id. Going to try later.");
+          return;
+        }
         if (model_id == "I9100") {
           if (DEBUG) {
             debug("Detected I9100, enabling " +
                   "RILQUIRKS_CALLSTATE_EXTRA_UINT32, " +
                   "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP, " +
                   "RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL.");
           }
           RILQUIRKS_CALLSTATE_EXTRA_UINT32 = true;
@@ -1519,18 +1525,32 @@ let RIL = {
   /**
    * Hang up the phone.
    *
    * @param callIndex
    *        Call index (1-based) as reported by REQUEST_GET_CURRENT_CALLS.
    */
   hangUp: function hangUp(options) {
     let call = this.currentCalls[options.callIndex];
-    if (call && call.state != CALL_STATE_HOLDING) {
-      Buf.simpleRequest(REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND);
+    if (!call) {
+      return;
+    }
+
+    switch (call.state) {
+      case CALL_STATE_ACTIVE:
+      case CALL_STATE_DIALING:
+      case CALL_STATE_ALERTING:
+        Buf.newParcel(REQUEST_HANGUP);
+        Buf.writeUint32(1);
+        Buf.writeUint32(options.callIndex);
+        Buf.sendParcel();
+        break;
+      case CALL_STATE_HOLDING:
+        Buf.simpleRequest(REQUEST_HANGUP_WAITING_OR_BACKGROUND);
+        break;
     }
   },
 
   /**
    * Mute or unmute the radio.
    *
    * @param mute
    *        Boolean to indicate whether to mute or unmute the radio.
@@ -2181,16 +2201,58 @@ let RIL = {
     }
 
     if (stateChanged) {
       rs.type = "dataregistrationstatechange";
       this._sendNetworkInfoMessage(NETWORK_INFO_DATA_REGISTRATION_STATE, rs);
     }
   },
 
+  _processOperator: function _processOperator(operatorData) {
+    if (operatorData.length < 3) {
+      if (DEBUG) {
+        debug("Expected at least 3 strings for operator.");
+      }
+    }
+
+    if (!this.operator) {
+      this.operator = {type: "operatorchange"};
+    }
+
+    let [longName, shortName, networkTuple] = operatorData;
+    let thisTuple = String(this.operator.mcc) + this.operator.mnc;
+
+    if (this.operator.longName !== longName ||
+        this.operator.shortName !== shortName ||
+        thisTuple !== networkTuple) {
+
+      this.operator.longName = longName;
+      this.operator.shortName = shortName;
+      this.operator.mcc = 0;
+      this.operator.mnc = 0;
+
+      // According to ril.h, the operator fields will be NULL when the operator
+      // is not currently registered. We can avoid trying to parse the numeric
+      // tuple in that case.
+      if (DEBUG && !longName) {
+        debug("Operator is currently unregistered");
+      }
+
+      if (longName && shortName && networkTuple) {
+        try {
+          this._processNetworkTuple(networkTuple, this.operator);
+        } catch (e) {
+          debug("Error processing operator tuple: " + e);
+        }
+      }
+
+      this._sendNetworkInfoMessage(NETWORK_INFO_OPERATOR, this.operator);
+    }
+  },
+
   /**
    * Helpers for processing call state and handle the active call.
    */
   _processCalls: function _processCalls(newCalls) {
     // Go through the calls we currently have on file and see if any of them
     // changed state. Remove them from the newCalls map as we deal with them
     // so that only new calls remain in the map after we're done.
     let lastCallsLength = this.currentCallsLength;
@@ -2977,46 +3039,22 @@ RIL[REQUEST_DATA_REGISTRATION_STATE] = f
 };
 RIL[REQUEST_OPERATOR] = function REQUEST_OPERATOR(length, options) {
   this._receivedNetworkInfo(NETWORK_INFO_OPERATOR);
 
   if (options.rilRequestError) {
     return;
   }
 
-  let operator = Buf.readStringList();
-
-  if (DEBUG) debug("Operator data: " + operator);
-  if (operator.length < 3) {
-    if (DEBUG) debug("Expected at least 3 strings for operator.");
-  }
-
-  if (!this.operator) {
-    this.operator = {type: "operatorchange"};
-  }
-
-  let numeric = String(this.operator.mcc) + this.operator.mnc;
-  if (this.operator.longName != operator[0] ||
-      this.operator.shortName != operator[1] ||
-      numeric != operator[2]) {
-
-    this.operator.longName = operator[0];
-    this.operator.shortName = operator[1];
-    this.operator.mcc = 0;
-    this.operator.mnc = 0;
-
-    let networkTuple = operator[2];
-    try {
-      this._processNetworkTuple(networkTuple, this.operator);
-    } catch (e) {
-      debug("Error processing operator tuple: " + e);
-    }
-
-    this._sendNetworkInfoMessage(NETWORK_INFO_OPERATOR, this.operator);
-  }
+  let operatorData = Buf.readStringList();
+  if (DEBUG) debug("operator: " + operatorData);
+
+  this._processOperator(operatorData);
+
+
 };
 RIL[REQUEST_RADIO_POWER] = null;
 RIL[REQUEST_DTMF] = null;
 RIL[REQUEST_SEND_SMS] = function REQUEST_SEND_SMS(length, options) {
   if (options.rilRequestError) {
     switch (options.rilRequestError) {
       case ERROR_SMS_SEND_FAIL_RETRY:
         if (options.retryCount < SMS_RETRY_MAX) {
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -473,36 +473,43 @@ Telephony::EnumerateCallState(PRUint32 a
   }
 
   *aContinue = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::NotifyError(PRInt32 aCallIndex,
-                        const nsAString& aError)
+                       const nsAString& aError)
 {
-  PRInt32 index = -1;
-  PRInt32 length = mCalls.Length();
-
-  // The connection is not established yet, remove the latest call object
-  if (aCallIndex == -1) {
-    if (length > 0) {
-      index = length - 1;
+  nsRefPtr<TelephonyCall> callToNotify;
+  if (!mCalls.IsEmpty()) {
+    // The connection is not established yet. Get the latest call object.
+    if (aCallIndex == -1) {
+      callToNotify = mCalls[mCalls.Length() - 1];
+    } else {
+      // The connection has been established. Get the failed call.
+      for (PRUint32 index = 0; index < mCalls.Length(); index++) {
+        nsRefPtr<TelephonyCall>& call = mCalls[index];
+        if (call->CallIndex() == aCallIndex) {
+          callToNotify = call;
+          break;
+        }
+      }
     }
-  } else {
-    if (aCallIndex < 0 || aCallIndex >= length) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    index = aCallIndex;
   }
-  if (index != -1) {
-    mCalls[index]->NotifyError(aError);
+
+  if (!callToNotify) {
+    NS_ERROR("Don't call me with a bad call index!");
+    return NS_ERROR_UNEXPECTED;
   }
 
+  // Set the call state to 'disconnected' and remove it from the calls list.
+  callToNotify->NotifyError(aError);
+
   return NS_OK;
 }
 
 nsresult
 NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony)
 {
   NS_ASSERTION(aWindow, "Null pointer!");
 
--- a/dom/tests/mochitest/general/test_offsets.js
+++ b/dom/tests/mochitest/general/test_offsets.js
@@ -66,19 +66,18 @@ function testElement(element)
     var top = element.firstChild.getBoundingClientRect().top;
     var bottom = element.lastChild.getBoundingClientRect().bottom;
     var contentsHeight = bottom - top;
     scrollHeight = contentsHeight + paddingTop + paddingBottom;
     clientWidth = paddingLeft + width + paddingRight - scrollbarWidth;
     clientHeight = paddingTop + height + paddingBottom - scrollbarHeight;
   }
   else {
-    // XXXndeakin note that Mozilla adds borders here, although the spec does not
-    scrollWidth = paddingLeft + width + paddingRight + borderLeft + borderRight;
-    scrollHeight = paddingTop + height + paddingBottom + borderTop + borderBottom;
+    scrollWidth = paddingLeft + width + paddingRight;
+    scrollHeight = paddingTop + height + paddingBottom;
     clientWidth = paddingLeft + width + paddingRight;
     clientHeight = paddingTop + height + paddingBottom;
   }
 
   if (element instanceof SVGElement)
     checkScrollState(element, 0, 0, 0, 0, element.id);
   else
     checkScrollState(element, 0, 0, scrollWidth, scrollHeight, element.id);
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -769,17 +769,16 @@ DrawTargetCG::CopySurface(SourceSurface 
 }
 
 void
 DrawTargetCG::DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, const Point &aOffset, Float aSigma, CompositionOp aOperator)
 {
   MarkChanged();
 
   CGImageRef image;
-  CGImageRef subimage = NULL;
   image = GetImageFromSourceSurface(aSurface);
 
   IntSize size = aSurface->GetSize();
   CGContextSaveGState(mCg);
   //XXX do we need to do the fixup here?
   CGContextSetBlendMode(mCg, ToBlendMode(aOperator));
 
   CGContextScaleCTM(mCg, 1, -1);
@@ -792,17 +791,16 @@ DrawTargetCG::DrawSurfaceWithShadow(Sour
   // CoreGraphics needs twice sigma as it's amount of blur
   CGContextSetShadowWithColor(mCg, offset, 2*aSigma, color);
   CGColorRelease(color);
 
   CGContextDrawImage(mCg, flippedRect, image);
 
   CGContextRestoreGState(mCg);
 
-  CGImageRelease(subimage);
 }
 
 bool
 DrawTargetCG::Init(CGContextRef cgContext, const IntSize &aSize)
 {
   // XXX: we should come up with some consistent semantics for dealing
   // with zero area drawtargets
   if (aSize.width == 0 || aSize.height == 0) {
--- a/ipc/glue/MessagePump.cpp
+++ b/ipc/glue/MessagePump.cpp
@@ -104,16 +104,19 @@ MessagePump::Run(MessagePump::Delegate* 
 
     if (did_work)
       continue;
 
     did_work = aDelegate->DoIdleWork();
     if (!keep_running_)
       break;
 
+    if (did_work)
+      continue;
+
     // This will either sleep or process an event.
     NS_ProcessNextEvent(mThread, true);
   }
 
   mDelayedWorkTimer->Cancel();
 
   keep_running_ = true;
 }
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -150,18 +150,18 @@ JSFunctionSpec MapObject::methods[] = {
     JS_FN("set", set, 2, 0),
     JS_FN("delete", delete_, 1, 0),
     JS_FS_END
 };
 
 JSObject *
 MapObject::initClass(JSContext *cx, JSObject *obj)
 {
-    return InitClass(cx, Rooted<GlobalObject*>(cx, &obj->asGlobal()),
-                     &class_, JSProto_Map, construct, methods);
+    Rooted<GlobalObject*> global(cx, &obj->asGlobal());
+    return InitClass(cx, global, &class_, JSProto_Map, construct, methods);
 }
 
 void
 MapObject::mark(JSTracer *trc, JSObject *obj)
 {
     MapObject *mapobj = static_cast<MapObject *>(obj);
     if (ValueMap *map = mapobj->getData()) {
         for (ValueMap::Enum iter(*map); !iter.empty(); iter.popFront()) {
@@ -343,18 +343,18 @@ JSFunctionSpec SetObject::methods[] = {
     JS_FN("add", add, 1, 0),
     JS_FN("delete", delete_, 1, 0),
     JS_FS_END
 };
 
 JSObject *
 SetObject::initClass(JSContext *cx, JSObject *obj)
 {
-    return InitClass(cx, Rooted<GlobalObject*>(cx, &obj->asGlobal()),
-                     &class_, JSProto_Set, construct, methods);
+    Rooted<GlobalObject*> global(cx, &obj->asGlobal());
+    return InitClass(cx, global, &class_, JSProto_Set, construct, methods);
 }
 
 void
 SetObject::mark(JSTracer *trc, JSObject *obj)
 {
     SetObject *setobj = static_cast<SetObject *>(obj);
     if (ValueSet *set = setobj->getData()) {
         for (ValueSet::Enum iter(*set); !iter.empty(); iter.popFront())
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -18,37 +18,39 @@
 using namespace js;
 using namespace js::types;
 
 class RegExpMatchBuilder
 {
     JSContext   * const cx;
     RootedObject array;
 
-    bool setProperty(JSAtom *name, Value v) {
-        return !!baseops::DefineProperty(cx, array, RootedId(cx, AtomToId(name)), &v,
+    bool setProperty(Handle<PropertyName*> name, Value v) {
+        return !!baseops::DefineProperty(cx, array, name, &v,
                                          JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE);
     }
 
   public:
     RegExpMatchBuilder(JSContext *cx, JSObject *array) : cx(cx), array(cx, array) {}
 
     bool append(uint32_t index, Value v) {
         JS_ASSERT(!array->getOps()->getElement);
         return !!baseops::DefineElement(cx, array, index, &v, JS_PropertyStub, JS_StrictPropertyStub,
                                         JSPROP_ENUMERATE);
     }
 
     bool setIndex(int index) {
-        return setProperty(cx->runtime->atomState.indexAtom, Int32Value(index));
+        Rooted<PropertyName*> name(cx, cx->runtime->atomState.indexAtom);
+        return setProperty(name, Int32Value(index));
     }
 
     bool setInput(JSString *str) {
         JS_ASSERT(str);
-        return setProperty(cx->runtime->atomState.inputAtom, StringValue(str));
+        Rooted<PropertyName*> name(cx, cx->runtime->atomState.inputAtom);
+        return setProperty(name, StringValue(str));
     }
 };
 
 static bool
 CreateRegExpMatchResult(JSContext *cx, JSString *input_, const jschar *chars, size_t length,
                         MatchPairs *matchPairs, Value *rval)
 {
     RootedString input(cx, input_);
@@ -189,18 +191,18 @@ EscapeNakedForwardSlashes(JSContext *cx,
  *  _ => pattern := ToString(pattern) if defined(pattern) else ''
  *       flags := ToString(flags) if defined(flags) else ''
  */
 static bool
 CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
 {
     if (args.length() == 0) {
         RegExpStatics *res = cx->regExpStatics();
-        RegExpObject *reobj = builder.build(RootedAtom(cx, cx->runtime->emptyString),
-                                            res->getFlags());
+        Rooted<JSAtom*> empty(cx, cx->runtime->emptyString);
+        RegExpObject *reobj = builder.build(empty, res->getFlags());
         if (!reobj)
             return false;
         args.rval() = ObjectValue(*reobj);
         return true;
     }
 
     Value sourceValue = args[0];
 
@@ -237,17 +239,18 @@ CompileRegExpObject(JSContext *cx, RegEx
         /*
          * 'toSource' is a permanent read-only property, so this is equivalent
          * to executing RegExpObject::getSource on the unwrapped object.
          */
         Value v;
         if (!sourceObj.getProperty(cx, cx->runtime->atomState.sourceAtom, &v))
             return false;
 
-        RegExpObject *reobj = builder.build(RootedAtom(cx, &v.toString()->asAtom()), flags);
+        Rooted<JSAtom*> sourceAtom(cx, &v.toString()->asAtom());
+        RegExpObject *reobj = builder.build(sourceAtom, flags);
         if (!reobj)
             return false;
 
         args.rval() = ObjectValue(*reobj);
         return true;
     }
 
     JSAtom *source;
@@ -457,17 +460,18 @@ js_InitRegExpClass(JSContext *cx, JSObje
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
 
     RootedObject proto(cx, global->createBlankPrototype(cx, &RegExpClass));
     if (!proto)
         return NULL;
     proto->setPrivate(NULL);
 
     RegExpObjectBuilder builder(cx, &proto->asRegExp());
-    if (!builder.build(RootedAtom(cx, cx->runtime->emptyString), RegExpFlag(0)))
+    Rooted<JSAtom*> empty(cx, cx->runtime->emptyString);
+    if (!builder.build(empty, RegExpFlag(0)))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, proto, NULL, regexp_methods))
         return NULL;
 
     RootedFunction ctor(cx);
     ctor = global->createConstructor(cx, regexp_construct, CLASS_NAME(cx, RegExp), 2);
     if (!ctor)
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -51,16 +51,18 @@ check-variable = $(if $(filter-out 0 1,$
 core_abspath = $(if $(findstring :,$(1)),$(1),$(if $(filter /%,$(1)),$(1),$(CURDIR)/$(1)))
 core_realpath = $(if $(realpath $(1)),$(realpath $(1)),$(call core_abspath,$(1)))
 
 nullstr :=
 space :=$(nullstr) # EOL
 
 core_winabspath = $(firstword $(subst /, ,$(call core_abspath,$(1)))):$(subst $(space),,$(patsubst %,\\%,$(wordlist 2,$(words $(subst /, ,$(call core_abspath,$(1)))), $(strip $(subst /, ,$(call core_abspath,$(1)))))))
 
+RM = rm -f
+
 # LIBXUL_DIST is not defined under js/src, thus we make it mean DIST there.
 LIBXUL_DIST ?= $(DIST)
 
 # FINAL_TARGET specifies the location into which we copy end-user-shipped
 # build products (typelibs, components, chrome).
 #
 # If XPI_NAME is set, the files will be shipped to $(DIST)/xpi-stage/$(XPI_NAME)
 # If DIST_SUBDIR is set, the files will be shipped to $(DIST)/$(DIST_SUBDIR)
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -628,17 +628,20 @@ include $(topsrcdir)/config/makefiles/ta
 
 ifneq (,$(filter-out %.$(LIB_SUFFIX),$(SHARED_LIBRARY_LIBS)))
 $(error SHARED_LIBRARY_LIBS must contain .$(LIB_SUFFIX) files only)
 endif
 
 HOST_LIBS_DEPS = $(filter %.$(LIB_SUFFIX),$(HOST_LIBS))
 
 # Dependencies which, if modified, should cause everything to rebuild
-GLOBAL_DEPS += Makefile Makefile.in $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk
+GLOBAL_DEPS += Makefile $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk
+ifndef NO_MAKEFILE_RULE
+GLOBAL_DEPS += Makefile.in
+endif
 
 ##############################################
 include $(topsrcdir)/config/makefiles/target_libs.mk
 
 ##############################################
 ifndef NO_PROFILE_GUIDED_OPTIMIZE
 ifdef MOZ_PROFILE_USE
 ifeq ($(OS_ARCH)_$(GNU_CC), WINNT_)
@@ -1142,26 +1145,30 @@ endif
 	$(JAR) cf $@ -C $(_JAVA_DIR) .
 
 GARBAGE_DIRS += $(_JAVA_DIR)
 
 ###############################################################################
 # Update Makefiles
 ###############################################################################
 
+ifndef NO_MAKEFILE_RULE
 # Note: Passing depth to make-makefile is optional.
 #       It saves the script some work, though.
 Makefile: Makefile.in
 	@$(PERL) $(AUTOCONF_TOOLS)/make-makefile -t $(topsrcdir) -d $(DEPTH)
+endif
 
+ifndef NO_SUBMAKEFILES_RULE
 ifdef SUBMAKEFILES
 # VPATH does not work on some machines in this case, so add $(srcdir)
 $(SUBMAKEFILES): % : $(srcdir)/%.in
 	$(PERL) $(AUTOCONF_TOOLS)/make-makefile -t $(topsrcdir) -d $(DEPTH) $@
 endif
+endif
 
 ifdef AUTOUPDATE_CONFIGURE
 $(topsrcdir)/configure: $(topsrcdir)/configure.in
 	(cd $(topsrcdir) && $(AUTOCONF)) && (cd $(DEPTH) && ./config.status --recheck)
 endif
 
 $(DEPTH)/config/autoconf.mk: $(topsrcdir)/config/autoconf.mk.in
 	cd $(DEPTH) && CONFIG_HEADERS= CONFIG_FILES=config/autoconf.mk ./config.status
--- a/js/src/config/system-headers
+++ b/js/src/config/system-headers
@@ -1054,8 +1054,10 @@ ogg/ogg.h
 ogg/os_types.h
 nestegg/nestegg.h
 cubeb/cubeb.h
 #endif
 gst/gst.h
 gst/app/gstappsink.h
 gst/app/gstappsrc.h
 gst/video/video.h
+sys/msg.h
+sys/ipc.h
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -463,17 +463,17 @@ case "$target" in
 
         AC_LANG_CPLUSPLUS
         AC_TRY_COMPILE([#include <new.h>],
             [ unsigned *test = new unsigned(42); ],,
             AC_MSG_ERROR([\$(CXX) test failed.  You must have MS VC++ in your path to build.]) )
         AC_LANG_RESTORE
 
         changequote(,)
-        _MSVC_VER_FILTER='s|.* ([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?).*|\1|p'
+        _MSVC_VER_FILTER='s|.*[^!-~]([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?).*|\1|p'
         changequote([,])
 
         # Determine compiler version
         CC_VERSION=`"${CC}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"`
         _CC_MAJOR_VERSION=`echo ${CC_VERSION} | $AWK -F\. '{ print $1 }'`
         _CC_MINOR_VERSION=`echo ${CC_VERSION} | $AWK -F\. '{ print $2 }'`
         _CC_RELEASE=`echo ${CC_VERSION} | $AWK -F\. '{ print $3 }'`
         _CC_BUILD=`echo ${CC_VERSION} | $AWK -F\. '{ print $4 }'`
@@ -516,17 +516,17 @@ case "$target" in
         dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool',
         dnl not something else like "magnetic tape manipulation utility".
         MSMT_TOOL=`mt 2>&1|grep 'Microsoft (R) Manifest Tool'`
         if test -z "$MSMT_TOOL"; then
           AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.])
         fi
 
         changequote(,)
-        _MSMT_VER_FILTER='s|.* \([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p'
+        _MSMT_VER_FILTER='s|.*[^!-~]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p'
         changequote([,])
         MSMANIFEST_TOOL_VERSION=`echo ${MSMT_TOOL}|sed -ne "$_MSMT_VER_FILTER"`
         if test -z "$MSMANIFEST_TOOL_VERSION"; then
           AC_MSG_WARN([Unknown version of the Microsoft (R) Manifest Tool.])
         fi
 
         MSMANIFEST_TOOL=1
         unset MSMT_TOOL
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -90,17 +90,17 @@ frontend::CompileScript(JSContext *cx, J
     /*
      * The scripted callerFrame can only be given for compile-and-go scripts
      * and non-zero static level requires callerFrame.
      */
     JS_ASSERT_IF(callerFrame, compileAndGo);
     JS_ASSERT_IF(staticLevel != 0, callerFrame);
 
     Parser parser(cx, principals, originPrincipals, chars, length, filename, lineno, version,
-                  callerFrame, /* foldConstants = */ true, compileAndGo);
+                  /* foldConstants = */ true, compileAndGo);
     if (!parser.init())
         return NULL;
 
     SharedContext sc(cx, scopeChain, /* fun = */ NULL, /* funbox = */ NULL);
 
     TreeContext tc(&parser, &sc, staticLevel);
     if (!tc.init())
         return NULL;
@@ -108,31 +108,26 @@ frontend::CompileScript(JSContext *cx, J
     bool savedCallerFun = compileAndGo && callerFrame && callerFrame->isFunctionFrame();
     GlobalObject *globalObject = needScriptGlobal ? GetCurrentGlobal(cx) : NULL;
     Rooted<JSScript*> script(cx);
     script = JSScript::Create(cx, savedCallerFun, principals, originPrincipals, compileAndGo,
                               noScriptRval, globalObject, version, staticLevel);
     if (!script)
         return NULL;
 
-    BytecodeEmitter bce(&parser, &sc, script, lineno);
+    // We can specialize a bit for the given scope chain if that scope chain is the global object.
+    JSObject *globalScope = scopeChain && scopeChain == &scopeChain->global() ? scopeChain : NULL;
+    JS_ASSERT_IF(globalScope, globalScope->isNative());
+    JS_ASSERT_IF(globalScope, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalScope->getClass()));
+
+    BytecodeEmitter bce(/* parent = */ NULL, &parser, &sc, script, callerFrame, !!globalScope,
+                        lineno);
     if (!bce.init())
         return NULL;
 
-    // We can specialize a bit for the given scope chain if that scope chain is the global object.
-    JSObject *globalObj = scopeChain && scopeChain == &scopeChain->global()
-                          ? &scopeChain->global()
-                          : NULL;
-
-    JS_ASSERT_IF(globalObj, globalObj->isNative());
-    JS_ASSERT_IF(globalObj, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalObj->getClass()));
-
-    GlobalScope globalScope(cx, globalObj);
-    bce.globalScope = &globalScope;
-
     /* If this is a direct call to eval, inherit the caller's strictness.  */
     if (callerFrame && callerFrame->isScriptFrame() && callerFrame->script()->strictModeCode)
         sc.setInStrictMode();
 
     if (compileAndGo) {
         if (source) {
             /*
              * Save eval program source in script->atoms[0] for the
@@ -187,48 +182,58 @@ frontend::CompileScript(JSContext *cx, J
 
         pn = parser.statement();
         if (!pn)
             return NULL;
 
         if (inDirectivePrologue && !parser.recognizeDirectivePrologue(pn, &inDirectivePrologue))
             return NULL;
 
-        if (!FoldConstants(cx, pn, bce.parser))
+        if (!FoldConstants(cx, pn, &parser))
             return NULL;
 
-        if (!AnalyzeFunctions(bce.parser))
+        if (!AnalyzeFunctions(&parser, callerFrame))
             return NULL;
         tc.functionList = NULL;
 
         if (!EmitTree(cx, &bce, pn))
             return NULL;
 
 #if JS_HAS_XML_SUPPORT
         if (!pn->isKind(PNK_SEMI) || !pn->pn_kid || !pn->pn_kid->isXMLItem())
             onlyXML = false;
 #endif
-        bce.parser->freeTree(pn);
+        parser.freeTree(pn);
     }
 
 #if JS_HAS_XML_SUPPORT
     /*
      * Prevent XML data theft via <script src="http://victim.com/foo.xml">.
      * For background, see:
      *
      * https://bugzilla.mozilla.org/show_bug.cgi?id=336551
      */
     if (pn && onlyXML && !callerFrame) {
         parser.reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_XML_WHOLE_PROGRAM);
         return NULL;
     }
 #endif
 
-    if (!parser.checkForArgumentsAndRest())
-        return NULL;
+    // It's an error to use |arguments| in a function that has a rest parameter.
+    if (callerFrame && callerFrame->isFunctionFrame() && callerFrame->fun()->hasRest()) {
+        PropertyName *arguments = cx->runtime->atomState.argumentsAtom;
+        for (AtomDefnRange r = tc.lexdeps->all(); !r.empty(); r.popFront()) {
+            if (r.front().key() == arguments) {
+                parser.reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ARGUMENTS_AND_REST);
+                return NULL;
+            }
+        }
+        // We're not in a function context, so we don't expect any bindings.
+        JS_ASSERT(sc.bindings.lookup(cx, arguments, NULL) == NONE);
+    }
 
     /*
      * Nowadays the threaded interpreter needs a stop instruction, so we
      * do have to emit that here.
      */
     if (Emit1(cx, &bce, JSOP_STOP) < 0)
         return NULL;
 
@@ -245,18 +250,17 @@ frontend::CompileScript(JSContext *cx, J
 // handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
 bool
 frontend::CompileFunctionBody(JSContext *cx, JSFunction *fun,
                               JSPrincipals *principals, JSPrincipals *originPrincipals,
                               Bindings *bindings, const jschar *chars, size_t length,
                               const char *filename, unsigned lineno, JSVersion version)
 {
     Parser parser(cx, principals, originPrincipals, chars, length, filename, lineno, version,
-                  /* callerFrame = */ NULL, /* foldConstants = */ true,
-                  /* compileAndGo = */ false);
+                  /* foldConstants = */ true, /* compileAndGo = */ false);
     if (!parser.init())
         return false;
 
     JS_ASSERT(fun);
     SharedContext funsc(cx, /* scopeChain = */ NULL, fun, /* funbox = */ NULL);
 
     unsigned staticLevel = 0;
     TreeContext funtc(&parser, &funsc, staticLevel);
@@ -266,21 +270,23 @@ frontend::CompileFunctionBody(JSContext 
     GlobalObject *globalObject = fun->getParent() ? &fun->getParent()->global() : NULL;
     Rooted<JSScript*> script(cx);
     script = JSScript::Create(cx, /* savedCallerFun = */ false, principals, originPrincipals,
                               /* compileAndGo = */ false, /* noScriptRval = */ false,
                               globalObject, version, staticLevel);
     if (!script)
         return false;
 
-    BytecodeEmitter funbce(&parser, &funsc, script, lineno);
+    StackFrame *nullCallerFrame = NULL;
+    BytecodeEmitter funbce(/* parent = */ NULL, &parser, &funsc, script, nullCallerFrame,
+                           /* hasGlobalScope = */ false, lineno);
     if (!funbce.init())
         return false;
 
-    funsc.bindings.transfer(cx, bindings);
+    funsc.bindings.transfer(bindings);
     fun->setArgCount(funsc.bindings.numArgs());
     if (!GenerateBlockId(&funsc, funsc.bodyid))
         return false;
 
     /* FIXME: make Function format the source for a function definition. */
     ParseNode *fn = FunctionNode::create(PNK_NAME, &parser);
     if (!fn)
         return false;
@@ -323,17 +329,17 @@ frontend::CompileFunctionBody(JSContext 
     if (!parser.tokenStream.matchToken(TOK_EOF)) {
         parser.reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
         return false;
     }
 
     if (!FoldConstants(cx, pn, &parser))
         return false;
 
-    if (!AnalyzeFunctions(&parser))
+    if (!AnalyzeFunctions(&parser, nullCallerFrame))
         return false;
 
     if (fn->pn_body) {
         JS_ASSERT(fn->pn_body->isKind(PNK_ARGSBODY));
         fn->pn_body->append(pn);
         fn->pn_body->pn_pos = pn->pn_pos;
         pn = fn->pn_body;
     }
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -60,36 +60,39 @@ using namespace js::frontend;
 
 static JSBool
 NewTryNote(JSContext *cx, BytecodeEmitter *bce, JSTryNoteKind kind, unsigned stackDepth,
            size_t start, size_t end);
 
 static JSBool
 SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, unsigned index, unsigned which, ptrdiff_t offset);
 
-BytecodeEmitter::BytecodeEmitter(Parser *parser, SharedContext *sc, Handle<JSScript*> script,
+BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent, Parser *parser, SharedContext *sc,
+                                 HandleScript script, StackFrame *callerFrame, bool hasGlobalScope,
                                  unsigned lineno)
   : sc(sc),
-    parent(NULL),
+    parent(parent),
     script(sc->context, script),
     parser(parser),
+    callerFrame(callerFrame),
     atomIndices(sc->context),
     stackDepth(0), maxStackDepth(0),
     ntrynotes(0), lastTryNode(NULL),
     arrayCompDepth(0),
     emitLevel(0),
     constMap(sc->context),
     constList(sc->context),
-    globalScope(NULL),
     closedArgs(sc->context),
     closedVars(sc->context),
     typesetCount(0),
     hasSingletons(false),
-    inForInit(false)
+    inForInit(false),
+    hasGlobalScope(hasGlobalScope)
 {
+    JS_ASSERT_IF(callerFrame, callerFrame->isScriptFrame());
     memset(&prolog, 0, sizeof prolog);
     memset(&main, 0, sizeof main);
     current = &main;
     firstLine = prolog.currentLine = main.currentLine = lineno;
 }
 
 bool
 BytecodeEmitter::init()
@@ -1063,17 +1066,17 @@ EmitEnterBlock(JSContext *cx, BytecodeEm
  *     undeclared = 17; // throws ReferenceError
  *   }
  *   foo();
  */
 static bool
 TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op)
 {
     if (bce->script->compileAndGo &&
-        bce->globalScope->globalObj &&
+        bce->hasGlobalScope &&
         !bce->sc->funMightAliasLocals() &&
         !pn->isDeoptimized() &&
         !bce->sc->inStrictMode()) {
         switch (*op) {
           case JSOP_NAME:     *op = JSOP_GETGNAME; break;
           case JSOP_SETNAME:  *op = JSOP_SETGNAME; break;
           case JSOP_INCNAME:  *op = JSOP_INCGNAME; break;
           case JSOP_NAMEINC:  *op = JSOP_GNAMEINC; break;
@@ -1159,17 +1162,17 @@ BindNameToSlot(JSContext *cx, BytecodeEm
      * declaration originates at top level in eval code.
      */
     switch (op) {
       case JSOP_NAME:
       case JSOP_SETCONST:
         break;
       case JSOP_DELNAME:
         if (dn_kind != Definition::UNKNOWN) {
-            if (bce->parser->callerFrame && dn->isTopLevel())
+            if (bce->callerFrame && dn->isTopLevel())
                 JS_ASSERT(bce->script->compileAndGo);
             else
                 pn->setOp(JSOP_FALSE);
             pn->pn_dflags |= PND_BOUND;
             return true;
         }
         break;
       default:
@@ -1182,17 +1185,17 @@ BindNameToSlot(JSContext *cx, BytecodeEm
                     return false;
                 }
             }
             pn->setOp(op = JSOP_NAME);
         }
     }
 
     if (cookie.isFree()) {
-        StackFrame *caller = bce->parser->callerFrame;
+        StackFrame *caller = bce->callerFrame;
         if (caller) {
             JS_ASSERT(bce->script->compileAndGo);
 
             /*
              * Don't generate upvars on the left side of a for loop. See
              * bug 470758.
              */
             if (bce->inForInit)
@@ -4728,34 +4731,38 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
                  fun->kind() == JSFUN_INTERPRETED);
 
     {
         FunctionBox *funbox = pn->pn_funbox;
         SharedContext sc(cx, /* scopeChain = */ NULL, fun, funbox);
         sc.cxFlags = funbox->cxFlags;
         if (bce->sc->funMightAliasLocals())
             sc.setFunMightAliasLocals();  // inherit funMightAliasLocals from parent
-        sc.bindings.transfer(cx, &funbox->bindings);
-
-        // Inherit various things (principals, version, etc) from the parent.
+        sc.bindings.transfer(&funbox->bindings);
+
+        // Inherit most things (principals, version, etc) from the parent.
         GlobalObject *globalObject = fun->getParent() ? &fun->getParent()->global() : NULL;
         Rooted<JSScript*> script(cx);
         Rooted<JSScript*> parent(cx, bce->script);
-        script = JSScript::Create(cx, parent->savedCallerFun, parent->principals,
-                                  parent->originPrincipals, parent->compileAndGo,
-                                  /* noScriptRval = */ false, globalObject,
-                                  parent->getVersion(), parent->staticLevel + 1);
+        script = JSScript::Create(cx,
+                                  /* savedCallerFun = */ false,
+                                  parent->principals,
+                                  parent->originPrincipals,
+                                  parent->compileAndGo,
+                                  /* noScriptRval = */ false,
+                                  globalObject,
+                                  parent->getVersion(),
+                                  parent->staticLevel + 1);
         if (!script)
             return false;
 
-        BytecodeEmitter bce2(bce->parser, &sc, script, pn->pn_pos.begin.lineno);
+        BytecodeEmitter bce2(bce, bce->parser, &sc, script, bce->callerFrame, bce->hasGlobalScope,
+                             pn->pn_pos.begin.lineno);
         if (!bce2.init())
             return false;
-        bce2.parent = bce;
-        bce2.globalScope = bce->globalScope;
 
         /* We measured the max scope depth when we parsed the function. */
         if (!EmitFunctionScript(cx, &bce2, pn->pn_body))
             return false;
     }
 
     /* Make the function object a literal in the outer script's pool. */
     unsigned index = bce->objectList.add(pn->pn_funbox);
@@ -5625,18 +5632,18 @@ EmitObject(JSContext *cx, BytecodeEmitte
              * a non-standard setter on objects.
              */
             if (pn3->pn_atom == cx->runtime->atomState.protoAtom)
                 obj = NULL;
             op = JSOP_INITPROP;
 
             if (obj) {
                 JS_ASSERT(!obj->inDictionaryMode());
-                if (!DefineNativeProperty(cx, obj, RootedId(cx, AtomToId(pn3->pn_atom)),
-                                          UndefinedValue(), NULL, NULL,
+                Rooted<jsid> id(cx, AtomToId(pn3->pn_atom));
+                if (!DefineNativeProperty(cx, obj, id, UndefinedValue(), NULL, NULL,
                                           JSPROP_ENUMERATE, 0, 0))
                 {
                     return false;
                 }
                 if (obj->inDictionaryMode())
                     obj = NULL;
             }
 
@@ -5925,16 +5932,18 @@ frontend::EmitTree(JSContext *cx, Byteco
                 rest = pn->pn_head;
                 while (rest->pn_next != pnlast)
                     rest = rest->pn_next;
                 if (Emit1(cx, bce, JSOP_REST) < 0)
                     return false;
                 CheckTypeSet(cx, bce, JSOP_REST);
                 if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
                     return false;
+                if (!BindNameToSlot(cx, bce, rest))
+                    return JS_FALSE;
                 if (!EmitVarOp(cx, rest, JSOP_SETARG, bce))
                     return false;
                 if (Emit1(cx, bce, JSOP_POP) < 0)
                     return false;
             }
             if (!EmitDefaults(cx, bce, pn))
                 return false;
             if (fun->hasRest()) {
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -58,44 +58,38 @@ class GCConstList {
     Vector<Value> list;
   public:
     GCConstList(JSContext *cx) : list(cx) {}
     bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
     size_t length() const { return list.length(); }
     void finish(ConstArray *array);
 };
 
-struct GlobalScope {
-    GlobalScope(JSContext *cx, JSObject *globalObj)
-      : globalObj(cx, globalObj)
-    { }
-
-    RootedObject globalObj;
-};
-
 struct BytecodeEmitter
 {
-    SharedContext   *sc;            /* context shared between parsing and bytecode generation */
+    SharedContext   *const sc;      /* context shared between parsing and bytecode generation */
 
-    BytecodeEmitter *parent;        /* enclosing function or global context */
+    BytecodeEmitter *const parent;  /* enclosing function or global context */
 
-    Rooted<JSScript*> script;       /* the JSScript we're ultimately producing */
+    const Rooted<JSScript*> script;       /* the JSScript we're ultimately producing */
 
     struct {
         jsbytecode  *base;          /* base of JS bytecode vector */
         jsbytecode  *limit;         /* one byte beyond end of bytecode */
         jsbytecode  *next;          /* pointer to next free bytecode */
         jssrcnote   *notes;         /* source notes, see below */
         unsigned    noteCount;      /* number of source notes so far */
         unsigned    noteLimit;      /* limit number for source notes in notePool */
         ptrdiff_t   lastNoteOffset; /* code offset for last source note */
         unsigned    currentLine;    /* line number for tree-based srcnote gen */
     } prolog, main, *current;
 
-    Parser          *parser;        /* the parser */
+    Parser          *const parser;  /* the parser */
+
+    StackFrame      *const callerFrame; /* scripted caller frame for eval and dbgapi */
 
     OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
     unsigned        firstLine;      /* first line, for JSScript::initFromEmitter */
 
     int             stackDepth;     /* current stack depth in script frame */
     unsigned        maxStackDepth;  /* maximum stack depth so far */
 
     unsigned        ntrynotes;      /* number of allocated so far try notes */
@@ -109,30 +103,33 @@ struct BytecodeEmitter
     ConstMap        constMap;       /* compile time constants */
 
     GCConstList     constList;      /* constants to be included with the script */
 
     CGObjectList    objectList;     /* list of emitted objects */
     CGObjectList    regexpList;     /* list of emitted regexp that will be
                                        cloned during execution */
 
-    GlobalScope     *globalScope;   /* frontend::CompileScript global scope, or null */
-
     /* Vectors of pn_cookie slot values. */
     typedef Vector<uint32_t, 8> SlotVector;
     SlotVector      closedArgs;
     SlotVector      closedVars;
 
     uint16_t        typesetCount;   /* Number of JOF_TYPESET opcodes generated */
 
     bool            hasSingletons:1;    /* script contains singleton initializer JSOP_OBJECT */
 
     bool            inForInit:1;        /* emitting init expr of for; exclude 'in' */
 
-    BytecodeEmitter(Parser *parser, SharedContext *sc, Handle<JSScript*> script, unsigned lineno);
+    const bool      hasGlobalScope:1;   /* frontend::CompileScript's scope chain is the
+                                           global object */
+
+    BytecodeEmitter(BytecodeEmitter *parent, Parser *parser, SharedContext *sc,
+                    HandleScript script, StackFrame *callerFrame, bool hasGlobalScope,
+                    unsigned lineno);
     bool init();
 
     /*
      * Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
      * space above their tempMark points. This means that you cannot alloc from
      * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
      * destructor call.
      */
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -79,32 +79,30 @@ using namespace js::frontend;
 bool
 StrictModeGetter::get() const
 {
     return parser->tc->sc->inStrictMode();
 }
 
 Parser::Parser(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin,
                const jschar *chars, size_t length, const char *fn, unsigned ln, JSVersion v,
-               StackFrame *cfp, bool foldConstants, bool compileAndGo)
+               bool foldConstants, bool compileAndGo)
   : AutoGCRooter(cx, PARSER),
     context(cx),
     strictModeGetter(this),
     tokenStream(cx, prin, originPrin, chars, length, fn, ln, v, &strictModeGetter),
     tempPoolMark(NULL),
-    callerFrame(cfp),
     allocator(cx),
     traceListHead(NULL),
     tc(NULL),
     keepAtoms(cx->runtime),
     foldConstants(foldConstants),
     compileAndGo(compileAndGo)
 {
     cx->activeCompilations++;
-    JS_ASSERT_IF(cfp, cfp->isScriptFrame());
 }
 
 bool
 Parser::init()
 {
     if (!context->ensureParseMapPool())
         return false;
 
@@ -152,17 +150,17 @@ Parser::newObjectBox(JSObject *obj)
 }
 
 FunctionBox::FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseNode *fn, TreeContext *tc)
   : ObjectBox(traceListHead, obj),
     node(fn),
     siblings(tc->functionList),
     kids(NULL),
     parent(tc->sc->inFunction() ? tc->sc->funbox() : NULL),
-    bindings(tc->sc->context),
+    bindings(),
     level(tc->staticLevel),
     ndefaults(0),
     inLoop(false),
     inWith(!!tc->innermostWith),
     inGenexpLambda(false),
     cxFlags(tc->sc->context)     // the cxFlags are set in LeaveFunction
 {
     isFunctionBox = true;
@@ -490,17 +488,17 @@ CheckStrictParameters(JSContext *cx, Par
     JSAtom *argumentsAtom = cx->runtime->atomState.argumentsAtom;
     JSAtom *evalAtom = cx->runtime->atomState.evalAtom;
 
     /* name => whether we've warned about the name already */
     HashMap<JSAtom *, bool> parameters(cx);
     if (!parameters.init(sc->bindings.numArgs()))
         return false;
 
-    /* Start with lastVariable(), not lastArgument(), for destructuring. */
+    // Start with lastVariable(), not the last argument, for destructuring.
     for (Shape::Range r = sc->bindings.lastVariable(); !r.empty(); r.popFront()) {
         jsid id = r.front().propid();
         if (!JSID_IS_ATOM(id))
             continue;
 
         JSAtom *name = JSID_TO_ATOM(id);
 
         if (name == argumentsAtom || name == evalAtom) {
@@ -535,17 +533,18 @@ CheckStrictParameters(JSContext *cx, Par
 }
 
 static bool
 BindLocalVariable(JSContext *cx, TreeContext *tc, ParseNode *pn, BindingKind kind)
 {
     JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
 
     unsigned index = tc->sc->bindings.numVars();
-    if (!tc->sc->bindings.add(cx, RootedAtom(cx, pn->pn_atom), kind))
+    Rooted<JSAtom*> atom(cx, pn->pn_atom);
+    if (!tc->sc->bindings.add(cx, atom, kind))
         return false;
 
     if (!pn->pn_cookie.set(cx, tc->staticLevel, index))
         return false;
     pn->pn_dflags |= PND_BOUND;
     return true;
 }
 
@@ -599,17 +598,17 @@ Parser::functionBody(FunctionBodyType ty
 
     /*
      * Check CheckStrictParameters before arguments logic below adds
      * 'arguments' to bindings.
      */
     if (!CheckStrictParameters(context, this))
         return NULL;
 
-    Rooted<PropertyName*> const arguments(context, context->runtime->atomState.argumentsAtom);
+    Rooted<PropertyName*> arguments(context, context->runtime->atomState.argumentsAtom);
 
     /*
      * Non-top-level functions use JSOP_DEFFUN which is a dynamic scope
      * operation which means it aliases any bindings with the same name.
      * Due to the implicit declaration mechanism (below), 'arguments' will not
      * have decls and, even if it did, they will not be noted as closed in the
      * emitter. Thus, in the corner case of function-statement-overridding-
      * arguments, flag the whole scope as dynamic.
@@ -704,34 +703,16 @@ Parser::functionBody(FunctionBodyType ty
         break;
       case ARGUMENT:
         break;
     }
 
     return pn;
 }
 
-bool
-Parser::checkForArgumentsAndRest()
-{
-    JS_ASSERT(!tc->sc->inFunction());
-    if (callerFrame && callerFrame->isFunctionFrame() && callerFrame->fun()->hasRest()) {
-        PropertyName *arguments = context->runtime->atomState.argumentsAtom;
-        for (AtomDefnRange r = tc->lexdeps->all(); !r.empty(); r.popFront()) {
-            if (r.front().key() == arguments) {
-                reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ARGUMENTS_AND_REST);
-                return false;
-            }
-        }
-        /* We're not in a function context, so we don't expect any bindings. */
-        JS_ASSERT(tc->sc->bindings.lookup(context, arguments, NULL) == NONE);
-    }
-    return true;
-}
-
 // Create a placeholder Definition node for |atom|.
 // Nb: unlike most functions that are passed a Parser, this one gets a
 // SharedContext passed in separately, because in this case |sc| may not equal
 // |parser->tc->sc|.
 static Definition *
 MakePlaceholder(ParseNode *pn, Parser *parser, SharedContext *sc)
 {
     Definition *dn = (Definition *) NameNode::create(PNK_NAME, pn->pn_atom, parser, sc);
@@ -1232,17 +1213,17 @@ LeaveFunction(ParseNode *fn, Parser *par
             funtc->lexdeps.clearMap();
             fn->pn_body->pn_tree = body;
         } else {
             funtc->lexdeps.releaseMap(funtc->sc->context);
         }
 
     }
 
-    funbox->bindings.transfer(funtc->sc->context, &funtc->sc->bindings);
+    funbox->bindings.transfer(&funtc->sc->bindings);
 
     return true;
 }
 
 bool
 Parser::functionArguments(ParseNode **listp, bool &hasRest)
 {
     if (tokenStream.getToken() != TOK_LP) {
@@ -6846,18 +6827,18 @@ Parser::primaryExpr(TokenKind tt, bool a
                             return NULL;
                         pn3->pn_atom = atom;
                         break;
                     }
 
                     pn->pn_xflags |= PNX_NONCONST;
 
                     /* NB: Getter function in { get x(){} } is unnamed. */
-                    pn2 = functionDef(RootedPropertyName(context, NULL),
-                                      op == JSOP_GETTER ? Getter : Setter, Expression);
+                    Rooted<PropertyName*> funName(context, NULL);
+                    pn2 = functionDef(funName, op == JSOP_GETTER ? Getter : Setter, Expression);
                     if (!pn2)
                         return NULL;
                     TokenPos pos = {begin, pn2->pn_pos.end};
                     pn2 = new_<BinaryNode>(PNK_COLON, op, pos, pn3, pn2);
                     goto skip;
                 }
               case TOK_STRING: {
                 atom = tokenStream.currentToken().atom();
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -33,17 +33,16 @@ enum LetContext { LetExpresion, LetState
 enum VarContext { HoistVars, DontHoistVars };
 
 struct Parser : private AutoGCRooter
 {
     JSContext           *const context; /* FIXME Bug 551291: use AutoGCRooter::context? */
     StrictModeGetter    strictModeGetter; /* used by tokenStream to test for strict mode */
     TokenStream         tokenStream;
     void                *tempPoolMark;  /* initial JSContext.tempLifoAlloc mark */
-    StackFrame          *const callerFrame;  /* scripted caller frame for eval and dbgapi */
     ParseNodeAllocator  allocator;
     ObjectBox           *traceListHead; /* list of parsed object for GC tracing */
 
     TreeContext         *tc;            /* innermost tree context (stack-allocated) */
 
     /* Root atoms and objects allocated for the parsed tree. */
     AutoKeepAtoms       keepAtoms;
 
@@ -52,17 +51,17 @@ struct Parser : private AutoGCRooter
 
   private:
     /* Script can optimize name references based on scope chain. */
     const bool          compileAndGo:1;
 
   public:
     Parser(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin,
            const jschar *chars, size_t length, const char *fn, unsigned ln, JSVersion version,
-           StackFrame *cfp, bool foldConstants, bool compileAndGo);
+           bool foldConstants, bool compileAndGo);
     ~Parser();
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 
     /*
      * Initialize a parser. The compiler owns the arena pool "tops-of-stack"
      * space above the current JSContext.tempLifoAlloc mark. This means you
      * cannot allocate from tempLifoAlloc and save the pointer beyond the next
@@ -136,18 +135,16 @@ struct Parser : private AutoGCRooter
 
     /*
      * Parse a function body.  Pass StatementListBody if the body is a list of
      * statements; pass ExpressionBody if the body is a single expression.
      */
     enum FunctionBodyType { StatementListBody, ExpressionBody };
     ParseNode *functionBody(FunctionBodyType type);
 
-    bool checkForArgumentsAndRest();
-
   private:
     /*
      * JS parsers, from lowest to highest precedence.
      *
      * Each parser must be called during the dynamic scope of a TreeContext
      * object, pointed to by this->tc.
      *
      * Each returns a parse node tree or null on error.
--- a/js/src/frontend/SemanticAnalysis.cpp
+++ b/js/src/frontend/SemanticAnalysis.cpp
@@ -153,23 +153,23 @@ MarkExtensibleScopeDescendants(JSContext
             }
         }
     }
 
     return true;
 }
 
 bool
-frontend::AnalyzeFunctions(Parser *parser)
+frontend::AnalyzeFunctions(Parser *parser, StackFrame *callerFrame)
 {
     TreeContext *tc = parser->tc;
     SharedContext *sc = tc->sc;
     if (!tc->functionList)
         return true;
     if (!MarkExtensibleScopeDescendants(sc->context, tc->functionList, false))
         return false;
-    bool isDirectEval = !!parser->callerFrame;
+    bool isDirectEval = !!callerFrame;
     bool isHeavyweight = false;
     SetFunctionKinds(tc->functionList, &isHeavyweight, sc->inFunction(), isDirectEval);
     if (isHeavyweight)
         sc->setFunIsHeavyweight();
     return true;
 }
--- a/js/src/frontend/SemanticAnalysis.h
+++ b/js/src/frontend/SemanticAnalysis.h
@@ -6,23 +6,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef SemanticAnalysis_h__
 #define SemanticAnalysis_h__
 
 namespace js {
 
 struct Parser;
+class StackFrame;
 
 namespace frontend {
 
 /*
  * For each function in the compilation unit given by tc, decide whether the
  * function is a full closure or a null closure and set JSFunction flags
  * accordingly.
  */
 bool
-AnalyzeFunctions(Parser *parser);
+AnalyzeFunctions(Parser *parser, StackFrame *callerFrame);
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* SemanticAnalysis_h__ */
--- a/js/src/frontend/TreeContext-inl.h
+++ b/js/src/frontend/TreeContext-inl.h
@@ -22,17 +22,17 @@ SharedContext::SharedContext(JSContext *
     bodyid(0),
     blockidGen(0),
     topStmt(NULL),
     topScopeStmt(NULL),
     blockChain(cx),
     fun_(cx, fun),
     funbox_(funbox),
     scopeChain_(cx, scopeChain),
-    bindings(cx),
+    bindings(),
     bindingsRoot(cx, &bindings),
     cxFlags(cx)
 {
     JS_ASSERT((fun && !scopeChain_) || (!fun && !funbox));
 }
 
 inline unsigned
 SharedContext::blockid()
--- a/js/src/gc/Root.h
+++ b/js/src/gc/Root.h
@@ -97,17 +97,17 @@ class Handle
         h.ptr = p;
         return h;
     }
 
     /*
      * Construct a handle from an explicitly rooted location. This is the
      * normal way to create a handle, and normally happens implicitly.
      */
-    template <typename S> inline Handle(const Rooted<S> &root);
+    template <typename S> inline Handle(Rooted<S> &root);
 
     const T *address() const { return ptr; }
     T value() const { return *ptr; }
 
     operator T () const { return value(); }
     T operator ->() const { return value(); }
 
   private:
@@ -164,25 +164,16 @@ class Rooted
 
         ptr = initial;
     }
 
   public:
     Rooted(JSContext *cx) { init(cx, RootMethods<T>::initial()); }
     Rooted(JSContext *cx, T initial) { init(cx, initial); }
 
-    /*
-     * This method is only necessary due to an obscure C++98 requirement (that
-     * there be an accessible, usable copy constructor when passing a temporary
-     * to an implicitly-called constructor for use with a const-ref parameter).
-     * (Head spinning yet?)  We can remove this when we build the JS engine
-     * with -std=c++11.
-     */
-    operator Handle<T> () const { return Handle<T>(*this); }
-
     ~Rooted()
     {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
         JS_ASSERT(*stack == this);
         *stack = prev;
 #endif
     }
 
@@ -218,17 +209,17 @@ class Rooted
     T ptr;
 
     Rooted() MOZ_DELETE;
     Rooted(const Rooted &) MOZ_DELETE;
 };
 
 template<typename T> template <typename S>
 inline
-Handle<T>::Handle(const Rooted<S> &root)
+Handle<T>::Handle(Rooted<S> &root)
 {
     testAssign<S>();
     ptr = reinterpret_cast<const T *>(root.address());
 }
 
 typedef Rooted<JSObject*>    RootedObject;
 typedef Rooted<JSFunction*>  RootedFunction;
 typedef Rooted<JSScript*>    RootedScript;
--- a/js/src/jit-test/tests/arguments/defaults-with-rest.js
+++ b/js/src/jit-test/tests/arguments/defaults-with-rest.js
@@ -12,8 +12,13 @@ function f2(a=rest, ...rest) {
     assertEq(a, undefined);
 }
 f2();
 function f3(a=rest, ...rest) {
     assertEq(a, 1);
     assertEqArray(rest, [2, 3, 4]);
 }
 f3(1, 2, 3, 4);
+function f4(a=42, ...f)  {
+    assertEq(typeof f, "function");
+    function f() {}
+}
+f4()
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1790,17 +1790,18 @@ JS_InitStandardClasses(JSContext *cx, JS
      * it before assertSameCompartment. (The API contract is that *after* this,
      * cx and obj must be in the same compartment.)
      */
     if (!cx->globalObject)
         JS_SetGlobalObject(cx, obj);
 
     assertSameCompartment(cx, obj);
 
-    return GlobalObject::initStandardClasses(cx, Rooted<GlobalObject*>(cx, &obj->global()));
+    Rooted<GlobalObject*> global(cx, &obj->global());
+    return GlobalObject::initStandardClasses(cx, global);
 }
 
 #define CLASP(name)                 (&name##Class)
 #define TYPED_ARRAY_CLASP(type)     (&TypedArray::classes[TypedArray::type])
 #define EAGER_ATOM(name)            NAME_OFFSET(name)
 #define EAGER_CLASS_ATOM(name)      CLASS_NAME_OFFSET(name)
 #define EAGER_ATOM_AND_CLASP(name)  EAGER_CLASS_ATOM(name), CLASP(name)
 
@@ -3160,17 +3161,17 @@ JS_ResolveStub(JSContext *cx, JSHandleOb
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ConvertStub(JSContext *cx, JSHandleObject obj, JSType type, jsval *vp)
 {
     JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
     JS_ASSERT(obj);
-    return DefaultValue(cx, RootedObject(cx, obj), type, vp);
+    return DefaultValue(cx, obj, type, vp);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_InitClass(JSContext *cx, JSObject *obj_, JSObject *parent_proto,
              JSClass *clasp, JSNative constructor, unsigned nargs,
              JSPropertySpec *ps, JSFunctionSpec *fs,
              JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
 {
@@ -3248,40 +3249,46 @@ JS_GetInstancePrivate(JSContext *cx, JSO
 
 JS_PUBLIC_API(JSObject *)
 JS_GetPrototype(JSObject *obj)
 {
     return obj->getProto();
 }
 
 JS_PUBLIC_API(JSBool)
-JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
-{
-    AssertNoGC(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj, proto);
-    return SetProto(cx, RootedObject(cx, obj), RootedObject(cx, proto), JS_FALSE);
+JS_SetPrototype(JSContext *cx, JSObject *obj_, JSObject *proto_)
+{
+    AssertNoGC(cx);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, obj_, proto_);
+
+    Rooted<JSObject*> obj(cx, obj_);
+    Rooted<JSObject*> proto(cx, proto_);
+    return SetProto(cx, obj, proto, JS_FALSE);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetParent(JSObject *obj)
 {
     JS_ASSERT(!obj->isScope());
     return obj->getParent();
 }
 
 JS_PUBLIC_API(JSBool)
-JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
-{
-    AssertNoGC(cx);
-    CHECK_REQUEST(cx);
-    JS_ASSERT(!obj->isScope());
-    JS_ASSERT(parent || !obj->getParent());
-    assertSameCompartment(cx, obj, parent);
-    return JSObject::setParent(cx, RootedObject(cx, obj), RootedObject(cx, parent));
+JS_SetParent(JSContext *cx, JSObject *obj_, JSObject *parent_)
+{
+    AssertNoGC(cx);
+    CHECK_REQUEST(cx);
+    JS_ASSERT(!obj_->isScope());
+    JS_ASSERT(parent_ || !obj_->getParent());
+    assertSameCompartment(cx, obj_, parent_);
+
+    Rooted<JSObject*> obj(cx, obj_);
+    Rooted<JSObject*> parent(cx, parent_);
+    return JSObject::setParent(cx, obj, parent);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetConstructor(JSContext *cx, JSObject *proto)
 {
     Value cval;
 
     AssertNoGC(cx);
@@ -3821,22 +3828,25 @@ JS_DefineUCPropertyWithTinyId(JSContext 
                               int8_t tinyid, jsval value,
                               JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
 {
     return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs,
                             Shape::HAS_SHORTID, tinyid);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
-{
-    AssertNoGC(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj, id, descriptor);
-    return js_DefineOwnProperty(cx, RootedObject(cx, obj), RootedId(cx, id), descriptor, bp);
+JS_DefineOwnProperty(JSContext *cx, JSObject *obj_, jsid id_, jsval descriptor, JSBool *bp)
+{
+    AssertNoGC(cx);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, obj_, id_, descriptor);
+
+    Rooted<JSObject*> obj(cx, obj_);
+    Rooted<jsid> id(cx, id_);
+    return js_DefineOwnProperty(cx, obj, id, descriptor, bp);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_DefineObject(JSContext *cx, JSObject *obj_, const char *name, JSClass *jsclasp,
                 JSObject *proto, unsigned attrs)
 {
     RootedObject obj(cx, obj_), nobj(cx);
 
@@ -4002,21 +4012,24 @@ JS_GetUCPropertyAttrsGetterAndSetter(JSC
                                      JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
 {
     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
     return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, AtomToId(atom),
                                                           attrsp, foundp, getterp, setterp);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
-{
-    AssertNoGC(cx);
-    CHECK_REQUEST(cx);
-    return GetOwnPropertyDescriptor(cx, RootedObject(cx, obj), RootedId(cx, id), vp);
+JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj_, jsid id_, jsval *vp)
+{
+    AssertNoGC(cx);
+    CHECK_REQUEST(cx);
+
+    Rooted<JSObject*> obj(cx, obj_);
+    Rooted<jsid> id(cx, id_);
+    return GetOwnPropertyDescriptor(cx, obj, id, vp);
 }
 
 static JSBool
 SetPropertyAttributesById(JSContext *cx, JSObject *obj, HandleId id, unsigned attrs, JSBool *foundp)
 {
     JSObject *obj2;
     JSProperty *prop;
 
@@ -4035,25 +4048,27 @@ SetPropertyAttributesById(JSContext *cx,
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
                          unsigned attrs, JSBool *foundp)
 {
     JSAtom *atom = js_Atomize(cx, name, strlen(name));
-    return atom && SetPropertyAttributesById(cx, obj, RootedId(cx, AtomToId(atom)), attrs, foundp);
+    Rooted<jsid> id(cx, AtomToId(atom));
+    return atom && SetPropertyAttributesById(cx, obj, id, attrs, foundp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
                            unsigned attrs, JSBool *foundp)
 {
     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
-    return atom && SetPropertyAttributesById(cx, obj, RootedId(cx, AtomToId(atom)), attrs, foundp);
+    Rooted<jsid> id(cx, AtomToId(atom));
+    return atom && SetPropertyAttributesById(cx, obj, id, attrs, foundp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     return JS_ForwardGetPropertyTo(cx, obj, id, obj, vp);
 }
 
@@ -4067,19 +4082,21 @@ JS_ForwardGetPropertyTo(JSContext *cx, J
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     assertSameCompartment(cx, onBehalfOf);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
     return obj->getGeneric(cx, onBehalfOf, id, vp);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp)
-{
-    return baseops::GetPropertyDefault(cx, RootedObject(cx, obj), RootedId(cx, id), def, vp);
+JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj_, jsid id_, jsval def, jsval *vp)
+{
+    Rooted<JSObject*> obj(cx, obj_);
+    Rooted<jsid> id(cx, id_);
+    return baseops::GetPropertyDefault(cx, obj, id, def, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetElement(JSContext *cx, JSObject *obj, uint32_t index, jsval *vp)
 {
     return JS_ForwardGetElementTo(cx, obj, index, obj, vp);
 }
 
@@ -4201,18 +4218,20 @@ JS_SetUCProperty(JSContext *cx, JSObject
 JS_PUBLIC_API(JSBool)
 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
-    if (JSID_IS_SPECIAL(id))
-        return obj->deleteSpecial(cx, Rooted<SpecialId>(cx, JSID_TO_SPECIALID(id)), rval, false);
+    if (JSID_IS_SPECIAL(id)) {
+        Rooted<SpecialId> sid(cx, JSID_TO_SPECIALID(id));
+        return obj->deleteSpecial(cx, sid, rval, false);
+    }
 
     return obj->deleteByValue(cx, IdToValue(id), rval, false);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeleteElement2(JSContext *cx, JSObject *obj, uint32_t index, jsval *rval)
 {
     AssertNoGC(cx);
@@ -4448,22 +4467,24 @@ JS_NextProperty(JSContext *cx, JSObject 
             *idp = ida->vector[--i];
             iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
         }
     }
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_NewElementIterator(JSContext *cx, JSObject *obj)
-{
-    AssertNoGC(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj);
-    return ElementIteratorObject::create(cx, RootedObject(cx, obj));
+JS_NewElementIterator(JSContext *cx, JSObject *obj_)
+{
+    AssertNoGC(cx);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, obj_);
+
+    Rooted<JSObject*> obj(cx, obj_);
+    return ElementIteratorObject::create(cx, obj);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_ElementIteratorStub(JSContext *cx, JSHandleObject obj, JSBool keysonly)
 {
     JS_ASSERT(!keysonly);
     return JS_NewElementIterator(cx, obj);
 }
@@ -4745,45 +4766,43 @@ JS_DefineFunctions(JSContext *cx, JSObje
     assertSameCompartment(cx, obj);
     for (; fs->name; fs++) {
         flags = fs->flags;
 
         RootedAtom atom(cx, js_Atomize(cx, fs->name, strlen(fs->name)));
         if (!atom)
             return JS_FALSE;
 
+        Rooted<jsid> id(cx, AtomToId(atom));
+
         /*
          * Define a generic arity N+1 static method for the arity N prototype
          * method if flags contains JSFUN_GENERIC_NATIVE.
          */
         if (flags & JSFUN_GENERIC_NATIVE) {
             if (!ctor) {
                 ctor = JS_GetConstructor(cx, obj);
                 if (!ctor)
                     return JS_FALSE;
             }
 
             flags &= ~JSFUN_GENERIC_NATIVE;
-            fun = js_DefineFunction(cx, ctor, RootedId(cx, AtomToId(atom)),
-                                    js_generic_native_method_dispatcher,
-                                    fs->nargs + 1,
-                                    flags,
-                                    JSFunction::ExtendedFinalizeKind);
+            fun = js_DefineFunction(cx, ctor, id, js_generic_native_method_dispatcher,
+                                    fs->nargs + 1, flags, JSFunction::ExtendedFinalizeKind);
             if (!fun)
                 return JS_FALSE;
 
             /*
              * As jsapi.h notes, fs must point to storage that lives as long
              * as fun->object lives.
              */
             fun->setExtendedSlot(0, PrivateValue(fs));
         }
 
-        fun = js_DefineFunction(cx, obj,
-                                RootedId(cx, AtomToId(atom)), fs->call, fs->nargs, flags);
+        fun = js_DefineFunction(cx, obj, id, fs->call, fs->nargs, flags);
         if (!fun)
             return JS_FALSE;
     }
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_DefineFunction(JSContext *cx, JSObject *obj_, const char *name, JSNative call,
@@ -4793,34 +4812,36 @@ JS_DefineFunction(JSContext *cx, JSObjec
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAtom *atom = js_Atomize(cx, name, strlen(name));
     if (!atom)
         return NULL;
-    return js_DefineFunction(cx, obj, RootedId(cx, AtomToId(atom)), call, nargs, attrs);
+    Rooted<jsid> id(cx, AtomToId(atom));
+    return js_DefineFunction(cx, obj, id, call, nargs, attrs);
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_DefineUCFunction(JSContext *cx, JSObject *obj_,
                     const jschar *name, size_t namelen, JSNative call,
                     unsigned nargs, unsigned attrs)
 {
     RootedObject obj(cx, obj_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
     if (!atom)
         return NULL;
-    return js_DefineFunction(cx, obj, RootedId(cx, AtomToId(atom)), call, nargs, attrs);
+    Rooted<jsid> id(cx, AtomToId(atom));
+    return js_DefineFunction(cx, obj, id, call, nargs, attrs);
 }
 
 extern JS_PUBLIC_API(JSFunction *)
 JS_DefineFunctionById(JSContext *cx, JSObject *obj_, jsid id_, JSNative call,
                     unsigned nargs, unsigned attrs)
 {
     RootedObject obj(cx, obj_);
     RootedId id(cx, id_);
@@ -4982,17 +5003,17 @@ JS_BufferIsCompilableUnit(JSContext *cx,
      * Return true on any out-of-memory error, so our caller doesn't try to
      * collect more buffered source.
      */
     result = JS_TRUE;
     exnState = JS_SaveExceptionState(cx);
     {
         Parser parser(cx, /* prin = */ NULL, /* originPrin = */ NULL,
                       chars, length, /* filename = */ NULL, /* lineno = */ 1, cx->findVersion(), 
-                      /* cfp = */ NULL, /* foldConstants = */ true, /* compileAndGo = */ false);
+                      /* foldConstants = */ true, /* compileAndGo = */ false);
         if (parser.init()) {
             older = JS_SetErrorReporter(cx, NULL);
             if (!parser.parse(obj) &&
                 parser.tokenStream.isUnexpectedEOF()) {
                 /*
                  * We ran into an error. If it was because we ran out of
                  * source, we return false so our caller knows to try to
                  * collect more buffered source.
@@ -5167,17 +5188,17 @@ CompileUCFunctionForPrincipalsCommon(JSC
 
     RootedAtom funAtom(cx);
     if (name) {
         funAtom = js_Atomize(cx, name, strlen(name));
         if (!funAtom)
             return NULL;
     }
 
-    Bindings bindings(cx);
+    Bindings bindings;
     for (unsigned i = 0; i < nargs; i++) {
         uint16_t dummy;
         RootedAtom argAtom(cx, js_Atomize(cx, argnames[i], strlen(argnames[i])));
         if (!argAtom || !bindings.addArgument(cx, argAtom, &dummy))
             return NULL;
     }
 
     JSFunction *fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
@@ -5185,21 +5206,20 @@ CompileUCFunctionForPrincipalsCommon(JSC
         return NULL;
 
     if (!frontend::CompileFunctionBody(cx, fun, principals, NULL, &bindings,
                                        chars, length, filename, lineno, version))
     {
         return NULL;
     }
 
-    if (obj && funAtom &&
-        !obj->defineGeneric(cx, RootedId(cx, AtomToId(funAtom)), ObjectValue(*fun), NULL, NULL,
-                            JSPROP_ENUMERATE))
-    {
-        return NULL;
+    if (obj && funAtom) {
+        Rooted<jsid> id(cx, AtomToId(funAtom));
+        if (!obj->defineGeneric(cx, id, ObjectValue(*fun), NULL, NULL, JSPROP_ENUMERATE))
+            return NULL;
     }
 
     return fun;
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj,
                                          JSPrincipals *principals, const char *name,
@@ -5488,18 +5508,21 @@ JS_CallFunctionName(JSContext *cx, JSObj
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj_, JSValueArray(argv, argc));
     AutoLastFrameCheck lfc(cx);
 
     RootedObject obj(cx, obj_);
 
     Value v;
     JSAtom *atom = js_Atomize(cx, name, strlen(name));
-    return atom &&
-           GetMethod(cx, obj, RootedId(cx, AtomToId(atom)), 0, &v) &&
+    if (!atom)
+        return false;
+
+    Rooted<jsid> id(cx, AtomToId(atom));
+    return GetMethod(cx, obj, id, 0, &v) &&
            Invoke(cx, ObjectOrNullValue(obj), v, argc, argv, rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, unsigned argc, jsval *argv,
                      jsval *rval)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
@@ -5868,17 +5891,19 @@ JS_NewDependentString(JSContext *cx, JSS
     return js_NewDependentString(cx, str, start, length);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
-    return js_ConcatStrings(cx, RootedString(cx, left), RootedString(cx, right));
+    Rooted<JSString*> lstr(cx, left);
+    Rooted<JSString*> rstr(cx, right);
+    return js_ConcatStrings(cx, lstr, rstr);
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_UndependString(JSContext *cx, JSString *str)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     return str->getCharsZ(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1402,33 +1402,20 @@ typedef JSBool
  *
  *  JSRESOLVE_QUALIFIED   a qualified property id: obj.id or obj[id], not id
  *  JSRESOLVE_ASSIGNING   obj[id] is on the left-hand side of an assignment
  *  JSRESOLVE_DETECTING   'if (o.p)...' or similar detection opcode sequence
  *  JSRESOLVE_DECLARING   var, const, or function prolog declaration opcode
  *
  * The *objp out parameter, on success, should be null to indicate that id
  * was not resolved; and non-null, referring to obj or one of its prototypes,
- * if id was resolved.
+ * if id was resolved.  The hook may assume *objp is null on entry.
  *
  * This hook instead of JSResolveOp is called via the JSClass.resolve member
  * if JSCLASS_NEW_RESOLVE is set in JSClass.flags.
- *
- * Setting JSCLASS_NEW_RESOLVE and JSCLASS_NEW_RESOLVE_GETS_START further
- * extends this hook by passing in the starting object on the prototype chain
- * via *objp.  Thus a resolve hook implementation may define the property id
- * being resolved in the object in which the id was first sought, rather than
- * in a prototype object whose class led to the resolve hook being called.
- *
- * When using JSCLASS_NEW_RESOLVE_GETS_START, the resolve hook must therefore
- * null *objp to signify "not resolved".  With only JSCLASS_NEW_RESOLVE and no
- * JSCLASS_NEW_RESOLVE_GETS_START, the hook can assume *objp is null on entry.
- * This is not good practice, but enough existing hook implementations count
- * on it that we can't break compatibility by passing the starting object in
- * *objp without a new JSClass flag.
  */
 typedef JSBool
 (* JSNewResolveOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
                    JSObject **objp);
 
 /*
  * Convert obj to the given type, returning true with the resulting value in
  * *vp on success, and returning false on error or exception.
@@ -3659,20 +3646,17 @@ struct JSClass {
 
     void                *reserved[40];
 };
 
 #define JSCLASS_HAS_PRIVATE             (1<<0)  /* objects have private slot */
 #define JSCLASS_NEW_ENUMERATE           (1<<1)  /* has JSNewEnumerateOp hook */
 #define JSCLASS_NEW_RESOLVE             (1<<2)  /* has JSNewResolveOp hook */
 #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  /* private is (nsISupports *) */
-#define JSCLASS_NEW_RESOLVE_GETS_START  (1<<4)  /* JSNewResolveOp gets starting
-                                                   object in prototype chain
-                                                   passed in via *objp in/out
-                                                   parameter */
+/* (1<<4) is unused */
 #define JSCLASS_IMPLEMENTS_BARRIERS     (1<<5)  /* Correctly implements GC read
                                                    and write barriers */
 #define JSCLASS_DOCUMENT_OBSERVER       (1<<6)  /* DOM document observer */
 #define JSCLASS_USERBIT1                (1<<7)  /* Reserved for embeddings. */
 
 /*
  * To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
  * JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -711,17 +711,18 @@ array_lookupGeneric(JSContext *cx, Handl
     }
     return proto->lookupGeneric(cx, id, objp, propp);
 }
 
 static JSBool
 array_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSObject **objp,
                      JSProperty **propp)
 {
-    return array_lookupGeneric(cx, obj, RootedId(cx, NameToId(name)), objp, propp);
+    Rooted<jsid> id(cx, NameToId(name));
+    return array_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 array_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, JSObject **objp,
                     JSProperty **propp)
 {
     if (!obj->isDenseArray())
         return baseops::LookupElement(cx, obj, index, objp, propp);
@@ -739,17 +740,18 @@ array_lookupElement(JSContext *cx, Handl
     *propp = NULL;
     return true;
 }
 
 static JSBool
 array_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSObject **objp,
                     JSProperty **propp)
 {
-    return array_lookupGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)), objp, propp);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return array_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     JS_ASSERT(obj->isDenseArray());
 
     uint32_t i;
@@ -770,18 +772,20 @@ array_getProperty(JSContext *cx, HandleO
         return true;
     }
 
     if (name == cx->runtime->atomState.protoAtom) {
         vp->setObjectOrNull(obj->getProto());
         return true;
     }
 
-    if (!obj->isDenseArray())
-        return baseops::GetProperty(cx, obj, receiver, RootedId(cx, NameToId(name)), vp);
+    if (!obj->isDenseArray()) {
+        Rooted<jsid> id(cx, NameToId(name));
+        return baseops::GetProperty(cx, obj, receiver, id, vp);
+    }
 
     JSObject *proto = obj->getProto();
     if (!proto) {
         vp->setUndefined();
         return true;
     }
 
     return proto->getProperty(cx, receiver, name, vp);
@@ -816,40 +820,42 @@ array_getElement(JSContext *cx, HandleOb
 static JSBool
 array_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid, Value *vp)
 {
     if (obj->isDenseArray() && !obj->getProto()) {
         vp->setUndefined();
         return true;
     }
 
-    return baseops::GetProperty(cx, obj, receiver, RootedId(cx, SPECIALID_TO_JSID(sid)), vp);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return baseops::GetProperty(cx, obj, receiver, id, vp);
 }
 
 static JSBool
 array_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, Value *vp)
 {
     Value idval = IdToValue(id);
 
     uint32_t index;
     if (IsDefinitelyIndex(idval, &index))
         return array_getElement(cx, obj, receiver, index, vp);
 
-    SpecialId sid;
-    if (ValueIsSpecial(obj, &idval, &sid, cx))
-        return array_getSpecial(cx, obj, receiver, Rooted<SpecialId>(cx, sid), vp);
+    Rooted<SpecialId> sid(cx);
+    if (ValueIsSpecial(obj, &idval, sid.address(), cx))
+        return array_getSpecial(cx, obj, receiver, sid, vp);
 
     JSAtom *atom = ToAtom(cx, idval);
     if (!atom)
         return false;
 
     if (atom->isIndex(&index))
         return array_getElement(cx, obj, receiver, index, vp);
 
-    return array_getProperty(cx, obj, receiver, RootedPropertyName(cx, atom->asPropertyName()), vp);
+    Rooted<PropertyName*> name(cx, atom->asPropertyName());
+    return array_getProperty(cx, obj, receiver, name, vp);
 }
 
 static JSBool
 slowarray_addProperty(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
 {
     uint32_t index, length;
 
     if (!js_IdIsIndex(id, &index))
@@ -899,17 +905,18 @@ array_setGeneric(JSContext *cx, HandleOb
     if (!JSObject::makeDenseArraySlow(cx, obj))
         return false;
     return baseops::SetPropertyHelper(cx, obj, id, 0, vp, strict);
 }
 
 static JSBool
 array_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, Value *vp, JSBool strict)
 {
-    return array_setGeneric(cx, obj, RootedId(cx, NameToId(name)), vp, strict);
+    Rooted<jsid> id(cx, NameToId(name));
+    return array_setGeneric(cx, obj, id, vp, strict);
 }
 
 static JSBool
 array_setElement(JSContext *cx, HandleObject obj, uint32_t index, Value *vp, JSBool strict)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
@@ -944,17 +951,18 @@ array_setElement(JSContext *cx, HandleOb
     if (!JSObject::makeDenseArraySlow(cx, obj))
         return false;
     return baseops::SetPropertyHelper(cx, obj, id, 0, vp, strict);
 }
 
 static JSBool
 array_setSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, Value *vp, JSBool strict)
 {
-    return array_setGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)), vp, strict);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return array_setGeneric(cx, obj, id, vp, strict);
 }
 
 JSBool
 js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
 {
     /*
      * Walk up the prototype chain and see if this indexed element already
      * exists. If we hit the end of the prototype chain, it's safe to set the
@@ -977,17 +985,17 @@ js_PrototypeHasIndexedProperties(JSConte
 static JSBool
 array_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *value,
                     JSPropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
         return JS_TRUE;
 
     if (!obj->isDenseArray())
-        return baseops::DefineProperty(cx, obj, id, value, getter, setter, attrs);
+        return baseops::DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 
     do {
         uint32_t i = 0;       // init to shut GCC up
         bool isIndex = js_IdIsIndex(id, &i);
         if (!isIndex || attrs != JSPROP_ENUMERATE)
             break;
 
         JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, i, 1);
@@ -1003,24 +1011,25 @@ array_defineGeneric(JSContext *cx, Handl
         obj->setDenseArrayElementWithType(cx, i, *value);
         return true;
     } while (false);
 
     AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
 
     if (!JSObject::makeDenseArraySlow(cx, obj))
         return false;
-    return baseops::DefineProperty(cx, obj, id, value, getter, setter, attrs);
+    return baseops::DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
 static JSBool
 array_defineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, const Value *value,
                      JSPropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
-    return array_defineGeneric(cx, obj, RootedId(cx, NameToId(name)), value, getter, setter, attrs);
+    Rooted<jsid> id(cx, NameToId(name));
+    return array_defineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
 namespace js {
 
 /* non-static for direct definition of array elements within the engine */
 JSBool
 array_defineElement(JSContext *cx, HandleObject obj, uint32_t index, const Value *value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
@@ -1058,18 +1067,18 @@ array_defineElement(JSContext *cx, Handl
 }
 
 } // namespace js
 
 static JSBool
 array_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, const Value *value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
-    return array_defineGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)),
-                               value, getter, setter, attrs);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return array_defineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
 static JSBool
 array_getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     *attrsp = JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)
         ? JSPROP_PERMANENT : JSPROP_ENUMERATE;
     return true;
@@ -1150,17 +1159,17 @@ array_deleteElement(JSContext *cx, Handl
     if (!obj->isDenseArray())
         return baseops::DeleteElement(cx, obj, index, rval, strict);
 
     if (index < obj->getDenseArrayInitializedLength()) {
         obj->markDenseArrayNotPacked(cx);
         obj->setDenseArrayElement(index, MagicValue(JS_ARRAY_HOLE));
     }
 
-    if (!js_SuppressDeletedElement(cx, RootedObject(cx, obj), index))
+    if (!js_SuppressDeletedElement(cx, obj, index))
         return false;
 
     rval->setBoolean(true);
     return true;
 }
 
 } // namespace js
 
@@ -1699,17 +1708,18 @@ array_toLocaleString(JSContext *cx, unsi
     RootedObject obj(cx, ToObject(cx, &args.thisv()));
     if (!obj)
         return false;
 
     /*
      *  Passing comma here as the separator. Need a way to get a
      *  locale-specific version.
      */
-    return array_toString_sub(cx, obj, JS_TRUE, RootedString(cx), args);
+    Rooted<JSString*> none(cx, NULL);
+    return array_toString_sub(cx, obj, JS_TRUE, none, args);
 }
 
 static inline bool
 InitArrayTypes(JSContext *cx, TypeObject *type, const Value *vector, unsigned count)
 {
     if (cx->typeInferenceEnabled() && !type->unknownProperties()) {
         AutoEnterTypeInference enter(cx);
 
@@ -2380,17 +2390,17 @@ NewbornArrayPushImpl(JSContext *cx, Hand
 {
     JS_ASSERT(!v.isMagic());
 
     uint32_t length = obj->getArrayLength();
     if (obj->isSlowArray()) {
         /* This can happen in one evil case. See bug 630377. */
         RootedId id(cx);
         return IndexToId(cx, length, id.address()) &&
-               baseops::DefineProperty(cx, obj, id, &v, NULL, NULL, JSPROP_ENUMERATE);
+               baseops::DefineGeneric(cx, obj, id, &v, NULL, NULL, JSPROP_ENUMERATE);
     }
 
     JS_ASSERT(obj->isDenseArray());
     JS_ASSERT(length <= obj->getDenseArrayCapacity());
 
     if (!obj->ensureElements(cx, length + 1))
         return false;
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -200,17 +200,17 @@ JSCompartment::wrap(JSContext *cx, Value
     } else {
         global = JS_ObjectToInnerObject(cx, cx->globalObject);
         if (!global)
             return false;
     }
 
     /* Unwrap incoming objects. */
     if (vp->isObject()) {
-        JSObject *obj = &vp->toObject();
+        Rooted<JSObject*> obj(cx, &vp->toObject());
 
         if (obj->compartment() == this)
             return WrapForSameCompartment(cx, obj, vp);
 
         /* Translate StopIteration singleton. */
         if (obj->isStopIteration())
             return js_FindClassObject(cx, NULL, JSProto_StopIteration, vp);
 
@@ -227,17 +227,17 @@ JSCompartment::wrap(JSContext *cx, Value
         }
 
         if (obj->compartment() == this)
             return WrapForSameCompartment(cx, obj, vp);
         vp->setObject(*obj);
 
 #ifdef DEBUG
         {
-            JSObject *outer = GetOuterObject(cx, RootedObject(cx, obj));
+            JSObject *outer = GetOuterObject(cx, obj);
             JS_ASSERT(outer && outer == obj);
         }
 #endif
     }
 
     RootedValue key(cx, *vp);
 
     /* If we already have a wrapper for this value, use it. */
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -2694,18 +2694,18 @@ js_InitDateClass(JSContext *cx, JSObject
      * Date.prototype.toUTCString.
      */
     if (!JS_DefineFunctions(cx, dateProto, date_methods))
         return NULL;
     Value toUTCStringFun;
     RootedId toUTCStringId(cx, NameToId(cx->runtime->atomState.toUTCStringAtom));
     RootedId toGMTStringId(cx, NameToId(cx->runtime->atomState.toGMTStringAtom));
     if (!baseops::GetProperty(cx, dateProto, toUTCStringId, &toUTCStringFun) ||
-        !baseops::DefineProperty(cx, dateProto, toGMTStringId, &toUTCStringFun,
-                                 JS_PropertyStub, JS_StrictPropertyStub, 0))
+        !baseops::DefineGeneric(cx, dateProto, toGMTStringId, &toUTCStringFun,
+                                JS_PropertyStub, JS_StrictPropertyStub, 0))
     {
         return NULL;
     }
 
     if (!DefineConstructorAndPrototype(cx, global, JSProto_Date, ctor, dateProto))
         return NULL;
 
     return dateProto;
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -778,17 +778,18 @@ GetPropertyDesc(JSContext *cx, JSObject 
     RootedObject obj(cx, obj_);
 
     JSBool wasThrowing = cx->isExceptionPending();
     Value lastException = UndefinedValue();
     if (wasThrowing)
         lastException = cx->getPendingException();
     cx->clearPendingException();
 
-    if (!baseops::GetProperty(cx, obj, RootedId(cx, shape->propid()), &pd->value)) {
+    Rooted<jsid> id(cx, shape->propid());
+    if (!baseops::GetProperty(cx, obj, id, &pd->value)) {
         if (!cx->isExceptionPending()) {
             pd->flags = JSPD_ERROR;
             pd->value = JSVAL_VOID;
         } else {
             pd->flags = JSPD_EXCEPTION;
             pd->value = cx->getPendingException();
         }
     } else {
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -260,27 +260,30 @@ InitExnPrivate(JSContext *cx, HandleObje
     {
         SuppressErrorsGuard seg(cx);
         for (ScriptFrameIter i(cx); !i.done(); ++i) {
 
             /* Ask the crystal CAPS ball whether we can see across compartments. */
             if (checkAccess && i.isNonEvalFunctionFrame()) {
                 Value v = NullValue();
                 RootedId callerid(cx, NameToId(cx->runtime->atomState.callerAtom));
-                if (!checkAccess(cx, RootedObject(cx, i.callee()), callerid, JSACC_READ, &v))
+                Rooted<JSObject*> obj(cx, i.callee());
+                if (!checkAccess(cx, obj, callerid, JSACC_READ, &v))
                     break;
             }
 
             if (!frames.growBy(1))
                 return false;
             JSStackTraceStackElem &frame = frames.back();
-            if (i.isNonEvalFunctionFrame())
-                frame.funName = i.callee()->atom ? i.callee()->atom : cx->runtime->emptyString;
-            else
+            if (i.isNonEvalFunctionFrame()) {
+                JSAtom *atom = i.callee()->atom ? i.callee()->atom : cx->runtime->emptyString;
+                frame.funName = atom;
+            } else {
                 frame.funName = NULL;
+            }
             const char *cfilename = i.script()->filename;
             if (!cfilename)
                 cfilename = "";
             frame.filename = SaveScriptFilename(cx, cfilename);
             if (!frame.filename)
                 return false;
             frame.ulineno = PCToLineNumber(i.script(), i.pc());
         }
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -226,18 +226,18 @@ JS_DefineFunctionsWithHelp(JSContext *cx
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     for (; fs->name; fs++) {
         JSAtom *atom = js_Atomize(cx, fs->name, strlen(fs->name));
         if (!atom)
             return false;
 
         RootedFunction fun(cx);
-        fun = js_DefineFunction(cx, obj, RootedId(cx, AtomToId(atom)),
-                                fs->call, fs->nargs, fs->flags);
+        Rooted<jsid> id(cx, AtomToId(atom));
+        fun = js_DefineFunction(cx, obj, id, fs->call, fs->nargs, fs->flags);
         if (!fun)
             return false;
 
         if (fs->usage) {
             if (!DefineHelpProperty(cx, fun, "usage", fs->usage))
                 return false;
         }
 
@@ -333,19 +333,18 @@ js::DefineFunctionWithReserved(JSContext
     RootedObject obj(cx, obj_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAtom *atom = js_Atomize(cx, name, strlen(name));
     if (!atom)
         return NULL;
-    return js_DefineFunction(cx, obj, RootedId(cx, AtomToId(atom)),
-                             call, nargs, attrs,
-                             JSFunction::ExtendedFinalizeKind);
+    Rooted<jsid> id(cx, AtomToId(atom));
+    return js_DefineFunction(cx, obj, id, call, nargs, attrs, JSFunction::ExtendedFinalizeKind);
 }
 
 JS_FRIEND_API(JSFunction *)
 js::NewFunctionWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
                             JSObject *parent_, const char *name)
 {
     RootedObject parent(cx, parent_);
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -439,17 +439,18 @@ js::CloneInterpretedFunction(JSContext *
     JSFunction *clone = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, parent, NULL);
     if (!clone)
         return NULL;
     if (!clone->clearParent(cx))
         return NULL;
     if (!clone->clearType(cx))
         return NULL;
 
-    JSScript *clonedScript = CloneScript(cx, RootedScript(cx, srcFun->script()));
+    Rooted<JSScript*> srcScript(cx, srcFun->script());
+    JSScript *clonedScript = CloneScript(cx, srcScript);
     if (!clonedScript)
         return NULL;
 
     clone->nargs = srcFun->nargs;
     clone->flags = srcFun->flags;
     clone->atom.init(srcFun->atom);
     clone->initScript(clonedScript);
     if (!clonedScript->typeSetFunction(cx, clone))
@@ -1047,17 +1048,17 @@ Function(JSContext *cx, unsigned argc, V
     /* Block this call if security callbacks forbid it. */
     Rooted<GlobalObject*> global(cx);
     global = &args.callee().global();
     if (!global->isRuntimeCodeGenEnabled(cx)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
         return false;
     }
 
-    Bindings bindings(cx);
+    Bindings bindings;
     Bindings::AutoRooter bindingsRoot(cx, &bindings);
 
     bool hasRest = false;
 
     const char *filename;
     unsigned lineno;
     JSPrincipals *originPrincipals;
     CurrentScriptFileLineOrigin(cx, &filename, &lineno, &originPrincipals);
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -201,17 +201,18 @@ CloneFunctionObjectIfNotSingleton(JSCont
     /*
      * For attempts to clone functions at a function definition opcode,
      * don't perform the clone if the function has singleton type. This
      * was called pessimistically, and we need to preserve the type's
      * property that if it is singleton there is only a single object
      * with its type in existence.
      */
     if (fun->hasSingletonType()) {
-        if (!JSObject::setParent(cx, fun, RootedObject(cx, SkipScopeParent(parent))))
+        Rooted<JSObject*> obj(cx, SkipScopeParent(parent));
+        if (!JSObject::setParent(cx, fun, obj))
             return NULL;
         fun->setEnvironment(parent);
         return fun;
     }
 
     return CloneFunctionObject(cx, fun, parent);
 }
 
@@ -225,20 +226,19 @@ CloneFunctionObject(JSContext *cx, Handl
      * objects so that fun->global() != fun->getProto()->global().
      * See ReparentWrapperIfFound.
      */
     JS_ASSERT(fun->getParent() && fun->getProto());
 
     if (fun->hasSingletonType())
         return fun;
 
-    return js_CloneFunctionObject(cx, fun,
-                                  RootedObject(cx, fun->environment()),
-                                  RootedObject(cx, fun->getProto()),
-                                  JSFunction::ExtendedFinalizeKind);
+    Rooted<JSObject*> env(cx, fun->environment());
+    Rooted<JSObject*> proto(cx, fun->getProto());
+    return js_CloneFunctionObject(cx, fun, env, proto, JSFunction::ExtendedFinalizeKind);
 }
 
 } /* namespace js */
 
 inline void
 JSFunction::setScript(JSScript *script_)
 {
     JS_ASSERT(isInterpreted());
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2546,17 +2546,18 @@ MaybeGC(JSContext *cx)
     if (rt->gcIsNeeded) {
         GCSlice(rt, GC_NORMAL, gcreason::MAYBEGC);
         return;
     }
 
     JSCompartment *comp = cx->compartment;
     if (comp->gcBytes > 8192 &&
         comp->gcBytes >= 3 * (comp->gcTriggerBytes / 4) &&
-        rt->gcIncrementalState == NO_INCREMENTAL)
+        rt->gcIncrementalState == NO_INCREMENTAL &&
+        !rt->gcHelperThread.sweeping())
     {
         PrepareCompartmentForGC(comp);
         GCSlice(rt, GC_NORMAL, gcreason::MAYBEGC);
         return;
     }
 
     if (comp->gcMallocAndFreeBytes > comp->gcTriggerMallocAndFreeBytes) {
         PrepareCompartmentForGC(comp);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1679,18 +1679,18 @@ TypeSet::isOwnProperty(JSContext *cx, Ty
     /*
      * Everywhere compiled code depends on definite properties associated with
      * a type object's newScript, we need to make sure there are constraints
      * in place which will mark those properties as configured should the
      * definite properties be invalidated.
      */
     if (object->flags & OBJECT_FLAG_NEW_SCRIPT_REGENERATE) {
         if (object->newScript) {
-            CheckNewScriptProperties(cx, RootedTypeObject(cx, object),
-                                     object->newScript->fun);
+            Rooted<TypeObject*> typeObj(cx, object);
+            CheckNewScriptProperties(cx, typeObj, object->newScript->fun);
         } else {
             JS_ASSERT(object->flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED);
             object->flags &= ~OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
         }
     }
 
     if (isOwnProperty(configurable))
         return true;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -551,17 +551,18 @@ js::LooselyEqual(JSContext *cx, const Va
         }
 
         if (lval.isObject()) {
             JSObject *l = &lval.toObject();
             JSObject *r = &rval.toObject();
 
             if (JSEqualityOp eq = l->getClass()->ext.equality) {
                 JSBool res;
-                if (!eq(cx, RootedObject(cx, l), &rval, &res))
+                Rooted<JSObject*> lobj(cx, l);
+                if (!eq(cx, lobj, &rval, &res))
                     return false;
                 *result = !!res;
                 return true;
             }
 
             *result = l == r;
             return true;
         }
@@ -997,17 +998,18 @@ IteratorMore(JSContext *cx, JSObject *it
 {
     if (iterobj->isIterator()) {
         NativeIterator *ni = iterobj->getNativeIterator();
         if (ni->isKeyIter()) {
             *cond = (ni->props_cursor < ni->props_end);
             return true;
         }
     }
-    if (!js_IteratorMore(cx, RootedObject(cx, iterobj), rval))
+    Rooted<JSObject*> iobj(cx, iterobj);
+    if (!js_IteratorMore(cx, iobj, rval))
         return false;
     *cond = rval->isTrue();
     return true;
 }
 
 static inline bool
 IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
 {
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -120,17 +120,18 @@ ValuePropertyBearer(JSContext *cx, Stack
         return global.getOrCreateBooleanPrototype(cx);
 
     JS_ASSERT(v.isNull() || v.isUndefined());
     js_ReportIsNullOrUndefined(cx, spindex, v, NULL);
     return NULL;
 }
 
 inline bool
-NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, unsigned getHow, Value *vp)
+NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, const Shape *shape,
+          unsigned getHow, Value *vp)
 {
     if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
         /* Fast path for Object instance properties. */
         JS_ASSERT(shape->hasSlot());
         *vp = pobj->nativeGetSlot(shape->slot());
     } else {
         if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp))
             return false;
@@ -206,19 +207,19 @@ GetPropertyOperation(JSContext *cx, jsby
         }
     }
 
     RootedObject obj(cx, ValueToObject(cx, lval));
     if (!obj)
         return false;
 
     PropertyCacheEntry *entry;
-    JSObject *obj2;
+    Rooted<JSObject*> obj2(cx);
     PropertyName *name;
-    JS_PROPERTY_CACHE(cx).test(cx, pc, obj.reference(), obj2, entry, name);
+    JS_PROPERTY_CACHE(cx).test(cx, pc, obj.reference(), obj2.reference(), entry, name);
     if (!name) {
         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
         if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp))
             return false;
         return true;
     }
 
     RootedId id(cx, NameToId(name));
@@ -330,21 +331,22 @@ FetchName(JSContext *cx, HandleObject ob
         JSAutoByteString printable;
         if (js_AtomToPrintableString(cx, name, &printable))
             js_ReportIsNotDefined(cx, printable.ptr());
         return false;
     }
 
     /* Take the slow path if prop was not found in a native object. */
     if (!obj->isNative() || !obj2->isNative()) {
-        if (!obj->getGeneric(cx, RootedId(cx, NameToId(name)), vp))
+        Rooted<jsid> id(cx, NameToId(name));
+        if (!obj->getGeneric(cx, id, vp))
             return false;
     } else {
         Shape *shape = (Shape *)prop;
-        JSObject *normalized = obj;
+        Rooted<JSObject*> normalized(cx, obj);
         if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
             normalized = &normalized->asWith().object();
         if (!NativeGet(cx, normalized, obj2, shape, 0, vp))
             return false;
     }
     return true;
 }
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -79,29 +79,31 @@ Class js::ObjectClass = {
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub
 };
 
 JS_FRIEND_API(JSObject *)
-JS_ObjectToInnerObject(JSContext *cx, JSObject *obj)
-{
-    if (!obj) {
+JS_ObjectToInnerObject(JSContext *cx, JSObject *obj_)
+{
+    if (!obj_) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
         return NULL;
     }
-    return GetInnerObject(cx, RootedObject(cx, obj));
+    Rooted<JSObject*> obj(cx, obj_);
+    return GetInnerObject(cx, obj);
 }
 
 JS_FRIEND_API(JSObject *)
-JS_ObjectToOuterObject(JSContext *cx, JSObject *obj)
-{
-    return GetOuterObject(cx, RootedObject(cx, obj));
+JS_ObjectToOuterObject(JSContext *cx, JSObject *obj_)
+{
+    Rooted<JSObject*> obj(cx, obj_);
+    return GetOuterObject(cx, obj);
 }
 
 #if JS_HAS_OBJ_PROTO_PROP
 
 static JSBool
 obj_getProto(JSContext *cx, HandleObject obj, HandleId id, Value *vp);
 
 static JSBool
@@ -196,31 +198,33 @@ MarkSharpObjects(JSContext *cx, HandleOb
                 if (hasSetter)
                     setter = shape->setterValue();
             } else {
                 hasGetter = hasSetter = false;
             }
             if (hasSetter) {
                 /* Mark the getter, then set val to setter. */
                 if (hasGetter && value.isObject()) {
-                    ok = MarkSharpObjects(cx, RootedObject(cx, &value.toObject()), NULL, NULL);
+                    Rooted<JSObject*> vobj(cx, &value.toObject());
+                    ok = MarkSharpObjects(cx, vobj, NULL, NULL);
                     if (!ok)
                         break;
                 }
                 value = setter;
             } else if (!hasGetter) {
                 ok = obj->getGeneric(cx, id, &value);
                 if (!ok)
                     break;
             }
-            if (value.isObject() &&
-                !MarkSharpObjects(cx, RootedObject(cx, &value.toObject()), NULL, NULL))
-            {
-                ok = false;
-                break;
+            if (value.isObject()) {
+                Rooted<JSObject*> vobj(cx, &value.toObject());
+                if (!MarkSharpObjects(cx, vobj, NULL, NULL)) {
+                    ok = false;
+                    break;
+                }
             }
         }
         if (!ok || !idap)
             JS_DestroyIdArray(cx, ida);
         if (!ok)
             return false;
     } else {
         if (!p->value.hasGen && !p->value.isSharp) {
@@ -697,18 +701,20 @@ obj_valueOf(JSContext *cx, unsigned argc
 }
 
 /* We should be able to assert this for *any* fp->scopeChain(). */
 static void
 AssertInnerizedScopeChain(JSContext *cx, JSObject &scopeobj)
 {
 #ifdef DEBUG
     for (JSObject *o = &scopeobj; o; o = o->enclosingScope()) {
-        if (JSObjectOp op = o->getClass()->ext.innerObject)
-            JS_ASSERT(op(cx, RootedObject(cx, o)) == o);
+        if (JSObjectOp op = o->getClass()->ext.innerObject) {
+            Rooted<JSObject*> obj(cx, o);
+            JS_ASSERT(op(cx, obj) == o);
+        }
     }
 #endif
 }
 
 #ifndef EVAL_CACHE_CHAIN_LIMIT
 # define EVAL_CACHE_CHAIN_LIMIT 4
 #endif
 
@@ -1079,19 +1085,21 @@ namespace js {
  * ES5 15.1.2.1.
  *
  * NB: This method handles only indirect eval.
  */
 JSBool
 eval(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    return WarnOnTooManyArgs(cx, args) &&
-           EvalKernel(cx, args, INDIRECT_EVAL, NULL,
-                      RootedObject(cx, &args.callee().global()));
+    if (!WarnOnTooManyArgs(cx, args))
+        return false;
+
+    Rooted<GlobalObject*> global(cx, &args.callee().global());
+    return EvalKernel(cx, args, INDIRECT_EVAL, NULL, global);
 }
 
 bool
 DirectEval(JSContext *cx, const CallArgs &args)
 {
     /* Direct eval can assume it was called from an interpreted frame. */
     StackFrame *caller = cx->fp();
     JS_ASSERT(caller->isScriptFrame());
@@ -1281,17 +1289,18 @@ js_HasOwnProperty(JSContext *cx, LookupG
     if (!*propp)
         return true;
 
     if (*objp == obj)
         return true;
 
     JSObject *outer = NULL;
     if (JSObjectOp op = (*objp)->getClass()->ext.outerObject) {
-        outer = op(cx, RootedObject(cx, *objp));
+        Rooted<JSObject*> inner(cx, *objp);
+        outer = op(cx, inner);
         if (!outer)
             return false;
     }
 
     if (outer != *objp)
         *propp = NULL;
     return true;
 }
@@ -1965,35 +1974,35 @@ DefinePropertyOnObject(JSContext *cx, Ha
         if (!obj->isExtensible())
             return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
 
         *rval = true;
 
         if (desc.isGenericDescriptor() || desc.isDataDescriptor()) {
             JS_ASSERT(!obj->getOps()->defineProperty);
             Value v = desc.hasValue() ? desc.value() : UndefinedValue();
-            return baseops::DefineProperty(cx, obj, id, &v,
-                                           JS_PropertyStub, JS_StrictPropertyStub,
-                                           desc.attributes());
+            return baseops::DefineGeneric(cx, obj, id, &v,
+                                          JS_PropertyStub, JS_StrictPropertyStub,
+                                          desc.attributes());
         }
 
         JS_ASSERT(desc.isAccessorDescriptor());
 
         /*
          * Getters and setters are just like watchpoints from an access
          * control point of view.
          */
         Value dummy;
         unsigned dummyAttrs;
         if (!CheckAccess(cx, obj, id, JSACC_WATCH, &dummy, &dummyAttrs))
             return JS_FALSE;
 
         Value tmp = UndefinedValue();
-        return baseops::DefineProperty(cx, obj, id, &tmp,
-                                       desc.getter(), desc.setter(), desc.attributes());
+        return baseops::DefineGeneric(cx, obj, id, &tmp,
+                                      desc.getter(), desc.setter(), desc.attributes());
     }
 
     /* 8.12.9 steps 5-6 (note 5 is merely a special case of 6). */
     Value v = UndefinedValue();
 
     JS_ASSERT(obj == obj2);
 
     Rooted<const Shape *> shape(cx, reinterpret_cast<Shape *>(current));
@@ -2233,17 +2242,17 @@ DefinePropertyOnObject(JSContext *cx, Ha
      * redefining it or we had invoked its setter to change its value).
      */
     if (callDelProperty) {
         Value dummy = UndefinedValue();
         if (!CallJSPropertyOp(cx, obj2->getClass()->delProperty, obj2, id, &dummy))
             return false;
     }
 
-    return baseops::DefineProperty(cx, obj, id, &v, getter, setter, attrs);
+    return baseops::DefineGeneric(cx, obj, id, &v, getter, setter, attrs);
 }
 
 static JSBool
 DefinePropertyOnArray(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &desc,
                       bool throwError, bool *rval)
 {
     /*
      * We probably should optimize dense array property definitions where
@@ -2377,17 +2386,17 @@ DefineProperties(JSContext *cx, HandleOb
 {
     AutoIdVector ids(cx);
     AutoPropDescArrayRooter descs(cx);
     if (!ReadPropertyDescriptors(cx, props, true, &ids, &descs))
         return false;
 
     bool dummy;
     for (size_t i = 0, len = ids.length(); i < len; i++) {
-        if (!DefineProperty(cx, obj, RootedId(cx, ids[i]), descs[i], true, &dummy))
+        if (!DefineProperty(cx, obj, Handle<jsid>::fromMarkedLocation(&ids[i]), descs[i], true, &dummy))
             return false;
     }
 
     return true;
 }
 
 extern JSBool
 js_PopulateObject(JSContext *cx, HandleObject newborn, JSObject *props)
@@ -3168,30 +3177,31 @@ JSObject::nonNativeSetElement(JSContext 
 bool
 JSObject::deleteByValue(JSContext *cx, const Value &property, Value *rval, bool strict)
 {
     uint32_t index;
     if (IsDefinitelyIndex(property, &index))
         return deleteElement(cx, index, rval, strict);
 
     Value propval = property;
-    SpecialId sid;
-    if (ValueIsSpecial(this, &propval, &sid, cx))
-        return deleteSpecial(cx, Rooted<SpecialId>(cx, sid), rval, strict);
+    Rooted<SpecialId> sid(cx);
+    if (ValueIsSpecial(this, &propval, sid.address(), cx))
+        return deleteSpecial(cx, sid, rval, strict);
 
     RootedObject self(cx, this);
 
     JSAtom *name = ToAtom(cx, propval);
     if (!name)
         return false;
 
     if (name->isIndex(&index))
         return self->deleteElement(cx, index, rval, false);
 
-    return self->deleteProperty(cx, RootedPropertyName(cx, name->asPropertyName()), rval, false);
+    Rooted<PropertyName*> propname(cx, name->asPropertyName());
+    return self->deleteProperty(cx, propname, rval, false);
 }
 
 JS_FRIEND_API(bool)
 JS_CopyPropertiesFrom(JSContext *cx, JSObject *target, JSObject *obj)
 {
     // If we're not native, then we cannot copy properties.
     JS_ASSERT(target->isNative() == obj->isNative());
     if (!target->isNative())
@@ -3212,17 +3222,18 @@ JS_CopyPropertiesFrom(JSContext *cx, JSO
         AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
         if ((attrs & JSPROP_GETTER) && !cx->compartment->wrap(cx, &getter))
             return false;
         if ((attrs & JSPROP_SETTER) && !cx->compartment->wrap(cx, &setter))
             return false;
         Value v = shape->hasSlot() ? obj->getSlot(shape->slot()) : UndefinedValue();
         if (!cx->compartment->wrap(cx, &v))
             return false;
-        if (!target->defineGeneric(cx, RootedId(cx, shape->propid()), v, getter, setter, attrs))
+        Rooted<jsid> id(cx, shape->propid());
+        if (!target->defineGeneric(cx, id, v, getter, setter, attrs))
             return false;
     }
     return true;
 }
 
 static bool
 CopySlots(JSContext *cx, JSObject *from, JSObject *to)
 {
@@ -3951,25 +3962,26 @@ JSObject::growSlots(JSContext *cx, uint3
      * by calling 'new' on a particular script, bump the GC kind for that
      * type to give these objects a larger number of fixed slots when future
      * objects are constructed.
      */
     if (!hasLazyType() && !oldCount && type()->newScript) {
         gc::AllocKind kind = type()->newScript->allocKind;
         unsigned newScriptSlots = gc::GetGCKindSlots(kind);
         if (newScriptSlots == numFixedSlots() && gc::TryIncrementAllocKind(&kind)) {
-            JSObject *obj = NewReshapedObject(cx, RootedTypeObject(cx, type()),
+            Rooted<TypeObject*> typeObj(cx, type());
+            JSObject *obj = NewReshapedObject(cx, typeObj,
                                               getParent(), kind,
-                                              type()->newScript->shape);
+                                              typeObj->newScript->shape);
             if (!obj)
                 return false;
 
-            type()->newScript->allocKind = kind;
-            type()->newScript->shape = obj->lastProperty();
-            type()->markStateChange(cx);
+            typeObj->newScript->allocKind = kind;
+            typeObj->newScript->shape = obj->lastProperty();
+            typeObj->markStateChange(cx);
         }
     }
 
     if (!oldCount) {
         slots = (HeapSlot *) cx->malloc_(newCount * sizeof(HeapSlot));
         if (!slots)
             return false;
         Debug_SetSlotRangeToCrashOnTouch(slots, newCount);
@@ -4471,34 +4483,34 @@ js_AddNativeProperty(JSContext *cx, Hand
      */
     if (!js_PurgeScopeChain(cx, obj, id))
         return NULL;
 
     return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid);
 }
 
 JSBool
-baseops::DefineProperty(JSContext *cx, HandleObject obj, HandleId id, const Value *value,
+baseops::DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *value,
                         PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0);
 }
 
 JSBool
 baseops::DefineElement(JSContext *cx, HandleObject obj, uint32_t index, const Value *value,
                        PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
+    Rooted<jsid> id(cx);
     if (index <= JSID_INT_MAX) {
-        return !!DefineNativeProperty(cx, obj, RootedId(cx, INT_TO_JSID(index)), *value,
-                                      getter, setter, attrs, 0, 0);
+        id = INT_TO_JSID(index);
+        return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0);
     }
 
     AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
 
-    RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
 
     return !!DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0);
 }
 
 /*
  * Backward compatibility requires allowing addProperty hooks to mutate the
@@ -4507,17 +4519,18 @@ baseops::DefineElement(JSContext *cx, Ha
  * both while saving cycles for classes that stub their addProperty hook.
  */
 static inline bool
 CallAddPropertyHook(JSContext *cx, Class *clasp, HandleObject obj, HandleShape shape, Value *vp)
 {
     if (clasp->addProperty != JS_PropertyStub) {
         Value nominal = *vp;
 
-        if (!CallJSPropertyOp(cx, clasp->addProperty, obj, RootedId(cx, shape->propid()), vp))
+        Rooted<jsid> id(cx, shape->propid());
+        if (!CallJSPropertyOp(cx, clasp->addProperty, obj, id, vp))
             return false;
         if (*vp != nominal) {
             if (shape->hasSlot())
                 obj->nativeSetSlotWithType(cx, shape, *vp);
         }
     }
     return true;
 }
@@ -4625,35 +4638,35 @@ DefineNativeProperty(JSContext *cx, Hand
     return shape;
 }
 
 } /* namespace js */
 
 /*
  * Call obj's resolve hook.
  *
- * cx, start, id, and flags are the parameters initially passed to the ongoing
- * lookup; objp and propp are its out parameters. obj is an object along
- * start's prototype chain.
+ * cx, id, and flags are the parameters initially passed to the ongoing lookup;
+ * objp and propp are its out parameters. obj is an object along the prototype
+ * chain from where the lookup started.
  *
  * There are four possible outcomes:
  *
  *   - On failure, report an error or exception and return false.
  *
  *   - If we are already resolving a property of *curobjp, set *recursedp = true,
  *     and return true.
  *
  *   - If the resolve hook finds or defines the sought property, set *objp and
  *     *propp appropriately, set *recursedp = false, and return true.
  *
  *   - Otherwise no property was resolved. Set *propp = NULL and *recursedp = false
  *     and return true.
  */
 static JSBool
-CallResolveOp(JSContext *cx, JSObject *start, HandleObject obj, HandleId id, unsigned flags,
+CallResolveOp(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
               JSObject **objp, JSProperty **propp, bool *recursedp)
 {
     Class *clasp = obj->getClass();
     JSResolveOp resolve = clasp->resolve;
 
     /*
      * Avoid recursion on (obj, id) already being resolved on cx.
      *
@@ -4672,18 +4685,17 @@ CallResolveOp(JSContext *cx, JSObject *s
 
     *propp = NULL;
 
     if (clasp->flags & JSCLASS_NEW_RESOLVE) {
         JSNewResolveOp newresolve = reinterpret_cast<JSNewResolveOp>(resolve);
         if (flags == RESOLVE_INFER)
             flags = js_InferFlags(cx, 0);
 
-        RootedObject obj2(cx);
-        obj2 = (clasp->flags & JSCLASS_NEW_RESOLVE_GETS_START) ? start : NULL;
+        RootedObject obj2(cx, NULL);
         if (!newresolve(cx, obj, id, flags, obj2.address()))
             return false;
 
         /*
          * We trust the new style resolve hook to set obj2 to NULL when
          * the id cannot be resolved. But, when obj2 is not null, we do
          * not assume that id must exist and do full nativeLookup for
          * compatibility.
@@ -4724,17 +4736,17 @@ LookupPropertyWithFlagsInline(JSContext 
             *objp = current;
             *propp = (JSProperty *) shape;
             return true;
         }
 
         /* Try obj's class resolve hook if id was not found in obj's scope. */
         if (current->getClass()->resolve != JS_ResolveStub) {
             bool recursed;
-            if (!CallResolveOp(cx, obj, current, id, flags, objp, propp, &recursed))
+            if (!CallResolveOp(cx, current, id, flags, objp, propp, &recursed))
                 return false;
             if (recursed)
                 break;
             if (*propp) {
                 /*
                  * For stats we do not recalculate protoIndex even if it was
                  * resolved on some other object.
                  */
@@ -4960,17 +4972,17 @@ js::FindIdentifierBase(JSContext *cx, Ha
         if (!parent)
             break;
         obj = parent;
     } while (!obj->isGlobal());
     return obj;
 }
 
 static JS_ALWAYS_INLINE JSBool
-js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *pobj,
+js_NativeGetInline(JSContext *cx, Handle<JSObject*> receiver, JSObject *obj, JSObject *pobj,
                    const Shape *shape, unsigned getHow, Value *vp)
 {
     JS_ASSERT(pobj->isNative());
 
     if (shape->hasSlot()) {
         *vp = pobj->nativeGetSlot(shape->slot());
         JS_ASSERT(!vp->isMagic());
         JS_ASSERT_IF(!pobj->hasSingletonType() && shape->hasDefaultGetter(),
@@ -4987,35 +4999,36 @@ js_NativeGetInline(JSContext *cx, JSObje
         analyze::Bytecode *code = script->analysis()->maybeCode(pc);
         if (code)
             code->accessGetter = true;
     }
 
     Rooted<const Shape*> shapeRoot(cx, shape);
     RootedObject pobjRoot(cx, pobj);
 
-    if (!shape->get(cx, RootedObject(cx, receiver), obj, pobj, vp))
+    if (!shape->get(cx, receiver, obj, pobj, vp))
         return false;
 
     /* Update slotful shapes according to the value produced by the getter. */
     if (shapeRoot->hasSlot() && pobjRoot->nativeContains(cx, *shapeRoot))
         pobjRoot->nativeSetSlot(shapeRoot->slot(), *vp);
 
     return true;
 }
 
 JSBool
-js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, unsigned getHow,
-             Value *vp)
+js_NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, const Shape *shape,
+             unsigned getHow, Value *vp)
 {
     return js_NativeGetInline(cx, obj, obj, pobj, shape, getHow, vp);
 }
 
 JSBool
-js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, bool strict, Value *vp)
+js_NativeSet(JSContext *cx, Handle<JSObject*> obj, const Shape *shape, bool added, bool strict,
+             Value *vp)
 {
     AddTypePropertyId(cx, obj, shape->propid(), *vp);
 
     JS_ASSERT(obj->isNative());
 
     if (shape->hasSlot()) {
         uint32_t slot = shape->slot();
 
@@ -5033,17 +5046,17 @@ js_NativeSet(JSContext *cx, JSObject *ob
          */
         if (!shape->hasGetterValue() && shape->hasDefaultSetter())
             return js_ReportGetterOnlyAssignment(cx);
     }
 
     Rooted<const Shape *> shapeRoot(cx, shape);
 
     int32_t sample = cx->runtime->propertyRemovals;
-    if (!shapeRoot->set(cx, RootedObject(cx, obj), strict, vp))
+    if (!shapeRoot->set(cx, obj, strict, vp))
         return false;
 
     /*
      * Update any slot for the shape with the value produced by the setter,
      * unless the setter deleted the shape.
      */
     if (shapeRoot->hasSlot() &&
         (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
@@ -5251,18 +5264,19 @@ JSObject::reportNotExtensible(JSContext 
                                     JSDVG_IGNORE_STACK, ObjectValue(*this),
                                     NULL, NULL, NULL);
 }
 
 bool
 JSObject::callMethod(JSContext *cx, HandleId id, unsigned argc, Value *argv, Value *vp)
 {
     Value fval;
-    return GetMethod(cx, RootedObject(cx, this), id, 0, &fval) &&
-           Invoke(cx, ObjectValue(*this), fval, argc, argv, vp);
+    Rooted<JSObject*> obj(cx, this);
+    return GetMethod(cx, obj, id, 0, &fval) &&
+           Invoke(cx, ObjectValue(*obj), fval, argc, argv, vp);
 }
 
 JSBool
 baseops::SetPropertyHelper(JSContext *cx, HandleObject obj, HandleId id, unsigned defineHow,
                            Value *vp, JSBool strict)
 {
     JSObject *pobj;
     JSProperty *prop;
@@ -5563,32 +5577,34 @@ baseops::DeleteGeneric(JSContext *cx, Ha
         return true;
 
     return obj->removeProperty(cx, id) && js_SuppressDeletedProperty(cx, obj, id);
 }
 
 JSBool
 baseops::DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, Value *rval, JSBool strict)
 {
-    return baseops::DeleteGeneric(cx, obj, RootedId(cx, NameToId(name)), rval, strict);
+    Rooted<jsid> id(cx, NameToId(name));
+    return baseops::DeleteGeneric(cx, obj, id, rval, strict);
 }
 
 JSBool
 baseops::DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, Value *rval, JSBool strict)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return baseops::DeleteGeneric(cx, obj, id, rval, strict);
 }
 
 JSBool
 baseops::DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, Value *rval, JSBool strict)
 {
-    return baseops::DeleteGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)), rval, strict);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return baseops::DeleteGeneric(cx, obj, id, rval, strict);
 }
 
 namespace js {
 
 bool
 HasDataProperty(JSContext *cx, HandleObject obj, jsid id, Value *vp)
 {
     if (const Shape *shape = obj->nativeLookup(cx, id)) {
@@ -5605,78 +5621,87 @@ HasDataProperty(JSContext *cx, HandleObj
  * Gets |obj[id]|.  If that value's not callable, returns true and stores a
  * non-primitive value in *vp.  If it's callable, calls it with no arguments
  * and |obj| as |this|, returning the result in *vp.
  *
  * This is a mini-abstraction for ES5 8.12.8 [[DefaultValue]], either steps 1-2
  * or steps 3-4.
  */
 static bool
-MaybeCallMethod(JSContext *cx, HandleObject obj, jsid id, Value *vp)
-{
-    if (!GetMethod(cx, obj, RootedId(cx, id), 0, vp))
+MaybeCallMethod(JSContext *cx, HandleObject obj, Handle<jsid> id, Value *vp)
+{
+    if (!GetMethod(cx, obj, id, 0, vp))
         return false;
     if (!js_IsCallable(*vp)) {
         *vp = ObjectValue(*obj);
         return true;
     }
     return Invoke(cx, ObjectValue(*obj), *vp, 0, NULL, vp);
 }
 
 JSBool
 DefaultValue(JSContext *cx, HandleObject obj, JSType hint, Value *vp)
 {
     JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
 #if JS_HAS_XML_SUPPORT
     JS_ASSERT(!obj->isXML());
 #endif
 
+    Rooted<jsid> id(cx);
+
     Class *clasp = obj->getClass();
     if (hint == JSTYPE_STRING) {
+        id = NameToId(cx->runtime->atomState.toStringAtom);
+
         /* Optimize (new String(...)).toString(). */
-        if (clasp == &StringClass &&
-            ClassMethodIsNative(cx, obj,
-                                 &StringClass,
-                                 RootedId(cx, NameToId(cx->runtime->atomState.toStringAtom)),
-                                 js_str_toString)) {
-            *vp = StringValue(obj->asString().unbox());
-            return true;
+        if (clasp == &StringClass) {
+            if (ClassMethodIsNative(cx, obj, &StringClass, id, js_str_toString)) {
+                *vp = StringValue(obj->asString().unbox());
+                return true;
+            }
         }
 
-        if (!MaybeCallMethod(cx, obj, NameToId(cx->runtime->atomState.toStringAtom), vp))
+        if (!MaybeCallMethod(cx, obj, id, vp))
             return false;
         if (vp->isPrimitive())
             return true;
 
-        if (!MaybeCallMethod(cx, obj, NameToId(cx->runtime->atomState.valueOfAtom), vp))
+        id = NameToId(cx->runtime->atomState.valueOfAtom);
+        if (!MaybeCallMethod(cx, obj, id, vp))
             return false;
         if (vp->isPrimitive())
             return true;
     } else {
-        /* Optimize (new String(...)).valueOf(). */
-        if ((clasp == &StringClass &&
-             ClassMethodIsNative(cx, obj, &StringClass,
-                                 RootedId(cx, NameToId(cx->runtime->atomState.valueOfAtom)),
-                                 js_str_toString)) ||
-            (clasp == &NumberClass &&
-             ClassMethodIsNative(cx, obj, &NumberClass,
-                                 RootedId(cx, NameToId(cx->runtime->atomState.valueOfAtom)),
-                                 js_num_valueOf))) {
-            *vp = obj->isString()
-                  ? StringValue(obj->asString().unbox())
-                  : NumberValue(obj->asNumber().unbox());
-            return true;
+
+        /* Optimize new String(...).valueOf(). */
+        if (clasp == &StringClass) {
+            id = NameToId(cx->runtime->atomState.valueOfAtom);
+            if (ClassMethodIsNative(cx, obj, &StringClass, id, js_str_toString)) {
+                *vp = StringValue(obj->asString().unbox());
+                return true;
+            }
         }
 
-        if (!MaybeCallMethod(cx, obj, NameToId(cx->runtime->atomState.valueOfAtom), vp))
+        /* Optimize new Number(...).valueOf(). */
+        if (clasp == &NumberClass) {
+            id = NameToId(cx->runtime->atomState.valueOfAtom);
+            if (ClassMethodIsNative(cx, obj, &NumberClass, id, js_num_valueOf)) {
+                *vp = NumberValue(obj->asNumber().unbox());
+                return true;
+            }
+        }
+
+        id = NameToId(cx->runtime->atomState.valueOfAtom);
+        if (!MaybeCallMethod(cx, obj, id, vp))
             return false;
         if (vp->isPrimitive())
             return true;
 
-        if (!MaybeCallMethod(cx, obj, NameToId(cx->runtime->atomState.toStringAtom), vp))
+        id = NameToId(cx->runtime->atomState.toStringAtom);
+        if (!MaybeCallMethod(cx, obj, id, vp))
             return false;
         if (vp->isPrimitive())
             return true;
     }
 
     /* Avoid recursive death when decompiling in js_ReportValueError. */
     JSString *str;
     if (hint == JSTYPE_STRING) {
@@ -5863,18 +5888,20 @@ js_GetClassPrototype(JSContext *cx, JSOb
     }
 
     return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp);
 }
 
 JSObject *
 PrimitiveToObject(JSContext *cx, const Value &v)
 {
-    if (v.isString())
-        return StringObject::create(cx, RootedString(cx, v.toString()));
+    if (v.isString()) {
+        Rooted<JSString*> str(cx, v.toString());
+        return StringObject::create(cx, str);
+    }
     if (v.isNumber())
         return NumberObject::create(cx, v.toNumber());
 
     JS_ASSERT(v.isBoolean());
     return BooleanObject::create(cx, v.toBoolean());
 }
 
 JSBool
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -100,27 +100,36 @@ namespace baseops {
 extern JS_FRIEND_API(JSBool)
 LookupProperty(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp,
                JSProperty **propp);
 
 inline bool
 LookupProperty(JSContext *cx, HandleObject obj, PropertyName *name,
                JSObject **objp, JSProperty **propp)
 {
-    return LookupProperty(cx, obj, RootedId(cx, NameToId(name)), objp, propp);
+    Rooted<jsid> id(cx, NameToId(name));
+    return LookupProperty(cx, obj, id, objp, propp);
 }
 
 extern JS_FRIEND_API(JSBool)
 LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
               JSObject **objp, JSProperty **propp);
 
 extern JSBool
-DefineProperty(JSContext *cx, HandleObject obj, HandleId id, const js::Value *value,
+DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, const js::Value *value,
                JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
 
+inline JSBool
+DefineProperty(JSContext *cx, HandleObject obj, PropertyName *name, const js::Value *value,
+               JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
+{
+    Rooted<jsid> id(cx, NameToId(name));
+    return DefineGeneric(cx, obj, id, value, getter, setter, attrs);
+}
+
 extern JSBool
 DefineElement(JSContext *cx, HandleObject obj, uint32_t index, const js::Value *value,
               JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
 
 extern JSBool
 GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, js::Value *vp);
 
 extern JSBool
@@ -144,17 +153,18 @@ GetPropertyDefault(JSContext *cx, Handle
 extern JSBool
 SetPropertyHelper(JSContext *cx, HandleObject obj, HandleId id, unsigned defineHow,
                   Value *vp, JSBool strict);
 
 inline bool
 SetPropertyHelper(JSContext *cx, HandleObject obj, PropertyName *name, unsigned defineHow,
                   Value *vp, JSBool strict)
 {
-    return SetPropertyHelper(cx, obj, RootedId(cx, NameToId(name)), defineHow, vp, strict);
+    Rooted<jsid> id(cx, NameToId(name));
+    return SetPropertyHelper(cx, obj, id, defineHow, vp, strict);
 }
 
 extern JSBool
 SetElementHelper(JSContext *cx, HandleObject obj, uint32_t index, unsigned defineHow,
                  Value *vp, JSBool strict);
 
 extern JSType
 TypeOf(JSContext *cx, HandleObject obj);
@@ -1138,33 +1148,34 @@ DefineNativeProperty(JSContext *cx, Hand
                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                      unsigned flags, int shortid, unsigned defineHow = 0);
 
 inline const Shape *
 DefineNativeProperty(JSContext *cx, HandleObject obj, PropertyName *name, const Value &value,
                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                      unsigned flags, int shortid, unsigned defineHow = 0)
 {
-    return DefineNativeProperty(cx, obj, RootedId(cx, NameToId(name)),
-                                value, getter, setter, attrs, flags,
+    Rooted<jsid> id(cx, NameToId(name));
+    return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, flags,
                                 shortid, defineHow);
 }
 
 /*
  * Specialized subroutine that allows caller to preset JSRESOLVE_* flags.
  */
 extern bool
 LookupPropertyWithFlags(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
                         JSObject **objp, JSProperty **propp);
 
 inline bool
 LookupPropertyWithFlags(JSContext *cx, HandleObject obj, PropertyName *name, unsigned flags,
                         JSObject **objp, JSProperty **propp)
 {
-    return LookupPropertyWithFlags(cx, obj, RootedId(cx, NameToId(name)), flags, objp, propp);
+    Rooted<jsid> id(cx, NameToId(name));
+    return LookupPropertyWithFlags(cx, obj, id, flags, objp, propp);
 }
 
 /*
  * Call the [[DefineOwnProperty]] internal method of obj.
  *
  * If obj is an array, this follows ES5 15.4.5.1.
  * If obj is any other native object, this follows ES5 8.12.9.
  * If obj is a proxy, this calls the proxy handler's defineProperty method.
@@ -1218,21 +1229,21 @@ const unsigned JSGET_CACHE_RESULT = 1; /
 
 /*
  * NB: js_NativeGet and js_NativeSet are called with the scope containing shape
  * (pobj's scope for Get, obj's for Set) locked, and on successful return, that
  * scope is again locked.  But on failure, both functions return false with the
  * scope containing shape unlocked.
  */
 extern JSBool
-js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const js::Shape *shape, unsigned getHow,
-             js::Value *vp);
+js_NativeGet(JSContext *cx, js::Handle<JSObject*> obj, js::Handle<JSObject*> pobj,
+             const js::Shape *shape, unsigned getHow, js::Value *vp);
 
 extern JSBool
-js_NativeSet(JSContext *cx, JSObject *obj, const js::Shape *shape, bool added,
+js_NativeSet(JSContext *cx, js::Handle<JSObject*> obj, const js::Shape *shape, bool added,
              bool strict, js::Value *vp);
 
 namespace js {
 
 bool
 GetPropertyHelper(JSContext *cx, HandleObject obj, jsid id, uint32_t getHow, Value *vp);
 
 inline bool
@@ -1251,17 +1262,18 @@ bool
 NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, Value *vp);
 
 extern JSBool
 GetMethod(JSContext *cx, HandleObject obj, HandleId id, unsigned getHow, Value *vp);
 
 inline bool
 GetMethod(JSContext *cx, HandleObject obj, PropertyName *name, unsigned getHow, Value *vp)
 {
-    return GetMethod(cx, obj, RootedId(cx, NameToId(name)), getHow, vp);
+    Rooted<jsid> id(cx, NameToId(name));
+    return GetMethod(cx, obj, id, getHow, vp);
 }
 
 /*
  * If obj has an already-resolved data property for id, return true and
  * store the property value in *vp.
  */
 extern bool
 HasDataProperty(JSContext *cx, HandleObject obj, jsid id, Value *vp);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -49,17 +49,18 @@
 #include "vm/ObjectImpl-inl.h"
 #include "vm/RegExpStatics-inl.h"
 #include "vm/String-inl.h"
 
 inline bool
 JSObject::enumerate(JSContext *cx, JSIterateOp iterop, js::Value *statep, jsid *idp)
 {
     JSNewEnumerateOp op = getOps()->enumerate;
-    return (op ? op : JS_EnumerateState)(cx, js::RootedObject(cx, this), iterop, statep, idp);
+    js::Rooted<JSObject*> obj(cx, this);
+    return (op ? op : JS_EnumerateState)(cx, obj, iterop, statep, idp);
 }
 
 inline bool
 JSObject::defaultValue(JSContext *cx, JSType hint, js::Value *vp)
 {
     js::RootedObject self(cx, this);
 
     JSConvertOp op = getClass()->convert;
@@ -71,81 +72,89 @@ JSObject::defaultValue(JSContext *cx, JS
     JS_ASSERT_IF(ok, vp->isPrimitive());
     return ok;
 }
 
 inline JSType
 JSObject::typeOf(JSContext *cx)
 {
     js::TypeOfOp op = getOps()->typeOf;
-    return (op ? op : js::baseops::TypeOf)(cx, js::RootedObject(cx, this));
+    js::Rooted<JSObject*> obj(cx, this);
+    return (op ? op : js::baseops::TypeOf)(cx, obj);
 }
 
 inline JSObject *
 JSObject::thisObject(JSContext *cx)
 {
     JSObjectOp op = getOps()->thisObject;
-    return op ? op(cx, js::RootedObject(cx, this)) : this;
+    js::Rooted<JSObject*> obj(cx, this);
+    return op ? op(cx, obj) : this;
 }
 
 inline JSBool
 JSObject::setGeneric(JSContext *cx, js::HandleId id, js::Value *vp, JSBool strict)
 {
     if (getOps()->setGeneric)
         return nonNativeSetProperty(cx, id, vp, strict);
-    return js::baseops::SetPropertyHelper(cx,
-                                          js::RootedObject(cx, this),
-                                          id, 0, vp, strict);
+    js::Rooted<JSObject*> obj(cx, this);
+    return js::baseops::SetPropertyHelper(cx, obj, id, 0, vp, strict);
 }
 
 inline JSBool
 JSObject::setProperty(JSContext *cx, js::PropertyName *name, js::Value *vp, JSBool strict)
 {
-    return setGeneric(cx, js::RootedId(cx, js::NameToId(name)), vp, strict);
+    js::Rooted<jsid> id(cx, js::NameToId(name));
+    return setGeneric(cx, id, vp, strict);
 }
 
 inline JSBool
 JSObject::setElement(JSContext *cx, uint32_t index, js::Value *vp, JSBool strict)
 {
     if (getOps()->setElement)
         return nonNativeSetElement(cx, index, vp, strict);
-    return js::baseops::SetElementHelper(cx, js::RootedObject(cx, this), index, 0, vp, strict);
+    js::Rooted<JSObject*> obj(cx, this);
+    return js::baseops::SetElementHelper(cx, obj, index, 0, vp, strict);
 }
 
 inline JSBool
 JSObject::setSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp, JSBool strict)
 {
-    return setGeneric(cx, js::RootedId(cx, SPECIALID_TO_JSID(sid)), vp, strict);
+    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return setGeneric(cx, id, vp, strict);
 }
 
 inline JSBool
 JSObject::setGenericAttributes(JSContext *cx, js::HandleId id, unsigned *attrsp)
 {
     js::types::MarkTypePropertyConfigured(cx, this, id);
     js::GenericAttributesOp op = getOps()->setGenericAttributes;
-    return (op ? op : js::baseops::SetAttributes)(cx, js::RootedObject(cx, this), id, attrsp);
+    js::Rooted<JSObject*> obj(cx, this);
+    return (op ? op : js::baseops::SetAttributes)(cx, obj, id, attrsp);
 }
 
 inline JSBool
 JSObject::setPropertyAttributes(JSContext *cx, js::PropertyName *name, unsigned *attrsp)
 {
-    return setGenericAttributes(cx, js::RootedId(cx, js::NameToId(name)), attrsp);
+    js::Rooted<jsid> id(cx, js::NameToId(name));
+    return setGenericAttributes(cx, id, attrsp);
 }
 
 inline JSBool
 JSObject::setElementAttributes(JSContext *cx, uint32_t index, unsigned *attrsp)
 {
     js::ElementAttributesOp op = getOps()->setElementAttributes;
-    return (op ? op : js::baseops::SetElementAttributes)(cx, js::RootedObject(cx, this), index, attrsp);
+    js::Rooted<JSObject*> obj(cx, this);
+    return (op ? op : js::baseops::SetElementAttributes)(cx, obj, index, attrsp);
 }
 
 inline JSBool
 JSObject::setSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrsp)
 {
-    return setGenericAttributes(cx, js::RootedId(cx, SPECIALID_TO_JSID(sid)), attrsp);
+    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return setGenericAttributes(cx, id, attrsp);
 }
 
 inline bool
 JSObject::changePropertyAttributes(JSContext *cx, js::Shape *shape, unsigned attrs)
 {
     return !!changeProperty(cx, shape, attrs, 0, shape->getter(), shape->setter());
 }
 
@@ -163,39 +172,43 @@ JSObject::getGeneric(JSContext *cx, js::
             return false;
     }
     return true;
 }
 
 inline JSBool
 JSObject::getProperty(JSContext *cx, js::HandleObject receiver, js::PropertyName *name, js::Value *vp)
 {
-    return getGeneric(cx, receiver, js::RootedId(cx, js::NameToId(name)), vp);
+    js::Rooted<jsid> id(cx, js::NameToId(name));
+    return getGeneric(cx, receiver, id, vp);
 }
 
 inline JSBool
 JSObject::getGeneric(JSContext *cx, js::HandleId id, js::Value *vp)
 {
-    return getGeneric(cx, js::RootedObject(cx, this), id, vp);
+    js::Rooted<JSObject*> obj(cx, this);
+    return getGeneric(cx, obj, id, vp);
 }
 
 inline JSBool
 JSObject::getProperty(JSContext *cx, js::PropertyName *name, js::Value *vp)
 {
-    return getGeneric(cx, js::RootedId(cx, js::NameToId(name)), vp);
+    js::Rooted<jsid> id(cx, js::NameToId(name));
+    return getGeneric(cx, id, vp);
 }
 
 inline bool
 JSObject::deleteProperty(JSContext *cx, js::HandlePropertyName name, js::Value *rval, bool strict)
 {
     jsid id = js::NameToId(name);
     js::types::AddTypePropertyId(cx, this, id, js::types::Type::UndefinedType());
     js::types::MarkTypePropertyConfigured(cx, this, id);
     js::DeletePropertyOp op = getOps()->deleteProperty;
-    return (op ? op : js::baseops::DeleteProperty)(cx, js::RootedObject(cx, this), name, rval, strict);
+    js::Rooted<JSObject*> obj(cx, this);
+    return (op ? op : js::baseops::DeleteProperty)(cx, obj, name, rval, strict);
 }
 
 inline bool
 JSObject::deleteElement(JSContext *cx, uint32_t index, js::Value *rval, bool strict)
 {
     js::RootedObject self(cx, this);
 
     jsid id;
@@ -209,17 +222,18 @@ JSObject::deleteElement(JSContext *cx, u
 
 inline bool
 JSObject::deleteSpecial(JSContext *cx, js::HandleSpecialId sid, js::Value *rval, bool strict)
 {
     jsid id = SPECIALID_TO_JSID(sid);
     js::types::AddTypePropertyId(cx, this, id, js::types::Type::UndefinedType());
     js::types::MarkTypePropertyConfigured(cx, this, id);
     js::DeleteSpecialOp op = getOps()->deleteSpecial;
-    return (op ? op : js::baseops::DeleteSpecial)(cx, js::RootedObject(cx, this), sid, rval, strict);
+    js::Rooted<JSObject*> obj(cx, this);
+    return (op ? op : js::baseops::DeleteSpecial)(cx, obj, sid, rval, strict);
 }
 
 inline void
 JSObject::finalize(js::FreeOp *fop)
 {
     js::Probes::finalizeObject(this);
 
     if (!fop->onBackgroundThread()) {
@@ -1021,39 +1035,41 @@ JSObject::lookupGeneric(JSContext *cx, j
     if (op)
         return op(cx, self, id, objp, propp);
     return js::baseops::LookupProperty(cx, self, id, objp, propp);
 }
 
 inline JSBool
 JSObject::lookupProperty(JSContext *cx, js::PropertyName *name, JSObject **objp, JSProperty **propp)
 {
-    return lookupGeneric(cx, js::RootedId(cx, js::NameToId(name)), objp, propp);
+    js::Rooted<jsid> id(cx, js::NameToId(name));
+    return lookupGeneric(cx, id, objp, propp);
 }
 
 inline JSBool
 JSObject::defineGeneric(JSContext *cx, js::HandleId id, const js::Value &value,
                         JSPropertyOp getter /* = JS_PropertyStub */,
                         JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
                         unsigned attrs /* = JSPROP_ENUMERATE */)
 {
     js::RootedObject self(cx, this);
 
     JS_ASSERT(!(attrs & JSPROP_NATIVE_ACCESSORS));
     js::DefineGenericOp op = getOps()->defineGeneric;
-    return (op ? op : js::baseops::DefineProperty)(cx, self, id, &value, getter, setter, attrs);
+    return (op ? op : js::baseops::DefineGeneric)(cx, self, id, &value, getter, setter, attrs);
 }
 
 inline JSBool
 JSObject::defineProperty(JSContext *cx, js::PropertyName *name, const js::Value &value,
                         JSPropertyOp getter /* = JS_PropertyStub */,
                         JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
                         unsigned attrs /* = JSPROP_ENUMERATE */)
 {
-    return defineGeneric(cx, js::RootedId(cx, js::NameToId(name)), value, getter, setter, attrs);
+    js::Rooted<jsid> id(cx, js::NameToId(name));
+    return defineGeneric(cx, id, value, getter, setter, attrs);
 }
 
 inline JSBool
 JSObject::defineElement(JSContext *cx, uint32_t index, const js::Value &value,
                         JSPropertyOp getter /* = JS_PropertyStub */,
                         JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
                         unsigned attrs /* = JSPROP_ENUMERATE */)
 {
@@ -1064,32 +1080,34 @@ JSObject::defineElement(JSContext *cx, u
 }
 
 inline JSBool
 JSObject::defineSpecial(JSContext *cx, js::SpecialId sid, const js::Value &value,
                         JSPropertyOp getter /* = JS_PropertyStub */,
                         JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
                         unsigned attrs /* = JSPROP_ENUMERATE */)
 {
-    return defineGeneric(cx, js::RootedId(cx, SPECIALID_TO_JSID(sid)), value, getter, setter, attrs);
+    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return defineGeneric(cx, id, value, getter, setter, attrs);
 }
 
 inline JSBool
 JSObject::lookupElement(JSContext *cx, uint32_t index, JSObject **objp, JSProperty **propp)
 {
     js::RootedObject self(cx, this);
 
     js::LookupElementOp op = getOps()->lookupElement;
     return (op ? op : js::baseops::LookupElement)(cx, self, index, objp, propp);
 }
 
 inline JSBool
 JSObject::lookupSpecial(JSContext *cx, js::SpecialId sid, JSObject **objp, JSProperty **propp)
 {
-    return lookupGeneric(cx, js::RootedId(cx, SPECIALID_TO_JSID(sid)), objp, propp);
+    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return lookupGeneric(cx, id, objp, propp);
 }
 
 inline JSBool
 JSObject::getElement(JSContext *cx, js::HandleObject receiver, uint32_t index, js::Value *vp)
 {
     js::RootedObject self(cx, this);
 
     js::ElementIdOp op = getOps()->getElement;
@@ -1100,17 +1118,18 @@ JSObject::getElement(JSContext *cx, js::
     if (!js::IndexToId(cx, index, id.address()))
         return false;
     return self->getGeneric(cx, receiver, id, vp);
 }
 
 inline JSBool
 JSObject::getElement(JSContext *cx, uint32_t index, js::Value *vp)
 {
-    return getElement(cx, js::RootedObject(cx, this), index, vp);
+    js::Rooted<JSObject*> obj(cx, this);
+    return getElement(cx, obj, index, vp);
 }
 
 inline JSBool
 JSObject::getElementIfPresent(JSContext *cx, js::HandleObject receiver, uint32_t index, js::Value *vp,
                               bool *present)
 {
     js::RootedObject self(cx, this);
 
@@ -1140,45 +1159,49 @@ JSObject::getElementIfPresent(JSContext 
 
     *present = true;
     return self->getGeneric(cx, receiver, id, vp);
 }
 
 inline JSBool
 JSObject::getSpecial(JSContext *cx, js::HandleObject receiver, js::SpecialId sid, js::Value *vp)
 {
-    return getGeneric(cx, receiver, js::RootedId(cx, SPECIALID_TO_JSID(sid)), vp);
+    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return getGeneric(cx, receiver, id, vp);
 }
 
 inline JSBool
 JSObject::getGenericAttributes(JSContext *cx, js::HandleId id, unsigned *attrsp)
 {
     js::GenericAttributesOp op = getOps()->getGenericAttributes;
-    return (op ? op : js::baseops::GetAttributes)(cx, js::RootedObject(cx, this), id, attrsp);
+    js::Rooted<JSObject*> obj(cx, this);
+    return (op ? op : js::baseops::GetAttributes)(cx, obj, id, attrsp);
 }
 
 inline JSBool
 JSObject::getPropertyAttributes(JSContext *cx, js::PropertyName *name, unsigned *attrsp)
 {
-    return getGenericAttributes(cx, js::RootedId(cx, js::NameToId(name)), attrsp);
+    js::Rooted<jsid> id(cx, js::NameToId(name));
+    return getGenericAttributes(cx, id, attrsp);
 }
 
 inline JSBool
 JSObject::getElementAttributes(JSContext *cx, uint32_t index, unsigned *attrsp)
 {
     js::RootedId id(cx);
     if (!js::IndexToId(cx, index, id.address()))
         return false;
     return getGenericAttributes(cx, id, attrsp);
 }
 
 inline JSBool
 JSObject::getSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrsp)
 {
-    return getGenericAttributes(cx, js::RootedId(cx, SPECIALID_TO_JSID(sid)), attrsp);
+    js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return getGenericAttributes(cx, id, attrsp);
 }
 
 inline bool
 JSObject::isProxy() const
 {
     return js::IsProxy(this);
 }
 
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -275,17 +275,18 @@ static bool
 PreprocessValue(JSContext *cx, JSObject *holder, KeyType key, Value *vp, StringifyContext *scx)
 {
     JSString *keyStr = NULL;
 
     /* Step 2. */
     if (vp->isObject()) {
         Value toJSON;
         RootedId id(cx, NameToId(cx->runtime->atomState.toJSONAtom));
-        if (!GetMethod(cx, RootedObject(cx, &vp->toObject()), id, 0, &toJSON))
+        Rooted<JSObject*> obj(cx, &vp->toObject());
+        if (!GetMethod(cx, obj, id, 0, &toJSON))
             return false;
 
         if (js_IsCallable(toJSON)) {
             keyStr = KeyStringifier<KeyType>::toString(cx, key);
             if (!keyStr)
                 return false;
 
             InvokeArgsGuard args;
@@ -850,17 +851,18 @@ Revive(JSContext *cx, const Value &reviv
 {
     RootedObject obj(cx, NewBuiltinClassInstance(cx, &ObjectClass));
     if (!obj)
         return false;
 
     if (!obj->defineProperty(cx, cx->runtime->atomState.emptyAtom, *vp))
         return false;
 
-    return Walk(cx, obj, RootedId(cx, NameToId(cx->runtime->atomState.emptyAtom)), reviver, vp);
+    Rooted<jsid> id(cx, NameToId(cx->runtime->atomState.emptyAtom));
+    return Walk(cx, obj, id, reviver, vp);
 }
 
 namespace js {
 
 JSBool
 ParseJSONWithReviver(JSContext *cx, const jschar *chars, size_t length, const Value &reviver,
                      Value *vp, DecodingMode decodingMode /* = STRICT */)
 {
--- a/js/src/jsonparser.cpp
+++ b/js/src/jsonparser.cpp
@@ -544,17 +544,18 @@ JSONParser::parse(Value *vp)
             if (token == OOM)
                 return false;
             if (token != Error)
                 error("property names must be double-quoted strings");
             return errorReturn();
 
           case FinishArrayElement: {
             Value v = valueStack.popCopy();
-            if (!js_NewbornArrayPush(cx, RootedObject(cx, &valueStack.back().toObject()), v))
+            Rooted<JSObject*> obj(cx, &valueStack.back().toObject());
+            if (!js_NewbornArrayPush(cx, obj, v))
                 return false;
             token = advanceAfterArrayElement();
             if (token == Comma) {
                 if (!stateStack.append(FinishArrayElement))
                     return false;
                 goto JSONValue;
             }
             if (token == ArrayClose)
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -305,17 +305,18 @@ BaseProxyHandler::regexp_toShared(JSCont
     JS_NOT_REACHED("This should have been a wrapped regexp");
     return false;
 }
 
 bool
 BaseProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint,
                                Value *vp)
 {
-    return DefaultValue(cx, RootedObject(cx, proxy), hint, vp);
+    Rooted<JSObject*> obj(cx, proxy);
+    return DefaultValue(cx, obj, hint, vp);
 }
 
 bool
 BaseProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
 {
     vp->setMagic(JS_NO_ITER_VALUE);
     return true;
 }
@@ -392,24 +393,24 @@ IndirectProxyHandler::getOwnPropertyDesc
                                                jsid id, bool set,
                                                PropertyDescriptor *desc)
 {
     return GetOwnPropertyDescriptor(cx, GetProxyTargetObject(proxy), id,
                                     JSRESOLVE_QUALIFIED, desc);
 }
 
 bool
-IndirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id,
+IndirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id_,
                                      PropertyDescriptor *desc)
 {
     RootedObject obj(cx, GetProxyTargetObject(proxy));
-    return CheckDefineProperty(cx, obj, RootedId(cx, id), RootedValue(cx, desc->value),
-                               desc->getter, desc->setter, desc->attrs) &&
-           JS_DefinePropertyById(cx, obj, id, desc->value, desc->getter, desc->setter,
-                                 desc->attrs);
+    Rooted<jsid> id(cx, id_);
+    Rooted<Value> v(cx, desc->value);
+    return CheckDefineProperty(cx, obj, id, v, desc->getter, desc->setter, desc->attrs) &&
+           JS_DefinePropertyById(cx, obj, id, v, desc->getter, desc->setter, desc->attrs);
 }
 
 bool
 IndirectProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy,
                                           AutoIdVector &props)
 {
     return GetPropertyNames(cx, GetProxyTargetObject(proxy),
                             JSITER_OWNONLY | JSITER_HIDDEN, &props);
@@ -518,35 +519,35 @@ IndirectProxyHandler::defaultValue(JSCon
     if (hint == JSTYPE_VOID)
         return ToPrimitive(cx, vp);
     return ToPrimitive(cx, hint, vp);
 }
 
 bool
 IndirectProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
 {
-    if (!js_IteratorMore(cx, RootedObject(cx, GetProxyTargetObject(proxy)),
-                         vp))
+    Rooted<JSObject*> target(cx, GetProxyTargetObject(proxy));
+    if (!js_IteratorMore(cx, target, vp))
         return false;
     if (vp->toBoolean()) {
         *vp = cx->iterValue;
-        cx->iterValue.setUndefined();
-    } else
-        vp->setMagic(JS_NO_ITER_VALUE);
+        cx->iterValue = UndefinedValue();
+    } else {
+        *vp = MagicValue(JS_NO_ITER_VALUE);
+    }
     return true;
 }
 
-DirectProxyHandler::DirectProxyHandler(void *family) :
-        IndirectProxyHandler(family)
+DirectProxyHandler::DirectProxyHandler(void *family)
+  : IndirectProxyHandler(family)
 {
 }
 
 bool
-DirectProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id,
-                        bool *bp)
+DirectProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 {
     JSBool found;
     if (!JS_HasPropertyById(cx, GetProxyTargetObject(proxy), id, &found))
         return false;
     *bp = !!found;
     return true;
 }
 
@@ -585,26 +586,27 @@ DirectProxyHandler::keys(JSContext *cx, 
     return GetPropertyNames(cx, GetProxyTargetObject(proxy), JSITER_OWNONLY,
                             &props);
 }
 
 bool
 DirectProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags,
                             Value *vp)
 {
-    return GetIterator(cx, RootedObject(cx, GetProxyTargetObject(proxy)),
-                       flags, vp);
+    Rooted<JSObject*> target(cx, GetProxyTargetObject(proxy));
+    return GetIterator(cx, target, flags, vp);
 }
 
 static bool
 GetTrap(JSContext *cx, JSObject *handler, PropertyName *name, Value *fvalp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
-    return handler->getGeneric(cx, RootedId(cx, NameToId(name)), fvalp);
+    Rooted<PropertyName*> propname(cx, name);
+    return handler->getProperty(cx, propname, fvalp);
 }
 
 static bool
 GetFundamentalTrap(JSContext *cx, JSObject *handler, PropertyName *name, Value *fvalp)
 {
     if (!GetTrap(cx, handler, name, fvalp))
         return false;
 
@@ -1238,33 +1240,35 @@ proxy_LookupGeneric(JSContext *cx, Handl
     }
     return true;
 }
 
 static JSBool
 proxy_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSObject **objp,
                      JSProperty **propp)
 {
-    return proxy_LookupGeneric(cx, obj, RootedId(cx, NameToId(name)), objp, propp);
+    Rooted<jsid> id(cx, NameToId(name));
+    return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 proxy_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, JSObject **objp,
                     JSProperty **propp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 proxy_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSObject **objp, JSProperty **propp)
 {
-    return proxy_LookupGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)), objp, propp);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 proxy_DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     AutoPropertyDescriptorRooter desc(cx);
     desc.obj = obj;
@@ -1275,47 +1279,49 @@ proxy_DefineGeneric(JSContext *cx, Handl
     desc.shortid = 0;
     return Proxy::defineProperty(cx, obj, id, &desc);
 }
 
 static JSBool
 proxy_DefineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, const Value *value,
                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
-    return proxy_DefineGeneric(cx, obj, RootedId(cx, NameToId(name)), value, getter, setter, attrs);
+    Rooted<jsid> id(cx, NameToId(name));
+    return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
 static JSBool
 proxy_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, const Value *value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
 static JSBool
 proxy_DefineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, const Value *value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
-    return proxy_DefineGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)),
-                               value, getter, setter, attrs);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 }
 
 static JSBool
 proxy_GetGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, Value *vp)
 {
     return Proxy::get(cx, obj, receiver, id, vp);
 }
 
 static JSBool
 proxy_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name, Value *vp)
 {
-    return proxy_GetGeneric(cx, obj, receiver, RootedId(cx, NameToId(name)), vp);
+    Rooted<jsid> id(cx, NameToId(name));
+    return proxy_GetGeneric(cx, obj, receiver, id, vp);
 }
 
 static JSBool
 proxy_GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, Value *vp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
@@ -1327,139 +1333,148 @@ proxy_GetElementIfPresent(JSContext *cx,
                           Value *vp, bool *present)
 {
     return Proxy::getElementIfPresent(cx, obj, receiver, index, vp, present);
 }
 
 static JSBool
 proxy_GetSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid, Value *vp)
 {
-    return proxy_GetGeneric(cx, obj, receiver, RootedId(cx, SPECIALID_TO_JSID(sid)), vp);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return proxy_GetGeneric(cx, obj, receiver, id, vp);
 }
 
 static JSBool
 proxy_SetGeneric(JSContext *cx, HandleObject obj, HandleId id, Value *vp, JSBool strict)
 {
     return Proxy::set(cx, obj, obj, id, strict, vp);
 }
 
 static JSBool
 proxy_SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, Value *vp, JSBool strict)
 {
-    return proxy_SetGeneric(cx, obj, RootedId(cx, NameToId(name)), vp, strict);
+    Rooted<jsid> id(cx, NameToId(name));
+    return proxy_SetGeneric(cx, obj, id, vp, strict);
 }
 
 static JSBool
 proxy_SetElement(JSContext *cx, HandleObject obj, uint32_t index, Value *vp, JSBool strict)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return proxy_SetGeneric(cx, obj, id, vp, strict);
 }
 
 static JSBool
 proxy_SetSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, Value *vp, JSBool strict)
 {
-    return proxy_SetGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)), vp, strict);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return proxy_SetGeneric(cx, obj, id, vp, strict);
 }
 
 static JSBool
 proxy_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     AutoPropertyDescriptorRooter desc(cx);
     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, false, &desc))
         return false;
     *attrsp = desc.attrs;
     return true;
 }
 
 static JSBool
 proxy_GetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
 {
-    return proxy_GetGenericAttributes(cx, obj, RootedId(cx, NameToId(name)), attrsp);
+    Rooted<jsid> id(cx, NameToId(name));
+    return proxy_GetGenericAttributes(cx, obj, id, attrsp);
 }
 
 static JSBool
 proxy_GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return proxy_GetGenericAttributes(cx, obj, id, attrsp);
 }
 
 static JSBool
 proxy_GetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
 {
-    return proxy_GetGenericAttributes(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)), attrsp);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return proxy_GetGenericAttributes(cx, obj, id, attrsp);
 }
 
 static JSBool
 proxy_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     /* Lookup the current property descriptor so we have setter/getter/value. */
     AutoPropertyDescriptorRooter desc(cx);
     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, true, &desc))
         return false;
     desc.attrs = (*attrsp & (~JSPROP_SHORTID));
     return Proxy::defineProperty(cx, obj, id, &desc);
 }
 
 static JSBool
 proxy_SetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
 {
-    return proxy_SetGenericAttributes(cx, obj, RootedId(cx, NameToId(name)), attrsp);
+    Rooted<jsid> id(cx, NameToId(name));
+    return proxy_SetGenericAttributes(cx, obj, id, attrsp);
 }
 
 static JSBool
 proxy_SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return proxy_SetGenericAttributes(cx, obj, id, attrsp);
 }
 
 static JSBool
 proxy_SetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
 {
-    return proxy_SetGenericAttributes(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)), attrsp);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return proxy_SetGenericAttributes(cx, obj, id, attrsp);
 }
 
 static JSBool
 proxy_DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, Value *rval, JSBool strict)
 {
     // TODO: throwing away strict
     bool deleted;
     if (!Proxy::delete_(cx, obj, id, &deleted) || !js_SuppressDeletedProperty(cx, obj, id))
         return false;
     rval->setBoolean(deleted);
     return true;
 }
 
 static JSBool
 proxy_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, Value *rval, JSBool strict)
 {
-    return proxy_DeleteGeneric(cx, obj, RootedId(cx, NameToId(name)), rval, strict);
+    Rooted<jsid> id(cx, NameToId(name));
+    return proxy_DeleteGeneric(cx, obj, id, rval, strict);
 }
 
 static JSBool
 proxy_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, Value *rval, JSBool strict)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return proxy_DeleteGeneric(cx, obj, id, rval, strict);
 }
 
 static JSBool
 proxy_DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, Value *rval, JSBool strict)
 {
-    return proxy_DeleteGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)), rval, strict);
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return proxy_DeleteGeneric(cx, obj, id, rval, strict);
 }
 
 static void
 proxy_TraceObject(JSTracer *trc, JSObject *obj)
 {
 #ifdef DEBUG
     if (!trc->runtime->gcDisableStrictProxyCheckingCount && obj->isWrapper()) {
         JSObject *referent = &GetProxyPrivate(obj).toObject();
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -3227,17 +3227,17 @@ reflect_parse(JSContext *cx, uint32_t ar
 
     size_t length = src->length();
     const jschar *chars = src->getChars(cx);
     if (!chars)
         return JS_FALSE;
 
     Parser parser(cx, /* prin = */ NULL, /* originPrin = */ NULL,
                   chars, length, filename, lineno, cx->findVersion(), 
-                  /* cfp = */ NULL, /* foldConstants = */ false, /* compileAndGo = */ false);
+                  /* foldConstants = */ false, /* compileAndGo = */ false);
     if (!parser.init())
         return JS_FALSE;
 
     serialize.setParser(&parser);
 
     ParseNode *pn = parser.parse(NULL);
     if (!pn)
         return JS_FALSE;
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -1008,17 +1008,19 @@ bool
 JSObject::shadowingShapeChange(JSContext *cx, const Shape &shape)
 {
     return generateOwnShape(cx);
 }
 
 bool
 JSObject::clearParent(JSContext *cx)
 {
-    return setParent(cx, RootedObject(cx, this), RootedObject(cx));
+    Rooted<JSObject*> obj(cx, this);
+    Rooted<JSObject*> newParent(cx, NULL);
+    return setParent(cx, obj, newParent);
 }
 
 /* static */ bool
 JSObject::setParent(JSContext *cx, HandleObject obj, HandleObject parent)
 {
     if (parent && !parent->setDelegate(cx))
         return false;
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -231,43 +231,23 @@ Bindings::getLocalNameArray(JSContext *c
     for (unsigned i = 0; i < n; i++)
         JS_ASSERT(names[i].maybeAtom != POISON);
 #endif
 
     return true;
 }
 
 const Shape *
-Bindings::lastArgument() const
-{
-    JS_ASSERT(lastBinding);
-
-    const js::Shape *shape = lastVariable();
-    if (nvars > 0) {
-        while (shape->previous() && shape->setter() != CallObject::setArgOp)
-            shape = shape->previous();
-    }
-    return shape;
-}
-
-const Shape *
 Bindings::lastVariable() const
 {
     JS_ASSERT(lastBinding);
     return lastBinding;
 }
 
 void
-Bindings::makeImmutable()
-{
-    JS_ASSERT(lastBinding);
-    JS_ASSERT(!lastBinding->inDictionary());
-}
-
-void
 Bindings::trace(JSTracer *trc)
 {
     if (lastBinding)
         MarkShape(trc, &lastBinding, "shape");
 }
 
 } /* namespace js */
 
@@ -413,17 +393,17 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
         return false;
     if (mode == XDR_DECODE) {
         nargs = argsVars >> 16;
         nvars = argsVars & 0xFFFF;
     }
     JS_ASSERT(nargs != Bindings::BINDING_COUNT_LIMIT);
     JS_ASSERT(nvars != Bindings::BINDING_COUNT_LIMIT);
 
-    Bindings bindings(cx);
+    Bindings bindings;
     Bindings::AutoRooter bindingsRoot(cx, &bindings);
 
     uint32_t nameCount = nargs + nvars;
     if (nameCount > 0) {
         LifoAllocScope las(&cx->tempLifoAlloc());
 
         /*
          * To xdr the names we prefix the names with a bitmap descriptor and
@@ -485,17 +465,16 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
                     return false;
             }
         }
     }
 
     if (mode == XDR_DECODE) {
         if (!bindings.ensureShape(cx))
             return false;
-        bindings.makeImmutable();
     }
 
     if (mode == XDR_ENCODE)
         length = script->length;
     if (!xdr->codeUint32(&length))
         return JS_FALSE;
 
     if (mode == XDR_ENCODE) {
@@ -595,17 +574,17 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
                                   /* globalObject = */ NULL,
                                   version_,
                                   /* staticLevel = */ 0);
         if (!script || !script->partiallyInit(cx, length, nsrcnotes, natoms, nobjects,
                                               nregexps, ntrynotes, nconsts, nClosedArgs,
                                               nClosedVars, nTypeSets))
             return JS_FALSE;
 
-        script->bindings.transfer(cx, &bindings);
+        script->bindings.transfer(&bindings);
         JS_ASSERT(!script->mainOffset);
         script->mainOffset = prologLength;
         script->nfixed = uint16_t(version >> 16);
 
         /* If we know nsrcnotes, we allocated space for notes in script. */
         notes = script->notes();
         *scriptp = script;
 
@@ -1166,17 +1145,17 @@ JSScript::partiallyInit(JSContext *cx, u
     size_t size = ScriptDataSize(length, nsrcnotes, natoms, nobjects, nregexps,
                                  ntrynotes, nconsts, nClosedArgs, nClosedVars);
     script->data = AllocScriptData(cx, size);
     if (!script->data)
         return false;
 
     script->length = length;
 
-    new (&script->bindings) Bindings(cx);
+    new (&script->bindings) Bindings;
 
     uint8_t *cursor = data;
     if (nconsts != 0) {
         script->setHasArray(CONSTS);
         cursor += sizeof(ConstArray);
     }
     if (nobjects != 0) {
         script->setHasArray(OBJECTS);
@@ -1291,18 +1270,16 @@ JSScript::fullyInitFromEmitter(JSContext
     uint16_t nClosedVars = uint16_t(bce->closedVars.length());
     JS_ASSERT(nClosedVars == bce->closedVars.length());
     if (!script->partiallyInit(cx, prologLength + mainLength, nsrcnotes, bce->atomIndices->count(),
                                bce->objectList.length, bce->regexpList.length, bce->ntrynotes,
                                bce->constList.length(), nClosedArgs, nClosedVars,
                                bce->typesetCount))
         return false;
 
-    bce->sc->bindings.makeImmutable();
-
     JS_ASSERT(script->mainOffset == 0);
     script->mainOffset = prologLength;
     PodCopy<jsbytecode>(script->code, bce->prologBase(), prologLength);
     PodCopy<jsbytecode>(script->main(), bce->base(), mainLength);
     uint32_t nfixed = bce->sc->inFunction() ? bce->sc->bindings.numVars() : 0;
     JS_ASSERT(nfixed < SLOTNO_LIMIT);
     script->nfixed = uint16_t(nfixed);
     InitAtomMap(cx, bce->atomIndices.getMap(), script->atoms);
@@ -1359,17 +1336,17 @@ JSScript::fullyInitFromEmitter(JSContext
         }
     }
 
     if (nClosedArgs)
         PodCopy<uint32_t>(script->closedArgs()->vector, &bce->closedArgs[0], nClosedArgs);
     if (nClosedVars)
         PodCopy<uint32_t>(script->closedVars()->vector, &bce->closedVars[0], nClosedVars);
 
-    script->bindings.transfer(cx, &bce->sc->bindings);
+    script->bindings.transfer(&bce->sc->bindings);
 
     JSFunction *fun = NULL;
     if (bce->sc->inFunction()) {
         JS_ASSERT(!bce->script->noScriptRval);
 
         script->isGenerator = bce->sc->funIsGenerator();
 
         /*
@@ -1737,36 +1714,36 @@ js::CloneScript(JSContext *cx, HandleScr
                                  nobjects, nregexps, ntrynotes, nconsts, nClosedArgs, nClosedVars);
 
     uint8_t *data = AllocScriptData(cx, size);
     if (!data)
         return NULL;
 
     /* Bindings */
 
-    Bindings bindings(cx);
+    Bindings bindings;
     Bindings::AutoRooter bindingsRoot(cx, &bindings);
     BindingNames names(cx);
     if (!src->bindings.getLocalNameArray(cx, &names))
         return NULL;
 
     for (unsigned i = 0; i < names.length(); ++i) {
         if (JSAtom *atom = names[i].maybeAtom) {
-            if (!bindings.add(cx, RootedAtom(cx, atom), names[i].kind))
+            Rooted<JSAtom*> root(cx, atom);
+            if (!bindings.add(cx, root, names[i].kind))
                 return NULL;
         } else {
             uint16_t _;
             if (!bindings.addDestructuring(cx, &_))
                 return NULL;
         }
     }
 
     if (!bindings.ensureShape(cx))
         return NULL;
-    bindings.makeImmutable();
 
     /* Objects */
 
     AutoObjectVector objects(cx);
     if (nobjects != 0) {
         HeapPtrObject *vector = src->objects()->vector;
         for (unsigned i = 0; i < nobjects; i++) {
             JSObject *clone = vector[i]->isStaticBlock()
@@ -1796,18 +1773,18 @@ js::CloneScript(JSContext *cx, HandleScr
                                      src->compileAndGo, src->noScriptRval,
                                      /* globalObject = */ NULL, src->getVersion(),
                                      src->staticLevel);
     if (!dst) {
         Foreground::free_(data);
         return NULL;
     }
 
-    new (&dst->bindings) Bindings(cx);
-    dst->bindings.transfer(cx, &bindings);
+    new (&dst->bindings) Bindings;
+    dst->bindings.transfer(&bindings);
 
     /* This assignment must occur before all the Rebase calls. */
     dst->data = data;
     memcpy(data, src->data, size);
 
     dst->code = Rebase<jsbytecode>(dst, src, src->code);
 
     /* Script filenames are runtime-wide. */
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -88,31 +88,24 @@ class Bindings
 {
     HeapPtr<Shape> lastBinding;
     uint16_t nargs;
     uint16_t nvars;
     bool     hasDup_:1;     // true if there are duplicate argument names
 
     inline Shape *initialShape(JSContext *cx) const;
   public:
-    inline Bindings(JSContext *cx);
+    inline Bindings();
 
     /*
      * Transfers ownership of bindings data from bindings into this fresh
      * Bindings instance. Once such a transfer occurs, the old bindings must
      * not be used again.
      */
-    inline void transfer(JSContext *cx, Bindings *bindings);
-
-    /*
-     * Clones bindings data from bindings, which must be immutable, into this
-     * fresh Bindings instance. A Bindings instance may be cloned multiple
-     * times.
-     */
-    inline void clone(JSContext *cx, Bindings *bindings);
+    inline void transfer(Bindings *bindings);
 
     uint16_t numArgs() const { return nargs; }
     uint16_t numVars() const { return nvars; }
     unsigned count() const { return nargs + nvars; }
 
     /*
      * These functions map between argument/var indices [0, nargs/nvars) and
      * and Bindings indices [0, nargs + nvars).
@@ -173,17 +166,18 @@ class Bindings
     }
     bool addArgument(JSContext *cx, HandleAtom name, uint16_t *slotp) {
         JS_ASSERT(name != NULL); /* not destructuring */
         *slotp = nargs;
         return add(cx, name, ARGUMENT);
     }
     bool addDestructuring(JSContext *cx, uint16_t *slotp) {
         *slotp = nargs;
-        return add(cx, RootedAtom(cx), ARGUMENT);
+        Rooted<JSAtom*> atom(cx, NULL);
+        return add(cx, atom, ARGUMENT);
     }
 
     void noteDup() { hasDup_ = true; }
     bool hasDup() const { return hasDup_; }
 
     /*
      * Look up an argument or variable name, returning its kind when found or
      * NONE when no such name exists. When indexp is not null and the name
@@ -204,32 +198,24 @@ class Bindings
      * The elements of the vector with index less than nargs correspond to the
      * the names of arguments. An index >= nargs addresses a var binding.
      * The name at an element will be null when the element is for an argument
      * corresponding to a destructuring pattern.
      */
     bool getLocalNameArray(JSContext *cx, BindingNames *namesp);
 
     /*
-     * Protect stored bindings from mutation.  Subsequent attempts to add
-     * bindings will copy the existing bindings before adding to them, allowing
-     * the original bindings to be safely shared.
-     */
-    void makeImmutable();
-
-    /*
-     * These methods provide direct access to the shape path normally
-     * encapsulated by js::Bindings. These methods may be used to make a
+     * This method provides direct access to the shape path normally
+     * encapsulated by js::Bindings. This method may be used to make a
      * Shape::Range for iterating over the relevant shapes from youngest to
      * oldest (i.e., last or right-most to first or left-most in source order).
      *
      * Sometimes iteration order must be from oldest to youngest, however. For
      * such cases, use js::Bindings::getLocalNameArray.
      */
-    const js::Shape *lastArgument() const;
     const js::Shape *lastVariable() const;
 
     void trace(JSTracer *trc);
 
     class AutoRooter : private AutoGCRooter
     {
       public:
         explicit AutoRooter(JSContext *cx, Bindings *bindings_
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -19,41 +19,32 @@
 #include "vm/GlobalObject.h"
 #include "vm/RegExpObject.h"
 
 #include "jsscopeinlines.h"
 
 namespace js {
 
 inline
-Bindings::Bindings(JSContext *cx)
+Bindings::Bindings()
     : lastBinding(NULL), nargs(0), nvars(0), hasDup_(false)
 {}
 
 inline void
-Bindings::transfer(JSContext *cx, Bindings *bindings)
+Bindings::transfer(Bindings *bindings)
 {
     JS_ASSERT(!lastBinding);
     JS_ASSERT(!bindings->lastBinding || !bindings->lastBinding->inDictionary());
 
     *this = *bindings;
 #ifdef DEBUG
     bindings->lastBinding = NULL;
 #endif
 }
 
-inline void
-Bindings::clone(JSContext *cx, Bindings *bindings)
-{
-    JS_ASSERT(!lastBinding);
-    JS_ASSERT(!bindings->lastBinding || !bindings->lastBinding->inDictionary());
-
-    *this = *bindings;
-}
-
 Shape *
 Bindings::lastShape() const
 {
     JS_ASSERT(lastBinding);
     JS_ASSERT(!lastBinding->inDictionary());
     return lastBinding;
 }
 
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp